ghostty-bg 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,14 +1,14 @@
1
1
  # ghostty-bg (`gbg`)
2
2
 
3
- Change your terminal background color with one command.
3
+ Per-directory background colors for Ghostty one command per project.
4
4
 
5
5
  https://github.com/user-attachments/assets/28d9a5a6-a82c-4da5-b39d-c8d9bf58036f
6
6
 
7
7
  `gbg` is a tiny, zero-dependency Node CLI. It sends the standard
8
8
  [OSC 11](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html) escape
9
- sequence to recolor the current window instantly, and saves the color to
10
- Ghostty's config so it sticks across new windows and restarts no Ghostty fork
11
- or special API required.
9
+ sequence to recolor the current window instantly, and remembers the color per
10
+ directory. With the shell hook installed, `cd` into a directory and its color
11
+ is applied automatically — no Ghostty fork or special API required.
12
12
 
13
13
  ## Install
14
14
 
@@ -25,13 +25,14 @@ npx ghostty-bg --color dracula
25
25
  ## Usage
26
26
 
27
27
  ```sh
28
- gbg # random color from the built-in palette
28
+ gbg # random color, remembered for this directory
29
29
  gbg --color dracula # a named theme
30
30
  gbg --color "#1a2b3c" # a hex value (#rgb or #rrggbb)
31
31
  gbg teal # shorthand for --color
32
- gbg --no-save tomato # current window only, don't persist
33
- gbg --reset # clear the color (window + saved config)
32
+ gbg --no-save tomato # current window only, not remembered
33
+ gbg --reset # forget this directory's color, reset background
34
34
  gbg --list # list available color names
35
+ gbg shell-init # print the zsh cd hook
35
36
  gbg --help # show help
36
37
  gbg --version # show version
37
38
  ```
@@ -51,29 +52,35 @@ Short flags: `-c` (color), `-n` (no-save), `-r` (reset), `-l` (list),
51
52
  Running `gbg` with no arguments picks a random color from a curated palette of
52
53
  dark, readable backgrounds.
53
54
 
54
- ## Persistence
55
+ ## Per-directory colors
55
56
 
56
57
  By default `gbg` does two things:
57
58
 
58
59
  1. Recolors the **current window** immediately via OSC 11.
59
- 2. Saves the color so it **survives new windows and restarts**.
60
+ 2. Remembers the color for the **current directory**.
60
61
 
61
- For persistence on Ghostty, `gbg` writes `background = <color>` to a dedicated
62
- `gbg.conf` in your Ghostty config directory and adds a single
63
- `config-file = .../gbg.conf` line to your main `config` (only that one line is
64
- ever added — the color itself lives only in `gbg.conf`).
62
+ To make `cd` apply the remembered color automatically, add the hook to your
63
+ shell:
65
64
 
66
- - Already-open windows update on the spot (OSC 11). Other already-open windows
67
- pick it up after a Ghostty config reload.
68
- - New windows and restarts read it from the config.
69
- - `gbg --no-save` skips step 2 (current window only).
70
- - `gbg --reset` clears the saved color and returns to your theme default.
65
+ ```sh
66
+ echo 'eval "$(gbg shell-init)"' >> ~/.zshrc
67
+ ```
68
+
69
+ After that:
70
+
71
+ - `cd` into a remembered directory → its color is applied.
72
+ - `cd` anywhere else → the background returns to your theme default.
73
+ - `gbg --no-save` applies to the current window without remembering it.
74
+ - `gbg --reset` forgets the current directory's color.
75
+
76
+ The hook is plain zsh and reads a small `paths` file with `awk`, so it adds no
77
+ Node startup cost on `cd`. Colors are matched by exact directory.
71
78
 
72
79
  ## How It Works
73
80
 
74
- `gbg` writes `ESC ] 11 ; <color> BEL` to the terminal to set the live
75
- background, and `ESC ] 111 BEL` to reset it. Persistence is a plain
76
- `background = <color>` line in a Ghostty `config-file` include.
81
+ `gbg` writes `ESC ] 11 ; <color> BEL` to the terminal to set the background and
82
+ `ESC ] 111 BEL` to reset it. Remembered colors live in
83
+ `${XDG_CONFIG_HOME:-~/.config}/gbg/paths` as `<dir><TAB><#hex>` lines.
77
84
 
78
85
  ## Requirements
79
86
 
package/bin/gbg.js CHANGED
@@ -9,41 +9,61 @@ import {
9
9
  UnknownColorError,
10
10
  } from "../src/colors.js";
11
11
  import { setBackground, resetBackground } from "../src/terminal.js";
12
- import { saveColor, clearColor, gbgConfPath } from "../src/config.js";
12
+ import { setPathColor, clearPathColor, pathsFile } from "../src/paths.js";
13
13
 
