From 0d305d7c3e5bb07c01eaab6fbe763ca98a071dea Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Thu, 11 Mar 2021 11:35:15 +1300 Subject: [PATCH] Lines no longer treats a text buffer as a line (#3153) --- crates/nu-command/src/commands/lines.rs | 99 +++++++++++++---------- crates/nu-command/src/utils/test_bins.rs | 15 ++++ crates/nu-command/tests/commands/lines.rs | 2 +- src/main.rs | 3 +- tests/shell/pipeline/commands/external.rs | 11 +++ 5 files changed, 84 insertions(+), 46 deletions(-) diff --git a/crates/nu-command/src/commands/lines.rs b/crates/nu-command/src/commands/lines.rs index 9d9d67f0a6..e3409929a6 100644 --- a/crates/nu-command/src/commands/lines.rs +++ b/crates/nu-command/src/commands/lines.rs @@ -56,59 +56,70 @@ async fn lines(args: CommandArgs) -> Result { Ok(args .input .chain(eos) - .map(move |item| { + .filter_map(move |item| { let leftover_string = leftover_string.clone(); + async move { + match item { + Value { + value: UntaggedValue::Primitive(Primitive::String(st)), + .. + } => { + let mut leftover_string = leftover_string.lock(); - match item { - Value { - value: UntaggedValue::Primitive(Primitive::String(st)), - .. - } => { - let mut leftover_string = leftover_string.lock(); + let mut buffer = leftover_string.clone(); + buffer.push_str(&st); - let lo_lines = (&*leftover_string).lines().map(|x| x.to_string()); - let st_lines = st.lines().map(|x| x.to_string()); - let mut lines: Vec = lo_lines.chain(st_lines).collect(); + let mut lines: Vec = + buffer.lines().map(|x| x.to_string()).collect(); - leftover_string.clear(); + leftover_string.clear(); - if !ends_with_line_ending(&st) { - if let Some(last) = lines.pop() { - leftover_string.push_str(&last); + if !ends_with_line_ending(&st) { + if let Some(last) = lines.pop() { + leftover_string.push_str(&last); + } + } + + if !lines.is_empty() { + let success_lines: Vec<_> = lines + .iter() + .map(|x| { + ReturnSuccess::value( + UntaggedValue::string(x).into_untagged_value(), + ) + }) + .collect(); + + Some(futures::stream::iter(success_lines)) + } else { + None } } - - let success_lines: Vec<_> = lines - .iter() - .map(|x| { - ReturnSuccess::value(UntaggedValue::string(x).into_untagged_value()) - }) - .collect(); - - futures::stream::iter(success_lines) - } - Value { - value: UntaggedValue::Primitive(Primitive::EndOfStream), - .. - } => { - let st = (&*leftover_string).lock().clone(); - if !st.is_empty() { - futures::stream::iter(vec![ReturnSuccess::value( - UntaggedValue::string(st).into_untagged_value(), - )]) - } else { - futures::stream::iter(vec![]) + Value { + value: UntaggedValue::Primitive(Primitive::EndOfStream), + .. + } => { + let st = (&*leftover_string).lock().clone(); + if !st.is_empty() { + Some(futures::stream::iter(vec![ReturnSuccess::value( + UntaggedValue::string(st).into_untagged_value(), + )])) + } else { + None + } } + Value { + tag: value_span, .. + } => Some(futures::stream::iter(vec![Err( + ShellError::labeled_error_with_secondary( + "Expected a string from pipeline", + "requires string input", + name_span, + "value originates from here", + value_span, + ), + )])), } - Value { - tag: value_span, .. - } => futures::stream::iter(vec![Err(ShellError::labeled_error_with_secondary( - "Expected a string from pipeline", - "requires string input", - name_span, - "value originates from here", - value_span, - ))]), } }) .flatten() diff --git a/crates/nu-command/src/utils/test_bins.rs b/crates/nu-command/src/utils/test_bins.rs index 78b727dfd7..2c5ed1ea8a 100644 --- a/crates/nu-command/src/utils/test_bins.rs +++ b/crates/nu-command/src/utils/test_bins.rs @@ -17,6 +17,21 @@ pub fn nonu() { args().iter().skip(1).for_each(|arg| print!("{}", arg)); } +pub fn repeater() { + let mut stdout = io::stdout(); + let args = args(); + let mut args = args.iter().skip(1); + let letter = args.next().expect("needs a character to iterate"); + let count = args.next().expect("need the number of times to iterate"); + + let count: u64 = count.parse().expect("can't convert count to number"); + + for _ in 0..count { + let _ = write!(stdout, "{}", letter); + } + let _ = stdout.flush(); +} + pub fn iecho() { // println! panics if stdout gets closed, whereas writeln gives us an error let mut stdout = io::stdout(); diff --git a/crates/nu-command/tests/commands/lines.rs b/crates/nu-command/tests/commands/lines.rs index c03f7792a7..26a4d80448 100644 --- a/crates/nu-command/tests/commands/lines.rs +++ b/crates/nu-command/tests/commands/lines.rs @@ -46,5 +46,5 @@ fn lines_multi_value_split() { "# )); - assert_eq!(actual.out, "6"); + assert_eq!(actual.out, "5"); } diff --git a/src/main.rs b/src/main.rs index a2ce96afd0..99f1ae72ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,7 +29,7 @@ fn main() -> Result<(), Box> { .hidden(true) .long("testbin") .value_name("TESTBIN") - .possible_values(&["cococo", "iecho", "fail", "nonu", "chop"]) + .possible_values(&["cococo", "iecho", "fail", "nonu", "chop", "repeater"]) .takes_value(true), ) .arg( @@ -77,6 +77,7 @@ fn main() -> Result<(), Box> { "fail" => binaries::fail(), "nonu" => binaries::nonu(), "chop" => binaries::chop(), + "repeater" => binaries::repeater(), _ => unreachable!(), } diff --git a/tests/shell/pipeline/commands/external.rs b/tests/shell/pipeline/commands/external.rs index 8cd6d05a38..cad98bac32 100644 --- a/tests/shell/pipeline/commands/external.rs +++ b/tests/shell/pipeline/commands/external.rs @@ -121,6 +121,17 @@ mod it_evaluation { }) } + #[test] + fn can_properly_buffer_lines_externally() { + let actual = nu!( + cwd: ".", + r#" + nu --testbin repeater c 8197 | lines | count + "# + ); + + assert_eq!(actual.out, "1"); + } #[test] fn supports_fetching_given_a_column_path_to_it() { Playground::setup("it_argument_test_3", |dirs, sandbox| {