mirror of
https://github.com/nushell/nushell.git
synced 2024-12-23 15:39:06 +01:00
allow find
command to look in specified columns only (#8937)
# Description This PR allows the `find` command to search in specific columns using `--columns [col1 col2 col3]`. This is really meant to help with the `help` command in the std.nu. There are a few more things I want to look at so this is a draft for now. - [x] add example - [x] look at regex part # User-Facing Changes <!-- List of all changes that impact the user experience here. This helps us keep track of breaking changes. --> # 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 -A clippy::needless_collect` to check that you're using the standard code style - `cargo test --workspace` to check that all tests pass - `cargo run -- crates/nu-std/tests/run.nu` 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 > ``` --> # 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. -->
This commit is contained in:
parent
c8f54476c9
commit
393f424f1c
@ -58,6 +58,12 @@ impl Command for Find {
|
||||
"dotall regex mode: allow a dot . to match newlines \\n; equivalent to (?s)",
|
||||
Some('s'),
|
||||
)
|
||||
.named(
|
||||
"columns",
|
||||
SyntaxShape::List(Box::new(SyntaxShape::String)),
|
||||
"column names to be searched (with rest parameter, not regex yet)",
|
||||
Some('c'),
|
||||
)
|
||||
.switch("invert", "invert the match", Some('v'))
|
||||
.rest("rest", SyntaxShape::Any, "terms to search")
|
||||
.category(Category::Filters)
|
||||
@ -134,8 +140,33 @@ impl Command for Find {
|
||||
Example {
|
||||
description: "Remove ANSI sequences from result",
|
||||
example: "[[foo bar]; [abc 123] [def 456]] | find 123 | get bar | ansi strip",
|
||||
result: None,
|
||||
result: None, // This is None because ansi strip is not available in tests
|
||||
},
|
||||
Example {
|
||||
description: "Find and highlight text in specific columns",
|
||||
example: "[[col1 col2 col3]; [moe larry curly] [larry curly moe]] | find moe -c [col1 col3]",
|
||||
result: Some(Value::List {
|
||||
vals: vec![
|
||||
Value::test_record(
|
||||
vec!["col1".to_string(), "col2".to_string(), "col3".to_string()],
|
||||
vec![
|
||||
Value::test_string("\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m".to_string()),
|
||||
Value::test_string("larry".to_string()),
|
||||
Value::test_string("curly".to_string()),
|
||||
]
|
||||
),
|
||||
Value::test_record(
|
||||
vec!["col1".to_string(), "col2".to_string(), "col3".to_string()],
|
||||
vec![
|
||||
Value::test_string("larry".to_string()),
|
||||
Value::test_string("curly".to_string()),
|
||||
Value::test_string("\u{1b}[37m\u{1b}[0m\u{1b}[41;37mmoe\u{1b}[0m\u{1b}[37m\u{1b}[0m".to_string()),
|
||||
]
|
||||
),
|
||||
],
|
||||
span: Span::test_data(),
|
||||
}),
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -179,13 +210,13 @@ fn find_with_regex(
|
||||
|
||||
let flags = match (insensitive, multiline, dotall) {
|
||||
(false, false, false) => "",
|
||||
(true, false, false) => "(?i)",
|
||||
(false, true, false) => "(?m)",
|
||||
(false, false, true) => "(?s)",
|
||||
(true, true, false) => "(?im)",
|
||||
(true, false, true) => "(?is)",
|
||||
(false, true, true) => "(?ms)",
|
||||
(true, true, true) => "(?ims)",
|
||||
(true, false, false) => "(?i)", // case insensitive
|
||||
(false, true, false) => "(?m)", // multi-line mode
|
||||
(false, false, true) => "(?s)", // allow . to match \n
|
||||
(true, true, false) => "(?im)", // case insensitive and multi-line mode
|
||||
(true, false, true) => "(?is)", // case insensitive and allow . to match \n
|
||||
(false, true, true) => "(?ms)", // multi-line mode and allow . to match \n
|
||||
(true, true, true) => "(?ims)", // case insensitive, multi-line mode and allow . to match \n
|
||||
};
|
||||
|
||||
let regex = flags.to_string() + regex.as_str();
|
||||
@ -226,7 +257,9 @@ fn find_with_regex(
|
||||
)
|
||||
}
|
||||
|
||||
fn highlight_terms_in_record(
|
||||
#[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,
|
||||
@ -235,15 +268,24 @@ fn highlight_terms_in_record(
|
||||
string_style: Style,
|
||||
ls_colors: &LsColors,
|
||||
) -> Value {
|
||||
let cols_to_search = if search_cols.is_empty() {
|
||||
cols.to_vec()
|
||||
} else {
|
||||
search_cols.to_vec()
|
||||
};
|
||||
let mut output = vec![];
|
||||
for val in vals {
|
||||
let mut potential_output = vec![];
|
||||
let mut found_a_hit = false;
|
||||
for (cur_col, val) in cols.iter().zip(vals) {
|
||||
let val_str = val.into_string("", config);
|
||||
let lower_val = val.into_string("", config).to_lowercase();
|
||||
let mut term_added_to_output = false;
|
||||
for term in terms {
|
||||
let term_str = term.into_string("", config);
|
||||
let lower_term = term.into_string("", config).to_lowercase();
|
||||
if lower_val.contains(&lower_term) {
|
||||
if lower_val.contains(&lower_term) && cols_to_search.contains(cur_col) {
|
||||
found_a_hit = true;
|
||||
term_added_to_output = true;
|
||||
if config.use_ls_colors {
|
||||
// Get the original LS_COLORS color
|
||||
let style = ls_colors.style_for_path(val_str.clone());
|
||||
@ -263,11 +305,10 @@ fn highlight_terms_in_record(
|
||||
Ok(hi) => hi,
|
||||
Err(_) => string_style.paint(term_str.to_string()).to_string(),
|
||||
};
|
||||
output.push(Value::String {
|
||||
potential_output.push(Value::String {
|
||||
val: hi,
|
||||
span: *span,
|
||||
});
|
||||
term_added_to_output = true;
|
||||
} else {
|
||||
// No LS_COLORS support, so just use the original value
|
||||
let hi = match highlight_search_string(&val_str, &term_str, &string_style) {
|
||||
@ -282,9 +323,14 @@ fn highlight_terms_in_record(
|
||||
}
|
||||
}
|
||||
if !term_added_to_output {
|
||||
output.push(val.clone());
|
||||
potential_output.push(val.clone());
|
||||
}
|
||||
}
|
||||
|
||||
if found_a_hit {
|
||||
output.append(&mut potential_output);
|
||||
}
|
||||
|
||||
Value::Record {
|
||||
cols: cols.to_vec(),
|
||||
vals: output,
|
||||
@ -315,6 +361,7 @@ fn find_with_rest_and_highlight(
|
||||
}
|
||||
})
|
||||
.collect::<Vec<Value>>();
|
||||
let columns_to_search: Option<Vec<String>> = call.get_flag(&engine_state, stack, "columns")?;
|
||||
|
||||
let style_computer = StyleComputer::from_config(&engine_state, stack);
|
||||
// Currently, search results all use the same style.
|
||||
@ -328,20 +375,28 @@ fn find_with_rest_and_highlight(
|
||||
};
|
||||
let ls_colors = get_ls_colors(ls_colors_env_str);
|
||||
|
||||
let cols_to_search = match columns_to_search {
|
||||
Some(cols) => cols,
|
||||
None => vec![],
|
||||
};
|
||||
|
||||
match input {
|
||||
PipelineData::Empty => Ok(PipelineData::Empty),
|
||||
PipelineData::Value(_, _) => input
|
||||
.map(
|
||||
move |mut x| match &mut x {
|
||||
Value::Record { cols, vals, span } => highlight_terms_in_record(
|
||||
cols,
|
||||
vals,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
&ls_colors,
|
||||
),
|
||||
Value::Record { cols, vals, span } => {
|
||||
highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search,
|
||||
cols,
|
||||
vals,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
&ls_colors,
|
||||
)
|
||||
}
|
||||
_ => x,
|
||||
},
|
||||
ctrlc.clone(),
|
||||
@ -417,15 +472,18 @@ fn find_with_rest_and_highlight(
|
||||
PipelineData::ListStream(stream, meta) => Ok(ListStream::from_stream(
|
||||
stream
|
||||
.map(move |mut x| match &mut x {
|
||||
Value::Record { cols, vals, span } => highlight_terms_in_record(
|
||||
cols,
|
||||
vals,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
&ls_colors,
|
||||
),
|
||||
Value::Record { cols, vals, span } => {
|
||||
highlight_terms_in_record_with_search_columns(
|
||||
&cols_to_search,
|
||||
cols,
|
||||
vals,
|
||||
span,
|
||||
&config,
|
||||
&terms,
|
||||
string_style,
|
||||
&ls_colors,
|
||||
)
|
||||
}
|
||||
_ => x,
|
||||
})
|
||||
.filter(move |value| {
|
||||
|
Loading…
Reference in New Issue
Block a user