From e9508b578a163deab0e6278aabe13b643d2499f9 Mon Sep 17 00:00:00 2001 From: Astrick <33888523+AstrickHarren@users.noreply.github.com> Date: Sat, 10 Jun 2023 17:57:26 -0400 Subject: [PATCH] Fix find puts extra cols into record (#9397) # Description Trying to fix #9394. The problem with PR #9159 seems to be when searching for multiple terms, each term is checked against the original values. It outputs a new value for each such check, thus introducing replication for each search term. As a result, it works fine with num of search term = 1. --- crates/nu-command/src/filters/find.rs | 63 +++++++++++++----------- crates/nu-command/tests/commands/find.rs | 25 ++++++++++ 2 files changed, 58 insertions(+), 30 deletions(-) diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index c7f0b488d..07fcd88ea 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -1,3 +1,4 @@ +use itertools::Itertools; use nu_cmd_lang::help::highlight_search_string; use fancy_regex::Regex; @@ -292,9 +293,9 @@ fn record_matches_regex(values: &[Value], re: &Regex, config: &Config) -> bool { #[allow(clippy::too_many_arguments)] fn highlight_terms_in_record_with_search_columns( search_cols: &Vec, - cols: &mut [String], - vals: &mut Vec, - span: &mut Span, + cols: &[String], + vals: &[Value], + span: &Span, config: &Config, terms: &[Value], string_style: Style, @@ -305,38 +306,40 @@ fn highlight_terms_in_record_with_search_columns( } else { search_cols.to_vec() }; - let mut output = vec![]; + let term_strs: Vec<_> = terms.iter().map(|v| v.into_string("", config)).collect(); - // We iterate every column in the record and every search term for matches - for (cur_col, val) in cols.iter().zip(vals) { + // iterator of Ok((val_str, term_str)) pairs if the value should be highlighted, otherwise Err(val) + let try_val_highlight = vals.iter().zip(cols).map(|(val, col)| { let val_str = val.into_string("", config); - for term in terms { - let term_str = term.into_string("", config); - let output_value = - if contains_ignore_case(&val_str, &term_str) && cols_to_search.contains(cur_col) { - let highlighted_str = match highlight_search_string( - &val_str, - &term_str, - &string_style, - &highlight_style, - ) { - Ok(highlighted_str) => highlighted_str, - Err(_) => string_style.paint(term_str).to_string(), - }; - Value::String { - val: highlighted_str, - span: *span, - } - } else { - val.clone() - }; - output.push(output_value); - } - } + let predicate = cols_to_search.contains(col); + predicate + .then_some(val_str) + .and_then(|val_str| { + term_strs + .iter() + .find(|term_str| contains_ignore_case(&val_str, term_str)) + .map(|term_str| (val_str, term_str)) + }) + .ok_or_else(|| val.clone()) + }); + + // turn Ok pairs into vals of highlighted strings, Err vals is original vals + let new_vals = try_val_highlight + .map_ok(|(val_str, term_str)| { + let highlighted_str = + highlight_search_string(&val_str, term_str, &string_style, &highlight_style) + .unwrap_or_else(|_| string_style.paint(term_str).to_string()); + + Value::String { + val: highlighted_str, + span: *span, + } + }) + .map(|v| v.unwrap_or_else(|v| v)); Value::Record { cols: cols.to_vec(), - vals: output, + vals: new_vals.collect(), span: *span, } } diff --git a/crates/nu-command/tests/commands/find.rs b/crates/nu-command/tests/commands/find.rs index 0bcaae922..139244496 100644 --- a/crates/nu-command/tests/commands/find.rs +++ b/crates/nu-command/tests/commands/find.rs @@ -94,3 +94,28 @@ fn inverted_find_in_table_keeps_row_if_none_of_the_selected_columns_matches() { assert_eq!(actual.out, r#"["Maurice"]"#); } + +#[test] +fn find_in_table_keeps_row_with_single_matched_and_keeps_other_columns() { + let actual = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18]] | find Maurice"); + + println!("{:?}", actual.out); + assert!(actual.out.contains("moe")); + assert!(actual.out.contains("Maurice")); + assert!(actual.out.contains("23")); +} + +#[test] +fn find_in_table_keeps_row_with_multiple_matched_and_keeps_other_columns() { + let actual = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18] [William bill 60]] | find moe William"); + + println!("{:?}", actual.out); + assert!(actual.out.contains("moe")); + assert!(actual.out.contains("Maurice")); + assert!(actual.out.contains("23")); + assert!(actual.out.contains("William")); + assert!(actual.out.contains("will")); + assert!(actual.out.contains("18")); + assert!(actual.out.contains("bill")); + assert!(actual.out.contains("60")); +}