From 2abaa81b0456b1d6dc5a41b1eee1d22e27af267e Mon Sep 17 00:00:00 2001 From: rhysd Date: Sun, 24 Nov 2024 00:07:42 +0900 Subject: [PATCH] separate writing Vim colorscheme, airline theme, and alacritty theme into each writers --- gen/src/main.rs | 1175 ++++++++++++++++++++++++----------------------- gen/src/test.rs | 188 +++----- 2 files changed, 675 insertions(+), 688 deletions(-) diff --git a/gen/src/main.rs b/gen/src/main.rs index 26b18d5..f41e938 100644 --- a/gen/src/main.rs +++ b/gen/src/main.rs @@ -7,7 +7,8 @@ use std::collections::HashMap; use std::env; use std::fmt::Display; use std::fs::File; -use std::io; +use std::io::{self, BufWriter, Write}; +use std::ops::Deref; use std::path::PathBuf; #[derive(Debug, PartialEq)] @@ -33,8 +34,6 @@ struct Color { cterm: ColorCode, } -type ColorTable = HashMap<&'static str, Color>; - type ColorName = Option<&'static str>; #[derive(Debug, PartialEq)] @@ -59,69 +58,15 @@ struct Highlight { } #[derive(Debug)] -enum HowToHighlight { - Always(Highlight), - Switch(Highlight, Highlight), +enum Highlighting { + Fixed(Highlight), + Dynamic { gui: Highlight, term: Highlight }, // Use different highlights for GUI and CUI } -use crate::HowToHighlight::{Always, Switch}; - -macro_rules! highlight { - ($name:ident, $fg:expr, $bg:expr, $sp:expr, $attr:ident) => { - Highlight { - name: stringify!($name), - fg: $fg, - bg: $bg, - sp: $sp, - attr: HighlightAttr::$attr, - } - }; -} - -macro_rules! fgbg { - ($name:ident, - , - , $attr:ident) => { - highlight!($name, None, None, None, $attr) - }; - ($name:ident, $fg:ident, - , $attr:ident) => { - highlight!($name, Some(stringify!($fg)), None, None, $attr) - }; - ($name:ident, - , $bg:ident, $attr:ident) => { - highlight!($name, None, Some(stringify!($bg)), None, $attr) - }; - ($name:ident, $fg:ident, $bg:ident, $attr:ident) => { - highlight!( - $name, - Some(stringify!($fg)), - Some(stringify!($bg)), - None, - $attr - ) - }; -} - -macro_rules! fgbgsp { - ($name:ident, $fg:ident, - , $sp:ident, $attr:ident) => { - highlight!( - $name, - Some(stringify!($fg)), - None, - Some(stringify!($sp)), - $attr - ) - }; - ($name:ident, $fg:ident, $bg:ident, $sp:ident, $attr:ident) => { - highlight!( - $name, - Some(stringify!($fg)), - Some(stringify!($bg)), - Some(stringify!($sp)), - $attr - ) - }; -} +use Highlighting::{Dynamic, Fixed}; #[derive(Debug, PartialEq, Default)] -struct ThemeModeColor<'a> { +struct AirlineModeColors<'a> { label: (&'a str, &'a str), info: (&'a str, &'a str), main: (&'a str, &'a str), @@ -131,7 +76,7 @@ struct ThemeModeColor<'a> { #[derive(Debug, Default)] struct AirlineThemeColors<'a> { - mode: HashMap<&'a str, ThemeModeColor<'a>>, + modes: HashMap<&'a str, AirlineModeColors<'a>>, paste: &'a str, info_mod: &'a str, error: (&'a str, &'a str), @@ -159,16 +104,374 @@ struct AlacrittyTheme<'a> { } #[derive(Debug)] -struct Writer<'a, W: io::Write> { - table: ColorTable, - highlights: &'a [HowToHighlight], +struct Palette(HashMap<&'static str, Color>); + +impl Deref for Palette { + type Target = HashMap<&'static str, Color>; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl Default for Palette { + #[rustfmt::skip] + fn default() -> Self { + fn normal(c: T) -> ColorCode { + ColorCode::Normal(c) + } + + fn contrast(high: T, low: T) -> ColorCode { + ColorCode::Contrast(high, low) + } + + let mut table = HashMap::new(); + + macro_rules! color_name { + ($name:ident, $gui:expr, $cterm:expr) => { + assert_eq!( + table.insert( + stringify!($name), + Color { + gui: $gui, + cterm: $cterm + } + ), + None + ) + }; + } + + color_name!(bg, contrast("#132132", "#334152"), normal(233)); + color_name!(bgweaker, contrast("#213243", "#3a4b5c"), normal(235)); + color_name!(bgemphasis, normal("#3a4b5c"), normal(235)); + color_name!(bglight, normal("#435060"), normal(236)); + color_name!(bgstrong, normal("#536273"), normal(238)); + color_name!(fg, normal("#fffeeb"), contrast(231, 230)); + color_name!(hiddenfg, normal("#607080"), normal(60)); + color_name!(weakfg, normal("#8d9eb2"), normal(103)); + color_name!(weakerfg, normal("#788898"), normal(102)); + color_name!(palepink, normal("#e7c6b7"), normal(181)); + color_name!(yellow, normal("#f0eaaa"), normal(229)); + color_name!(white, normal("#ffffff"), normal(231)); + color_name!(purple, normal("#e7d5ff"), normal(189)); + color_name!(darkpurple, normal("#605779"), normal(60)); + color_name!(gray, normal("#545f6e"), normal(59)); + color_name!(light, normal("#646f7c"), normal(60)); + color_name!(yaezakura, normal("#70495d"), normal(95)); + color_name!(sakura, normal("#a9667a"), normal(132)); + color_name!(orange, normal("#f0aa8a"), normal(216)); + color_name!(green, normal("#a9dd9d"), normal(150)); + color_name!(darkgreen, normal("#5f8770"), normal(65)); + color_name!(skyblue, normal("#a8d2eb"), normal(153)); + color_name!(gold, normal("#fedf81"), normal(222)); + color_name!(darkgold, contrast("#484000", "#685800"), normal(58)); + color_name!(red, normal("#fd8489"), normal(210)); + color_name!(mildred, normal("#ab6560"), normal(167)); + color_name!(crimson, normal("#ff6a6f"), normal(203)); + color_name!(mikan, normal("#fb8965"), normal(209)); + color_name!(darkblue, normal("#00091e"), normal(235)); + color_name!(blue, normal("#7098e6"), normal(69)); + color_name!(paleblue, normal("#98b8e6"), normal(111)); + color_name!(lime, normal("#c9fd88"), normal(149)); + color_name!(palesakura, normal("#e996aa"), normal(175)); + color_name!(whitepink, normal("#ebeadb"), normal(224)); + color_name!(whitegreen, normal("#eaf0aa"), normal(194)); + color_name!(whiteblue, normal("#d8e2f0"), normal(195)); + color_name!(whitered, normal("#ffbfaf"), normal(217)); + color_name!(black, normal("#111e25"), normal(233)); + color_name!(inu, normal("#ddbc96"), normal(180)); + + Self(table) + } +} + +#[derive(Debug)] +struct ColorschemeWriter<'a, W> { + palette: &'a Palette, + highlightings: &'a [Highlighting], term_colors: [&'static str; 16], - airline_theme: AirlineThemeColors<'a>, - alacritty_theme: AlacrittyTheme<'a>, out: W, } -impl<'a, W: io::Write> Writer<'a, W> { +impl<'a, W: Write> ColorschemeWriter<'a, W> { + #[rustfmt::skip::macros(fgbg, fgbgsp)] + fn new(out: W, palette: &'a Palette) -> Self { + macro_rules! highlight { + ($name:ident, $fg:expr, $bg:expr, $sp:expr, $attr:ident) => { + Highlight { + name: stringify!($name), + fg: $fg, + bg: $bg, + sp: $sp, + attr: HighlightAttr::$attr, + } + }; + } + + macro_rules! fgbg { + ($name:ident, - , - , $attr:ident) => { + highlight!($name, None, None, None, $attr) + }; + ($name:ident, $fg:ident, - , $attr:ident) => { + highlight!($name, Some(stringify!($fg)), None, None, $attr) + }; + ($name:ident, - , $bg:ident, $attr:ident) => { + highlight!($name, None, Some(stringify!($bg)), None, $attr) + }; + ($name:ident, $fg:ident, $bg:ident, $attr:ident) => { + highlight!( + $name, + Some(stringify!($fg)), + Some(stringify!($bg)), + None, + $attr + ) + }; + } + + macro_rules! fgbgsp { + ($name:ident, $fg:ident, - , $sp:ident, $attr:ident) => { + highlight!( + $name, + Some(stringify!($fg)), + None, + Some(stringify!($sp)), + $attr + ) + }; + ($name:ident, $fg:ident, $bg:ident, $sp:ident, $attr:ident) => { + highlight!( + $name, + Some(stringify!($fg)), + Some(stringify!($bg)), + Some(stringify!($sp)), + $attr + ) + }; + } + + let highlightings = &[ + // Normal colors + Fixed(fgbg!(Boolean, red, -, Nothing)), + Fixed(fgbg!(Character, green, -, Nothing)), + Fixed(fgbg!(ColorColumn, -, bgstrong, Nothing)), + Fixed(fgbg!(Comment, weakfg, -, CommentItalic)), + Fixed(fgbg!(Conceal, mikan, bg, Nothing)), + Fixed(fgbg!(Conditional, skyblue, -, Nothing)), + Fixed(fgbg!(Constant, red, -, Nothing)), + Fixed(fgbg!(Cursor, bg, fg, Nothing)), + Fixed(fgbg!(lCursor, bg, fg, Nothing)), + Fixed(fgbg!(CursorColumn, -, bgemphasis, Nothing)), + Fixed(fgbg!(CursorLine, -, bgemphasis, None)), + Fixed(fgbg!(CursorLineNr, purple, bgstrong, Nothing)), + Fixed(fgbg!(Define, orange, -, Nothing)), + Fixed(fgbg!(Directory, green, -, Nothing)), + Fixed(fgbg!(EndOfBuffer, bgstrong, -, Nothing)), + Fixed(fgbg!(Error, red, bgemphasis, Bold)), + Fixed(fgbg!(ErrorMsg, red, bg, Bold)), + Fixed(fgbg!(Float, red, -, Nothing)), + Fixed(fgbg!(NormalFloat, fg, bgweaker, Nothing)), + Fixed(fgbg!(FloatBorder, weakfg, bgweaker, Nothing)), + Fixed(fgbg!(FoldColumn, purple, bgemphasis, Nothing)), + Fixed(fgbg!(Folded, purple, light, Nothing)), + Fixed(fgbg!(Function, orange, -, Nothing)), + Fixed(fgbg!(Identifier, gold, -, Italic)), + Fixed(fgbg!(IncSearch, NONE, sakura, Underline)), + Fixed(fgbg!(Keyword, yellow, -, Bold)), + Fixed(fgbg!(Label, skyblue, -, Nothing)), + Fixed(fgbg!(LineNr, weakerfg, bgemphasis, Nothing)), + Fixed(fgbg!(MatchParen, bg, gold, Bold)), + Fixed(fgbg!(ModeMsg, gold, -, Nothing)), + Fixed(fgbg!(MoreMsg, green, -, Nothing)), + Fixed(fgbg!(NonText, light, -, Nothing)), + Fixed(fgbg!(Normal, fg, bg, Nothing)), + Fixed(fgbg!(Number, red, -, Nothing)), + Fixed(fgbg!(Operater, orange, -, Nothing)), + Fixed(fgbg!(Pmenu, purple, bgemphasis, Nothing)), + Fixed(fgbg!(PmenuSbar, gold, bgstrong, Nothing)), + Fixed(fgbg!(PmenuSel, gold, bgstrong, Nothing)), + Fixed(fgbg!(PmenuThumb, gold, weakfg, Nothing)), + Fixed(fgbg!(PreProc, orange, -, Nothing)), + Fixed(fgbg!(Question, skyblue, -, Nothing)), + Fixed(fgbg!(Search, NONE, darkpurple, Underline)), + Fixed(fgbg!(SignColumn, fg, bgemphasis, Nothing)), + Fixed(fgbg!(Special, yellow, -, Bold)), + Fixed(fgbg!(SpecialKey, hiddenfg, -, Nothing)), + Fixed(fgbg!(SpecialComment, palepink, -, Nothing)), + Dynamic { + gui: fgbgsp!(SpellBad, red, -, red, Undercurl), + term: fgbgsp!(SpellBad, red, NONE, red, Undercurl), + }, + Dynamic { + gui: fgbgsp!(SpellCap, purple, -, purple, Undercurl), + term: fgbgsp!(SpellCap, purple, NONE, purple, Undercurl), + }, + Dynamic { + gui: fgbgsp!(SpellLocal, red, -, red, Undercurl), + term: fgbgsp!(SpellLocal, red, NONE, red, Undercurl), + }, + Dynamic { + gui: fgbgsp!(SpellRare, yellow, -, yellow, Undercurl), + term: fgbgsp!(SpellRare, yellow, NONE, yellow, Undercurl), + }, + Fixed(fgbg!(Statement, skyblue, -, Nothing)), + Fixed(fgbg!(StatusLine, fg, bgstrong, Bold)), + Fixed(fgbg!(StatusLineNC, weakfg, bgemphasis, None)), + Fixed(fgbg!(StatusLineTerm, fg, bgstrong, Bold)), + Fixed(fgbg!(StatusLineTermNC, weakfg, bgemphasis, None)), + Fixed(fgbg!(StorageClass, gold, -, Italic)), + Fixed(fgbg!(String, green, -, Nothing)), + Fixed(fgbg!(TabLine, weakfg, bgstrong, Nothing)), + Fixed(fgbg!(TabLineFill, bgemphasis, -, Nothing)), + Fixed(fgbg!(TabLineSel, gold, bg, Bold)), + Fixed(fgbg!(Tag, orange, -, Nothing)), + Fixed(fgbg!(Title, gold, -, Bold)), + Fixed(fgbg!(Todo, bg, red, Bold)), + Fixed(fgbg!(ToolbarButton, gold, bg, Bold)), + Fixed(fgbg!(ToolbarLine, weakfg, bgstrong, Nothing)), + Fixed(fgbg!(Type, gold, -, Nothing)), + Fixed(fgbg!(Underlined, skyblue, -, Underline)), + Fixed(fgbg!(VertSplit, bgemphasis, bg, Nothing)), + Fixed(fgbg!(Visual, -, yaezakura, Nothing)), + Fixed(fgbg!(WarningMsg, mikan, bgemphasis, Nothing)), + Fixed(fgbg!(WildMenu, bg, gold, Nothing)), + // + // File type specific + // + // Markdown is highlighted with HTML highlights in gVim but link text doesn't + // have a color. So define it here. + Fixed(fgbg!(cmakeArguments, yellow, -, Nothing)), + Fixed(fgbg!(cmakeOperators, red, -, Nothing)), + Fixed(fgbg!(cStorageClass, yellow, -, Nothing)), + Fixed(fgbg!(cTypedef, yellow, -, Nothing)), + Fixed(fgbg!(DiffAdd, -, darkgreen, Bold)), + Fixed(fgbg!(DiffChange, -, darkgold, Bold)), + Fixed(fgbg!(DiffDelete, fg, mildred, Bold)), + Fixed(fgbg!(DiffText, -, bg, Nothing)), + Fixed(fgbg!(diffAdded, green, -, Nothing)), + Fixed(fgbg!(diffFile, yellow, -, Nothing)), + Fixed(fgbg!(diffIndexLine, gold, -, Nothing)), + Fixed(fgbg!(diffNewFile, yellow, -, Nothing)), + Fixed(fgbg!(diffRemoved, red, -, Nothing)), + Fixed(fgbg!(gitCommitOverflow, -, mildred, Nothing)), + Fixed(fgbg!(gitCommitSummary, yellow, -, Nothing)), + Fixed(fgbg!(gitCommitSelectedFile, skyblue, -, Nothing)), + Fixed(fgbg!(gitconfigSection, skyblue, -, Bold)), + Fixed(fgbg!(goBuiltins, red, -, Nothing)), + Fixed(fgbg!(helpExample, skyblue, -, Nothing)), + Fixed(fgbg!(helpCommand, purple, -, Nothing)), + Fixed(fgbg!(htmlBold, -, bgemphasis, Nothing)), + Fixed(fgbg!(htmlLinkText, skyblue, -, Nothing)), + Fixed(fgbg!(htmlTagName, orange, -, Nothing)), + Fixed(fgbg!(javaScriptBraces, fg, -, Nothing)), + Fixed(fgbg!(makeCommands, yellow, -, Nothing)), + Fixed(fgbg!(markdownCode, yellow, -, Nothing)), + Fixed(fgbg!(markdownUrl, weakfg, -, Nothing)), + Fixed(fgbg!(ocamlConstructor, gold, -, Nothing)), + Fixed(fgbg!(ocamlKeyChar, skyblue, -, Nothing)), + Fixed(fgbg!(ocamlKeyword, gold , -, Nothing)), + Fixed(fgbg!(ocamlFunDef, skyblue, -, Nothing)), + Fixed(fgbg!(plantumlColonLine, skyblue, -, Nothing)), + Fixed(fgbg!(pythonBuiltin, red, -, Nothing)), + Fixed(fgbg!(qfFileName, gold, -, Nothing)), + Fixed(fgbg!(qfLineNr, skyblue, -, Nothing)), + Fixed(fgbg!(rstEmphasis, -, bgemphasis, Italic)), + Fixed(fgbg!(rstStrongEmphasis, -, bgstrong, Bold)), + Fixed(fgbg!(rubyFunction, yellow, -, Nothing)), + Fixed(fgbg!(rubyIdentifier, yellow, -, Nothing)), + Fixed(fgbg!(rustEnumVariant, gold, -, Nothing)), + Fixed(fgbg!(rustFuncCall, fg, -, Nothing)), + Fixed(fgbg!(rustCommentLineDoc, palepink, -, Nothing)), + Fixed(fgbg!(scalaInstanceDeclaration, gold, -, Nothing)), + Fixed(fgbg!(tomlTable, skyblue, -, Nothing)), + Fixed(fgbg!(tomlTableArray, skyblue, -, Nothing)), + Fixed(fgbg!(tomlKey, gold, -, Nothing)), + Fixed(fgbg!(tmuxCommands, skyblue, -, Nothing)), + Fixed(fgbg!(tmuxFlags, gold, -, Nothing)), + Fixed(fgbg!(tmuxFormatString, yellow, -, Nothing)), + Fixed(fgbg!(typescriptBraces, fg, -, Nothing)), + Fixed(fgbg!(typescriptAsyncFuncKeyword, skyblue, -, Nothing)), + Fixed(fgbg!(typescriptKeywordOp, yellow, -, Bold)), + Fixed(fgbg!(vimfilerColumn__SizeLine, weakfg, -, Nothing)), + Fixed(fgbg!(vimfilerClosedFile, green, -, Nothing)), + Fixed(fgbg!(vimCommand, skyblue, -, Nothing)), + Fixed(fgbg!(watListDelimiter, fg, -, Nothing)), + Fixed(fgbg!(watInstGeneral, yellow, -, Nothing)), + Fixed(fgbg!(watInstGetSet, yellow, -, Nothing)), + Fixed(fgbg!(watInstWithType, yellow, -, Nothing)), + Fixed(fgbg!(watUnnamedVar , purple, -, Nothing)), + Fixed(fgbg!(zshDelimiter, skyblue, -, Nothing)), + Fixed(fgbg!(zshPrecommand, red, -, Nothing)), + Fixed(fgbg!(debugPC, bg, skyblue, Nothing)), + Fixed(fgbg!(debugBreakPoint, bg, gold, Nothing)), + Fixed(fgbg!(zigMultilineStringDelimiter, yellow, -, Nothing)), + // + // Plugin specific + // + // Some plugins introduce its own highlight definitions. Adjust them for + // working fine with this colorscheme. + Fixed(fgbg!(ALEWarningSign, orange, bgemphasis, Bold)), + Fixed(fgbg!(ALEErrorSign, bgemphasis, mildred, Bold)), + Fixed(fgbg!(ALEInfoSign, -, light, Nothing)), + Fixed(fgbg!(ALEError, -, mildred, Nothing)), + Fixed(fgbg!(ALEWarning, -, darkgold, Nothing)), + Fixed(fgbg!(Flake8_Error, red, bgemphasis, Nothing)), + Fixed(fgbg!(Flake8_Warning, yellow, bgemphasis, Nothing)), + Fixed(fgbg!(Flake8_PyFlake, skyblue, bgemphasis, Nothing)), + Fixed(fgbg!(Flake8_Complexity, skyblue, bgemphasis, Nothing)), + Fixed(fgbg!(Flake8_Naming, skyblue, bgemphasis, Nothing)), + Fixed(fgbg!(SignifySignAdd, green, bgemphasis, Nothing)), + Fixed(fgbg!(SignifySignChange, yellow, bgemphasis, Nothing)), + Fixed(fgbg!(SignifySignChangeDelete, gold, bgemphasis, Nothing)), + Fixed(fgbg!(SignifySignDelete, red, bgemphasis, Nothing)), + Fixed(fgbg!(CleverFChar, bg, red, Nothing)), + Fixed(fgbg!(CleverFDirect, bg, red, Nothing)), + Fixed(fgbg!(DirvishArg, yellow, -, Bold)), + Fixed(fgbg!(EasyMotionTarget, red, -, Bold)), + Fixed(fgbg!(EasyMotionShade, weakfg, bg, Nothing)), + Fixed(fgbg!(GitGutterAdd, green, bgemphasis, Nothing)), + Fixed(fgbg!(GitGutterChange, yellow, bgemphasis, Nothing)), + Fixed(fgbg!(GitGutterChangeDelete, gold, bgemphasis, Nothing)), + Fixed(fgbg!(GitGutterDelete, red, bgemphasis, Nothing)), + Fixed(fgbg!(HighlightedyankRegion, -, bgemphasis, Nothing)), + Dynamic { + gui: fgbg!(EasyMotionIncCursor, bg, fg, Nothing), + term: fgbg!(EasyMotionIncCursor, -, -, Reverse), + }, + Fixed(fgbg!(plugDeleted, weakfg, -, Nothing)), + Fixed(fgbg!(ConflictMarker, -, mildred, Nothing)), + Fixed(fgbg!(IndentGuidesOdd, -, bgweaker, Nothing)), + Fixed(fgbg!(IndentGuidesEven, -, bgemphasis, Nothing)), + ]; + + let term_colors = [ + "bg", + "crimson", + "green", + "gold", + "blue", + "darkpurple", + "skyblue", + "fg", + "weakfg", + "red", + "lime", + "yellow", + "paleblue", + "purple", + "skyblue", + "white", + ]; + + Self { + palette, + highlightings, + term_colors, + out, + } + } + fn write_header(&mut self) -> io::Result<()> { write!( self.out, @@ -233,7 +536,7 @@ endif fn write_contrast_color_variables(&mut self) -> io::Result<()> { // Sort by key name to avoid random order for (name, color) in { - let mut v = self.table.iter().collect::>(); + let mut v = self.palette.iter().collect::>(); v.sort_by_key(|(&k, _)| k); v } { @@ -257,32 +560,29 @@ endif fn build_highlight_item( &self, - color_name: &'static str, - item_name: &'static str, + name: &'static str, + item: &'static str, color: &ColorCode, ) -> String { match color { - ColorCode::Normal(c) => format!("{}={}", item_name, c), - ColorCode::Contrast(..) => { - if item_name.starts_with("gui") { - format!("'{}='.s:{}_gui", item_name, color_name) - } else { - format!("'{}='.s:{}_cterm", item_name, color_name) - } + ColorCode::Normal(c) => format!("{}={}", item, c), + ColorCode::Contrast(..) if item.starts_with("gui") => { + format!("'{}='.s:{}_gui", item, name) } + ColorCode::Contrast(..) => format!("'{}='.s:{}_cterm", item, name), } } fn write_highlight(&mut self, highlight: &Highlight, indent: u32) -> io::Result<()> { let mut args = vec![highlight.name.to_string(), "term=NONE".to_string()]; - for &(color_name, gui, cterm) in &[ + for (color_name, gui, cterm) in [ (&highlight.fg, "guifg", "ctermfg"), (&highlight.bg, "guibg", "ctermbg"), ] { - if let Some(ref name) = color_name { + if let Some(name) = color_name { if name != &"NONE" { - let color = &self.table[name]; + let color = &self.palette[name]; args.push(self.build_highlight_item(name, gui, &color.gui)); args.push(self.build_highlight_item(name, cterm, &color.cterm)); } else { @@ -292,12 +592,12 @@ endif } } - if let Some(ref name) = highlight.sp { + if let Some(name) = highlight.sp { // Note: ctermsp does not exist args.push(self.build_highlight_item( name, "guisp", - &self.table[name].gui, // Currently guisp must not be NONE + &self.palette[name].gui, // Currently guisp must not be NONE )); } @@ -336,11 +636,11 @@ endif } } - fn write_highlights(&mut self) -> io::Result<()> { - for highlight in self.highlights { - match highlight { - Always(ref hl) => self.write_highlight(hl, 0u32)?, - Switch(ref gui, ref term) => { + fn write_highlightings(&mut self) -> io::Result<()> { + for highlighting in self.highlightings { + match highlighting { + Fixed(hl) => self.write_highlight(hl, 0u32)?, + Dynamic { gui, term } => { writeln!(self.out, "if s:gui_running")?; self.write_highlight(gui, 1u32)?; writeln!(self.out, "else")?; @@ -361,7 +661,7 @@ endif self.out, " let g:terminal_color_{} = '{}'", index, - self.table[name].gui.normal() + self.palette[name].gui.normal() )?; } writeln!(self.out, " else")?; @@ -370,7 +670,7 @@ endif self.out, " let g:terminal_color_{} = {}", index, - self.table[name].cterm.normal() + self.palette[name].cterm.normal() )?; } writeln!(self.out, " endif")?; @@ -389,7 +689,7 @@ endif let elems_for_vim = self .term_colors .iter() - .map(|name| format!("'{}'", self.table[name].gui.normal())) + .map(|name| format!("'{}'", self.palette[name].gui.normal())) .collect::>() .join(", "); writeln!( @@ -401,15 +701,91 @@ endif writeln!(self.out, "endif") } - fn write_color_scheme(&mut self) -> io::Result<()> { + fn write(&mut self) -> io::Result<()> { self.write_header()?; self.write_contrast_color_variables()?; - self.write_highlights()?; + self.write_highlightings()?; self.write_term_colors() } +} + +#[derive(Debug)] +struct AirlineThemeWriter<'a, W> { + palette: &'a Palette, + theme: AirlineThemeColors<'a>, + out: W, +} + +impl<'a, W: Write> AirlineThemeWriter<'a, W> { + fn new(out: W, palette: &'a Palette) -> Self { + // Note: Pair strings are color names of (fg, bg) + let theme = AirlineThemeColors { + modes: { + let mut m = HashMap::new(); + + macro_rules! theme_mode_colors { + ($name:ident { $($n:ident: $e:expr,)+ }) => { + assert_eq!(m.insert(stringify!($name), AirlineModeColors { $($n: $e,)+ }), None) + }; + } + + theme_mode_colors!(normal { + label: ("bg", "gold"), + info: ("gold", "hiddenfg"), + main: ("yellow", "bglight"), + modified: Some("green"), + modified_main: Some("whitegreen"), + }); + + theme_mode_colors!(insert { + label: ("bg", "skyblue"), + info: ("skyblue", "hiddenfg"), + main: ("whiteblue", "bglight"), + modified: None, + modified_main: None, + }); + + theme_mode_colors!(visual { + label: ("bg", "palesakura"), + info: ("palesakura", "hiddenfg"), + main: ("whitepink", "bglight"), + modified: Some("sakura"), + modified_main: None, + }); + + theme_mode_colors!(replace { + label: ("bg", "red"), + info: ("red", "hiddenfg"), + main: ("whitered", "bglight"), + modified: Some("crimson"), + modified_main: None, + }); + + theme_mode_colors!(inactive { + label: ("weakfg", "bglight"), + info: ("weakfg", "bglight"), + main: ("weakfg", "bglight"), + modified: None, + modified_main: None, + }); + + m + }, + paste: "mikan", + info_mod: "hiddenfg", + error: ("bg", "red"), + warning: ("bg", "mikan"), + }; + + Self { + palette, + theme, + out, + } + } - fn write_airline_theme_header(&mut self) -> io::Result<()> { - let red = &self.table["red"]; + fn write_header(&mut self) -> io::Result<()> { + let red = &self.palette["red"]; // Header write!( self.out, @@ -437,9 +813,9 @@ let g:airline#themes#spring_night#palette.accents = {{ ) } - fn build_airline_one_palette_color(&self, fgbg: (&'a str, &'a str)) -> String { - let fg = &self.table[fgbg.0]; - let bg = &self.table[fgbg.1]; + fn build_one_palette_color(&self, fgbg: (&'a str, &'a str)) -> String { + let fg = &self.palette[fgbg.0]; + let bg = &self.palette[fgbg.1]; format!( "['{}', '{}', {}, {}, '']", fg.gui.normal(), @@ -449,18 +825,18 @@ let g:airline#themes#spring_night#palette.accents = {{ ) } - fn write_airline_palette(&mut self, name: &str, error: &str, warning: &str) -> io::Result<()> { - let map = &self.airline_theme.mode[name]; + fn write_mode_palette(&mut self, name: &str, error: &str, warning: &str) -> io::Result<()> { + let mode = &self.theme.modes[name]; writeln!( self.out, "let g:airline#themes#spring_night#palette.{} = {{", - name + name, )?; - let label = self.build_airline_one_palette_color(map.label); - let info = self.build_airline_one_palette_color(map.info); - let main = self.build_airline_one_palette_color(map.main); + let label = self.build_one_palette_color(mode.label); + let info = self.build_one_palette_color(mode.info); + let main = self.build_one_palette_color(mode.main); writeln!(self.out, "\\ 'airline_a': {},", label)?; writeln!(self.out, "\\ 'airline_b': {},", info)?; @@ -472,16 +848,15 @@ let g:airline#themes#spring_night#palette.accents = {{ writeln!(self.out, "\\ 'airline_warning': {},", warning)?; writeln!(self.out, "\\ }}")?; - if let Some(modified) = map.modified { - let label = self.build_airline_one_palette_color((map.label.0, modified)); - let info = - self.build_airline_one_palette_color((modified, self.airline_theme.info_mod)); - let main_fg = if let Some(n) = map.modified_main { + if let Some(modified) = mode.modified { + let label = self.build_one_palette_color((mode.label.0, modified)); + let info = self.build_one_palette_color((modified, self.theme.info_mod)); + let main_fg = if let Some(n) = mode.modified_main { n } else { modified }; - let main = self.build_airline_one_palette_color((main_fg, map.main.1)); + let main = self.build_one_palette_color((main_fg, mode.main.1)); writeln!( self.out, "let g:airline#themes#spring_night#palette.{}_modified = {{", @@ -498,32 +873,27 @@ let g:airline#themes#spring_night#palette.accents = {{ writeln!(self.out) } - fn write_airline_theme(&mut self) -> io::Result<()> { - self.write_airline_theme_header()?; + fn write(&mut self) -> io::Result<()> { + self.write_header()?; - let error = self.build_airline_one_palette_color(self.airline_theme.error); - let warning = self.build_airline_one_palette_color(self.airline_theme.warning); + let error = self.build_one_palette_color(self.theme.error); + let warning = self.build_one_palette_color(self.theme.warning); - for name in &["normal", "insert", "visual", "replace", "inactive"] { - self.write_airline_palette(name, &error, &warning)?; + for mode in &["normal", "insert", "visual", "replace", "inactive"] { + self.write_mode_palette(mode, &error, &warning)?; } - let normal_map = &self.airline_theme.mode["normal"]; - let insert_map = &self.airline_theme.mode["insert"]; + let normal_map = &self.theme.modes["normal"]; + let insert_map = &self.theme.modes["insert"]; // Insert Paste writeln!( self.out, "let g:airline#themes#spring_night#palette.insert_paste = {{" )?; - let label = - self.build_airline_one_palette_color((insert_map.label.0, self.airline_theme.paste)); - let info = self.build_airline_one_palette_color(( - self.airline_theme.paste, - self.airline_theme.info_mod, - )); - let main = - self.build_airline_one_palette_color((self.airline_theme.paste, normal_map.main.1)); + let label = self.build_one_palette_color((insert_map.label.0, self.theme.paste)); + let info = self.build_one_palette_color((self.theme.paste, self.theme.info_mod)); + let main = self.build_one_palette_color((self.theme.paste, normal_map.main.1)); writeln!(self.out, "\\ 'airline_a': {},", label)?; writeln!(self.out, "\\ 'airline_b': {},", info)?; writeln!(self.out, "\\ 'airline_c': {},", main)?; @@ -536,7 +906,7 @@ let g:airline#themes#spring_night#palette.accents = {{ self.out, "let g:airline#themes#spring_night#palette.inactive_modified = {{" )?; - let modified_color = &self.table[normal_map.modified.unwrap()]; + let modified_color = &self.palette[normal_map.modified.unwrap()]; let guifg = modified_color.gui.normal(); let ctermfg = modified_color.cterm.normal(); writeln!( @@ -550,415 +920,129 @@ let g:airline#themes#spring_night#palette.accents = {{ Ok(()) } +} - #[rustfmt::skip] - fn write_alacritty_theme(&mut self) -> io::Result<()> { - fn hex(color: &Color) -> &str { - match color.gui { - ColorCode::Normal(c) => c, - ColorCode::Contrast(c, _) => c, - } +#[derive(Debug)] +struct AlacrittyThemeWriter<'a, W> { + palette: &'a Palette, + theme: AlacrittyTheme<'a>, + out: W, +} + +impl<'a, W: Write> AlacrittyThemeWriter<'a, W> { + fn new(out: W, palette: &'a Palette) -> Self { + let theme = AlacrittyTheme { + background: "bg", + normal: AlacrittyFgColors { + foreground: "fg", + black: "black", + red: "crimson", + green: "green", + yellow: "gold", + blue: "blue", + magenta: "purple", + cyan: "skyblue", + white: "white", + }, + bright: AlacrittyFgColors { + foreground: "fg", + black: "gray", + red: "mildred", + green: "lime", + yellow: "yellow", + blue: "paleblue", + magenta: "purple", + cyan: "skyblue", + white: "white", + }, + }; + + Self { + palette, + theme, + out, } + } + #[rustfmt::skip] + fn write(&mut self) -> io::Result<()> { writeln!(self.out, "[colors.primary]")?; - writeln!(self.out, "background = \"{}\"", hex(&self.table[self.alacritty_theme.background]))?; - writeln!(self.out, "foreground = \"{}\"", hex(&self.table[self.alacritty_theme.normal.foreground]))?; - writeln!(self.out, "bright_foreground = \"{}\"", hex(&self.table[self.alacritty_theme.bright.foreground]))?; + writeln!(self.out, "background = \"{}\"", &self.palette[self.theme.background].gui.normal())?; + writeln!(self.out, "foreground = \"{}\"", &self.palette[self.theme.normal.foreground].gui.normal())?; + writeln!(self.out, "bright_foreground = \"{}\"", &self.palette[self.theme.bright.foreground].gui.normal())?; for (ty, colors) in [ - ("normal", &self.alacritty_theme.normal), - ("bright", &self.alacritty_theme.bright), + ("normal", &self.theme.normal), + ("bright", &self.theme.bright), ] { writeln!(self.out)?; writeln!(self.out, "[colors.{}]", ty)?; - writeln!(self.out, "black = \"{}\"", hex(&self.table[colors.black]))?; - writeln!(self.out, "red = \"{}\"", hex(&self.table[colors.red]))?; - writeln!(self.out, "green = \"{}\"", hex(&self.table[colors.green]))?; - writeln!(self.out, "yellow = \"{}\"", hex(&self.table[colors.yellow]))?; - writeln!(self.out, "blue = \"{}\"", hex(&self.table[colors.blue]))?; - writeln!(self.out, "magenta = \"{}\"", hex(&self.table[colors.magenta]))?; - writeln!(self.out, "cyan = \"{}\"", hex(&self.table[colors.cyan]))?; - writeln!(self.out, "white = \"{}\"", hex(&self.table[colors.white]))?; + writeln!(self.out, "black = \"{}\"", &self.palette[colors.black].gui.normal())?; + writeln!(self.out, "red = \"{}\"", &self.palette[colors.red].gui.normal())?; + writeln!(self.out, "green = \"{}\"", &self.palette[colors.green].gui.normal())?; + writeln!(self.out, "yellow = \"{}\"", &self.palette[colors.yellow].gui.normal())?; + writeln!(self.out, "blue = \"{}\"", &self.palette[colors.blue].gui.normal())?; + writeln!(self.out, "magenta = \"{}\"", &self.palette[colors.magenta].gui.normal())?; + writeln!(self.out, "cyan = \"{}\"", &self.palette[colors.cyan].gui.normal())?; + writeln!(self.out, "white = \"{}\"", &self.palette[colors.white].gui.normal())?; } + Ok(()) } } -#[rustfmt::skip::macros(color_name, fgbg, fgbgsp)] -fn spring_night_writer<'a, W: io::Write>(out: W) -> Writer<'a, W> { - let mut table = HashMap::new(); - { - fn normal(c: T) -> ColorCode { - ColorCode::Normal(c) - } - - fn contrast(high: T, low: T) -> ColorCode { - ColorCode::Contrast(high, low) - } +fn write_to_files(dir: &str) -> Result<()> { + let palette = Palette::default(); - macro_rules! color_name { - ($name:ident, $gui:expr, $cterm:expr) => { - assert_eq!( - table.insert( - stringify!($name), - Color { - gui: $gui, - cterm: $cterm - } - ), - None - ) - }; + fn join(entries: &[&str]) -> PathBuf { + let mut it = entries.iter(); + let mut path = PathBuf::from(it.next().unwrap()); + for entry in it { + path.push(entry); } - - color_name!(bg, contrast("#132132", "#334152"), normal(233)); - color_name!(bgweaker, contrast("#213243", "#3a4b5c"), normal(235)); - color_name!(bgemphasis, normal("#3a4b5c"), normal(235)); - color_name!(bglight, normal("#435060"), normal(236)); - color_name!(bgstrong, normal("#536273"), normal(238)); - color_name!(fg, normal("#fffeeb"), contrast(231, 230)); - color_name!(hiddenfg, normal("#607080"), normal(60)); - color_name!(weakfg, normal("#8d9eb2"), normal(103)); - color_name!(weakerfg, normal("#788898"), normal(102)); - color_name!(palepink, normal("#e7c6b7"), normal(181)); - color_name!(yellow, normal("#f0eaaa"), normal(229)); - color_name!(white, normal("#ffffff"), normal(231)); - color_name!(purple, normal("#e7d5ff"), normal(189)); - color_name!(darkpurple, normal("#605779"), normal(60)); - color_name!(gray, normal("#545f6e"), normal(59)); - color_name!(light, normal("#646f7c"), normal(60)); - color_name!(yaezakura, normal("#70495d"), normal(95)); - color_name!(sakura, normal("#a9667a"), normal(132)); - color_name!(orange, normal("#f0aa8a"), normal(216)); - color_name!(green, normal("#a9dd9d"), normal(150)); - color_name!(darkgreen, normal("#5f8770"), normal(65)); - color_name!(skyblue, normal("#a8d2eb"), normal(153)); - color_name!(gold, normal("#fedf81"), normal(222)); - color_name!(darkgold, contrast("#484000", "#685800"), normal(58)); - color_name!(red, normal("#fd8489"), normal(210)); - color_name!(mildred, normal("#ab6560"), normal(167)); - color_name!(crimson, normal("#ff6a6f"), normal(203)); - color_name!(mikan, normal("#fb8965"), normal(209)); - color_name!(darkblue, normal("#00091e"), normal(235)); - color_name!(blue, normal("#7098e6"), normal(69)); - color_name!(paleblue, normal("#98b8e6"), normal(111)); - color_name!(lime, normal("#c9fd88"), normal(149)); - color_name!(palesakura, normal("#e996aa"), normal(175)); - color_name!(whitepink, normal("#ebeadb"), normal(224)); - color_name!(whitegreen, normal("#eaf0aa"), normal(194)); - color_name!(whiteblue, normal("#d8e2f0"), normal(195)); - color_name!(whitered, normal("#ffbfaf"), normal(217)); - color_name!(black, normal("#111e25"), normal(233)); - color_name!(inu, normal("#ddbc96"), normal(180)); + path } - let table = table; - - let highlights = &[ - // Normal colors - Always(fgbg!(Boolean, red, -, Nothing)), - Always(fgbg!(Character, green, -, Nothing)), - Always(fgbg!(ColorColumn, -, bgstrong, Nothing)), - Always(fgbg!(Comment, weakfg, -, CommentItalic)), - Always(fgbg!(Conceal, mikan, bg, Nothing)), - Always(fgbg!(Conditional, skyblue, -, Nothing)), - Always(fgbg!(Constant, red, -, Nothing)), - Always(fgbg!(Cursor, bg, fg, Nothing)), - Always(fgbg!(lCursor, bg, fg, Nothing)), - Always(fgbg!(CursorColumn, -, bgemphasis, Nothing)), - Always(fgbg!(CursorLine, -, bgemphasis, None)), - Always(fgbg!(CursorLineNr, purple, bgstrong, Nothing)), - Always(fgbg!(Define, orange, -, Nothing)), - Always(fgbg!(Directory, green, -, Nothing)), - Always(fgbg!(EndOfBuffer, bgstrong, -, Nothing)), - Always(fgbg!(Error, red, bgemphasis, Bold)), - Always(fgbg!(ErrorMsg, red, bg, Bold)), - Always(fgbg!(Float, red, -, Nothing)), - Always(fgbg!(NormalFloat, fg, bgweaker, Nothing)), - Always(fgbg!(FloatBorder, weakfg, bgweaker, Nothing)), - Always(fgbg!(FoldColumn, purple, bgemphasis, Nothing)), - Always(fgbg!(Folded, purple, light, Nothing)), - Always(fgbg!(Function, orange, -, Nothing)), - Always(fgbg!(Identifier, gold, -, Italic)), - Always(fgbg!(IncSearch, NONE, sakura, Underline)), - Always(fgbg!(Keyword, yellow, -, Bold)), - Always(fgbg!(Label, skyblue, -, Nothing)), - Always(fgbg!(LineNr, weakerfg, bgemphasis, Nothing)), - Always(fgbg!(MatchParen, bg, gold, Bold)), - Always(fgbg!(ModeMsg, gold, -, Nothing)), - Always(fgbg!(MoreMsg, green, -, Nothing)), - Always(fgbg!(NonText, light, -, Nothing)), - Always(fgbg!(Normal, fg, bg, Nothing)), - Always(fgbg!(Number, red, -, Nothing)), - Always(fgbg!(Operater, orange, -, Nothing)), - Always(fgbg!(Pmenu, purple, bgemphasis, Nothing)), - Always(fgbg!(PmenuSbar, gold, bgstrong, Nothing)), - Always(fgbg!(PmenuSel, gold, bgstrong, Nothing)), - Always(fgbg!(PmenuThumb, gold, weakfg, Nothing)), - Always(fgbg!(PreProc, orange, -, Nothing)), - Always(fgbg!(Question, skyblue, -, Nothing)), - Always(fgbg!(Search, NONE, darkpurple, Underline)), - Always(fgbg!(SignColumn, fg, bgemphasis, Nothing)), - Always(fgbg!(Special, yellow, -, Bold)), - Always(fgbg!(SpecialKey, hiddenfg, -, Nothing)), - Always(fgbg!(SpecialComment, palepink, -, Nothing)), - Switch( - fgbgsp!(SpellBad, red, -, red, Undercurl), - fgbgsp!(SpellBad, red, NONE, red, Undercurl), - ), - Switch( - fgbgsp!(SpellCap, purple, -, purple, Undercurl), - fgbgsp!(SpellCap, purple, NONE, purple, Undercurl), - ), - Switch( - fgbgsp!(SpellLocal, red, -, red, Undercurl), - fgbgsp!(SpellLocal, red, NONE, red, Undercurl), - ), - Switch( - fgbgsp!(SpellRare, yellow, -, yellow, Undercurl), - fgbgsp!(SpellRare, yellow, NONE, yellow, Undercurl), - ), - Always(fgbg!(Statement, skyblue, -, Nothing)), - Always(fgbg!(StatusLine, fg, bgstrong, Bold)), - Always(fgbg!(StatusLineNC, weakfg, bgemphasis, None)), - Always(fgbg!(StatusLineTerm, fg, bgstrong, Bold)), - Always(fgbg!(StatusLineTermNC, weakfg, bgemphasis, None)), - Always(fgbg!(StorageClass, gold, -, Italic)), - Always(fgbg!(String, green, -, Nothing)), - Always(fgbg!(TabLine, weakfg, bgstrong, Nothing)), - Always(fgbg!(TabLineFill, bgemphasis, -, Nothing)), - Always(fgbg!(TabLineSel, gold, bg, Bold)), - Always(fgbg!(Tag, orange, -, Nothing)), - Always(fgbg!(Title, gold, -, Bold)), - Always(fgbg!(Todo, bg, red, Bold)), - Always(fgbg!(ToolbarButton, gold, bg, Bold)), - Always(fgbg!(ToolbarLine, weakfg, bgstrong, Nothing)), - Always(fgbg!(Type, gold, -, Nothing)), - Always(fgbg!(Underlined, skyblue, -, Underline)), - Always(fgbg!(VertSplit, bgemphasis, bg, Nothing)), - Always(fgbg!(Visual, -, yaezakura, Nothing)), - Always(fgbg!(WarningMsg, mikan, bgemphasis, Nothing)), - Always(fgbg!(WildMenu, bg, gold, Nothing)), - // - // File type specific - // - // Markdown is highlighted with HTML highlights in gVim but link text doesn't - // have a color. So define it here. - Always(fgbg!(cmakeArguments, yellow, -, Nothing)), - Always(fgbg!(cmakeOperators, red, -, Nothing)), - Always(fgbg!(cStorageClass, yellow, -, Nothing)), - Always(fgbg!(cTypedef, yellow, -, Nothing)), - Always(fgbg!(DiffAdd, -, darkgreen, Bold)), - Always(fgbg!(DiffChange, -, darkgold, Bold)), - Always(fgbg!(DiffDelete, fg, mildred, Bold)), - Always(fgbg!(DiffText, -, bg, Nothing)), - Always(fgbg!(diffAdded, green, -, Nothing)), - Always(fgbg!(diffFile, yellow, -, Nothing)), - Always(fgbg!(diffIndexLine, gold, -, Nothing)), - Always(fgbg!(diffNewFile, yellow, -, Nothing)), - Always(fgbg!(diffRemoved, red, -, Nothing)), - Always(fgbg!(gitCommitOverflow, -, mildred, Nothing)), - Always(fgbg!(gitCommitSummary, yellow, -, Nothing)), - Always(fgbg!(gitCommitSelectedFile, skyblue, -, Nothing)), - Always(fgbg!(gitconfigSection, skyblue, -, Bold)), - Always(fgbg!(goBuiltins, red, -, Nothing)), - Always(fgbg!(helpExample, skyblue, -, Nothing)), - Always(fgbg!(helpCommand, purple, -, Nothing)), - Always(fgbg!(htmlBold, -, bgemphasis, Nothing)), - Always(fgbg!(htmlLinkText, skyblue, -, Nothing)), - Always(fgbg!(htmlTagName, orange, -, Nothing)), - Always(fgbg!(javaScriptBraces, fg, -, Nothing)), - Always(fgbg!(makeCommands, yellow, -, Nothing)), - Always(fgbg!(markdownCode, yellow, -, Nothing)), - Always(fgbg!(markdownUrl, weakfg, -, Nothing)), - Always(fgbg!(ocamlConstructor, gold, -, Nothing)), - Always(fgbg!(ocamlKeyChar, skyblue, -, Nothing)), - Always(fgbg!(ocamlKeyword, gold , -, Nothing)), - Always(fgbg!(ocamlFunDef, skyblue, -, Nothing)), - Always(fgbg!(plantumlColonLine, skyblue, -, Nothing)), - Always(fgbg!(pythonBuiltin, red, -, Nothing)), - Always(fgbg!(qfFileName, gold, -, Nothing)), - Always(fgbg!(qfLineNr, skyblue, -, Nothing)), - Always(fgbg!(rstEmphasis, -, bgemphasis, Italic)), - Always(fgbg!(rstStrongEmphasis, -, bgstrong, Bold)), - Always(fgbg!(rubyFunction, yellow, -, Nothing)), - Always(fgbg!(rubyIdentifier, yellow, -, Nothing)), - Always(fgbg!(rustEnumVariant, gold, -, Nothing)), - Always(fgbg!(rustFuncCall, fg, -, Nothing)), - Always(fgbg!(rustCommentLineDoc, palepink, -, Nothing)), - Always(fgbg!(scalaInstanceDeclaration, gold, -, Nothing)), - Always(fgbg!(tomlTable, skyblue, -, Nothing)), - Always(fgbg!(tomlTableArray, skyblue, -, Nothing)), - Always(fgbg!(tomlKey, gold, -, Nothing)), - Always(fgbg!(tmuxCommands, skyblue, -, Nothing)), - Always(fgbg!(tmuxFlags, gold, -, Nothing)), - Always(fgbg!(tmuxFormatString, yellow, -, Nothing)), - Always(fgbg!(typescriptBraces, fg, -, Nothing)), - Always(fgbg!(typescriptAsyncFuncKeyword, skyblue, -, Nothing)), - Always(fgbg!(typescriptKeywordOp, yellow, -, Bold)), - Always(fgbg!(vimfilerColumn__SizeLine, weakfg, -, Nothing)), - Always(fgbg!(vimfilerClosedFile, green, -, Nothing)), - Always(fgbg!(vimCommand, skyblue, -, Nothing)), - Always(fgbg!(watListDelimiter, fg, -, Nothing)), - Always(fgbg!(watInstGeneral, yellow, -, Nothing)), - Always(fgbg!(watInstGetSet, yellow, -, Nothing)), - Always(fgbg!(watInstWithType, yellow, -, Nothing)), - Always(fgbg!(watUnnamedVar , purple, -, Nothing)), - Always(fgbg!(zshDelimiter, skyblue, -, Nothing)), - Always(fgbg!(zshPrecommand, red, -, Nothing)), - Always(fgbg!(debugPC, bg, skyblue, Nothing)), - Always(fgbg!(debugBreakPoint, bg, gold, Nothing)), - Always(fgbg!(zigMultilineStringDelimiter, yellow, -, Nothing)), - // - // Plugin specific - // - // Some plugins introduce its own highlight definitions. Adjust them for - // working fine with this colorscheme. - Always(fgbg!(ALEWarningSign, orange, bgemphasis, Bold)), - Always(fgbg!(ALEErrorSign, bgemphasis, mildred, Bold)), - Always(fgbg!(ALEInfoSign, -, light, Nothing)), - Always(fgbg!(ALEError, -, mildred, Nothing)), - Always(fgbg!(ALEWarning, -, darkgold, Nothing)), - Always(fgbg!(Flake8_Error, red, bgemphasis, Nothing)), - Always(fgbg!(Flake8_Warning, yellow, bgemphasis, Nothing)), - Always(fgbg!(Flake8_PyFlake, skyblue, bgemphasis, Nothing)), - Always(fgbg!(Flake8_Complexity, skyblue, bgemphasis, Nothing)), - Always(fgbg!(Flake8_Naming, skyblue, bgemphasis, Nothing)), - Always(fgbg!(SignifySignAdd, green, bgemphasis, Nothing)), - Always(fgbg!(SignifySignChange, yellow, bgemphasis, Nothing)), - Always(fgbg!(SignifySignChangeDelete, gold, bgemphasis, Nothing)), - Always(fgbg!(SignifySignDelete, red, bgemphasis, Nothing)), - Always(fgbg!(CleverFChar, bg, red, Nothing)), - Always(fgbg!(CleverFDirect, bg, red, Nothing)), - Always(fgbg!(DirvishArg, yellow, -, Bold)), - Always(fgbg!(EasyMotionTarget, red, -, Bold)), - Always(fgbg!(EasyMotionShade, weakfg, bg, Nothing)), - Always(fgbg!(GitGutterAdd, green, bgemphasis, Nothing)), - Always(fgbg!(GitGutterChange, yellow, bgemphasis, Nothing)), - Always(fgbg!(GitGutterChangeDelete, gold, bgemphasis, Nothing)), - Always(fgbg!(GitGutterDelete, red, bgemphasis, Nothing)), - Always(fgbg!(HighlightedyankRegion, -, bgemphasis, Nothing)), - Switch( - fgbg!(EasyMotionIncCursor, bg, fg, Nothing), - fgbg!(EasyMotionIncCursor, -, -, Reverse), - ), - Always(fgbg!(plugDeleted, weakfg, -, Nothing)), - Always(fgbg!(ConflictMarker, -, mildred, Nothing)), - Always(fgbg!(IndentGuidesOdd, -, bgweaker, Nothing)), - Always(fgbg!(IndentGuidesEven, -, bgemphasis, Nothing)), - ]; - - let term_colors = [ - "bg", - "crimson", - "green", - "gold", - "blue", - "darkpurple", - "skyblue", - "fg", - "weakfg", - "red", - "lime", - "yellow", - "paleblue", - "purple", - "skyblue", - "white", - ]; - - // Note: Pair strings are color names of (fg, bg) - let airline_theme = AirlineThemeColors { - mode: { - let mut m = HashMap::new(); - - macro_rules! theme_mode_colors { - ($name:ident { $($n:ident: $e:expr,)+ }) => { - assert_eq!(m.insert(stringify!($name), ThemeModeColor { $($n: $e,)+ }), None) - }; - } - theme_mode_colors!(normal { - label: ("bg", "gold"), - info: ("gold", "hiddenfg"), - main: ("yellow", "bglight"), - modified: Some("green"), - modified_main: Some("whitegreen"), - }); - - theme_mode_colors!(insert { - label: ("bg", "skyblue"), - info: ("skyblue", "hiddenfg"), - main: ("whiteblue", "bglight"), - modified: None, - modified_main: None, - }); - - theme_mode_colors!(visual { - label: ("bg", "palesakura"), - info: ("palesakura", "hiddenfg"), - main: ("whitepink", "bglight"), - modified: Some("sakura"), - modified_main: None, - }); - - theme_mode_colors!(replace { - label: ("bg", "red"), - info: ("red", "hiddenfg"), - main: ("whitered", "bglight"), - modified: Some("crimson"), - modified_main: None, - }); - - theme_mode_colors!(inactive { - label: ("weakfg", "bglight"), - info: ("weakfg", "bglight"), - main: ("weakfg", "bglight"), - modified: None, - modified_main: None, - }); - - m - }, - paste: "mikan", - info_mod: "hiddenfg", - error: ("bg", "red"), - warning: ("bg", "mikan"), - }; + let path = join(&[dir, "colors", "spring-night.vim"]); + let file = File::create(&path) + .with_context(|| format!("Failed to read colorscheme file: {:?}", &path))?; + ColorschemeWriter::new(BufWriter::new(file), &palette) + .write() + .with_context(|| format!("While writing to colorscheme file {:?}", &path))?; + + let path = join(&[dir, "autoload", "airline", "themes", "spring_night.vim"]); + let file = File::create(&path) + .with_context(|| format!("Could not make airline theme file {:?}", &path))?; + AirlineThemeWriter::new(BufWriter::new(file), &palette) + .write() + .with_context(|| format!("While writing to airline theme file {:?}", &path))?; + + let path = join(&[dir, "alacritty", "spring_night.toml"]); + let file = File::create(&path) + .with_context(|| format!("Could not make alacritty theme file {:?}", &path))?; + AlacrittyThemeWriter::new(BufWriter::new(file), &palette) + .write() + .with_context(|| format!("While writing to alacritty theme file {:?}", &path))?; - let alacritty_theme = AlacrittyTheme { - background: "bg", - normal: AlacrittyFgColors { - foreground: "fg", - black: "black", - red: "crimson", - green: "green", - yellow: "gold", - blue: "blue", - magenta: "purple", - cyan: "skyblue", - white: "white", - }, - bright: AlacrittyFgColors { - foreground: "fg", - black: "gray", - red: "mildred", - green: "lime", - yellow: "yellow", - blue: "paleblue", - magenta: "purple", - cyan: "skyblue", - white: "white", - }, - }; + Ok(()) +} - Writer { - table, - highlights, - term_colors, - airline_theme, - alacritty_theme, - out, - } +fn write_to_stdout() -> Result<()> { + let palette = Palette::default(); + let mut stdout = io::stdout().lock(); + + ColorschemeWriter::new(&mut stdout, &palette) + .write() + .with_context(|| "While writing colorscheme to stdout")?; + writeln!(stdout)?; + AirlineThemeWriter::new(&mut stdout, &palette) + .write() + .with_context(|| "While writing airline theme to stdout")?; + writeln!(stdout)?; + AlacrittyThemeWriter::new(&mut stdout, &palette) + .write() + .with_context(|| "While writing alacritty theme to stdout")?; + Ok(()) } fn main() -> Result<()> { @@ -969,12 +1053,7 @@ fn main() -> Result<()> { let opts = { let mut o = Options::new(); - o.optopt( - "d", - "dir", - "root directory of vim-color-spring-night repository", - "PATH", - ); + o.optopt("d", "dir", "repository root directory", "PATH"); o.optflag("h", "help", "print this help"); o }; @@ -989,52 +1068,10 @@ fn main() -> Result<()> { return Ok(()); } - match matches.opt_str("d") { - Some(dir) => { - let path = PathBuf::from(&dir).join("colors").join("spring-night.vim"); - let out = io::BufWriter::new( - File::create(&path) - .with_context(|| format!("Failed to read colorscheme file: {:?}", &path))?, - ); - let mut writer = spring_night_writer(out); - writer - .write_color_scheme() - .with_context(|| format!("While writing to colorscheme file {:?}", &path))?; - let path = PathBuf::from(&dir) - .join("autoload") - .join("airline") - .join("themes") - .join("spring_night.vim"); - writer.out = io::BufWriter::new( - File::create(&path) - .with_context(|| format!("Could not make airline theme file {:?}", &path))?, - ); - writer - .write_airline_theme() - .with_context(|| format!("While writing to airline theme file {:?}", &path))?; - let path = PathBuf::from(&dir) - .join("alacritty") - .join("spring_night.toml"); - writer.out = io::BufWriter::new( - File::create(&path) - .with_context(|| format!("Could not make alacritty theme file {:?}", &path))?, - ); - writer - .write_alacritty_theme() - .with_context(|| format!("While writing to alacritty theme file {:?}", &path))?; - } - None => { - use std::io::Write; - let out = io::BufWriter::new(io::stdout()); - let mut writer = spring_night_writer(out); - writer - .write_color_scheme() - .with_context(|| "While writing colorscheme script to stdout")?; - writeln!(writer.out)?; - writer - .write_airline_theme() - .with_context(|| "While writing airline theme to stdout")?; - } + if let Some(dir) = matches.opt_str("d") { + write_to_files(&dir)?; + } else { + write_to_stdout()?; } Ok(()) diff --git a/gen/src/test.rs b/gen/src/test.rs index e3e6d83..36433ae 100644 --- a/gen/src/test.rs +++ b/gen/src/test.rs @@ -4,10 +4,6 @@ use std::collections::{HashMap, HashSet}; use std::str; use toml_edit::DocumentMut; -const DUMMY_TERM_COLORS: [&str; 16] = [ - "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", -]; - #[test] fn test_color_code() { assert_eq!(*ColorCode::Normal(10).normal(), 10); @@ -16,14 +12,8 @@ fn test_color_code() { #[test] fn test_write_header() { - let mut w = Writer { - table: HashMap::new(), - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(HashMap::new()); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); w.write_header().unwrap(); let rendered = str::from_utf8(&w.out).unwrap(); assert!(rendered.starts_with(r#"" spring-night: Calm-colored dark color scheme"#)); @@ -32,14 +22,8 @@ fn test_write_header() { #[test] fn test_write_contrast_color_variables() { - let mut w = Writer { - table: HashMap::new(), - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(HashMap::new()); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); w.write_contrast_color_variables().unwrap(); assert_eq!(str::from_utf8(&w.out).unwrap(), "\n"); @@ -72,14 +56,8 @@ fn test_write_contrast_color_variables() { cterm: ColorCode::Normal(123), }, ); - let mut w = Writer { - table: m, - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(m); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); w.write_contrast_color_variables().unwrap(); for (actual, expected) in [ "let s:goodbye_gui = g:spring_night_high_contrast ? '#000000' : '#ffffff'", @@ -140,34 +118,23 @@ fn test_write_highlight() { cterm: ColorCode::Contrast(123, 234), }, ); - let mut w = Writer { - table: m, - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(m); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); w.write_highlight(&hl, indent as u32).unwrap(); assert_eq!(str::from_utf8(&w.out).unwrap(), format!("{}\n", expected)); } // Edge case - let mut w = Writer { - table: HashMap::new(), - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; - w.write_highlights().unwrap(); + let palette = Palette(HashMap::new()); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); + w.highlightings = &[]; + w.write_highlightings().unwrap(); assert_eq!(str::from_utf8(&w.out).unwrap(), "\n"); } #[test] fn test_write_highlights() { - fn hl() -> Highlight { + const fn hl() -> Highlight { Highlight { name: "HL", fg: None, @@ -176,26 +143,22 @@ fn test_write_highlights() { attr: HighlightAttr::Nothing, } } - let mut w = Writer { - table: HashMap::new(), - highlights: &[Always(hl())], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; - w.write_highlights().unwrap(); + + let palette = Palette(HashMap::new()); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); + let fixed = &[Fixed(hl())]; + w.highlightings = fixed; + w.write_highlightings().unwrap(); assert_eq!(str::from_utf8(&w.out).unwrap(), "hi HL term=NONE\n\n"); - let mut w = Writer { - table: HashMap::new(), - highlights: &[Switch(hl(), hl())], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; - w.write_highlights().unwrap(); + let dynamic = &[Dynamic { + gui: hl(), + term: hl(), + }]; + let palette = Palette(HashMap::new()); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); + w.highlightings = dynamic; + w.write_highlightings().unwrap(); assert_eq!( str::from_utf8(&w.out).unwrap().lines().collect::>(), vec![ @@ -226,17 +189,12 @@ fn test_write_term_colors() { cterm: ColorCode::Contrast(1, 2), }, ); - let mut w = Writer { - table: m, - highlights: &[], - term_colors: [ - "normal", "contrast", "normal", "contrast", "normal", "contrast", "normal", "contrast", - "normal", "contrast", "normal", "contrast", "normal", "contrast", "normal", "contrast", - ], - airline_theme: Default::default(), - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(m); + let mut w = ColorschemeWriter::new(Vec::new(), &palette); + w.term_colors = [ + "normal", "contrast", "normal", "contrast", "normal", "contrast", "normal", "contrast", + "normal", "contrast", "normal", "contrast", "normal", "contrast", "normal", "contrast", + ]; w.write_term_colors().unwrap(); let rendered = str::from_utf8(&w.out).unwrap(); assert!(rendered.contains("let g:terminal_color_0 = '#123456'")); @@ -247,16 +205,18 @@ fn test_write_term_colors() { } #[test] -fn test_spring_night_writer() { +fn test_colorscheme_writer() { + let palette = Palette::default(); + let w = ColorschemeWriter::new(Vec::new(), &palette); + // Check duplicate highlights - let w = spring_night_writer(Vec::new()); let mut unique_check = HashSet::new(); - for hl in w.highlights { + for hl in w.highlightings { let name = match hl { - Always(h) => h.name, - Switch(g, t) => { - assert_eq!(g.name, t.name); - g.name + Fixed(h) => h.name, + Dynamic { gui, term } => { + assert_eq!(gui.name, term.name); + gui.name } }; assert!(unique_check.insert(name), "Duplicate highlight '{}'", name); @@ -265,7 +225,7 @@ fn test_spring_night_writer() { // Check terminal colors are correct for tc in &w.term_colors { assert!( - w.table.contains_key(tc), + w.palette.contains_key(tc), "Terminal color '{}' is not present in color names", tc ); @@ -273,7 +233,7 @@ fn test_spring_night_writer() { // Check color code is correct let re = Regex::new(r"^#[[:xdigit:]]{6}$").unwrap(); - for (name, c) in w.table { + for (name, c) in w.palette.iter() { match c.gui { ColorCode::Normal(c) => assert!( re.is_match(c), @@ -301,15 +261,15 @@ fn test_spring_night_writer() { #[test] fn test_write_airline_theme() { - let mut table = HashMap::new(); - table.insert( + let mut m = HashMap::new(); + m.insert( "color1", Color { gui: ColorCode::Normal("#123456"), cterm: ColorCode::Normal(123), }, ); - table.insert( + m.insert( "color2", Color { gui: ColorCode::Contrast("#000000", "#ffffff"), @@ -317,7 +277,7 @@ fn test_write_airline_theme() { }, ); // Userd for accents - table.insert( + m.insert( "red", Color { gui: ColorCode::Normal("#ff0000"), @@ -325,12 +285,12 @@ fn test_write_airline_theme() { }, ); - let airline_theme = AirlineThemeColors { - mode: { + let theme = AirlineThemeColors { + modes: { let mut m = HashMap::new(); m.insert( "normal", - ThemeModeColor { + AirlineModeColors { label: ("color1", "color2"), info: ("color2", "color1"), main: ("color2", "color2"), @@ -340,7 +300,7 @@ fn test_write_airline_theme() { ); m.insert( "insert", - ThemeModeColor { + AirlineModeColors { label: ("color2", "color1"), info: ("color1", "color2"), main: ("color1", "color1"), @@ -350,7 +310,7 @@ fn test_write_airline_theme() { ); m.insert( "visual", - ThemeModeColor { + AirlineModeColors { label: ("color1", "color1"), info: ("color2", "color2"), main: ("color1", "color1"), @@ -360,7 +320,7 @@ fn test_write_airline_theme() { ); m.insert( "replace", - ThemeModeColor { + AirlineModeColors { label: ("color1", "color1"), info: ("color2", "color2"), main: ("color1", "color1"), @@ -370,7 +330,7 @@ fn test_write_airline_theme() { ); m.insert( "inactive", - ThemeModeColor { + AirlineModeColors { label: ("color1", "color1"), info: ("color2", "color2"), main: ("color1", "color1"), @@ -386,16 +346,11 @@ fn test_write_airline_theme() { warning: ("color2", "color1"), }; - let mut w = Writer { - table, - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme, - alacritty_theme: Default::default(), - out: Vec::new(), - }; + let palette = Palette(m); + let mut w = AirlineThemeWriter::new(Vec::new(), &palette); + w.theme = theme; - w.write_airline_theme().unwrap(); + w.write().unwrap(); let rendered = str::from_utf8(&w.out).unwrap(); let re_var = Regex::new(r"^let g:airline#themes#spring_night#palette\.(\w+) =").unwrap(); @@ -407,7 +362,7 @@ fn test_write_airline_theme() { Some(found) => { let mode = &found[1]; assert!( - w.airline_theme.mode.keys().any(|m| *m == mode + w.theme.modes.keys().any(|m| *m == mode || format!("{}_modified", m) == mode || format!("{}_paste", m) == mode || "accents" == mode), @@ -429,22 +384,22 @@ fn test_write_airline_theme() { #[test] fn test_write_alacritty_theme() { - let mut table = HashMap::new(); - table.insert( + let mut m = HashMap::new(); + m.insert( "color1", Color { gui: ColorCode::Normal("#ff0000"), cterm: ColorCode::Normal(123), }, ); - table.insert( + m.insert( "color2", Color { gui: ColorCode::Normal("#00ff00"), cterm: ColorCode::Normal(123), }, ); - table.insert( + m.insert( "color3", Color { gui: ColorCode::Normal("#0000ff"), @@ -474,22 +429,17 @@ fn test_write_alacritty_theme() { cyan: "color3", white: "color3", }; - let alacritty_theme = AlacrittyTheme { + let theme = AlacrittyTheme { background: "color1", normal, bright, }; - let mut w = Writer { - table, - highlights: &[], - term_colors: DUMMY_TERM_COLORS, - airline_theme: Default::default(), - alacritty_theme, - out: Vec::new(), - }; + let palette = Palette(m); + let mut w = AlacrittyThemeWriter::new(Vec::new(), &palette); + w.theme = theme; - w.write_alacritty_theme().unwrap(); + w.write().unwrap(); let rendered = str::from_utf8(&w.out).unwrap(); rendered.parse::().unwrap(); }