feat: adaptive theme selection based on the terminal color scheme

pull/12098/head
Luca Schlecker 5 days ago
parent 6101b3a7a3
commit 30da0f94a6

26
Cargo.lock generated

@ -1459,6 +1459,7 @@ dependencies = [
"serde_json", "serde_json",
"slotmap", "slotmap",
"tempfile", "tempfile",
"terminal-colorsaurus",
"thiserror 2.0.3", "thiserror 2.0.3",
"tokio", "tokio",
"tokio-stream", "tokio-stream",
@ -2376,6 +2377,31 @@ dependencies = [
"windows-sys 0.59.0", "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]] [[package]]
name = "termini" name = "termini"
version = "1.0.0" version = "1.0.0"

@ -11,6 +11,8 @@ Example config:
```toml ```toml
theme = "onedark" theme = "onedark"
# Adaptive Theme
# theme = { light = "onelight", dark = "onedark" }
[editor] [editor]
line-number = "relative" line-number = "relative"

@ -1,6 +1,7 @@
## Themes ## Themes
To use a theme add `theme = "<name>"` to the top of your [`config.toml`](./configuration.md) file, or select it during runtime using `:theme <name>`. To use a theme add `theme = "<name>"` to the top of your [`config.toml`](./configuration.md) file, or select it during runtime using `:theme <name>`.
Alternatively, `theme = { light = "<name>", dark = "<name>" }` 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 ## Creating a theme

@ -113,6 +113,7 @@ impl Application {
let theme = config let theme = config
.theme .theme
.as_ref() .as_ref()
.map(helix_view::theme::Config::get_active_theme)
.and_then(|theme| { .and_then(|theme| {
theme_loader theme_loader
.load(theme) .load(theme)
@ -428,6 +429,7 @@ impl Application {
let theme = config let theme = config
.theme .theme
.as_ref() .as_ref()
.map(helix_view::theme::Config::get_active_theme)
.and_then(|theme| { .and_then(|theme| {
self.theme_loader self.theme_loader
.load(theme) .load(theme)

@ -11,7 +11,7 @@ use toml::de::Error as TomlError;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Config { pub struct Config {
pub theme: Option<String>, pub theme: Option<helix_view::theme::Config>,
pub keys: HashMap<Mode, KeyTrie>, pub keys: HashMap<Mode, KeyTrie>,
pub editor: helix_view::editor::Config, pub editor: helix_view::editor::Config,
} }
@ -19,7 +19,7 @@ pub struct Config {
#[derive(Debug, Clone, PartialEq, Deserialize)] #[derive(Debug, Clone, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)] #[serde(deny_unknown_fields)]
pub struct ConfigRaw { pub struct ConfigRaw {
pub theme: Option<String>, pub theme: Option<helix_view::theme::Config>,
pub keys: Option<HashMap<Mode, KeyTrie>>, pub keys: Option<HashMap<Mode, KeyTrie>>,
pub editor: Option<toml::Value>, pub editor: Option<toml::Value>,
} }

@ -27,6 +27,7 @@ helix-vcs = { path = "../helix-vcs" }
bitflags = "2.6" bitflags = "2.6"
anyhow = "1" anyhow = "1"
crossterm = { version = "0.28", optional = true } crossterm = { version = "0.28", optional = true }
terminal-colorsaurus = "0.4"
tempfile = "3.14" tempfile = "3.14"

@ -9,7 +9,7 @@ use helix_core::hashmap;
use helix_loader::merge_toml_values; use helix_loader::merge_toml_values;
use log::warn; use log::warn;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use serde::{Deserialize, Deserializer}; use serde::{Deserialize, Deserializer, Serialize};
use toml::{map::Map, Value}; use toml::{map::Map, Value};
use crate::graphics::UnderlineStyle; use crate::graphics::UnderlineStyle;
@ -540,6 +540,28 @@ impl TryFrom<Value> for ThemePalette {
} }
} }
#[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)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;

Loading…
Cancel
Save