diff --git a/Cargo.lock b/Cargo.lock index 364d2d9276..8cd33b2ec2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2723,6 +2723,7 @@ dependencies = [ "sysinfo", "unicode-segmentation", "uuid", + "which 5.0.0", ] [[package]] diff --git a/crates/nu-cli/Cargo.toml b/crates/nu-cli/Cargo.toml index 6afa3678f9..fd800c8561 100644 --- a/crates/nu-cli/Cargo.toml +++ b/crates/nu-cli/Cargo.toml @@ -40,6 +40,7 @@ pathdiff = "0.2" sysinfo = "0.29" unicode-segmentation = "1.10" uuid = { version = "1.6.0", features = ["v4"] } +which = "5.0.0" [features] plugin = [] diff --git a/crates/nu-cli/src/syntax_highlight.rs b/crates/nu-cli/src/syntax_highlight.rs index 8f1265499d..babe1635da 100644 --- a/crates/nu-cli/src/syntax_highlight.rs +++ b/crates/nu-cli/src/syntax_highlight.rs @@ -17,10 +17,27 @@ impl Highlighter for NuHighlighter { fn highlight(&self, line: &str, _cursor: usize) -> StyledText { trace!("highlighting: {}", line); + let highlight_resolved_externals = + self.engine_state.get_config().highlight_resolved_externals; let mut working_set = StateWorkingSet::new(&self.engine_state); let block = parse(&mut working_set, None, line.as_bytes(), false); let (shapes, global_span_offset) = { - let shapes = flatten_block(&working_set, &block); + let mut shapes = flatten_block(&working_set, &block); + // Highlighting externals has a config point because of concerns that using which to resolve + // externals may slow down things too much. + if highlight_resolved_externals { + for (span, shape) in shapes.iter_mut() { + if *shape == FlatShape::External { + let str_contents = + working_set.get_span_contents(Span::new(span.start, span.end)); + + let str_word = String::from_utf8_lossy(str_contents).to_string(); + if which::which(str_word).ok().is_some() { + *shape = FlatShape::ExternalResolved; + } + } + } + } (shapes, self.engine_state.next_span_start()) }; @@ -91,6 +108,7 @@ impl Highlighter for NuHighlighter { FlatShape::InternalCall(_) => add_colored_token(&shape.1, next_token), FlatShape::External => add_colored_token(&shape.1, next_token), FlatShape::ExternalArg => add_colored_token(&shape.1, next_token), + FlatShape::ExternalResolved => add_colored_token(&shape.1, next_token), FlatShape::Keyword => add_colored_token(&shape.1, next_token), FlatShape::Literal => add_colored_token(&shape.1, next_token), FlatShape::Operator => add_colored_token(&shape.1, next_token), diff --git a/crates/nu-color-config/src/shape_color.rs b/crates/nu-color-config/src/shape_color.rs index a3db8a377c..188abda992 100644 --- a/crates/nu-color-config/src/shape_color.rs +++ b/crates/nu-color-config/src/shape_color.rs @@ -15,6 +15,7 @@ pub fn default_shape_color(shape: String) -> Style { "shape_directory" => Style::new().fg(Color::Cyan), "shape_external" => Style::new().fg(Color::Cyan), "shape_externalarg" => Style::new().fg(Color::Green).bold(), + "shape_external_resolved" => Style::new().fg(Color::LightYellow).bold(), "shape_filepath" => Style::new().fg(Color::Cyan), "shape_flag" => Style::new().fg(Color::Blue).bold(), "shape_float" => Style::new().fg(Color::Purple).bold(), diff --git a/crates/nu-parser/src/flatten.rs b/crates/nu-parser/src/flatten.rs index 6f364951a9..b2bf26f46b 100644 --- a/crates/nu-parser/src/flatten.rs +++ b/crates/nu-parser/src/flatten.rs @@ -18,6 +18,7 @@ pub enum FlatShape { Directory, External, ExternalArg, + ExternalResolved, Filepath, Flag, Float, @@ -57,6 +58,7 @@ impl Display for FlatShape { FlatShape::Directory => write!(f, "shape_directory"), FlatShape::External => write!(f, "shape_external"), FlatShape::ExternalArg => write!(f, "shape_externalarg"), + FlatShape::ExternalResolved => write!(f, "shape_external_resolved"), FlatShape::Filepath => write!(f, "shape_filepath"), FlatShape::Flag => write!(f, "shape_flag"), FlatShape::Float => write!(f, "shape_float"), diff --git a/crates/nu-protocol/src/config/mod.rs b/crates/nu-protocol/src/config/mod.rs index e414773e62..dc2566aa6e 100644 --- a/crates/nu-protocol/src/config/mod.rs +++ b/crates/nu-protocol/src/config/mod.rs @@ -72,6 +72,7 @@ pub struct Config { pub datetime_table_format: Option, pub error_style: ErrorStyle, pub use_kitty_protocol: bool, + pub highlight_resolved_externals: bool, } impl Default for Config { @@ -137,6 +138,7 @@ impl Default for Config { error_style: ErrorStyle::Fancy, use_kitty_protocol: false, + highlight_resolved_externals: false, } } } @@ -622,6 +624,9 @@ impl Value { "use_kitty_protocol" => { process_bool_config(value, &mut errors, &mut config.use_kitty_protocol); } + "highlight_resolved_externals" => { + process_bool_config(value, &mut errors, &mut config.highlight_resolved_externals); + } // Menus "menus" => match create_menus(value) { Ok(map) => config.menus = map, diff --git a/crates/nu-utils/src/sample_config/default_config.nu b/crates/nu-utils/src/sample_config/default_config.nu index d01687e080..f07764eade 100644 --- a/crates/nu-utils/src/sample_config/default_config.nu +++ b/crates/nu-utils/src/sample_config/default_config.nu @@ -42,6 +42,7 @@ let dark_theme = { shape_directory: cyan shape_external: cyan shape_externalarg: green_bold + shape_external_resolved: light_yellow_bold shape_filepath: cyan shape_flag: blue_bold shape_float: purple_bold @@ -106,6 +107,7 @@ let light_theme = { shape_directory: cyan shape_external: cyan shape_externalarg: green_bold + shape_external_resolved: light_purple_bold shape_filepath: cyan shape_flag: blue_bold shape_float: purple_bold @@ -233,7 +235,8 @@ $env.config = { edit_mode: emacs # emacs, vi shell_integration: false # enables terminal shell integration. Off by default, as some terminals have issues with this. render_right_prompt_on_last_line: false # true or false to enable or disable right prompt to be rendered on last line of the prompt. - use_kitty_protocol: false # enables keyboard enhancement protocol implemented by kitty console, only if your terminal support this + use_kitty_protocol: false # enables keyboard enhancement protocol implemented by kitty console, only if your terminal support this. + highlight_resolved_externals: false # true enables highlighting of external commands in the repl resolved by which. hooks: { pre_prompt: [{ null }] # run before the prompt is shown