diff --git a/docs/meta-configs.md b/docs/meta-configs.md new file mode 100644 index 0000000..ae79416 --- /dev/null +++ b/docs/meta-configs.md @@ -0,0 +1,98 @@ +# Meta-Configs Pattern + +This repository uses a **meta-config pattern** for configuration files that drive imperative actions during `chezmoi apply`, rather than being deployed directly to the filesystem. + +## What are Meta-Configs? + +Meta-configs are configuration files that: + +1. **Are NOT deployed** to the target system +2. **Drive scripts** that perform imperative actions (downloads, installations, modifications) +3. **Live in `meta/`** at the repository root (outside `home/`) +4. **Trigger `run_onchange_*` scripts** when their content changes + +This pattern separates "what to configure" from "configuration files that get deployed." + +## Directory Structure + +``` +chezmoi/ +├── meta/ # Meta-configs (NOT deployed) +│ ├── fonts.toml # Drives font installation +│ └── ... # Future meta-configs +├── home/ # Deployed to $HOME +│ ├── .config/ +│ ├── .local/ +│ └── ... +└── docs/ + └── meta-configs.md # This file +``` + +## Current Meta-Configs + +### `meta/fonts.toml` + +Drives the `install-fonts.ts` script to download and install fonts. + +```toml +[ui] +primary = "Inter" +fallback = "Noto Sans" + +[mono] +primary = "Geist Mono" +fallback = "JetBrains Mono" + +[extras] +# Fonts to install without category assignment +fonts = ["ZedMono NF"] +``` + +**Triggered by:** `run_onchange_after_install-fonts.sh.tmpl` + +**Script:** `~/.local/bin/install-fonts.ts` + +## How It Works + +1. Edit a meta-config in `meta/` (e.g., `meta/fonts.toml`) +2. Run `chezmoi apply` +3. Chezmoi detects the file changed via `{{ include "../meta/fonts.toml" | sha256sum }}` +4. The corresponding `run_onchange_*` script executes +5. The script reads the meta-config and performs imperative actions + +## Why This Pattern? + +### Problem + +Some configuration requires imperative actions: +- Downloading files from the internet +- Installing packages +- Modifying system state + +These don't fit the declarative "deploy this file" model of chezmoi. + +### Solution + +Meta-configs provide: +- **Centralized configuration** - Easy to edit, version-controlled +- **Imperative execution** - Scripts perform the actual work +- **Change detection** - `run_onchange_*` only runs when config changes +- **Clear separation** - Meta-configs are clearly not "files to deploy" + +## Adding a New Meta-Config + +1. Create `meta/.toml` with your configuration schema +2. Create a script in `home/dot_local/bin/` to process the config +3. Create `home/run_onchange_after_.sh.tmpl` that: + - Includes a hash comment: `# hash: {{ include "../meta/.toml" | sha256sum }}` + - Calls your processing script +4. Document the meta-config in this file + +## Comparison with `.managed/` + +| Aspect | `meta/` | `.managed/` | +| ------------ | ---------------------------------- | --------------------------------------- | +| Deployed | No | Yes (via symlinks) | +| Purpose | Drive imperative scripts | Source of truth for app configs | +| Consumed by | Chezmoi scripts | Applications (via symlinks) | +| Location | Repo root | Inside `home/` | diff --git a/home/.managed/zed/keymap.linux.json b/home/.managed/zed/keymap.linux.json index b7c1be6..88306f1 100644 --- a/home/.managed/zed/keymap.linux.json +++ b/home/.managed/zed/keymap.linux.json @@ -10,24 +10,38 @@ "context": "Workspace", "bindings": { // "shift shift": "file_finder::Toggle" - } + }, }, { "context": "Editor && vim_mode == insert", "bindings": { - // "j k": "vim::NormalBefore" - } + "j k": "vim::NormalBefore", + }, }, { "context": "Editor", "bindings": { - "alt-pageup": "editor::HalfPageUp" - } + "alt-pageup": "editor::HalfPageUp", + }, }, { "context": "Editor", "bindings": { - "alt-pagedown": "editor::HalfPageDown" - } - } + "alt-pagedown": "editor::HalfPageDown", + }, + }, + { + "context": "Workspace", + "bindings": { + "ctrl-tab": "pane::ActivateNextItem", + "ctrl-shift-tab": "pane::ActivatePreviousItem", + }, + }, + { + "context": "Editor", + "bindings": { + "ctrl-alt-left": "pane::SwapItemLeft", + "ctrl-alt-right": "pane::SwapItemRight", + }, + }, ] diff --git a/home/.managed/zed/settings.linux.json b/home/.managed/zed/settings.linux.json index 873c337..259c8fa 100644 --- a/home/.managed/zed/settings.linux.json +++ b/home/.managed/zed/settings.linux.json @@ -7,12 +7,19 @@ // custom settings, run `zed: open default settings` from the // command palette (cmd-shift-p / ctrl-shift-p) { - "base_keymap": "Cursor", + "vim_mode": false, + "icon_theme": "Material Icon Theme", + "use_system_path_prompts": false, + "base_keymap": "VSCode", "ui_font_size": 16, "buffer_font_size": 15, + "auto_signature_help": false, "theme": { - "mode": "dark", + "mode": "light", "light": "One Light", - "dark": "Gruvbox Dark Hard" + "dark": "Min Dark (Blurred)" + }, + "terminal": { + "font_family": "ZedMono Nerd Font" } } diff --git a/home/dot_config/fontconfig/fonts.toml b/home/dot_config/fontconfig/fonts.toml deleted file mode 100644 index fbd6d83..0000000 --- a/home/dot_config/fontconfig/fonts.toml +++ /dev/null @@ -1,31 +0,0 @@ -# Font Configuration for Chezmoi -# This file defines which fonts to install and configure. -# Fonts are sourced from Google Fonts automatically. -# -# To add a font: Just type its name - fuzzy matching will help if you misspell. -# To swap fonts: Change the primary, run `chezmoi apply`, done! -# -# Run `install-fonts.ts` manually to see available fonts or troubleshoot. - -[ui] -# Sans-serif fonts for user interface elements -primary = "Inter" -fallback = "Noto Sans" - -[serif] -# Serif fonts for documents and reading -primary = "Source Serif 4" -fallback = "Noto Serif" - -[mono] -# Monospace fonts for code and terminals -primary = "Geist Mono" -fallback = "JetBrains Mono" - -[emoji] -# Emoji font for unicode emoji support -primary = "Noto Color Emoji" - -# Optional: Uncomment to install accessibility-focused fonts -# [accessibility] -# primary = "Atkinson Hyperlegible" diff --git a/home/dot_local/bin/executable_install-fonts.ts b/home/dot_local/bin/executable_install-fonts.ts index 3e0097f..f2f4112 100644 --- a/home/dot_local/bin/executable_install-fonts.ts +++ b/home/dot_local/bin/executable_install-fonts.ts @@ -49,11 +49,14 @@ interface FontDetails extends GoogleFont { variants: FontVariant[]; } +interface FontCategoryConfig { + primary: string; + fallback?: string; +} + interface FontConfig { - [category: string]: { - primary: string; - fallback?: string; - }; + categories: Record; + extras: string[]; } interface FuseResult { @@ -67,7 +70,8 @@ interface FuseResult { // ============================================================================ const FONTS_DIR = join(homedir(), ".local", "share", "fonts"); -const CONFIG_PATH = join(homedir(), ".config", "fontconfig", "fonts.toml"); +// Meta-config location: chezmoi source dir, not deployed to filesystem +const CONFIG_PATH = join(homedir(), ".local", "share", "chezmoi", "meta", "fonts.toml"); const API_BASE = "https://gwfh.mranftl.com/api"; const CACHE_FILE = join(homedir(), ".cache", "font-catalog.json"); const CACHE_MAX_AGE_MS = 7 * 24 * 60 * 60 * 1000; // 7 days @@ -81,6 +85,10 @@ interface GitHubFontConfig { } const GITHUB_FONTS: Record = { + "ZedMono NF": { + repo: "ryanoasis/nerd-fonts", + assetPattern: /^ZedMono\.zip$/, + }, Iosevka: { repo: "be5invis/Iosevka", assetPattern: /^PkgTTF-Iosevka-[\d.]+\.zip$/, @@ -517,7 +525,7 @@ async function loadConfig(): Promise { const content = await Bun.file(CONFIG_PATH).text(); // Simple TOML parser for our specific format - const config: FontConfig = {}; + const config: FontConfig = { categories: {}, extras: [] }; let currentSection = ""; for (const line of content.split("\n")) { @@ -530,16 +538,33 @@ async function loadConfig(): Promise { const sectionMatch = trimmed.match(/^\[(\w+)\]$/); if (sectionMatch) { currentSection = sectionMatch[1]; - config[currentSection] = { primary: "" }; + if (currentSection !== "extras") { + config.categories[currentSection] = { primary: "" }; + } continue; } - // Key-value pair + // Handle [extras] section - array of fonts + if (currentSection === "extras") { + // Match: fonts = ["Font1", "Font2"] + const arrayMatch = trimmed.match(/^fonts\s*=\s*\[(.*)\]$/); + if (arrayMatch) { + const arrayContent = arrayMatch[1]; + // Parse quoted strings from array + const fontMatches = arrayContent.matchAll(/"([^"]+)"/g); + for (const match of fontMatches) { + config.extras.push(match[1]); + } + } + continue; + } + + // Key-value pair for category sections const kvMatch = trimmed.match(/^(\w+)\s*=\s*"([^"]+)"$/); - if (kvMatch && currentSection) { + if (kvMatch && currentSection && currentSection !== "extras") { const [, key, value] = kvMatch; if (key === "primary" || key === "fallback") { - config[currentSection][key] = value; + config.categories[currentSection][key] = value; } } } @@ -630,13 +655,16 @@ async function installFromConfig(): Promise { mkdirSync(FONTS_DIR, { recursive: true }); } - // Collect all fonts to install + // Collect all fonts to install from categories const fontsToInstall: string[] = []; - for (const category of Object.values(config)) { + for (const category of Object.values(config.categories)) { if (category.primary) fontsToInstall.push(category.primary); if (category.fallback) fontsToInstall.push(category.fallback); } + // Add extras + fontsToInstall.push(...config.extras); + // Remove duplicates const uniqueFonts = [...new Set(fontsToInstall)]; diff --git a/home/run_onchange_after_install-fonts.sh.tmpl b/home/run_onchange_after_install-fonts.sh.tmpl index d2a685b..dee6149 100644 --- a/home/run_onchange_after_install-fonts.sh.tmpl +++ b/home/run_onchange_after_install-fonts.sh.tmpl @@ -1,9 +1,9 @@ {{ if eq .chezmoi.os "linux" -}} #!/bin/bash # Font Installer Hook -# Runs automatically when fonts.toml changes +# Runs automatically when meta/fonts.toml changes # -# fonts.toml hash: {{ include "dot_config/fontconfig/fonts.toml" | sha256sum }} +# fonts.toml hash: {{ include "../meta/fonts.toml" | sha256sum }} set -eu diff --git a/meta/fonts.toml b/meta/fonts.toml new file mode 100644 index 0000000..eaea280 --- /dev/null +++ b/meta/fonts.toml @@ -0,0 +1,35 @@ +# Font Installation Meta-Config +# +# This file drives the install-fonts.ts script. +# It is NOT deployed to the filesystem. +# +# Fonts are sourced from: +# - Google Fonts (via google-webfonts-helper API) +# - GitHub releases (for fonts like Iosevka, ZedMono NF) +# +# Run `install-fonts.ts --help` for manual usage. +# Run `install-fonts.ts --search ` to find fonts. + +[ui] +# Sans-serif fonts for user interface elements +primary = "Inter" +fallback = "Noto Sans" + +[serif] +# Serif fonts for documents and reading +primary = "Source Serif 4" +fallback = "Noto Serif" + +[mono] +# Monospace fonts for code and terminals +primary = "Geist Mono" +fallback = "JetBrains Mono" + +[emoji] +# Emoji font for unicode emoji support +primary = "Noto Color Emoji" + +[extras] +# Additional fonts to install without category assignment +# Useful for fonts needed by specific applications +fonts = ["ZedMono NF"]