mirror of
https://github.com/nushell/nushell.git
synced 2025-02-02 03:30:16 +01:00
enable find to be able to highlight some hits (#6086)
* enable find to be able to highlight some hits * oops, deps in the wrong place
This commit is contained in:
parent
a35a71fd82
commit
db9b88089e
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2806,6 +2806,7 @@ name = "nu-utils"
|
|||||||
version = "0.65.1"
|
version = "0.65.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossterm_winapi",
|
"crossterm_winapi",
|
||||||
|
"lscolors",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -344,7 +344,7 @@ You can also learn more at https://www.nushell.sh/book/"#;
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Highlight the search string using ANSI escape sequences and regular expressions.
|
// Highlight the search string using ANSI escape sequences and regular expressions.
|
||||||
fn highlight_search_string(
|
pub fn highlight_search_string(
|
||||||
haystack: &str,
|
haystack: &str,
|
||||||
needle: &str,
|
needle: &str,
|
||||||
string_style: &Style,
|
string_style: &Style,
|
||||||
|
@ -14,7 +14,7 @@ mod export_env;
|
|||||||
mod export_extern;
|
mod export_extern;
|
||||||
mod extern_;
|
mod extern_;
|
||||||
mod for_;
|
mod for_;
|
||||||
mod help;
|
pub mod help;
|
||||||
mod hide;
|
mod hide;
|
||||||
mod if_;
|
mod if_;
|
||||||
mod ignore;
|
mod ignore;
|
||||||
|
@ -1,10 +1,15 @@
|
|||||||
use nu_engine::{eval_block, CallExt};
|
use crate::help::highlight_search_string;
|
||||||
|
use lscolors::Style as LsColors_Style;
|
||||||
|
use nu_ansi_term::{Color::Default, Style};
|
||||||
|
use nu_color_config::get_color_config;
|
||||||
|
use nu_engine::{env_to_string, eval_block, CallExt};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{CaptureBlock, Command, EngineState, Stack},
|
engine::{CaptureBlock, Command, EngineState, Stack},
|
||||||
Category, Example, IntoInterruptiblePipelineData, PipelineData, ShellError, Signature, Span,
|
Category, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, ShellError,
|
||||||
SyntaxShape, Value,
|
Signature, Span, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
|
use nu_utils::get_ls_colors;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@ -149,7 +154,7 @@ impl Command for Find {
|
|||||||
find_with_predicate(predicate, engine_state, stack, call, input)
|
find_with_predicate(predicate, engine_state, stack, call, input)
|
||||||
}
|
}
|
||||||
(Some(regex), None) => find_with_regex(regex, engine_state, stack, call, input),
|
(Some(regex), None) => find_with_regex(regex, engine_state, stack, call, input),
|
||||||
(None, None) => find_with_rest(engine_state, stack, call, input),
|
(None, None) => find_with_rest_and_highlight(engine_state, stack, call, input),
|
||||||
(Some(_), Some(_)) => Err(ShellError::IncompatibleParametersSingle(
|
(Some(_), Some(_)) => Err(ShellError::IncompatibleParametersSingle(
|
||||||
"expected either predicate or regex flag, not both".to_owned(),
|
"expected either predicate or regex flag, not both".to_owned(),
|
||||||
call.head,
|
call.head,
|
||||||
@ -265,7 +270,7 @@ fn find_with_predicate(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_with_rest(
|
fn find_with_rest_and_highlight(
|
||||||
engine_state: &EngineState,
|
engine_state: &EngineState,
|
||||||
stack: &mut Stack,
|
stack: &mut Stack,
|
||||||
call: &Call,
|
call: &Call,
|
||||||
@ -273,11 +278,10 @@ fn find_with_rest(
|
|||||||
) -> Result<PipelineData, ShellError> {
|
) -> Result<PipelineData, ShellError> {
|
||||||
let span = call.head;
|
let span = call.head;
|
||||||
let ctrlc = engine_state.ctrlc.clone();
|
let ctrlc = engine_state.ctrlc.clone();
|
||||||
let metadata = input.metadata();
|
|
||||||
let engine_state = engine_state.clone();
|
let engine_state = engine_state.clone();
|
||||||
let config = engine_state.get_config().clone();
|
let config = engine_state.get_config().clone();
|
||||||
|
let filter_config = engine_state.get_config().clone();
|
||||||
let invert = call.has_flag("invert");
|
let invert = call.has_flag("invert");
|
||||||
|
|
||||||
let terms = call.rest::<Value>(&engine_state, stack, 0)?;
|
let terms = call.rest::<Value>(&engine_state, stack, 0)?;
|
||||||
let lower_terms = terms
|
let lower_terms = terms
|
||||||
.iter()
|
.iter()
|
||||||
@ -290,7 +294,20 @@ fn find_with_rest(
|
|||||||
})
|
})
|
||||||
.collect::<Vec<Value>>();
|
.collect::<Vec<Value>>();
|
||||||
|
|
||||||
let pipe = input.filter(
|
let color_hm = get_color_config(&config);
|
||||||
|
let default_style = Style::new().fg(Default).on(Default);
|
||||||
|
let string_style = match color_hm.get("string") {
|
||||||
|
Some(style) => *style,
|
||||||
|
None => default_style,
|
||||||
|
};
|
||||||
|
let ls_colors_env_str = match stack.get_env_var(&engine_state, "LS_COLORS") {
|
||||||
|
Some(v) => Some(env_to_string("LS_COLORS", &v, &engine_state, stack)?),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
let ls_colors = get_ls_colors(ls_colors_env_str);
|
||||||
|
|
||||||
|
match input {
|
||||||
|
PipelineData::Value(_, _) => input.filter(
|
||||||
move |value| {
|
move |value| {
|
||||||
let lower_value = if let Ok(span) = value.span() {
|
let lower_value = if let Ok(span) = value.span() {
|
||||||
Value::string(value.into_string("", &config).to_lowercase(), span)
|
Value::string(value.into_string("", &config).to_lowercase(), span)
|
||||||
@ -298,6 +315,123 @@ fn find_with_rest(
|
|||||||
value.clone()
|
value.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
lower_terms.iter().any(|term| match value {
|
||||||
|
Value::Bool { .. }
|
||||||
|
| Value::Int { .. }
|
||||||
|
| Value::Filesize { .. }
|
||||||
|
| Value::Duration { .. }
|
||||||
|
| Value::Date { .. }
|
||||||
|
| Value::Range { .. }
|
||||||
|
| Value::Float { .. }
|
||||||
|
| Value::Block { .. }
|
||||||
|
| Value::Nothing { .. }
|
||||||
|
| Value::Error { .. } => lower_value
|
||||||
|
.eq(span, term, span)
|
||||||
|
.map_or(false, |val| val.is_true()),
|
||||||
|
Value::String { .. }
|
||||||
|
| Value::List { .. }
|
||||||
|
| Value::CellPath { .. }
|
||||||
|
| Value::CustomValue { .. } => term
|
||||||
|
.r#in(span, &lower_value, span)
|
||||||
|
.map_or(false, |val| val.is_true()),
|
||||||
|
Value::Record { vals, .. } => vals.iter().any(|val| {
|
||||||
|
if let Ok(span) = val.span() {
|
||||||
|
let lower_val = Value::string(
|
||||||
|
val.into_string("", &config).to_lowercase(),
|
||||||
|
Span::test_data(),
|
||||||
|
);
|
||||||
|
|
||||||
|
term.r#in(span, &lower_val, span)
|
||||||
|
.map_or(false, |aval| aval.is_true())
|
||||||
|
} else {
|
||||||
|
term.r#in(span, val, span)
|
||||||
|
.map_or(false, |aval| aval.is_true())
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
Value::Binary { .. } => false,
|
||||||
|
}) != invert
|
||||||
|
},
|
||||||
|
ctrlc,
|
||||||
|
),
|
||||||
|
PipelineData::ListStream(stream, meta) => {
|
||||||
|
Ok(ListStream::from_stream(
|
||||||
|
stream
|
||||||
|
.map(move |mut x| match &mut x {
|
||||||
|
Value::Record { cols, vals, span } => {
|
||||||
|
let mut output = vec![];
|
||||||
|
for val in 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.clone() {
|
||||||
|
let term_str = term.into_string("", &config);
|
||||||
|
let lower_term = term.into_string("", &config).to_lowercase();
|
||||||
|
if lower_val.contains(&lower_term) {
|
||||||
|
if config.use_ls_colors {
|
||||||
|
// Get the original LS_COLORS color
|
||||||
|
let style = ls_colors.style_for_path(val_str.clone());
|
||||||
|
let ansi_style = style
|
||||||
|
.map(LsColors_Style::to_crossterm_style)
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
|
let ls_colored_val =
|
||||||
|
ansi_style.apply(&val_str).to_string();
|
||||||
|
let hi = match highlight_search_string(
|
||||||
|
&ls_colored_val,
|
||||||
|
&term_str,
|
||||||
|
&string_style,
|
||||||
|
) {
|
||||||
|
Ok(hi) => hi,
|
||||||
|
Err(_) => string_style
|
||||||
|
.paint(term_str.to_string())
|
||||||
|
.to_string(),
|
||||||
|
};
|
||||||
|
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,
|
||||||
|
) {
|
||||||
|
Ok(hi) => hi,
|
||||||
|
Err(_) => string_style
|
||||||
|
.paint(term_str.to_string())
|
||||||
|
.to_string(),
|
||||||
|
};
|
||||||
|
output.push(Value::String {
|
||||||
|
val: hi,
|
||||||
|
span: *span,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !term_added_to_output {
|
||||||
|
output.push(val.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Value::Record {
|
||||||
|
cols: cols.to_vec(),
|
||||||
|
vals: output,
|
||||||
|
span: *span,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => x,
|
||||||
|
})
|
||||||
|
.filter(move |value| {
|
||||||
|
let lower_value = if let Ok(span) = value.span() {
|
||||||
|
Value::string(
|
||||||
|
value.into_string("", &filter_config).to_lowercase(),
|
||||||
|
span,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
value.clone()
|
||||||
|
};
|
||||||
|
|
||||||
lower_terms.iter().any(|term| match value {
|
lower_terms.iter().any(|term| match value {
|
||||||
Value::Bool { .. }
|
Value::Bool { .. }
|
||||||
| Value::Int { .. }
|
| Value::Int { .. }
|
||||||
@ -320,7 +454,7 @@ fn find_with_rest(
|
|||||||
Value::Record { vals, .. } => vals.iter().any(|val| {
|
Value::Record { vals, .. } => vals.iter().any(|val| {
|
||||||
if let Ok(span) = val.span() {
|
if let Ok(span) = val.span() {
|
||||||
let lower_val = Value::string(
|
let lower_val = Value::string(
|
||||||
val.into_string("", &config).to_lowercase(),
|
val.into_string("", &filter_config).to_lowercase(),
|
||||||
Span::test_data(),
|
Span::test_data(),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -333,13 +467,20 @@ fn find_with_rest(
|
|||||||
}),
|
}),
|
||||||
Value::Binary { .. } => false,
|
Value::Binary { .. } => false,
|
||||||
}) != invert
|
}) != invert
|
||||||
},
|
}),
|
||||||
ctrlc,
|
ctrlc.clone(),
|
||||||
)?;
|
)
|
||||||
|
.into_pipeline_data(ctrlc)
|
||||||
match metadata {
|
.set_metadata(meta))
|
||||||
Some(m) => Ok(pipe.into_pipeline_data_with_metadata(m, engine_state.ctrlc.clone())),
|
}
|
||||||
None => Ok(pipe),
|
// PipelineData::ExternalStream {
|
||||||
|
// stdout,
|
||||||
|
// stderr,
|
||||||
|
// exit_code,
|
||||||
|
// span,
|
||||||
|
// metadata,
|
||||||
|
// } => todo!(),
|
||||||
|
_ => todo!(), // not sure what to do here
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -12,6 +12,7 @@ name = "utils"
|
|||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
lscolors = { version = "0.10.0", features = ["crossterm"]}
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
crossterm_winapi = "0.9.0"
|
crossterm_winapi = "0.9.0"
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
pub mod utils;
|
pub mod utils;
|
||||||
|
|
||||||
pub use utils::{enable_vt_processing, stderr_write_all_and_flush, stdout_write_all_and_flush};
|
pub use utils::{
|
||||||
|
enable_vt_processing, get_ls_colors, stderr_write_all_and_flush, stdout_write_all_and_flush,
|
||||||
|
};
|
||||||
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue
Block a user