From 51a497cb043da0c1cee9c67c7430c796850a2641 Mon Sep 17 00:00:00 2001 From: Gregor Lohaus Date: Tue, 8 Sep 2026 10:32:15 +0200 Subject: [PATCH] theming --- .gitignore | 1 + config.example.toml | 23 +- examples/gen_themes.rs | 699 ++++ src/app.rs | 83 +- src/config.rs | 49 +- src/main.rs | 10 +- src/pane.rs | 51 +- src/render.rs | 75 +- src/tests.rs | 27 +- src/theme.rs | 261 ++ src/themes.rs | 3623 +++++++++++++++++ themes/LICENSES/ashen.license | 22 + themes/LICENSES/carbonfox.license | 21 + themes/LICENSES/cyan_light.LICENSE | 21 + themes/LICENSES/dark-synthwave.license | 21 + themes/LICENSES/doom-one.LICENSE | 23 + themes/LICENSES/everforest.LICENSE | 21 + themes/LICENSES/kinda_nvim.LICENSE | 21 + themes/LICENSES/lapis_aquamarine.LICENSE | 23 + themes/LICENSES/modus_vivendi.LICENSE | 5 + .../modus_vivendi_deuteranopia.LICENSE | 5 + themes/LICENSES/modus_vivendi_tinted.LICENSE | 5 + .../LICENSES/modus_vivendi_tritanopia.LICENSE | 5 + themes/LICENSES/poimandres.LICENSE | 21 + themes/LICENSES/serika-syntax.LICENSE | 21 + themes/LICENSES/sonokai.LICENSE | 21 + themes/LICENSES/starlight.LICENSE | 24 + themes/LICENSES/vesper.LICENSE | 21 + 28 files changed, 5135 insertions(+), 68 deletions(-) create mode 100644 examples/gen_themes.rs create mode 100644 src/theme.rs create mode 100644 src/themes.rs create mode 100644 themes/LICENSES/ashen.license create mode 100644 themes/LICENSES/carbonfox.license create mode 100644 themes/LICENSES/cyan_light.LICENSE create mode 100644 themes/LICENSES/dark-synthwave.license create mode 100644 themes/LICENSES/doom-one.LICENSE create mode 100644 themes/LICENSES/everforest.LICENSE create mode 100644 themes/LICENSES/kinda_nvim.LICENSE create mode 100644 themes/LICENSES/lapis_aquamarine.LICENSE create mode 100644 themes/LICENSES/modus_vivendi.LICENSE create mode 100644 themes/LICENSES/modus_vivendi_deuteranopia.LICENSE create mode 100644 themes/LICENSES/modus_vivendi_tinted.LICENSE create mode 100644 themes/LICENSES/modus_vivendi_tritanopia.LICENSE create mode 100644 themes/LICENSES/poimandres.LICENSE create mode 100644 themes/LICENSES/serika-syntax.LICENSE create mode 100644 themes/LICENSES/sonokai.LICENSE create mode 100644 themes/LICENSES/starlight.LICENSE create mode 100644 themes/LICENSES/vesper.LICENSE diff --git a/.gitignore b/.gitignore index 8dd2a95..85d0da3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ /target/ /.tools/ /result +/.worktrees diff --git a/config.example.toml b/config.example.toml index a89b2fd..5ccf992 100644 --- a/config.example.toml +++ b/config.example.toml @@ -7,9 +7,26 @@ font_size = 16 scrollback = 10000 window_width = 1100 window_height = 720 -background = "#17191c" -foreground = "#e2e4e8" -accent = "#58c4ad" + +# Any theme from `slerm --list-themes`: "slerm" plus every theme Helix ships. +theme = "slerm" + +# Shorthand for the [colors] entries of the same name. +# background = "#17191c" +# foreground = "#e2e4e8" +# accent = "#58c4ad" + +# Colors overriding the theme, all optional. Alongside the three above: +# cursor, selection_background, selection_foreground, border, +# chrome_background, chrome_foreground, chrome_active_background, +# popup_background, +# and the sixteen ANSI colors: +# black, red, green, yellow, blue, magenta, cyan, white, +# and each of those again as bright_black ... bright_white. +# [colors] +# cursor = "#58c4ad" +# red = "#cc6666" +# bright_red = "#d54e53" [kitty] image_storage_mb = 64 diff --git a/examples/gen_themes.rs b/examples/gen_themes.rs new file mode 100644 index 0000000..b0da02b --- /dev/null +++ b/examples/gen_themes.rs @@ -0,0 +1,699 @@ +//! Converts the themes Helix ships in `runtime/themes` into `src/themes.rs`. +//! +//! Helix themes describe an editor: they name syntax scopes, not the sixteen +//! ANSI colors a terminal needs. The conversion therefore reads the UI scopes +//! directly (`ui.background`, `ui.statusline`, ...) and *infers* the ANSI +//! palette by scoring every color the theme uses against the hue each slot is +//! expected to hold, preferring the scopes that conventionally carry it. +//! +//! cargo run --example gen_themes -- /runtime/themes src/themes.rs + +use std::{collections::BTreeMap, fmt::Write as _, path::Path}; +use toml::Value; + +type Rgb = [u8; 3]; + +/// A color as written in a theme: its RGB value, plus the ANSI slot it named if +/// it was written as one of Helix's terminal color names rather than as hex. +#[derive(Clone, Copy, PartialEq, Eq)] +struct Color { + rgb: Rgb, + ansi: Option, +} + +/// Helix's terminal color names and the palette slots they select. `gray` is +/// the dim one and `light-gray` the bright one, matching how Helix hands them +/// to crossterm (`Gray` -> dark grey, `LightGray` -> grey). +const NAMED: &[(&str, u8)] = &[ + ("black", 0), + ("red", 1), + ("green", 2), + ("yellow", 3), + ("blue", 4), + ("magenta", 5), + ("cyan", 6), + ("light-gray", 7), + ("gray", 8), + ("light-red", 9), + ("light-green", 10), + ("light-yellow", 11), + ("light-blue", 12), + ("light-magenta", 13), + ("light-cyan", 14), + ("white", 15), +]; + +/// The xterm defaults, used both for themes that name terminal colors outright +/// and as the last resort for a slot nothing in a theme fits. +const XTERM: [Rgb; 16] = [ + [0x00, 0x00, 0x00], + [0xcd, 0x00, 0x00], + [0x00, 0xcd, 0x00], + [0xcd, 0xcd, 0x00], + [0x00, 0x00, 0xee], + [0xcd, 0x00, 0xcd], + [0x00, 0xcd, 0xcd], + [0xe5, 0xe5, 0xe5], + [0x7f, 0x7f, 0x7f], + [0xff, 0x00, 0x00], + [0x00, 0xff, 0x00], + [0xff, 0xff, 0x00], + [0x5c, 0x5c, 0xff], + [0xff, 0x00, 0xff], + [0x00, 0xff, 0xff], + [0xff, 0xff, 0xff], +]; + +/// The hue each chromatic slot aims for, and the scopes that conventionally +/// carry it. Earlier scopes are preferred, but only as a tie-break: a theme +/// whose `function` is teal still gets a teal blue rather than a stray hue. +const SLOTS: [(u8, f32, &[&str]); 6] = [ + ( + 1, + 0.0, + &[ + "error", + "diagnostic.error", + "diff.minus", + "keyword.control.exception", + "markup.list.unchecked", + "variable.builtin", + ], + ), + ( + 2, + 120.0, + &[ + "string", + "diff.plus", + "markup.raw", + "hint", + "diagnostic.hint", + "variable.other.member", + ], + ), + ( + 3, + 48.0, + &[ + "warning", + "diagnostic.warning", + "constant.numeric", + "attribute", + "type", + "markup.heading", + ], + ), + ( + 4, + 230.0, + &[ + "function", + "info", + "diagnostic.info", + "constructor", + "markup.link.url", + "diff.delta", + ], + ), + ( + 5, + 300.0, + &[ + "keyword", + "constant", + "special", + "namespace", + "markup.link.text", + "type.enum.variant", + ], + ), + ( + 6, + 185.0, + &[ + "operator", + "constant.character.escape", + "markup.quote", + "string.special", + "punctuation.special", + "label", + ], + ), +]; + +/// One theme file, before inheritance is resolved. +#[derive(Default)] +struct Raw { + inherits: Option, + palette: BTreeMap, + /// Scope -> (fg, bg), each already flattened out of Helix's several + /// spellings (bare string, `{ fg, bg }`, `{ underline = { color } }`). + scopes: BTreeMap, Option)>, +} + +fn read(path: &Path) -> Raw { + let text = std::fs::read_to_string(path).expect("cannot read theme file"); + let table: toml::Table = toml::from_str(&text).expect("theme is not valid TOML"); + let mut raw = Raw::default(); + for (key, value) in table { + match (key.as_str(), value) { + ("inherits", Value::String(name)) => raw.inherits = Some(name), + ("palette", Value::Table(entries)) => { + for (name, value) in entries { + if let Value::String(color) = value { + raw.palette.insert(name, color); + } + } + } + (_, Value::String(fg)) => { + raw.scopes.insert(key, (Some(fg), None)); + } + (_, Value::Table(style)) => { + let text = |v: Option<&Value>| v.and_then(Value::as_str).map(str::to_owned); + let fg = text(style.get("fg")).or_else(|| { + style + .get("underline") + .and_then(Value::as_table) + .and_then(|u| text(u.get("color"))) + }); + raw.scopes.insert(key, (fg, text(style.get("bg")))); + } + _ => {} + } + } + raw +} + +/// A theme with its `inherits` chain folded in: the child's palette entries and +/// whole scope entries win over the parent's, exactly as Helix merges them. +struct Theme { + palette: BTreeMap, + scopes: BTreeMap, Option)>, +} + +fn flatten(name: &str, raws: &BTreeMap) -> Theme { + let mut chain = vec![]; + let mut current = Some(name.to_owned()); + while let Some(name) = current { + if chain.contains(&name) { + break; + } + current = raws.get(&name).and_then(|r| r.inherits.clone()); + chain.push(name); + } + let mut theme = Theme { + palette: BTreeMap::new(), + scopes: BTreeMap::new(), + }; + // Ancestors first so that descendants overwrite them. + for name in chain.iter().rev() { + let Some(raw) = raws.get(name) else { continue }; + theme.palette.extend(raw.palette.clone()); + theme.scopes.extend(raw.scopes.clone()); + } + theme +} + +impl Theme { + fn color(&self, text: &str) -> Option { + let text = self.palette.get(text).map(String::as_str).unwrap_or(text); + if let Some((_, index)) = NAMED.iter().find(|(name, _)| *name == text) { + return Some(Color { + rgb: XTERM[*index as usize], + ansi: Some(*index), + }); + } + let digits = text.strip_prefix('#')?; + let expand = |c: u8| (c << 4) | c; + let nibble = |i: usize| u8::from_str_radix(&digits[i..i + 1], 16).ok(); + let byte = |i: usize| u8::from_str_radix(&digits[i..i + 2], 16).ok(); + let rgb = match digits.len() { + 3 => [expand(nibble(0)?), expand(nibble(1)?), expand(nibble(2)?)], + 6 | 8 => [byte(0)?, byte(2)?, byte(4)?], + _ => return None, + }; + Some(Color { rgb, ansi: None }) + } + + fn fg(&self, scope: &str) -> Option { + self.color(self.scopes.get(scope)?.0.as_deref()?) + } + + fn bg(&self, scope: &str) -> Option { + self.color(self.scopes.get(scope)?.1.as_deref()?) + } + + /// Every color the theme mentions anywhere, with the number of scopes that + /// use it. This is the pool the ANSI slots are chosen from; the count + /// separates a theme's working colors from one-off accents such as the + /// color of a jump label. + fn all(&self) -> Vec<(Color, usize)> { + let mut counts: BTreeMap = BTreeMap::new(); + let named = self.palette.values().map(String::as_str); + // `ui.*` carries backgrounds, greys and one-off markers such as the + // color of a jump label, none of which belong in a terminal palette. + let scoped = self + .scopes + .iter() + .filter(|(scope, _)| !scope.starts_with("ui.")) + .flat_map(|(_, (fg, bg))| [fg, bg]) + .filter_map(|c| c.as_deref()); + for color in named.chain(scoped).filter_map(|c| self.color(c)) { + counts.entry(color.rgb).or_insert((color, 0)).1 += 1; + } + counts.into_values().collect() + } +} + +fn luma(c: Rgb) -> f32 { + let channel = |v: u8| { + let v = v as f32 / 255.0; + if v <= 0.04045 { + v / 12.92 + } else { + ((v + 0.055) / 1.055).powf(2.4) + } + }; + 0.2126 * channel(c[0]) + 0.7152 * channel(c[1]) + 0.0722 * channel(c[2]) +} + +fn contrast(a: Rgb, b: Rgb) -> f32 { + let (a, b) = (luma(a) + 0.05, luma(b) + 0.05); + if a > b { a / b } else { b / a } +} + +/// Hue in degrees, saturation and lightness in 0..1. +fn hsl(c: Rgb) -> (f32, f32, f32) { + let [r, g, b] = [ + c[0] as f32 / 255.0, + c[1] as f32 / 255.0, + c[2] as f32 / 255.0, + ]; + let max = r.max(g).max(b); + let min = r.min(g).min(b); + let (span, sum) = (max - min, max + min); + let lightness = sum / 2.0; + if span < f32::EPSILON { + return (0.0, 0.0, lightness); + } + let saturation = span / (1.0 - (sum - 1.0).abs()); + let hue = if max == r { + 60.0 * (((g - b) / span) % 6.0) + } else if max == g { + 60.0 * ((b - r) / span + 2.0) + } else { + 60.0 * ((r - g) / span + 4.0) + }; + (hue.rem_euclid(360.0), saturation, lightness) +} + +fn hue_distance(a: f32, b: f32) -> f32 { + let d = (a - b).abs() % 360.0; + d.min(360.0 - d) +} + +fn mix(a: Rgb, b: Rgb, t: f32) -> Rgb { + let channel = |i: usize| (a[i] as f32 + (b[i] as f32 - a[i] as f32) * t).round() as u8; + [channel(0), channel(1), channel(2)] +} + +const BLACK: Rgb = [0, 0, 0]; +const WHITE: Rgb = [255, 255, 255]; + +/// The converted theme, mirroring the struct in `src/theme.rs`. +struct Out { + dark: bool, + background: Rgb, + foreground: Rgb, + cursor: Rgb, + selection_bg: Rgb, + selection_fg: Rgb, + accent: Rgb, + chrome_bg: Rgb, + chrome_fg: Rgb, + chrome_active_bg: Rgb, + border: Rgb, + popup_bg: Rgb, + ansi: [Rgb; 16], +} + +fn convert(theme: &Theme) -> Out { + let text = theme + .fg("ui.text") + .or_else(|| theme.fg("ui.background")) + .or_else(|| theme.fg("ui.statusline")); + let background = theme + .bg("ui.background") + .or_else(|| theme.bg("ui.popup")) + .or_else(|| theme.bg("ui.statusline")); + // A theme that never states a background (the `term16` family leaves it to + // the terminal) is placed by the brightness of its text instead. + let dark = match (background, text) { + (Some(bg), _) => luma(bg.rgb) < 0.22, + (None, Some(fg)) => luma(fg.rgb) > 0.22, + (None, None) => true, + }; + let background = background.map_or(if dark { BLACK } else { WHITE }, |c| c.rgb); + let mut foreground = text.map_or(if dark { WHITE } else { BLACK }, |c| c.rgb); + // A theme that states neither (peachpuff leaves both to the terminal) can + // resolve to text the same shade as its background, which renders nothing. + if contrast(foreground, background) < 2.0 { + foreground = if dark { WHITE } else { BLACK }; + } + let far = if dark { WHITE } else { BLACK }; + + let ansi = palette(theme, background, foreground, dark); + let cursor = theme + .bg("ui.cursor.primary") + .or_else(|| theme.bg("ui.cursor")) + .or_else(|| theme.fg("ui.cursor.primary")) + .or_else(|| theme.fg("ui.cursor")) + .map_or(foreground, |c| c.rgb); + let selection_bg = theme + .bg("ui.selection.primary") + .or_else(|| theme.bg("ui.selection")) + .map_or(mix(background, far, 0.22), |c| c.rgb); + let selection_fg = theme + .fg("ui.selection.primary") + .or_else(|| theme.fg("ui.selection")) + .map(|c| c.rgb) + .filter(|c| contrast(*c, selection_bg) >= 2.5) + .unwrap_or_else(|| { + if contrast(foreground, selection_bg) >= 2.5 { + foreground + } else { + mix( + selection_bg, + if luma(selection_bg) > 0.3 { + BLACK + } else { + WHITE + }, + 0.85, + ) + } + }); + let chrome_bg = theme + .bg("ui.statusline") + .or_else(|| theme.bg("ui.popup")) + .map(|c| c.rgb) + .filter(|c| *c != background) + .unwrap_or_else(|| mix(background, far, 0.09)); + let chrome_fg = theme + .fg("ui.statusline") + .map(|c| c.rgb) + .filter(|c| contrast(*c, chrome_bg) >= 2.0) + .unwrap_or_else(|| mix(chrome_bg, far, 0.7)); + // The accent marks the focused pane: it is drawn both on the title bar and + // as a border on the terminal background, so it has to read on both. + let readable = |c: Rgb| contrast(c, chrome_bg) >= 2.5 && contrast(c, background) >= 2.5; + let vivid = [theme.fg("ui.cursor.match").map(|c| c.rgb), Some(cursor)] + .into_iter() + .flatten() + .find(|c| readable(*c) && hsl(*c).1 > 0.30); + let accent = vivid + // A theme whose cursor is a plain grey still deserves a colored focus + // ring, so fall back to its own blue, cyan or magenta. + .or_else(|| { + [4, 6, 5, 3] + .into_iter() + .map(|i| ansi[i]) + .find(|c| readable(*c)) + }) + .or(Some(cursor).filter(|c| readable(*c))) + .unwrap_or(foreground); + Out { + dark, + background, + foreground, + cursor, + selection_bg, + selection_fg, + accent, + chrome_bg, + chrome_fg, + // The focused pane's title bar steps away from the unfocused ones, + // whichever direction that is for this theme's chrome. + chrome_active_bg: mix( + chrome_bg, + if luma(chrome_bg) > 0.18 { BLACK } else { WHITE }, + 0.14, + ), + // Unfocused borders are a hint, not a frame, so a theme with a loud + // window color is pulled back towards its background. + border: theme + .fg("ui.window") + .or_else(|| theme.fg("ui.virtual.indent-guide")) + .map_or(mix(background, far, 0.28), |c| mix(background, c.rgb, 0.65)), + popup_bg: theme.bg("ui.popup").map_or(chrome_bg, |c| c.rgb), + ansi, + } +} + +/// Picks the sixteen ANSI colors. The six chromatic slots score every color the +/// theme uses against the slot's hue; the greys are derived from the background +/// and foreground so that they always stay legible against the theme's own +/// background. +fn palette(theme: &Theme, background: Rgb, foreground: Rgb, dark: bool) -> [Rgb; 16] { + let pool = theme.all(); + let mut ansi = XTERM; + // A theme whose palette names terminal colors outright is already + // describing a palette; those entries are taken as written. + let named: BTreeMap = theme + .palette + .keys() + .filter_map(|name| Some((slot_named(name)?, theme.color(name)?.rgb))) + .collect(); + let mut taken: Vec = vec![]; + let mut assigned = [false; 7]; + for (index, rgb) in &named { + ansi[*index as usize] = *rgb; + if let Some(slot) = assigned.get_mut(*index as usize) { + *slot = true; + taken.push(*rgb); + } + } + + // Score every slot against every color the theme uses, then hand each color + // to the slot that wants it most. Assigning greedily one slot at a time + // would let an early slot take a color a later slot needed far more, which + // is how palettes with no true blue end up with two cyans. + let mut pairs: Vec<(f32, usize, Rgb)> = vec![]; + for (index, hue, scopes) in SLOTS { + if assigned[index as usize] { + continue; + } + let preferred: Vec = scopes + .iter() + .filter_map(|s| Some(theme.fg(s)?.rgb)) + .collect(); + for (candidate, uses) in &pool { + let (h, s, l) = hsl(candidate.rgb); + // A grey, an unreadable color, the plain text color and a color the + // theme only spelled as a terminal name (which says nothing about + // what that terminal color should be) are never palette entries. + if s < 0.10 + || contrast(candidate.rgb, background) < 1.8 + || candidate.ansi.is_some() + || candidate.rgb == foreground + || candidate.rgb == background + { + continue; + } + let rank = preferred + .iter() + .position(|p| *p == candidate.rgb) + .map_or(20.0, |r| r as f32 * 2.5); + // Whichever slot's hue this color sits closest to has the better + // claim on it, so that a theme's red is not spent on magenta just + // because it happens to be the color of `keyword`. + let closest = SLOTS + .iter() + .map(|(_, target, _)| *target) + .min_by(|a, b| hue_distance(h, *a).total_cmp(&hue_distance(h, *b))); + let score = hue_distance(h, hue) * 1.5 + + rank + + (1.0 - s) * 38.0 + + if closest == Some(hue) { 0.0 } else { 45.0 } + // A color used once is a one-off accent, not a working color. + + match uses { + 0 | 1 => 22.0, + 2 => 10.0, + _ => 0.0, + } + + if l > 0.85 { 40.0 } else { 0.0 }; + pairs.push((score, index as usize, candidate.rgb)); + } + } + pairs.sort_by(|a, b| a.0.total_cmp(&b.0).then(a.1.cmp(&b.1))); + for (_, index, rgb) in &pairs { + if !assigned[*index] && !taken.contains(rgb) { + assigned[*index] = true; + ansi[*index] = *rgb; + taken.push(*rgb); + } + } + // A theme with fewer than six usable colors leaves slots over; those share + // whichever color came closest rather than falling back to a stock xterm + // primary that belongs to no theme at all. + for (_, index, rgb) in &pairs { + if !assigned[*index] { + assigned[*index] = true; + ansi[*index] = *rgb; + } + } + for (index, _, _) in SLOTS { + if !assigned[index as usize] { + ansi[index as usize] = mix(XTERM[index as usize], foreground, 0.4); + } + } + + // The bright variant is the theme's own lighter shade of the same color + // where it has one, and a lightened copy otherwise. Matching the hue is not + // enough: a pale grey-blue is a poor bright blue, so the candidate has to + // keep most of the base color's chroma, and it cannot be a color another + // slot already owns. + let chroma = |c: Rgb| (*c.iter().max().unwrap() - *c.iter().min().unwrap()) as f32; + for (index, _, _) in SLOTS { + if named.contains_key(&(index + 8)) { + continue; + } + let base = ansi[index as usize]; + let (base_hue, _, lightness) = hsl(base); + let brighter = pool + .iter() + .map(|(c, _)| c) + .filter(|c| { + let (h, _, l) = hsl(c.rgb); + hue_distance(h, base_hue) <= 30.0 + && chroma(c.rgb) >= chroma(base) * 0.7 + && (0.05..=0.40).contains(&(l - lightness)) + && contrast(c.rgb, background) >= 2.0 + && !taken.contains(&c.rgb) + }) + .min_by(|a, b| hsl(a.rgb).2.total_cmp(&hsl(b.rgb).2)); + ansi[index as usize + 8] = brighter.map_or_else( + || mix(base, WHITE, if lightness > 0.7 { 0.12 } else { 0.26 }), + |c| c.rgb, + ); + } + + // Greys: black through bright white always span from the theme's darker end + // to its lighter end, so ANSI text stays readable in light themes too. + let comment = theme + .fg("comment") + .map(|c| c.rgb) + .filter(|c| contrast(*c, background) >= 2.0); + let greys = if dark { + [ + mix(background, WHITE, 0.13), + foreground, + comment.unwrap_or_else(|| mix(background, WHITE, 0.42)), + mix(foreground, WHITE, 0.35), + ] + } else { + [ + mix(foreground, BLACK, 0.25), + mix(background, BLACK, 0.13), + comment.unwrap_or_else(|| mix(foreground, background, 0.45)), + background, + ] + }; + for (slot, grey) in [0, 7, 8, 15].into_iter().zip(greys) { + ansi[slot as usize] = *named.get(&slot).unwrap_or(&grey); + } + ansi +} + +/// The palette slot a `[palette]` key names outright, so that a theme defining +/// `red`/`bright-blue` and friends keeps its own values. +fn slot_named(name: &str) -> Option { + let name = name.to_ascii_lowercase().replace('_', "-"); + let (bright, base) = match name + .strip_prefix("bright-") + .or_else(|| name.strip_prefix("light-")) + { + Some(base) => (8, base.to_owned()), + None => (0, name), + }; + let index = match base.as_str() { + "black" => 0, + "red" => 1, + "green" => 2, + "yellow" => 3, + "blue" => 4, + "magenta" => 5, + "cyan" => 6, + "white" => 7, + _ => return None, + }; + Some(index + bright) +} + +fn main() { + let mut args = std::env::args().skip(1); + let dir = args + .next() + .expect("usage: gen_themes "); + let out = args + .next() + .expect("usage: gen_themes "); + + let mut raws = BTreeMap::new(); + for entry in std::fs::read_dir(&dir).expect("cannot read themes directory") { + let path = entry.expect("cannot read theme").path(); + if path.extension().is_some_and(|e| e == "toml") { + let name = path.file_stem().unwrap().to_string_lossy().into_owned(); + raws.insert(name, read(&path)); + } + } + + let mut text = String::from( + "//! The themes Helix ships with, converted by `cargo run --example gen_themes`.\n\ + //! Generated file: edit the generator, not this.\n\ + //!\n\ + //! Upstream: .\n\ + //! The individual themes keep their own authors and licenses; see `themes/LICENSES`.\n\n\ + use crate::theme::Theme;\n\n\ + /// Every built-in theme, sorted by name so that lookup can binary search.\n\ + pub static THEMES: &[(&str, Theme)] = &[\n", + ); + for name in raws.keys() { + let out = convert(&flatten(name, &raws)); + let hex = |c: Rgb| format!("0x{:02x}{:02x}{:02x}", c[0], c[1], c[2]); + let ansi = out + .ansi + .iter() + .map(|c| hex(*c)) + .collect::>() + .join(", "); + writeln!( + text, + " (\n {name:?},\n Theme {{\n \ + dark: {dark},\n background: {bg},\n foreground: {fg},\n \ + cursor: {cursor},\n \ + selection_bg: {sel_bg},\n selection_fg: {sel_fg},\n \ + accent: {accent},\n chrome_bg: {chrome_bg},\n \ + chrome_fg: {chrome_fg},\n chrome_active_bg: {chrome_active},\n \ + border: {border},\n popup_bg: {popup},\n \ + ansi: [\n {ansi},\n ],\n }},\n ),", + dark = out.dark, + bg = hex(out.background), + fg = hex(out.foreground), + cursor = hex(out.cursor), + sel_bg = hex(out.selection_bg), + sel_fg = hex(out.selection_fg), + accent = hex(out.accent), + chrome_bg = hex(out.chrome_bg), + chrome_fg = hex(out.chrome_fg), + chrome_active = hex(out.chrome_active_bg), + border = hex(out.border), + popup = hex(out.popup_bg), + ) + .unwrap(); + } + text.push_str("];\n"); + std::fs::write(&out, text).expect("cannot write output"); + eprintln!("wrote {} themes to {out}", raws.len()); +} diff --git a/src/app.rs b/src/app.rs index 22e547d..d2bbc3a 100644 --- a/src/app.rs +++ b/src/app.rs @@ -3,10 +3,10 @@ use crate::{ input, layout::{Axis, Direction, Layout, PaneId, Tab}, pane::{self, Pane}, - render::color, + theme::{self, Theme}, }; use anyhow::{Result, ensure}; -use egui::{Color32, CornerRadius, Rect, Stroke, vec2}; +use egui::{CornerRadius, Rect, Stroke, vec2}; use std::{ collections::{BTreeMap, HashSet}, path::PathBuf, @@ -14,6 +14,7 @@ use std::{ pub struct App { config: Config, + theme: Theme, config_path: PathBuf, panes: BTreeMap, tabs: Vec, @@ -76,11 +77,13 @@ impl App { config: Config, config_path: PathBuf, ) -> Result { - cc.egui_ctx.set_visuals(egui::Visuals::dark()); + let theme = config.theme()?; + cc.egui_ctx.set_visuals(theme.visuals()); cc.egui_ctx.set_fonts(fonts(&config)?); - let pane = Pane::new(&config, &cc.egui_ctx, None)?; + let pane = Pane::new(&config, &theme, &cc.egui_ctx, None)?; Ok(Self { config, + theme, config_path, panes: BTreeMap::from([(1, pane)]), tabs: vec![Tab::new(1, 1)], @@ -102,13 +105,27 @@ impl App { .get(self.current) .and_then(|tab| self.panes.get(&tab.active)) .and_then(Pane::cwd); - let pane = Pane::new(&self.config, ctx, cwd.as_deref())?; + let pane = Pane::new(&self.config, &self.theme, ctx, cwd.as_deref())?; let id = self.next_id; self.next_id += 1; self.panes.insert(id, pane); Ok(id) } + /// Switches theme for this session. Every open pane is retinted, since a + /// terminal keeps its palette rather than asking for it each frame. + fn set_theme(&mut self, name: &str, ctx: &egui::Context) -> Result<()> { + let previous = std::mem::replace(&mut self.config.theme, name.to_owned()); + self.theme = self.config.theme().inspect_err(|_| { + self.config.theme = previous; + })?; + for pane in self.panes.values_mut() { + pane::apply_config(&mut pane.terminal, &self.config, &self.theme)?; + } + ctx.set_visuals(self.theme.visuals()); + Ok(()) + } + fn action(&mut self, action: Action, ctx: &egui::Context) -> Result<()> { let active = self.tabs[self.current].active; match action { @@ -216,10 +233,12 @@ impl App { Action::ReloadConfig => { let config = Config::load(&self.config_path)?; let fonts = fonts(&config)?; + self.theme = config.theme()?; for pane in self.panes.values_mut() { - pane::apply_config(&mut pane.terminal, &config)?; + pane::apply_config(&mut pane.terminal, &config, &self.theme)?; } ctx.set_fonts(fonts); + ctx.set_visuals(self.theme.visuals()); self.config = config; } Action::Copy => { @@ -382,6 +401,7 @@ impl eframe::App for App { return; } let mut action = None; + let mut picked = None; egui::TopBottomPanel::top("tabs").show(ctx, |ui| { ui.horizontal_wrapped(|ui| { if cfg!(target_os = "macos") { @@ -429,6 +449,20 @@ impl eframe::App for App { action = Some(Action::ReloadConfig); ui.close(); } + ui.menu_button("Theme", |ui| { + ui.label("Applies now; set `theme` in the config to keep it."); + egui::ScrollArea::vertical() + .max_height(420.0) + .show(ui, |ui| { + for name in theme::names() { + let current = self.config.theme == name; + if ui.selectable_label(current, name).clicked() && !current { + picked = Some(name); + ui.close(); + } + } + }); + }); }); }); if cfg!(target_os = "macos") { @@ -438,14 +472,14 @@ impl eframe::App for App { if let Some(error) = self.error.clone() { egui::TopBottomPanel::bottom("error").show(ctx, |ui| { ui.horizontal_wrapped(|ui| { - ui.colored_label(Color32::LIGHT_RED, error); + ui.colored_label(theme::color(self.theme.ansi[9]), error); if ui.button("Dismiss").clicked() { self.error = None; } }); }); } - let bg = color(config::rgb(&self.config.background).unwrap()); + let bg = theme::color(self.theme.background); let tab = &mut self.tabs[self.current]; let mut tiled = vec![]; let mut workspace = Rect::NOTHING; @@ -464,7 +498,7 @@ impl eframe::App for App { if !tab.zoomed { pane.last_rect = *rect; } - if show_pane(ui, *id, pane, *rect, &self.config, active) { + if show_pane(ui, *id, pane, *rect, &self.config, &self.theme, active) { tab.active = *id; } } @@ -487,7 +521,7 @@ impl eframe::App for App { let rect = ui.available_rect_before_wrap(); ui.allocate_rect(rect, egui::Sense::hover()); pane.last_rect = rect; - if show_pane(ui, id, pane, rect, &self.config, active) { + if show_pane(ui, id, pane, rect, &self.config, &self.theme, active) { tab.active = id; } }); @@ -510,6 +544,11 @@ impl eframe::App for App { pane.error = Some(e.to_string()); } } + if let Some(name) = picked + && let Err(e) = self.set_theme(name, ctx) + { + self.error = Some(e.to_string()); + } if !self.tabs.is_empty() && let Some(action) = action && let Err(e) = self.action(action, ctx) @@ -552,9 +591,10 @@ fn show_pane( pane: &mut Pane, rect: Rect, config: &Config, + theme: &Theme, active: bool, ) -> bool { - let accent = color(config::rgb(&config.accent).unwrap()); + let accent = theme::color(theme.accent); let title_rect = Rect::from_min_size(rect.min, vec2(rect.width(), 25.0_f32.min(rect.height()))); // The title bar only rounds off the top of the pane, unless the pane is so // short that the bar is all there is of it. @@ -571,7 +611,11 @@ fn show_pane( sw: bottom, se: bottom, }, - Color32::from_gray(if active { 43 } else { 31 }), + theme::color(if active { + theme.chrome_active_bg + } else { + theme.chrome_bg + }), ); ui.painter() .with_clip_rect(title_rect.shrink(3.0).intersect(ui.clip_rect())) @@ -580,7 +624,11 @@ fn show_pane( egui::Align2::LEFT_TOP, pane_title(id, pane), egui::FontId::proportional(13.0), - if active { accent } else { Color32::GRAY }, + if active { + accent + } else { + theme::color(theme.chrome_fg) + }, ); // Click-only leaves dragging to the floating window's existing move handler. let header = ui.interact( @@ -594,7 +642,7 @@ fn show_pane( // The pane rectangle is already allocated; a layout scope would grow its parent. let mut content_ui = ui.new_child(egui::UiBuilder::new().id_salt(id).max_rect(content)); content_ui.set_clip_rect(content.intersect(ui.clip_rect())); - match pane.show(&mut content_ui, content, config, active) { + match pane.show(&mut content_ui, content, config, theme, active) { Ok(clicked) => focused |= clicked, Err(e) => pane.error = Some(e.to_string()), } @@ -606,7 +654,7 @@ fn show_pane( if active { accent } else { - Color32::from_gray(54) + theme::color(theme.border) }, ), egui::StrokeKind::Inside, @@ -649,9 +697,11 @@ mod tests { shell: vec!["/bin/sh".into()], ..Default::default() }; - let pane = Pane::new(&config, ctx, None).unwrap(); + let theme = config.theme().unwrap(); + let pane = Pane::new(&config, &theme, ctx, None).unwrap(); App { config, + theme, config_path: PathBuf::new(), panes: BTreeMap::from([(1, pane)]), tabs: vec![Tab::new(1, 1)], @@ -687,6 +737,7 @@ mod tests { app.panes.get_mut(&1).unwrap(), rect, &app.config, + &app.theme, true, ); }) diff --git a/src/config.rs b/src/config.rs index 5cbcc6d..c40451c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use crate::theme::{self, Theme}; use anyhow::{Context, Result, bail, ensure}; use serde::Deserialize; use std::{ @@ -17,9 +18,13 @@ pub struct Config { pub scrollback: usize, pub window_width: f32, pub window_height: f32, - pub background: String, - pub foreground: String, - pub accent: String, + pub theme: String, + /// Shorthand for the `[colors]` entries of the same name. + pub background: Option, + pub foreground: Option, + pub accent: Option, + /// Colors overriding the theme, keyed by the names in `theme::FIELDS`. + pub colors: BTreeMap, pub kitty: Kitty, pub multiplexer: Multiplexer, pub keys: BTreeMap, @@ -102,9 +107,11 @@ impl Default for Config { scrollback: 10000, window_width: 1100.0, window_height: 720.0, - background: "#17191c".into(), - foreground: "#e2e4e8".into(), - accent: "#58c4ad".into(), + theme: theme::DEFAULT_NAME.into(), + background: None, + foreground: None, + accent: None, + colors: BTreeMap::new(), kitty: Kitty::default(), multiplexer: Multiplexer::default(), keys: [ @@ -196,14 +203,38 @@ impl Config { "floating maximums must be 160..16384 points" ); } - for color in [&config.background, &config.foreground, &config.accent] { - rgb(color)?; - } + config.theme()?; for key in config.keys.keys() { shortcut(key)?; } Ok(config) } + + /// The configured theme with the `[colors]` overrides applied. Validated by + /// `parse`, so a config that loaded is a config whose theme resolves. + pub fn theme(&self) -> Result { + let mut theme = theme::find(&self.theme) + .with_context(|| format!("unknown theme: {} (try --list-themes)", self.theme))?; + let shorthand = [ + ("background", &self.background), + ("foreground", &self.foreground), + ("accent", &self.accent), + ]; + let named = shorthand + .iter() + .filter_map(|(name, value)| Some((*name, value.as_ref()?))) + .chain(self.colors.iter().map(|(k, v)| (k.as_str(), v))); + for (name, value) in named { + theme.set(name, packed(value)?)?; + } + Ok(theme) + } +} + +/// A `#RRGGBB` string as the packed integer a theme stores. +pub fn packed(text: &str) -> Result { + let color = rgb(text)?; + Ok((color.r as u32) << 16 | (color.g as u32) << 8 | color.b as u32) } pub fn rgb(text: &str) -> Result { diff --git a/src/main.rs b/src/main.rs index 6da6eb3..a101562 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,8 @@ mod pty; mod render; #[cfg(test)] mod tests; +mod theme; +mod themes; use anyhow::{Context, Result, bail}; @@ -20,13 +22,19 @@ fn main() -> Result<()> { "--config" => path = args.next().context("--config needs a path")?.into(), "--check-config" => check = true, "--init-config" => init = true, + "--list-themes" => { + for name in theme::names() { + println!("{name}"); + } + return Ok(()); + } "--version" => { println!("slerm {}", env!("CARGO_PKG_VERSION")); return Ok(()); } "--help" | "-h" => { println!( - "slerm [--config PATH] [--check-config | --init-config]\n\nDefault config: {}", + "slerm [--config PATH] [--check-config | --init-config | --list-themes]\n\nDefault config: {}", path.display() ); return Ok(()); diff --git a/src/pane.rs b/src/pane.rs index 482a819..11689c3 100644 --- a/src/pane.rs +++ b/src/pane.rs @@ -1,8 +1,9 @@ use crate::{ - config::{Config, rgb}, + config::Config, input, pty::Pty, - render::{Renderer, cell_size}, + render::{Grid, Renderer, cell_size}, + theme::{self, Theme}, }; use anyhow::{Result, ensure}; use egui::{FontId, Rect, Sense, vec2}; @@ -91,14 +92,14 @@ fn percent_decode(path: &str) -> String { String::from_utf8_lossy(&out).into_owned() } -pub fn terminal(config: &Config) -> Result> { +pub fn terminal(config: &Config, theme: &Theme) -> Result> { let mut term = Terminal::new(TerminalOptions { cols: 80, rows: 24, max_scrollback: config.scrollback, })?; term.resize(80, 24, 8, 16)?; - apply_config(&mut term, config)?; + apply_config(&mut term, config, theme)?; term.on_xtversion(|_| Some(concat!("slerm ", env!("CARGO_PKG_VERSION"))))?; term.on_device_attributes(|_| { Some(terminal::DeviceAttributes { @@ -114,14 +115,21 @@ pub fn terminal(config: &Config) -> Result> { tertiary: Default::default(), }) })?; - term.on_color_scheme(|_| Some(terminal::ColorScheme::Dark))?; + let scheme = if theme.dark { + terminal::ColorScheme::Dark + } else { + terminal::ColorScheme::Light + }; + term.on_color_scheme(move |_| Some(scheme))?; Ok(term) } -pub fn apply_config(term: &mut Terminal<'_, '_>, config: &Config) -> Result<()> { - term.set_default_fg_color(Some(rgb(&config.foreground)?))? - .set_default_bg_color(Some(rgb(&config.background)?))? - .set_default_cursor_color(Some(rgb(&config.accent)?))? +pub fn apply_config(term: &mut Terminal<'_, '_>, config: &Config, theme: &Theme) -> Result<()> { + let palette = theme.palette(term.default_color_palette()?); + term.set_default_fg_color(Some(theme::rgb_color(theme.foreground)))? + .set_default_bg_color(Some(theme::rgb_color(theme.background)))? + .set_default_cursor_color(Some(theme::rgb_color(theme.cursor)))? + .set_default_color_palette(Some(palette))? .set_kitty_image_storage_limit(config.kitty.image_storage_mb * 1024 * 1024)? .set_kitty_image_from_file_allowed(config.kitty.allow_file)? .set_kitty_image_from_temp_file_allowed(config.kitty.allow_temp_file)? @@ -130,8 +138,13 @@ pub fn apply_config(term: &mut Terminal<'_, '_>, config: &Config) -> Result<()> } impl Pane { - pub fn new(config: &Config, ctx: &egui::Context, cwd: Option<&Path>) -> Result { - let mut terminal = terminal(config)?; + pub fn new( + config: &Config, + theme: &Theme, + ctx: &egui::Context, + cwd: Option<&Path>, + ) -> Result { + let mut terminal = terminal(config, theme)?; let renderer = Renderer::new()?; let mouse_encoder = mouse::Encoder::new()?; let mouse_event = mouse::Event::new()?; @@ -261,6 +274,7 @@ impl Pane { ui: &mut egui::Ui, rect: Rect, config: &Config, + theme: &Theme, active: bool, ) -> Result { let font = FontId::monospace(config.font_size); @@ -289,15 +303,24 @@ impl Pane { } let response = ui.interact(grid, ui.id().with("terminal"), Sense::click_and_drag()); self.pointer(ui, &response, grid, cell)?; - self.renderer - .paint(&self.terminal, ui.painter(), grid, cell, &font, active)?; + self.renderer.paint( + &self.terminal, + ui.painter(), + &Grid { + rect: grid, + cell, + font: &font, + theme, + active, + }, + )?; if let Some(error) = &self.error { ui.painter().text( grid.left_bottom() - vec2(0.0, ch), egui::Align2::LEFT_TOP, error, FontId::proportional(12.0), - egui::Color32::LIGHT_RED, + theme::color(theme.ansi[9]), ); } Ok(response.clicked() diff --git a/src/render.rs b/src/render.rs index 5cb4451..67d734a 100644 --- a/src/render.rs +++ b/src/render.rs @@ -1,3 +1,4 @@ +use crate::theme::{self, Theme}; use anyhow::{Result, ensure}; use egui::{ Color32, ColorImage, FontId, Painter, Rect, Stroke, TextureHandle, TextureOptions, pos2, vec2, @@ -15,6 +16,17 @@ use std::{ sync::Arc, }; +/// Where a pane's terminal is drawn this frame, and the colors that are slerm's +/// own rather than the terminal's. +#[derive(Clone, Copy)] +pub struct Grid<'a> { + pub rect: Rect, + pub cell: egui::Vec2, + pub font: &'a FontId, + pub theme: &'a Theme, + pub active: bool, +} + pub fn color(c: RgbColor) -> Color32 { Color32::from_rgb(c.r, c.g, c.b) } @@ -145,6 +157,7 @@ pub struct Renderer { glyphs: HashMap>, font_marker: Option>, cached_colors: Option, + cached_selection: (Color32, Color32), cached_cell: egui::Vec2, cached_cols: u16, #[cfg(test)] @@ -163,6 +176,7 @@ impl Renderer { glyphs: HashMap::new(), font_marker: None, cached_colors: None, + cached_selection: (Color32::PLACEHOLDER, Color32::PLACEHOLDER), cached_cell: egui::Vec2::ZERO, cached_cols: 0, #[cfg(test)] @@ -174,11 +188,15 @@ impl Renderer { &mut self, term: &Terminal<'static, '_>, painter: &Painter, - rect: Rect, - cell: egui::Vec2, - font: &FontId, - active: bool, + grid: &Grid<'_>, ) -> Result<()> { + let &Grid { + rect, + cell, + font, + theme, + active, + } = grid; let painter = painter.with_clip_rect(rect.intersect(painter.clip_rect())); // Keep one egui galley alive in its cache each frame. A new identity means // fonts/DPI/the atlas were reset, invalidating every cached glyph's UVs. @@ -199,12 +217,18 @@ impl Renderer { let colors = snapshot.colors()?; let cols = snapshot.cols()?; let row_count = snapshot.rows()? as usize; + let selected_colors = ( + theme::color(theme.selection_bg), + theme::color(theme.selection_fg), + ); let rebuild_all = snapshot.dirty()? == Dirty::Full || self.cached_colors.as_ref() != Some(&colors) + || self.cached_selection != selected_colors || self.cached_cols != cols || self.row_cache.len() != row_count; self.row_cache.resize_with(row_count, CachedRow::default); self.cached_colors = Some(colors.clone()); + self.cached_selection = selected_colors; self.cached_cols = cols; painter.rect_filled(rect, 0, color(colors.background)); let mut rows = self.rows.update(&snapshot)?; @@ -237,9 +261,14 @@ impl Renderer { let explicit_bg = c.bg_color()?; let mut bg = color(explicit_bg.unwrap_or(colors.background)); let selected = c.is_selected()?; - if style.inverse ^ selected { + if style.inverse { std::mem::swap(&mut fg, &mut bg); } + // A selection takes the theme's own colors rather than inverting + // the cell, which would be invisible over inverted text. + if selected { + (bg, fg) = selected_colors; + } if explicit_bg.is_some() || style.inverse || selected { backgrounds.push(egui::Shape::rect_filled(cell_rect, 0, bg)); } @@ -461,7 +490,17 @@ mod tests { ctx.run(egui::RawInput::default(), |ctx| { let painter = ctx.layer_painter(egui::LayerId::background()); renderer - .paint(term, &painter, rect, cell_size(&painter, font), font, true) + .paint( + term, + &painter, + &Grid { + rect, + cell: cell_size(&painter, font), + font, + theme: &theme::DEFAULT, + active: true, + }, + ) .unwrap(); }) .shapes @@ -475,7 +514,9 @@ mod tests { }; let ctx = egui::Context::default(); - let mut term = crate::pane::terminal(&crate::config::Config::default()).unwrap(); + let mut term = + crate::pane::terminal(&crate::config::Config::default(), &crate::theme::DEFAULT) + .unwrap(); term.resize(20, 5, 8, 16).unwrap(); term.vt_write("\x1b[31mNOR\u{e0b4}\x1b[0m Android\r\nsecond line".as_bytes()); let rect = Rect::from_min_size(pos2(12.0, 24.0), vec2(200.0, 120.0)); @@ -548,7 +589,9 @@ mod tests { #[test] fn cached_glyphs_rebuild_after_font_or_scale_changes() { let ctx = egui::Context::default(); - let mut term = crate::pane::terminal(&crate::config::Config::default()).unwrap(); + let mut term = + crate::pane::terminal(&crate::config::Config::default(), &crate::theme::DEFAULT) + .unwrap(); term.resize(20, 5, 8, 16).unwrap(); term.vt_write(b"font cache"); let rect = Rect::from_min_size(egui::Pos2::ZERO, vec2(200.0, 120.0)); @@ -595,7 +638,7 @@ mod tests { }; let ctx = egui::Context::default(); ctx.set_fonts(crate::app::fonts(&config).unwrap()); - let mut term = crate::pane::terminal(&config).unwrap(); + let mut term = crate::pane::terminal(&config, &theme::DEFAULT).unwrap(); term.resize(160, 50, 9, 18).unwrap(); let screen = (1..=50) .map(|row| { @@ -629,10 +672,16 @@ mod tests { .paint( &term, &ctx.layer_painter(egui::LayerId::background()), - Rect::from_min_size(egui::Pos2::ZERO, vec2(1440.0, 900.0)), - vec2(9.0, 18.0), - &FontId::monospace(16.0), - true, + &Grid { + rect: Rect::from_min_size( + egui::Pos2::ZERO, + vec2(1440.0, 900.0), + ), + cell: vec2(9.0, 18.0), + font: &FontId::monospace(16.0), + theme: &theme::DEFAULT, + active: true, + }, ) .unwrap(); }, diff --git a/src/tests.rs b/src/tests.rs index e482c57..a0d1e3b 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,4 +1,4 @@ -use crate::{config::Config, input, pane, render}; +use crate::{config::Config, input, pane, render, theme}; use base64::Engine; use egui::{Event, Key, Modifiers}; use libghostty_vt::{ @@ -30,7 +30,7 @@ fn key(key: Key, modifiers: Modifiers) -> Event { #[test] fn terminal_preserves_unicode_colors_and_application_input_modes() { - let mut term = pane::terminal(&Config::default()).unwrap(); + let mut term = pane::terminal(&Config::default(), &theme::DEFAULT).unwrap(); term.vt_write("hello \x1b[31mred\x1b[0m \u{754c}e\u{301}\r\n".as_bytes()); assert!(plain(&term).contains("hello red \u{754c}e\u{301}")); let events = [ @@ -59,7 +59,7 @@ fn terminal_preserves_unicode_colors_and_application_input_modes() { #[test] fn queries_return_to_the_pty_and_alternate_screen_restores() { - let mut term = pane::terminal(&Config::default()).unwrap(); + let mut term = pane::terminal(&Config::default(), &theme::DEFAULT).unwrap(); let response = Rc::new(RefCell::new(vec![])); let writer = response.clone(); term.on_pty_write(move |_, bytes| writer.borrow_mut().extend_from_slice(bytes)) @@ -74,7 +74,7 @@ fn queries_return_to_the_pty_and_alternate_screen_restores() { #[test] fn kitty_images_decode_render_reuse_and_delete() { graphics::set_png_decoder(Some(Box::new(render::PngDecoder))).unwrap(); - let mut term = pane::terminal(&Config::default()).unwrap(); + let mut term = pane::terminal(&Config::default(), &theme::DEFAULT).unwrap(); let replies = Rc::new(RefCell::new(vec![])); let output = replies.clone(); term.on_pty_write(move |_, data| output.borrow_mut().extend_from_slice(data)) @@ -137,10 +137,13 @@ fn kitty_images_decode_render_reuse_and_delete() { .paint( &term, &painter, - rect, - egui::vec2(8.0, 16.0), - &egui::FontId::monospace(12.0), - true, + &render::Grid { + rect, + cell: egui::vec2(8.0, 16.0), + font: &egui::FontId::monospace(12.0), + theme: &theme::DEFAULT, + active: true, + }, ) .unwrap(); }) @@ -173,7 +176,7 @@ fn pty_executes_input_and_bracketed_paste_is_sanitized() { ..Default::default() }; let ctx = egui::Context::default(); - let mut pane = pane::Pane::new(&config, &ctx, None).unwrap(); + let mut pane = pane::Pane::new(&config, &theme::DEFAULT, &ctx, None).unwrap(); pane.send(b"printf '\\033[31mpty-%s\\033[0m\\n' 'success'\r".to_vec()) .unwrap(); let deadline = Instant::now() + Duration::from_secs(5); @@ -216,7 +219,7 @@ fn new_panes_start_in_the_directory_of_the_pane_they_came_from() { let dir = std::env::temp_dir().join(format!("slerm cwd {}", std::process::id())); std::fs::create_dir_all(&dir).unwrap(); let dir = dir.canonicalize().unwrap(); - let mut pane = pane::Pane::new(&config, &ctx, None).unwrap(); + let mut pane = pane::Pane::new(&config, &theme::DEFAULT, &ctx, None).unwrap(); pane.send(format!("cd '{}'\r", dir.display()).into_bytes()) .unwrap(); // /bin/sh reports no OSC 7, so the directory has to come from the process. @@ -227,7 +230,7 @@ fn new_panes_start_in_the_directory_of_the_pane_they_came_from() { } assert_eq!(pane.cwd().as_deref(), Some(dir.as_path())); - let mut child = pane::Pane::new(&config, &ctx, pane.cwd().as_deref()).unwrap(); + let mut child = pane::Pane::new(&config, &theme::DEFAULT, &ctx, pane.cwd().as_deref()).unwrap(); child .send(b"printf 'at:%s\\n' \"$PWD\"\r".to_vec()) .unwrap(); @@ -251,7 +254,7 @@ fn osc7_wins_over_the_process_directory_but_only_for_this_machine() { let reported = std::env::temp_dir().join(format!("slerm osc7 {}", std::process::id())); std::fs::create_dir_all(&reported).unwrap(); let reported = reported.canonicalize().unwrap(); - let mut pane = pane::Pane::new(&config, &ctx, None).unwrap(); + let mut pane = pane::Pane::new(&config, &theme::DEFAULT, &ctx, None).unwrap(); let process_cwd = pane.cwd().unwrap(); assert_ne!(process_cwd, reported); diff --git a/src/theme.rs b/src/theme.rs new file mode 100644 index 0000000..520a0dd --- /dev/null +++ b/src/theme.rs @@ -0,0 +1,261 @@ +use crate::themes::THEMES; +use anyhow::{Result, bail}; +use egui::Color32; +use libghostty_vt::style::{Palette, PaletteIndex, RgbColor}; + +/// A packed `0xRRGGBB` color. Themes are compiled in, so they hold plain +/// integers rather than anything that needs allocating or parsing at startup. +pub type Rgb = u32; + +/// Every color slerm draws with. A theme covers the terminal grid, the sixteen +/// ANSI colors programs address by index, and the chrome around them, so that +/// picking a light theme does not leave a dark tab bar behind. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub struct Theme { + /// Whether the chrome should be drawn as a dark or a light widget set. + pub dark: bool, + pub background: Rgb, + pub foreground: Rgb, + pub cursor: Rgb, + pub selection_bg: Rgb, + pub selection_fg: Rgb, + /// The focused pane: its border, its title and the cursor. + pub accent: Rgb, + /// The tab bar, menus and pane title bars. + pub chrome_bg: Rgb, + pub chrome_fg: Rgb, + /// The title bar of the focused pane. + pub chrome_active_bg: Rgb, + /// The border of an unfocused pane. + pub border: Rgb, + pub popup_bg: Rgb, + /// ANSI 0..=15: black, red, green, yellow, blue, magenta, cyan, white, then + /// the same eight again in their bright form. + pub ansi: [Rgb; 16], +} + +/// The name of slerm's own theme, which is what a config without a `theme` gets. +pub const DEFAULT_NAME: &str = "slerm"; + +/// slerm's own colors. The palette is libghostty's built-in one, so the default +/// look is exactly what the terminal renders with no theme applied at all. +pub const DEFAULT: Theme = Theme { + dark: true, + background: 0x17191c, + foreground: 0xe2e4e8, + cursor: 0x58c4ad, + selection_bg: 0x2f3d44, + selection_fg: 0xe2e4e8, + accent: 0x58c4ad, + chrome_bg: 0x1f2124, + chrome_fg: 0xa8adb5, + chrome_active_bg: 0x2b2e33, + border: 0x363636, + popup_bg: 0x1f2124, + ansi: [ + 0x1d1f21, 0xcc6666, 0xb5bd68, 0xf0c674, 0x81a2be, 0xb294bb, 0x8abeb7, 0xc5c8c6, 0x666666, + 0xd54e53, 0xb9ca4a, 0xe7c547, 0x7aa6da, 0xc397d8, 0x70c0b1, 0xeaeaea, + ], +}; + +/// The theme with this name, if there is one. slerm's own comes first; the rest +/// are the Helix themes, which `THEMES` keeps sorted for the binary search. +pub fn find(name: &str) -> Option { + if name == DEFAULT_NAME { + return Some(DEFAULT); + } + let index = THEMES.binary_search_by_key(&name, |(name, _)| name).ok()?; + Some(THEMES[index].1) +} + +/// Every theme name, in the order a picker should list them. +pub fn names() -> impl Iterator { + std::iter::once(DEFAULT_NAME).chain(THEMES.iter().map(|(name, _)| *name)) +} + +pub fn color(rgb: Rgb) -> Color32 { + Color32::from_rgb((rgb >> 16) as u8, (rgb >> 8) as u8, rgb as u8) +} + +pub fn rgb_color(rgb: Rgb) -> RgbColor { + RgbColor { + r: (rgb >> 16) as u8, + g: (rgb >> 8) as u8, + b: rgb as u8, + } +} + +/// Where one of the names a config may override writes to. +type Field = fn(&mut Theme) -> &mut Rgb; + +/// The names a config may override, paired with the field each one writes. +/// Ordered so that `[colors]` reads the way a palette is usually written. +const FIELDS: [(&str, Field); 27] = [ + ("background", |t| &mut t.background), + ("foreground", |t| &mut t.foreground), + ("cursor", |t| &mut t.cursor), + ("selection_background", |t| &mut t.selection_bg), + ("selection_foreground", |t| &mut t.selection_fg), + ("accent", |t| &mut t.accent), + ("chrome_background", |t| &mut t.chrome_bg), + ("chrome_foreground", |t| &mut t.chrome_fg), + ("chrome_active_background", |t| &mut t.chrome_active_bg), + ("border", |t| &mut t.border), + ("popup_background", |t| &mut t.popup_bg), + ("black", |t| &mut t.ansi[0]), + ("red", |t| &mut t.ansi[1]), + ("green", |t| &mut t.ansi[2]), + ("yellow", |t| &mut t.ansi[3]), + ("blue", |t| &mut t.ansi[4]), + ("magenta", |t| &mut t.ansi[5]), + ("cyan", |t| &mut t.ansi[6]), + ("white", |t| &mut t.ansi[7]), + ("bright_black", |t| &mut t.ansi[8]), + ("bright_red", |t| &mut t.ansi[9]), + ("bright_green", |t| &mut t.ansi[10]), + ("bright_yellow", |t| &mut t.ansi[11]), + ("bright_blue", |t| &mut t.ansi[12]), + ("bright_magenta", |t| &mut t.ansi[13]), + ("bright_cyan", |t| &mut t.ansi[14]), + ("bright_white", |t| &mut t.ansi[15]), +]; + +impl Theme { + /// Overrides one color by the name a config file uses for it. + pub fn set(&mut self, name: &str, value: Rgb) -> Result<()> { + let Some((_, field)) = FIELDS.iter().find(|(known, _)| *known == name) else { + bail!("unknown color: {name}"); + }; + *field(self) = value; + Ok(()) + } + + /// The 256-color palette a terminal renders indexed colors through. Only + /// the first sixteen are themed; the color cube and greyscale ramp above + /// them are fixed by the protocol, so they keep libghostty's values. + pub fn palette(&self, default: Palette) -> Palette { + const SLOTS: [PaletteIndex; 16] = [ + PaletteIndex::BLACK, + PaletteIndex::RED, + PaletteIndex::GREEN, + PaletteIndex::YELLOW, + PaletteIndex::BLUE, + PaletteIndex::MAGENTA, + PaletteIndex::CYAN, + PaletteIndex::WHITE, + PaletteIndex::BRIGHT_BLACK, + PaletteIndex::BRIGHT_RED, + PaletteIndex::BRIGHT_GREEN, + PaletteIndex::BRIGHT_YELLOW, + PaletteIndex::BRIGHT_BLUE, + PaletteIndex::BRIGHT_MAGENTA, + PaletteIndex::BRIGHT_CYAN, + PaletteIndex::BRIGHT_WHITE, + ]; + let mut palette = default; + for (slot, rgb) in SLOTS.into_iter().zip(self.ansi) { + palette.set(slot, rgb_color(rgb)); + } + palette + } + + /// egui's widget colors, so that the tab bar, menus and buttons follow the + /// theme rather than staying on egui's own dark palette. + pub fn visuals(&self) -> egui::Visuals { + let mut visuals = if self.dark { + egui::Visuals::dark() + } else { + egui::Visuals::light() + }; + let (chrome, accent, text) = ( + color(self.chrome_bg), + color(self.accent), + color(self.chrome_fg), + ); + let widgets = &mut visuals.widgets; + widgets.noninteractive.bg_fill = chrome; + widgets.noninteractive.weak_bg_fill = chrome; + widgets.noninteractive.fg_stroke = egui::Stroke::new(1.0_f32, text); + widgets.noninteractive.bg_stroke = egui::Stroke::new(1.0_f32, color(self.border)); + for widget in [ + &mut widgets.inactive, + &mut widgets.hovered, + &mut widgets.active, + &mut widgets.open, + ] { + widget.bg_fill = color(self.chrome_active_bg); + widget.weak_bg_fill = color(self.chrome_active_bg); + widget.fg_stroke = egui::Stroke::new(1.0_f32, color(self.foreground)); + widget.bg_stroke = egui::Stroke::new(1.0_f32, color(self.border)); + } + widgets.hovered.weak_bg_fill = color(self.selection_bg); + widgets.active.weak_bg_fill = color(self.selection_bg); + widgets.active.fg_stroke = egui::Stroke::new(1.0_f32, accent); + visuals.panel_fill = chrome; + visuals.window_fill = color(self.popup_bg); + visuals.extreme_bg_color = color(self.background); + visuals.selection.bg_fill = color(self.selection_bg); + visuals.selection.stroke = egui::Stroke::new(1.0_f32, accent); + visuals.hyperlink_color = accent; + visuals.window_stroke = egui::Stroke::new(1.0_f32, color(self.border)); + visuals + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn every_helix_theme_is_present_sorted_and_legible() { + assert!(THEMES.len() > 150, "expected the full Helix theme set"); + assert!( + THEMES.windows(2).all(|w| w[0].0 < w[1].0), + "THEMES must be sorted for find() to binary search it" + ); + for name in ["catppuccin_mocha", "gruvbox", "nord", "onedark", "dracula"] { + assert!(find(name).is_some(), "missing {name}"); + } + assert_eq!(find(DEFAULT_NAME), Some(DEFAULT)); + assert_eq!(find("no such theme"), None); + assert_eq!(names().count(), THEMES.len() + 1); + + // A theme whose text matches its background, or whose palette collapses + // onto one color, would render an unusable terminal. + for (name, theme) in THEMES { + let luma = |rgb: Rgb| { + let channel = |shift: u32| ((rgb >> shift) & 0xff) as f32 / 255.0; + 0.2126 * channel(16) + 0.7152 * channel(8) + 0.0722 * channel(0) + }; + assert!( + (luma(theme.foreground) - luma(theme.background)).abs() > 0.15, + "{name}: text is not readable on its background" + ); + assert_eq!(theme.dark, luma(theme.background) < luma(theme.foreground)); + // Themes built on three or four colors (acme, vesper) reuse them + // across slots; anything flatter than that has lost its palette. + let distinct: std::collections::BTreeSet<_> = theme.ansi.iter().collect(); + assert!(distinct.len() >= 9, "{name}: palette is too flat"); + } + } + + #[test] + fn overrides_are_named_and_reach_the_palette() { + let mut theme = DEFAULT; + theme.set("red", 0x123456).unwrap(); + theme.set("bright_white", 0xfedcba).unwrap(); + theme.set("accent", 0x00ff00).unwrap(); + assert_eq!(theme.ansi[1], 0x123456); + assert_eq!(theme.ansi[15], 0xfedcba); + assert_eq!(theme.accent, 0x00ff00); + for unknown in ["dark", "purple", "ansi", ""] { + assert!(theme.set(unknown, 0).is_err(), "accepted {unknown}"); + } + + let palette = theme.palette(Palette([RgbColor { r: 0, g: 0, b: 0 }; 256])); + assert_eq!(palette.get(PaletteIndex::RED), rgb_color(0x123456)); + assert_eq!(palette.get(PaletteIndex::BRIGHT_WHITE), rgb_color(0xfedcba)); + // Everything above the sixteen named slots is left as it was. + assert_eq!(palette.0[16], RgbColor { r: 0, g: 0, b: 0 }); + } +} diff --git a/src/themes.rs b/src/themes.rs new file mode 100644 index 0000000..aaf4069 --- /dev/null +++ b/src/themes.rs @@ -0,0 +1,3623 @@ +//! The themes Helix ships with, converted by `cargo run --example gen_themes`. +//! Generated file: edit the generator, not this. +//! +//! Upstream: . +//! The individual themes keep their own authors and licenses; see `themes/LICENSES`. + +use crate::theme::Theme; + +/// Every built-in theme, sorted by name so that lookup can binary search. +pub static THEMES: &[(&str, Theme)] = &[ + ( + "acme", + Theme { + dark: false, + background: 0xffffea, + foreground: 0x000000, + cursor: 0x444444, + selection_bg: 0xeeee9e, + selection_fg: 0x000000, + accent: 0x065905, + chrome_bg: 0xaeeeee, + chrome_fg: 0x000000, + chrome_active_bg: 0x96cdcd, + border: 0xb8b8a8, + popup_bg: 0xffffea, + ansi: [ + 0x000000, 0xa0342f, 0x065905, 0xf0ad4e, 0x065905, 0xa0342f, 0x065905, 0xffffff, + 0x065905, 0xb96965, 0x478446, 0xf4c27c, 0x478446, 0xb96965, 0x478446, 0xffffea, + ], + }, + ), + ( + "adwaita-dark", + Theme { + dark: true, + background: 0x1d1d1d, + foreground: 0xdeddda, + cursor: 0x9a9996, + selection_bg: 0x193d66, + selection_fg: 0xdeddda, + accent: 0x62a0ea, + chrome_bg: 0x303030, + chrome_fg: 0xdeddda, + chrome_active_bg: 0x4d4d4d, + border: 0x3e3e3e, + popup_bg: 0x282828, + ansi: [ + 0x3a3a3a, 0xc01c28, 0x8ff0a4, 0xf8e45c, 0x62a0ea, 0xc061cb, 0x33b2a4, 0xdeddda, + 0x5e5c64, 0xe01b24, 0x9cf2af, 0xffbe6f, 0x8bb9ef, 0xdc8add, 0x33d17a, 0xeae9e7, + ], + }, + ), + ( + "adwaita-light", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x3d3846, + cursor: 0x000000, + selection_bg: 0xd3e4f9, + selection_fg: 0x3d3846, + accent: 0x1c71d8, + chrome_bg: 0xdeddda, + chrome_fg: 0x3d3846, + chrome_active_bg: 0xbfbebb, + border: 0x8d8d8d, + popup_bg: 0xf6f5f4, + ansi: [ + 0x2e2a35, 0xa51d2d, 0x4e9a06, 0xe5a50a, 0x1c71d8, 0xdc8add, 0x26a1a2, 0xdedede, + 0xb0afac, 0xc01c28, 0x7cb447, 0xecbc4a, 0x3584e4, 0xe098e1, 0x33b2a4, 0xffffff, + ], + }, + ), + ( + "amberwood", + Theme { + dark: true, + background: 0x0f1014, + foreground: 0xc9c7cd, + cursor: 0xe5c890, + selection_bg: 0x3e3e43, + selection_fg: 0xc9c7cd, + accent: 0xe5c890, + chrome_bg: 0x1b1b1d, + chrome_fg: 0xe5c890, + chrome_active_bg: 0x3b3b3d, + border: 0x212124, + popup_bg: 0x1b1b1d, + ansi: [ + 0x2e2f33, 0xe78284, 0x90b99f, 0xe5c890, 0xaca1cf, 0xe29eca, 0xea83a5, 0xc1c0d4, + 0x808080, 0xf591b2, 0x9dc6ac, 0xe8cf9d, 0xb9aeda, 0xe5aad0, 0xf591b2, 0xcac9dd, + ], + }, + ), + ( + "ao", + Theme { + dark: true, + background: 0x080d15, + foreground: 0xdadada, + cursor: 0xdadada, + selection_bg: 0x7533bd, + selection_fg: 0xdadada, + accent: 0x45b1e8, + chrome_bg: 0x2c5484, + chrome_fg: 0xf3f4f6, + chrome_active_bg: 0x4a6c95, + border: 0x585e6a, + popup_bg: 0x0d1526, + ansi: [ + 0x0d1117, 0xfa7970, 0x81be83, 0xffba00, 0x45b1e8, 0xd2a8ff, 0x254862, 0xdadada, + 0x838a97, 0xfb8981, 0xa2cfa3, 0xffcc42, 0x6eb0ff, 0xd7b2ff, 0x2c5484, 0xe7e7e7, + ], + }, + ), + ( + "ashen", + Theme { + dark: true, + background: 0x121212, + foreground: 0xb4b4b4, + cursor: 0xb4b4b4, + selection_bg: 0x322119, + selection_fg: 0xb4b4b4, + accent: 0xe49a44, + chrome_bg: 0x212121, + chrome_fg: 0xb4b4b4, + chrome_active_bg: 0x404040, + border: 0x3c3c3c, + popup_bg: 0x1d1d1d, + ansi: [ + 0x313131, 0xc53030, 0xe49a44, 0xe5a72a, 0x4a8b8b, 0xb14242, 0xd87c4a, 0xb4b4b4, + 0x737373, 0xdf6464, 0xebb475, 0xecbe61, 0x79a9a9, 0xdf6464, 0xdf6464, 0xcecece, + ], + }, + ), + ( + "ataraxia", + Theme { + dark: true, + background: 0x1c0c28, + foreground: 0x00d2f7, + cursor: 0xa600ff, + selection_bg: 0x7b52c7, + selection_fg: 0x000000, + accent: 0x8f45ff, + chrome_bg: 0x30223b, + chrome_fg: 0x00ddff, + chrome_active_bg: 0x4d4156, + border: 0x6731b4, + popup_bg: 0x1c0c28, + ansi: [ + 0x3a2c44, 0xeb3e5e, 0x00d974, 0x025c33, 0x8aa3fe, 0xa600ff, 0x00ddff, 0x00d2f7, + 0x5c3a9e, 0xf07088, 0x42e398, 0x448668, 0x98aefe, 0x8f45ff, 0x42e6ff, 0x59e2fa, + ], + }, + ), + ( + "autumn", + Theme { + dark: true, + background: 0x232323, + foreground: 0xf3f2cc, + cursor: 0x7e7d6a, + selection_bg: 0x404040, + selection_fg: 0xf3f2cc, + accent: 0xf3f2cc, + chrome_bg: 0x323232, + chrome_fg: 0xc8c8c8, + chrome_active_bg: 0x4f4f4f, + border: 0x363636, + popup_bg: 0x323232, + ansi: [ + 0x404040, 0xf05e48, 0x99be70, 0xffff9f, 0x72a59e, 0xfad566, 0x86c1b9, 0xf3f2cc, + 0x646f69, 0xf48878, 0xb4cf95, 0xffffab, 0x97bcb7, 0xfbe08e, 0xa5d1cb, 0xf7f7de, + ], + }, + ), + ( + "autumn_night", + Theme { + dark: true, + background: 0x090909, + foreground: 0xf3f2cc, + cursor: 0x7e7d6a, + selection_bg: 0x404040, + selection_fg: 0xf3f2cc, + accent: 0xf3f2cc, + chrome_bg: 0x1a1a1a, + chrome_fg: 0xc4c4c4, + chrome_active_bg: 0x3a3a3a, + border: 0x2d2d2d, + popup_bg: 0x1a1a1a, + ansi: [ + 0x292929, 0xf05e48, 0x99be70, 0xffff9f, 0x72a59e, 0xfad566, 0x86c1b9, 0xf3f2cc, + 0x626c66, 0xf48878, 0xb4cf95, 0xffffab, 0x97bcb7, 0xfbe08e, 0xa5d1cb, 0xf7f7de, + ], + }, + ), + ( + "ayu_dark", + Theme { + dark: true, + background: 0x0f1419, + foreground: 0xbfbdb6, + cursor: 0xff8f40, + selection_bg: 0x2d3640, + selection_fg: 0xbfbdb6, + accent: 0xff8f40, + chrome_bg: 0x131721, + chrome_fg: 0xbfbdb6, + chrome_active_bg: 0x343740, + border: 0x232a32, + popup_bg: 0x131721, + ansi: [ + 0x131721, 0xf07178, 0xaad94c, 0xe6b450, 0x59c2ff, 0xd2a6ff, 0x73b8ff, 0xbfbdb6, + 0x5c6773, 0xf4969b, 0xc0e37b, 0xedc87e, 0x84d2ff, 0xd7b1ff, 0x84c1ff, 0xd5d4d0, + ], + }, + ), + ( + "ayu_evolve", + Theme { + dark: true, + background: 0x020202, + foreground: 0xbfbdb6, + cursor: 0xff8f40, + selection_bg: 0x2d3640, + selection_fg: 0xbfbdb6, + accent: 0xff8f40, + chrome_bg: 0x0d0d0d, + chrome_fg: 0xbfbdb6, + chrome_active_bg: 0x2f2f2f, + border: 0x1e242a, + popup_bg: 0x0d0d0d, + ansi: [ + 0x0d0d0d, 0xdd3e25, 0xaad94c, 0xe6b450, 0x59c2ff, 0xd2a6ff, 0x73b8ff, 0xbfbdb6, + 0x5c6773, 0xff8732, 0xc0e37b, 0xedc87e, 0x84d2ff, 0xd7b1ff, 0x84c1ff, 0xd5d4d0, + ], + }, + ), + ( + "ayu_light", + Theme { + dark: false, + background: 0xfafafa, + foreground: 0x5c6166, + cursor: 0xfa8d3e, + selection_bg: 0xd8d8d7, + selection_fg: 0x5c6166, + accent: 0x478acc, + chrome_bg: 0xe7eaed, + chrome_fg: 0x5c6166, + chrome_active_bg: 0xc7c9cc, + border: 0xe4e4e3, + popup_bg: 0xe7eaed, + ansi: [ + 0xe7eaed, 0xf07171, 0x86b300, 0xffaa33, 0x399ee6, 0xa37acc, 0x478acc, 0xfcfcfc, + 0x828c9a, 0xf49696, 0xa5c742, 0xffc068, 0x55b4d4, 0xbb9dd9, 0x77a8d9, 0xfafafa, + ], + }, + ), + ( + "ayu_mirage", + Theme { + dark: true, + background: 0x1f2430, + foreground: 0xcccac2, + cursor: 0xffad66, + selection_bg: 0x323843, + selection_fg: 0xcccac2, + accent: 0xffad66, + chrome_bg: 0x1a1f29, + chrome_fg: 0xcccac2, + chrome_active_bg: 0x3a3e47, + border: 0x2b313c, + popup_bg: 0x1a1f29, + ansi: [ + 0x1a1f29, 0xf28779, 0xd5ff80, 0xffcc77, 0x73d0ff, 0xdfbfff, 0x444b55, 0xcccac2, + 0x565b66, 0xf49589, 0xdaff8f, 0xffd287, 0x84d6ff, 0xe3c7ff, 0x565b66, 0xdeddd7, + ], + }, + ), + ( + "base16_default_dark", + Theme { + dark: true, + background: 0x181818, + foreground: 0xd8d8d8, + cursor: 0xd8d8d8, + selection_bg: 0x383838, + selection_fg: 0xd8d8d8, + accent: 0xf7ca88, + chrome_bg: 0x282828, + chrome_fg: 0xb8b8b8, + chrome_active_bg: 0x464646, + border: 0x595959, + popup_bg: 0x282828, + ansi: [ + 0x363636, 0xab4642, 0xa1b56c, 0xf7ca88, 0x7cafc2, 0xba8baf, 0x86c1b9, 0xd8d8d8, + 0x585858, 0xdc9656, 0xb9c892, 0xf8d096, 0x9ec4d2, 0xcca9c4, 0xa5d1cb, 0xe6e6e6, + ], + }, + ), + ( + "base16_default_light", + Theme { + dark: false, + background: 0xf8f8f8, + foreground: 0x383838, + cursor: 0x383838, + selection_bg: 0xd8d8d8, + selection_fg: 0x383838, + accent: 0x383838, + chrome_bg: 0xe8e8e8, + chrome_fg: 0x585858, + chrome_active_bg: 0xc8c8c8, + border: 0xb3b3b3, + popup_bg: 0xe8e8e8, + ansi: [ + 0x2a2a2a, 0xab4642, 0xa1b56c, 0xdc9656, 0x7cafc2, 0xba8baf, 0x86c1b9, 0xd8d8d8, + 0x8e8e8e, 0xc17673, 0xb9c892, 0xe5b182, 0x9ec4d2, 0xcca9c4, 0xa5d1cb, 0xf8f8f8, + ], + }, + ), + ( + "base16_terminal", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0xe5e5e5, + selection_bg: 0x383838, + selection_fg: 0x7f7f7f, + accent: 0xffff00, + chrome_bg: 0x171717, + chrome_fg: 0xffffff, + chrome_active_bg: 0x373737, + border: 0x474747, + popup_bg: 0x000000, + ansi: [ + 0x212121, 0xe16666, 0x66e166, 0xe1e166, 0x6666f5, 0xe166e1, 0x66e1e1, 0xffffff, + 0xe5e5e5, 0xe98e8e, 0x8ee98e, 0xe9e98e, 0x8e8ef8, 0xe98ee9, 0x8ee9e9, 0xffffff, + ], + }, + ), + ( + "base16_transparent", + Theme { + dark: true, + background: 0x000000, + foreground: 0xe5e5e5, + cursor: 0xe5e5e5, + selection_bg: 0x7f7f7f, + selection_fg: 0xe5e5e5, + accent: 0xffff00, + chrome_bg: 0x171717, + chrome_fg: 0xffffff, + chrome_active_bg: 0x373737, + border: 0x535353, + popup_bg: 0x171717, + ansi: [ + 0x212121, 0xd75c5c, 0x5cd75c, 0xd7d75c, 0x5c5cea, 0xd75cd7, 0x5cd7d7, 0xe5e5e5, + 0xe5e5e5, 0xe18686, 0x86e186, 0xe1e186, 0x8686ef, 0xe186e1, 0x86e1e1, 0xeeeeee, + ], + }, + ), + ( + "beans", + Theme { + dark: true, + background: 0x111111, + foreground: 0xebebd8, + cursor: 0x0ac1cd, + selection_bg: 0xbe67e1, + selection_fg: 0x1c1c1c, + accent: 0x0ac1cd, + chrome_bg: 0x292929, + chrome_fg: 0xebebd8, + chrome_active_bg: 0x474747, + border: 0x5f5f5f, + popup_bg: 0x1c1c1c, + ansi: [ + 0x303030, 0xcc7c8a, 0xccff00, 0xfad07a, 0x048ac7, 0xbe67e1, 0x63e7f0, 0xffffff, + 0x6d6d6d, 0xd99ea8, 0xd9ff42, 0xebebd8, 0x48c6ff, 0xcf8fe9, 0x8cedf4, 0xf2f2e6, + ], + }, + ), + ( + "bogster", + Theme { + dark: true, + background: 0x161c23, + foreground: 0xe5ded6, + cursor: 0xabb2bf, + selection_bg: 0x313f4e, + selection_fg: 0xe5ded6, + accent: 0xabb2bf, + chrome_bg: 0x232d38, + chrome_fg: 0xe5ded6, + chrome_active_bg: 0x424a54, + border: 0x575c61, + popup_bg: 0x232d38, + ansi: [ + 0x343a40, 0xdc597f, 0x7fdc59, 0xdcb659, 0xabb2bf, 0xb759dc, 0x36b2d4, 0xe5ded6, + 0xabb2bf, 0xe584a0, 0xa0e584, 0xe5c984, 0xb5bbc7, 0xca84e5, 0x59dcb7, 0xeeeae4, + ], + }, + ), + ( + "bogster_light", + Theme { + dark: false, + background: 0xf6fbd6, + foreground: 0x161c23, + cursor: 0xabb2bf, + selection_bg: 0xc7c7ba, + selection_fg: 0x161c23, + accent: 0x232d38, + chrome_bg: 0xc7c7ba, + chrome_fg: 0x161c23, + chrome_active_bg: 0xababa0, + border: 0xb1b59a, + popup_bg: 0xc7c7ba, + ansi: [ + 0x11151a, 0xdc597f, 0x23a580, 0xa58023, 0x232d38, 0xd32c5d, 0x289cbc, 0xd6daba, + 0x627d9d, 0xe584a0, 0x5cbca1, 0xdc7759, 0x415367, 0xde6387, 0x60b6cd, 0xf6fbd6, + ], + }, + ), + ( + "boo_berry", + Theme { + dark: true, + background: 0x3a2a4d, + foreground: 0xc7b8e0, + cursor: 0xc7b8e0, + selection_bg: 0x2b1c3d, + selection_fg: 0xc7b8e0, + accent: 0xc7b8e0, + chrome_bg: 0x2b1c3d, + chrome_fg: 0xc7b8e0, + chrome_active_bg: 0x493c58, + border: 0x6d5580, + popup_bg: 0x2b1c3d, + ansi: [ + 0x544664, 0x886c9c, 0x7fc9ab, 0xe3c0a8, 0xc78dfc, 0xd678b5, 0x7fc9ab, 0xc7b8e0, + 0x886c9c, 0xc7b8e0, 0xa0d7c1, 0xe6c8b2, 0xce9bfc, 0xe19bc8, 0xa0d7c1, 0xdbd1eb, + ], + }, + ), + ( + "carbon", + Theme { + dark: true, + background: 0x161616, + foreground: 0xa8a8a8, + cursor: 0xbae6ff, + selection_bg: 0x525252, + selection_fg: 0xa8a8a8, + accent: 0xbae6ff, + chrome_bg: 0x262626, + chrome_fg: 0xa8a8a8, + chrome_active_bg: 0x444444, + border: 0x2d2d2d, + popup_bg: 0x262626, + ansi: [ + 0x343434, 0xffa4a9, 0x6fdc8c, 0xf1c21b, 0x78a9ff, 0xbe95ff, 0x82cfff, 0xa8a8a8, + 0x525252, 0xffafb3, 0x94e5aa, 0xf5d256, 0x88b3ff, 0xc6a2ff, 0x91d5ff, 0xc6c6c6, + ], + }, + ), + ( + "carbonfox", + Theme { + dark: true, + background: 0x161616, + foreground: 0xf2f4f8, + cursor: 0xf2f4f8, + selection_bg: 0x525253, + selection_fg: 0xf2f4f8, + accent: 0x08bdba, + chrome_bg: 0x0c0c0c, + chrome_fg: 0xb6b8bb, + chrome_active_bg: 0x2e2e2e, + border: 0x101010, + popup_bg: 0x0c0c0c, + ansi: [ + 0x282828, 0xee5396, 0x25be6a, 0x08bdba, 0x78a9ff, 0xbe95ff, 0x33b1ff, 0xdfdfe0, + 0x738091, 0xff7eb6, 0x5ecf91, 0x2dc7c4, 0x88b3ff, 0xc6a2ff, 0x52bdff, 0xf7f8fa, + ], + }, + ), + ( + "catppuccin_frappe", + Theme { + dark: true, + background: 0x303446, + foreground: 0xc6d0f5, + cursor: 0xf2d5cf, + selection_bg: 0x51576d, + selection_fg: 0xc6d0f5, + accent: 0xef9f76, + chrome_bg: 0x292c3c, + chrome_fg: 0xb5bfe2, + chrome_active_bg: 0x474a57, + border: 0x282b3a, + popup_bg: 0x414559, + ansi: [ + 0x4b4e5e, 0xe78284, 0xa6d189, 0xe5c890, 0x8caaee, 0xca9ee6, 0x99d1db, 0xc6d0f5, + 0x949cbb, 0xea999c, 0xbddda8, 0xe8cf9d, 0x9ab4f0, 0xd0aae9, 0xa5d7df, 0xdae0f9, + ], + }, + ), + ( + "catppuccin_latte", + Theme { + dark: false, + background: 0xeff1f5, + foreground: 0x4c4f69, + cursor: 0xdc8a78, + selection_bg: 0xbcc0cc, + selection_fg: 0x4c4f69, + accent: 0x1e66f5, + chrome_bg: 0xe6e9ef, + chrome_fg: 0x5c5f77, + chrome_active_bg: 0xc6c8ce, + border: 0xe3e6ed, + popup_bg: 0xccd0da, + ansi: [ + 0x393b4f, 0xd20f39, 0x40a02b, 0xdf8e1d, 0x1e66f5, 0xea76cb, 0x04a5e5, 0xd0d2d5, + 0x7c7f93, 0xe64553, 0x72b962, 0xe7ab58, 0x598ef8, 0xef9ad9, 0x45bcec, 0xeff1f5, + ], + }, + ), + ( + "catppuccin_macchiato", + Theme { + dark: true, + background: 0x24273a, + foreground: 0xcad3f5, + cursor: 0xf4dbd6, + selection_bg: 0x494d64, + selection_fg: 0xcad3f5, + accent: 0xf5a97f, + chrome_bg: 0x1e2030, + chrome_fg: 0xb8c0e0, + chrome_active_bg: 0x3e3f4d, + border: 0x1c1e2d, + popup_bg: 0x363a4f, + ansi: [ + 0x404354, 0xed8796, 0xa6da95, 0xeed49f, 0x8aadf4, 0xc6a0f6, 0x91d7e3, 0xcad3f5, + 0x939ab7, 0xef95a3, 0xb1dea2, 0xf0d9ab, 0x98b7f5, 0xcdabf7, 0x9edce6, 0xdde2f9, + ], + }, + ), + ( + "catppuccin_mocha", + Theme { + dark: true, + background: 0x1e1e2e, + foreground: 0xcdd6f4, + cursor: 0xf5e0dc, + selection_bg: 0x45475a, + selection_fg: 0xcdd6f4, + accent: 0xfab387, + chrome_bg: 0x181825, + chrome_fg: 0xbac2de, + chrome_active_bg: 0x383844, + border: 0x161622, + popup_bg: 0x313244, + ansi: [ + 0x3b3b49, 0xf38ba8, 0xa6e3a1, 0xf9e2af, 0x89b4fa, 0xcba6f7, 0x89dceb, 0xcdd6f4, + 0x9399b2, 0xf499b2, 0xb1e6ac, 0xfae5b9, 0x97bdfb, 0xd1b1f8, 0x97e0ed, 0xdfe4f8, + ], + }, + ), + ( + "curzon", + Theme { + dark: true, + background: 0x000000, + foreground: 0xbfdbfe, + cursor: 0xbfdbfe, + selection_bg: 0x4f46e5, + selection_fg: 0xbfdbfe, + accent: 0xbfdbfe, + chrome_bg: 0x171717, + chrome_fg: 0x6366f1, + chrome_active_bg: 0x373737, + border: 0x0b0b0b, + popup_bg: 0x1e3a8a, + ansi: [ + 0x000000, 0xf43f5e, 0x6ee7b7, 0xffcd1c, 0x6366f1, 0xdbbfef, 0xbee0ec, 0xffffff, + 0x697c81, 0xf47868, 0x94edca, 0xffda57, 0xbee0ec, 0xdfc7f1, 0xc6e4ee, 0xd5e8fe, + ], + }, + ), + ( + "cyan_light", + Theme { + dark: false, + background: 0xf2f3f7, + foreground: 0x434b6c, + cursor: 0x80bfff, + selection_bg: 0xd0eaff, + selection_fg: 0x434b6c, + accent: 0x0073e6, + chrome_bg: 0xdadde8, + chrome_fg: 0x343a54, + chrome_active_bg: 0xbbbec8, + border: 0x8a91ad, + popup_bg: 0xe6e8f0, + ansi: [ + 0x323851, 0xd90016, 0x00733b, 0x808000, 0x0073e6, 0x660e7a, 0x458383, 0xd3d3d7, + 0x808080, 0xe34253, 0x5dce87, 0xf49810, 0x99ccff, 0x8e4d9d, 0x75a3a3, 0xf2f3f7, + ], + }, + ), + ( + "darcula", + Theme { + dark: true, + background: 0x282828, + foreground: 0xd0d0d0, + cursor: 0xd8d8d8, + selection_bg: 0x104158, + selection_fg: 0xd0d0d0, + accent: 0x6897bb, + chrome_bg: 0x383838, + chrome_fg: 0xb8b8b8, + chrome_active_bg: 0x545454, + border: 0x323232, + popup_bg: 0x181818, + ansi: [ + 0x444444, 0xa34a27, 0x32cd32, 0xeedd82, 0x104158, 0x9876aa, 0x6897bb, 0xd0d0d0, + 0x808080, 0xcc7832, 0x67da67, 0xf0e191, 0x4e7283, 0xb39ac0, 0x8fb2cd, 0xe0e0e0, + ], + }, + ), + ( + "darcula-solid", + Theme { + dark: true, + background: 0x1f1f1f, + foreground: 0xd0d0d0, + cursor: 0xd8d8d8, + selection_bg: 0x104158, + selection_fg: 0xd0d0d0, + accent: 0x6897bb, + chrome_bg: 0x323232, + chrome_fg: 0xa8a8a8, + chrome_active_bg: 0x4f4f4f, + border: 0x2b2b2b, + popup_bg: 0x101010, + ansi: [ + 0x3c3c3c, 0xa34a27, 0x32cd32, 0xeedd82, 0x104158, 0x9876aa, 0x6897bb, 0xd0d0d0, + 0x808080, 0xcc7832, 0x67da67, 0xf0e191, 0x4e7283, 0xb39ac0, 0x8fb2cd, 0xe0e0e0, + ], + }, + ), + ( + "dark-synthwave", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0xffffff, + selection_bg: 0x001069, + selection_fg: 0xffffff, + accent: 0x848bbd, + chrome_bg: 0x171717, + chrome_fg: 0xffffff, + chrome_active_bg: 0x373737, + border: 0xa62142, + popup_bg: 0x1e1e1e, + ansi: [ + 0x000000, 0xff5252, 0x1afc65, 0xfede5d, 0x848bbd, 0xff7edb, 0x36f9f6, 0xffffff, + 0x848bbd, 0xf97e72, 0x47ffa0, 0xfee787, 0xa4a9ce, 0xff8ddf, 0x6afbf8, 0xffffff, + ], + }, + ), + ( + "dark_high_contrast", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0xffffff, + selection_bg: 0xffffff, + selection_fg: 0x142743, + accent: 0x66a4ff, + chrome_bg: 0x142743, + chrome_fg: 0xffffff, + chrome_active_bg: 0x35455d, + border: 0x487f91, + popup_bg: 0x142743, + ansi: [ + 0x000000, 0xb65f5f, 0x427a2d, 0xcedc84, 0x66a4ff, 0xc586c0, 0x6fc3df, 0xffffff, + 0xffffff, 0xce9178, 0x739d64, 0xdbe5a4, 0x8ebcff, 0xd4a5d0, 0x94d3e7, 0xffffff, + ], + }, + ), + ( + "dark_plus", + Theme { + dark: true, + background: 0x1e1e1e, + foreground: 0xd4d4d4, + cursor: 0xa6a6a6, + selection_bg: 0x264f78, + selection_fg: 0xd4d4d4, + accent: 0xd4d4d4, + chrome_bg: 0x007acc, + chrome_fg: 0xffffff, + chrome_active_bg: 0x0069af, + border: 0x343434, + popup_bg: 0x252526, + ansi: [ + 0x3b3b3b, 0xff1212, 0x487e02, 0xcca700, 0x007acc, 0xc586c0, 0x4fc1ff, 0xffffff, + 0x6a9955, 0xff5050, 0x78a044, 0xd9be42, 0x75beff, 0xd4a5d0, 0x75beff, 0xe3e3e3, + ], + }, + ), + ( + "doom-one", + Theme { + dark: true, + background: 0x282c34, + foreground: 0xbbc2cf, + cursor: 0x46d9ff, + selection_bg: 0x3c4048, + selection_fg: 0xbbc2cf, + accent: 0x46d9ff, + chrome_bg: 0x3b3f46, + chrome_fg: 0x51afef, + chrome_active_bg: 0x565a60, + border: 0x494f56, + popup_bg: 0x282c34, + ansi: [ + 0x44474e, 0xff6c6b, 0x98be65, 0xecbe7b, 0x51afef, 0xc678dd, 0x46d9ff, 0xbbc2cf, + 0x5b6268, 0xff7e7d, 0xb3cf8d, 0xeec68b, 0x7ec4f3, 0xe99bea, 0x76e3ff, 0xd3d7e0, + ], + }, + ), + ( + "doom_acario_dark", + Theme { + dark: true, + background: 0x0d0e16, + foreground: 0xc3dbe5, + cursor: 0xd85f00, + selection_bg: 0x1e1e33, + selection_fg: 0xc3dbe5, + accent: 0x36d8bd, + chrome_bg: 0x464a56, + chrome_fg: 0xc3dbe5, + chrome_active_bg: 0x60636e, + border: 0x515254, + popup_bg: 0x040408, + ansi: [ + 0x000000, 0xd83441, 0x79d836, 0xd8b941, 0x3679d8, 0x8041d8, 0x36d8bd, 0xffffff, + 0x767676, 0xe26972, 0x9ce26a, 0xe2cb72, 0x6a9ce2, 0xa172e2, 0x6ae2ce, 0xd8e8ee, + ], + }, + ), + ( + "dracula", + Theme { + dark: true, + background: 0x282a36, + foreground: 0xf8f8f2, + cursor: 0xbd93f9, + selection_bg: 0x44475a, + selection_fg: 0xf8f8f2, + accent: 0xbd93f9, + chrome_bg: 0x222430, + chrome_fg: 0xf8f8f2, + chrome_active_bg: 0x41434d, + border: 0xafb0b0, + popup_bg: 0x191a21, + ansi: [ + 0x191a21, 0xff5555, 0x50fa7b, 0xf1fa8c, 0x6272a4, 0xff79c6, 0x8be9fd, 0xf8f8f2, + 0x6272a4, 0xff8181, 0x7efb9d, 0xf3fb9a, 0x8b97bc, 0xff89cd, 0x99ecfd, 0xfafaf7, + ], + }, + ), + ( + "dracula_at_night", + Theme { + dark: true, + background: 0x0e1419, + foreground: 0xf8f8f2, + cursor: 0x8be9fd, + selection_bg: 0xff79c6, + selection_fg: 0x0e1419, + accent: 0x50fa7b, + chrome_bg: 0x21222c, + chrome_fg: 0xf8f8f2, + chrome_active_bg: 0x40414a, + border: 0xa6a8a6, + popup_bg: 0x21222c, + ansi: [ + 0x2d3337, 0xff5555, 0x50fa7b, 0xf1fa8c, 0x6272a4, 0xff79c6, 0x8be9fd, 0xf8f8f2, + 0x6272a4, 0xff8181, 0x7efb9d, 0xf3fb9a, 0x8b97bc, 0xff89cd, 0x99ecfd, 0xfafaf7, + ], + }, + ), + ( + "earl_grey", + Theme { + dark: true, + background: 0x101010, + foreground: 0xa6a6a6, + cursor: 0xb59efc, + selection_bg: 0x3e3e3e, + selection_fg: 0xa6a6a6, + accent: 0xb59efc, + chrome_bg: 0x1b1b1b, + chrome_fg: 0xb59efc, + chrome_active_bg: 0x3b3b3b, + border: 0x212123, + popup_bg: 0x1b1b1b, + ansi: [ + 0x000000, 0xe78284, 0x90b99f, 0xe5c890, 0x99bbe0, 0xe29eca, 0xb59efc, 0xffffff, + 0x747474, 0xea9193, 0xadcbb8, 0xe8cf9d, 0xa5c3e4, 0xe5aad0, 0xbeaafc, 0xc5c5c5, + ], + }, + ), + ( + "eiffel", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x000000, + selection_bg: 0xc3dcff, + selection_fg: 0x000000, + accent: 0x0206ff, + chrome_bg: 0xededed, + chrome_fg: 0x000000, + chrome_active_bg: 0xcccccc, + border: 0x595959, + popup_bg: 0xededed, + ansi: [ + 0x000000, 0x990000, 0x00b418, 0xcd0000, 0x0206ff, 0xb90690, 0x0100b6, 0xdedede, + 0x00b418, 0xd80800, 0x42c854, 0xda4242, 0x4447ff, 0xcb47ad, 0x1c02ff, 0xffffff, + ], + }, + ), + ( + "emacs", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x000000, + selection_bg: 0xeedc82, + selection_fg: 0x000000, + accent: 0x0000ff, + chrome_bg: 0xbfbfbf, + chrome_fg: 0x000000, + chrome_active_bg: 0xa4a4a4, + border: 0x595959, + popup_bg: 0xf7f7f7, + ansi: [ + 0x000000, 0xff0000, 0x00ff00, 0xffff00, 0x0000ff, 0xff00ff, 0x00ffff, 0xffffff, + 0xb22222, 0xee2c2c, 0x90ee90, 0xffffe0, 0xadd8e6, 0x912cee, 0xe0ffff, 0xffffff, + ], + }, + ), + ( + "everblush", + Theme { + dark: true, + background: 0x141b1e, + foreground: 0xdadada, + cursor: 0xdadada, + selection_bg: 0x232a2d, + selection_fg: 0xdadada, + accent: 0x67b0e8, + chrome_bg: 0x293032, + chrome_fg: 0xdadada, + chrome_active_bg: 0x474d4f, + border: 0x1e2528, + popup_bg: 0x161d1f, + ansi: [ + 0x232a2d, 0xe57474, 0x8ccf7e, 0xe5c76b, 0x67b0e8, 0xc47fd5, 0x6cbfbf, 0xb3b9b8, + 0x777b7d, 0xec9898, 0xaadba0, 0xf4d67a, 0x8fc5ee, 0xd3a0e0, 0x67cbe7, 0xe7e7e7, + ], + }, + ), + ( + "everforest_dark", + Theme { + dark: true, + background: 0x2d353b, + foreground: 0xd3c6aa, + cursor: 0xd3c6aa, + selection_bg: 0x475258, + selection_fg: 0xd3c6aa, + accent: 0xe69875, + chrome_bg: 0x475258, + chrome_fg: 0x9da9a0, + chrome_active_bg: 0x616a6f, + border: 0x434c52, + popup_bg: 0x3d484d, + ansi: [ + 0x484f54, 0xe67e80, 0xa7c080, 0xdbbc7f, 0x7fbbb3, 0xd699b6, 0x83c092, 0xd3c6aa, + 0x859289, 0xeda0a1, 0xbed0a1, 0xe4cda0, 0xa0cdc7, 0xdba5bf, 0xa3d0ae, 0xe2dac8, + ], + }, + ), + ( + "everforest_light", + Theme { + dark: false, + background: 0xfdf6e3, + foreground: 0x5c6a72, + cursor: 0x5c6a72, + selection_bg: 0xe6e2cc, + selection_fg: 0x5c6a72, + accent: 0x3a94c5, + chrome_bg: 0xe6e2cc, + chrome_fg: 0x829181, + chrome_active_bg: 0xc6c2af, + border: 0xeae5d1, + popup_bg: 0xefebd4, + ansi: [ + 0x455056, 0xf85552, 0x8da101, 0xdfa000, 0x3a94c5, 0xdf69ba, 0x35a77c, 0xdcd6c5, + 0x939f91, 0xfa817f, 0xabb943, 0xf57d26, 0x6db0d4, 0xe790cc, 0x6abe9e, 0xfdf6e3, + ], + }, + ), + ( + "ferra", + Theme { + dark: true, + background: 0x2b292d, + foreground: 0xfecdb2, + cursor: 0xfecdb2, + selection_bg: 0x4d424b, + selection_fg: 0xfecdb2, + accent: 0xfecdb2, + chrome_bg: 0x383539, + chrome_fg: 0xfecdb2, + chrome_active_bg: 0x545155, + border: 0x574b50, + popup_bg: 0x383539, + ansi: [ + 0x474548, 0xe06b75, 0xb1b695, 0xf5d76e, 0xd1d1e0, 0xf6b6c9, 0xffa07a, 0xfecdb2, + 0x6f5d63, 0xe89199, 0xc5c9b1, 0xf8e194, 0xd7d7e4, 0xf7bfcf, 0xffab8a, 0xfedfcd, + ], + }, + ), + ( + "flatwhite", + Theme { + dark: false, + background: 0xf7f3ee, + foreground: 0x605a52, + cursor: 0xf7f3ee, + selection_bg: 0x93836c, + selection_fg: 0xf1ece4, + accent: 0x605a52, + chrome_bg: 0x605a52, + chrome_fg: 0xf7f3ee, + chrome_active_bg: 0x76716a, + border: 0x959089, + popup_bg: 0xf1ece4, + ansi: [ + 0x48443e, 0xff1414, 0x2db448, 0xf2a60d, 0x4c5361, 0x614c61, 0x465953, 0xffffff, + 0xb9a992, 0xff5151, 0x64c878, 0xf5bd4c, 0x7382a0, 0x9c739c, 0x5f8c7d, 0xf7f3ee, + ], + }, + ), + ( + "fleet_dark", + Theme { + dark: true, + background: 0x181818, + foreground: 0xd1d1d1, + cursor: 0xd1d1d1, + selection_bg: 0x194176, + selection_fg: 0xd1d1d1, + accent: 0x87c3ff, + chrome_bg: 0x292929, + chrome_fg: 0xd1d1d1, + chrome_active_bg: 0x474747, + border: 0x2d2d2d, + popup_bg: 0x292929, + ansi: [ + 0x000000, 0xff5269, 0xa8cc7c, 0xebc88d, 0x87c3ff, 0xe394dc, 0x82d2ce, 0xffffff, + 0x898989, 0xff7f90, 0xbfd99e, 0xedcf9b, 0x95caff, 0xe6a1e0, 0xa3dedb, 0xe1e1e1, + ], + }, + ), + ( + "flexoki_dark", + Theme { + dark: true, + background: 0x100f0f, + foreground: 0xcecdc3, + cursor: 0xcecdc3, + selection_bg: 0x343331, + selection_fg: 0xcecdc3, + accent: 0x4385be, + chrome_bg: 0x1c1b1a, + chrome_fg: 0xcecdc3, + chrome_active_bg: 0x3c3b3a, + border: 0x8c8b84, + popup_bg: 0x1c1b1a, + ansi: [ + 0x2f2e2e, 0xd14d41, 0x879a39, 0xd0a215, 0x4385be, 0xce5d97, 0x3aa99f, 0xcecdc3, + 0x575653, 0xdd7b72, 0xa6b46c, 0xda702c, 0x74a5cf, 0xdb87b2, 0x6dbfb8, 0xdfdfd8, + ], + }, + ), + ( + "flexoki_light", + Theme { + dark: false, + background: 0xfffcf0, + foreground: 0x100f0f, + cursor: 0x100f0f, + selection_bg: 0xdad8ce, + selection_fg: 0x100f0f, + accent: 0x205ea6, + chrome_bg: 0xf2f0e5, + chrome_fg: 0x100f0f, + chrome_active_bg: 0xd0cec5, + border: 0x64625e, + popup_bg: 0xf2f0e5, + ansi: [ + 0x0c0b0b, 0xaf3029, 0x66800b, 0xad8301, 0x205ea6, 0xa02f6f, 0x24837b, 0xdedbd1, + 0x7c7a74, 0xc46661, 0x8ea14a, 0xbc5215, 0x5a88bd, 0xb96594, 0x5da39d, 0xfffcf0, + ], + }, + ), + ( + "focus_nova", + Theme { + dark: true, + background: 0x1e1e2e, + foreground: 0xdcdcdc, + cursor: 0xa8a8a8, + selection_bg: 0x5a5a72, + selection_fg: 0xdcdcdc, + accent: 0x89b4fa, + chrome_bg: 0x3b3b4d, + chrome_fg: 0xdcdcdc, + chrome_active_bg: 0x565666, + border: 0x5d5d69, + popup_bg: 0x2e2e3e, + ansi: [ + 0x3b3b49, 0xff6e7f, 0xc0fca0, 0xf9e2af, 0x89b4fa, 0xcba6f7, 0x94e2d5, 0xdcdcdc, + 0x7a7a89, 0xff7f8e, 0xc8fcab, 0xfae5b9, 0x97bdfb, 0xd1b1f8, 0xa1e5da, 0xe8e8e8, + ], + }, + ), + ( + "github_dark", + Theme { + dark: true, + background: 0x0d1117, + foreground: 0x8b949e, + cursor: 0x8b949e, + selection_bg: 0x0d419d, + selection_fg: 0x8b949e, + accent: 0xd29922, + chrome_bg: 0x21262d, + chrome_fg: 0x8b949e, + chrome_active_bg: 0x40444a, + border: 0x242930, + popup_bg: 0x161b22, + ansi: [ + 0x2c3035, 0xf85149, 0x3fb950, 0xd29922, 0x58a6ff, 0xd2a8ff, 0xa5d6ff, 0x8b949e, + 0x8b949e, 0xf78166, 0x56d364, 0xe3b341, 0x79c0ff, 0xd7b2ff, 0xb0dbff, 0xb4b9c0, + ], + }, + ), + ( + "github_dark_colorblind", + Theme { + dark: true, + background: 0x0d1117, + foreground: 0x8b949e, + cursor: 0x8b949e, + selection_bg: 0x0d419d, + selection_fg: 0x8b949e, + accent: 0xd29922, + chrome_bg: 0x21262d, + chrome_fg: 0x8b949e, + chrome_active_bg: 0x40444a, + border: 0x242930, + popup_bg: 0x161b22, + ansi: [ + 0x2c3035, 0xffa28b, 0x79c0ff, 0xd29922, 0x58a6ff, 0xd2a8ff, 0xa5d6ff, 0x8b949e, + 0x8b949e, 0xffad99, 0x89c8ff, 0xec8e2c, 0x83bdff, 0xd7b2ff, 0xb0dbff, 0xb4b9c0, + ], + }, + ), + ( + "github_dark_dimmed", + Theme { + dark: true, + background: 0x22272e, + foreground: 0x768390, + cursor: 0x768390, + selection_bg: 0x1b4b91, + selection_fg: 0xdde4ef, + accent: 0xc69026, + chrome_bg: 0x373e47, + chrome_fg: 0x768390, + chrome_active_bg: 0x535961, + border: 0x383f48, + popup_bg: 0x2d333b, + ansi: [ + 0x3f4349, 0xe5534b, 0x57ab5a, 0xc69026, 0x539bf5, 0xc96198, 0x96d0ff, 0x768390, + 0x768390, 0xf47067, 0x6bc46d, 0xdaaa3f, 0x6cb6ff, 0xe275ad, 0xa3d6ff, 0xa6aeb7, + ], + }, + ), + ( + "github_dark_high_contrast", + Theme { + dark: true, + background: 0x0a0c10, + foreground: 0xf0f3f6, + cursor: 0xf0f3f6, + selection_bg: 0x2672f3, + selection_fg: 0xf0f3f6, + accent: 0xf0b72f, + chrome_bg: 0x272b33, + chrome_fg: 0xf0f3f6, + chrome_active_bg: 0x454950, + border: 0x535962, + popup_bg: 0x272b33, + ansi: [ + 0x2a2c2f, 0xff6a69, 0x26cd4d, 0xf0b72f, 0x71b7ff, 0xef6eb1, 0xaddcff, 0xf0f3f6, + 0xf0f3f6, 0xff9492, 0x4ae168, 0xf7c843, 0x91cbff, 0xff8dc7, 0xb7e0ff, 0xf5f7f9, + ], + }, + ), + ( + "github_dark_tritanopia", + Theme { + dark: true, + background: 0x0d1117, + foreground: 0x8b949e, + cursor: 0x8b949e, + selection_bg: 0x0d419d, + selection_fg: 0x8b949e, + accent: 0xd29922, + chrome_bg: 0x21262d, + chrome_fg: 0x8b949e, + chrome_active_bg: 0x40444a, + border: 0x242930, + popup_bg: 0x161b22, + ansi: [ + 0x2c3035, 0xf85149, 0x79c0ff, 0xd29922, 0x58a6ff, 0xd2a8ff, 0xa5d6ff, 0x8b949e, + 0x8b949e, 0xf78166, 0x89c8ff, 0xe3b341, 0x83bdff, 0xd7b2ff, 0xb0dbff, 0xb4b9c0, + ], + }, + ), + ( + "github_light", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x57606a, + cursor: 0x57606a, + selection_bg: 0xb6e3ff, + selection_fg: 0x57606a, + accent: 0x9a6700, + chrome_bg: 0xeaeef2, + chrome_fg: 0x57606a, + chrome_active_bg: 0xc9cdd0, + border: 0xe0e5ea, + popup_bg: 0xf6f8fa, + ansi: [ + 0x414850, 0xcf222e, 0x1a7f37, 0x9a6700, 0x0969da, 0xff80c8, 0x0550ae, 0xdedede, + 0x57606a, 0xec6547, 0x2da44e, 0xbc4c00, 0x218bff, 0xff8fcf, 0x218bff, 0xffffff, + ], + }, + ), + ( + "github_light_colorblind", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x57606a, + cursor: 0x57606a, + selection_bg: 0xb6e3ff, + selection_fg: 0x57606a, + accent: 0x9a6700, + chrome_bg: 0xeaeef2, + chrome_fg: 0x57606a, + chrome_active_bg: 0xc9cdd0, + border: 0xe0e5ea, + popup_bg: 0xf6f8fa, + ansi: [ + 0x414850, 0x510901, 0xb35900, 0x9a6700, 0x0969da, 0xff80c8, 0x0550ae, 0xdedede, + 0x57606a, 0x691105, 0xc4432b, 0xbf8700, 0x218bff, 0xff8fcf, 0x218bff, 0xffffff, + ], + }, + ), + ( + "github_light_high_contrast", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x0e1116, + cursor: 0x0e1116, + selection_bg: 0x9cd7ff, + selection_fg: 0x0e1116, + accent: 0x744500, + chrome_bg: 0xe7ecf0, + chrome_fg: 0x0e1116, + chrome_active_bg: 0xc7cbce, + border: 0x6e7176, + popup_bg: 0xffffff, + ansi: [ + 0x0b0d11, 0xa0111f, 0x055d20, 0x744500, 0x0349b4, 0x971368, 0x023b95, 0xdedede, + 0x0e1116, 0xcd3425, 0x117f32, 0x956400, 0x1168e3, 0xc9248e, 0x1168e3, 0xffffff, + ], + }, + ), + ( + "github_light_tritanopia", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x57606a, + cursor: 0x57606a, + selection_bg: 0xb6e3ff, + selection_fg: 0x57606a, + accent: 0x9a6700, + chrome_bg: 0xeaeef2, + chrome_fg: 0x57606a, + chrome_active_bg: 0xc9cdd0, + border: 0xe0e5ea, + popup_bg: 0xf6f8fa, + ansi: [ + 0x414850, 0xcf222e, 0xbf8700, 0x9a6700, 0x0969da, 0xff80c8, 0x0550ae, 0xdedede, + 0x57606a, 0xec6547, 0xd4a72c, 0xd4a72c, 0x218bff, 0xff8fcf, 0x218bff, 0xffffff, + ], + }, + ), + ( + "gruber-darker", + Theme { + dark: true, + background: 0x181818, + foreground: 0xe4e4ef, + cursor: 0xe4e4ef, + selection_bg: 0x404040, + selection_fg: 0xe4e4ef, + accent: 0x96a6c8, + chrome_bg: 0x282828, + chrome_fg: 0xe4e4ef, + chrome_active_bg: 0x464646, + border: 0x222222, + popup_bg: 0x232323, + ansi: [ + 0x363636, 0xf43841, 0x73c936, 0xffdd33, 0x96a6c8, 0xfb4934, 0x5292c8, 0xe4e4ef, + 0xcc8c3c, 0xff4f58, 0x97d76a, 0xffe668, 0xb1bdd6, 0xff4f58, 0x7faed6, 0xededf5, + ], + }, + ), + ( + "gruvbox", + Theme { + dark: true, + background: 0x282828, + foreground: 0xebdbb2, + cursor: 0xbdae93, + selection_bg: 0x665c54, + selection_fg: 0xebdbb2, + accent: 0x83a598, + chrome_bg: 0x504945, + chrome_fg: 0xebdbb2, + chrome_active_bg: 0x69625f, + border: 0x646464, + popup_bg: 0x3c3836, + ansi: [ + 0x444444, 0xfb4934, 0x8ec07c, 0xfabd2f, 0x83a598, 0xd3869b, 0x458588, 0xebdbb2, + 0x928374, 0xfc7869, 0xabd09e, 0xfbce65, 0xa3bcb3, 0xdea5b5, 0x75a5a7, 0xf2e8cd, + ], + }, + ), + ( + "gruvbox-material", + Theme { + dark: true, + background: 0x282828, + foreground: 0xd4be98, + cursor: 0xd4be98, + selection_bg: 0x45403d, + selection_fg: 0xd4be98, + accent: 0xd4be98, + chrome_bg: 0x32302f, + chrome_fg: 0xddc7a1, + chrome_active_bg: 0x4f4d4c, + border: 0x49433f, + popup_bg: 0x45403d, + ansi: [ + 0x444444, 0xea6962, 0xa9b665, 0xd8a657, 0x7daea3, 0xd3869b, 0x89b482, 0xd4be98, + 0x928374, 0xef908b, 0xbfc98d, 0xe2bd83, 0x9fc3bb, 0xdea5b5, 0xa8c8a3, 0xe3d5bc, + ], + }, + ), + ( + "gruvbox_dark_hard", + Theme { + dark: true, + background: 0x1d2021, + foreground: 0xebdbb2, + cursor: 0x504945, + selection_bg: 0x665c54, + selection_fg: 0xebdbb2, + accent: 0x83a598, + chrome_bg: 0x504945, + chrome_fg: 0xebdbb2, + chrome_active_bg: 0x69625f, + border: 0x5c5e5f, + popup_bg: 0x3c3836, + ansi: [ + 0x3a3d3e, 0xfb4934, 0x8ec07c, 0xfabd2f, 0x83a598, 0xd3869b, 0x458588, 0xebdbb2, + 0x928374, 0xfc7869, 0xabd09e, 0xfbce65, 0xa3bcb3, 0xdea5b5, 0x75a5a7, 0xf2e8cd, + ], + }, + ), + ( + "gruvbox_dark_soft", + Theme { + dark: true, + background: 0x32302f, + foreground: 0xebdbb2, + cursor: 0xbdae93, + selection_bg: 0x665c54, + selection_fg: 0xebdbb2, + accent: 0x83a598, + chrome_bg: 0x504945, + chrome_fg: 0xebdbb2, + chrome_active_bg: 0x69625f, + border: 0x6b6a69, + popup_bg: 0x3c3836, + ansi: [ + 0x4d4b4a, 0xfb4934, 0x8ec07c, 0xfabd2f, 0x83a598, 0xd3869b, 0x458588, 0xebdbb2, + 0x928374, 0xfc7869, 0xabd09e, 0xfbce65, 0xa3bcb3, 0xdea5b5, 0x75a5a7, 0xf2e8cd, + ], + }, + ), + ( + "gruvbox_light", + Theme { + dark: false, + background: 0xfbf1c7, + foreground: 0x3c3836, + cursor: 0xd5c4a1, + selection_bg: 0xbdae93, + selection_fg: 0x3c3836, + accent: 0x076678, + chrome_bg: 0xd5c4a1, + chrome_fg: 0x3c3836, + chrome_active_bg: 0xb7a98a, + border: 0xb5ae8f, + popup_bg: 0xebdbb2, + ansi: [ + 0x2d2a29, 0x9d0006, 0x689d6a, 0xb57614, 0x458588, 0x8f3f71, 0x076678, 0xdad2ad, + 0x928374, 0xd65d0e, 0x8fb691, 0xd65d0e, 0x75a5a7, 0xb16286, 0x478e9b, 0xfbf1c7, + ], + }, + ), + ( + "gruvbox_light_hard", + Theme { + dark: false, + background: 0xf9f5d7, + foreground: 0x3c3836, + cursor: 0xd5c4a1, + selection_bg: 0xbdae93, + selection_fg: 0x3c3836, + accent: 0x076678, + chrome_bg: 0xd5c4a1, + chrome_fg: 0x3c3836, + chrome_active_bg: 0xb7a98a, + border: 0xb3b09b, + popup_bg: 0xebdbb2, + ansi: [ + 0x2d2a29, 0x9d0006, 0x689d6a, 0xb57614, 0x458588, 0x8f3f71, 0x076678, 0xd9d5bb, + 0x928374, 0xd65d0e, 0x8fb691, 0xd65d0e, 0x75a5a7, 0xb16286, 0x478e9b, 0xf9f5d7, + ], + }, + ), + ( + "gruvbox_light_soft", + Theme { + dark: false, + background: 0xf2e5bc, + foreground: 0x3c3836, + cursor: 0xd5c4a1, + selection_bg: 0xbdae93, + selection_fg: 0x3c3836, + accent: 0x076678, + chrome_bg: 0xd5c4a1, + chrome_fg: 0x3c3836, + chrome_active_bg: 0xb7a98a, + border: 0xaea587, + popup_bg: 0xebdbb2, + ansi: [ + 0x2d2a29, 0x9d0006, 0x689d6a, 0xb57614, 0x458588, 0x8f3f71, 0x076678, 0xd3c7a4, + 0x928374, 0xd65d0e, 0x8fb691, 0xd65d0e, 0x75a5a7, 0xb16286, 0x478e9b, 0xf2e5bc, + ], + }, + ), + ( + "heisenberg", + Theme { + dark: true, + background: 0x000000, + foreground: 0x32c9fa, + cursor: 0x32c9fa, + selection_bg: 0x2b0c02, + selection_fg: 0x32c9fa, + accent: 0xf7b90c, + chrome_bg: 0x121212, + chrome_fg: 0x32c9fa, + chrome_active_bg: 0x333333, + border: 0x006244, + popup_bg: 0x000000, + ansi: [ + 0x121212, 0xc32101, 0x00ff80, 0xf7b90c, 0x5c6773, 0xbd5173, 0x009669, 0x32c9fa, + 0xbd5173, 0xff8f40, 0x42ffa1, 0xff8f40, 0x32c9fa, 0xce7e97, 0x42b190, 0x7adcfc, + ], + }, + ), + ( + "hex_lavender", + Theme { + dark: true, + background: 0x181a17, + foreground: 0x61586f, + cursor: 0x29bbff, + selection_bg: 0x290019, + selection_fg: 0x958e9a, + accent: 0xff2e5f, + chrome_bg: 0x0e0e0d, + chrome_fg: 0x61586f, + chrome_active_bg: 0x30302f, + border: 0x474250, + popup_bg: 0x0e0e0d, + ansi: [ + 0x000000, 0xff0900, 0x57ff89, 0xffbf00, 0x0048bd, 0x8e80de, 0xa0c7cf, 0x61586f, + 0x797a78, 0xff2e5f, 0x83ffa8, 0xffd042, 0x29bbff, 0xaba1e7, 0xabced5, 0x9892a1, + ], + }, + ), + ( + "hex_poison", + Theme { + dark: true, + background: 0x1e1f1b, + foreground: 0x5a6052, + cursor: 0xd7ff52, + selection_bg: 0x290019, + selection_fg: 0xc8e732, + accent: 0xff2e5f, + chrome_bg: 0x121211, + chrome_fg: 0x5a6052, + chrome_active_bg: 0x333332, + border: 0x45493f, + popup_bg: 0x121211, + ansi: [ + 0x000000, 0xc73500, 0x57ff89, 0xdcbb00, 0x0048bd, 0xff2e5f, 0x16a7c7, 0x5a6052, + 0x396884, 0xff4000, 0x83ffa8, 0xc8e732, 0x4278ce, 0xff6489, 0x53bed6, 0x94988f, + ], + }, + ), + ( + "hex_steel", + Theme { + dark: true, + background: 0x1d1e1b, + foreground: 0x656869, + cursor: 0xd4d987, + selection_bg: 0x4a9aa6, + selection_fg: 0x080a0b, + accent: 0xf23672, + chrome_bg: 0x0e0e0d, + chrome_fg: 0x656869, + chrome_active_bg: 0x30302f, + border: 0x4c4e4e, + popup_bg: 0x0e0e0d, + ansi: [ + 0x000000, 0xff4000, 0xc9d400, 0xffbf00, 0x0048bd, 0xd85c60, 0x42baff, 0x656869, + 0x654642, 0xf69c3c, 0xd7df42, 0xf69c3c, 0x4278ce, 0xf78c5e, 0x73ccff, 0x9b9d9e, + ], + }, + ), + ( + "hex_toxic", + Theme { + dark: true, + background: 0x1b2a32, + foreground: 0x8792ab, + cursor: 0xf8ed8b, + selection_bg: 0xb10656, + selection_fg: 0x101719, + accent: 0xff0a50, + chrome_bg: 0x101719, + chrome_fg: 0x8792ab, + chrome_active_bg: 0x313739, + border: 0x616e81, + popup_bg: 0x101719, + ansi: [ + 0x000000, 0xff0900, 0x57ff89, 0xffbf00, 0x0048bd, 0xb10656, 0x8bb2b9, 0x8792ab, + 0x417e8c, 0xff4942, 0x83ffa8, 0xffd042, 0x4278ce, 0xff0a50, 0xb0d4d8, 0xb1b8c8, + ], + }, + ), + ( + "horizon-dark", + Theme { + dark: true, + background: 0x1c1e26, + foreground: 0xd5d8da, + cursor: 0xd5d8da, + selection_bg: 0x353747, + selection_fg: 0xd5d8da, + accent: 0x25b2bc, + chrome_bg: 0x16161c, + chrome_fg: 0x6c6f93, + chrome_active_bg: 0x37373c, + border: 0x2c2e3b, + popup_bg: 0x16161c, + ansi: [ + 0x3a3b42, 0xe95678, 0x27d796, 0xfab795, 0x25b2bc, 0xb877db, 0x6c6f93, 0xd5d8da, + 0x6c6f93, 0xf09383, 0x5fe1b1, 0xfbc0a2, 0x5ec6cd, 0xca9ae4, 0x9294af, 0xe4e6e7, + ], + }, + ), + ( + "iceberg-dark", + Theme { + dark: true, + background: 0x161822, + foreground: 0xc7c9d1, + cursor: 0xc7c9d1, + selection_bg: 0x282d43, + selection_fg: 0xc7c9d1, + accent: 0x85a0c7, + chrome_bg: 0x0f1117, + chrome_fg: 0x828597, + chrome_active_bg: 0x313237, + border: 0x4e5265, + popup_bg: 0x3d425c, + ansi: [ + 0x1e2132, 0xe27878, 0xb5bf82, 0xe2a478, 0x85a0c7, 0xa093c7, 0x89b9c2, 0xc6c8d1, + 0x6c7189, 0xe98989, 0xc0ca8e, 0xe9b189, 0x91acd1, 0xada0d3, 0x95c4ce, 0xdbdce1, + ], + }, + ), + ( + "iceberg-light", + Theme { + dark: false, + background: 0xe9e9ed, + foreground: 0x33374d, + cursor: 0x33374d, + selection_bg: 0xcacdd8, + selection_fg: 0x33374d, + accent: 0x2e539e, + chrome_bg: 0xcad0de, + chrome_fg: 0x757da3, + chrome_active_bg: 0xaeb3bf, + border: 0xa7abbe, + popup_bg: 0xcccfe0, + ansi: [ + 0xdcdfe7, 0xcd517a, 0x668f3d, 0xc57339, 0x2e539e, 0x7759b4, 0x3f84a6, 0x33374c, + 0x8489a4, 0xcc3768, 0x598030, 0xb6662d, 0x22478e, 0x6845ad, 0x327698, 0xe9e9ed, + ], + }, + ), + ( + "ingrid", + Theme { + dark: false, + background: 0xfffcfd, + foreground: 0x7b91b3, + cursor: 0xed5466, + selection_bg: 0xf3eae9, + selection_fg: 0x7b91b3, + accent: 0xed5466, + chrome_bg: 0xf3eae9, + chrome_fg: 0x250e07, + chrome_active_bg: 0xd1c9c8, + border: 0xb8b5b6, + popup_bg: 0xf3e8e9, + ansi: [ + 0x5c6d86, 0xd74e50, 0x839a53, 0xd4a520, 0xa6b6ce, 0xd68482, 0x89beb7, 0xdedbdc, + 0xa6b6ce, 0xe17c7e, 0xa3b480, 0xdfbc5a, 0xb1bfd4, 0xe1a4a3, 0xa8cfca, 0xfffcfd, + ], + }, + ), + ( + "iroaseta", + Theme { + dark: true, + background: 0x0d1117, + foreground: 0xdadada, + cursor: 0xdadada, + selection_bg: 0x7533bd, + selection_fg: 0xdadada, + accent: 0x45b1e8, + chrome_bg: 0x000000, + chrome_fg: 0xf2f0eb, + chrome_active_bg: 0x242424, + border: 0x050608, + popup_bg: 0x010409, + ansi: [ + 0x0d1117, 0xfa7970, 0x81be83, 0xffba00, 0x45b1e8, 0xd2a8ff, 0x91a3b0, 0xdadada, + 0x838a97, 0xfb8981, 0xa2cfa3, 0xffcc42, 0x6eb0ff, 0xd7b2ff, 0x6eb0ff, 0xe7e7e7, + ], + }, + ), + ( + "jellybeans", + Theme { + dark: true, + background: 0x151515, + foreground: 0xebebd8, + cursor: 0x151515, + selection_bg: 0x37232d, + selection_fg: 0xf2aac7, + accent: 0x52a7f6, + chrome_bg: 0x292929, + chrome_fg: 0xebebd8, + chrome_active_bg: 0x474747, + border: 0x606060, + popup_bg: 0x1e1e1e, + ansi: [ + 0x333333, 0xcc7c8a, 0x99ad6a, 0xfad07a, 0x52a7f6, 0xcdbef0, 0x2197f3, 0xffffff, + 0x6d6d6d, 0xf2aac7, 0xb4c291, 0xebebd8, 0x8fbfdc, 0xd3c6f2, 0x5bb2f6, 0xf2f2e6, + ], + }, + ), + ( + "jetbrains_dark", + Theme { + dark: true, + background: 0x1e1f22, + foreground: 0xbcbec4, + cursor: 0xbcbec4, + selection_bg: 0x214283, + selection_fg: 0xbcbec4, + accent: 0x57aaf7, + chrome_bg: 0x2b2d30, + chrome_fg: 0xbfc0c1, + chrome_active_bg: 0x494a4d, + border: 0x2a2d30, + popup_bg: 0x2b2d30, + ansi: [ + 0x3b3c3f, 0xd64d5b, 0x499c54, 0xc29e4a, 0x57aaf7, 0xc77dbb, 0x2aacb8, 0xbcbec4, + 0x7a7e85, 0xe17b86, 0x6aab73, 0xcf8e6d, 0x83c0f9, 0xd69fcd, 0x56a8f5, 0xd3d5d9, + ], + }, + ), + ( + "kanagawa", + Theme { + dark: true, + background: 0x1f1f28, + foreground: 0xdcd7ba, + cursor: 0xdcd7ba, + selection_bg: 0x2d4f67, + selection_fg: 0xdcd7ba, + accent: 0xe46876, + chrome_bg: 0x16161d, + chrome_fg: 0xc8c093, + chrome_active_bg: 0x37373d, + border: 0x191921, + popup_bg: 0x16161d, + ansi: [ + 0x3c3c44, 0xe82424, 0x76946a, 0xff9e3b, 0x7e9cd8, 0x957fb8, 0x7fb4ca, 0xdcd7ba, + 0x727169, 0xff5d62, 0x7aa880, 0xffa066, 0xa0b6e2, 0xb1a0ca, 0xa0c8d8, 0xe8e5d2, + ], + }, + ), + ( + "kanagawa-dragon", + Theme { + dark: true, + background: 0x181616, + foreground: 0xc5c9c5, + cursor: 0xdcd7ba, + selection_bg: 0x223249, + selection_fg: 0xc5c9c5, + accent: 0xff9e3b, + chrome_bg: 0x0d0c0c, + chrome_fg: 0xc8c093, + chrome_active_bg: 0x2f2e2e, + border: 0x17161b, + popup_bg: 0x0d0c0c, + ansi: [ + 0x363434, 0xe82424, 0x76946a, 0xff9e3b, 0x949fb5, 0xd27e99, 0x8ba4b0, 0xc5c9c5, + 0x737c73, 0xff5d62, 0x7aa880, 0xffa066, 0x9cabca, 0xdea0b4, 0x7e9cd8, 0xd9dcd9, + ], + }, + ), + ( + "kaolin-dark", + Theme { + dark: true, + background: 0x18181b, + foreground: 0xadadb9, + cursor: 0xadadb9, + selection_bg: 0x2e403b, + selection_fg: 0xadadb9, + accent: 0x968cc7, + chrome_bg: 0x222225, + chrome_fg: 0x80bcb6, + chrome_active_bg: 0x414144, + border: 0x1f1f22, + popup_bg: 0x222225, + ansi: [ + 0x363639, 0xcd5c60, 0x6fb593, 0xdbac66, 0x968cc7, 0xab98b5, 0x4d9391, 0xadadb9, + 0x545c5e, 0xda8689, 0x68f3ca, 0xe4c28e, 0xb1aad6, 0xc1b3c8, 0x80bcb6, 0xcacad2, + ], + }, + ), + ( + "kaolin-light", + Theme { + dark: false, + background: 0xedeeeb, + foreground: 0x383e3f, + cursor: 0x383e3f, + selection_bg: 0xd3e4f0, + selection_fg: 0x383e3f, + accent: 0x3b84cc, + chrome_bg: 0xdfe1dc, + chrome_fg: 0x4c7a90, + chrome_active_bg: 0xc0c2bd, + border: 0xe4e6e1, + popup_bg: 0xdfe1dc, + ansi: [ + 0x2a2f2f, 0xe84c58, 0x39854c, 0xe36b3f, 0x3b84cc, 0x845a84, 0x13665f, 0xcecfcc, + 0x7c878a, 0xee7b83, 0x6ca57b, 0xea9171, 0x6ea4d9, 0xa485a4, 0x4c7a90, 0xedeeeb, + ], + }, + ), + ( + "kaolin-valley-dark", + Theme { + dark: true, + background: 0x262221, + foreground: 0xcea2ca, + cursor: 0xcea2ca, + selection_bg: 0x402e2e, + selection_fg: 0xcea2ca, + accent: 0xcea2ca, + chrome_bg: 0x2e2a29, + chrome_fg: 0xeee6d3, + chrome_active_bg: 0x4b4847, + border: 0x2b2726, + popup_bg: 0x2e2a29, + ansi: [ + 0x423f3e, 0xe84c58, 0x91f368, 0xeed891, 0x9587dd, 0x766884, 0x49bdb0, 0xcea2ca, + 0x635c4a, 0xef6787, 0xaef68f, 0xf0dd9e, 0xb1a6e6, 0x968cc7, 0x41b0f3, 0xdfc3dd, + ], + }, + ), + ( + "kinda_nvim", + Theme { + dark: true, + background: 0x00120c, + foreground: 0xb6bfbc, + cursor: 0xb6bfbc, + selection_bg: 0x003624, + selection_fg: 0xb6bfbc, + accent: 0x6797c2, + chrome_bg: 0x172722, + chrome_fg: 0xb6bfbc, + chrome_active_bg: 0x374541, + border: 0x31403b, + popup_bg: 0x001c13, + ansi: [ + 0x21312c, 0xc27280, 0x12b27d, 0xb8a26c, 0x6797c2, 0x9c59b2, 0x32878f, 0xb6bfbc, + 0x526b82, 0xd297a1, 0x50c69f, 0xcaba92, 0x8fb2d2, 0xb684c6, 0x6c94b8, 0xd0d5d3, + ], + }, + ), + ( + "kinda_nvim_light", + Theme { + dark: false, + background: 0xf2f5f4, + foreground: 0x414d49, + cursor: 0x414d49, + selection_bg: 0xe6e8e7, + selection_fg: 0x414d49, + accent: 0x005bab, + chrome_bg: 0xdcdfde, + chrome_fg: 0x414d49, + chrome_active_bg: 0xbdc0bf, + border: 0xd0dcd8, + popup_bg: 0xfcfffe, + ansi: [ + 0x313a37, 0xbf0020, 0x008c5d, 0xb58200, 0x005bab, 0x9847b2, 0x119ca8, 0xd3d5d4, + 0x759aba, 0xd0425a, 0x2f9c77, 0xc8a342, 0x2470b2, 0xa860bf, 0x2470b2, 0xf2f5f4, + ], + }, + ), + ( + "lapis_aquamarine", + Theme { + dark: true, + background: 0x1b1f27, + foreground: 0xd6e2ff, + cursor: 0x83abfc, + selection_bg: 0x43537a, + selection_fg: 0xabfc83, + accent: 0x83abfc, + chrome_bg: 0x30333a, + chrome_fg: 0xd6e2ff, + chrome_active_bg: 0x4d5056, + border: 0x273044, + popup_bg: 0x1b1f27, + ansi: [ + 0x393c43, 0xfc83ab, 0xabfc83, 0xfcd583, 0x83abfc, 0xd483fc, 0x84fcd4, 0xd6e2ff, + 0x7183a9, 0xfc92b5, 0xb5fc92, 0xfcda92, 0x92b5fc, 0xd992fc, 0x93fcd9, 0xe4ecff, + ], + }, + ), + ( + "material_darker", + Theme { + dark: true, + background: 0x212121, + foreground: 0xb0bec5, + cursor: 0xeeffff, + selection_bg: 0x404040, + selection_fg: 0xb0bec5, + accent: 0xeeffff, + chrome_bg: 0x353535, + chrome_fg: 0xb0bec5, + chrome_active_bg: 0x515151, + border: 0x4b4b4b, + popup_bg: 0x3f3f3f, + ansi: [ + 0x3e3e3e, 0xf07178, 0xc3e88d, 0xffcb6b, 0x82aaff, 0xc792ea, 0x89ddff, 0xeeffff, + 0x616161, 0xf4969b, 0xcaeb9b, 0xffd17d, 0x91b4ff, 0xce9fed, 0x97e1ff, 0xccd5d9, + ], + }, + ), + ( + "material_deep_ocean", + Theme { + dark: true, + background: 0x0f111a, + foreground: 0xa6accd, + cursor: 0xeeffff, + selection_bg: 0x1f2233, + selection_fg: 0xa6accd, + accent: 0xeeffff, + chrome_bg: 0x25262f, + chrome_fg: 0xa6accd, + chrome_active_bg: 0x44444c, + border: 0x4f577e, + popup_bg: 0x1f2233, + ansi: [ + 0x2e3038, 0xf07178, 0xc3e88d, 0xffcb6b, 0x82aaff, 0xc792ea, 0x89ddff, 0xeeffff, + 0x464b5d, 0xf4969b, 0xcaeb9b, 0xffd17d, 0x91b4ff, 0xce9fed, 0x97e1ff, 0xc5c9df, + ], + }, + ), + ( + "material_oceanic", + Theme { + dark: true, + background: 0x25363b, + foreground: 0xb0bec5, + cursor: 0xeeffff, + selection_bg: 0x395b65, + selection_fg: 0xb0bec5, + accent: 0xeeffff, + chrome_bg: 0x39484d, + chrome_fg: 0xb0bec5, + chrome_active_bg: 0x556266, + border: 0x445a64, + popup_bg: 0x425b67, + ansi: [ + 0x415054, 0xf07178, 0xc3e88d, 0xffcb6b, 0x82aaff, 0xc792ea, 0x89ddff, 0xeeffff, + 0x546e7a, 0xf4969b, 0xcaeb9b, 0xffd17d, 0x91b4ff, 0xce9fed, 0x97e1ff, 0xccd5d9, + ], + }, + ), + ( + "material_palenight", + Theme { + dark: true, + background: 0x292d3e, + foreground: 0xa6accd, + cursor: 0xeeffff, + selection_bg: 0x444267, + selection_fg: 0xa6accd, + accent: 0xeeffff, + chrome_bg: 0x3c404f, + chrome_fg: 0xa6accd, + chrome_active_bg: 0x575b68, + border: 0x58608b, + popup_bg: 0x444267, + ansi: [ + 0x454857, 0xf07178, 0xc3e88d, 0xffcb6b, 0x82aaff, 0xc792ea, 0x89ddff, 0xeeffff, + 0x676e95, 0xf4969b, 0xcaeb9b, 0xffd17d, 0x91b4ff, 0xce9fed, 0x97e1ff, 0xc5c9df, + ], + }, + ), + ( + "meliora", + Theme { + dark: true, + background: 0x1c1917, + foreground: 0xdad7d5, + cursor: 0xc2b4a8, + selection_bg: 0x302d2b, + selection_fg: 0xdad7d5, + accent: 0xa49db9, + chrome_bg: 0x302d2b, + chrome_fg: 0xaaa7a6, + chrome_active_bg: 0x4d4a49, + border: 0x292624, + popup_bg: 0x252220, + ansi: [ + 0x1c1917, 0xd29595, 0x707035, 0xc9b58e, 0xa49db9, 0xb494af, 0xcbab8a, 0xdad7d5, + 0x252220, 0xd7a2a2, 0x95956a, 0xd7c8ab, 0xbcb6cb, 0xc8b0c4, 0xd9c1a8, 0xe7e5e4, + ], + }, + ), + ( + "mellow", + Theme { + dark: true, + background: 0x161617, + foreground: 0xc9c7cd, + cursor: 0x57575f, + selection_bg: 0x3e3e43, + selection_fg: 0xc9c7cd, + accent: 0xe6b99d, + chrome_bg: 0x1b1b1d, + chrome_fg: 0xc9c7cd, + chrome_active_bg: 0x3b3b3d, + border: 0x232325, + popup_bg: 0x1b1b1d, + ansi: [ + 0x27272a, 0xf5a191, 0x90b99f, 0xe6b99d, 0xaca1cf, 0xe29eca, 0xea83a5, 0xc1c0d4, + 0x353539, 0xffae9f, 0x9dc6ac, 0xf0c5a9, 0xb9aeda, 0xecaad6, 0xf591b2, 0xcac9dd, + ], + }, + ), + ( + "merionette", + Theme { + dark: true, + background: 0x190f0f, + foreground: 0xcebabf, + cursor: 0xc79295, + selection_bg: 0x442022, + selection_fg: 0xcebabf, + accent: 0xcebabf, + chrome_bg: 0xd2505f, + chrome_fg: 0x190f0f, + chrome_active_bg: 0xb54552, + border: 0x523031, + popup_bg: 0x2c1617, + ansi: [ + 0x372e2e, 0xd95362, 0x6db269, 0xeb842b, 0xd2505f, 0xce8b9f, 0x65aba3, 0xcebabf, + 0xd2505f, 0xff7550, 0x93c690, 0xff7550, 0xff7550, 0xdba9b8, 0x8dc1bb, 0xdfd2d5, + ], + }, + ), + ( + "modus_operandi", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x595959, + selection_bg: 0xc4c4c4, + selection_fg: 0x000000, + accent: 0x0031a9, + chrome_bg: 0xc8c8c8, + chrome_fg: 0x000000, + chrome_active_bg: 0xacacac, + border: 0x939393, + popup_bg: 0xf2f2f2, + ansi: [ + 0x000000, 0xa60000, 0x006800, 0x6f5500, 0x0031a9, 0x721045, 0x005e8b, 0xdedede, + 0x595959, 0xd00000, 0x008900, 0x948142, 0x0000ff, 0xa0132f, 0x4288a9, 0xffffff, + ], + }, + ), + ( + "modus_operandi_deuteranopia", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x595959, + selection_bg: 0xc4c4c4, + selection_fg: 0x000000, + accent: 0x0031a9, + chrome_bg: 0xd0d6ff, + chrome_fg: 0x0f0f0f, + chrome_active_bg: 0xb3b8db, + border: 0x939393, + popup_bg: 0xf2f2f2, + ansi: [ + 0x000000, 0xa60000, 0x006800, 0x695500, 0x0031a9, 0x721045, 0x005e8b, 0xdedede, + 0x77492f, 0xd00000, 0x008900, 0x973300, 0x0000ff, 0xa0132f, 0x4288a9, 0xffffff, + ], + }, + ), + ( + "modus_operandi_tinted", + Theme { + dark: false, + background: 0xfbf7f0, + foreground: 0x000000, + cursor: 0xd00000, + selection_bg: 0xc9b9b0, + selection_fg: 0x000000, + accent: 0xd00000, + chrome_bg: 0xcab9b2, + chrome_fg: 0x000000, + chrome_active_bg: 0xae9f99, + border: 0x92908e, + popup_bg: 0xefe9dd, + ansi: [ + 0x000000, 0xa60000, 0x006800, 0x6f5500, 0x0031a9, 0x721045, 0x005e8b, 0xdad7d1, + 0x7f0000, 0xd00000, 0x008900, 0x948142, 0x0000ff, 0xa0132f, 0x4288a9, 0xfbf7f0, + ], + }, + ), + ( + "modus_operandi_tritanopia", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x595959, + selection_bg: 0xc4c4c4, + selection_fg: 0x000000, + accent: 0x0031a9, + chrome_bg: 0xafe0f2, + chrome_fg: 0x0f0f0f, + chrome_active_bg: 0x97c1d0, + border: 0x939393, + popup_bg: 0xf2f2f2, + ansi: [ + 0x000000, 0xa60000, 0x006800, 0x695500, 0x0031a9, 0x721045, 0x005e8b, 0xdedede, + 0x702000, 0xd00000, 0x008900, 0x973300, 0x0000ff, 0xa0132f, 0x4288a9, 0xffffff, + ], + }, + ), + ( + "modus_vivendi", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0x989898, + selection_bg: 0x535353, + selection_fg: 0xffffff, + accent: 0x2fafff, + chrome_bg: 0x505050, + chrome_fg: 0xffffff, + chrome_active_bg: 0x696969, + border: 0x636363, + popup_bg: 0x1e1e1e, + ansi: [ + 0x212121, 0xff5f59, 0x44bc44, 0xd0bc00, 0x2fafff, 0xfeacd0, 0x00d3d0, 0xffffff, + 0x989898, 0xff7f86, 0x44df44, 0xefef00, 0x65c4ff, 0xfeb6d6, 0x00eff0, 0xffffff, + ], + }, + ), + ( + "modus_vivendi_deuteranopia", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0x989898, + selection_bg: 0x535353, + selection_fg: 0xffffff, + accent: 0x2fafff, + chrome_bg: 0x2a2a6a, + chrome_fg: 0xf0f0f0, + chrome_active_bg: 0x48487f, + border: 0x636363, + popup_bg: 0x1e1e1e, + ansi: [ + 0x212121, 0xff5f59, 0x44bc44, 0xcabf00, 0x2fafff, 0xfeacd0, 0x00d3d0, 0xffffff, + 0xd8af7a, 0xff7f86, 0x44df44, 0xe5bf00, 0x65c4ff, 0xfeb6d6, 0x00eff0, 0xffffff, + ], + }, + ), + ( + "modus_vivendi_tinted", + Theme { + dark: true, + background: 0x0d0e1c, + foreground: 0xffffff, + cursor: 0xff66ff, + selection_bg: 0x4a4f69, + selection_fg: 0xffffff, + accent: 0xff66ff, + chrome_bg: 0x484d67, + chrome_fg: 0xffffff, + chrome_active_bg: 0x62667c, + border: 0x67686d, + popup_bg: 0x1d2235, + ansi: [ + 0x2c2d3a, 0xff5f59, 0x44bc44, 0xd0bc00, 0x2fafff, 0xfeacd0, 0x00d3d0, 0xffffff, + 0xff9f80, 0xff7f86, 0x44df44, 0xefef00, 0x65c4ff, 0xfeb6d6, 0x00eff0, 0xffffff, + ], + }, + ), + ( + "modus_vivendi_tritanopia", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0x989898, + selection_bg: 0x535353, + selection_fg: 0xffffff, + accent: 0x2fafff, + chrome_bg: 0x003c52, + chrome_fg: 0xf0f0f0, + chrome_active_bg: 0x24576a, + border: 0x636363, + popup_bg: 0x1e1e1e, + ansi: [ + 0x212121, 0xff5f59, 0x44bc44, 0xcabf00, 0x2fafff, 0xfeacd0, 0x00d3d0, 0xffffff, + 0xff9070, 0xff7f86, 0x44df44, 0xefef00, 0x4ae2ff, 0xfeb6d6, 0x00eff0, 0xffffff, + ], + }, + ), + ( + "molokai", + Theme { + dark: true, + background: 0x1b1d1e, + foreground: 0xf8f8f2, + cursor: 0xf8f8f0, + selection_bg: 0x575b61, + selection_fg: 0xf8f8f2, + accent: 0xf8f8f0, + chrome_bg: 0x414339, + chrome_fg: 0xffffff, + chrome_active_bg: 0x5c5d55, + border: 0x5b5c5d, + popup_bg: 0x000000, + ansi: [ + 0x393a3b, 0xf48771, 0xa6e22e, 0xcca700, 0x75beff, 0xc586c0, 0x66d9ef, 0xf8f8f2, + 0x7e8e91, 0xf7a696, 0xbdea64, 0xfd971f, 0x66d9ef, 0xd4a5d0, 0x8ee3f3, 0xfafaf7, + ], + }, + ), + ( + "monokai", + Theme { + dark: true, + background: 0x272822, + foreground: 0xf8f8f2, + cursor: 0xa6a6a6, + selection_bg: 0x575b61, + selection_fg: 0xf8f8f2, + accent: 0x75beff, + chrome_bg: 0x414339, + chrome_fg: 0xffffff, + chrome_active_bg: 0x5c5d55, + border: 0x636460, + popup_bg: 0x1e1f1c, + ansi: [ + 0x43443f, 0xf48771, 0xa6e22e, 0xcca700, 0x75beff, 0xc586c0, 0x66d9ef, 0xf8f8f2, + 0x88846f, 0xf7a696, 0xbdea64, 0xfd971f, 0x86c6ff, 0xd4a5d0, 0x8ee3f3, 0xfafaf7, + ], + }, + ), + ( + "monokai_aqua", + Theme { + dark: true, + background: 0x272822, + foreground: 0xf8f8f2, + cursor: 0xa6a6a6, + selection_bg: 0x575b61, + selection_fg: 0xf8f8f2, + accent: 0x75beff, + chrome_bg: 0x414339, + chrome_fg: 0xffffff, + chrome_active_bg: 0x5c5d55, + border: 0x636460, + popup_bg: 0x1e1f1c, + ansi: [ + 0x43443f, 0xf48771, 0xa6e22e, 0xcca700, 0x75beff, 0xc586c0, 0x66d9ef, 0xf8f8f2, + 0x88846f, 0xf7a696, 0xbdea64, 0xfd971f, 0x86c6ff, 0xd4a5d0, 0x8ee3f3, 0xfafaf7, + ], + }, + ), + ( + "monokai_pro", + Theme { + dark: true, + background: 0x2d2a2e, + foreground: 0xfcfcfa, + cursor: 0xc1c0c0, + selection_bg: 0x5b595c, + selection_fg: 0xfcfcfa, + accent: 0x78dce8, + chrome_bg: 0x5b595c, + chrome_fg: 0xfcfcfa, + chrome_active_bg: 0x727073, + border: 0x686669, + popup_bg: 0x403e41, + ansi: [ + 0x484649, 0xff6188, 0xa9dc76, 0xffd866, 0x78dce8, 0xab9df2, 0xfc9867, 0xfcfcfa, + 0x727072, 0xff8aa7, 0xbfe59a, 0xffe28e, 0x9be5ee, 0xb5a9f4, 0xfdb38f, 0xfdfdfc, + ], + }, + ), + ( + "monokai_pro_machine", + Theme { + dark: true, + background: 0x273136, + foreground: 0xf2fffc, + cursor: 0xb8c4c3, + selection_bg: 0x545f62, + selection_fg: 0xf2fffc, + accent: 0x7cd5f1, + chrome_bg: 0x545f62, + chrome_fg: 0xf2fffc, + chrome_active_bg: 0x6c7578, + border: 0x636b6e, + popup_bg: 0x3a4449, + ansi: [ + 0x434c50, 0xff6d7e, 0xa2e57b, 0xffed72, 0x7cd5f1, 0xbaa0f8, 0xffb270, 0xf2fffc, + 0x6b7678, 0xff7f8d, 0xbaec9d, 0xffef83, 0x8cdaf3, 0xc2abf9, 0xffbb81, 0xf7fffd, + ], + }, + ), + ( + "monokai_pro_octagon", + Theme { + dark: true, + background: 0x282a3a, + foreground: 0xeaf2f1, + cursor: 0xb2b9bd, + selection_bg: 0x535763, + selection_fg: 0xeaf2f1, + accent: 0x9cd1bb, + chrome_bg: 0x535763, + chrome_fg: 0xeaf2f1, + chrome_active_bg: 0x6b6f79, + border: 0x646671, + popup_bg: 0x3a3d4b, + ansi: [ + 0x444654, 0xff657a, 0xbad761, 0xffd76d, 0x9cd1bb, 0xc39ac9, 0xff9b5e, 0xeaf2f1, + 0x696d77, 0xff8d9d, 0xcce18a, 0xffdc7f, 0xa8d7c3, 0xd3b4d7, 0xffb588, 0xf1f7f6, + ], + }, + ), + ( + "monokai_pro_ristretto", + Theme { + dark: true, + background: 0x2c2525, + foreground: 0xfff1f3, + cursor: 0xc3b7b8, + selection_bg: 0x5b5353, + selection_fg: 0xfff1f3, + accent: 0x85dacc, + chrome_bg: 0x5b5353, + chrome_fg: 0xfff1f3, + chrome_active_bg: 0x726b6b, + border: 0x676262, + popup_bg: 0x403838, + ansi: [ + 0x474141, 0xfd6883, 0xadda78, 0xf9cc6c, 0x85dacc, 0xf38d70, 0xa8a9eb, 0xfff1f3, + 0x72696a, 0xfe8fa3, 0xc2e49b, 0xfbd992, 0xa5e4d9, 0xf6ab95, 0xb2b3ed, 0xfff6f7, + ], + }, + ), + ( + "monokai_pro_spectrum", + Theme { + dark: true, + background: 0x222222, + foreground: 0xf7f1ff, + cursor: 0xbab6c0, + selection_bg: 0x525053, + selection_fg: 0xf7f1ff, + accent: 0x5ad4e6, + chrome_bg: 0x525053, + chrome_fg: 0xf7f1ff, + chrome_active_bg: 0x6a696b, + border: 0x606060, + popup_bg: 0x363537, + ansi: [ + 0x3f3f3f, 0xfc618d, 0x7bd88f, 0xfce566, 0x5ad4e6, 0x948ae3, 0xfd9353, 0xf7f1ff, + 0x69676c, 0xfd8aab, 0x9de2ac, 0xfdec8e, 0x85dfed, 0xa198e6, 0xfeaf80, 0xfaf6ff, + ], + }, + ), + ( + "monokai_soda", + Theme { + dark: true, + background: 0x191919, + foreground: 0xcfcfc2, + cursor: 0xcfcfc2, + selection_bg: 0x444444, + selection_fg: 0xcfcfc2, + accent: 0x66d9ef, + chrome_bg: 0x444444, + chrome_fg: 0xc7c7c7, + chrome_active_bg: 0x5e5e5e, + border: 0x595959, + popup_bg: 0x444444, + ansi: [ + 0x222222, 0xf92a72, 0xa6e22e, 0xe6db74, 0x66d9ef, 0xae81ff, 0xfd971f, 0xcfcfc2, + 0x75715e, 0xfb6197, 0xbdea64, 0xede498, 0x8ee3f3, 0xb890ff, 0xfeb259, 0xe0e0d7, + ], + }, + ), + ( + "naysayer", + Theme { + dark: true, + background: 0x062329, + foreground: 0xd1b897, + cursor: 0xffffff, + selection_bg: 0x0000ff, + selection_fg: 0xd1b897, + accent: 0xd1b897, + chrome_bg: 0xd1b897, + chrome_fg: 0x062329, + chrome_active_bg: 0xb49e82, + border: 0x4c6165, + popup_bg: 0x062329, + ansi: [ + 0x264045, 0xf92672, 0xa6e22e, 0xe6db74, 0x66d9ef, 0xfd5ff0, 0xa1efe4, 0xffffff, + 0x44b340, 0xfb5e97, 0xbdea64, 0xede498, 0x8ee3f3, 0xfe89f4, 0xacf1e7, 0xe1d1bb, + ], + }, + ), + ( + "new_moon", + Theme { + dark: true, + background: 0x2d2d2d, + foreground: 0xd4d4d4, + cursor: 0xa6a6a6, + selection_bg: 0x264f78, + selection_fg: 0xd4d4d4, + accent: 0x76d4d6, + chrome_bg: 0x007acc, + chrome_fg: 0xffffff, + chrome_active_bg: 0x0069af, + border: 0x4e4e4e, + popup_bg: 0x252526, + ansi: [ + 0x484848, 0xf2777a, 0x92d192, 0xffd479, 0x6ab0f3, 0xe1a6f2, 0x76d4d6, 0xd4d4d4, + 0x777c85, 0xf4878a, 0xaeddae, 0xffeea6, 0x91c5f6, 0xe5b1f4, 0x9adfe1, 0xe3e3e3, + ], + }, + ), + ( + "night_owl", + Theme { + dark: true, + background: 0x011627, + foreground: 0xd6deeb, + cursor: 0xecc48d, + selection_bg: 0x2d2c5d, + selection_fg: 0xd6deeb, + accent: 0xecc48d, + chrome_bg: 0x112630, + chrome_fg: 0xeeeeee, + chrome_active_bg: 0x32444d, + border: 0x4e555b, + popup_bg: 0x112630, + ansi: [ + 0x223443, 0xff5874, 0xaddb67, 0xecc48d, 0x82aaff, 0xc792ea, 0x7fdbca, 0xd6deeb, + 0x637777, 0xff8398, 0xc2e48f, 0xeecb9b, 0x91b4ff, 0xce9fed, 0xa0e4d8, 0xe4eaf2, + ], + }, + ), + ( + "nightfox", + Theme { + dark: true, + background: 0x192330, + foreground: 0xcdcecf, + cursor: 0xcdcecf, + selection_bg: 0x3c5372, + selection_fg: 0xcdcecf, + accent: 0xdbc074, + chrome_bg: 0x131a24, + chrome_fg: 0xaeafb0, + chrome_active_bg: 0x343a43, + border: 0x151d28, + popup_bg: 0x131a24, + ansi: [ + 0x393b44, 0xc94f6d, 0x81b29a, 0xdbc074, 0x719cd6, 0x9d79d6, 0x63cdcf, 0xdfdfe0, + 0x738091, 0xd77d93, 0xa2c6b4, 0xe0c989, 0x86abdc, 0xb69ce1, 0x7ad4d6, 0xdfdfe0, + ], + }, + ), + ( + "noctis", + Theme { + dark: true, + background: 0x00262a, + foreground: 0xb1cace, + cursor: 0x87efff, + selection_bg: 0x0d6772, + selection_fg: 0xb1cace, + accent: 0x87efff, + chrome_bg: 0x0d6772, + chrome_fg: 0x48e9a7, + chrome_active_bg: 0x2f7c86, + border: 0x053338, + popup_bg: 0x073a40, + ansi: [ + 0x214246, 0xe34e1b, 0x48e9a7, 0xffd800, 0x918cff, 0xdf769b, 0x87efff, 0xb1cace, + 0x5b858b, 0xffa864, 0x48e9a7, 0xffe242, 0x87efff, 0xe79ab5, 0x95f1ff, 0xccdddf, + ], + }, + ), + ( + "noctis_bordo", + Theme { + dark: true, + background: 0x322a2d, + foreground: 0xcbbec2, + cursor: 0xcbbec2, + selection_bg: 0x997582, + selection_fg: 0xf0eaec, + accent: 0xdf769b, + chrome_bg: 0x2c2528, + chrome_fg: 0x997582, + chrome_active_bg: 0x4a4446, + border: 0x6b6668, + popup_bg: 0x2c2528, + ansi: [ + 0x4d4648, 0xdf769b, 0x49e9a6, 0xd5971a, 0xb0b0ff, 0xba8baf, 0x16a3b6, 0xcbbec2, + 0x888385, 0xe79ab5, 0x78efbd, 0xe0b256, 0xb9b9ff, 0xcca9c4, 0x53bbc9, 0xddd5d7, + ], + }, + ), + ( + "nord", + Theme { + dark: true, + background: 0x2e3440, + foreground: 0xd8dee9, + cursor: 0xd8dee9, + selection_bg: 0x4c566a, + selection_fg: 0xd8dee9, + accent: 0x8fbcbb, + chrome_bg: 0x3b4252, + chrome_fg: 0xc4c6cb, + chrome_active_bg: 0x565c6a, + border: 0x363d4c, + popup_bg: 0x3b4252, + ansi: [ + 0x494e59, 0xbf616a, 0xa3be8c, 0xebcb8b, 0x5e81ac, 0xb48ead, 0x8fbcbb, 0xd8dee9, + 0x616e88, 0xd08770, 0xbbcfaa, 0xedd199, 0x81a1c1, 0xc8abc2, 0xaccdcd, 0xe6eaf1, + ], + }, + ), + ( + "nord-night", + Theme { + dark: true, + background: 0x252933, + foreground: 0xc0c5cf, + cursor: 0xc0c5cf, + selection_bg: 0x4c566a, + selection_fg: 0xc0c5cf, + accent: 0x8fbcbb, + chrome_bg: 0x3b4252, + chrome_fg: 0xc4c6cb, + chrome_active_bg: 0x565c6a, + border: 0x333947, + popup_bg: 0x3b4252, + ansi: [ + 0x41454e, 0xbf616a, 0xa3be8c, 0xebcb8b, 0x5e81ac, 0xb48ead, 0x8fbcbb, 0xc0c5cf, + 0x616e88, 0xd08770, 0xbbcfaa, 0xedd199, 0x81a1c1, 0xc8abc2, 0xaccdcd, 0xd6d9e0, + ], + }, + ), + ( + "nord_light", + Theme { + dark: false, + background: 0xeceff4, + foreground: 0x2e3440, + cursor: 0x5e81ac, + selection_bg: 0x8fbcbb, + selection_fg: 0x2e3440, + accent: 0x5e81ac, + chrome_bg: 0xd8dee9, + chrome_fg: 0x2e3440, + chrome_active_bg: 0xbabfc8, + border: 0xaaacb0, + popup_bg: 0xd8dee9, + ansi: [ + 0x232730, 0xbf616a, 0x5e81ac, 0xd08770, 0x4c566a, 0xb48ead, 0x8fbcbb, 0xcdd0d4, + 0x848891, 0xd08a91, 0x81a1c1, 0xdca695, 0x81a1c1, 0xc8abc2, 0xaccdcd, 0xeceff4, + ], + }, + ), + ( + "nyxvamp-obsidian", + Theme { + dark: true, + background: 0x000a0f, + foreground: 0xc0c0ce, + cursor: 0xf28fad, + selection_bg: 0x2e2e30, + selection_fg: 0xc0c0ce, + accent: 0xf28fad, + chrome_bg: 0x1e1e20, + chrome_fg: 0xc0c0ce, + chrome_active_bg: 0x3e3e3f, + border: 0x474f52, + popup_bg: 0x0e0e10, + ansi: [ + 0x212a2e, 0xd78284, 0x8fbf8f, 0xd5b880, 0x7a9ccc, 0xf5c2e7, 0x7fafd7, 0xc0c0ce, + 0x5e5a76, 0xf28fad, 0xacd0ac, 0xe0caa1, 0x9db6d9, 0xf6c9ea, 0xa0c4e1, 0xd6d6df, + ], + }, + ), + ( + "nyxvamp-radiance", + Theme { + dark: false, + background: 0xf7f7ff, + foreground: 0x1e1e2e, + cursor: 0x9655ff, + selection_bg: 0xfef5bc, + selection_fg: 0x1e1e2e, + accent: 0x9655ff, + chrome_bg: 0xe8e8f0, + chrome_fg: 0x1e1e2e, + chrome_active_bg: 0xc8c8ce, + border: 0xb2b2b8, + popup_bg: 0xe8e8f0, + ansi: [ + 0x171723, 0xe78284, 0x6e6a86, 0xf28fad, 0x8caaee, 0x9655ff, 0x005f87, 0xd7d7de, + 0x6e6a86, 0xea9193, 0x9491a5, 0xf49cb7, 0x9ab4f0, 0xb181ff, 0x4289a6, 0xf7f7ff, + ], + }, + ), + ( + "nyxvamp-veil", + Theme { + dark: true, + background: 0x1e1e2e, + foreground: 0xd9e0ee, + cursor: 0xf5c2e7, + selection_bg: 0x494d64, + selection_fg: 0xd9e0ee, + accent: 0xf5c2e7, + chrome_bg: 0x302d41, + chrome_fg: 0xd9e0ee, + chrome_active_bg: 0x4d4a5c, + border: 0x5d5d69, + popup_bg: 0x1e1e2e, + ansi: [ + 0x3b3b49, 0xe78284, 0xabe9b3, 0xe5c890, 0x8caaee, 0xddb6f2, 0x96cdfb, 0xd9e0ee, + 0x6e6a86, 0xf8bd96, 0xb5ecbc, 0xe8cf9d, 0x9ab4f0, 0xe1bff4, 0xa3d3fb, 0xe6ebf4, + ], + }, + ), + ( + "onedark", + Theme { + dark: true, + background: 0x282c34, + foreground: 0xabb2bf, + cursor: 0xabb2bf, + selection_bg: 0x3e4452, + selection_fg: 0xabb2bf, + accent: 0x61afef, + chrome_bg: 0x2c323c, + chrome_fg: 0xabb2bf, + chrome_active_bg: 0x4a4f57, + border: 0x363c48, + popup_bg: 0x3e4452, + ansi: [ + 0x282c34, 0xe06c75, 0x98c379, 0xe5c07b, 0x61afef, 0xc678dd, 0x56b6c2, 0xabb2bf, + 0x2c323c, 0xe89299, 0xb3d39c, 0xecd09d, 0x8ac4f3, 0xd59be6, 0x82c9d2, 0xc8cdd5, + ], + }, + ), + ( + "onedarker", + Theme { + dark: true, + background: 0x16181a, + foreground: 0xabb2bf, + cursor: 0xabb2bf, + selection_bg: 0x252d30, + selection_fg: 0xabb2bf, + accent: 0x519fdf, + chrome_bg: 0x2c323c, + chrome_fg: 0xabb2bf, + chrome_active_bg: 0x4a4f57, + border: 0x202628, + popup_bg: 0x252d30, + ansi: [ + 0x16181a, 0xd05c65, 0x7da869, 0xd5b06b, 0x519fdf, 0xb668cd, 0x46a6b2, 0xabb2bf, + 0x2c323c, 0xdc868d, 0x9fbf90, 0xe0c591, 0x7eb8e7, 0xc98fda, 0x76bdc6, 0xc8cdd5, + ], + }, + ), + ( + "onelight", + Theme { + dark: false, + background: 0xfafafa, + foreground: 0x282c34, + cursor: 0x282c34, + selection_bg: 0xe0e0e0, + selection_fg: 0x282c34, + accent: 0x0061ff, + chrome_bg: 0xe0e0e0, + chrome_fg: 0x282c34, + chrome_active_bg: 0xc1c1c1, + border: 0xbebebe, + popup_bg: 0xeeeeee, + ansi: [ + 0x282c34, 0xd50000, 0x24a443, 0xff6f00, 0x0061ff, 0xb500a9, 0x0086c1, 0xfafafa, + 0x5c6370, 0xe04242, 0x5dbc74, 0xff9442, 0x0091ea, 0xc842bf, 0x0091ea, 0xfafafa, + ], + }, + ), + ( + "papercolor-dark", + Theme { + dark: true, + background: 0x1c1c1c, + foreground: 0xd0d0d0, + cursor: 0xd0d0d0, + selection_bg: 0x8787af, + selection_fg: 0x000000, + accent: 0xd0d0d0, + chrome_bg: 0x5f8787, + chrome_fg: 0x1c1c1c, + chrome_active_bg: 0x527474, + border: 0x486262, + popup_bg: 0x303030, + ansi: [ + 0x1c1c1c, 0xaf005f, 0x5faf00, 0xd7af5f, 0x5fafd7, 0x808080, 0xd7875f, 0xd0d0d0, + 0x585858, 0x5faf5f, 0xafd700, 0xaf87d7, 0xffaf00, 0xff5faf, 0x00afaf, 0x5f8787, + ], + }, + ), + ( + "papercolor-light", + Theme { + dark: false, + background: 0xeeeeee, + foreground: 0x444444, + cursor: 0x444444, + selection_bg: 0x0087af, + selection_fg: 0xeeeeee, + accent: 0x444444, + chrome_bg: 0x005f87, + chrome_fg: 0xe4e4e4, + chrome_active_bg: 0x247598, + border: 0x5391ab, + popup_bg: 0xd0d0d0, + ansi: [ + 0xeeeeee, 0xd70000, 0x008700, 0x5f8700, 0x0087af, 0x878787, 0x005f87, 0x444444, + 0xbcbcbc, 0xd70000, 0xd70087, 0x8700af, 0xd75f00, 0xd75f00, 0x4c7a4d, 0x005faf, + ], + }, + ), + ( + "peachpuff", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0xe5e5e5, + selection_bg: 0x383838, + selection_fg: 0x7f7f7f, + accent: 0x6666f5, + chrome_bg: 0x00ffff, + chrome_fg: 0x000000, + chrome_active_bg: 0x00dbdb, + border: 0x474747, + popup_bg: 0x000000, + ansi: [ + 0x212121, 0xe16666, 0x66e166, 0xe1e166, 0x6666f5, 0xe166e1, 0x66e1e1, 0xffffff, + 0x00ff00, 0xe98e8e, 0x8ee98e, 0xe9e98e, 0x8e8ef8, 0xe98ee9, 0x8ee9e9, 0xffffff, + ], + }, + ), + ( + "penumbra+", + Theme { + dark: true, + background: 0x24272b, + foreground: 0x9e9e9e, + cursor: 0x9e9e9e, + selection_bg: 0x3e4044, + selection_fg: 0x9e9e9e, + accent: 0x9e9e9e, + chrome_bg: 0x9e9e9e, + chrome_fg: 0x24272b, + chrome_active_bg: 0x888888, + border: 0x737476, + popup_bg: 0x181b1f, + ansi: [ + 0x404347, 0xdf7f78, 0x50b584, 0x9ca748, 0x61a3e6, 0xd080b6, 0x00b3c2, 0x9e9e9e, + 0x636363, 0xe7a09b, 0x7ec8a4, 0xb6be78, 0x8abbed, 0xdca1c9, 0x42c7d2, 0xc0c0c0, + ], + }, + ), + ( + "poimandres", + Theme { + dark: true, + background: 0x1b1e28, + foreground: 0xa6accd, + cursor: 0xa6accd, + selection_bg: 0x30354a, + selection_fg: 0xa6accd, + accent: 0xadd7ff, + chrome_bg: 0x30354a, + chrome_fg: 0xe4f0fb, + chrome_active_bg: 0x4d5163, + border: 0x757a93, + popup_bg: 0x20232d, + ansi: [ + 0x000000, 0xf087bd, 0x5fb3a1, 0xfffac2, 0xadd7ff, 0xd0679d, 0x5de4c7, 0xffffff, + 0x6c7494, 0xf295c5, 0x89c7b9, 0xfffbc9, 0xb7dcff, 0xdc8fb6, 0x87ebd6, 0xc5c9df, + ], + }, + ), + ( + "poimandres_storm", + Theme { + dark: true, + background: 0x252b37, + foreground: 0xa6accd, + cursor: 0xa6accd, + selection_bg: 0x3d455c, + selection_fg: 0xa6accd, + accent: 0xadd7ff, + chrome_bg: 0x3d455c, + chrome_fg: 0xe4f0fb, + chrome_active_bg: 0x585f73, + border: 0x797f99, + popup_bg: 0x2a303c, + ansi: [ + 0x101010, 0xf087bd, 0x5fb3a1, 0xfffac2, 0xadd7ff, 0xd0679d, 0x5de4c7, 0xffffff, + 0x818cae, 0xf295c5, 0x89c7b9, 0xfffbc9, 0xb7dcff, 0xdc8fb6, 0x87ebd6, 0xc5c9df, + ], + }, + ), + ( + "pop-dark", + Theme { + dark: true, + background: 0x3e3b39, + foreground: 0xdedede, + cursor: 0xfdaf1f, + selection_bg: 0x4aaad6, + selection_fg: 0xffffff, + accent: 0xfdaf1f, + chrome_bg: 0x4c4643, + chrome_fg: 0xdedede, + chrome_active_bg: 0x65605d, + border: 0x322f2e, + popup_bg: 0x2b2928, + ansi: [ + 0x000000, 0xff2200, 0x4dd44d, 0xff9500, 0x4d4ddd, 0xdd4ddd, 0x6dd2fa, 0xffffff, + 0xa0b4a7, 0xffad34, 0x7bdf7b, 0xfdaf1f, 0x7b7be6, 0xe67be6, 0x8deef9, 0xeaeaea, + ], + }, + ), + ( + "rasmus", + Theme { + dark: true, + background: 0x1a1a19, + foreground: 0xd1d1d1, + cursor: 0x3a3a39, + selection_bg: 0x323231, + selection_fg: 0xd1d1d1, + accent: 0xffdeaa, + chrome_bg: 0x2a2a29, + chrome_fg: 0xb6b6b5, + chrome_active_bg: 0x484847, + border: 0x242423, + popup_bg: 0x222221, + ansi: [ + 0x333332, 0xff968c, 0x61957f, 0xffc591, 0x8db4d4, 0xde9bc8, 0x7bb099, 0xd1d1d1, + 0x4c4c4b, 0xffafa5, 0x7aae98, 0xffdeaa, 0xa6cded, 0xf7b4e1, 0x94c9b2, 0xeaeaea, + ], + }, + ), + ( + "rose_pine", + Theme { + dark: true, + background: 0x191724, + foreground: 0xe0def4, + cursor: 0x6e6a86, + selection_bg: 0x403d52, + selection_fg: 0xe0def4, + accent: 0xe0def4, + chrome_bg: 0x1f1d2e, + chrome_fg: 0x908caa, + chrome_active_bg: 0x3e3d4b, + border: 0x211f32, + popup_bg: 0x1f1d2e, + ansi: [ + 0x373540, 0xeb6f92, 0x31748f, 0xf6c177, 0x908caa, 0xc4a7e7, 0x9ccfd8, 0xe0def4, + 0x6e6a86, 0xf094ae, 0x6798ac, 0xf7c887, 0xe0def4, 0xcbb2ea, 0xa8d5dd, 0xebeaf8, + ], + }, + ), + ( + "rose_pine_dawn", + Theme { + dark: false, + background: 0xfaf4ed, + foreground: 0x575279, + cursor: 0x9893a5, + selection_bg: 0xdfdad9, + selection_fg: 0x575279, + accent: 0x797593, + chrome_bg: 0xfffaf3, + chrome_fg: 0x797593, + chrome_active_bg: 0xdbd7d1, + border: 0xf5ede5, + popup_bg: 0xfffaf3, + ansi: [ + 0x413e5b, 0xd7827e, 0x56949f, 0xea9d34, 0x797593, 0x907aa9, 0x286983, 0xdad4ce, + 0x9893a5, 0xe1a3a0, 0x82b0b8, 0xefb669, 0x9c99af, 0xad9dbf, 0x6090a3, 0xfaf4ed, + ], + }, + ), + ( + "rose_pine_moon", + Theme { + dark: true, + background: 0x232136, + foreground: 0xe0def4, + cursor: 0x6e6a86, + selection_bg: 0x44415a, + selection_fg: 0xe0def4, + accent: 0xe0def4, + chrome_bg: 0x2a273f, + chrome_fg: 0x908caa, + chrome_active_bg: 0x48455a, + border: 0x312e48, + popup_bg: 0x2a273f, + ansi: [ + 0x403e50, 0xeb6f92, 0x3e8fb0, 0xf6c177, 0x908caa, 0xc4a7e7, 0x9ccfd8, 0xe0def4, + 0x6e6a86, 0xf094ae, 0x70acc5, 0xf7c887, 0xe0def4, 0xcbb2ea, 0xa8d5dd, 0xebeaf8, + ], + }, + ), + ( + "seoul256-dark", + Theme { + dark: true, + background: 0x3a3a3a, + foreground: 0xd0d0d0, + cursor: 0xd0d0d0, + selection_bg: 0x005f5f, + selection_fg: 0xd0d0d0, + accent: 0xaf5f5f, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0x9c9c9c, + popup_bg: 0x303030, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xff5f00, 0xc4e189, 0xffaf87, 0xafd7d7, 0xd75f87, 0xa6dbff, 0xe0e0e0, + ], + }, + ), + ( + "seoul256-dark-hard", + Theme { + dark: true, + background: 0x1c1c1c, + foreground: 0xd0d0d0, + cursor: 0xd0d0d0, + selection_bg: 0x005f5f, + selection_fg: 0xd0d0d0, + accent: 0xaf5f5f, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0x919191, + popup_bg: 0x121212, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xff5f00, 0xc4e189, 0xffaf87, 0xafd7d7, 0xd75f87, 0xa6dbff, 0xe0e0e0, + ], + }, + ), + ( + "seoul256-dark-soft", + Theme { + dark: true, + background: 0x4e4e4e, + foreground: 0xd0d0d0, + cursor: 0xd0d0d0, + selection_bg: 0x005f5f, + selection_fg: 0xd0d0d0, + accent: 0xd0d0d0, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0xa3a3a3, + popup_bg: 0x444444, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xff5f00, 0xc4e189, 0xffaf87, 0xafd7d7, 0xd75f87, 0xa6dbff, 0xe0e0e0, + ], + }, + ), + ( + "seoul256-light", + Theme { + dark: false, + background: 0xdadada, + foreground: 0x14161b, + cursor: 0x3a3a3a, + selection_bg: 0xafd7d7, + selection_fg: 0x14161b, + accent: 0xaf5f5f, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0xd4d4d4, + popup_bg: 0xd0d0d0, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xff5f00, 0xc4e189, 0xe2c489, 0xa6c4c4, 0xd75f87, 0xa6e1e1, 0xdadada, + ], + }, + ), + ( + "seoul256-light-hard", + Theme { + dark: false, + background: 0xeeeeee, + foreground: 0x14161b, + cursor: 0x3a3a3a, + selection_bg: 0xafd7d7, + selection_fg: 0x14161b, + accent: 0xaf5f5f, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0xdbdbdb, + popup_bg: 0xe4e4e4, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xff5f00, 0xc4e189, 0xe2c489, 0xa6c4c4, 0xd75f87, 0xa6e1e1, 0xeeeeee, + ], + }, + ), + ( + "seoul256-light-soft", + Theme { + dark: false, + background: 0xd0d0d0, + foreground: 0x14161b, + cursor: 0x3a3a3a, + selection_bg: 0xafd7d7, + selection_fg: 0x14161b, + accent: 0xaf5f5f, + chrome_bg: 0xd7d7af, + chrome_fg: 0x875f5f, + chrome_active_bg: 0xb9b997, + border: 0xd0d0d0, + popup_bg: 0xc6c6c6, + ansi: [ + 0x000000, 0xd70000, 0xafd75f, 0xd8af5f, 0x87afaf, 0xaf5f5f, 0x87d7d7, 0xd0d0d0, + 0x5f875f, 0xe14242, 0xc4e189, 0xe2c489, 0xa6c4c4, 0xd75f87, 0xa6e1e1, 0xd0d0d0, + ], + }, + ), + ( + "serika-dark", + Theme { + dark: true, + background: 0x323437, + foreground: 0xd1d0c5, + cursor: 0xd1d0c5, + selection_bg: 0xe2b714, + selection_fg: 0x221b03, + accent: 0xadc9db, + chrome_bg: 0x55585e, + chrome_fg: 0xe1e1e3, + chrome_active_bg: 0x6d6f75, + border: 0x414447, + popup_bg: 0x494c50, + ansi: [ + 0x4d4e51, 0xe29da7, 0xbcd5a8, 0xe2b714, 0xadc9db, 0xbe9ec9, 0xb9c2c6, 0xd1d0c5, + 0x646669, 0xe5a9b2, 0xc4dab2, 0xdd8a3c, 0xb7cfdf, 0xc6aacf, 0xc1c9cd, 0xe1e0d9, + ], + }, + ), + ( + "serika-light", + Theme { + dark: false, + background: 0xd1d0c5, + foreground: 0x323437, + cursor: 0xaaaeb3, + selection_bg: 0xaaaeb3, + selection_fg: 0x323437, + accent: 0x323437, + chrome_bg: 0x797e86, + chrome_fg: 0xe1e1e3, + chrome_active_bg: 0x686c73, + border: 0x989b9c, + popup_bg: 0x797e86, + ansi: [ + 0x262729, 0x621d28, 0x3d5128, 0x9a7d0e, 0x3f5673, 0x5a4066, 0x6a89af, 0xb6b5ab, + 0x646669, 0x7e2a33, 0x6f7e60, 0xb49f4d, 0x718297, 0x85728e, 0x91a8c4, 0xd1d0c5, + ], + }, + ), + ( + "sidra", + Theme { + dark: true, + background: 0x1f1f21, + foreground: 0xd3d3d3, + cursor: 0xbd93f9, + selection_bg: 0x71797e, + selection_fg: 0xffffff, + accent: 0xbd93f9, + chrome_bg: 0x303030, + chrome_fg: 0xd3d3d3, + chrome_active_bg: 0x4d4d4d, + border: 0xa89a78, + popup_bg: 0x3b3b3d, + ansi: [ + 0x3c3c3e, 0xb80000, 0xa8ffb4, 0xf1fa8c, 0x3876bf, 0xc90076, 0x8be9fd, 0xd3d3d3, + 0xd3d3d3, 0xd7005f, 0xb2ffbd, 0xf3fb9a, 0x6c9ad0, 0xff69b4, 0x99ecfd, 0xe2e2e2, + ], + }, + ), + ( + "snazzy", + Theme { + dark: true, + background: 0x282a36, + foreground: 0xeff0eb, + cursor: 0x9aedfe, + selection_bg: 0x800049, + selection_fg: 0xeff0eb, + accent: 0x5af78e, + chrome_bg: 0x21222c, + chrome_fg: 0xeff0eb, + chrome_active_bg: 0x40414a, + border: 0xa9abac, + popup_bg: 0x21222c, + ansi: [ + 0x444650, 0xff5c57, 0x5af78e, 0xf3f99d, 0x57c7ff, 0xff6ac1, 0x9aedfe, 0xeff0eb, + 0xa39e9b, 0xf97c7c, 0x85f9ab, 0xf4faa9, 0x83d6ff, 0xff7cc8, 0xa6effe, 0xf5f5f2, + ], + }, + ), + ( + "solarized_dark", + Theme { + dark: true, + background: 0x002b36, + foreground: 0x93a1a1, + cursor: 0x93a1a1, + selection_bg: 0x2c4f59, + selection_fg: 0x93a1a1, + accent: 0x93a1a1, + chrome_bg: 0x839496, + chrome_fg: 0x002b36, + chrome_active_bg: 0x717f81, + border: 0xa4afa6, + popup_bg: 0x073642, + ansi: [ + 0x214750, 0xdc322f, 0x859900, 0xb58900, 0x268bd2, 0xd33682, 0x2aa198, 0x93a1a1, + 0x586e75, 0xe56765, 0xa5b442, 0xcb4b16, 0x5ea9de, 0xde6aa3, 0x61b9b3, 0xb9c2c2, + ], + }, + ), + ( + "solarized_light", + Theme { + dark: false, + background: 0xfdf6e3, + foreground: 0x586e75, + cursor: 0x586e75, + selection_bg: 0xc5c8bd, + selection_fg: 0x586e75, + accent: 0x586e75, + chrome_bg: 0x657b83, + chrome_fg: 0xfdf6e3, + chrome_active_bg: 0x576a71, + border: 0x597273, + popup_bg: 0xeee8d5, + ansi: [ + 0x425358, 0xdc322f, 0x859900, 0xb58900, 0x268bd2, 0xd33682, 0x2aa198, 0xdcd6c5, + 0x93a1a1, 0xe56765, 0xa5b442, 0xcb4b16, 0x5ea9de, 0xde6aa3, 0x61b9b3, 0xfdf6e3, + ], + }, + ), + ( + "sonokai", + Theme { + dark: true, + background: 0x2c2e34, + foreground: 0xe2e2e3, + cursor: 0xe2e2e3, + selection_bg: 0x414550, + selection_fg: 0xe2e2e3, + accent: 0x76cce0, + chrome_bg: 0x3b3e48, + chrome_fg: 0xe2e2e3, + chrome_active_bg: 0x565962, + border: 0x626670, + popup_bg: 0x363944, + ansi: [ + 0x181819, 0xfc5d7c, 0x9ed072, 0xe7c664, 0x76cce0, 0xb39df3, 0x8dd0b6, 0xe2e2e3, + 0x7f8490, 0xfd879e, 0xb7dc97, 0xedd58c, 0x85d3f2, 0xbca9f4, 0xabdcc9, 0xececed, + ], + }, + ), + ( + "spacebones_light", + Theme { + dark: false, + background: 0xfbf8ef, + foreground: 0x655370, + cursor: 0x655370, + selection_bg: 0xd3d3e7, + selection_fg: 0x655370, + accent: 0x002db3, + chrome_bg: 0xd1dcdf, + chrome_fg: 0x655370, + chrome_active_bg: 0xb4bdc0, + border: 0xb5b3ac, + popup_bg: 0xefeae9, + ansi: [ + 0x4c3e54, 0xe0211d, 0x67b11d, 0xb1951d, 0x002db3, 0x6c3163, 0x21b8c7, 0xdad8d0, + 0xa49da5, 0xe85b58, 0x8fc558, 0xda8b55, 0x3a81c3, 0xa31db1, 0x5bcad6, 0xfbf8ef, + ], + }, + ), + ( + "starlight", + Theme { + dark: true, + background: 0x242424, + foreground: 0xe6e6e6, + cursor: 0xe9e836, + selection_bg: 0x24acd4, + selection_fg: 0xffffff, + accent: 0xe9e836, + chrome_bg: 0x353535, + chrome_fg: 0xe6e6e6, + chrome_active_bg: 0x515151, + border: 0x2f2f2f, + popup_bg: 0x353535, + ansi: [ + 0x1e1e1e, 0xff4d51, 0x35d450, 0xe9e836, 0x5dc5f8, 0xfeabf2, 0x24dfc4, 0xffffff, + 0x929292, 0xff7b7e, 0x6adf7e, 0xefee6a, 0x87d4fa, 0xfeb5f4, 0x5de7d3, 0xefefef, + ], + }, + ), + ( + "sunset", + Theme { + dark: true, + background: 0x111111, + foreground: 0xeeeeee, + cursor: 0x777777, + selection_bg: 0x333333, + selection_fg: 0xeeeeee, + accent: 0xee1111, + chrome_bg: 0x222222, + chrome_fg: 0xbdbdbd, + chrome_active_bg: 0x414141, + border: 0x1c1c1c, + popup_bg: 0x111111, + ansi: [ + 0x303030, 0xee1111, 0x66cc33, 0xee7711, 0xee7777, 0x775599, 0x77aaaa, 0xeeeeee, + 0x777777, 0xf24f4f, 0x8ed968, 0xf29a4f, 0xf29a9a, 0x9a81b4, 0x9ac0c0, 0xf4f4f4, + ], + }, + ), + ( + "term16_dark", + Theme { + dark: true, + background: 0x000000, + foreground: 0xe5e5e5, + cursor: 0xe5e5e5, + selection_bg: 0x7f7f7f, + selection_fg: 0xe5e5e5, + accent: 0xffff00, + chrome_bg: 0x7f7f7f, + chrome_fg: 0xe5e5e5, + chrome_active_bg: 0x6d6d6d, + border: 0x535353, + popup_bg: 0x000000, + ansi: [ + 0x212121, 0xd75c5c, 0x5cd75c, 0xd7d75c, 0x5c5cea, 0xd75cd7, 0x5cd7d7, 0xe5e5e5, + 0xe5e5e5, 0xe18686, 0x86e186, 0xe1e186, 0x8686ef, 0xe186e1, 0x86e1e1, 0xeeeeee, + ], + }, + ), + ( + "term16_light", + Theme { + dark: false, + background: 0xffffff, + foreground: 0x000000, + cursor: 0x000000, + selection_bg: 0xe5e5e5, + selection_fg: 0x000000, + accent: 0x00008f, + chrome_bg: 0xe8e8e8, + chrome_fg: 0x464646, + chrome_active_bg: 0xc8c8c8, + border: 0xacacac, + popup_bg: 0xffffff, + ansi: [ + 0x000000, 0x7b0000, 0x007b00, 0x7b7b00, 0x00008f, 0x7b007b, 0x007b7b, 0xdedede, + 0x7f7f7f, 0xcd0000, 0x00cd00, 0x9d9d42, 0x0000ee, 0xcd00cd, 0x429d9d, 0xffffff, + ], + }, + ), + ( + "tokyonight", + Theme { + dark: true, + background: 0x1a1b26, + foreground: 0xc0caf5, + cursor: 0xc0caf5, + selection_bg: 0x283457, + selection_fg: 0xc0caf5, + accent: 0xff9e64, + chrome_bg: 0x16161e, + chrome_fg: 0xa9b1d6, + chrome_active_bg: 0x37373e, + border: 0x171821, + popup_bg: 0x16161e, + ansi: [ + 0x414868, 0xf7768e, 0x73daca, 0xe0af68, 0x7aa2f7, 0xbb9af7, 0x7dcfff, 0xc0caf5, + 0x565f89, 0xf8869c, 0x9ece6a, 0xff9e64, 0x8aadf8, 0xc3a6f8, 0xb4f9f8, 0xd6ddf9, + ], + }, + ), + ( + "tokyonight_day", + Theme { + dark: false, + background: 0xe1e2e7, + foreground: 0x3760bf, + cursor: 0x3760bf, + selection_bg: 0xc4c8da, + selection_fg: 0x3760bf, + accent: 0xb15c00, + chrome_bg: 0xe9e9ec, + chrome_fg: 0x6172b0, + chrome_active_bg: 0xc8c8cb, + border: 0xe6e7eb, + popup_bg: 0xe9e9ec, + ansi: [ + 0xa1a6c5, 0xf52a65, 0x387068, 0x8c6c3e, 0x2e7de9, 0x9854f1, 0x007197, 0xc4c5c9, + 0x848cb5, 0xf8618d, 0x587539, 0xaa9270, 0x649fef, 0xb380f5, 0x2e5857, 0xe1e2e7, + ], + }, + ), + ( + "tokyonight_moon", + Theme { + dark: true, + background: 0x222436, + foreground: 0xc8d3f5, + cursor: 0xc8d3f5, + selection_bg: 0x2f334d, + selection_fg: 0xc8d3f5, + accent: 0xff966c, + chrome_bg: 0x1e2030, + chrome_fg: 0x828bb8, + chrome_active_bg: 0x3e3f4d, + border: 0x1d1f2f, + popup_bg: 0x1e2030, + ansi: [ + 0x444a73, 0xff757f, 0x4fd6be, 0xffc777, 0x82aaff, 0xc099ff, 0x86e1fc, 0xc8d3f5, + 0x636da6, 0xff868e, 0xc3e88d, 0xffce87, 0x91b4ff, 0xc8a5ff, 0xb4f9f8, 0xdbe2f9, + ], + }, + ), + ( + "tokyonight_storm", + Theme { + dark: true, + background: 0x24283b, + foreground: 0xc0caf5, + cursor: 0xc0caf5, + selection_bg: 0x373d5a, + selection_fg: 0xc0caf5, + accent: 0xff9e64, + chrome_bg: 0x1f2335, + chrome_fg: 0xa9b1d6, + chrome_active_bg: 0x3e4251, + border: 0x1f2333, + popup_bg: 0x1f2335, + ansi: [ + 0x414868, 0xf7768e, 0x73daca, 0xe0af68, 0x7aa2f7, 0xbb9af7, 0x7dcfff, 0xc0caf5, + 0x565f89, 0xf8869c, 0x9ece6a, 0xff9e64, 0x8aadf8, 0xc3a6f8, 0xb4f9f8, 0xd6ddf9, + ], + }, + ), + ( + "ttox", + Theme { + dark: true, + background: 0x000000, + foreground: 0xffffff, + cursor: 0xe5e5e5, + selection_bg: 0x7f7f7f, + selection_fg: 0xffffff, + accent: 0x6666f5, + chrome_bg: 0x171717, + chrome_fg: 0xffffff, + chrome_active_bg: 0x373737, + border: 0x474747, + popup_bg: 0x000000, + ansi: [ + 0x212121, 0xe16666, 0x66e166, 0xe1e166, 0x6666f5, 0xe166e1, 0x66e1e1, 0xffffff, + 0x6b6b6b, 0xe98e8e, 0x8ee98e, 0xe9e98e, 0x8e8ef8, 0xe98ee9, 0x8ee9e9, 0xffffff, + ], + }, + ), + ( + "varua", + Theme { + dark: true, + background: 0x282828, + foreground: 0xdfbf8e, + cursor: 0xdfbf8e, + selection_bg: 0x3c3836, + selection_fg: 0xdfbf8e, + accent: 0xe69875, + chrome_bg: 0x32302f, + chrome_fg: 0xdfbf8e, + chrome_active_bg: 0x4f4d4c, + border: 0x6d6359, + popup_bg: 0x32302f, + ansi: [ + 0x444444, 0xe67e80, 0xa7c080, 0xdbbc7f, 0x7fbbb3, 0xd699b6, 0x83c092, 0xdfbf8e, + 0x928374, 0xeda0a1, 0xbed0a1, 0xe4cda0, 0xa0cdc7, 0xdba5bf, 0xa3d0ae, 0xead5b6, + ], + }, + ), + ( + "vesper", + Theme { + dark: true, + background: 0x101010, + foreground: 0xffffff, + cursor: 0xaeafad, + selection_bg: 0x666666, + selection_fg: 0xffffff, + accent: 0x99ffe4, + chrome_bg: 0x1c1c1c, + chrome_fg: 0xbbbbbb, + chrome_active_bg: 0x3c3c3c, + border: 0x535353, + popup_bg: 0x1c1c1c, + ansi: [ + 0x101010, 0xff8080, 0x99ffe4, 0xffc799, 0x99ffe4, 0xff8080, 0x99ffe4, 0xffffff, + 0x8b8b8b, 0xff8f8f, 0x99ffe4, 0xffcea5, 0xa5ffe7, 0xff8f8f, 0xa5ffe7, 0xffffff, + ], + }, + ), + ( + "vim_dark_high_contrast", + Theme { + dark: true, + background: 0x000000, + foreground: 0xc1c9d2, + cursor: 0x85d996, + selection_bg: 0x3e4043, + selection_fg: 0xc1c9d2, + accent: 0x7fd3ed, + chrome_bg: 0x602864, + chrome_fg: 0xf0b4e4, + chrome_active_bg: 0x76467a, + border: 0x1d2a4b, + popup_bg: 0x3e4043, + ansi: [ + 0x000000, 0xed5f74, 0x1ea672, 0xd97917, 0x688ef1, 0xc96ed0, 0x3a97d4, 0xe3e8ee, + 0x697386, 0xfbb5b2, 0x85d996, 0xefc078, 0x9fcdff, 0xf0b4e4, 0x7fd3ed, 0xffffff, + ], + }, + ), + ( + "vintage", + Theme { + dark: true, + background: 0x1f1f21, + foreground: 0xe5e5e5, + cursor: 0xe5e5e5, + selection_bg: 0x7f7f7f, + selection_fg: 0xffffff, + accent: 0xf1dca7, + chrome_bg: 0x7f7f7f, + chrome_fg: 0x000000, + chrome_active_bg: 0x6d6d6d, + border: 0xa89a78, + popup_bg: 0x3b3b3d, + ansi: [ + 0x3c3c3e, 0xb80000, 0x778e61, 0xf1dca7, 0x3876bf, 0xb577b0, 0xa5c4d4, 0xe5e5e5, + 0xe5e5e5, 0xca4242, 0x9b9b7a, 0xffcb69, 0x6c9ad0, 0xc89ac5, 0xb0cbd9, 0xeeeeee, + ], + }, + ), + ( + "voxed", + Theme { + dark: true, + background: 0x1f1f21, + foreground: 0xffffff, + cursor: 0x706b68, + selection_bg: 0x8c8681, + selection_fg: 0xffffff, + accent: 0x6f44f0, + chrome_bg: 0xb7afa8, + chrome_fg: 0x000000, + chrome_active_bg: 0x9d9790, + border: 0xb1b1b1, + popup_bg: 0x25262b, + ansi: [ + 0x3c3c3e, 0xff5964, 0x7ddf64, 0xffe74c, 0x6f44f0, 0xb784a3, 0x458588, 0xffffff, + 0x8c8681, 0xff848c, 0x9fe78c, 0xffed7b, 0x5c5cff, 0xcaa4bb, 0x75a5a7, 0xffffff, + ], + }, + ), + ( + "yellowed", + Theme { + dark: true, + background: 0x242424, + foreground: 0xffffff, + cursor: 0xffd900, + selection_bg: 0x3f3f3f, + selection_fg: 0xffffff, + accent: 0xffd900, + chrome_bg: 0x2a2a2a, + chrome_fg: 0xffffff, + chrome_active_bg: 0x484848, + border: 0xb2b2b2, + popup_bg: 0x202020, + ansi: [ + 0x404040, 0xff0000, 0x378b1d, 0xffd900, 0x008dff, 0xff80f4, 0x0092ff, 0xffffff, + 0x6b6b6b, 0xff4242, 0x00cd00, 0xffe342, 0x42abff, 0xff8ff5, 0x42aeff, 0xffffff, + ], + }, + ), + ( + "yo", + Theme { + dark: true, + background: 0x191919, + foreground: 0xb4b4b4, + cursor: 0xb4b4b4, + selection_bg: 0x313131, + selection_fg: 0xb4b4b4, + accent: 0x3b9eff, + chrome_bg: 0x2a2a2a, + chrome_fg: 0xb4b4b4, + chrome_active_bg: 0x484848, + border: 0x383838, + popup_bg: 0x2a2a2a, + ansi: [ + 0x373737, 0xec5d5e, 0x33b074, 0xff801f, 0x3b9eff, 0x9a5cd0, 0xae8c7e, 0xb4b4b4, + 0x3b9eff, 0xf18788, 0x68c598, 0xffa159, 0x6eb7ff, 0xb486dc, 0xc3aaa0, 0xcecece, + ], + }, + ), + ( + "yo_berry", + Theme { + dark: true, + background: 0x1a191b, + foreground: 0xb5b2bc, + cursor: 0xb5b2bc, + selection_bg: 0x323035, + selection_fg: 0xb5b2bc, + accent: 0x9eb1ff, + chrome_bg: 0x2b292d, + chrome_fg: 0xb5b2bc, + chrome_active_bg: 0x49474a, + border: 0x39373c, + popup_bg: 0x2b292d, + ansi: [ + 0x383739, 0xee518a, 0x3b9eff, 0xffff57, 0x9eb1ff, 0xb658c4, 0x0eb39e, 0xb5b2bc, + 0x3b9eff, 0xf27ea8, 0x6eb7ff, 0xffff83, 0xaabaff, 0xc983d3, 0x4dc7b7, 0xcfcdd3, + ], + }, + ), + ( + "yo_light", + Theme { + dark: false, + background: 0xf9f9f9, + foreground: 0x646464, + cursor: 0x646464, + selection_bg: 0xe0e0e0, + selection_fg: 0x646464, + accent: 0x957468, + chrome_bg: 0xe8e8e8, + chrome_fg: 0x646464, + chrome_active_bg: 0xc8c8c8, + border: 0xdddddd, + popup_bg: 0xe8e8e8, + ansi: [ + 0x4b4b4b, 0xdc3e42, 0x2b9a66, 0xef5f00, 0x957468, 0x8347b9, 0x0588f0, 0xd9d9d9, + 0x0588f0, 0xe57073, 0x62b48e, 0xf38942, 0xb1988f, 0xa377cb, 0x46a7f4, 0xf9f9f9, + ], + }, + ), + ( + "zed_onedark", + Theme { + dark: true, + background: 0x282c33, + foreground: 0xc8ccd4, + cursor: 0xc8ccd4, + selection_bg: 0x293b5b, + selection_fg: 0xc8ccd4, + accent: 0x73ade9, + chrome_bg: 0x2f343e, + chrome_fg: 0xc8ccd4, + chrome_active_bg: 0x4c5059, + border: 0x2d313a, + popup_bg: 0x2f343e, + ansi: [ + 0x282c33, 0xd07277, 0xa1c181, 0xdfc184, 0x73ade9, 0xb477cf, 0x6eb4bf, 0xc8ccd4, + 0x5d636f, 0xdc979a, 0xb9d1a2, 0xe7d1a4, 0x97c2ef, 0xc89adb, 0x94c8d0, 0xdbdee3, + ], + }, + ), + ( + "zed_onelight", + Theme { + dark: false, + background: 0xfafafa, + foreground: 0x383a41, + cursor: 0x4a62db, + selection_bg: 0xd9dcea, + selection_fg: 0x383a41, + accent: 0x5b79e3, + chrome_bg: 0xeaeaed, + chrome_fg: 0x383a41, + chrome_active_bg: 0xc9c9cc, + border: 0xf0f0f1, + popup_bg: 0xebebec, + ansi: [ + 0x383a41, 0xd36151, 0x649f57, 0xdabb7e, 0x5b79e3, 0xa449ab, 0x3882b7, 0xfafafa, + 0x2e323a, 0xde8a7e, 0x8cb883, 0xe4cda0, 0x869cea, 0xbc78c1, 0x4a62db, 0xfafafa, + ], + }, + ), + ( + "zenburn", + Theme { + dark: true, + background: 0x3f3f3f, + foreground: 0xdcdccc, + cursor: 0x8faf9f, + selection_bg: 0x2f2f2f, + selection_fg: 0xdcdccc, + accent: 0x709080, + chrome_bg: 0x313633, + chrome_fg: 0xccdc90, + chrome_active_bg: 0x4e5250, + border: 0x494949, + popup_bg: 0x2c2e2e, + ansi: [ + 0x585858, 0xe37170, 0x7f9f7f, 0xefef8f, 0x709080, 0xdca3a3, 0x8cd0d3, 0xdcdccc, + 0x7f9f7f, 0xea9695, 0xa0b8a0, 0xf1f19c, 0x95ada1, 0xffcfaf, 0xaadcde, 0xe8e8de, + ], + }, + ), +]; diff --git a/themes/LICENSES/ashen.license b/themes/LICENSES/ashen.license new file mode 100644 index 0000000..fe85aed --- /dev/null +++ b/themes/LICENSES/ashen.license @@ -0,0 +1,22 @@ +MIT License + +Copyright (c) 2025 Daniel Fichtinger + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/themes/LICENSES/carbonfox.license b/themes/LICENSES/carbonfox.license new file mode 100644 index 0000000..4f446e7 --- /dev/null +++ b/themes/LICENSES/carbonfox.license @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 James Simpson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/themes/LICENSES/cyan_light.LICENSE b/themes/LICENSES/cyan_light.LICENSE new file mode 100644 index 0000000..3a4a2fb --- /dev/null +++ b/themes/LICENSES/cyan_light.LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 CloudCannon + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/dark-synthwave.license b/themes/LICENSES/dark-synthwave.license new file mode 100644 index 0000000..4d5572b --- /dev/null +++ b/themes/LICENSES/dark-synthwave.license @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Aaron Young + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/doom-one.LICENSE b/themes/LICENSES/doom-one.LICENSE new file mode 100644 index 0000000..1d0112f --- /dev/null +++ b/themes/LICENSES/doom-one.LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2025 NTBBloodbath + +This theme has been ported by spentbliss . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/everforest.LICENSE b/themes/LICENSES/everforest.LICENSE new file mode 100644 index 0000000..546ed63 --- /dev/null +++ b/themes/LICENSES/everforest.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 sainnhe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/kinda_nvim.LICENSE b/themes/LICENSES/kinda_nvim.LICENSE new file mode 100644 index 0000000..bb0429b --- /dev/null +++ b/themes/LICENSES/kinda_nvim.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Strash + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/lapis_aquamarine.LICENSE b/themes/LICENSES/lapis_aquamarine.LICENSE new file mode 100644 index 0000000..0e8d30d --- /dev/null +++ b/themes/LICENSES/lapis_aquamarine.LICENSE @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2025 Alex Barnett + +This theme has been ported by spentbliss . + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/modus_vivendi.LICENSE b/themes/LICENSES/modus_vivendi.LICENSE new file mode 100644 index 0000000..7e22450 --- /dev/null +++ b/themes/LICENSES/modus_vivendi.LICENSE @@ -0,0 +1,5 @@ +Copyright (C) 2020-2023 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.” + +(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.” diff --git a/themes/LICENSES/modus_vivendi_deuteranopia.LICENSE b/themes/LICENSES/modus_vivendi_deuteranopia.LICENSE new file mode 100644 index 0000000..7e22450 --- /dev/null +++ b/themes/LICENSES/modus_vivendi_deuteranopia.LICENSE @@ -0,0 +1,5 @@ +Copyright (C) 2020-2023 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.” + +(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.” diff --git a/themes/LICENSES/modus_vivendi_tinted.LICENSE b/themes/LICENSES/modus_vivendi_tinted.LICENSE new file mode 100644 index 0000000..7e22450 --- /dev/null +++ b/themes/LICENSES/modus_vivendi_tinted.LICENSE @@ -0,0 +1,5 @@ +Copyright (C) 2020-2023 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.” + +(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.” diff --git a/themes/LICENSES/modus_vivendi_tritanopia.LICENSE b/themes/LICENSES/modus_vivendi_tritanopia.LICENSE new file mode 100644 index 0000000..7e22450 --- /dev/null +++ b/themes/LICENSES/modus_vivendi_tritanopia.LICENSE @@ -0,0 +1,5 @@ +Copyright (C) 2020-2023 Free Software Foundation, Inc. + +Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, with the Front-Cover Texts being “A GNU Manual,” and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled “GNU Free Documentation License.” + +(a) The FSF’s Back-Cover Text is: “You have the freedom to copy and modify this GNU manual.” diff --git a/themes/LICENSES/poimandres.LICENSE b/themes/LICENSES/poimandres.LICENSE new file mode 100644 index 0000000..bc8d1cf --- /dev/null +++ b/themes/LICENSES/poimandres.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 drcmda + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/serika-syntax.LICENSE b/themes/LICENSES/serika-syntax.LICENSE new file mode 100644 index 0000000..a88cd6f --- /dev/null +++ b/themes/LICENSES/serika-syntax.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 arturoalviar + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/sonokai.LICENSE b/themes/LICENSES/sonokai.LICENSE new file mode 100644 index 0000000..167e749 --- /dev/null +++ b/themes/LICENSES/sonokai.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 sainnhe + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/themes/LICENSES/starlight.LICENSE b/themes/LICENSES/starlight.LICENSE new file mode 100644 index 0000000..fdddb29 --- /dev/null +++ b/themes/LICENSES/starlight.LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/themes/LICENSES/vesper.LICENSE b/themes/LICENSES/vesper.LICENSE new file mode 100644 index 0000000..f931c3b --- /dev/null +++ b/themes/LICENSES/vesper.LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Rauno Freiberg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.