highlight term on PipelineData::Value() (#6997)

This commit is contained in:
David Matos 2022-11-04 14:42:16 +01:00 committed by GitHub
parent ecfee4c542
commit ca9bf19041
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -1,13 +1,14 @@
use crate::help::highlight_search_string;
use fancy_regex::Regex;
use lscolors::{Color as LsColors_Color, Style as LsColors_Style};
use lscolors::{Color as LsColors_Color, LsColors, Style as LsColors_Style};
use nu_ansi_term::{Color, Color::Default, Style};
use nu_color_config::get_color_config;
use nu_engine::{env_to_string, eval_block, CallExt};
use nu_protocol::{
ast::Call,
engine::{CaptureBlock, Command, EngineState, Stack},
Category, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, ShellError,
Category, Config, Example, IntoInterruptiblePipelineData, ListStream, PipelineData, ShellError,
Signature, Span, SyntaxShape, Value,
};
use nu_utils::get_ls_colors;
@ -278,6 +279,72 @@ fn find_with_predicate(
)
}
fn highlight_terms_in_record(
cols: &mut [String],
vals: &mut Vec<Value>,
span: &mut Span,
config: &Config,
terms: &[Value],
string_style: Style,
ls_colors: &LsColors,
) -> Value {
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 {
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 ansi_term_style = style
.map(to_nu_ansi_term_style)
.unwrap_or_else(|| string_style);
let hi =
match highlight_search_string(&ls_colored_val, &term_str, &ansi_term_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,
}
}
fn find_with_rest_and_highlight(
engine_state: &EngineState,
stack: &mut Stack,
@ -315,177 +382,129 @@ fn find_with_rest_and_highlight(
let ls_colors = get_ls_colors(ls_colors_env_str);
match input {
PipelineData::Value(_, _) => input.filter(
move |value| {
let lower_value = if let Ok(span) = value.span() {
Value::string(value.into_string("", &config).to_lowercase(), span)
} else {
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 ansi_term_style = style
.map(to_nu_ansi_term_style)
.unwrap_or_else(|| string_style);
let hi = match highlight_search_string(
&ls_colored_val,
&term_str,
&ansi_term_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 {
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, |value| value.is_true()),
Value::String { .. }
| Value::List { .. }
| Value::CellPath { .. }
| Value::CustomValue { .. } => term
.r#in(span, &lower_value, span)
.map_or(false, |value| value.is_true()),
Value::Record { vals, .. } => vals.iter().any(|val| {
if let Ok(span) = val.span() {
let lower_val = Value::string(
val.into_string("", &filter_config).to_lowercase(),
Span::test_data(),
);
term.r#in(span, &lower_val, span)
.map_or(false, |value| value.is_true())
} else {
term.r#in(span, val, span)
.map_or(false, |value| value.is_true())
}
}),
Value::Binary { .. } => false,
}) != invert
}),
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,
),
_ => x,
},
ctrlc.clone(),
)
.into_pipeline_data(ctrlc)
.set_metadata(meta))
}
)?
.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 {
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("", &filter_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 } => highlight_terms_in_record(
cols,
vals,
span,
&config,
&terms,
string_style,
&ls_colors,
),
_ => 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 {
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, |value| value.is_true()),
Value::String { .. }
| Value::List { .. }
| Value::CellPath { .. }
| Value::CustomValue { .. } => term
.r#in(span, &lower_value, span)
.map_or(false, |value| value.is_true()),
Value::Record { vals, .. } => vals.iter().any(|val| {
if let Ok(span) = val.span() {
let lower_val = Value::string(
val.into_string("", &filter_config).to_lowercase(),
Span::test_data(),
);
term.r#in(span, &lower_val, span)
.map_or(false, |value| value.is_true())
} else {
term.r#in(span, val, span)
.map_or(false, |value| value.is_true())
}
}),
Value::Binary { .. } => false,
}) != invert
}),
ctrlc.clone(),
)
.into_pipeline_data(ctrlc)
.set_metadata(meta)),
PipelineData::ExternalStream { stdout: None, .. } => Ok(PipelineData::new(span)),
PipelineData::ExternalStream {
stdout: Some(stream),