Fix find puts extra cols into record (#9397)

# Description
<!--
Thank you for improving Nushell. Please, check our [contributing
guide](../CONTRIBUTING.md) and talk to the core team before making major
changes.

Description of your pull request goes here. **Provide examples and/or
screenshots** if your changes affect the user experience.
-->

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.
This commit is contained in:
Astrick 2023-06-10 17:57:26 -04:00 committed by GitHub
parent 0bdc362e13
commit e9508b578a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 58 additions and 30 deletions

View File

@ -1,3 +1,4 @@
use itertools::Itertools;
use nu_cmd_lang::help::highlight_search_string; use nu_cmd_lang::help::highlight_search_string;
use fancy_regex::Regex; use fancy_regex::Regex;
@ -292,9 +293,9 @@ fn record_matches_regex(values: &[Value], re: &Regex, config: &Config) -> bool {
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn highlight_terms_in_record_with_search_columns( fn highlight_terms_in_record_with_search_columns(
search_cols: &Vec<String>, search_cols: &Vec<String>,
cols: &mut [String], cols: &[String],
vals: &mut Vec<Value>, vals: &[Value],
span: &mut Span, span: &Span,
config: &Config, config: &Config,
terms: &[Value], terms: &[Value],
string_style: Style, string_style: Style,
@ -305,38 +306,40 @@ fn highlight_terms_in_record_with_search_columns(
} else { } else {
search_cols.to_vec() 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 // iterator of Ok((val_str, term_str)) pairs if the value should be highlighted, otherwise Err(val)
for (cur_col, val) in cols.iter().zip(vals) { let try_val_highlight = vals.iter().zip(cols).map(|(val, col)| {
let val_str = val.into_string("", config); let val_str = val.into_string("", config);
for term in terms { let predicate = cols_to_search.contains(col);
let term_str = term.into_string("", config); predicate
let output_value = .then_some(val_str)
if contains_ignore_case(&val_str, &term_str) && cols_to_search.contains(cur_col) { .and_then(|val_str| {
let highlighted_str = match highlight_search_string( term_strs
&val_str, .iter()
&term_str, .find(|term_str| contains_ignore_case(&val_str, term_str))
&string_style, .map(|term_str| (val_str, term_str))
&highlight_style, })
) { .ok_or_else(|| val.clone())
Ok(highlighted_str) => highlighted_str, });
Err(_) => string_style.paint(term_str).to_string(),
}; // 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 { Value::String {
val: highlighted_str, val: highlighted_str,
span: *span, span: *span,
} }
} else { })
val.clone() .map(|v| v.unwrap_or_else(|v| v));
};
output.push(output_value);
}
}
Value::Record { Value::Record {
cols: cols.to_vec(), cols: cols.to_vec(),
vals: output, vals: new_vals.collect(),
span: *span, span: *span,
} }
} }

View File

@ -94,3 +94,28 @@ fn inverted_find_in_table_keeps_row_if_none_of_the_selected_columns_matches() {
assert_eq!(actual.out, r#"["Maurice"]"#); 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"));
}