mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-08-04 18:18:03 +00:00
applying config in app
This commit is contained in:
parent
c73927729d
commit
b3b52f7f2f
4 changed files with 91 additions and 14 deletions
25
cli/app.rs
25
cli/app.rs
|
@ -4,12 +4,13 @@ use crate::{
|
||||||
import::ImportFile,
|
import::ImportFile,
|
||||||
Command, CommandParser,
|
Command, CommandParser,
|
||||||
},
|
},
|
||||||
|
config::Config,
|
||||||
helper::LimboHelper,
|
helper::LimboHelper,
|
||||||
input::{get_io, get_writer, DbLocation, OutputMode, Settings},
|
input::{get_io, get_writer, DbLocation, OutputMode, Settings},
|
||||||
opcodes_dictionary::OPCODE_DESCRIPTIONS,
|
opcodes_dictionary::OPCODE_DESCRIPTIONS,
|
||||||
HISTORY_FILE,
|
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 limbo_core::{Database, LimboError, Statement, StepResult, Value};
|
||||||
use tracing_appender::non_blocking::WorkerGuard;
|
use tracing_appender::non_blocking::WorkerGuard;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt, EnvFilter};
|
||||||
|
@ -72,6 +73,7 @@ pub struct Limbo {
|
||||||
input_buff: String,
|
input_buff: String,
|
||||||
opts: Settings,
|
opts: Settings,
|
||||||
pub rl: Option<Editor<LimboHelper, DefaultHistory>>,
|
pub rl: Option<Editor<LimboHelper, DefaultHistory>>,
|
||||||
|
config: Option<Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct QueryStatistics {
|
struct QueryStatistics {
|
||||||
|
@ -104,8 +106,6 @@ macro_rules! query_internal {
|
||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static COLORS: &[Color] = &[Color::Green, Color::Black, Color::Grey];
|
|
||||||
|
|
||||||
impl Limbo {
|
impl Limbo {
|
||||||
pub fn new() -> anyhow::Result<Self> {
|
pub fn new() -> anyhow::Result<Self> {
|
||||||
let opts = Opts::parse();
|
let opts = Opts::parse();
|
||||||
|
@ -154,13 +154,23 @@ impl Limbo {
|
||||||
input_buff: String::new(),
|
input_buff: String::new(),
|
||||||
opts: Settings::from(opts),
|
opts: Settings::from(opts),
|
||||||
rl: None,
|
rl: None,
|
||||||
|
config: None,
|
||||||
};
|
};
|
||||||
app.first_run(sql, quiet)?;
|
app.first_run(sql, quiet)?;
|
||||||
Ok(app)
|
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<LimboHelper, DefaultHistory>) -> Self {
|
pub fn with_readline(mut self, mut rl: Editor<LimboHelper, DefaultHistory>) -> 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));
|
rl.set_helper(Some(h));
|
||||||
self.rl = Some(rl);
|
self.rl = Some(rl);
|
||||||
self
|
self
|
||||||
|
@ -727,6 +737,7 @@ impl Limbo {
|
||||||
println!("Query interrupted.");
|
println!("Query interrupted.");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
let config = self.config.as_ref().unwrap();
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
table
|
table
|
||||||
.set_content_arrangement(ContentArrangement::Dynamic)
|
.set_content_arrangement(ContentArrangement::Dynamic)
|
||||||
|
@ -738,7 +749,7 @@ impl Limbo {
|
||||||
let name = rows.get_column_name(i);
|
let name = rows.get_column_name(i);
|
||||||
Cell::new(name)
|
Cell::new(name)
|
||||||
.add_attribute(Attribute::Bold)
|
.add_attribute(Attribute::Bold)
|
||||||
.fg(Color::White)
|
.fg(config.table.header_color.into_comfy_table_color())
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
table.set_header(header);
|
table.set_header(header);
|
||||||
|
@ -774,7 +785,9 @@ impl Limbo {
|
||||||
row.add_cell(
|
row.add_cell(
|
||||||
Cell::new(content)
|
Cell::new(content)
|
||||||
.set_alignment(alignment)
|
.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);
|
table.add_row(row);
|
||||||
|
|
|
@ -258,4 +258,4 @@ impl LimboColor {
|
||||||
Color::Fixed(ansi_color_num) => comfy_table::Color::AnsiValue(ansi_color_num),
|
Color::Fixed(ansi_color_num) => comfy_table::Color::AnsiValue(ansi_color_num),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,14 @@ use std::marker::PhantomData;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{ffi::OsString, path::PathBuf, str::FromStr as _};
|
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::commands::CommandParser;
|
||||||
|
use crate::config::{HighlightConfig, CONFIG_DIR};
|
||||||
|
|
||||||
macro_rules! try_result {
|
macro_rules! try_result {
|
||||||
($expr:expr, $err:expr) => {
|
($expr:expr, $err:expr) => {
|
||||||
|
@ -27,14 +33,37 @@ macro_rules! try_result {
|
||||||
pub struct LimboHelper {
|
pub struct LimboHelper {
|
||||||
#[rustyline(Completer)]
|
#[rustyline(Completer)]
|
||||||
completer: SqlCompleter<CommandParser>,
|
completer: SqlCompleter<CommandParser>,
|
||||||
|
syntax_set: SyntaxSet,
|
||||||
|
theme_set: ThemeSet,
|
||||||
|
syntax_config: HighlightConfig,
|
||||||
#[rustyline(Hinter)]
|
#[rustyline(Hinter)]
|
||||||
hinter: HistoryHinter,
|
hinter: HistoryHinter,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LimboHelper {
|
impl LimboHelper {
|
||||||
pub fn new(conn: Rc<Connection>, io: Arc<dyn limbo_core::IO>) -> Self {
|
pub fn new(
|
||||||
|
conn: Rc<Connection>,
|
||||||
|
io: Arc<dyn limbo_core::IO>,
|
||||||
|
syntax_config: Option<HighlightConfig>,
|
||||||
|
) -> 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 {
|
LimboHelper {
|
||||||
completer: SqlCompleter::new(conn, io),
|
completer: SqlCompleter::new(conn, io),
|
||||||
|
syntax_set: ps,
|
||||||
|
theme_set: ts,
|
||||||
|
syntax_config: syntax_config.unwrap_or_default(),
|
||||||
hinter: HistoryHinter::new(),
|
hinter: HistoryHinter::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,9 +72,37 @@ impl LimboHelper {
|
||||||
impl Highlighter for LimboHelper {
|
impl Highlighter for LimboHelper {
|
||||||
fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> {
|
fn highlight<'l>(&self, line: &'l str, pos: usize) -> std::borrow::Cow<'l, str> {
|
||||||
let _ = pos;
|
let _ = pos;
|
||||||
let style = Style::new().fg(Color::White); // Standard shell text color
|
if self.syntax_config.enable {
|
||||||
let styled_str = style.paint(line);
|
// TODO use lifetimes to store highlight lines
|
||||||
std::borrow::Cow::Owned(styled_str.to_string())
|
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>(
|
fn highlight_prompt<'b, 's: 'b, 'p: 'b>(
|
||||||
|
@ -55,13 +112,13 @@ impl Highlighter for LimboHelper {
|
||||||
) -> std::borrow::Cow<'b, str> {
|
) -> std::borrow::Cow<'b, str> {
|
||||||
let _ = default;
|
let _ = default;
|
||||||
// Dark emerald green for prompt
|
// 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);
|
let styled_str = style.paint(prompt);
|
||||||
std::borrow::Cow::Owned(styled_str.to_string())
|
std::borrow::Cow::Owned(styled_str.to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_hint<'h>(&self, hint: &'h str) -> std::borrow::Cow<'h, str> {
|
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);
|
let styled_str = style.paint(hint);
|
||||||
std::borrow::Cow::Owned(styled_str.to_string())
|
std::borrow::Cow::Owned(styled_str.to_string())
|
||||||
}
|
}
|
||||||
|
@ -72,7 +129,7 @@ impl Highlighter for LimboHelper {
|
||||||
completion: rustyline::CompletionType,
|
completion: rustyline::CompletionType,
|
||||||
) -> std::borrow::Cow<'c, str> {
|
) -> std::borrow::Cow<'c, str> {
|
||||||
let _ = completion;
|
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);
|
let styled_str = style.paint(candidate);
|
||||||
std::borrow::Cow::Owned(styled_str.to_string())
|
std::borrow::Cow::Owned(styled_str.to_string())
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ mod helper;
|
||||||
mod input;
|
mod input;
|
||||||
mod opcodes_dictionary;
|
mod opcodes_dictionary;
|
||||||
|
|
||||||
|
use config::CONFIG_DIR;
|
||||||
use rustyline::{error::ReadlineError, Config, Editor};
|
use rustyline::{error::ReadlineError, Config, Editor};
|
||||||
use std::{
|
use std::{
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
|
@ -33,6 +34,12 @@ fn main() -> anyhow::Result<()> {
|
||||||
if HISTORY_FILE.exists() {
|
if HISTORY_FILE.exists() {
|
||||||
rl.load_history(HISTORY_FILE.as_path())?;
|
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);
|
app = app.with_readline(rl);
|
||||||
} else {
|
} else {
|
||||||
tracing::debug!("not in tty");
|
tracing::debug!("not in tty");
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue