mirror of
https://github.com/nushell/nushell.git
synced 2025-04-15 08:48:19 +02:00
add the ability to highlight with regular expressiosn (#5992)
This commit is contained in:
parent
221f36ca65
commit
c0ce78f892
@ -1,10 +1,13 @@
|
|||||||
use nu_ansi_term::Color::{Red, White};
|
use nu_ansi_term::{
|
||||||
|
Color::{Red, White},
|
||||||
|
Style,
|
||||||
|
};
|
||||||
use nu_engine::{get_full_help, CallExt};
|
use nu_engine::{get_full_help, CallExt};
|
||||||
use nu_protocol::{
|
use nu_protocol::{
|
||||||
ast::Call,
|
ast::Call,
|
||||||
engine::{Command, EngineState, Stack},
|
engine::{Command, EngineState, Stack},
|
||||||
span, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
|
span, Category, Example, IntoInterruptiblePipelineData, IntoPipelineData, PipelineData,
|
||||||
ShellError, Signature, Spanned, SyntaxShape, Value,
|
ShellError, Signature, Span, Spanned, SyntaxShape, Value,
|
||||||
};
|
};
|
||||||
use std::borrow::Borrow;
|
use std::borrow::Borrow;
|
||||||
|
|
||||||
@ -80,11 +83,9 @@ fn help(
|
|||||||
let head = call.head;
|
let head = call.head;
|
||||||
let find: Option<Spanned<String>> = call.get_flag(engine_state, stack, "find")?;
|
let find: Option<Spanned<String>> = call.get_flag(engine_state, stack, "find")?;
|
||||||
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
|
let rest: Vec<Spanned<String>> = call.rest(engine_state, stack, 0)?;
|
||||||
|
|
||||||
let commands = engine_state.get_decl_ids_sorted(false);
|
let commands = engine_state.get_decl_ids_sorted(false);
|
||||||
|
|
||||||
if let Some(f) = find {
|
if let Some(f) = find {
|
||||||
let replace_string = White.on(Red).paint(f.item.clone()).to_string();
|
|
||||||
let org_search_string = f.item.clone();
|
let org_search_string = f.item.clone();
|
||||||
let search_string = f.item.to_lowercase();
|
let search_string = f.item.to_lowercase();
|
||||||
let mut found_cmds_vec = Vec::new();
|
let mut found_cmds_vec = Vec::new();
|
||||||
@ -92,13 +93,12 @@ fn help(
|
|||||||
for decl_id in commands {
|
for decl_id in commands {
|
||||||
let mut cols = vec![];
|
let mut cols = vec![];
|
||||||
let mut vals = vec![];
|
let mut vals = vec![];
|
||||||
|
|
||||||
let decl = engine_state.get_decl(decl_id);
|
let decl = engine_state.get_decl(decl_id);
|
||||||
let sig = decl.signature().update_from_command(decl.borrow());
|
let sig = decl.signature().update_from_command(decl.borrow());
|
||||||
|
|
||||||
let key = sig.name;
|
let key = sig.name;
|
||||||
let usage = sig.usage;
|
let usage = sig.usage;
|
||||||
let search_terms = sig.search_terms;
|
let search_terms = sig.search_terms;
|
||||||
|
|
||||||
let matches_term = if !search_terms.is_empty() {
|
let matches_term = if !search_terms.is_empty() {
|
||||||
search_terms
|
search_terms
|
||||||
.iter()
|
.iter()
|
||||||
@ -113,7 +113,7 @@ fn help(
|
|||||||
cols.push("name".into());
|
cols.push("name".into());
|
||||||
vals.push(Value::String {
|
vals.push(Value::String {
|
||||||
val: if key_match {
|
val: if key_match {
|
||||||
key.as_str().replace(&org_search_string, &replace_string)
|
highlight_search_string(&key, &org_search_string)?
|
||||||
} else {
|
} else {
|
||||||
key
|
key
|
||||||
},
|
},
|
||||||
@ -147,7 +147,7 @@ fn help(
|
|||||||
cols.push("usage".into());
|
cols.push("usage".into());
|
||||||
vals.push(Value::String {
|
vals.push(Value::String {
|
||||||
val: if use_match {
|
val: if use_match {
|
||||||
usage.as_str().replace(&org_search_string, &replace_string)
|
highlight_search_string(&usage, &org_search_string)?
|
||||||
} else {
|
} else {
|
||||||
usage
|
usage
|
||||||
},
|
},
|
||||||
@ -164,7 +164,10 @@ fn help(
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|term| {
|
.map(|term| {
|
||||||
if term.to_lowercase().contains(&search_string) {
|
if term.to_lowercase().contains(&search_string) {
|
||||||
term.replace(&org_search_string, &replace_string.clone())
|
match highlight_search_string(term, &org_search_string) {
|
||||||
|
Ok(s) => s,
|
||||||
|
Err(_) => term.to_string(),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
term.clone()
|
term.clone()
|
||||||
}
|
}
|
||||||
@ -325,3 +328,40 @@ You can also learn more at https://www.nushell.sh/book/"#;
|
|||||||
.into_pipeline_data())
|
.into_pipeline_data())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Highlight the search string using ANSI escape sequences and regular expressions.
|
||||||
|
fn highlight_search_string(haystack: &str, needle: &str) -> Result<String, ShellError> {
|
||||||
|
let regex_string = format!("(?i){}", needle);
|
||||||
|
let regex = match regex::Regex::new(®ex_string) {
|
||||||
|
Ok(regex) => regex,
|
||||||
|
Err(err) => {
|
||||||
|
return Err(ShellError::GenericError(
|
||||||
|
"Could not compile regex".into(),
|
||||||
|
err.to_string(),
|
||||||
|
Some(Span::test_data()),
|
||||||
|
None,
|
||||||
|
Vec::new(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let mut last_match_end = 0;
|
||||||
|
let style = Style::new().fg(White).on(Red);
|
||||||
|
let mut highlighted = String::new();
|
||||||
|
|
||||||
|
for cap in regex.captures_iter(haystack) {
|
||||||
|
let start = match cap.get(0) {
|
||||||
|
Some(cap) => cap.start(),
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
let end = match cap.get(0) {
|
||||||
|
Some(cap) => cap.end(),
|
||||||
|
None => 0,
|
||||||
|
};
|
||||||
|
highlighted.push_str(&haystack[last_match_end..start]);
|
||||||
|
highlighted.push_str(&style.paint(&haystack[start..end]).to_string());
|
||||||
|
last_match_end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
highlighted.push_str(&haystack[last_match_end..]);
|
||||||
|
Ok(highlighted)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user