Skip to content

Architecture

alsi-lawr edited this page Jul 16, 2026 · 3 revisions

Architecture

Neotheme separates theme data, semantic palette roles, highlight definitions, plugin integrations, session state, commands, and browser UI into distinct layers.

Baseline resolution and load flow

setup(options)
  -> validate and merge with defaults
  -> copy the selected built-in palette, or create empty custom categories
  -> run configure_palette
  -> validate supplied categories, fields, and colors
  -> warn about missing semantic roles
  -> store private configured and resolved palette copies

colorscheme neotheme / load()
  -> prepare the configured baseline
  -> check Neovim version
  -> set background and termguicolors
  -> apply core, Tree-sitter, LSP, diagnostic, and terminal layers
  -> apply enabled integrations
  -> invalidate cached Lualine adapters
  -> create colorscheme lifecycle and sidebar autocmds
  -> commit applied state and clear the session override

Session switch and browser preview flow

switch(theme) / browser confirmation
  -> copy the latest configured options
  -> replace only the theme name
  -> resolve a fresh built-in palette
  -> run the same apply pipeline
  -> commit applied state with an override marker when it differs from the baseline

browser row movement
  -> prepare the selected built-in with the latest configured typography and palette callback
  -> apply core, Tree-sitter, LSP, and diagnostic groups to the preview highlight namespace
  -> leave global state, background, terminal colors, integrations, and Lualine caches unchanged

reset() prepares and applies the configured baseline. reload() prepares the active override or configured theme from a fresh base and reapplies it.

Module layout

Path Responsibility
plugin/neotheme.lua User-command registration
colors/neotheme.lua Single colorscheme entrypoint
lua/neotheme/init.lua Public API, baseline and applied state, application lifecycle, and exact restoration
lua/neotheme/browser.lua Family-first floating browser, isolated previews, motion policies, confirmation checkpoints, resize handling, and cleanup
lua/neotheme/commands.lua Command definitions, output, validation, and completion
lua/neotheme/config.lua Defaults, option validation, deep merge, and copy isolation
lua/neotheme/palette.lua Complete semantic schema, palette validation, and missing-role detection
lua/neotheme/themes/init.lua Built-in registry, family and background metadata, and theme copies
lua/neotheme/themes/simplified.lua Family-neutral compact-to-semantic transform
lua/neotheme/themes/<family>/ Raw built-in theme colors
lua/neotheme/highlights/ Core, Tree-sitter, LSP, terminal, and apply utilities
lua/neotheme/integrations/ Opt-in plugin highlight definitions
lua/neotheme/lualine.lua Lualine theme generated from the resolved palette
lua/lualine/themes/neotheme.lua Lualine discovery adapter

State model

Neotheme keeps separate configured and applied state:

  • The configured baseline contains the latest successful setup options and palette.
  • Applied state records the theme, options, and palette currently visible in Neovim.
  • An override marker identifies a session switch away from the baseline.
  • A baseline-applied marker distinguishes a fully applied setup from configuration prepared while an older palette remains visible.

This separation lets current() report active and configured themes independently, lets reset restore the complete baseline, and lets browser confirmation advance a private cancellation checkpoint without making row navigation public state.

Data ownership and copies

Neotheme isolates registry, configuration, palette, and public state from caller mutation:

  • Theme registry lookup returns a deep copy.
  • configure_palette receives a copied selected palette.
  • Configured, resolved, and applied palettes are copied before storage.
  • palette() and current() return defensive copies.
  • themes() and families() return new sorted lists.

Browser transactions

The browser snapshots applied state before creating UI resources and assigns a private highlight namespace to the preview window. Family movement changes only selection metadata. Theme movement prepares the palette and applies core, Tree-sitter, LSP, and diagnostic groups only in that namespace. Interpolation and winblend transitions carry generation tokens so superseded or stale callbacks cannot modify a newer selection or a closed browser.

Enter confirms through the public switch pipeline and closes. Space confirms through the same pipeline, keeps the browser open, and replaces the cancellation checkpoint. Cancellation restores the latest checkpoint without rerunning configure_palette, then deletes browser windows, buffers, diagnostics, and autocmds.

The browser owns a separate NeothemeBrowser augroup for:

  • ColorScheme highlight refresh
  • CursorMoved selection and preview handling
  • VimResized layout recalculation
  • WinClosed and BufWipeout cancellation

Resize failures and layouts below 64 columns by 18 usable rows cancel transactionally rather than leaving partial UI or preview state.

Highlight layers

The application pipeline uses this order:

  1. Core Vim syntax and editor UI groups
  2. Tree-sitter captures
  3. LSP semantic tokens and diagnostics
  4. Terminal color globals
  5. Enabled plugin integrations

Every layer consumes semantic palette roles. Raw color literals belong in theme definitions, not highlight modules.

Colorscheme lifecycle

Neotheme owns an augroup named Neotheme.

  • ColorSchemePre removes Neotheme's lifecycle autocmds before another colorscheme loads.
  • FileType applies sidebar window highlights to help and quickfix buffers.

Every load, confirmed switch, reset, reload, or restoration clears and recreates this augroup, preventing duplicate handlers.

Built-in and custom theme paths

A built-in theme is resolved from the private registry and copied. A custom theme starts with the same seven category tables but no values. Both paths then pass through configure_palette, validation, missing-role detection, and copy isolation.

Named session switching excludes custom themes because their palette is defined by setup-time user code rather than a reconstructable registry entry.

Clone this wiki locally