Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
124 changes: 121 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down Expand Up @@ -67,6 +64,127 @@
@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

<details>
<summary>Unix Systems (Linux/macOS)</summary>

Make sure to copy the following files from the `scripts/` folder to `~/.config/matugen/scripts/`:
- `harmonizer.py`
- `generate-term-colors.py`
- `base-palette.json`

And then in your matugen config:
```toml
# 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/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"
```

</details>

<details>
<summary>Windows</summary>

Make sure to copy all four scripts from the `scripts/` folder to your matugen config's `scripts/` directory:
- `harmonizer.py`
- `generate-term-colors.py`
- `base-palette.json`
- `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 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"
```

</details>

### Applying colors (All terminals) through terminal sequence

<details>
<summary>Unix Systems (Linux/macOS)</summary>

```bash
# in bashrc or zshrc or fish
cat ~/.cache/matugen/sequences.txt 2> /dev/null
```

</details>

<details>
<summary>Windows</summary>

```pwsh
# in powershell profile
Get-Content "$env:USERPROFILE\.cache\matugen\sequences.txt" 2>$null
```

</details>

### Applying colors as a theme (Kitty, WezTerm, Windows Terminal)

<details>
<summary>Kitty</summary>

The script writes `~/.config/kitty/matugen.conf`. Add to your `kitty.conf`:

```
include matugen.conf
```

</details>

<details>
<summary>WezTerm</summary>

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
```

</details>

<details>
<summary>Windows Terminal</summary>

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.

</details>

### 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

Expand Down
226 changes: 226 additions & 0 deletions post-hook-scripts/generate-term-colors.py
Original file line number Diff line number Diff line change
@@ -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()
Loading