From 30da0f94a625b8660990239285f940f38247c758 Mon Sep 17 00:00:00 2001 From: Luca Schlecker Date: Wed, 20 Nov 2024 10:37:11 +0100 Subject: [PATCH] feat: adaptive theme selection based on the terminal color scheme --- Cargo.lock | 26 ++++++++++++++++++++++++++ book/src/configuration.md | 2 ++ book/src/themes.md | 1 + helix-term/src/application.rs | 2 ++ helix-term/src/config.rs | 4 ++-- helix-view/Cargo.toml | 1 + helix-view/src/theme.rs | 24 +++++++++++++++++++++++- 7 files changed, 57 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4f03c797..ed539372c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1459,6 +1459,7 @@ dependencies = [ "serde_json", "slotmap", "tempfile", + "terminal-colorsaurus", "thiserror 2.0.3", "tokio", "tokio-stream", @@ -2376,6 +2377,31 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "terminal-colorsaurus" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7778d24b27585f6f92ec5d2705e7cf1710fd0ffa43262c807dfb49fa53471e95" +dependencies = [ + "cfg-if", + "libc", + "memchr", + "mio", + "terminal-trx", + "windows-sys 0.59.0", +] + +[[package]] +name = "terminal-trx" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57a5b836e7f4f81afe61b5cd399eee774f25edcfd47009a76e29f53bb6487833" +dependencies = [ + "cfg-if", + "libc", + "windows-sys 0.59.0", +] + [[package]] name = "termini" version = "1.0.0" diff --git a/book/src/configuration.md b/book/src/configuration.md index 317007efc..388a468ba 100644 --- a/book/src/configuration.md +++ b/book/src/configuration.md @@ -11,6 +11,8 @@ # Configuration ```toml theme = "onedark" +# Adaptive Theme +# theme = { light = "onelight", dark = "onedark" } [editor] line-number = "relative" diff --git a/book/src/themes.md b/book/src/themes.md index 4e0142ddd..a55778377 100644 --- a/book/src/themes.md +++ b/book/src/themes.md @@ -1,6 +1,7 @@ ## Themes To use a theme add `theme = ""` to the top of your [`config.toml`](./configuration.md) file, or select it during runtime using `:theme `. +Alternatively, `theme = { light = "", dark = "" }` tries to select a theme based on the terminal color scheme. The detection should work with all major terminals including Windows Terminal (starting with v1.22). ## Creating a theme diff --git a/helix-term/src/application.rs b/helix-term/src/application.rs index a567815fc..7713d256c 100644 --- a/helix-term/src/application.rs +++ b/helix-term/src/application.rs @@ -113,6 +113,7 @@ pub fn new(args: Args, config: Config, lang_loader: syntax::Loader) -> Result Result<(), Error> { let theme = config .theme .as_ref() + .map(helix_view::theme::Config::get_active_theme) .and_then(|theme| { self.theme_loader .load(theme) diff --git a/helix-term/src/config.rs b/helix-term/src/config.rs index bcba8d8e1..af24566f6 100644 --- a/helix-term/src/config.rs +++ b/helix-term/src/config.rs @@ -11,7 +11,7 @@ #[derive(Debug, Clone, PartialEq)] pub struct Config { - pub theme: Option, + pub theme: Option, pub keys: HashMap, pub editor: helix_view::editor::Config, } @@ -19,7 +19,7 @@ pub struct Config { #[derive(Debug, Clone, PartialEq, Deserialize)] #[serde(deny_unknown_fields)] pub struct ConfigRaw { - pub theme: Option, + pub theme: Option, pub keys: Option>, pub editor: Option, } diff --git a/helix-view/Cargo.toml b/helix-view/Cargo.toml index 6bbe15868..755676dca 100644 --- a/helix-view/Cargo.toml +++ b/helix-view/Cargo.toml @@ -27,6 +27,7 @@ helix-vcs = { path = "../helix-vcs" } bitflags = "2.6" anyhow = "1" crossterm = { version = "0.28", optional = true } +terminal-colorsaurus = "0.4" tempfile = "3.14" diff --git a/helix-view/src/theme.rs b/helix-view/src/theme.rs index 9dc326444..e658d0959 100644 --- a/helix-view/src/theme.rs +++ b/helix-view/src/theme.rs @@ -9,7 +9,7 @@ use helix_loader::merge_toml_values; use log::warn; use once_cell::sync::Lazy; -use serde::{Deserialize, Deserializer}; +use serde::{Deserialize, Deserializer, Serialize}; use toml::{map::Map, Value}; use crate::graphics::UnderlineStyle; @@ -540,6 +540,28 @@ fn try_from(value: Value) -> Result { } } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[serde(untagged, deny_unknown_fields)] +pub enum Config { + Static(String), + Adaptive { light: String, dark: String }, +} + +impl Config { + pub fn get_active_theme(&self) -> &str { + match self { + Config::Static(x) => x, + Config::Adaptive { light, dark } => { + use terminal_colorsaurus::{color_scheme, ColorScheme, QueryOptions}; + match color_scheme(QueryOptions::default()).unwrap_or(ColorScheme::Dark) { + ColorScheme::Light => light, + ColorScheme::Dark => dark, + } + } + } + } +} + #[cfg(test)] mod tests { use super::*;