Skip to content
Closed
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
13 changes: 8 additions & 5 deletions docs/ghostty-fork.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ When we change the fork, update this document and the parent submodule SHA.
## Current fork changes

The fork was refreshed from upstream `main` again on May 1, 2026.
Current cmux pinned fork head: `ff6e1260d`, based on `aef980e27`, with the
Current cmux pinned fork head: `176bd550f`, based on `ff6e1260d`, with the
manual embedded IO patch in https://github.com/manaflow-ai/ghostty/pull/53,
the Metal renderer row rebuild guard for https://github.com/manaflow-ai/cmux/issues/3369, and the URL/path
regex bound for spaced file paths followed by prose. This head keeps the cmux
theme picker hooks, exposes the manual surface IO needed by libghostty iOS
clients, bounds shaped glyph iteration during IME/preedit row rebuilds, and
prevents Cmd-hover from highlighting normal sentence text after a file path.
It also supports Ctrl-N and Ctrl-P in the cmux theme picker.
The corresponding prebuilt archive is published at
https://github.com/manaflow-ai/ghostty/releases/tag/xcframework-ff6e1260d2e7767de55b8d9307b328e4060545b7-crashsubdir-cmux-crash-v1
https://github.com/manaflow-ai/ghostty/releases/tag/xcframework-176bd550f6fedd29e85cd92470e5dfadf295ebf7-crashsubdir-cmux-crash-v1
and pinned in `scripts/ghosttykit-checksums.txt`.

### 1) macOS display link restart on display changes
Expand Down Expand Up @@ -77,6 +78,7 @@ tend to conflict together during rebases.
- `eb34bcdd6` (Harden cmux theme override writes)
- `04ec69173` (Apply highlighted cmux theme on Enter)
- `4265d3428` (Apply cmux theme from picker search)
- `176bd550f` (Add ctrl navigation to cmux theme picker)
- Files:
- `build.zig`
- `src/cli/list_themes.zig`
Expand All @@ -87,6 +89,7 @@ tend to conflict together during rebases.
- Keeps the preview UI readable in light mode, matches upstream picker startup behavior, and hardens writes to the cmux-managed theme override file.
- Restores Enter as the cmux apply action by writing the currently highlighted theme before the picker exits.
- Applies the highlighted search result when Enter is pressed from search mode in cmux-managed picker sessions.
- Supports Ctrl-N and Ctrl-P as one-row down/up navigation in cmux-managed picker sessions.

### 5) Color scheme mode 2031 reporting

Expand Down Expand Up @@ -211,9 +214,9 @@ tend to conflict together during rebases.

The current cmux pin is the head listed above. It is reachable from
`manaflow-ai/ghostty` through the
`xcframework-ff6e1260d2e7767de55b8d9307b328e4060545b7-crashsubdir-cmux-crash-v1`
release tag and branch `issue-cmd-hover-path-range`.
Published `xcframework-ff6e1260d2e7767de55b8d9307b328e4060545b7-crashsubdir-cmux-crash-v1` and pinned its
`xcframework-176bd550f6fedd29e85cd92470e5dfadf295ebf7-crashsubdir-cmux-crash-v1`
release tag and branch `issue-themes-broken-ctrl-np`.
Published `xcframework-176bd550f6fedd29e85cd92470e5dfadf295ebf7-crashsubdir-cmux-crash-v1` and pinned its
archive checksum in `scripts/ghosttykit-checksums.txt`. The release and checksum
pin must be regenerated whenever this commit changes, even for comment-only
amends, because the release tag is keyed by the Ghostty commit SHA.
Expand Down
2 changes: 1 addition & 1 deletion ghostty
1 change: 1 addition & 0 deletions scripts/ghosttykit-checksums.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ fe972c09579a7943f6fe9607fdd24f0f7c999cb1 4dde2bc84b27de84b14a38618ade03b2167a039
aef980e27b584a9d914f1ff0499b13c6ed1973e0 c6b8d560ad6b53d73396f80ba6995cb880ae9de9bfe8cae4dbd9ee72629798b5
6eed7af9240789ba18ccc617e51c384663be34a5 68bf3282478a92640d248c0b52b70cb41387aaed5baee9daa32e1019525f2d07
ff6e1260d2e7767de55b8d9307b328e4060545b7 02e5017a0d27ce5ada9ad92f675ce8c80dcebbc4bcfbe4060b6814b12b28cde9
176bd550f6fedd29e85cd92470e5dfadf295ebf7 60c612900a6101d2fa88e0d5c8debbcbe7f66230cca6b39f8ce24d5fd8c267ed
48 changes: 47 additions & 1 deletion tests/test_bundled_ghostty_theme_picker_helper.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,13 @@ fi

