From ef51b31696d8679e8bd228be317534fab6b6cb61 Mon Sep 17 00:00:00 2001 From: Warden Clyffe Date: Sat, 4 Oct 2025 10:16:49 +0200 Subject: [PATCH 1/5] parser: adding neovim subcommand --- src/caelestia/parser.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/caelestia/parser.py b/src/caelestia/parser.py index 840ead5c..a2773584 100644 --- a/src/caelestia/parser.py +++ b/src/caelestia/parser.py @@ -1,6 +1,6 @@ import argparse -from caelestia.subcommands import clipboard, emoji, record, resizer, scheme, screenshot, shell, toggle, wallpaper +from caelestia.subcommands import clipboard, emoji, record, resizer, scheme, screenshot, shell, toggle, wallpaper, neovim from caelestia.utils.paths import wallpapers_dir from caelestia.utils.scheme import get_scheme_names, scheme_variants from caelestia.utils.wallpaper import get_wallpaper @@ -127,4 +127,8 @@ def parse_args() -> (argparse.ArgumentParser, argparse.Namespace): resizer_parser.add_argument("height", nargs="?", help="height to resize to") resizer_parser.add_argument("actions", nargs="?", help="comma-separated actions to apply (float,center,pip)") + # Create parser for neovim opts + neovim_parser = command_parser.add_parser("neovim", help="generate a neovim colorscheme") + neovim_parser.set_defaults(cls=neovim.Command) + return parser, parser.parse_args() From 398fa13b8ffe3d282487285d13b77ad2f2eb207e Mon Sep 17 00:00:00 2001 From: Warden Clyffe Date: Sat, 4 Oct 2025 10:18:15 +0200 Subject: [PATCH 2/5] paths: add neovim configuration related paths --- src/caelestia/utils/paths.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/caelestia/utils/paths.py b/src/caelestia/utils/paths.py index 14eb5505..cb8cbe68 100644 --- a/src/caelestia/utils/paths.py +++ b/src/caelestia/utils/paths.py @@ -40,6 +40,11 @@ recording_path = c_state_dir / "record/recording.mp4" recording_notif_path = c_state_dir / "record/notifid.txt" +neovim_config_path = config_dir / "nvim" +neovim_colors_path = neovim_config_path / "colors" +neovim_colorscheme_file = neovim_colors_path / "caelestia.lua" +neovim_template_path = templates_dir / "neovim.lua" + def compute_hash(path: Path | str) -> str: sha = hashlib.sha256() From b13181b2037bf1ca23ec512cf81bb6f35cba2886 Mon Sep 17 00:00:00 2001 From: Warden Clyffe Date: Sat, 4 Oct 2025 12:39:28 +0200 Subject: [PATCH 3/5] neovim: add subcommand to create caelestia neovim colorscheme --- src/caelestia/data/templates/neovim.lua | 230 ++++++++++++++++++++++++ src/caelestia/subcommands/neovim.py | 33 ++++ 2 files changed, 263 insertions(+) create mode 100644 src/caelestia/data/templates/neovim.lua create mode 100644 src/caelestia/subcommands/neovim.py diff --git a/src/caelestia/data/templates/neovim.lua b/src/caelestia/data/templates/neovim.lua new file mode 100644 index 00000000..21df0825 --- /dev/null +++ b/src/caelestia/data/templates/neovim.lua @@ -0,0 +1,230 @@ +-- Neovim Color Scheme Generated by Caelestia +-- https://github.com/inodb/caelestia + +-- Reset +vim.cmd("hi clear") +if vim.fn.exists("syntax_on") then + vim.cmd("syntax reset") +end +vim.g.colors_name = "caelestia" + +-- Define Color Palette +local colors = { + background = "#{{ $background }}", + foreground = "#{{ $onSurface }}", + black = "#{{ $surface }}", + white = "#{{ $onSurface }}", + red = "#{{ $red }}", + green = "#{{ $green }}", + yellow = "#{{ $yellow }}", + blue = "#{{ $blue }}", + magenta = "#{{ $mauve }}", + cyan = "#{{ $sky }}", + orange = "#{{ $peach }}", + pink = "#{{ $pink }}", + primary = "#{{ $primary }}", + secondary = "#{{ $secondary }}", + tertiary = "#{{ $tertiary }}", + error = "#{{ $error }}", + surface = "#{{ $surface }}", + surface_container = "#{{ $surfaceContainer }}", + surface_container_high = "#{{ $surfaceContainerHigh }}", + surface_container_highest = "#{{ $surfaceContainerHighest }}", + on_surface = "#{{ $onSurface }}", + on_surface_variant = "#{{ $onSurfaceVariant }}", + outline = "#{{ $outline }}", + outline_variant = "#{{ $outlineVariant }}", + shadow = "#{{ $shadow }}", + inverse_surface = "#{{ $inverseSurface }}", + inverse_on_surface = "#{{ $inverseOnSurface }}", + inverse_primary = "#{{ $inversePrimary }}", + surface_variant = "#{{ $surfaceVariant }}", + on_surface_variant_2 = "#{{ $onSurfaceVariant }}", + primary_container = "#{{ $primaryContainer }}", + on_primary_container = "#{{ $onPrimaryContainer }}", + secondary_container = "#{{ $secondaryContainer }}", + on_secondary_container = "#{{ $onSecondaryContainer }}", + tertiary_container = "#{{ $tertiaryContainer }}", + on_tertiary_container = "#{{ $onTertiaryContainer }}", + error_container = "#{{ $errorContainer }}", + on_error_container = "#{{ $onErrorContainer }}", + surface_bright = "#{{ $surfaceBright }}", + surface_dim = "#{{ $surfaceDim }}", + surface_container_low = "#{{ $surfaceContainerLow }}", + surface_container_lowest = "#{{ $surfaceContainerLowest }}", + surface_tint = "#{{ $surfaceTint }}", + on_primary = "#{{ $onPrimary }}", + on_secondary = "#{{ $onSecondary }}", + on_tertiary = "#{{ $onTertiary }}", + on_error = "#{{ $onError }}", + maroon = "#{{ $maroon }}", + peach = "#{{ $peach }}", + teal = "#{{ $teal }}", + sapphire = "#{{ $sapphire }}", + sky = "#{{ $sky }}", + mauve = "#{{ $mauve }}", + lavender = "#{{ $lavender }}", + rosewater = "#{{ $rosewater }}", +} + +-- Helper function to set highlights +local function s(group, styles) + vim.api.nvim_set_hl(0, group, styles) +end + +-- Set UI Highlights +s("Normal", { fg = colors.foreground, bg = colors.background }) +s("NormalFloat", { fg = colors.foreground, bg = colors.surface_container }) +s("FloatBorder", { fg = colors.primary, bg = colors.surface_container }) +s("Cursor", { bg = colors.primary, fg = colors.background }) +s("CursorLine", { bg = colors.surface_container }) +s("CursorLineNr", { fg = colors.primary, bg = colors.surface_container }) +s("LineNr", { fg = colors.on_surface_variant, bg = colors.background }) +s("SignColumn", { bg = colors.background, fg = colors.on_surface_variant }) +s("StatusLine", { fg = colors.on_surface, bg = colors.surface_container_high }) +s("StatusLineNC", { fg = colors.on_surface_variant, bg = colors.surface_container }) +s("TabLine", { fg = colors.on_surface_variant, bg = colors.surface_container }) +s("TabLineFill", { bg = colors.surface_container }) +s("TabLineSel", { fg = colors.primary, bg = colors.surface_container_high }) +s("VertSplit", { fg = colors.outline, bg = colors.background }) +s("WinSeparator", { fg = colors.outline, bg = colors.background }) +s("Pmenu", { fg = colors.foreground, bg = colors.surface_container }) +s("PmenuSel", { fg = colors.primary, bg = colors.surface_container_high }) +s("PmenuSbar", { bg = colors.surface_container }) +s("PmenuThumb", { bg = colors.outline }) +s("WildMenu", { fg = colors.primary, bg = colors.surface_container_high }) +s("Visual", { bg = colors.surface_container_high }) +s("VisualNOS", { bg = colors.surface_container_high }) +s("Search", { fg = colors.background, bg = colors.primary }) +s("IncSearch", { fg = colors.background, bg = colors.yellow }) +s("Question", { fg = colors.primary }) +s("MoreMsg", { fg = colors.primary }) +s("ModeMsg", { fg = colors.primary, bold = true }) +s("Directory", { fg = colors.blue }) +s("ErrorMsg", { fg = colors.error, bg = colors.background, bold = true }) +s("WarningMsg", { fg = colors.yellow, bg = colors.background, bold = true }) +s("Title", { fg = colors.primary, bold = true }) +s("NonText", { fg = colors.outline }) +s("SpecialKey", { fg = colors.on_surface_variant }) +s("Whitespace", { fg = colors.outline }) +s("Conceal", { fg = colors.on_surface_variant, bg = "NONE" }) + +-- Set Syntax Highlights +s("Comment", { fg = colors.on_surface_variant, italic = true }) +s("Constant", { fg = colors.peach }) +s("String", { fg = colors.green }) +s("Character", { fg = colors.green }) +s("Number", { fg = colors.peach }) +s("Boolean", { fg = colors.peach }) +s("Float", { fg = colors.peach }) +s("Identifier", { fg = colors.on_surface }) +s("Function", { fg = colors.blue }) +s("Statement", { fg = colors.magenta }) +s("Conditional", { fg = colors.magenta }) +s("Repeat", { fg = colors.magenta }) +s("Label", { fg = colors.yellow }) +s("Operator", { fg = colors.cyan }) +s("Keyword", { fg = colors.magenta }) +s("Exception", { fg = colors.red }) +s("PreProc", { fg = colors.yellow }) +s("Include", { fg = colors.blue }) +s("Define", { fg = colors.magenta }) +s("Macro", { fg = colors.yellow }) +s("PreCondit", { fg = colors.yellow }) +s("Type", { fg = colors.yellow }) +s("StorageClass", { fg = colors.yellow }) +s("Structure", { fg = colors.yellow }) +s("Typedef", { fg = colors.yellow }) +s("Special", { fg = colors.pink }) +s("SpecialChar", { fg = colors.pink }) +s("Tag", { fg = colors.pink }) +s("Delimiter", { fg = colors.on_surface }) +s("SpecialComment", { fg = colors.on_surface_variant }) +s("Debug", { fg = colors.on_surface_variant }) +s("Underlined", { underline = true }) +s("Ignore", {}) +s("Error", { fg = colors.error, bg = colors.background }) +s("Todo", { fg = colors.yellow, bg = colors.background, bold = true }) + +-- LSP/Diagnostics +s("LspDiagnosticsDefaultError", { fg = colors.error }) +s("LspDiagnosticsDefaultWarning", { fg = colors.yellow }) +s("LspDiagnosticsDefaultInformation", { fg = colors.cyan }) +s("LspDiagnosticsDefaultHint", { fg = colors.green }) +s("DiagnosticError", { fg = colors.error }) +s("DiagnosticWarn", { fg = colors.yellow }) +s("DiagnosticInfo", { fg = colors.cyan }) +s("DiagnosticHint", { fg = colors.green }) +s("DiagnosticUnderlineError", { undercurl = true, sp = colors.error }) +s("DiagnosticUnderlineWarn", { undercurl = true, sp = colors.yellow }) +s("DiagnosticUnderlineInfo", { undercurl = true, sp = colors.cyan }) +s("DiagnosticUnderlineHint", { undercurl = true, sp = colors.green }) + +-- Treesitter +s("@text", { fg = colors.foreground }) +s("@text.strong", { bold = true }) +s("@text.emphasis", { italic = true }) +s("@text.underline", { underline = true }) +s("@text.strike", { strikethrough = true }) +s("@text.title", { fg = colors.primary, bold = true }) +s("@text.literal", { fg = colors.green }) +s("@text.uri", { fg = colors.blue, underline = true }) +s("@comment", { fg = colors.on_surface_variant, italic = true }) +s("@punctuation.delimiter", { fg = colors.on_surface }) +s("@punctuation.bracket", { fg = colors.on_surface }) +s("@punctuation.special", { fg = colors.pink }) +s("@constant", { fg = colors.peach }) +s("@constant.builtin", { fg = colors.peach }) +s("@constant.macro", { fg = colors.yellow }) +s("@string", { fg = colors.green }) +s("@string.regex", { fg = colors.cyan }) +s("@string.escape", { fg = colors.pink }) +s("@character", { fg = colors.green }) +s("@number", { fg = colors.peach }) +s("@boolean", { fg = colors.peach }) +s("@float", { fg = colors.peach }) +s("@function", { fg = colors.blue }) +s("@function.builtin", { fg = colors.blue }) +s("@function.macro", { fg = colors.yellow }) +s("@method", { fg = colors.blue }) +s("@keyword", { fg = colors.magenta }) +s("@keyword.function", { fg = colors.magenta }) +s("@keyword.operator", { fg = colors.cyan }) +s("@operator", { fg = colors.cyan }) +s("@conditional", { fg = colors.magenta }) +s("@repeat", { fg = colors.magenta }) +s("@label", { fg = colors.yellow }) +s("@include", { fg = colors.blue }) +s("@exception", { fg = colors.red }) +s("@type", { fg = colors.yellow }) +s("@type.builtin", { fg = colors.yellow }) +s("@structure", { fg = colors.yellow }) +s("@namespace", { fg = colors.on_surface }) +s("@constructor", { fg = colors.yellow }) +s("@@variable", { fg = colors.on_surface }) +s("@variable.builtin", { fg = colors.red }) +s("@property", { fg = colors.on_surface }) +s("@field", { fg = colors.on_surface }) +s("@parameter", { fg = colors.on_surface }) +s("@tag", { fg = colors.pink }) +s("@tag.attribute", { fg = colors.on_surface }) +s("@tag.delimiter", { fg = colors.on_surface }) + +-- Git +s("DiffAdd", { bg = colors.green, fg = colors.background }) +s("DiffChange", { bg = colors.yellow, fg = colors.background }) +s("DiffDelete", { bg = colors.red, fg = colors.background }) +s("DiffText", { bg = colors.surface_container_high }) +s("GitSignsAdd", { fg = colors.green }) +s("GitSignsChange", { fg = colors.yellow }) +s("GitSignsDelete", { fg = colors.red }) + +-- Telescope +s("TelescopeNormal", { fg = colors.foreground, bg = colors.surface_container }) +s("TelescopeBorder", { fg = colors.primary, bg = colors.surface_container }) +s("TelescopePromptNormal", { fg = colors.foreground, bg = colors.surface_container_high }) +s("TelescopePromptBorder", { fg = colors.primary, bg = colors.surface_container_high }) +s("TelescopePromptTitle", { fg = colors.primary, bg = colors.surface_container_high }) +s("TelescopePreviewTitle", { fg = colors.primary, bg = colors.surface_container }) +s("TelescopeResultsTitle", { fg = colors.primary, bg = colors.surface_container }) +s("TelescopeSelection", { bg = colors.surface_container_highest }) diff --git a/src/caelestia/subcommands/neovim.py b/src/caelestia/subcommands/neovim.py new file mode 100644 index 00000000..e79ef296 --- /dev/null +++ b/src/caelestia/subcommands/neovim.py @@ -0,0 +1,33 @@ +import os +from argparse import Namespace + +from caelestia.utils.paths import neovim_colors_path, neovim_colorscheme_file, neovim_template_path +from caelestia.utils.scheme import get_scheme + + +class Command: + args: Namespace + + def __init__(self, args: Namespace) -> None: + self.args = args + + def run(self) -> None: + # 1. Get the scheme + scheme = get_scheme() + + # 2. Read the template + template_file = neovim_template_path + with open(template_file, "r") as f: + template = f.read() + + # 3. Replace placeholders + for color_name, color_value in scheme.colours.items(): + template = template.replace(f"{{{{ ${color_name} }}}}", color_value) + + # 4. Write the colorscheme + os.makedirs(neovim_colors_path, exist_ok=True) + + with open(neovim_colorscheme_file, "w") as f: + f.write(template) + + print(f"Neovim colorscheme generated at {neovim_colorscheme_file}") From 62fc2c22c36799f7090e6b01a8d83b6d5529bfba Mon Sep 17 00:00:00 2001 From: Warden Clyffe Date: Sun, 5 Oct 2025 12:50:14 +0200 Subject: [PATCH 4/5] revert changes from neovim subcommand not following expected guidelines --- src/caelestia/parser.py | 6 +----- src/caelestia/subcommands/neovim.py | 33 ----------------------------- src/caelestia/utils/paths.py | 5 ----- 3 files changed, 1 insertion(+), 43 deletions(-) delete mode 100644 src/caelestia/subcommands/neovim.py diff --git a/src/caelestia/parser.py b/src/caelestia/parser.py index a2773584..840ead5c 100644 --- a/src/caelestia/parser.py +++ b/src/caelestia/parser.py @@ -1,6 +1,6 @@ import argparse -from caelestia.subcommands import clipboard, emoji, record, resizer, scheme, screenshot, shell, toggle, wallpaper, neovim +from caelestia.subcommands import clipboard, emoji, record, resizer, scheme, screenshot, shell, toggle, wallpaper from caelestia.utils.paths import wallpapers_dir from caelestia.utils.scheme import get_scheme_names, scheme_variants from caelestia.utils.wallpaper import get_wallpaper @@ -127,8 +127,4 @@ def parse_args() -> (argparse.ArgumentParser, argparse.Namespace): resizer_parser.add_argument("height", nargs="?", help="height to resize to") resizer_parser.add_argument("actions", nargs="?", help="comma-separated actions to apply (float,center,pip)") - # Create parser for neovim opts - neovim_parser = command_parser.add_parser("neovim", help="generate a neovim colorscheme") - neovim_parser.set_defaults(cls=neovim.Command) - return parser, parser.parse_args() diff --git a/src/caelestia/subcommands/neovim.py b/src/caelestia/subcommands/neovim.py deleted file mode 100644 index e79ef296..00000000 --- a/src/caelestia/subcommands/neovim.py +++ /dev/null @@ -1,33 +0,0 @@ -import os -from argparse import Namespace - -from caelestia.utils.paths import neovim_colors_path, neovim_colorscheme_file, neovim_template_path -from caelestia.utils.scheme import get_scheme - - -class Command: - args: Namespace - - def __init__(self, args: Namespace) -> None: - self.args = args - - def run(self) -> None: - # 1. Get the scheme - scheme = get_scheme() - - # 2. Read the template - template_file = neovim_template_path - with open(template_file, "r") as f: - template = f.read() - - # 3. Replace placeholders - for color_name, color_value in scheme.colours.items(): - template = template.replace(f"{{{{ ${color_name} }}}}", color_value) - - # 4. Write the colorscheme - os.makedirs(neovim_colors_path, exist_ok=True) - - with open(neovim_colorscheme_file, "w") as f: - f.write(template) - - print(f"Neovim colorscheme generated at {neovim_colorscheme_file}") diff --git a/src/caelestia/utils/paths.py b/src/caelestia/utils/paths.py index cb8cbe68..14eb5505 100644 --- a/src/caelestia/utils/paths.py +++ b/src/caelestia/utils/paths.py @@ -40,11 +40,6 @@ recording_path = c_state_dir / "record/recording.mp4" recording_notif_path = c_state_dir / "record/notifid.txt" -neovim_config_path = config_dir / "nvim" -neovim_colors_path = neovim_config_path / "colors" -neovim_colorscheme_file = neovim_colors_path / "caelestia.lua" -neovim_template_path = templates_dir / "neovim.lua" - def compute_hash(path: Path | str) -> str: sha = hashlib.sha256() From fa9601dd295a244bd5ccdaec3bee63a83011f619 Mon Sep 17 00:00:00 2001 From: Warden Clyffe Date: Sun, 5 Oct 2025 12:51:18 +0200 Subject: [PATCH 5/5] theme: Adding neovim colorscheme generation --- src/caelestia/utils/theme.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/caelestia/utils/theme.py b/src/caelestia/utils/theme.py index d8e648d7..0fc67e8b 100644 --- a/src/caelestia/utils/theme.py +++ b/src/caelestia/utils/theme.py @@ -223,6 +223,12 @@ def apply_cava(colours: dict[str, str]) -> None: subprocess.run(["killall", "-USR2", "cava"], stderr=subprocess.DEVNULL) +@log_exception +def apply_neovim(colours: dict[str, str]) -> None: + template = gen_replace(colours, templates_dir / "neovim.lua") + write_file(config_dir / "nvim/colors/caelestia.lua", template) + + @log_exception def apply_user_templates(colours: dict[str, str]) -> None: if not user_templates_dir.is_dir(): @@ -267,4 +273,6 @@ def check(key: str) -> bool: apply_warp(colours, mode) if check("enableCava"): apply_cava(colours) + if check("enableNeovim"): + apply_neovim(colours) apply_user_templates(colours)