diff options
Diffstat (limited to 'src/choice.rs')
-rw-r--r-- | src/choice.rs | 182 |
1 files changed, 140 insertions, 42 deletions
diff --git a/src/choice.rs b/src/choice.rs index 941f512..2f89ff0 100644 --- a/src/choice.rs +++ b/src/choice.rs @@ -23,11 +23,11 @@ impl Choice { } } - pub fn print_choice<WriterType: Write>( + pub fn print_choice<W: Write>( &self, line: &String, config: &Config, - handle: &mut BufWriter<WriterType>, + handle: &mut BufWriter<W>, ) { let mut line_iter = config .separator @@ -51,59 +51,87 @@ impl Choice { } } + let mut iter = stack.iter().rev().peekable(); loop { - match stack.pop() { - Some(s) => Choice::write_bytes(handle, s.as_bytes()), + match iter.next() { + Some(s) => { + Choice::write_bytes(s.as_bytes(), config, handle, iter.peek().is_some()) + } None => break, } } } else if self.has_negative_index() { let vec = line_iter.collect::<Vec<&str>>(); - - let start = if self.start >= 0 { - self.start.try_into().unwrap() - } else { - vec.len() - .checked_sub(self.start.abs().try_into().unwrap()) - .unwrap() - }; - - let end = if self.end >= 0 { - self.end.try_into().unwrap() - } else { - vec.len() - .checked_sub(self.end.abs().try_into().unwrap()) - .unwrap() - }; - - if end > start { - for word in vec[start..=std::cmp::min(end, vec.len() - 1)].iter() { - Choice::write_bytes(handle, word.as_bytes()); - } - } else if self.start < 0 { - for word in vec[end..=std::cmp::min(start, vec.len() - 1)].iter().rev() { - Choice::write_bytes(handle, word.as_bytes()); - } - } + self.print_negative_choice(vec, config, handle); } else { if self.start > 0 { line_iter.nth((self.start - 1).try_into().unwrap()); } - for i in 0..=(self.end - self.start) { - match line_iter.next() { - Some(s) => Choice::write_bytes(handle, s.as_bytes()), + let mut peek_line_iter = line_iter.peekable(); + for i in self.start..=self.end { + match peek_line_iter.next() { + Some(s) => Choice::write_bytes( + s.as_bytes(), + config, + handle, + peek_line_iter.peek().is_some() && i != self.end, + ), None => break, }; + } + } + } - if self.end <= self.start + i { - break; - } + fn print_negative_choice<W: Write>( + &self, + vec: Vec<&str>, + config: &Config, + handle: &mut BufWriter<W>, + ) { + let start = if self.start >= 0 { + self.start.try_into().unwrap() + } else { + vec.len() + .checked_sub(self.start.abs().try_into().unwrap()) + .unwrap() + }; + + let end = if self.end >= 0 { + self.end.try_into().unwrap() + } else { + vec.len() + .checked_sub(self.end.abs().try_into().unwrap()) + .unwrap() + }; + + if end > start { + for word in vec[start..std::cmp::min(end, vec.len() - 1)].iter() { + Choice::write_bytes(word.as_bytes(), config, handle, true); } + Choice::write_bytes( + vec[std::cmp::min(end, vec.len() - 1)].as_bytes(), + config, + handle, + false, + ); + } else if self.start < 0 { + for word in vec[end + 1..=std::cmp::min(start, vec.len() - 1)] + .iter() + .rev() + { + Choice::write_bytes(word.as_bytes(), config, handle, true); + } + Choice::write_bytes(vec[end].as_bytes(), config, handle, false); } } - fn write_bytes<WriterType: Write>(handle: &mut BufWriter<WriterType>, b: &[u8]) { + fn write_bytes<WriterType: Write>( + b: &[u8], + config: &Config, + handle: &mut BufWriter<WriterType>, + print_separator: bool, + ) { let num_bytes_written = match handle.write(b) { Ok(x) => x, Err(e) => { @@ -111,11 +139,15 @@ impl Choice { 0 } }; - if num_bytes_written > 0 { - match handle.write(b" ") { - Ok(_) => (), - Err(e) => eprintln!("Failed to write to output: {}", e), - } + if num_bytes_written > 0 && print_separator { + Choice::write_separator(config, handle); + }; + } + + pub fn write_separator<W: Write>(config: &Config, handle: &mut BufWriter<W>) { + match handle.write(&config.output_separator) { + Ok(_) => (), + Err(e) => eprintln!("Failed to write to output: {}", e), } } @@ -564,6 +596,72 @@ mod tests { config.opt.choice[0].print_choice(&String::from("a:b::c:::d"), &config, &mut handle); assert_eq!(String::from("d"), MockStdout::str_from_buf_writer(handle)); } + + #[test] + fn print_1_to_3_with_output_field_separator() { + let config = Config::from_iter(vec!["choose", "1:3", "-o", "#"]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice(&String::from("a b c d"), &config, &mut handle); + assert_eq!( + String::from("b#c#d"), + MockStdout::str_from_buf_writer(handle) + ); + } + + #[test] + fn print_1_and_3_with_output_field_separator() { + let config = Config::from_iter(vec!["choose", "1", "3", "-o", "#"]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice(&String::from("a b c d"), &config, &mut handle); + handle.write(&config.output_separator).unwrap(); + config.opt.choice[1].print_choice(&String::from("a b c d"), &config, &mut handle); + assert_eq!(String::from("b#d"), MockStdout::str_from_buf_writer(handle)); + } + + #[test] + fn print_2_to_4_with_output_field_separator() { + let config = Config::from_iter(vec!["choose", "2:4", "-o", "%"]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice( + &String::from("Lorem ipsum dolor sit amet, consectetur"), + &config, + &mut handle, + ); + assert_eq!( + String::from("dolor%sit%amet,"), + MockStdout::str_from_buf_writer(handle) + ); + } + + #[test] + fn print_3_to_1_with_output_field_separator() { + let config = Config::from_iter(vec!["choose", "3:1", "-o", "#"]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice(&String::from("a b c d"), &config, &mut handle); + assert_eq!( + String::from("d#c#b"), + MockStdout::str_from_buf_writer(handle) + ); + } + + #[test] + fn print_0_to_neg_2_with_output_field_separator() { + let config = Config::from_iter(vec!["choose", "0:-2", "-o", "#"]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice(&String::from("a b c d"), &config, &mut handle); + assert_eq!( + String::from("a#b#c"), + MockStdout::str_from_buf_writer(handle) + ); + } + + #[test] + fn print_0_to_2_with_empty_output_field_separator() { + let config = Config::from_iter(vec!["choose", "0:2", "-o", ""]); + let mut handle = BufWriter::new(MockStdout::new()); + config.opt.choice[0].print_choice(&String::from("a b c d"), &config, &mut handle); + assert_eq!(String::from("abc"), MockStdout::str_from_buf_writer(handle)); + } } mod is_reverse_range_tests { |