CONFIG_PATH="$TMP_DIR/config.ghostty"
SEARCH_CONFIG_PATH="$TMP_DIR/search-config.ghostty"
CTRL_N_CONFIG_PATH="$TMP_DIR/ctrl-n-config.ghostty"
CTRL_P_CONFIG_PATH="$TMP_DIR/ctrl-p-config.ghostty"
RESULTS_PATH="$TMP_DIR/config-paths.txt"
export CONFIG_PATH
export SEARCH_CONFIG_PATH
export CTRL_N_CONFIG_PATH
export CTRL_P_CONFIG_PATH
export RESULTS_PATH
export GHOSTTY_RESOURCES_DIR
export HELPER_PATH
Expand All @@ -83,11 +87,44 @@ import time
helper_path = os.environ["HELPER_PATH"]
config_path = os.environ["CONFIG_PATH"]
search_config_path = os.environ["SEARCH_CONFIG_PATH"]
ctrl_n_config_path = os.environ["CTRL_N_CONFIG_PATH"]
ctrl_p_config_path = os.environ["CTRL_P_CONFIG_PATH"]
results_path = os.environ["RESULTS_PATH"]
ghostty_resources_dir = os.environ["GHOSTTY_RESOURCES_DIR"]


def run_picker(label, scenario_config_path, scripted_input):
theme_dir = os.path.join(ghostty_resources_dir, "themes")
theme_names = sorted(
(
entry.name
for entry in os.scandir(theme_dir)
if entry.is_file() or entry.is_symlink()
),
key=lambda name: name.lower(),
)
if len(theme_names) < 2:
sys.stderr.write(f"FAIL: expected at least two bundled themes in {theme_dir}\n")
sys.exit(1)


def assert_theme_written(label, scenario_config_path, expected_theme):
try:
with open(scenario_config_path, "r", encoding="utf-8") as config:
contents = config.read()
except FileNotFoundError:
sys.stderr.write(f"FAIL: theme picker did not write config for {label}.\n")
sys.exit(1)

expected_line = f"theme = light:{expected_theme},dark:{expected_theme}"
if expected_line not in contents:
sys.stderr.write(
f"FAIL: expected {label} to write {expected_line!r}.\n"
)
sys.stderr.write(contents)
sys.exit(1)


def run_picker(label, scenario_config_path, scripted_input, expected_theme=None):
env = os.environ.copy()
env.update(
{
Expand Down Expand Up @@ -174,13 +211,22 @@ def run_picker(label, scenario_config_path, scripted_input):
finally:
os.close(master_fd)

if expected_theme is not None:
assert_theme_written(label, scenario_config_path, expected_theme)

first_theme = theme_names[0]
second_theme = theme_names[1]

run_picker("normal mode", config_path, b"\r")
run_picker("search mode", search_config_path, b"/tokyo\r")
run_picker("Ctrl-N navigation", ctrl_n_config_path, b"\x0e\r", second_theme)
run_picker("Ctrl-P navigation", ctrl_p_config_path, b"\x0e\x10\r", first_theme)

with open(results_path, "w", encoding="utf-8") as results:
results.write(config_path + "\n")
results.write(search_config_path + "\n")
results.write(ctrl_n_config_path + "\n")
results.write(ctrl_p_config_path + "\n")
PY

while IFS= read -r CONFIG_PATH; do
Expand Down
Loading