mirror of
https://github.com/tursodatabase/limbo.git
synced 2025-07-07 20:45:01 +00:00
193 lines
5.6 KiB
Rust
193 lines
5.6 KiB
Rust
mod palette;
|
|
mod terminal;
|
|
|
|
use crate::input::OutputMode;
|
|
use crate::HOME_DIR;
|
|
use nu_ansi_term::Color;
|
|
use palette::LimboColor;
|
|
use schemars::JsonSchema;
|
|
use serde::{Deserialize, Deserializer};
|
|
use std::fmt::Debug;
|
|
use std::fs::read_to_string;
|
|
use std::path::PathBuf;
|
|
use std::sync::LazyLock;
|
|
use terminal::{TerminalDetector, TerminalTheme};
|
|
use validator::Validate;
|
|
|
|
pub static CONFIG_DIR: LazyLock<PathBuf> = LazyLock::new(|| HOME_DIR.join(".config/limbo"));
|
|
|
|
fn ok_or_default<'de, T, D>(deserializer: D) -> Result<T, D::Error>
|
|
where
|
|
T: Deserialize<'de> + Default + Validate + Debug,
|
|
D: Deserializer<'de>,
|
|
{
|
|
let v: toml::Value = Deserialize::deserialize(deserializer)?;
|
|
let x = T::deserialize(v)
|
|
.map(|v| {
|
|
let validate = v.validate();
|
|
if validate.is_err() {
|
|
tracing::error!(
|
|
"Invalid value for {}.\n Original config value: {:?}",
|
|
validate.unwrap_err(),
|
|
v
|
|
);
|
|
T::default()
|
|
} else {
|
|
v
|
|
}
|
|
})
|
|
.unwrap_or_default();
|
|
Ok(x)
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Clone, Default, JsonSchema)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct Config {
|
|
#[serde(deserialize_with = "ok_or_default")]
|
|
pub table: TableConfig,
|
|
pub highlight: HighlightConfig,
|
|
}
|
|
|
|
impl Config {
|
|
pub fn from_config_file(path: PathBuf) -> Self {
|
|
if let Some(config) = Self::read_config_str(path) {
|
|
Self::from_config_str(&config)
|
|
} else {
|
|
Self::default()
|
|
}
|
|
}
|
|
|
|
pub fn from_config_str(config: &str) -> Self {
|
|
toml::from_str(config)
|
|
.inspect_err(|err| tracing::error!("{}", err))
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
fn read_config_str(path: PathBuf) -> Option<String> {
|
|
if path.exists() {
|
|
tracing::trace!("Trying to read from {:?}", path);
|
|
|
|
let result = read_to_string(path);
|
|
|
|
if result.is_err() {
|
|
tracing::debug!("Error reading file: {:?}", result);
|
|
} else {
|
|
tracing::trace!("File read successfully");
|
|
};
|
|
|
|
result.ok()
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
|
|
pub fn for_output_mode(mode: OutputMode) -> Self {
|
|
let table = if mode == OutputMode::Pretty {
|
|
TableConfig::adaptive_colors()
|
|
} else {
|
|
TableConfig::no_colors()
|
|
};
|
|
Self {
|
|
table,
|
|
highlight: HighlightConfig::default(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Clone, JsonSchema, Validate)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct TableConfig {
|
|
#[serde(default = "TableConfig::default_header_color")]
|
|
pub header_color: LimboColor,
|
|
#[serde(default = "TableConfig::default_column_colors")]
|
|
#[validate(length(min = 1))]
|
|
pub column_colors: Vec<LimboColor>,
|
|
}
|
|
|
|
impl Default for TableConfig {
|
|
fn default() -> Self {
|
|
// Always use adaptive colors based on terminal theme
|
|
Self::adaptive_colors()
|
|
}
|
|
}
|
|
|
|
impl TableConfig {
|
|
// These methods are needed for serde default attributes
|
|
fn default_header_color() -> LimboColor {
|
|
// Use adaptive colors for serde defaults too
|
|
Self::adaptive_colors().header_color
|
|
}
|
|
|
|
fn default_column_colors() -> Vec<LimboColor> {
|
|
// Use adaptive colors for serde defaults too
|
|
Self::adaptive_colors().column_colors
|
|
}
|
|
|
|
/// Get adaptive colors based on detected terminal theme
|
|
pub fn adaptive_colors() -> Self {
|
|
let theme = TerminalDetector::detect_theme();
|
|
match theme {
|
|
TerminalTheme::Light => Self::light_theme_colors(),
|
|
TerminalTheme::Dark => Self::dark_theme_colors(),
|
|
TerminalTheme::Unknown => Self::no_colors(), // No colors for unsupported platforms
|
|
}
|
|
}
|
|
|
|
/// No colors configuration - for Windows or when detection fails
|
|
fn no_colors() -> Self {
|
|
Self {
|
|
header_color: LimboColor(Color::Default),
|
|
column_colors: vec![LimboColor(Color::Default)],
|
|
}
|
|
}
|
|
|
|
/// Colors optimized for light terminal backgrounds
|
|
fn light_theme_colors() -> Self {
|
|
Self {
|
|
header_color: LimboColor(Color::Black),
|
|
column_colors: vec![
|
|
LimboColor(Color::Fixed(22)), // Dark green
|
|
LimboColor(Color::Fixed(17)), // Dark blue
|
|
LimboColor(Color::Fixed(88)), // Dark red
|
|
LimboColor(Color::Fixed(94)), // Orange
|
|
LimboColor(Color::Fixed(55)), // Purple
|
|
],
|
|
}
|
|
}
|
|
|
|
/// Colors optimized for dark terminal backgrounds
|
|
fn dark_theme_colors() -> Self {
|
|
Self {
|
|
header_color: LimboColor(Color::LightGray),
|
|
column_colors: vec![
|
|
LimboColor(Color::LightGreen),
|
|
LimboColor(Color::LightBlue),
|
|
LimboColor(Color::LightCyan),
|
|
LimboColor(Color::LightYellow),
|
|
LimboColor(Color::LightMagenta),
|
|
],
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Deserialize, Clone, JsonSchema)]
|
|
#[serde(default, deny_unknown_fields)]
|
|
pub struct HighlightConfig {
|
|
pub enable: bool,
|
|
pub theme: String,
|
|
pub prompt: LimboColor,
|
|
pub hint: LimboColor,
|
|
pub candidate: LimboColor,
|
|
}
|
|
|
|
impl Default for HighlightConfig {
|
|
fn default() -> Self {
|
|
Self {
|
|
enable: true,
|
|
theme: "base16-ocean.dark".to_string(),
|
|
prompt: LimboColor(Color::Rgb(34u8, 197u8, 94u8)),
|
|
hint: LimboColor(Color::Rgb(107u8, 114u8, 128u8)),
|
|
candidate: LimboColor(Color::Green),
|
|
}
|
|
}
|
|
}
|