ghostty-bg 0.1.0 → 0.2.1
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/LICENSE +21 -0
- package/README.md +60 -47
- package/bin/gbg.js +60 -18
- package/package.json +1 -1
- package/src/paths.js +51 -0
- package/src/config.js +0 -57
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Masa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,81 +1,94 @@
|
|
|
1
1
|
# ghostty-bg (`gbg`)
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
ディレクトリごとに Ghostty の背景色を切り替える小さな CLI。プロジェクトごとに 1 コマンド。
|
|
4
4
|
|
|
5
5
|
https://github.com/user-attachments/assets/28d9a5a6-a82c-4da5-b39d-c8d9bf58036f
|
|
6
6
|
|
|
7
|
-
`gbg`
|
|
8
|
-
[OSC 11](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
`gbg` は依存ゼロの小さな Node 製 CLI です。標準の
|
|
8
|
+
[OSC 11](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html) エスケープ
|
|
9
|
+
シーケンスを送って現在のウィンドウの背景色を即座に変え、その色を**ディレクトリ
|
|
10
|
+
ごとに記憶**します。シェルフックを入れておけば、`cd` でそのディレクトリの色が
|
|
11
|
+
自動で適用されます。Ghostty の fork や特別な API は不要です。
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
> [!TIP]
|
|
14
|
+
> セットアップを自分でやらずに済ませたい場合は、この README をそのまま
|
|
15
|
+
> Claude Code や Codex などのコーディングエージェントに渡して
|
|
16
|
+
> 「この README の通りに gbg をインストールして設定して」と頼んでください。
|
|
17
|
+
> インストールから zsh フックの追加まで代わりにやってくれます。
|
|
18
|
+
|
|
19
|
+
## インストール
|
|
14
20
|
|
|
15
21
|
```sh
|
|
16
22
|
npm install -g ghostty-bg
|
|
17
23
|
```
|
|
18
24
|
|
|
19
|
-
|
|
25
|
+
インストールせずに試す場合:
|
|
20
26
|
|
|
21
27
|
```sh
|
|
22
28
|
npx ghostty-bg --color dracula
|
|
23
29
|
```
|
|
24
30
|
|
|
25
|
-
##
|
|
31
|
+
## 使い方
|
|
26
32
|
|
|
27
33
|
```sh
|
|
28
|
-
gbg #
|
|
29
|
-
gbg --color dracula #
|
|
30
|
-
gbg --color "#1a2b3c" #
|
|
31
|
-
gbg teal #
|
|
32
|
-
gbg --no-save tomato #
|
|
33
|
-
gbg --reset #
|
|
34
|
-
gbg --list #
|
|
35
|
-
gbg
|
|
36
|
-
gbg --
|
|
34
|
+
gbg # パレットからランダムに選び、このディレクトリに記憶
|
|
35
|
+
gbg --color dracula # 名前付きテーマ
|
|
36
|
+
gbg --color "#1a2b3c" # HEX 値 (#rgb または #rrggbb)
|
|
37
|
+
gbg teal # --color の短縮形
|
|
38
|
+
gbg --no-save tomato # 現在のウィンドウのみ(記憶しない)
|
|
39
|
+
gbg --reset # このディレクトリの色を忘れて背景をリセット
|
|
40
|
+
gbg --list # 利用可能な色名の一覧
|
|
41
|
+
gbg shell-init # zsh の cd フックを出力
|
|
42
|
+
gbg --help # ヘルプ
|
|
43
|
+
gbg --version # バージョン
|
|
37
44
|
```
|
|
38
45
|
|
|
39
|
-
|
|
40
|
-
`-h` (help), `-v` (version)
|
|
46
|
+
短縮フラグ: `-c` (color), `-n` (no-save), `-r` (reset), `-l` (list),
|
|
47
|
+
`-h` (help), `-v` (version)。
|
|
48
|
+
|
|
49
|
+
## 色の指定
|
|
50
|
+
|
|
51
|
+
`--color` は 3 種類の値を受け付けます。
|
|
41
52
|
|
|
42
|
-
|
|
53
|
+
- **名前付きテーマ** — `dracula`, `nord`, `gruvbox`, `tokyonight`,
|
|
54
|
+
`catppuccin`, `solarized`, `github-dark` など約 40 種類。`gbg --list` で確認。
|
|
55
|
+
- **CSS 色名** — `red`, `teal`, `midnightblue`, `rebeccapurple` など。
|
|
56
|
+
- **HEX** — `#rgb` または `#rrggbb`(先頭の `#` は省略可)。
|
|
43
57
|
|
|
44
|
-
|
|
58
|
+
引数なしの `gbg` は、読みやすい暗色のパレットからランダムに 1 色を選びます。
|
|
45
59
|
|
|
46
|
-
|
|
47
|
-
`catppuccin`, `solarized`, `github-dark`, and ~40 more. Run `gbg --list`.
|
|
48
|
-
- **CSS color names** — `red`, `teal`, `midnightblue`, `rebeccapurple`, ...
|
|
49
|
-
- **Hex** — `#rgb` or `#rrggbb`, with or without the leading `#`.
|
|
60
|
+
## ディレクトリごとの色
|
|
50
61
|
|
|
51
|
-
|
|
52
|
-
dark, readable backgrounds.
|
|
62
|
+
デフォルトで `gbg` は次の 2 つを行います。
|
|
53
63
|
|
|
54
|
-
|
|
64
|
+
1. 現在のウィンドウの背景色を OSC 11 で即座に変更する。
|
|
65
|
+
2. その色を**現在のディレクトリ**に記憶する。
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
`cd` で記憶した色を自動適用するには、シェルにフックを追加します。
|
|
68
|
+
|
|
69
|
+
```sh
|
|
70
|
+
grep -q 'gbg shell-init' ~/.zshrc || echo 'eval "$(gbg shell-init)"' >> ~/.zshrc
|
|
71
|
+
```
|
|
57
72
|
|
|
58
|
-
|
|
59
|
-
2. Saves the color so it **survives new windows and restarts**.
|
|
73
|
+
追加後の挙動:
|
|
60
74
|
|
|
61
|
-
|
|
62
|
-
`
|
|
63
|
-
|
|
64
|
-
|
|
75
|
+
- 記憶済みのディレクトリに `cd` する → その色が適用される。
|
|
76
|
+
- それ以外の場所に `cd` する → 背景がテーマの既定色に戻る。
|
|
77
|
+
- `gbg --no-save` は記憶せず、現在のウィンドウにだけ適用する。
|
|
78
|
+
- `gbg --reset` は現在のディレクトリの色を忘れる。
|
|
65
79
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
- `gbg --no-save` skips step 2 (current window only).
|
|
70
|
-
- `gbg --reset` clears the saved color and returns to your theme default.
|
|
80
|
+
フックは純粋な zsh で、小さな `paths` ファイルを `awk` で読むだけなので、`cd`
|
|
81
|
+
ごとに Node を起動するコストはかかりません。色は**ディレクトリの完全一致**で
|
|
82
|
+
照合されます。
|
|
71
83
|
|
|
72
|
-
##
|
|
84
|
+
## 仕組み
|
|
73
85
|
|
|
74
|
-
`gbg`
|
|
75
|
-
|
|
76
|
-
`
|
|
86
|
+
`gbg` は背景設定に `ESC ] 11 ; <色> BEL`、リセットに `ESC ] 111 BEL` を
|
|
87
|
+
ターミナルへ書き込みます。記憶した色は
|
|
88
|
+
`${XDG_CONFIG_HOME:-~/.config}/gbg/paths` に `<ディレクトリ><TAB><#hex>` の
|
|
89
|
+
行として保存されます。
|
|
77
90
|
|
|
78
|
-
##
|
|
91
|
+
## 必要環境
|
|
79
92
|
|
|
80
93
|
- Node.js >= 18
|
|
81
|
-
-
|
|
94
|
+
- OSC 11 に対応したターミナル(Ghostty, iTerm2 など大半のモダンターミナル)
|
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 {
|
|
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 —
|
|
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
|
|
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
|
|
26
|
-
gbg --reset
|
|
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
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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,25 @@ 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) {
|
|
124
|
+
if (values.color || positionals[0]) {
|
|
125
|
+
console.error("gbg: --reset ignores any color argument");
|
|
126
|
+
}
|
|
92
127
|
resetBackground();
|
|
93
|
-
|
|
94
|
-
console.error(
|
|
128
|
+
const had = clearPathColor(cwd);
|
|
129
|
+
console.error(
|
|
130
|
+
had
|
|
131
|
+
? `gbg: forgot color for ${cwd} and reset the background`
|
|
132
|
+
: "gbg: background reset to theme default",
|
|
133
|
+
);
|
|
95
134
|
return;
|
|
96
135
|
}
|
|
97
136
|
|
|
@@ -116,8 +155,11 @@ function main() {
|
|
|
116
155
|
console.error(`gbg: background → ${label}`);
|
|
117
156
|
|
|
118
157
|
if (!values["no-save"]) {
|
|
119
|
-
|
|
120
|
-
|
|
158
|
+
if (setPathColor(cwd, result.hex)) {
|
|
159
|
+
console.error(`gbg: remembered for ${cwd} (applies when you cd here)`);
|
|
160
|
+
} else {
|
|
161
|
+
console.error("gbg: applied but not remembered (path contains a tab or newline)");
|
|
162
|
+
}
|
|
121
163
|
}
|
|
122
164
|
}
|
|
123
165
|
|
package/package.json
CHANGED
package/src/paths.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
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
|
+
// TAB and newline are the file's field/record separators; a path containing
|
|
38
|
+
// either would corrupt unrelated entries, so refuse to store it.
|
|
39
|
+
if (dir.includes("\t") || dir.includes("\n")) return false;
|
|
40
|
+
const map = read();
|
|
41
|
+
map.set(dir, hex);
|
|
42
|
+
write(map);
|
|
43
|
+
return true;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function clearPathColor(dir) {
|
|
47
|
+
const map = read();
|
|
48
|
+
const had = map.delete(dir);
|
|
49
|
+
if (had) write(map);
|
|
50
|
+
return had;
|
|
51
|
+
}
|
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
|
-
}
|