From 72af3e2cc3abd35883a4c971cd37b05fd9fbcbbf Mon Sep 17 00:00:00 2001 From: haikalllp Date: Thu, 16 Apr 2026 23:16:10 +0800 Subject: [PATCH 1/3] feat: add scripts and templates for universal terminal colors --- scripts/apply-term-colors.py | 13 ++ scripts/base-palette.json | 44 ++++ scripts/generate-term-colors.py | 357 ++++++++++++++++++++++++++++++++ scripts/windows_term_post.ps1 | 21 ++ templates/term-colors.json | 27 +++ 5 files changed, 462 insertions(+) create mode 100644 scripts/apply-term-colors.py create mode 100644 scripts/base-palette.json create mode 100755 scripts/generate-term-colors.py create mode 100644 scripts/windows_term_post.ps1 create mode 100644 templates/term-colors.json diff --git a/scripts/apply-term-colors.py b/scripts/apply-term-colors.py new file mode 100644 index 0000000..013eae1 --- /dev/null +++ b/scripts/apply-term-colors.py @@ -0,0 +1,13 @@ +import os +import subprocess +import sys + +# Resolve relative to this file's location so it works regardless of +# where the user's matugen config directory is (e.g. ~/.config/matugen +# on Unix, %APPDATA%\InioX\matugen\config on Windows). +script_dir = os.path.dirname(os.path.abspath(__file__)) +home = os.path.expanduser("~") +script = os.path.join(script_dir, "generate-term-colors.py") +colors = os.path.join(home, ".cache", "matugen", "term-colors.json") + +subprocess.run([sys.executable, script, "--colors", colors, "--apply"], check=True) diff --git a/scripts/base-palette.json b/scripts/base-palette.json new file mode 100644 index 0000000..2007501 --- /dev/null +++ b/scripts/base-palette.json @@ -0,0 +1,44 @@ +{ + "dark": { + "term0": "#282828", + "term1": "#CC241D", + "term2": "#98971A", + "term3": "#D79921", + "term4": "#458588", + "term5": "#B16286", + "term6": "#689D6A", + "term7": "#A89984", + "term8": "#928374", + "term9": "#FB4934", + "term10": "#B8BB26", + "term11": "#FABD2F", + "term12": "#83A598", + "term13": "#D3869B", + "term14": "#8EC07C", + "term15": "#EBDBB2", + "term16": "#D65D0E", + "term17": "#A89984", + "term18": "#D79921" + }, + "light": { + "term0": "#FDF9F3", + "term1": "#FF6188", + "term2": "#A9DC76", + "term3": "#FC9867", + "term4": "#FFD866", + "term5": "#F47FD4", + "term6": "#78DCE8", + "term7": "#333034", + "term8": "#121212", + "term9": "#FF6188", + "term10": "#A9DC76", + "term11": "#FC9867", + "term12": "#FFD866", + "term13": "#F47FD4", + "term14": "#78DCE8", + "term15": "#333034", + "term16": "#D65D0E", + "term17": "#A89984", + "term18": "#D79921" + } +} diff --git a/scripts/generate-term-colors.py b/scripts/generate-term-colors.py new file mode 100755 index 0000000..a4bb78b --- /dev/null +++ b/scripts/generate-term-colors.py @@ -0,0 +1,357 @@ +#!/usr/bin/env python3 +""" +Generate terminal colors from matugen output. + +Reads matugen's generated colors JSON, harmonizes a base 16-color terminal +palette toward the wallpaper accent using HCT color space, then outputs +terminal theme files + live OSC injection to running terminals. + +Terminals: + Unix: Kitty, Wezterm + Win32: Windows Terminal, Wezterm + +Usage (as matugen post_hook): + python3 generate-term-colors.py --colors ~/.cache/matugen/term-colors.json --apply + +Standalone: + python3 generate-term-colors.py --colors term-colors.json --harmony 0.8 --print +""" + +import argparse +import json +import os +import signal +import subprocess +import sys + +try: + from materialyoucolor.hct import Hct + from materialyoucolor.utils.color_utils import rgba_from_argb, argb_from_rgb + from materialyoucolor.utils.math_utils import ( + difference_degrees, + rotation_direction, + sanitize_degrees_double, + ) +except ImportError: + print( + "Error: materialyoucolor is required. Install it with: pip install materialyoucolor", + file=sys.stderr, + ) + sys.exit(1) + +IS_UNIX = sys.platform != "win32" +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +DEFAULT_PALETTE = os.path.join(SCRIPT_DIR, "base-palette.json") + +CACHE_DIR = os.path.expanduser("~/.cache/matugen") +KITTY_PATH = os.path.expanduser("~/.config/kitty/matugen.conf") +WEZTERM_PATH = os.path.expanduser("~/.config/wezterm/matugen.lua") +WINDOWS_TERM_SCHEME = os.path.join(CACHE_DIR, "windows_term.json") +WINDOWS_TERM_POST = os.path.join(SCRIPT_DIR, "windows_term_post.ps1") +SEQUENCES_PATH = os.path.join(CACHE_DIR, "sequences.txt") + + +# ── Color helpers ────────────────────────────────────────────────────── + + +def hex_to_rgb(h): + h = h.lstrip("#") + return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)) + + +def rgb_to_hex(r, g, b): + return "#{:02X}{:02X}{:02X}".format(r, g, b) + + +def hex_to_argb(h): + r, g, b = hex_to_rgb(h) + return argb_from_rgb(r, g, b) + + +def argb_to_hex(argb): + rgba = rgba_from_argb(argb) + return "#{:02X}{:02X}{:02X}".format(round(rgba[0]), round(rgba[1]), round(rgba[2])) + + +def hex_to_rgb_spec(h): + r, g, b = hex_to_rgb(h) + return f"rgb:{r:02x}/{g:02x}/{b:02x}" + + +def luminance(h): + r, g, b = hex_to_rgb(h) + return 0.2126 * r + 0.7152 * g + 0.0722 * b + + +# ── HCT harmonization ───────────────────────────────────────────────── + + +def harmonize(design_argb, source_argb, threshold, harmony): + from_hct = Hct.from_int(design_argb) + to_hct = Hct.from_int(source_argb) + diff = difference_degrees(from_hct.hue, to_hct.hue) + rot = min(diff * harmony, threshold) + out_hue = sanitize_degrees_double( + from_hct.hue + rot * rotation_direction(from_hct.hue, to_hct.hue) + ) + return Hct.from_hct(out_hue, from_hct.chroma, from_hct.tone).to_int() + + +def boost_tone(argb, factor): + hct = Hct.from_int(argb) + new_tone = max(2, min(98, hct.tone * factor)) + return Hct.from_hct(hct.hue, hct.chroma, new_tone).to_int() + + +def harmonize_palette(base, primary_hex, harmony, threshold, fg_boost, is_dark): + primary_argb = hex_to_argb(primary_hex) + colors = {} + for name, hex_val in base.items(): + h = harmonize(hex_to_argb(hex_val), primary_argb, threshold, harmony) + if name != "term0": + direction = 1 if is_dark else -1 + h = boost_tone(h, 1 + (fg_boost * direction)) + colors[name] = argb_to_hex(h) + return colors + + +# ── Terminal writers ─────────────────────────────────────────────────── + + +def write_kitty(term, mc): + os.makedirs(os.path.dirname(KITTY_PATH), exist_ok=True) + with open(KITTY_PATH, "w") as f: + f.write(f"background {term['term0']}\n") + f.write(f"foreground {term['term7']}\n") + f.write(f"cursor {term['term7']}\n") + f.write(f"cursor_text_color {term['term0']}\n") + f.write( + f"selection_background {mc.get('on_secondary_container', term['term7'])}\n" + ) + f.write( + f"selection_foreground {mc.get('secondary_container', term['term0'])}\n" + ) + for i in range(19): + f.write(f"color{i} {term[f'term{i}']}\n") + + +def write_wezterm(term, mc): + sel_bg = mc.get("on_secondary_container", term["term7"]) + sel_fg = mc.get("secondary_container", term["term0"]) + os.makedirs(os.path.dirname(WEZTERM_PATH), exist_ok=True) + with open(WEZTERM_PATH, "w") as f: + f.write("local colors = {\n") + f.write(f' foreground = "{term["term7"]}",\n') + f.write(f' background = "{term["term0"]}",\n') + f.write(f' cursor_bg = "{term["term7"]}",\n') + f.write(f' cursor_fg = "{term["term0"]}",\n') + f.write(f' selection_bg = "{sel_bg}",\n') + f.write(f' selection_fg = "{sel_fg}",\n') + f.write(" ansi = {\n") + for i in range(8): + f.write(f' "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write(" brights = {\n") + for i in range(8, 16): + f.write(f' "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write(" indexed = {\n") + for i in range(16, 19): + f.write(f' [{i}] = "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write("}\n") + f.write("return colors\n") + + +def write_windows_terminal(term, mc): + theme_name = "Matugen Colors" + scheme = { + "name": theme_name, + "black": term["term0"], + "red": term["term1"], + "green": term["term2"], + "yellow": term["term3"], + "blue": term["term4"], + "purple": term["term5"], + "cyan": term["term6"], + "white": term["term7"], + "brightBlack": term["term8"], + "brightRed": term["term9"], + "brightGreen": term["term10"], + "brightYellow": term["term11"], + "brightBlue": term["term12"], + "brightPurple": term["term13"], + "brightCyan": term["term14"], + "brightWhite": term["term15"], + "background": term["term0"], + "foreground": term["term7"], + "selectionBackground": mc.get("primary", term["term7"]), + "cursorColor": term["term7"], + } + os.makedirs(os.path.dirname(WINDOWS_TERM_SCHEME), exist_ok=True) + with open(WINDOWS_TERM_SCHEME, "w") as f: + json.dump(scheme, f, indent=4) + subprocess.run( + [ + "powershell", + "-ExecutionPolicy", + "Bypass", + "-File", + WINDOWS_TERM_POST, + "-SchemePath", + WINDOWS_TERM_SCHEME, + ], + check=True, + ) + + +# ── OSC live injection (Unix only) ──────────────────────────────────── + + +def build_osc_sequences(term, num_colors=19): + bg = hex_to_rgb_spec(term["term0"]) + fg = hex_to_rgb_spec(term["term7"]) + ESC = "\033" + ST = "\033\\" + seq = "" + seq += f"{ESC}]10;{fg}{ST}" + seq += f"{ESC}]11;{bg}{ST}" + seq += f"{ESC}]12;{fg}{ST}" + seq += f"{ESC}]17;{fg}{ST}" + for i in range(num_colors): + color = hex_to_rgb_spec(term[f"term{i}"]) + seq += f"{ESC}]4;{i};{color}{ST}" + return seq + + +def write_sequences(seq): + os.makedirs(os.path.dirname(SEQUENCES_PATH), exist_ok=True) + with open(SEQUENCES_PATH, "w") as f: + f.write(seq) + + +def apply_kitty_reload(): + try: + pids = subprocess.check_output(["pgrep", "kitty"], text=True).strip().split() + for pid in pids: + try: + os.kill(int(pid), signal.SIGUSR1) + except (OSError, ProcessLookupError): + pass + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + +def reload_all_ptys(seq): + import glob as _glob + + for tty in sorted(_glob.glob("/dev/pts/[0-9]*")): + try: + with open(tty, "w") as f: + f.write(seq) + except (OSError, PermissionError): + pass + + +# ── Main ─────────────────────────────────────────────────────────────── + + +def main(): + parser = argparse.ArgumentParser( + description="Harmonize terminal colors from matugen output" + ) + parser.add_argument( + "--colors", required=True, help="Path to matugen-generated colors JSON" + ) + parser.add_argument( + "--palette", default=DEFAULT_PALETTE, help="Path to base palette JSON" + ) + parser.add_argument( + "--harmony", type=float, default=0.8, help="Hue shift strength 0-1" + ) + parser.add_argument( + "--harmonize-threshold", + type=float, + default=100, + help="Max hue shift angle 0-180", + ) + parser.add_argument( + "--term-fg-boost", type=float, default=0.35, help="Contrast boost factor" + ) + parser.add_argument( + "--apply", action="store_true", help="Push colors to running terminals" + ) + parser.add_argument("--print", action="store_true", help="Print harmonized colors") + args = parser.parse_args() + + with open(args.colors) as f: + mc = json.load(f) + + with open(args.palette) as f: + palette = json.load(f) + + is_dark = luminance(mc.get("background", "#000000")) < 128 + mode = "dark" if is_dark else "light" + base = palette[mode] + + accent = mc.get("source_color") or mc.get("primary", "#888888") + + term = harmonize_palette( + base, + accent, + args.harmony, + args.harmonize_threshold, + args.term_fg_boost, + is_dark, + ) + + term["term0"] = mc.get("background", term["term0"]) + term["term7"] = mc.get("on_background", term["term7"]) + term["term8"] = mc.get("outline", term["term8"]) + term["term15"] = mc.get("on_surface", term["term15"]) + term["term16"] = mc.get("tertiary", term["term16"]) + term["term17"] = mc.get("on_secondary", term["term17"]) + term["term18"] = mc.get("secondary", term["term18"]) + + # Write terminal themes (platform-aware) + if IS_UNIX: + write_kitty(term, mc) + + write_wezterm(term, mc) + + if not IS_UNIX: + write_windows_terminal(term, mc) + + # Print info + if args.print: + print(f"mode: {mode}") + print(f"accent: {accent}") + print() + for name in sorted(term, key=lambda k: int(k.replace("term", ""))): + print(f" {name:8s} {term[name]}") + print() + if IS_UNIX: + print(f"kitty: {KITTY_PATH}") + else: + print(f"windows terminal: {WINDOWS_TERM_SCHEME}") + print(f"wezterm: {WEZTERM_PATH}") + + # Live injection (Unix only) + if args.apply: + seq = build_osc_sequences(term) + write_sequences(seq) + if IS_UNIX: + apply_kitty_reload() + reload_all_ptys(seq) + if args.print: + print(f"\nSequences written to {SEQUENCES_PATH}") + if IS_UNIX: + print("Apply with: cat ~/.cache/matugen/sequences.txt 2> /dev/null") + else: + print( + 'Apply with: Get-Content "$env:USERPROFILE\\.cache\\matugen\\sequences.txt" 2>$null' + ) + + +if __name__ == "__main__": + main() diff --git a/scripts/windows_term_post.ps1 b/scripts/windows_term_post.ps1 new file mode 100644 index 0000000..f9fe3b3 --- /dev/null +++ b/scripts/windows_term_post.ps1 @@ -0,0 +1,21 @@ +param( + [Parameter(Mandatory=$true)] + [string]$SchemePath +) + +$storePath = "$env:LOCALAPPDATA\Packages\Microsoft.WindowsTerminal_8wekyb3d8bbwe\LocalState\settings.json" +$standalonePath = "$env:LOCALAPPDATA\Microsoft\Windows Terminal\settings.json" + +if (Test-Path $storePath) { + $p = $storePath +} elseif (Test-Path $standalonePath) { + $p = $standalonePath +} else { + Write-Error "Windows Terminal settings not found (checked Store and standalone locations)" + exit 1 +} + +$n = Get-Content $SchemePath | ConvertFrom-Json +$s = Get-Content $p | ConvertFrom-Json +$s.schemes = @($s.schemes | Where-Object { $_.name -ne $n.name }) + $n +$s | ConvertTo-Json -Depth 10 | Set-Content $p diff --git a/templates/term-colors.json b/templates/term-colors.json new file mode 100644 index 0000000..499ee38 --- /dev/null +++ b/templates/term-colors.json @@ -0,0 +1,27 @@ +{ + "background": "{{colors.background.default.hex}}", + "on_background": "{{colors.on_background.default.hex}}", + "surface": "{{colors.surface.default.hex}}", + "on_surface": "{{colors.on_surface.default.hex}}", + "surface_variant": "{{colors.surface_variant.default.hex}}", + "on_surface_variant": "{{colors.on_surface_variant.default.hex}}", + "outline": "{{colors.outline.default.hex}}", + "outline_variant": "{{colors.outline_variant.default.hex}}", + "primary": "{{colors.primary.default.hex}}", + "on_primary": "{{colors.on_primary.default.hex}}", + "primary_container": "{{colors.primary_container.default.hex}}", + "on_primary_container": "{{colors.on_primary_container.default.hex}}", + "secondary": "{{colors.secondary.default.hex}}", + "on_secondary": "{{colors.on_secondary.default.hex}}", + "secondary_container": "{{colors.secondary_container.default.hex}}", + "on_secondary_container": "{{colors.on_secondary_container.default.hex}}", + "tertiary": "{{colors.tertiary.default.hex}}", + "on_tertiary": "{{colors.on_tertiary.default.hex}}", + "tertiary_container": "{{colors.tertiary_container.default.hex}}", + "on_tertiary_container": "{{colors.on_tertiary_container.default.hex}}", + "error": "{{colors.error.default.hex}}", + "on_error": "{{colors.on_error.default.hex}}", + "error_container": "{{colors.error_container.default.hex}}", + "on_error_container": "{{colors.on_error_container.default.hex}}", + "source_color": "{{colors.source_color.default.hex}}" +} From be770c9828856b5c1023f7a31bba23d8f1b1808e Mon Sep 17 00:00:00 2001 From: haikalllp Date: Fri, 17 Apr 2026 00:24:59 +0800 Subject: [PATCH 2/3] docs: update readme accordingly --- README.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 118 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 4cb4b64..d680edc 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,6 @@ ### Using with firefox based browsers - - - 1. Go to `about:config` and set `toolkit.legacyUserProfileCustomizations.stylesheets` to `true` 2. Find your profile directory by going to `about:support`. Under "Application Basics", find "Profile Directory" and click "Open Directory" 3. Make a folder inside of that directory called `chrome` @@ -67,6 +64,124 @@ @import url("/home/ini/.floorp/ini/chrome/websites/github.css"); @import url("/home/ini/.floorp/ini/chrome/websites/youtube.css"); ``` +## Templates for universal terminals + +Generates a harmonized 16-color terminal palette. Supports all terminals and is cross platform. + +> [!NOTE] +> Requires the `materialyoucolor` Python package: `pip install materialyoucolor` + +### Setup + +
+Unix Systems (Linux/macOS) + +Make sure to copy the following files from the `scripts/` folder to `~/.config/matugen/scripts/`: +- `apply-term-colors.py` +- `generate-term-colors.py` +- `base-palette.json` + +And then in your matugen config: +```toml +[config] +# ... + +[templates.term-colors] +input_path = './templates/term-colors.json' +output_path = '~/.cache/matugen/term-colors.json' +post_hook = 'python ~/.config/matugen/scripts/apply-term-colors.py' +``` + +
+ +
+Windows + +Make sure to copy all four scripts from the `scripts/` folder to your matugen config's `scripts/` directory: +- `apply-term-colors.py` +- `generate-term-colors.py` +- `base-palette.json` +- `windows_term_post.ps1` + +And then in your matugen config: +```toml +[config] +# ... + +[templates.term-colors] +input_path = './templates/term-colors.json' +output_path = '~/.cache/matugen/term-colors.json' +# windows must use absolute paths +post_hook = 'python C:\\Users\\user\\AppData\\Roaming\\InioX\\matugen\\config\\scripts\\apply-term-colors.py' +``` + +
+ +### Applying colors (All terminals) through terminal sequence + +
+Unix Systems (Linux/macOS) + +```bash +# in bashrc or zshrc or fish +cat ~/.cache/matugen/sequences.txt 2> /dev/null +``` + +
+ +
+Windows + +```pwsh +# in powershell profile +Get-Content "$env:USERPROFILE\.cache\matugen\sequences.txt" 2>$null +``` + +
+ +### Applying colors as a theme (Kitty, WezTerm, Windows Terminal) + +
+Kitty + +The script writes `~/.config/kitty/matugen.conf`. Add to your `kitty.conf`: + +``` +include matugen.conf +``` + +
+ +
+WezTerm + +The script writes `~/.config/wezterm/matugen.lua`. Use it in your config: + +```lua +local config = wezterm.config_builder() + +local theme = require("matugen") +config.colors = theme +config.bold_brightens_ansi_colors = false -- important to make colors properly render + +return config +``` + +
+ +
+Windows Terminal + +The PowerShell post-script automatically injects the scheme into your `settings.json`. +In your **Windows Terminal** settings simply select the "Matugen Colors" scheme and apply it as default scheme. + +
+ +### What this does: +1. Generate matugen colors as JSON via the template +2. Run the python script as posthook to generate proper terminal sequence and themes +3. Write and inject colors into running terminals + ## Templates for programs From 81d529337b0fba32770d9510679f5995b34d12c4 Mon Sep 17 00:00:00 2001 From: haikalllp Date: Fri, 15 May 2026 22:31:27 +0800 Subject: [PATCH 3/3] fixes --- README.md | 33 +- post-hook-scripts/generate-term-colors.py | 226 +++++++++++ post-hook-scripts/harmonizer.py | 134 +++++++ .../windows-term-post.ps1 | 0 scripts/apply-term-colors.py | 13 - scripts/base-palette.json | 44 --- scripts/generate-term-colors.py | 357 ------------------ 7 files changed, 378 insertions(+), 429 deletions(-) create mode 100755 post-hook-scripts/generate-term-colors.py create mode 100644 post-hook-scripts/harmonizer.py rename scripts/windows_term_post.ps1 => post-hook-scripts/windows-term-post.ps1 (100%) delete mode 100644 scripts/apply-term-colors.py delete mode 100644 scripts/base-palette.json delete mode 100755 scripts/generate-term-colors.py diff --git a/README.md b/README.md index d680edc..52fe9af 100644 --- a/README.md +++ b/README.md @@ -77,19 +77,20 @@ Generates a harmonized 16-color terminal palette. Supports all terminals and is Unix Systems (Linux/macOS) Make sure to copy the following files from the `scripts/` folder to `~/.config/matugen/scripts/`: -- `apply-term-colors.py` +- `harmonizer.py` - `generate-term-colors.py` - `base-palette.json` And then in your matugen config: ```toml -[config] -# ... - +# Universal terminal colors [templates.term-colors] -input_path = './templates/term-colors.json' -output_path = '~/.cache/matugen/term-colors.json' -post_hook = 'python ~/.config/matugen/scripts/apply-term-colors.py' +input_path = "./templates/term-colors.json" +output_path = "~/.cache/matugen/term-colors.json" +post_hook = "python ~/.config/matugen/scripts/generate-term-colors.py ~/.cache/matugen/term-colors.json" + +# Optionally you can adjust harmonization strength: +post_hook = "python ~/.config/matugen/scripts/generate-term-colors.py ~/.cache/matugen/term-colors.json --strength 0.95" ``` @@ -98,21 +99,23 @@ post_hook = 'python ~/.config/matugen/scripts/apply-term-colors.py' Windows Make sure to copy all four scripts from the `scripts/` folder to your matugen config's `scripts/` directory: -- `apply-term-colors.py` +- `harmonizer.py` - `generate-term-colors.py` - `base-palette.json` -- `windows_term_post.ps1` +- `windows-term-post.ps1` And then in your matugen config: ```toml [config] -# ... - +# Universal terminal colors [templates.term-colors] -input_path = './templates/term-colors.json' -output_path = '~/.cache/matugen/term-colors.json' -# windows must use absolute paths -post_hook = 'python C:\\Users\\user\\AppData\\Roaming\\InioX\\matugen\\config\\scripts\\apply-term-colors.py' +input_path = "./templates/term-colors.json" +output_path = "~/.cache/matugen/term-colors.json" +# windows use slight different path +post_hook = "python ~/AppData/Roaming/InioX/matugen/config/scripts/generate-term-colors.py ~/.cache/matugen/term-colors.json" + +# Optionally you can adjust harmonization strength: +post_hook = "python ~/AppData/Roaming/InioX/matugen/config/scripts/generate-term-colors.py ~/.cache/matugen/term-colors.json --strength 0.95" ``` diff --git a/post-hook-scripts/generate-term-colors.py b/post-hook-scripts/generate-term-colors.py new file mode 100755 index 0000000..f969788 --- /dev/null +++ b/post-hook-scripts/generate-term-colors.py @@ -0,0 +1,226 @@ +#!/usr/bin/env python3 +"""Generate harmonized terminal colors from matugen output.""" + +import argparse +import json +import os +import signal +import subprocess +import sys + +sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) +from harmonizer import ( + hex_to_rgb_spec, + harmonize_from_matugen, +) + +IS_UNIX = sys.platform != "win32" +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) + +CACHE_DIR = os.path.expanduser("~/.cache/matugen") +KITTY_PATH = os.path.expanduser("~/.config/kitty/matugen.conf") +WEZTERM_PATH = os.path.expanduser("~/.config/wezterm/matugen.lua") +WINDOWS_TERM_SCHEME = os.path.join(CACHE_DIR, "windows-term.json") +WINDOWS_TERM_POST = os.path.join(SCRIPT_DIR, "windows-term-post.ps1") +SEQUENCES_PATH = os.path.join(CACHE_DIR, "sequences.txt") + + +def write_kitty(term, mc): + os.makedirs(os.path.dirname(KITTY_PATH), exist_ok=True) + with open(KITTY_PATH, "w") as f: + f.write(f"background {term['term0']}\n") + f.write(f"foreground {term['term7']}\n") + f.write(f"cursor {term['term7']}\n") + f.write(f"cursor_text_color {term['term0']}\n") + f.write( + f"selection_background {mc.get('on_secondary_container', term['term7'])}\n" + ) + f.write( + f"selection_foreground {mc.get('secondary_container', term['term0'])}\n" + ) + for i in range(19): + f.write(f"color{i} {term[f'term{i}']}\n") + + f.write(f"active_tab_foreground {mc.get('surface', term['term0'])}\n") + f.write(f"active_tab_background {mc.get('primary', term['term1'])}\n") + f.write( + f"inactive_tab_foreground {mc.get('on_surface_variant', term['term8'])}\n" + ) + f.write( + f"inactive_tab_background {mc.get('surface_container', term['term0'])}\n" + ) + f.write(f"tab_bar_background {mc.get('surface', term['term0'])}\n") + + +def write_wezterm(term, mc): + sel_bg = mc.get("on_secondary_container", term["term7"]) + sel_fg = mc.get("secondary_container", term["term0"]) + os.makedirs(os.path.dirname(WEZTERM_PATH), exist_ok=True) + with open(WEZTERM_PATH, "w") as f: + f.write("local colors = {\n") + f.write(f' foreground = "{term["term7"]}",\n') + f.write(f' background = "{term["term0"]}",\n') + f.write(f' cursor_bg = "{term["term7"]}",\n') + f.write(f' cursor_fg = "{term["term0"]}",\n') + f.write(f' selection_bg = "{sel_bg}",\n') + f.write(f' selection_fg = "{sel_fg}",\n') + f.write(" ansi = {\n") + for i in range(8): + f.write(f' "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write(" brights = {\n") + for i in range(8, 16): + f.write(f' "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write(" indexed = {\n") + for i in range(16, 19): + f.write(f' [{i}] = "{term[f"term{i}"]}",\n') + f.write(" },\n") + f.write("}\n") + f.write("return colors\n") + + +def write_windows_terminal(term, mc): + theme_name = "Matugen Colors" + scheme = { + "name": theme_name, + "black": term["term0"], + "red": term["term1"], + "green": term["term2"], + "yellow": term["term3"], + "blue": term["term4"], + "purple": term["term5"], + "cyan": term["term6"], + "white": term["term7"], + "brightBlack": term["term8"], + "brightRed": term["term9"], + "brightGreen": term["term10"], + "brightYellow": term["term11"], + "brightBlue": term["term12"], + "brightPurple": term["term13"], + "brightCyan": term["term14"], + "brightWhite": term["term15"], + "background": term["term0"], + "foreground": term["term7"], + "selectionBackground": mc.get("primary", term["term7"]), + "cursorColor": term["term7"], + } + os.makedirs(os.path.dirname(WINDOWS_TERM_SCHEME), exist_ok=True) + with open(WINDOWS_TERM_SCHEME, "w") as f: + json.dump(scheme, f, indent=4) + subprocess.run( + [ + "powershell", + "-ExecutionPolicy", + "Bypass", + "-File", + WINDOWS_TERM_POST, + "-SchemePath", + WINDOWS_TERM_SCHEME, + ], + check=True, + ) + + +def build_osc_sequences(term, num_colors=19): + bg = hex_to_rgb_spec(term["term0"]) + fg = hex_to_rgb_spec(term["term7"]) + ESC = "\033" + ST = "\033\\" + seq = "" + seq += f"{ESC}]10;{fg}{ST}" + seq += f"{ESC}]11;{bg}{ST}" + seq += f"{ESC}]12;{fg}{ST}" + seq += f"{ESC}]17;{fg}{ST}" + for i in range(num_colors): + color = hex_to_rgb_spec(term[f"term{i}"]) + seq += f"{ESC}]4;{i};{color}{ST}" + return seq + + +def write_sequences(seq): + os.makedirs(os.path.dirname(SEQUENCES_PATH), exist_ok=True) + with open(SEQUENCES_PATH, "w") as f: + f.write(seq) + + +def apply_kitty_reload(): + try: + pids = subprocess.check_output(["pgrep", "kitty"], text=True).strip().split() + for pid in pids: + try: + os.kill(int(pid), signal.SIGUSR1) + except (OSError, ProcessLookupError): + pass + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + +def reload_all_ptys(seq): + import glob as _glob + + for tty in sorted(_glob.glob("/dev/pts/[0-9]*")): + try: + with open(tty, "w") as f: + f.write(seq) + except (OSError, PermissionError): + pass + + +def main(): + parser = argparse.ArgumentParser( + description="Harmonize terminal colors from matugen output" + ) + parser.add_argument("colors", help="Path to matugen-generated colors JSON") + parser.add_argument( + "--strength", + type=float, + default=0.8, + help="Harmonization strength 0.0-1.0 (default: 0.8)", + ) + args = parser.parse_args() + + term, mc, mode, accent = harmonize_from_matugen( + args.colors, + strength=args.strength, + ) + + term["term0"] = mc.get("background", term["term0"]) + term["term7"] = mc.get("on_background", term["term7"]) + + if IS_UNIX: + write_kitty(term, mc) + + if not IS_UNIX: + write_windows_terminal(term, mc) + + write_wezterm(term, mc) + + print(f"mode: {mode}") + print(f"accent: {accent}") + print() + for name in sorted(term, key=lambda k: int(k.replace("term", ""))): + print(f" {name:8s} {term[name]}") + print() + if IS_UNIX: + print(f"kitty: {KITTY_PATH}") + else: + print(f"windows terminal: {WINDOWS_TERM_SCHEME}") + print(f"wezterm: {WEZTERM_PATH}") + + seq = build_osc_sequences(term) + write_sequences(seq) + if IS_UNIX: + apply_kitty_reload() + reload_all_ptys(seq) + print(f"\nSequences written to {SEQUENCES_PATH}") + if IS_UNIX: + print("Apply with: cat ~/.cache/matugen/sequences.txt 2> /dev/null") + else: + print( + 'Apply with: Get-Content "$env:USERPROFILE\\.cache\\matugen\\sequences.txt" 2>$null' + ) + + +if __name__ == "__main__": + main() diff --git a/post-hook-scripts/harmonizer.py b/post-hook-scripts/harmonizer.py new file mode 100644 index 0000000..9345681 --- /dev/null +++ b/post-hook-scripts/harmonizer.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python3 +"""Shared HCT harmonization utilities for matugen scripts.""" + +import json + +from materialyoucolor.hct import Hct +from materialyoucolor.utils.color_utils import rgba_from_argb, argb_from_rgb +from materialyoucolor.utils.math_utils import ( + difference_degrees, + rotation_direction, + sanitize_degrees_double, +) + +DEFAULT_PALETTE = { + "dark": { + "term0": "#282828", + "term1": "#CC241D", + "term2": "#98971A", + "term3": "#D79921", + "term4": "#458588", + "term5": "#B16286", + "term6": "#689D6A", + "term7": "#A89984", + "term8": "#928374", + "term9": "#FB4934", + "term10": "#B8BB26", + "term11": "#FABD2F", + "term12": "#83A598", + "term13": "#D3869B", + "term14": "#8EC07C", + "term15": "#EBDBB2", + "term16": "#D65D0E", + "term17": "#A89984", + "term18": "#D79921", + }, + "light": { + "term0": "#FDF9F3", + "term1": "#FF6188", + "term2": "#A9DC76", + "term3": "#FC9867", + "term4": "#FFD866", + "term5": "#F47FD4", + "term6": "#78DCE8", + "term7": "#333034", + "term8": "#121212", + "term9": "#FF6188", + "term10": "#A9DC76", + "term11": "#FC9867", + "term12": "#FFD866", + "term13": "#F47FD4", + "term14": "#78DCE8", + "term15": "#333034", + "term16": "#D65D0E", + "term17": "#A89984", + "term18": "#D79921", + }, +} + + +def hex_to_rgb(h): + h = h.lstrip("#") + return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)) + + +def rgb_to_hex(r, g, b): + return "#{:02X}{:02X}{:02X}".format(r, g, b) + + +def hex_to_argb(h): + r, g, b = hex_to_rgb(h) + return argb_from_rgb(r, g, b) + + +def argb_to_hex(argb): + rgba = rgba_from_argb(argb) + return "#{:02X}{:02X}{:02X}".format(round(rgba[0]), round(rgba[1]), round(rgba[2])) + + +def hex_to_rgb_spec(h): + r, g, b = hex_to_rgb(h) + return f"rgb:{r:02x}/{g:02x}/{b:02x}" + + +def luminance(h): + r, g, b = hex_to_rgb(h) + return 0.2126 * r + 0.7152 * g + 0.0722 * b + + +def harmonize(from_hct, to_hct, tone_boost, chroma_scale=1.0, strength=0.8): + diff = difference_degrees(from_hct.hue, to_hct.hue) + rot = diff * strength + out_hue = sanitize_degrees_double( + from_hct.hue + rot * rotation_direction(from_hct.hue, to_hct.hue) + ) + out_chroma = from_hct.chroma * chroma_scale + return Hct.from_hct(out_hue, out_chroma, from_hct.tone * (1 + tone_boost)) + + +def harmonize_palette(base, primary_hex, is_dark, source_hex=None, strength=0.8): + primary_hct = Hct.from_int(hex_to_argb(primary_hex)) + if source_hex: + source_hct = Hct.from_int(hex_to_argb(source_hex)) + chroma_scale = min(primary_hct.chroma / max(source_hct.chroma, 1), 1.0) + else: + chroma_scale = 1.0 + colors = {} + for name, hex_val in base.items(): + idx = int(name.replace("term", "")) + from_hct = Hct.from_int(hex_to_argb(hex_val)) + if idx == 0: + tone_boost = 0 + else: + boost = 0.35 if idx < 8 else 0.20 + tone_boost = boost * (-1 if not is_dark else 1) + h = harmonize(from_hct, primary_hct, tone_boost, chroma_scale, strength) + colors[name] = argb_to_hex(h.to_int()) + return colors + + +def harmonize_from_matugen(colors_path, strength=0.8): + """Load matugen colors and harmonize with built-in palette.""" + with open(colors_path) as f: + mc = json.load(f) + + is_dark = luminance(mc.get("background", "#000000")) < 128 + mode = "dark" if is_dark else "light" + base = DEFAULT_PALETTE[mode] + + primary = mc.get("primary") or mc.get("source_color", "#888888") + source = mc.get("source_color") + + term = harmonize_palette(base, primary, is_dark, source, strength) + + return term, mc, mode, primary diff --git a/scripts/windows_term_post.ps1 b/post-hook-scripts/windows-term-post.ps1 similarity index 100% rename from scripts/windows_term_post.ps1 rename to post-hook-scripts/windows-term-post.ps1 diff --git a/scripts/apply-term-colors.py b/scripts/apply-term-colors.py deleted file mode 100644 index 013eae1..0000000 --- a/scripts/apply-term-colors.py +++ /dev/null @@ -1,13 +0,0 @@ -import os -import subprocess -import sys - -# Resolve relative to this file's location so it works regardless of -# where the user's matugen config directory is (e.g. ~/.config/matugen -# on Unix, %APPDATA%\InioX\matugen\config on Windows). -script_dir = os.path.dirname(os.path.abspath(__file__)) -home = os.path.expanduser("~") -script = os.path.join(script_dir, "generate-term-colors.py") -colors = os.path.join(home, ".cache", "matugen", "term-colors.json") - -subprocess.run([sys.executable, script, "--colors", colors, "--apply"], check=True) diff --git a/scripts/base-palette.json b/scripts/base-palette.json deleted file mode 100644 index 2007501..0000000 --- a/scripts/base-palette.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "dark": { - "term0": "#282828", - "term1": "#CC241D", - "term2": "#98971A", - "term3": "#D79921", - "term4": "#458588", - "term5": "#B16286", - "term6": "#689D6A", - "term7": "#A89984", - "term8": "#928374", - "term9": "#FB4934", - "term10": "#B8BB26", - "term11": "#FABD2F", - "term12": "#83A598", - "term13": "#D3869B", - "term14": "#8EC07C", - "term15": "#EBDBB2", - "term16": "#D65D0E", - "term17": "#A89984", - "term18": "#D79921" - }, - "light": { - "term0": "#FDF9F3", - "term1": "#FF6188", - "term2": "#A9DC76", - "term3": "#FC9867", - "term4": "#FFD866", - "term5": "#F47FD4", - "term6": "#78DCE8", - "term7": "#333034", - "term8": "#121212", - "term9": "#FF6188", - "term10": "#A9DC76", - "term11": "#FC9867", - "term12": "#FFD866", - "term13": "#F47FD4", - "term14": "#78DCE8", - "term15": "#333034", - "term16": "#D65D0E", - "term17": "#A89984", - "term18": "#D79921" - } -} diff --git a/scripts/generate-term-colors.py b/scripts/generate-term-colors.py deleted file mode 100755 index a4bb78b..0000000 --- a/scripts/generate-term-colors.py +++ /dev/null @@ -1,357 +0,0 @@ -#!/usr/bin/env python3 -""" -Generate terminal colors from matugen output. - -Reads matugen's generated colors JSON, harmonizes a base 16-color terminal -palette toward the wallpaper accent using HCT color space, then outputs -terminal theme files + live OSC injection to running terminals. - -Terminals: - Unix: Kitty, Wezterm - Win32: Windows Terminal, Wezterm - -Usage (as matugen post_hook): - python3 generate-term-colors.py --colors ~/.cache/matugen/term-colors.json --apply - -Standalone: - python3 generate-term-colors.py --colors term-colors.json --harmony 0.8 --print -""" - -import argparse -import json -import os -import signal -import subprocess -import sys - -try: - from materialyoucolor.hct import Hct - from materialyoucolor.utils.color_utils import rgba_from_argb, argb_from_rgb - from materialyoucolor.utils.math_utils import ( - difference_degrees, - rotation_direction, - sanitize_degrees_double, - ) -except ImportError: - print( - "Error: materialyoucolor is required. Install it with: pip install materialyoucolor", - file=sys.stderr, - ) - sys.exit(1) - -IS_UNIX = sys.platform != "win32" -SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) -DEFAULT_PALETTE = os.path.join(SCRIPT_DIR, "base-palette.json") - -CACHE_DIR = os.path.expanduser("~/.cache/matugen") -KITTY_PATH = os.path.expanduser("~/.config/kitty/matugen.conf") -WEZTERM_PATH = os.path.expanduser("~/.config/wezterm/matugen.lua") -WINDOWS_TERM_SCHEME = os.path.join(CACHE_DIR, "windows_term.json") -WINDOWS_TERM_POST = os.path.join(SCRIPT_DIR, "windows_term_post.ps1") -SEQUENCES_PATH = os.path.join(CACHE_DIR, "sequences.txt") - - -# ── Color helpers ────────────────────────────────────────────────────── - - -def hex_to_rgb(h): - h = h.lstrip("#") - return (int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)) - - -def rgb_to_hex(r, g, b): - return "#{:02X}{:02X}{:02X}".format(r, g, b) - - -def hex_to_argb(h): - r, g, b = hex_to_rgb(h) - return argb_from_rgb(r, g, b) - - -def argb_to_hex(argb): - rgba = rgba_from_argb(argb) - return "#{:02X}{:02X}{:02X}".format(round(rgba[0]), round(rgba[1]), round(rgba[2])) - - -def hex_to_rgb_spec(h): - r, g, b = hex_to_rgb(h) - return f"rgb:{r:02x}/{g:02x}/{b:02x}" - - -def luminance(h): - r, g, b = hex_to_rgb(h) - return 0.2126 * r + 0.7152 * g + 0.0722 * b - - -# ── HCT harmonization ───────────────────────────────────────────────── - - -def harmonize(design_argb, source_argb, threshold, harmony): - from_hct = Hct.from_int(design_argb) - to_hct = Hct.from_int(source_argb) - diff = difference_degrees(from_hct.hue, to_hct.hue) - rot = min(diff * harmony, threshold) - out_hue = sanitize_degrees_double( - from_hct.hue + rot * rotation_direction(from_hct.hue, to_hct.hue) - ) - return Hct.from_hct(out_hue, from_hct.chroma, from_hct.tone).to_int() - - -def boost_tone(argb, factor): - hct = Hct.from_int(argb) - new_tone = max(2, min(98, hct.tone * factor)) - return Hct.from_hct(hct.hue, hct.chroma, new_tone).to_int() - - -def harmonize_palette(base, primary_hex, harmony, threshold, fg_boost, is_dark): - primary_argb = hex_to_argb(primary_hex) - colors = {} - for name, hex_val in base.items(): - h = harmonize(hex_to_argb(hex_val), primary_argb, threshold, harmony) - if name != "term0": - direction = 1 if is_dark else -1 - h = boost_tone(h, 1 + (fg_boost * direction)) - colors[name] = argb_to_hex(h) - return colors - - -# ── Terminal writers ─────────────────────────────────────────────────── - - -def write_kitty(term, mc): - os.makedirs(os.path.dirname(KITTY_PATH), exist_ok=True) - with open(KITTY_PATH, "w") as f: - f.write(f"background {term['term0']}\n") - f.write(f"foreground {term['term7']}\n") - f.write(f"cursor {term['term7']}\n") - f.write(f"cursor_text_color {term['term0']}\n") - f.write( - f"selection_background {mc.get('on_secondary_container', term['term7'])}\n" - ) - f.write( - f"selection_foreground {mc.get('secondary_container', term['term0'])}\n" - ) - for i in range(19): - f.write(f"color{i} {term[f'term{i}']}\n") - - -def write_wezterm(term, mc): - sel_bg = mc.get("on_secondary_container", term["term7"]) - sel_fg = mc.get("secondary_container", term["term0"]) - os.makedirs(os.path.dirname(WEZTERM_PATH), exist_ok=True) - with open(WEZTERM_PATH, "w") as f: - f.write("local colors = {\n") - f.write(f' foreground = "{term["term7"]}",\n') - f.write(f' background = "{term["term0"]}",\n') - f.write(f' cursor_bg = "{term["term7"]}",\n') - f.write(f' cursor_fg = "{term["term0"]}",\n') - f.write(f' selection_bg = "{sel_bg}",\n') - f.write(f' selection_fg = "{sel_fg}",\n') - f.write(" ansi = {\n") - for i in range(8): - f.write(f' "{term[f"term{i}"]}",\n') - f.write(" },\n") - f.write(" brights = {\n") - for i in range(8, 16): - f.write(f' "{term[f"term{i}"]}",\n') - f.write(" },\n") - f.write(" indexed = {\n") - for i in range(16, 19): - f.write(f' [{i}] = "{term[f"term{i}"]}",\n') - f.write(" },\n") - f.write("}\n") - f.write("return colors\n") - - -def write_windows_terminal(term, mc): - theme_name = "Matugen Colors" - scheme = { - "name": theme_name, - "black": term["term0"], - "red": term["term1"], - "green": term["term2"], - "yellow": term["term3"], - "blue": term["term4"], - "purple": term["term5"], - "cyan": term["term6"], - "white": term["term7"], - "brightBlack": term["term8"], - "brightRed": term["term9"], - "brightGreen": term["term10"], - "brightYellow": term["term11"], - "brightBlue": term["term12"], - "brightPurple": term["term13"], - "brightCyan": term["term14"], - "brightWhite": term["term15"], - "background": term["term0"], - "foreground": term["term7"], - "selectionBackground": mc.get("primary", term["term7"]), - "cursorColor": term["term7"], - } - os.makedirs(os.path.dirname(WINDOWS_TERM_SCHEME), exist_ok=True) - with open(WINDOWS_TERM_SCHEME, "w") as f: - json.dump(scheme, f, indent=4) - subprocess.run( - [ - "powershell", - "-ExecutionPolicy", - "Bypass", - "-File", - WINDOWS_TERM_POST, - "-SchemePath", - WINDOWS_TERM_SCHEME, - ], - check=True, - ) - - -# ── OSC live injection (Unix only) ──────────────────────────────────── - - -def build_osc_sequences(term, num_colors=19): - bg = hex_to_rgb_spec(term["term0"]) - fg = hex_to_rgb_spec(term["term7"]) - ESC = "\033" - ST = "\033\\" - seq = "" - seq += f"{ESC}]10;{fg}{ST}" - seq += f"{ESC}]11;{bg}{ST}" - seq += f"{ESC}]12;{fg}{ST}" - seq += f"{ESC}]17;{fg}{ST}" - for i in range(num_colors): - color = hex_to_rgb_spec(term[f"term{i}"]) - seq += f"{ESC}]4;{i};{color}{ST}" - return seq - - -def write_sequences(seq): - os.makedirs(os.path.dirname(SEQUENCES_PATH), exist_ok=True) - with open(SEQUENCES_PATH, "w") as f: - f.write(seq) - - -def apply_kitty_reload(): - try: - pids = subprocess.check_output(["pgrep", "kitty"], text=True).strip().split() - for pid in pids: - try: - os.kill(int(pid), signal.SIGUSR1) - except (OSError, ProcessLookupError): - pass - except (subprocess.CalledProcessError, FileNotFoundError): - pass - - -def reload_all_ptys(seq): - import glob as _glob - - for tty in sorted(_glob.glob("/dev/pts/[0-9]*")): - try: - with open(tty, "w") as f: - f.write(seq) - except (OSError, PermissionError): - pass - - -# ── Main ─────────────────────────────────────────────────────────────── - - -def main(): - parser = argparse.ArgumentParser( - description="Harmonize terminal colors from matugen output" - ) - parser.add_argument( - "--colors", required=True, help="Path to matugen-generated colors JSON" - ) - parser.add_argument( - "--palette", default=DEFAULT_PALETTE, help="Path to base palette JSON" - ) - parser.add_argument( - "--harmony", type=float, default=0.8, help="Hue shift strength 0-1" - ) - parser.add_argument( - "--harmonize-threshold", - type=float, - default=100, - help="Max hue shift angle 0-180", - ) - parser.add_argument( - "--term-fg-boost", type=float, default=0.35, help="Contrast boost factor" - ) - parser.add_argument( - "--apply", action="store_true", help="Push colors to running terminals" - ) - parser.add_argument("--print", action="store_true", help="Print harmonized colors") - args = parser.parse_args() - - with open(args.colors) as f: - mc = json.load(f) - - with open(args.palette) as f: - palette = json.load(f) - - is_dark = luminance(mc.get("background", "#000000")) < 128 - mode = "dark" if is_dark else "light" - base = palette[mode] - - accent = mc.get("source_color") or mc.get("primary", "#888888") - - term = harmonize_palette( - base, - accent, - args.harmony, - args.harmonize_threshold, - args.term_fg_boost, - is_dark, - ) - - term["term0"] = mc.get("background", term["term0"]) - term["term7"] = mc.get("on_background", term["term7"]) - term["term8"] = mc.get("outline", term["term8"]) - term["term15"] = mc.get("on_surface", term["term15"]) - term["term16"] = mc.get("tertiary", term["term16"]) - term["term17"] = mc.get("on_secondary", term["term17"]) - term["term18"] = mc.get("secondary", term["term18"]) - - # Write terminal themes (platform-aware) - if IS_UNIX: - write_kitty(term, mc) - - write_wezterm(term, mc) - - if not IS_UNIX: - write_windows_terminal(term, mc) - - # Print info - if args.print: - print(f"mode: {mode}") - print(f"accent: {accent}") - print() - for name in sorted(term, key=lambda k: int(k.replace("term", ""))): - print(f" {name:8s} {term[name]}") - print() - if IS_UNIX: - print(f"kitty: {KITTY_PATH}") - else: - print(f"windows terminal: {WINDOWS_TERM_SCHEME}") - print(f"wezterm: {WEZTERM_PATH}") - - # Live injection (Unix only) - if args.apply: - seq = build_osc_sequences(term) - write_sequences(seq) - if IS_UNIX: - apply_kitty_reload() - reload_all_ptys(seq) - if args.print: - print(f"\nSequences written to {SEQUENCES_PATH}") - if IS_UNIX: - print("Apply with: cat ~/.cache/matugen/sequences.txt 2> /dev/null") - else: - print( - 'Apply with: Get-Content "$env:USERPROFILE\\.cache\\matugen\\sequences.txt" 2>$null' - ) - - -if __name__ == "__main__": - main()