diff --git a/crates/nu-ansi-term/src/style.rs b/crates/nu-ansi-term/src/style.rs index ec72dbdb31..a11002e028 100644 --- a/crates/nu-ansi-term/src/style.rs +++ b/crates/nu-ansi-term/src/style.rs @@ -368,6 +368,12 @@ pub enum Color { Rgb(u8, u8, u8), } +impl Default for Color { + fn default() -> Self { + Color::White + } +} + impl Color { /// Returns a `Style` with the foreground color set to this color. /// diff --git a/crates/nu-cli/src/shell/helper.rs b/crates/nu-cli/src/shell/helper.rs index 5502d49ad2..49dfc0c2ed 100644 --- a/crates/nu-cli/src/shell/helper.rs +++ b/crates/nu-cli/src/shell/helper.rs @@ -84,7 +84,12 @@ impl rustyline::highlight::Highlighter for Helper { } fn highlight<'l>(&self, line: &'l str, _pos: usize) -> Cow<'l, str> { - Painter::paint_string(line, &self.context.scope, &DefaultPalette {}) + let cfg = &self.context.configs.lock(); + if let Some(palette) = &cfg.syntax_config { + Painter::paint_string(line, &self.context.scope, palette) + } else { + Painter::paint_string(line, &self.context.scope, &DefaultPalette {}) + } } fn highlight_char(&self, _line: &str, _pos: usize) -> bool { diff --git a/crates/nu-engine/src/config_holder.rs b/crates/nu-engine/src/config_holder.rs index d6079a3265..388460859d 100644 --- a/crates/nu-engine/src/config_holder.rs +++ b/crates/nu-engine/src/config_holder.rs @@ -1,13 +1,14 @@ -use std::path::Path; - +use crate::shell::palette::ThemedPalette; use nu_data::config::NuConfig; use nu_protocol::ConfigPath; +use std::path::Path; /// ConfigHolder holds information which configs have been loaded. #[derive(Clone)] pub struct ConfigHolder { pub global_config: Option, pub local_configs: Vec, + pub syntax_config: Option, } impl Default for ConfigHolder { @@ -21,6 +22,7 @@ impl ConfigHolder { ConfigHolder { global_config: None, local_configs: vec![], + syntax_config: None, } } @@ -31,6 +33,13 @@ impl ConfigHolder { } } + pub fn syntax_colors(&self) -> ThemedPalette { + match &self.syntax_config { + Some(cfg) => cfg.clone(), + None => ThemedPalette::default(), + } + } + pub fn add_local_cfg(&mut self, cfg: NuConfig) { self.local_configs.push(cfg); } @@ -39,6 +48,10 @@ impl ConfigHolder { self.global_config = Some(cfg); } + pub fn set_syntax_colors(&mut self, cfg: ThemedPalette) { + self.syntax_config = Some(cfg); + } + pub fn remove_cfg(&mut self, cfg_path: &ConfigPath) { match cfg_path { ConfigPath::Global(_) => self.global_config = None, diff --git a/crates/nu-engine/src/evaluation_context.rs b/crates/nu-engine/src/evaluation_context.rs index da32cda2b9..b0294f9fd7 100644 --- a/crates/nu-engine/src/evaluation_context.rs +++ b/crates/nu-engine/src/evaluation_context.rs @@ -1,4 +1,5 @@ use crate::evaluate::scope::{Scope, ScopeFrame}; +use crate::shell::palette::ThemedPalette; use crate::shell::shell_manager::ShellManager; use crate::whole_stream_command::Command; use crate::{call_info::UnevaluatedCallInfo, config_holder::ConfigHolder}; @@ -13,6 +14,8 @@ use nu_source::{Span, Tag}; use nu_stream::InputStream; use nu_test_support::NATIVE_PATH_ENV_VAR; use parking_lot::Mutex; +use std::fs::File; +use std::io::BufReader; use std::sync::atomic::AtomicBool; use std::{path::Path, sync::Arc}; @@ -212,6 +215,51 @@ impl EvaluationContext { } } + // The syntax_theme is really the file stem of a json file i.e. + // grape.json is the theme file and grape is the file stem and + // the syntax_theme and grape.json would be located in the same + // folder as the config.toml + + // Let's open the config + let global_config = self.configs.lock().global_config(); + // Get the root syntax_theme value + let syntax_theme = global_config.var("syntax_theme"); + // If we have a syntax_theme let's process it + if let Some(theme_value) = syntax_theme { + // Append the .json to the syntax_theme to form the file name + let syntax_theme_filename = format!("{}.json", theme_value.convert_to_string()); + // Load the syntax config json + let config_file_path = cfg_path.get_path(); + // The syntax file should be in the same location as the config.toml + let syntax_file_path = if config_file_path.ends_with("config.toml") { + config_file_path + .display() + .to_string() + .replace("config.toml", &syntax_theme_filename) + } else { + "".to_string() + }; + // if we have a syntax_file_path use it otherwise default + if Path::new(&syntax_file_path).exists() { + // eprintln!("Loading syntax file: [{:?}]", syntax_file_path); + let syntax_theme_file = File::open(syntax_file_path)?; + let mut reader = BufReader::new(syntax_theme_file); + let theme = ThemedPalette::new(&mut reader).unwrap_or_default(); + // eprintln!("Theme: [{:?}]", theme); + self.configs.lock().set_syntax_colors(theme); + } else { + // If the file was missing, use the default + self.configs + .lock() + .set_syntax_colors(ThemedPalette::default()) + } + } else { + // if there's no syntax_theme, use the default + self.configs + .lock() + .set_syntax_colors(ThemedPalette::default()) + }; + if !startup_scripts.is_empty() { self.run_scripts(startup_scripts, cfg_path.get_path().parent()); } diff --git a/crates/nu-engine/src/shell/palette.rs b/crates/nu-engine/src/shell/palette.rs index 9437b7688c..7a5bf5272d 100644 --- a/crates/nu-engine/src/shell/palette.rs +++ b/crates/nu-engine/src/shell/palette.rs @@ -7,52 +7,43 @@ use std::ops::Deref; use std::str::Bytes; use std::{fmt, io}; -// FIXME: find a good home, as nu-engine may be too core for styling pub trait Palette { fn styles_for_shape(&self, shape: &Spanned) -> Vec>; } +#[derive(Debug, Clone, Default)] pub struct DefaultPalette {} impl Palette for DefaultPalette { fn styles_for_shape(&self, shape: &Spanned) -> Vec> { match &shape.item { - FlatShape::OpenDelimiter(_) => single_style_span(Color::White.normal(), shape.span), + FlatShape::BareMember => single_style_span(Color::Yellow.bold(), shape.span), FlatShape::CloseDelimiter(_) => single_style_span(Color::White.normal(), shape.span), - FlatShape::ItVariable | FlatShape::Keyword => { - single_style_span(Color::Purple.bold(), shape.span) - } - FlatShape::Variable | FlatShape::Identifier => { - single_style_span(Color::Purple.normal(), shape.span) - } - FlatShape::Type => single_style_span(Color::Blue.bold(), shape.span), - FlatShape::Operator => single_style_span(Color::Yellow.normal(), shape.span), + FlatShape::Comment => single_style_span(Color::Green.bold(), shape.span), + FlatShape::Decimal => single_style_span(Color::Purple.bold(), shape.span), + FlatShape::Dot => single_style_span(Style::new().fg(Color::White), shape.span), + FlatShape::DotDot => single_style_span(Color::Yellow.bold(), shape.span), FlatShape::DotDotLeftAngleBracket => { single_style_span(Color::Yellow.bold(), shape.span) } - FlatShape::DotDot => single_style_span(Color::Yellow.bold(), shape.span), - FlatShape::Dot => single_style_span(Style::new().fg(Color::White), shape.span), - FlatShape::InternalCommand => single_style_span(Color::Cyan.bold(), shape.span), FlatShape::ExternalCommand => single_style_span(Color::Cyan.normal(), shape.span), FlatShape::ExternalWord => single_style_span(Color::Green.bold(), shape.span), - FlatShape::BareMember => single_style_span(Color::Yellow.bold(), shape.span), - FlatShape::StringMember => single_style_span(Color::Yellow.bold(), shape.span), - FlatShape::String => single_style_span(Color::Green.normal(), shape.span), - FlatShape::Path => single_style_span(Color::Cyan.normal(), shape.span), - FlatShape::GlobPattern => single_style_span(Color::Cyan.bold(), shape.span), - FlatShape::Word => single_style_span(Color::Green.normal(), shape.span), - FlatShape::Pipe => single_style_span(Color::Purple.bold(), shape.span), FlatShape::Flag => single_style_span(Color::Blue.bold(), shape.span), - FlatShape::ShorthandFlag => single_style_span(Color::Blue.bold(), shape.span), - FlatShape::Int => single_style_span(Color::Purple.bold(), shape.span), - FlatShape::Decimal => single_style_span(Color::Purple.bold(), shape.span), - FlatShape::Whitespace | FlatShape::Separator => { - single_style_span(Color::White.normal(), shape.span) - } - FlatShape::Comment => single_style_span(Color::Green.bold(), shape.span), FlatShape::Garbage => { single_style_span(Style::new().fg(Color::White).on(Color::Red), shape.span) } + FlatShape::GlobPattern => single_style_span(Color::Cyan.bold(), shape.span), + FlatShape::Identifier => single_style_span(Color::Purple.normal(), shape.span), + FlatShape::Int => single_style_span(Color::Purple.bold(), shape.span), + FlatShape::InternalCommand => single_style_span(Color::Cyan.bold(), shape.span), + FlatShape::ItVariable => single_style_span(Color::Purple.bold(), shape.span), + FlatShape::Keyword => single_style_span(Color::Purple.bold(), shape.span), + FlatShape::OpenDelimiter(_) => single_style_span(Color::White.normal(), shape.span), + FlatShape::Operator => single_style_span(Color::Yellow.normal(), shape.span), + FlatShape::Path => single_style_span(Color::Cyan.normal(), shape.span), + FlatShape::Pipe => single_style_span(Color::Purple.bold(), shape.span), + FlatShape::Separator => single_style_span(Color::White.normal(), shape.span), + FlatShape::ShorthandFlag => single_style_span(Color::Blue.bold(), shape.span), FlatShape::Size { number, unit } => vec![ Spanned::