Adds progress-style config to control OSC 9;4 progress bar visibility.
Defaults to true, set false to hide.
Fixes#11241
AI Disclosure: Claude Code (Opus 4.6) used for codebase exploration,
code review, and testing assistance. All code written and reviewed by
hand.
Fixes#11396
Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
Fixes#11396
Track menu items populated from Ghostty keybind actions and only trigger
those from SurfaceView performKeyEquivalent. This avoids app-default
shortcuts such as Hide from pre-empting explicit keybinds.
Fixes#11379
For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle down. There is no horizontal component. I want to find the
right balance between always visible (today mostly) to only visible on
direct hover, because I think it'll be too hard to discover on that far
right side.
Fixes#11379
For this pass, I made it a very simple "within 20%" (height-wise) of the
split handle. There is no horizontal component. I want to find the right
balance between always visible (today mostly) to only visible on direct
hover, because I think it'll be too hard to discover on that far right
side.
Claude wrote the fail path in the UI tests, or you can easily reproduce
this manually. This is kinda a regression after #11322, since we are not
delaying the frame update anymore, which exposes some of the "flaws" of
the previous implementation.
The following three commits fix this step by step:
- We shouldn't save intermediate frames when the window is loading,
which is triggered by `windowDidResize` and `windowDidMove` during the
process.
- We should set the initial position (from the config) after the window
is loaded.
- A small refactor on `LastWindowPosition` to support restoring the
window frame under certain conditions.
https://github.com/user-attachments/assets/6f90f9a5-653d-4146-95c6-8e5c69bda656
### AI Disclosure
Claude helped me write the UI tests.
Use OSC 133;P (prompt mark) instead of 133;A (fresh line + prompt mark)
inside PS1 and PS2. Readline redraws the prompt on vi mode switches,
Ctrl-L, and other events, and 133;A's fresh-line behavior would emit a
CR+LF whenever the cursor wasn't at column 0, causing visible extra
newlines.
The one-time 133;A is now emitted via printf in __ghostty_precmd, which
only runs once per prompt cycle via PROMPT_COMMAND. On SIGWINCH, bash
redraws PS1 (firing the 133;P marks) but doesn't re-run PROMPT_COMMAND,
so there's no unwanted fresh-line on resize either. The redraw=last flag
persists from the initial printf.
This is a little less optimal than our previous approach, in terms of
number of prompt marks we emit, but it produces an overall more correct
result, which is the important thing.
Because readline prints its output outside the scope of PS1, those
characters "inherit" the surrounded prompt scope. This is usually fine,
but it can sometimes get out of sync (especially during redraws). This
is inherently a limitation of the fact that it's a separate output
channel, so we just have to accept that can happen.
Fixes: #10953
See: #11267
Use OSC 133;P (prompt mark) instead of 133;A (fresh line + prompt mark)
inside PS1 and PS2. Readline redraws the prompt on vi mode switches,
Ctrl-L, and other events, and 133;A's fresh-line behavior would emit a
CR+LF whenever the cursor wasn't at column 0, causing visible extra
newlines.
The one-time 133;A is now emitted via printf in __ghostty_precmd, which
only runs once per prompt cycle via PROMPT_COMMAND. On SIGWINCH, bash
redraws PS1 (firing the 133;P marks) but doesn't re-run PROMPT_COMMAND,
so there's no unwanted fresh-line on resize either. The redraw=last flag
persists from the initial printf.
This is a little less optimal than our previous approach, in terms of
number of prompt marks we emit, but it produces an overall more correct
result, which is the important thing.
Because readline prints its output outside the scope of PS1, those
characters "inherit" the surrounded prompt scope. This is usually fine,
but it can sometimes get out of sync (especially during redraws). This
is inherently a limitation of the fact that it's a separate output
channel, so we just have to accept that can happen.
See: #11267
Tests that window position and size are correctly restored after
reopen for all four macos-titlebar-style variants.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#11316
This mirrors the `prompt` actions (hence why there is no window action
here) and enables setting titles via keybind actions which importantly
lets this work via command palettes, App Intents, AppleScript, etc.
Fixes#11316
This mirrors the `prompt` actions (hence why there is no window action
here) and enables setting titles via keybind actions which importantly
lets this work via command palettes, App Intents, AppleScript, etc.
Only replace the \n prompt escape when inserting secondary prompt marks,
not literal newlines `($'\n')`. Literal newlines may appear inside
`$(...)` or `...` command substitutions, and inserting escape sequences
there breaks the shell syntax. For example:
PS1='$(if [ $? -eq 0 ]; then echo -e "P";
else echo -e "F";
fi) $ '
The literal newlines between the if/else/fi are part of the shell syntax
inside the command substitution. The previous code replaced all literal
newlines in PS1 with newline + OSC 133 escape sequences, which injected
terminal escapes into the middle of the command substitution and caused
bash to report a syntax error when evaluating it.
The \n prompt escape is PS1-specific and safe to replace globally. This
means prompts using literal newlines for line breaks (rather than \n)
won't get per-line secondary marks, but this is the conventional form
and avoids the need for complex shell parsing.
Fixes: #11267
Only replace the \n prompt escape when inserting secondary prompt marks,
not literal newlines ($'\n'). Literal newlines may appear inside $(...)
or `...` command substitutions, and inserting escape sequences there
breaks the shell syntax. For example:
PS1='$(if [ $? -eq 0 ]; then echo -e "P";
else echo -e "F";
fi) $ '
The literal newlines between the if/else/fi are part of the shell syntax
inside the command substitution. The previous code replaced all literal
newlines in PS1 with newline + OSC 133 escape sequences, which injected
terminal escapes into the middle of the command substitution and caused
bash to report a syntax error when evaluating it.
The \n prompt escape is PS1-specific and safe to replace globally. This
means prompts using literal newlines for line breaks (rather than \n)
won't get per-line secondary marks, but this is the conventional form
and avoids the need for complex shell parsing.
Fixes: #11267
Replace the strip-in-preexec / re-add-in-precmd pattern for OSC 133
marks with a save/restore approach. Instead of pattern-matching marks
out of PS1 (which exposes PS1 in intermediate states to other hooks), we
save the original PS1/PS2 before adding marks and then restore them.
This also adds dynamic theme detection: if PS1 changed between cycles
(e.g., a theme rebuilt it), we skip injecting continuation marks into
newlines. This prevents breaking plugins like Pure that use pattern
matching to strip/rebuild the prompt.
Additionally, move _ghostty_precmd to the end of precmd_functions in
_ghostty_deferred_init (instead of substituting in-place) so that the
first prompt is properly marked even when other hooks were appended
after our auto-injection.
There's one scenario that we still don't complete cover:
precmd_functions+=(_test_overwrite_ps1)
_test_overwrite_ps1() {
PS1="test> "
}
... which results in the first prompt not printing its prompt marks
because _test_overwrite_ps1 becomes the last thing to run, overwriting
our marks, but this will be fixed for subsequent prompts when we move
our handler back to the last index.
Fixes: #11282
Replace the strip-in-preexec / re-add-in-precmd pattern for OSC 133
marks with a save/restore approach. Instead of pattern-matching marks
out of PS1 (which exposes PS1 in intermediate states to other hooks), we
save the original PS1/PS2 before adding marks and then restore them.
This also adds dynamic theme detection: if PS1 changed between cycles
(e.g., a theme rebuilt it), we skip injecting continuation marks into
newlines. This prevents breaking plugins like Pure that use pattern
matching to strip/rebuild the prompt.
Additionally, move _ghostty_precmd to the end of precmd_functions in
_ghostty_deferred_init (instead of substituting in-place) so that the
first prompt is properly marked even when other hooks were appended
after our auto-injection.
There's one scenario that we still don't complete cover:
precmd_functions+=(_test_overwrite_ps1)
_test_overwrite_ps1() {
PS1="test> "
}
... which results in the first prompt not printing its prompt marks
because _test_overwrite_ps1 becomes the last thing to run, overwriting
our marks, but this will be fixed for subsequent prompts when we move
our handler back to the last index.
Fixes: #11282
If the CLI argument `--working-directory` is not used with
`+new-window`, the current working directory that `ghostty +new-window`
is run from will be appended to the list of configuration data sent
to the main Ghostty process. If `-e` _was_ used on the CLI, the
`--working-directory` that was appended will be interpreted as part of
the command to be executed, likely causing it to fail.
Instead, insert `--working-directory` at the beginning of the list of
configuration that it sent to the main Ghostty process.
Fixes#11356
This disables all the automatic one-time code inputs in Ghostty. It'd be
really neat to actually dynamically change this (not sure if it's
possible with NSTextContext or how often thats cached) but for now we
should just fully disable it.
Thanks to Ricky Mondello for the heads up on this.
This disables all the automatic one-time code inputs in Ghostty.
It'd be really neat to actually dynamically change this (not sure if its
possible with NSTextContext or how often thats cached) but for now we
should just fully disable it.
Fixes#11336
Introduce a proper WorkingDirectory tagged union type with home,
inherit, and path variants. The field is now an optional
(?WorkingDirectory) where null represents "use platform default" which
is resolved during Config.finalize to .inherit (CLI) or .home (desktop
launcher).
Fixes#11336
Introduce a proper WorkingDirectory tagged union type with home, inherit,
and path variants. The field is now an optional (?WorkingDirectory) where
null represents "use platform default" which is resolved during Config.finalize
to .inherit (CLI) or .home (desktop launcher).
Test boolean, string, enum, and numeric config properties using
TemporaryConfig to verify defaults and parsed values.
Co-Authored-By: Claude <noreply@anthropic.com>
If you have "Noto Sans Tai Tham" and/or "Noto Sans Javanese" installed
locally on Linux, three tests fail. This PR disables those tests until a
more permanent solution can be found.