From 6530403ff8e36bbc292b4dbc5c4e97e866443995 Mon Sep 17 00:00:00 2001 From: Georgiana Grigoreanu <90071779+Geox644@users.noreply.github.com> Date: Tue, 30 Jan 2024 16:06:20 +0200 Subject: [PATCH] Highlights find upgrade (#11509) this PR should close #9105 # Description I have implemented highlights for find which work for all strings. The implementation also works for lists, but with exceptions (for example, it does not work for list of lists). The implementation is also not implemented for --regex. --------- Co-authored-by: Georgiana Co-authored-by: Darren Schroeder <343840+fdncred@users.noreply.github.com> --- crates/nu-command/src/filters/find.rs | 39 ++++++++++++++++++++++-- crates/nu-command/tests/commands/find.rs | 19 +++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/crates/nu-command/src/filters/find.rs b/crates/nu-command/src/filters/find.rs index 709a98a7ee..7148507820 100644 --- a/crates/nu-command/src/filters/find.rs +++ b/crates/nu-command/src/filters/find.rs @@ -75,9 +75,9 @@ impl Command for Find { result: None, }, Example { - description: "Search for a term in a string", + description: "Search and highlight text for a term in a string", example: r#"'Cargo.toml' | find toml"#, - result: Some(Value::test_string("Cargo.toml".to_owned())), + result: Some(Value::test_string("\u{1b}[37mCargo.\u{1b}[0m\u{1b}[41;37mtoml\u{1b}[0m\u{1b}[37m\u{1b}[0m".to_owned())), }, Example { description: "Search a number or a file size in a list of numbers", @@ -91,7 +91,7 @@ impl Command for Find { description: "Search a char in a list of string", example: r#"[moe larry curly] | find l"#, result: Some(Value::list( - vec![Value::test_string("larry"), Value::test_string("curly")], + vec![Value::test_string("\u{1b}[37m\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37marry\u{1b}[0m"), Value::test_string("\u{1b}[37mcur\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37my\u{1b}[0m")], Span::test_data(), )), }, @@ -276,6 +276,31 @@ where }) } +fn highlight_terms_in_string( + val: &Value, + span: Span, + config: &Config, + terms: &[Value], + string_style: Style, + highlight_style: Style, +) -> Value { + let val_str = val.into_string("", config); + + if let Some(term) = terms + .iter() + .find(|term| contains_ignore_case(&val_str, &term.into_string("", config))) + { + let term_str = term.into_string("", config); + let highlighted_str = + highlight_search_string(&val_str, &term_str, &string_style, &highlight_style) + .unwrap_or_else(|_| string_style.paint(&term_str).to_string()); + + return Value::string(highlighted_str, span); + } + + val.clone() +} + #[allow(clippy::too_many_arguments)] fn highlight_terms_in_record_with_search_columns( search_cols: &[String], @@ -369,6 +394,14 @@ fn find_with_rest_and_highlight( string_style, highlight_style, ), + Value::String { .. } => highlight_terms_in_string( + &x, + span, + &config, + &terms, + string_style, + highlight_style, + ), _ => x, } }, diff --git a/crates/nu-command/tests/commands/find.rs b/crates/nu-command/tests/commands/find.rs index 139244496b..a1c4a208a8 100644 --- a/crates/nu-command/tests/commands/find.rs +++ b/crates/nu-command/tests/commands/find.rs @@ -4,14 +4,17 @@ use nu_test_support::nu; fn find_with_list_search_with_string() { let actual = nu!("[moe larry curly] | find moe | get 0"); - assert_eq!(actual.out, "moe"); + assert_eq!( + actual.out, + "\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m" + ); } #[test] fn find_with_list_search_with_char() { let actual = nu!("[moe larry curly] | find l | to json -r"); - assert_eq!(actual.out, r#"["larry","curly"]"#); + assert_eq!(actual.out, "[\"\u{1b}[37m\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37marry\u{1b}[0m\",\"\u{1b}[37mcur\u{1b}[0m\u{1b}[41;37ml\u{1b}[0m\u{1b}[37my\u{1b}[0m\"]"); } #[test] @@ -25,7 +28,10 @@ fn find_with_list_search_with_number() { fn find_with_string_search_with_string() { let actual = nu!("echo Cargo.toml | find toml"); - assert_eq!(actual.out, "Cargo.toml"); + assert_eq!( + actual.out, + "\u{1b}[37mCargo.\u{1b}[0m\u{1b}[41;37mtoml\u{1b}[0m\u{1b}[37m\u{1b}[0m" + ); } #[test] @@ -40,7 +46,10 @@ fn find_with_filepath_search_with_string() { let actual = nu!(r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find arep | to json -r"#); - assert_eq!(actual.out, r#"["arepas.clu"]"#); + assert_eq!( + actual.out, + "[\"\u{1b}[37m\u{1b}[0m\u{1b}[41;37marep\u{1b}[0m\u{1b}[37mas.clu\u{1b}[0m\"]" + ); } #[test] @@ -48,7 +57,7 @@ fn find_with_filepath_search_with_multiple_patterns() { let actual = nu!(r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find arep ami | to json -r"#); - assert_eq!(actual.out, r#"["amigos.txt","arepas.clu"]"#); + assert_eq!(actual.out, "[\"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mami\u{1b}[0m\u{1b}[37mgos.txt\u{1b}[0m\",\"\u{1b}[37m\u{1b}[0m\u{1b}[41;37marep\u{1b}[0m\u{1b}[37mas.clu\u{1b}[0m\"]"); } #[test]