Skip to content

Commit 1349187

Browse files
MudadaTangui
andauthored
Add --raw to find command (nushell#14970)
<!-- if this PR closes one or more issues, you can automatically link the PR with them by using one of the [*linking keywords*](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue#linking-a-pull-request-to-an-issue-using-a-keyword), e.g. - this PR should close #xxxx - fixes #xxxx you can also mention related issues, PRs or discussions! --> # 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. --> When using `find`, we insert ansi code. This is great for visual but it make comparison a tedious task. For exemple ```nu > ([{a: 1 b: 1}] | find 1 | get 0 | get a) == 1 # false ``` The documentation recommand using the `ansi strip` command but you then lose your typing converting it to a string. ```nu > [{a: 1 b: 1}] | find 1 | get 0 | get a | ansi strip | describe # string ``` And this makes me very sad 😢 . The idea here is to have a simple option to keep the usage of `find` without the ansi marking. ```nu > ([{a: 1 b: 1}] | find --raw 1 | get 0 | get a) == 1 # true ``` Tbh I think we could also do a fix on the parser to really escape the ansi makers but this sounded like way more work so I would like your opinion on this before working on it. Also note that this is my first time writting rust and trying to contribute to nushell so if you see any weird shenanigans be sure to tell me ! # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> A new flag for find # Tests + Formatting <!-- Don't forget to add tests that cover your changes. Make sure you've run and fixed any issues with these commands: - `cargo fmt --all -- --check` to check standard code formatting (`cargo fmt --all` applies these changes) - `cargo clippy --workspace -- -D warnings -D clippy::unwrap_used` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass (on Windows make sure to [enable developer mode](https://learn.microsoft.com/en-us/windows/apps/get-started/developer-mode-features-and-debugging)) - `cargo run -- -c "use toolkit.nu; toolkit test stdlib"` to run the tests for the standard library > **Note** > from `nushell` you can also use the `toolkit` as follows > ```bash > use toolkit.nu # or use an `env_change` hook to activate it automatically > toolkit check pr > ``` --> For testing I updated all the previous `find` test to also run them with this new flag just to be sure that we didn't lose any other functionalities # After Submitting <!-- If your PR had any user-facing changes, update [the documentation](https://github.com/nushell/nushell.github.io) after the PR is merged, if necessary. This will help us keep the docs up to date. --> --------- Co-authored-by: Tangui <mael.nicolas@clever-cloud.com>
1 parent b55ed69 commit 1349187

File tree

2 files changed

+112
-12
lines changed

2 files changed

+112
-12
lines changed

crates/nu-command/src/filters/find.rs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ impl Command for Find {
5252
"column names to be searched (with rest parameter, not regex yet)",
5353
Some('c'),
5454
)
55+
.switch(
56+
"no-highlight",
57+
"no-highlight mode: find without marking with ascii code",
58+
Some('n'),
59+
)
5560
.switch("invert", "invert the match", Some('v'))
5661
.rest("rest", SyntaxShape::Any, "Terms to search.")
5762
.category(Category::Filters)
@@ -161,8 +166,15 @@ impl Command for Find {
161166
},
162167
Example {
163168
description: "Remove ANSI sequences from result",
164-
example: "[[foo bar]; [abc 123] [def 456]] | find 123 | get bar | ansi strip",
165-
result: None, // This is None because ansi strip is not available in tests
169+
example:"[[foo bar]; [abc 123] [def 456]] | find --no-highlight 123",
170+
result: Some(Value::list(
171+
vec![Value::test_record(record! {
172+
"foo" => Value::test_string("abc"),
173+
"bar" => Value::test_int(123)
174+
}
175+
)],
176+
Span::test_data(),
177+
))
166178
},
167179
Example {
168180
description: "Find and highlight text in specific columns",
@@ -350,6 +362,7 @@ fn find_with_rest_and_highlight(
350362
let span = call.head;
351363
let config = stack.get_config(engine_state);
352364
let filter_config = config.clone();
365+
let no_highlight = call.has_flag(engine_state, stack, "no-highlight")?;
353366
let invert = call.has_flag(engine_state, stack, "invert")?;
354367
let terms = call.rest::<Value>(engine_state, stack, 0)?;
355368
let lower_terms = terms
@@ -377,6 +390,9 @@ fn find_with_rest_and_highlight(
377390
.map(
378391
move |mut x| {
379392
let span = x.span();
393+
if no_highlight {
394+
return x;
395+
};
380396
match &mut x {
381397
Value::Record { val, .. } => highlight_terms_in_record_with_search_columns(
382398
&cols_to_search_in_map,
@@ -417,6 +433,9 @@ fn find_with_rest_and_highlight(
417433
let stream = stream.modify(|iter| {
418434
iter.map(move |mut x| {
419435
let span = x.span();
436+
if no_highlight {
437+
return x;
438+
};
420439
match &mut x {
421440
Value::Record { val, .. } => highlight_terms_in_record_with_search_columns(
422441
&cols_to_search_in_map,
@@ -458,15 +477,19 @@ fn find_with_rest_and_highlight(
458477
let lower_val = line.to_lowercase();
459478
for term in &terms {
460479
if lower_val.contains(term) {
461-
output.push(Value::string(
462-
highlight_search_string(
463-
&line,
464-
term,
465-
&string_style,
466-
&highlight_style,
467-
)?,
468-
span,
469-
))
480+
if no_highlight {
481+
output.push(Value::string(&line, span))
482+
} else {
483+
output.push(Value::string(
484+
highlight_search_string(
485+
&line,
486+
term,
487+
&string_style,
488+
&highlight_style,
489+
)?,
490+
span,
491+
))
492+
}
470493
}
471494
}
472495
}

crates/nu-command/tests/commands/find.rs

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,130 +3,179 @@ use nu_test_support::nu;
33
#[test]
44
fn find_with_list_search_with_string() {
55
let actual = nu!("[moe larry curly] | find moe | get 0");
6+
let actual_no_highlight = nu!("[moe larry curly] | find --no-highlight moe | get 0");
67

78
assert_eq!(
89
actual.out,
910
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m"
1011
);
12+
assert_eq!(actual_no_highlight.out, "moe");
1113
}
1214

1315
#[test]
1416
fn find_with_list_search_with_char() {
1517
let actual = nu!("[moe larry curly] | find l | to json -r");
18+
let actual_no_highlight = nu!("[moe larry curly] | find --no-highlight l | to json -r");
1619

1720
assert_eq!(actual.out, "[\"\\u001b[37m\\u001b[0m\\u001b[41;37ml\\u001b[0m\\u001b[37marry\\u001b[0m\",\"\\u001b[37mcur\\u001b[0m\\u001b[41;37ml\\u001b[0m\\u001b[37my\\u001b[0m\"]");
21+
assert_eq!(actual_no_highlight.out, "[\"larry\",\"curly\"]");
1822
}
1923

2024
#[test]
2125
fn find_with_bytestream_search_with_char() {
2226
let actual =
2327
nu!("\"ABC\" | save foo.txt; let res = open foo.txt | find abc; rm foo.txt; $res | get 0");
28+
let actual_no_highlight =
29+
nu!("\"ABC\" | save foo.txt; let res = open foo.txt | find --no-highlight abc; rm foo.txt; $res | get 0");
30+
2431
assert_eq!(
2532
actual.out,
2633
"\u{1b}[37m\u{1b}[0m\u{1b}[41;37mABC\u{1b}[0m\u{1b}[37m\u{1b}[0m"
27-
)
34+
);
35+
assert_eq!(actual_no_highlight.out, "ABC");
2836
}
2937

3038
#[test]
3139
fn find_with_list_search_with_number() {
3240
let actual = nu!("[1 2 3 4 5] | find 3 | get 0");
41+
let actual_no_highlight = nu!("[1 2 3 4 5] | find --no-highlight 3 | get 0");
3342

3443
assert_eq!(actual.out, "3");
44+
assert_eq!(actual_no_highlight.out, "3");
3545
}
3646

3747
#[test]
3848
fn find_with_string_search_with_string() {
3949
let actual = nu!("echo Cargo.toml | find toml");
50+
let actual_no_highlight = nu!("echo Cargo.toml | find --no-highlight toml");
4051

4152
assert_eq!(
4253
actual.out,
4354
"\u{1b}[37mCargo.\u{1b}[0m\u{1b}[41;37mtoml\u{1b}[0m\u{1b}[37m\u{1b}[0m"
4455
);
56+
assert_eq!(actual_no_highlight.out, "Cargo.toml");
4557
}
4658

4759
#[test]
4860
fn find_with_string_search_with_string_not_found() {
4961
let actual = nu!("[moe larry curly] | find shemp | is-empty");
62+
let actual_no_highlight = nu!("[moe larry curly] | find --no-highlight shemp | is-empty");
5063

5164
assert_eq!(actual.out, "true");
65+
assert_eq!(actual_no_highlight.out, "true");
5266
}
5367

5468
#[test]
5569
fn find_with_filepath_search_with_string() {
5670
let actual =
5771
nu!(r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find arep | to json -r"#);
72+
let actual_no_highlight = nu!(
73+
r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find --no-highlight arep | to json -r"#
74+
);
5875

5976
assert_eq!(
6077
actual.out,
6178
"[\"\\u001b[37m\\u001b[0m\\u001b[41;37marep\\u001b[0m\\u001b[37mas.clu\\u001b[0m\"]"
6279
);
80+
assert_eq!(actual_no_highlight.out, "[\"arepas.clu\"]");
6381
}
6482

6583
#[test]
6684
fn find_with_filepath_search_with_multiple_patterns() {
6785
let actual =
6886
nu!(r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find arep ami | to json -r"#);
87+
let actual_no_highlight = nu!(
88+
r#"["amigos.txt","arepas.clu","los.txt","tres.txt"] | find --no-highlight arep ami | to json -r"#
89+
);
6990

7091
assert_eq!(actual.out, "[\"\\u001b[37m\\u001b[0m\\u001b[41;37mami\\u001b[0m\\u001b[37mgos.txt\\u001b[0m\",\"\\u001b[37m\\u001b[0m\\u001b[41;37marep\\u001b[0m\\u001b[37mas.clu\\u001b[0m\"]");
92+
assert_eq!(actual_no_highlight.out, "[\"amigos.txt\",\"arepas.clu\"]");
7193
}
7294

7395
#[test]
7496
fn find_takes_into_account_linebreaks_in_string() {
7597
let actual = nu!(r#""atest\nanothertest\nnohit\n" | find a | length"#);
98+
let actual_no_highlight =
99+
nu!(r#""atest\nanothertest\nnohit\n" | find --no-highlight a | length"#);
76100

77101
assert_eq!(actual.out, "2");
102+
assert_eq!(actual_no_highlight.out, "2");
78103
}
79104

80105
#[test]
81106
fn find_with_regex_in_table_keeps_row_if_one_column_matches() {
82107
let actual = nu!(
83108
"[[name nickname]; [Maurice moe] [Laurence larry]] | find --regex ce | get name | to json -r"
84109
);
110+
let actual_no_highlight = nu!(
111+
"[[name nickname]; [Maurice moe] [Laurence larry]] | find --no-highlight --regex ce | get name | to json -r"
112+
);
85113

86114
assert_eq!(actual.out, r#"["Maurice","Laurence"]"#);
115+
assert_eq!(actual_no_highlight.out, r#"["Maurice","Laurence"]"#);
87116
}
88117

89118
#[test]
90119
fn inverted_find_with_regex_in_table_keeps_row_if_none_of_the_columns_matches() {
91120
let actual = nu!(
92121
"[[name nickname]; [Maurice moe] [Laurence larry]] | find --regex moe --invert | get name | to json -r"
93122
);
123+
let actual_no_highlight = nu!(
124+
"[[name nickname]; [Maurice moe] [Laurence larry]] | find --no-highlight --regex moe --invert | get name | to json -r"
125+
);
94126

95127
assert_eq!(actual.out, r#"["Laurence"]"#);
128+
assert_eq!(actual_no_highlight.out, r#"["Laurence"]"#);
96129
}
97130

98131
#[test]
99132
fn find_in_table_only_keep_rows_with_matches_on_selected_columns() {
100133
let actual = nu!(
101134
"[[name nickname]; [Maurice moe] [Laurence larry]] | find r --columns [nickname] | get name | to json -r"
102135
);
136+
let actual_no_highlight = nu!(
137+
"[[name nickname]; [Maurice moe] [Laurence larry]] | find r --no-highlight --columns [nickname] | get name | to json -r"
138+
);
103139

104140
assert!(actual.out.contains("Laurence"));
105141
assert!(!actual.out.contains("Maurice"));
142+
assert!(actual_no_highlight.out.contains("Laurence"));
143+
assert!(!actual_no_highlight.out.contains("Maurice"));
106144
}
107145

108146
#[test]
109147
fn inverted_find_in_table_keeps_row_if_none_of_the_selected_columns_matches() {
110148
let actual = nu!(
111149
"[[name nickname]; [Maurice moe] [Laurence larry]] | find r --columns [nickname] --invert | get name | to json -r"
112150
);
151+
let actual_no_highlight = nu!(
152+
"[[name nickname]; [Maurice moe] [Laurence larry]] | find r --no-highlight --columns [nickname] --invert | get name | to json -r"
153+
);
113154

114155
assert_eq!(actual.out, r#"["Maurice"]"#);
156+
assert_eq!(actual_no_highlight.out, r#"["Maurice"]"#);
115157
}
116158

117159
#[test]
118160
fn find_in_table_keeps_row_with_single_matched_and_keeps_other_columns() {
119161
let actual = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18]] | find Maurice");
162+
let actual_no_highlight = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18]] | find --no-highlight Maurice");
120163

121164
println!("{:?}", actual.out);
122165
assert!(actual.out.contains("moe"));
123166
assert!(actual.out.contains("Maurice"));
124167
assert!(actual.out.contains("23"));
168+
169+
println!("{:?}", actual_no_highlight.out);
170+
assert!(actual_no_highlight.out.contains("moe"));
171+
assert!(actual_no_highlight.out.contains("Maurice"));
172+
assert!(actual_no_highlight.out.contains("23"));
125173
}
126174

127175
#[test]
128176
fn find_in_table_keeps_row_with_multiple_matched_and_keeps_other_columns() {
129177
let actual = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18] [William bill 60]] | find moe William");
178+
let actual_no_highlight = nu!("[[name nickname Age]; [Maurice moe 23] [Laurence larry 67] [William will 18] [William bill 60]] | find --no-highlight moe William");
130179

131180
println!("{:?}", actual.out);
132181
assert!(actual.out.contains("moe"));
@@ -137,64 +186,92 @@ fn find_in_table_keeps_row_with_multiple_matched_and_keeps_other_columns() {
137186
assert!(actual.out.contains("18"));
138187
assert!(actual.out.contains("bill"));
139188
assert!(actual.out.contains("60"));
189+
190+
println!("{:?}", actual_no_highlight.out);
191+
assert!(actual_no_highlight.out.contains("moe"));
192+
assert!(actual_no_highlight.out.contains("Maurice"));
193+
assert!(actual_no_highlight.out.contains("23"));
194+
assert!(actual_no_highlight.out.contains("William"));
195+
assert!(actual_no_highlight.out.contains("will"));
196+
assert!(actual_no_highlight.out.contains("18"));
197+
assert!(actual_no_highlight.out.contains("bill"));
198+
assert!(actual_no_highlight.out.contains("60"));
140199
}
141200

142201
#[test]
143202
fn find_with_string_search_with_special_char_1() {
144203
let actual = nu!("[[d]; [a?b] [a*b] [a{1}b] ] | find '?' | to json -r");
204+
let actual_no_highlight =
205+
nu!("[[d]; [a?b] [a*b] [a{1}b] ] | find --no-highlight '?' | to json -r");
145206

146207
assert_eq!(
147208
actual.out,
148209
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m?\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
149210
);
211+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a?b\"}]");
150212
}
151213

152214
#[test]
153215
fn find_with_string_search_with_special_char_2() {
154216
let actual = nu!("[[d]; [a?b] [a*b] [a{1}b]] | find '*' | to json -r");
217+
let actual_no_highlight =
218+
nu!("[[d]; [a?b] [a*b] [a{1}b]] | find --no-highlight '*' | to json -r");
155219

156220
assert_eq!(
157221
actual.out,
158222
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m*\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
159223
);
224+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a*b\"}]");
160225
}
161226

162227
#[test]
163228
fn find_with_string_search_with_special_char_3() {
164229
let actual = nu!("[[d]; [a?b] [a*b] [a{1}b] ] | find '{1}' | to json -r");
230+
let actual_no_highlight =
231+
nu!("[[d]; [a?b] [a*b] [a{1}b] ] | find --no-highlight '{1}' | to json -r");
165232

166233
assert_eq!(
167234
actual.out,
168235
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m{1}\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
169236
);
237+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a{1}b\"}]");
170238
}
171239

172240
#[test]
173241
fn find_with_string_search_with_special_char_4() {
174242
let actual = nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find '[' | to json -r");
243+
let actual_no_highlight =
244+
nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find --no-highlight '[' | to json -r");
175245

176246
assert_eq!(
177247
actual.out,
178248
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m[\\u001b[0m\\u001b[37m]b\\u001b[0m\"}]"
179249
);
250+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
180251
}
181252

182253
#[test]
183254
fn find_with_string_search_with_special_char_5() {
184255
let actual = nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find ']' | to json -r");
256+
let actual_no_highlight =
257+
nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find --no-highlight ']' | to json -r");
185258

186259
assert_eq!(
187260
actual.out,
188261
"[{\"d\":\"\\u001b[37ma[\\u001b[0m\\u001b[41;37m]\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
189262
);
263+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
190264
}
191265

192266
#[test]
193267
fn find_with_string_search_with_special_char_6() {
194268
let actual = nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find '[]' | to json -r");
269+
let actual_no_highlight =
270+
nu!("[{d: a?b} {d: a*b} {d: a{1}b} {d: a[]b}] | find --no-highlight '[]' | to json -r");
195271

196272
assert_eq!(
197273
actual.out,
198274
"[{\"d\":\"\\u001b[37ma\\u001b[0m\\u001b[41;37m[]\\u001b[0m\\u001b[37mb\\u001b[0m\"}]"
199275
);
276+
assert_eq!(actual_no_highlight.out, "[{\"d\":\"a[]b\"}]");
200277
}

0 commit comments

Comments
 (0)