From b3b52f7f2fe3fac461321e2a240e9474c829db0d Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Fri, 2 May 2025 01:58:02 -0300 Subject: [PATCH] applying config in app --- cli/app.rs | 25 +++++++++++---- cli/config/palette.rs | 2 +- cli/helper.rs | 71 ++++++++++++++++++++++++++++++++++++++----- cli/main.rs | 7 +++++ 4 files changed, 91 insertions(+), 14 deletions(-) diff --git a/cli/app.rs b/cli/app.rs index 2744666c4..69b770202 100644 --- a/cli/app.rs +++ b/cli/app.rs @@ -4,12 +4,13 @@ use crate::{ import::ImportFile, Command, CommandParser, }, + config::Config, helper::LimboHelper, input::{get_io, get_writer, DbLocation, OutputMode, Settings}, opcodes_dictionary::OPCODE_DESCRIPTIONS, HISTORY_FILE, }; -use comfy_table::{Attribute, Cell, CellAlignment, Color, ContentArrangement, Row, Table}; +use comfy_table::{Attribute, Cell, CellAlignment, ContentArrangement, Row, Table}; use limbo_core::{Database, LimboError, Statement, StepResult, Value}; use tracing_appender::non_blocking::WorkerGuard; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; @@ -72,6 +73,7 @@ pub struct Limbo { input_buff: String, opts: Settings, pub rl: Option>, + config: Option, } struct QueryStatistics { @@ -104,8 +106,6 @@ macro_rules! query_internal { }}; } -static COLORS: &[Color] = &[Color::Green, Color::Black, Color::Grey]; - impl Limbo { pub fn new() -> anyhow::Result { let opts = Opts::parse(); @@ -154,13 +154,23 @@ impl Limbo { input_buff: String::new(), opts: Settings::from(opts), rl: None, + config: None, }; app.first_run(sql, quiet)?; Ok(app) } + pub fn with_config(mut self, config: Config) -> Self { + self.config = Some(config); + self + } + pub fn with_readline(mut self, mut rl: Editor) -> Self { - let h = LimboHelper::new(self.conn.clone(), self.io.clone()); + let h = LimboHelper::new( + self.conn.clone(), + self.io.clone(), + self.config.as_ref().map(|c| c.highlight.clone()), + ); rl.set_helper(Some(h)); self.rl = Some(rl); self @@ -727,6 +737,7 @@ impl Limbo { println!("Query interrupted."); return Ok(()); } + let config = self.config.as_ref().unwrap(); let mut table = Table::new(); table .set_content_arrangement(ContentArrangement::Dynamic) @@ -738,7 +749,7 @@ impl Limbo { let name = rows.get_column_name(i); Cell::new(name) .add_attribute(Attribute::Bold) - .fg(Color::White) + .fg(config.table.header_color.into_comfy_table_color()) }) .collect::>(); table.set_header(header); @@ -774,7 +785,9 @@ impl Limbo { row.add_cell( Cell::new(content) .set_alignment(alignment) - .fg(COLORS[idx % COLORS.len()]), + .fg(config.table.column_colors + [idx % config.table.column_colors.len()] + .into_comfy_table_color()), ); } table.add_row(row); diff --git a/cli/config/palette.rs b/cli/config/palette.rs index fde1d4cc1..3b6962270 100644 --- a/cli/config/palette.rs +++ b/cli/config/palette.rs @@ -258,4 +258,4 @@ impl LimboColor { Color::Fixed(ansi_color_num) => comfy_table::Color::AnsiValue(ansi_color_num), } } -} \ No newline at end of file +} diff --git a/cli/helper.rs b/cli/helper.rs index 70194234d..f8e606a89 100644 --- a/cli/helper.rs +++ b/cli/helper.rs @@ -11,8 +11,14 @@ use std::marker::PhantomData; use std::rc::Rc; use std::sync::Arc; use std::{ffi::OsString, path::PathBuf, str::FromStr as _}; +use syntect::dumps::from_uncompressed_data; +use syntect::easy::HighlightLines; +use syntect::highlighting::ThemeSet; +use syntect::parsing::{Scope, SyntaxSet}; +use syntect::util::{as_24_bit_terminal_escaped, LinesWithEndings}; use crate::commands::CommandParser; +use crate::config::{HighlightConfig, CONFIG_DIR}; macro_rules! try_result { ($expr:expr, $err:expr) => { @@ -27,14 +33,37 @@ macro_rules! try_result { pub struct LimboHelper { #[rustyline(Completer)] completer: SqlCompleter, + syntax_set: SyntaxSet, + theme_set: ThemeSet, + syntax_config: HighlightConfig, #[rustyline(Hinter)] hinter: HistoryHinter, } impl LimboHelper { - pub fn new(conn: Rc, io: Arc) -> Self { + pub fn new( + conn: Rc, + io: Arc, + syntax_config: Option, + ) -> Self { + // Load only predefined syntax + let ps = from_uncompressed_data(include_bytes!(concat!( + env!("OUT_DIR"), + "/SQL_syntax_set_dump.packdump" + ))) + .unwrap(); + let mut ts = ThemeSet::load_defaults(); + let theme_dir = CONFIG_DIR.join("themes"); + if theme_dir.exists() { + if let Err(err) = ts.add_from_folder(theme_dir) { + tracing::error!("{err}"); + } + } LimboHelper { completer: SqlCompleter::new(conn, io), + syntax_set: ps, + theme_set: ts, + syntax_config: syntax_config.unwrap_or_default(), hinter: HistoryHinter::new(), } } @@ -43,9 +72,37 @@ impl LimboHelper { impl Highlighter for LimboHelper { fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> { let _ = pos; - let style = Style::new().fg(Color::White); // Standard shell text color - let styled_str = style.paint(line); - std::borrow::Cow::Owned(styled_str.to_string()) + if self.syntax_config.enable { + // TODO use lifetimes to store highlight lines + let syntax = self + .syntax_set + .find_syntax_by_scope(Scope::new("source.sql").unwrap()) + .unwrap(); + let theme = self + .theme_set + .themes + .get(&self.syntax_config.theme) + .unwrap_or(&self.theme_set.themes["base16-ocean.dark"]); + let mut h = HighlightLines::new(syntax, theme); + let ranges = { + let mut ret_ranges = Vec::new(); + for new_line in LinesWithEndings::from(line) { + let ranges: Vec<(syntect::highlighting::Style, &str)> = + h.highlight_line(new_line, &self.syntax_set).unwrap(); + ret_ranges.extend(ranges); + } + ret_ranges + }; + let mut ret_line = as_24_bit_terminal_escaped(&ranges[..], false); + // Push this escape sequence to reset terminal color modes at the end of the string + ret_line.push_str("\x1b[0m"); + std::borrow::Cow::Owned(ret_line) + } else { + // Appease Pekka in syntax highlighting + let style = Style::new().fg(Color::White); // Standard shell text color + let styled_str = style.paint(line); + std::borrow::Cow::Owned(styled_str.to_string()) + } } fn highlight_prompt<'b, 's: 'b, 'p: 'b>( @@ -55,13 +112,13 @@ impl Highlighter for LimboHelper { ) -> std::borrow::Cow<'b, str> { let _ = default; // Dark emerald green for prompt - let style = Style::new().bold().fg(Color::Rgb(34u8, 197u8, 94u8)); + let style = Style::new().bold().fg(self.syntax_config.prompt.0); let styled_str = style.paint(prompt); std::borrow::Cow::Owned(styled_str.to_string()) } fn highlight_hint<'h>(&self, hint: &'h str) -> std::borrow::Cow<'h, str> { - let style = Style::new().bold().fg(Color::Rgb(107u8, 114u8, 128u8)); // Brighter dark grey for hints + let style = Style::new().bold().fg(self.syntax_config.hint.0); // Brighter dark grey for hints let styled_str = style.paint(hint); std::borrow::Cow::Owned(styled_str.to_string()) } @@ -72,7 +129,7 @@ impl Highlighter for LimboHelper { completion: rustyline::CompletionType, ) -> std::borrow::Cow<'c, str> { let _ = completion; - let style = Style::new().fg(Color::Green); + let style = Style::new().fg(self.syntax_config.candidate.0); let styled_str = style.paint(candidate); std::borrow::Cow::Owned(styled_str.to_string()) } diff --git a/cli/main.rs b/cli/main.rs index d24bbbc8a..843d6580e 100644 --- a/cli/main.rs +++ b/cli/main.rs @@ -6,6 +6,7 @@ mod helper; mod input; mod opcodes_dictionary; +use config::CONFIG_DIR; use rustyline::{error::ReadlineError, Config, Editor}; use std::{ path::PathBuf, @@ -33,6 +34,12 @@ fn main() -> anyhow::Result<()> { if HISTORY_FILE.exists() { rl.load_history(HISTORY_FILE.as_path())?; } + let config_file = CONFIG_DIR.join("limbo.toml"); + + let config = config::Config::from_config_file(config_file); + tracing::info!("Configuration: {:?}", config); + app = app.with_config(config); + app = app.with_readline(rl); } else { tracing::debug!("not in tty");