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 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<String>,
cols: &mut [String],
vals: &mut Vec<Value>,
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,
}
}

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"]"#);
}
#[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"));
}