14
14
  function readVersion() {
15
15
  const pkgPath = fileURLToPath(new URL("../package.json", import.meta.url));
16
16
  return JSON.parse(readFileSync(pkgPath, "utf8")).version;
17
17
  }
18
18
 
19
- const HELP = `gbg — change your terminal background color (Ghostty & any OSC 11 terminal)
19
+ const HELP = `gbg — per-directory background colors for Ghostty (& any OSC 11 terminal)
20
20
 
21
21
  Usage:
22
- gbg Apply a random color from the built-in palette
23
- gbg --color <name|hex> Apply a specific color (name or #hex)
22
+ gbg Apply a random color and remember it for this directory
23
+ gbg --color <name|hex> Apply a specific color (name or #hex) and remember it
24
24
  gbg <name|hex> Shorthand for --color
25
- gbg --no-save Apply to the current session only (don't persist)
26
- gbg --reset Reset the background and clear the persisted color
25
+ gbg --no-save Apply to the current window only (don't remember)
26
+ gbg --reset Forget this directory's color and reset the background
27
27
  gbg --list List available color names
28
+ gbg shell-init Print the zsh hook that switches color on cd
28
29
  gbg --help Show this help
29
30
  gbg --version Show version
30
31
 
31
32
  Examples:
32
- gbg
33
- gbg --color dracula
34
- gbg -c "#1a2b3c"
33
+ gbg --color dracula # this directory is dracula from now on
35
34
  gbg teal
36
- gbg --no-save tomato
35
+ gbg --no-save tomato # one-off, not remembered
37
36
  gbg --reset
38
37
 
38
+ Per-directory colors:
39
+ By default gbg remembers the color for the current directory. Add the cd hook
40
+ to your shell so it switches automatically:
41
+
42
+ echo 'eval "$(gbg shell-init)"' >> ~/.zshrc
43
+
44
+ Then cd into a remembered directory and its color is applied; cd elsewhere and
45
+ the background returns to your theme default.
46
+
39
47
  Colors:
40
48
  - Named themes (dracula, nord, gruvbox, tokyonight, ...)
41
49
  - CSS color names (red, teal, midnightblue, ...)
42
- - Hex: #rgb or #rrggbb (with or without the leading #)
50
+ - Hex: #rgb or #rrggbb (with or without the leading #)`;
43
51
 
44
- By default the color is applied to the current session (via OSC 11) and saved to
45
- Ghostty's config so it survives new windows and restarts. Use --no-save for a
46
- one-off change, or --reset to clear it.`;
52
+ const SHELL_INIT = `# gbg: per-directory background colors
53
+ _gbg_paths="\${XDG_CONFIG_HOME:-$HOME/.config}/gbg/paths"
54
+ _gbg_apply() {
55
+ [[ -t 1 ]] || return
56
+ local hex=""
57
+ [[ -r "$_gbg_paths" ]] && hex=$(command awk -F'\\t' -v p="$PWD" '$1==p{print $2; exit}' "$_gbg_paths")
58
+ if [[ -n "$hex" ]]; then
59
+ printf '\\033]11;%s\\007' "$hex"
60
+ else
61
+ printf '\\033]111\\007'
62
+ fi
63
+ }
64
+ autoload -Uz add-zsh-hook
65
+ add-zsh-hook chpwd _gbg_apply
66
+ _gbg_apply`;
47
67
 
48
68
  function printList() {
49
69
  const { themes, css } = colorNames();
@@ -76,6 +96,10 @@ function main() {
76
96
 
77
97
  const { values, positionals } = parsed;
78
98
 
99
+ if (positionals[0] === "shell-init") {
100
+ console.log(SHELL_INIT);
101
+ return;
102
+ }
79
103
  if (values.help) {
80
104
  console.log(HELP);
81
105
  return;
@@ -88,10 +112,22 @@ function main() {
88
112
  printList();
89
113
  return;
90
114
  }
115
+
116
+ // Match the shell's logical $PWD (which the cd hook uses) rather than the
117
+ // symlink-resolved physical path, so keys line up across symlinked dirs.
118
+ const cwd =
119
+ process.env.PWD && process.env.PWD.startsWith("/")
120
+ ? process.env.PWD
121
+ : process.cwd();
122
+
91
123
  if (values.reset) {
92
124
  resetBackground();
93
- clearColor();
94
- console.error("gbg: background reset (cleared from this session and Ghostty config)");
125
+ const had = clearPathColor(cwd);
126
+ console.error(
127
+ had
128
+ ? `gbg: forgot color for ${cwd} and reset the background`
129
+ : "gbg: background reset to theme default",
130
+ );
95
131
  return;
96
132
  }
97
133
 
@@ -116,8 +152,8 @@ function main() {
116
152
  console.error(`gbg: background → ${label}`);
117
153
 
118
154
  if (!values["no-save"]) {
119
- saveColor(result.hex);
120
- console.error(`gbg: saved to ${gbgConfPath()} (new windows & restarts; reload Ghostty config to refresh open windows)`);
155
+ setPathColor(cwd, result.hex);
156
+ console.error(`gbg: remembered for ${cwd} (applies when you cd here)`);
121
157
  }
122
158
  }
123
159
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ghostty-bg",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Change your Ghostty (or any OSC 11 terminal) background color with a single command.",
5
5
  "author": "Masa",
6
6
  "homepage": "https://github.com/MASAKASUNO1/ghostty-path-bg#readme",
package/src/paths.js ADDED
@@ -0,0 +1,47 @@
1
+ // Per-directory color memory. Stored as a simple tab-separated file
2
+ // (`<abs-dir>\t<#hex>` per line) so the zsh cd-hook can read it with awk
3
+ // without spawning Node on every directory change.
4
+ import { homedir } from "node:os";
5
+ import { join } from "node:path";
6
+ import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
7
+
8
+ function gbgDir() {
9
+ const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
10
+ return join(base, "gbg");
11
+ }
12
+
13
+ export function pathsFile() {
14
+ return join(gbgDir(), "paths");
15
+ }
16
+
17
+ function read() {
18
+ const file = pathsFile();
19
+ const map = new Map();
20
+ if (!existsSync(file)) return map;
21
+ for (const line of readFileSync(file, "utf8").split("\n")) {
22
+ if (!line) continue;
23
+ const tab = line.indexOf("\t");
24
+ if (tab < 0) continue;
25
+ map.set(line.slice(0, tab), line.slice(tab + 1));
26
+ }
27
+ return map;
28
+ }
29
+
30
+ function write(map) {
31
+ mkdirSync(gbgDir(), { recursive: true });
32
+ const body = [...map.entries()].map(([dir, hex]) => `${dir}\t${hex}`).join("\n");
33
+ writeFileSync(pathsFile(), body.length ? body + "\n" : "");
34
+ }
35
+
36
+ export function setPathColor(dir, hex) {
37
+ const map = read();
38
+ map.set(dir, hex);
39
+ write(map);
40
+ }
41
+
42
+ export function clearPathColor(dir) {
43
+ const map = read();
44
+ const had = map.delete(dir);
45
+ if (had) write(map);
46
+ return had;
47
+ }
package/src/config.js DELETED
@@ -1,57 +0,0 @@
1
- // Persist the background across Ghostty restarts and new windows.
2
- //
3
- // gbg owns a small include file (gbg.conf) and makes the main Ghostty config
4
- // load it via `config-file`. Only that one include line is ever added to the
5
- // user's config; the color itself only ever lives in gbg.conf, so gbg never
6
- // rewrites the rest of the user's configuration.
7
- import { homedir } from "node:os";
8
- import { join } from "node:path";
9
- import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
10
-
11
- function ghosttyDir() {
12
- const base = process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
13
- return join(base, "ghostty");
14
- }
15
-
16
- export function gbgConfPath() {
17
- return join(ghosttyDir(), "gbg.conf");
18
- }
19
-
20
- function mainConfigPath() {
21
- return join(ghosttyDir(), "config");
22
- }
23
-
24
- const INCLUDE_MARKER = "# gbg: persist background across Ghostty restarts";
25
-
26
- function ensureInclude() {
27
- const dir = ghosttyDir();
28
- mkdirSync(dir, { recursive: true });
29
-
30
- const main = mainConfigPath();
31
- const includeLine = `config-file = ${gbgConfPath()}`;
32
- const content = existsSync(main) ? readFileSync(main, "utf8") : "";
33
- if (content.includes(includeLine)) return;
34
-
35
- // Appended last so gbg.conf's `background` overrides any theme background.
36
- const sep = content.length && !content.endsWith("\n") ? "\n" : "";
37
- writeFileSync(main, `${content}${sep}\n${INCLUDE_MARKER}\n${includeLine}\n`);
38
- }
39
-
40
- export function saveColor(hex) {
41
- ensureInclude();
42
- const body =
43
- "# Managed by gbg — do not edit by hand.\n" +
44
- "# Set with: gbg --color <name|hex> Clear with: gbg --reset\n" +
45
- `background = ${hex}\n`;
46
- writeFileSync(gbgConfPath(), body);
47
- }
48
-
49
- export function clearColor() {
50
- // Keep the file (emptied) so the config-file include never dangles.
51
- if (!existsSync(gbgConfPath())) return;
52
- writeFileSync(
53
- gbgConfPath(),
54
- "# Managed by gbg — no persisted background (cleared).\n" +
55
- "# Set one with: gbg --color <name|hex>\n",
56
- );
57
- }