Skip to content

pkg/edit: add support for OSC 133 semantic prompts#1917

Open
jparise wants to merge 5 commits intoelves:mainfrom
jparise:osc133
Open

pkg/edit: add support for OSC 133 semantic prompts#1917
jparise wants to merge 5 commits intoelves:mainfrom
jparise:osc133

Conversation

@jparise
Copy link

@jparise jparise commented Feb 4, 2026

OSC 133 semantic prompt sequences help terminals understand shell command structure for features like command navigation, intelligent text selection, and command status indicators.

https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md

This change adds support for OSC 133 A (prompt start), B (input start), C (command start), D (command exit), and P;k=r (right prompt). These sequences are only emitted to TTYs in interactive shell sessions.

I introduced the concept of "zero-width" buffer cells to prevent these "invisible" sequences from contributing to line width calculations. This adds a small (int) cost to each Cell instance. I explored some alternatives (interfaces, out-of-band tracking, a magic "style" value), but this ended up being the clearest and most efficient approach.

This feature is controlled via a new edit:shell-integration variable. It defaults to $true (enabled) but can be disabled at any time. It could be generalized to a map of shell integration features later while maintaining backwards compatibility (e.g. $true means all enabled):

set edit:shell-integration = [ &osc133=$true &osc8=$true ]

I also explored ways to implement this support at the script level, but the existing edit: hooks don't cover enough cases, and the prompt's asynchronous, control-sequence-stripping output was too limiting.

Closes #1808

OSC 133 semantic prompt sequences help terminals understand shell
command structure for features like command navigation, intelligent text
selection, and command status indicators.

https://gitlab.freedesktop.org/Per_Bothner/specifications/blob/master/proposals/semantic-prompts.md

This change adds support for OSC 133 A (prompt start), B (input start),
C (command start), D (command exit), and P;k=r (right prompt). These
sequences are only emitted to TTYs in interactive shell sessions.

I introduced the concept of "zero-width" buffer cells to prevent these
"invisible" sequences from contributing to line width calculations. This
adds a small (`bool`) cost to each `Cell` instance. I explored some
alternatives (interfaces, out-of-band tracking, a magic "style" value),
but this ended up being the clearest and most efficient approach.

This feature is controlled via a new `edit:shell-integration` variable.
It defaults to `$true` (enabled) but can be disabled at any time. It
could be generalized to a map of shell integration features later while
maintaining backwards compatibility (e.g. `$true` means all enabled):

    set edit:shell-integration = [ &osc133=$true &osc8=$true ]

I also explored ways to implement this support at the script level, but
the existing `edit:` hooks don't cover enough cases, and the prompt's
asynchronous, control-sequence-stripping output was too limiting.
@jparise
Copy link
Author

jparise commented Feb 4, 2026

Here's an example of this running in Ghostty using our semantic prompt inspector overlay:

CleanShot 2026-02-03 at 19 15 53@2x

(orange regions are prompts, blue regions are inputs)

@jparise
Copy link
Author

jparise commented Feb 4, 2026

Now marking the continuation indent region as a secondary prompt:

image

Also, correct the previous OSC 133;A sequence, which shouldn't send the
`k=i` option because it's implied.
Rather than using an indirect ZeroWidth flag to skip the Cell width
calculation, store an explicit Width value instead. It becomes the
writer's responsibility to set the text's width when the Cell is
created.

This is a more general solution, and the burden on the writers isn't too
bad because we don't create Cells in many places. For the tests, we have
a small cell() helper function that simplifies standard cell creation.

This also results in a small efficiency gain:

1. We can now use wcwidth.OfRune(), which saves us a string iteration
   from the wcwidth.Of() path.
2. TTYString() no longer needs to repeat the width calculation. (And it
   should have been checking ZeroWidth before, so this also fixes a
   bug.)
> To help track this nesting we make use of an optional application
> identifier (aid) which can be an arbirary string specified by the
> application. It is suggested that the aid be (or contain) the
> process id of the application; if that is unavailable, the name
> of the application.
jparise added a commit to jparise/ghostty that referenced this pull request Mar 8, 2026
Improve the Elvish shell integration's semantic prompt support with the
changes that can be reliably implemented at the script level:

- Add `cl=line` parameter to 133;A for click-to-line functionality
- Add `aid=$pid` parameter to 133;A and 133;D for nested shell tracking
- Fix state comparison (was incorrectly using `constantly`)

OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues. Full semantic prompt support requires a native
implementation: elves/elvish#1917

See: ghostty-org#10523
jparise added a commit to jparise/ghostty that referenced this pull request Mar 8, 2026
Add `aid=$pid` to 133;A and 133;D for nested shell tracking, and fix the
state comparison which was incorrectly using `constantly` (comparing a
string to a function, which always evaluated to true).

OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues because Elvish renders its prompts on a background
thread. Full semantic prompt support requires a native implementation:
elves/elvish#1917

See: ghostty-org#10523
mitchellh added a commit to ghostty-org/ghostty that referenced this pull request Mar 8, 2026
Add `aid=$pid` to 133;A and 133;D for nested shell tracking, and fix the
state comparison which was incorrectly using `constantly` (comparing a
string to a function, which always evaluated to true).

OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues because Elvish renders its prompts on a background
thread. Full semantic prompt support requires a native implementation:
elves/elvish#1917

See: #10523
nicosuave added a commit to sidequery/ghostree that referenced this pull request Mar 10, 2026
* Remove duplicate word in README_TRANSLATORS § CODEOWNERS.

* Improve word grouping w.r.t. localization team names.

“always include a language and a country code” reads as “always include
a language, and also always include a country code”, while the intended
meaning was that it includes both a language *code* and a country code.

* Elaborate on X-Generator removal.

That line was intended to guide those who do not normally edit po files
with a plain text editor, but ended up sounding like it states the
obvious (“to do X, do X”) before this change.

* macos: fix window size/position restoration on Cmd+W close

This fixes two overlapping issues regarding window positioning and Cmd+W window closures on macOS:

1. `window-position-x` and `window-position-y` coordinates were being ignored on initial launch because `TerminalWindow.setInitialWindowPosition` depended on the `TerminalController`, which isn't fully attached during `awakeFromNib`. This logic was moved so explicit coordinates are correctly enforced.
2. When closing a window via Cmd+W (leaving the app active), reopening the window would continuously cascade down and to the right rather than restoring to the previous position. It now checks if there are other windows open before cascading.
3. `LastWindowPosition` was updated to save both the frame origin and size (width/height), ensuring that restoring a closed window correctly mimics native AppKit State Restoration size behaviors while honoring explicit configurations.

* fix(macos): extract window cascade logic into helper function

* Update VOUCHED list (ghostty-org#11071)

Triggered by
[comment](ghostty-org#11070 (comment))
from @mitchellh.

Vouch: @abdurrahmanski

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Rename pt.po back to pt_BR.po.

Portugal exists! Wikipedia notes [1] it to be the main other dialect.
There's already a PR for pt_PT support too:
ghostty-org#9078.

It was renamed from pt_BR.UTF-8.po to pt.po in ghostty-org#10976.

[1]: https://en.wikipedia.org/wiki/Portuguese_dialects

* Rename ko.po back to ko_KR.po.

While it was renamed from ko_KR.UTF-8.po to ko.po in ghostty-org#10976, @uhojin,
a Korean locale maintainer, notes [1] that “ko_KR [*South* Korean] makes
more sense in locale context just to avoid any potential confusion
between 한국어 vs 조선어”.

Despite ko_KP (North Korean) not being present in glibc (as of version
2.43), and the ISO639 maintainers expressing disapproval of ko_KP [2],
it is possible opinions may change in the future, and individual
opinions may be contested—disambiguating doesn't hurt.

[1]: ghostty-org#10976 (comment)
[2]: ghostty-org#10976 (comment)

* i18n: update Hungarian translations

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>

* Update VOUCHED list (ghostty-org#11078)

Triggered by [discussion
comment](ghostty-org#11076 (comment))
from @jcollie.

Vouch: @DiaaEddin

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update macos/Sources/Features/Terminal/TerminalController.swift

apply reviewer suggestion for cascading

Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com>

* Remove old "acceptance tests" 

We haven't used or run these in forever (literally like 3+ years).
They're just wasting cognitive space and confuse some users as to what
they're for. Remove them.

* fix(terminal): bounds check params in DCS passthrough entry

When a DCS sequence has more than MAX_PARAMS parameters, entering
dcs_passthrough would write to params[params_idx] without a bounds
check, causing an out-of-bounds access. Drop the entire DCS hook
when params overflow, consistent with how csi_dispatch handles it.

Found by AFL fuzzing.

* test/fuzz-libghostty: basic afl++-based fuzzer for libghostty

* pkg/afl++

* switch to pkg/afl++ for fuzz

* test/fuzz-libghostty: gitignore and initial corpus

* test/fuzz-libghostty: add zig build run

* pkg/afl++: clean up, comments

* pkg/afl++: extract runner

* test/fuzz-libghostty: add README

* Corpus management update

* pkg/afl++: use usize for len

* pkg/afl++: fuzzer takes a file argument

* typos

* pkg/afl++: remove file arg

* Clear key state overlay on "ignore" action

* Update VOUCHED list (ghostty-org#11093)

Triggered by
[comment](ghostty-org#5036 (comment))
from @jcollie.

Vouch: @AlexJuca

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* 🐛 Prevent git log output with signature information

When users have something like

[log]
        showSignature = true

in their .gitconfig files, invocations of the log or show git sub-command
emit additional information about signatures.  This additional output
disturbs the generation of short_hash in GitVersion.zig, the additional text
is copied verbatim into the string and then shown in the CSI >q output.

To fix it always suppress the output of the signature information.  This
has no effects when the setting is disabled anyway.

* docs: clarify if pre-vouching contributors are also required to apply to get vouched before contributing to Ghostty

* chore: add improvements

* fix: format with prettier

* Update VOUCHED list (ghostty-org#11098)

Triggered by
[comment](ghostty-org#11094 (comment))
from @jcollie.

Vouch: @drepper

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11099)

Triggered by [discussion
comment](ghostty-org#11090 (comment))
from @jcollie.

Vouch: @cespare

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* ci: fix windows CI checkouts with afl-min filenames

* fuzz: replace : with _ for Windows

* ci: test libghostty fuzzer build

* shellcheck

* fuzz: update corpus

* typos: ignore fuzz corpus

* Update CONTRIBUTING.md

Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>

* Update CONTRIBUTING.md

Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>

* Update CONTRIBUTING.md

Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>

* Update CONTRIBUTING.md

Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>

* chore: improve grammer

* Update CONTRIBUTING.md

Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>

* Update VOUCHED list (ghostty-org#11107)

Triggered by [discussion
comment](ghostty-org#11102 (comment))
from @mitchellh.

Vouch: @mischief

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* terminal: fix out-of-bounds access in CSI W handler with no params

CSI ? W (cursor tabulation control) accessed input.params[0] without
first checking that params.len > 0, causing an index out-of-bounds
panic when the sequence had an intermediate but no parameters.

Add a params.len == 1 guard before accessing params[0].

Found by AFL++ fuzzing.

* terminal: insertBlanks should not crash with count 0 and CSI @ clamps [1,)

CSI @ (ICH) with an explicit parameter of 0 should be clamped to 1,
matching xterm behavior. Previously, a zero count reached
Terminal.insertBlanks which called clearCells with an empty slice,
triggering an out-of-bounds panic.

Fix the stream dispatch to clamp 0 to 1 via @max, and add a defensive
guard in insertBlanks for count == 0. Found by AFL++ stream fuzzer.

* fuzz/vt-stream

* Clean up how fuzzers are laid out

* fuzz/stream: clean up

* prettier should ignore various fuzz files

* fix up gitattributes

* fuzz: stream cmin

* terminal: fix panic on CSI g (TBC) with overflowing param

A fuzz crash found that CSI g with a parameter that saturates to
u16 max (65535) causes @enumFromInt to panic when narrowing to
TabClear (enum(u8)). Use std.meta.intToEnum instead, which safely
returns an error for out-of-range values.

* terminal: handle trailing colon in SGR underline parsing

A trailing colon with no following sub-parameter (e.g. "ESC[58:4:m")
leaves the colon separator bit set on the last param without adding
another entry to the params array. When the SGR parser later iterates
to that param (4 = underline) and sees the colon bit, it entered the
colon path which asserted slice.len >= 2, but the slice only had one
element.

Replace the assert with a bounds check that treats the malformed
sequence as a default single underline.

Add a regression test reproducing the crash from AFL++ fuzzing
(afl-out/stream/default/crashes/id:000021).

* Sync CODEOWNERS vouch list (ghostty-org#11114)

Sync CODEOWNERS owners with vouch list.

## Added Users

- @derVedro

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* i18n: update pt_BR translations (ghostty-org#10635)

Add missing pt_BR translations reported in
ghostty-org#10632 for version 1.3

* Update VOUCHED list (ghostty-org#11116)

Triggered by
[comment](ghostty-org#11115 (comment))
from @mitchellh.

Vouch: @markdorison

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* terminal: fix integrity violation printing wide char with hyperlink at right edge

Printing a wide character at the right edge of the screen with an active
hyperlink triggered a page integrity violation (UnwrappedSpacerHead).
printCell wrote the spacer_head to the cell and then called
cursorSetHyperlink, whose internal integrity check observed the
spacer_head before printWrap had a chance to set the row wrap flag.

Fix by setting row.wrap = true before calling printCell for the
spacer_head case, so all integrity checks see a consistent state.
printWrap sets wrap again afterward, which is harmless. Found by AFL++
stream fuzzer.

* fuzz: add replay-crashes.nu to help find crash repros

* fuzz: new stream corpus from 2 hour run

* pin python depds to latest tag

* Update VOUCHED list (ghostty-org#11122)

Triggered by
[comment](ghostty-org#11121 (comment))
from @jcollie.

Vouch: @rhodes-b

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11123)

Triggered by [discussion
comment](ghostty-org#11118 (comment))
from @pluiedev.

Vouch: @jguthmiller

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* terminal: fix insertBlanks integrity violation with wide char at right margin

insertBlanks checks whether the last source cell being shifted is wide
and clears it to avoid splitting, but it did not check the destination
cells at the right edge of the scroll region. When a wide character
straddles the right scroll margin (head at the margin, spacer_tail just
beyond it), the swap loop displaced the wide head without clearing the
orphaned spacer_tail, causing a page integrity violation
(InvalidSpacerTailLocation).

Fix by checking the cell at the right margin (last destination cell)
before the swap loop and clearing it along with its spacer_tail when it
is wide. 

Found by AFL++ stream fuzzer. ghostty-org#11109

* terminal: fix printCell corrupting previous row when overwriting wide char

printCell, when overwriting a wide cell with a narrow cell at x<=1 and
y>0, unconditionally sets the last cell of the previous row to .narrow.
This is intended to clear a spacer_head left by a wrapped wide char, but
the cell could be a spacer_tail if a wide char fit entirely on the
previous row. Setting a spacer_tail to .narrow orphans the preceding
.wide cell, which later causes an integrity violation in insertBlanks
(assert that the cell after a .wide is .spacer_tail).

Fix by guarding the assignment so it only fires when the previous row's
last cell is actually a .spacer_head. The same fix is applied in both
the .wide and .spacer_tail branches of printCell.

Found by AFL++ stream fuzzer.

* terminal: fix no-reflow resize leaving stale spacer heads

resizeWithoutReflowGrowCols has a fast path that reuses existing page
capacity when growing columns: it simply bumps page.size.cols without
touching cell data. If any row has a spacer_head at the old last column
(from a wide char that did not fit), that cell is no longer at the end
of the now-wider row, causing a page integrity violation.

Fix by checking for spacer_head cells at the old last column before
taking the fast path. If any are found, fall through to the slow path
which handles spacer heads correctly via cloneRowFrom.

Found by AFL++ stream fuzzer. ghostty-org#11109

* terminal: fix insertLines/deleteLines orphaned cells on full clear

When deleteLines or insertLines count >= scroll region height, all rows
go through the clear-only path (no shifting). This path did not call
rowWillBeShifted, leaving orphaned spacer_tail cells when wide characters
straddled the right margin boundary, causing a "spacer tail not following
wide" page integrity violation.

Add rowWillBeShifted before clearCells in the else branch of both
functions.

Found via AFL++ fuzzing. ghostty-org#11109

* terminal: fix insertBlanks orphaned spacer_tail beyond right margin

When insertBlanks clears the entire region from cursor to the right
margin (scroll_amount == 0), a wide character whose head is at the right
margin gets cleared but its spacer_tail just beyond the margin is left
behind, causing a "spacer tail not following wide" page integrity
violation.

Move the right-margin wide-char cleanup from inside the scroll_amount >
0 block to before it, so it runs unconditionally — matching the
rowWillBeShifted pattern of cleaning up boundary-straddling wide chars
up front.

Found via AFL++ fuzzing. ghostty-org#11109

* Update VOUCHED list (ghostty-org#11139)

Triggered by [discussion
comment](ghostty-org#11128 (comment))
from @mitchellh.

Vouch: @noib3

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* address comments

* pkg/afl++: remove @@ from run target since we use in-memory targets

* config: respect cursor-click-to-move for OSC133 click to move

When cursor-click-to-move is set to false, disable all prompt
click-to-move mechanisms including shell-native methods such as OSC 133
cl= (arrow key synthesis) and click_events. 

I forgot to port this config over when we did the OSC133 stuff.

Also update the config documentation to accurately describe the current
behavior.

Fixes ghostty-org#11138

* terminfo: add support for SGR dim

This PR implements the fix discussed in
ghostty-org#11128

* macos: finish editing tab title when the window resigns as key window

* macos: passthrough mouse down event to TabTitleEditor if needed

* macos: passthrough right mouse down event to TabTitleEditor if needed

* macos: hide close button when editing tab title

* fuzz: add OSC parser fuzzer

* macos: use a separated struct to hide and restore tab states

* input: send composed text in kitty keyboard protocol

When the kitty keyboard protocol "report all keys as escape codes" mode
was active, composed/IME text (e.g. from dead keys or compose sequences)
was silently dropped. 

This happened because the composed text is sent within our GTK apprt
with key=unidentified and no unshifted_codepoint, so no kitty entry was
found and the encoder returned without producing any output. The
plain-text fallback was also skipped because report_all bypasses it.

Send composed text as raw UTF-8 when no kitty entry is found, matching
the behavior of Kitty on Linux for me.

Fixes ghostty-org#10049

* build: link to the system FontConfig by default on non-macOS systems

Because of the global shared state that FontConfig maintains, FontConfig
must be linked dynamically to the same system FontConfig shared library
that GTK uses. Ghostty's default has been changed to always link to the
system FontConfig library on non-macOS systems. If that is overridden
(by specifying `-fno-sys=fontconfig` during the build) Ghostty may crash
when trying to locate glyphs that are not available in the default font.

Fixes ghostty-org#10432

* macos: implement audio bell support with bell-audio-path

Extends the macOS bell implementation to support the `audio` bell
feature by playing a user-specified audio file via NSSound.

Previously, macOS only supported the `system` feature (NSSound.beep()).
This change adds support for:
- `audio` bell feature: plays the file at `bell-audio-path` using
  NSSound, respecting the `bell-audio-volume` setting
- Adds `cval()` to the `Path` type so it can be returned via the C API

Also removes the "(GTK only)" restriction from `bell-audio-path` and
`bell-audio-volume` documentation, as these options now work on macOS.

Example config:
  bell-features = audio
  bell-audio-path = /System/Library/Sounds/Glass.aiff
  bell-audio-volume = 0.8

* Update VOUCHED list (ghostty-org#11155)

Triggered by
[comment](ghostty-org#11154 (comment))
from @mitchellh.

Vouch: @alaasdk

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11156)

Triggered by [discussion
comment](ghostty-org#10982 (reply in thread))
from @jcollie.

Vouch: @cmwetherell

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* build(deps): bump cachix/install-nix-action from 31.9.1 to 31.10.0

Bumps [cachix/install-nix-action](https://github.com/cachix/install-nix-action) from 31.9.1 to 31.10.0.
- [Release notes](https://github.com/cachix/install-nix-action/releases)
- [Changelog](https://github.com/cachix/install-nix-action/blob/master/RELEASE.md)
- [Commits](cachix/install-nix-action@2126ae7...19effe9)

---
updated-dependencies:
- dependency-name: cachix/install-nix-action
  dependency-version: 31.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>

* i18n: add Vietnamese translation

* update translation

* use proper type for optional path

* macos: Ghostty.Shell.escape unit tests

* i18n: add Kazakh translation (kk)

* fix: zsh shell integration when `sudo` and `ssh` aliases are defined

* zsh: fix extra newlines with leading-newline prompts

In our multiline prompt logic, skip the newline immediately after the
first mark to avoid introducing a double newline due to OSC 133;A's
fresh-line behavior.

Fixes: ghostty-org#11003

* zsh: emit missing prompt markers in line-init

Emit semantic prompt markers at line-init if PS1 doesn't contain our
marks. This ensures the terminal sees prompt markers even if another
plugin (like zinit or oh-my-posh) regenerated PS1 after our precmd ran.
We use 133;P instead of 133;A to avoid fresh-line behavior which would
disrupt the display since the prompt has already been drawn. We also
emit 133;B to mark the input area, which is needed for click-to-move.

Fixes: ghostty-org#10555

* macos: suppress split-focus click mouse reports

Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>

* gtk: suppress mouse reports on focus-transfer clicks

Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>

* macos: defer key-window focus sync to reduce churn

Amp-Thread-ID: https://ampcode.com/threads/T-019cb9fe-b11b-753f-99e7-8ecc52b73ec4
Co-authored-by: Amp <amp@ampcode.com>

* gtk: `+new-window` now respects `--working-directory` and `-e`

Fixes: ghostty-org#8862
Fixes: ghostty-org#10716

This adds the machinery to pass configuration settings received over
DBus down to the GObject Surface so that that configuration information
can be used to override some settings from the current "live" config
when creating a new window. Currently it's only possible to override
`--working-directory` and `--command`. `-e` on the `ghostty +new-window`
CLI works as well.

Adding more overridable settings is possible, but being able to fully
override any possible setting would better be served with a major
revamp of how Ghostty handles configs, which I is way out of scope at
the moment.

* gtk: `+new-window` now respects `--title`

* gtk: `+new-window` document `--title`

* gtk: use simpler method for passing overrides around

As discussed in Discord, this commit drops the `ConfigOverride` object
in favor of a simpler method of passing the overrides around. Completely
avoiding changes to the core wasn't possible but it's very minimal now.

* gtk: remove modifications to the core for overrides

* Revert "build: link to the system FontConfig by default on non-macOS systems (ghostty-org#11152)"

This reverts commit ee4c6f8.

* Revert "build: link to the system FontConfig by default on non-macOS systems"

This reverts commit 89f9dd7.

* gtk: simplify new-window action memory management with an arena

* apprt/gtk: reduce split-tree flicker by reusing leaf widgets 

Fixes ghostty-org#8208

Split-tree updates currently clear `tree_bin` and then wait for every surface
to become parentless before rebuilding. That leaves the split area blank for
one or more frames, which is the visible flicker during split create/close/
resize/equalize actions.

Keep the previous widget tree attached until the idle rebuild runs, then
swap in the rebuilt tree in one step. During rebuild, reuse existing
leaf widgets by detaching and reparenting them into the new `GtkPaned` 
hierarchy instead of recreating wrappers for every leaf.

This removes the parent-settling rebuild path and avoids transient blank
frames while preserving debounced rebuild behavior.

* Update VOUCHED list (ghostty-org#11176)

Triggered by
[comment](ghostty-org#11175 (comment))
from @jcollie.

Vouch: @douglas

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11179)

Triggered by [discussion
comment](ghostty-org#11164 (comment))
from @mitchellh.

Vouch: @Michielvk

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix Windows test in src/Command.zig

This was introduced in ghostty-org#10611. This doesn't fix all of the current
Windows build problems, but at least fixes one that I introduced.

* terminal: bound link regex search work with Oniguruma retry limits 

Fixes ghostty-org#11177

Use per-search Oniguruma match params (retry_limit_in_search) in
StringMap-backed link detection to avoid pathological backtracking hangs
on very long lines.

The units are ticks in the internal loop so its kind of opaque but
this seems to still match some very long URLs. The test case in question
was a 169K character line (which is now rejected).

* GTK: add 'move' to the drop target actions

Fixes ghostty-org#11175

* windows: use new callconv convention

* Update VOUCHED list (ghostty-org#11191)

Triggered by
[comment](ghostty-org#11190 (comment))
from @00-kat.

Vouch: @AnthonyZhOon

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11192)

Triggered by [discussion
comment](ghostty-org#11184 (comment))
from @mitchellh.

Vouch: @mac0ne

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* windows: avoid the use of wcwidth

* windows: add trivial implementation of expandHome

* windows: use explicit error sets to work around lack of file locking

* windows: add GetComputerNameA so that hostname-related functions work

* build(deps): bump docker/build-push-action from 6.19.2 to 7.0.0

Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 6.19.2 to 7.0.0.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](docker/build-push-action@10e90e3...d08e5c3)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* macos: add build script, update AGENTS.md, skip UI tests

This is an update to address common agentic issues I run into,
but the `build.nu` script may be generally helpful to people using
the Nix env since `xcodebuild` is broken by default in Nix due to the
compiler/linker overrides Nix shell does.

* macos: AppleScript starting

* macos: implement basic read-only applescript stuff

* macos: add ability for agents to run debug app

* macos: fix perform action

* macos: add AppleScript `split` command

Add a new `split` command to the AppleScript scripting dictionary that
splits a terminal in a given direction (right, left, down, up) and
returns the newly created terminal.

The command is exposed as:
  split terminal <terminal> direction <direction>

Also adds a `fourCharCode` String extension for converting four-character
ASCII strings to their FourCharCode (UInt32) representation.

* macos: add focus and close AppleScript commands for terminals

Add two new AppleScript commands to the scripting dictionary:

- `focus terminal <terminal>` — focuses the given terminal and brings
  its window to the front.
- `close terminal <terminal>` — closes the given terminal without a
  confirmation prompt.

Each command is implemented as an NSScriptCommand subclass following
the same pattern as the existing split command.

* macos: add AppleScript commands for text input, key, and mouse events

Add five new AppleScript commands to Ghostty.sdef mirroring the existing
App Intents for terminal input:

- `input text`: send text to a terminal as if pasted
- `send key`: simulate a keyboard event with optional action and modifiers
- `send mouse button`: send a mouse button press/release event
- `send mouse position`: send a mouse cursor position event
- `send mouse scroll`: send a scroll event with precision and momentum

A shared `input action` enumeration (press/release) is used by both key
and mouse button commands. Modifier keys are passed as a comma-separated
string parameter (shift, control, option, command).

* macos: add standard application properties and commands

Add standard Cocoa scripting definitions to the AppleScript dictionary:

- Application properties: name, frontmost, version
- Standard Suite commands: exists, quit

These are backed by built-in Cocoa scripting classes (NSExistsCommand,
NSQuitCommand) and standard NSApplication KVC keys, so no Swift code
changes are needed.

* typos: ignore apple four char codes

* macos: fix iOS build

* macos: AppleScript windows/tabs 

Add ScriptWindow and ScriptTab classes to expose window/tab hierarchy
to AppleScript, along with the corresponding sdef definitions.

* macos: fix AppleScript quit command being silently ignored

The application class in Ghostty.sdef was missing a responds-to
declaration for the quit command. Apple's Cocoa Scripting requires
the application class to explicitly declare it responds to quit via
handleQuitScriptCommand: for the aevtquit event to be dispatched.

* macos: add terminals element to window and tab AppleScript classes

Expose terminal surfaces as elements on both ScriptWindow and ScriptTab,
allowing AppleScript to enumerate terminals scoped to a specific window
or tab (e.g. `terminals of window 1`, `terminals of tab 1 of window 1`).

Changes:
- Add `<element type="terminal">` to window and tab classes in Ghostty.sdef
- Add `terminals` computed property and `valueInTerminalsWithUniqueID:`
  lookup to ScriptWindow (returns all surfaces across all tabs)
- Add `terminals` computed property and `valueInTerminalsWithUniqueID:`
  lookup to ScriptTab (returns surfaces within that tab)

* macos: expose name (title) on window, tab, and terminal via AppleScript

Add a `name` property (code `pnam`, cocoa key `title`) to the window, tab,
and terminal classes in the scripting definition. This follows the standard
Cocoa scripting convention where `name`/`pnam` maps to the `title` KVC key,
matching what Apple does in CocoaStandard.sdef for NSWindow.

Also fixes the pre-existing terminal `title` property which used a custom
four-char code (`Gttl`) that AppleScript could not resolve directly — only
via `properties of terminal`. All three classes now use the standard `pnam`
code so `name of window 1`, `name of tab 1 of window 1`, and
`name of terminal 1` all work correctly.

* macos: add AppleScript new window command

Add a `new window` command to the scripting dictionary and wire it to
`NSApplication` so AppleScript can create Ghostty windows.

The command returns a scripting `window` object for the created window,
with a fallback to a direct wrapper when AppKit window ordering has not
yet refreshed in the current run loop.

* macos: use value-style AppleScript surface configuration records

Add a `surface configuration` record type to the scripting dictionary,
implement `new surface configuration` (with optional copy-from), and allow
`new window` to accept `with configuration`.

* macos: order AppleScript dictionary definitions

Document the preferred Ghostty.sdef top-level order in AGENTS.md and reorder 
Ghostty Suite definitions to classes, records, enums, then commands.

* macos: allow split command surface configuration

* macos: add new tab command

* macos: Add AppleScript commands for window and tab control

Add scripting dictionary commands for activating windows, selecting tabs,
closing tabs, and closing windows.

Implement the corresponding Cocoa AppleScript command handlers and expose
minimal ScriptWindow/ScriptTab helpers needed to resolve live targets.

Verified by building Ghostty and running osascript commands against the
absolute Debug app path to exercise all four new commands.

* macos: add macos-applescript config

* swiftlint

* macos: rename surface config working directory to not be ambiguous

* Add es_ES.UTF-8 translation

* Fix snap EGL vendor dirs to include host NVIDIA ICD paths

* Update VOUCHED list (ghostty-org#11211)

Triggered by
[comment](ghostty-org#11209 (comment))
from @mitchellh.

Vouch: @04cb

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* address some PR feedback

* macos: use direct parameters for object-targeting commands

Change split, focus, close, activate window, select tab, close tab, and
close window commands to accept their target object as a direct parameter
instead of a named parameter. This produces natural AppleScript syntax:

  activate window (window 1)
  close tab (tab 1 of window 1)
  split (terminal 1) direction right

instead of the awkward redundant form:

  activate window window (window 1)
  close tab tab (tab 1 of window 1)
  split terminal (terminal 1) direction right

The implementation moves command logic from NSScriptCommand subclasses
into responds-to handler methods on ScriptTerminal, ScriptWindow, and
ScriptTab, which is the standard Cocoa Scripting pattern for commands
whose direct parameter is an application class.

* macos: implement the quit command

* elvish: improve OSC 133 semantic prompt support

Add `aid=$pid` to 133;A and 133;D for nested shell tracking, and fix the
state comparison which was incorrectly using `constantly` (comparing a
string to a function, which always evaluated to true).

OSC 133;B (input start) and 133;P;k=r (right prompt) cannot be reliably
implemented at the script level because Elvish escapes control
characters in prompt function output, and writing directly to /dev/tty
has timing issues because Elvish renders its prompts on a background
thread. Full semantic prompt support requires a native implementation:
elves/elvish#1917

See: ghostty-org#10523

* if search is active dont apply unfocused options

* i18n: update Indonesian translation (id_ID)

* Update es_AR.po

Minor updates

* Update es_AR.po

* Update es_AR.po

* Update VOUCHED list (ghostty-org#11228)

Triggered by
[comment](ghostty-org#11227 (comment))
from @00-kat.

Vouch: @dariogriffo

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* macos: fix quick terminal glassy background

* Update VOUCHED list (ghostty-org#11230)

Triggered by [discussion
comment](ghostty-org#11125 (comment))
from @mitchellh.

Vouch: @pauley-unsaturated

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* fix: list-actions outputs without `--docs`

Explicitly flush the buffer once the generation is complete.

Resolves ghostty-org#11221

* Update VOUCHED list (ghostty-org#11232)

Triggered by
[comment](ghostty-org#11231 (comment))
from @mitchellh.

Vouch: @dmehala

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update es_AR.po

* vt: align SGR C enum tags with parser output

Remove the stale GHOSTTY_SGR_ATTR_RESET_UNDERLINE entry from the C header
and renumber subsequent GhosttySgrAttributeTag values to match
src/terminal/sgr.zig Attribute.Tag ordering.

This fixes misclassified attributes from ghostty_sgr_next for C consumers
that switch on the enum tags from include/ghostty/vt/sgr.h.

* Update VOUCHED list (ghostty-org#11240)

Triggered by [discussion
comment](ghostty-org#11207 (comment))
from @mitchellh.

Vouch: @MOlechowski

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* pass search active state through blueprint

* Update VOUCHED list (ghostty-org#11247)

Triggered by [discussion
comment](ghostty-org#11246 (comment))
from @jcollie.

Vouch: @jmcgover

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* macos: add AppleScript front window and focused terminal properties

This adds two new propeties to make it easy to get the frontmost (main)
window and the focused terminal within a tab. We already had a property
to get the selected tab of a tab group.

* bash: only define $__ghostty_ps0 when unset

This fixes an error if the script was sourced a second time:

    bash: __ghostty_ps0: readonly variable

Because this is a non-exported variable, this would only happen if the
script was sourced multiple times in the same bash session.

* bash: handle existing ; in PROMPT_COMMAND

If an existing PROMPT_COMMAND was a string ending in ; (and maybe some
spaces), we'd add a redundant ;, resulting in a syntax error. Now we
strip any trailing `;[[:space:]]*` characters from the original string
before add ours.

* terminal: fix grapheme edge-wrap hyperlink integrity panic

When a grapheme expands to width 2 at the screen edge, this path can write
spacer_head before printWrap() sets row.wrap. With an active hyperlink,
printCell triggers hyperlink bookkeeping and page integrity checks in that
intermediate state, causing UnwrappedSpacerHead.

Mark row.wrap before writing spacer_head in this grapheme-wrap path to keep
the intermediate state valid.

* macOS: filter proper intrinsicContentSize when opening new window

Fixes ghostty-org#11256

* Revert "macOS: filter proper intrinsicContentSize when opening new window (ghostty-org#11257)"

This reverts commit 3445c9a, reversing
changes made to 1e981f8.

* macos: increase window-width/height apply delay from 10ms to 40ms

Band-aid for ghostty-org#10304

We don't have a robust fix yet but this should help mitigate more
scenarios.

* Bump version to 1.3.0

* Update VOUCHED list (ghostty-org#11275)

Triggered by [discussion
comment](ghostty-org#11274 (comment))
from @jcollie.

Vouch: @seruman

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* docs: update bell-features docs for macOS

PR ghostty-org#11154 didn't fully update the docs regarding `bell-features=audio`
on macOS.

* Update VOUCHED list (ghostty-org#11314)

Triggered by [discussion
comment](ghostty-org#11287 (comment))
from @mitchellh.

Vouch: @ocean6954

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Update VOUCHED list (ghostty-org#11318)

Triggered by [discussion
comment](ghostty-org#11309 (comment))
from @mitchellh.

Vouch: @dzhlobo

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>

* Fix PR CI and new-window working-directory handling

* Format AGENTS.md for prettier

---------

Signed-off-by: Balázs Szücs <bszucs1209@gmail.com>
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Mitchell Hashimoto <m@mitchellh.com>
Co-authored-by: Kat <65649991+00-kat@users.noreply.github.com>
Co-authored-by: trag1c <dev@jakubr.me>
Co-authored-by: A-AKB <abdurrahmanakb@icloud.com>
Co-authored-by: ghostty-vouch[bot] <262049992+ghostty-vouch[bot]@users.noreply.github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Jeffrey C. Ollie <jeff@ocjtech.us>
Co-authored-by: Balázs Szücs <bszucs1209@gmail.com>
Co-authored-by: Abdurrahman <96236378+abdurrahmanski@users.noreply.github.com>
Co-authored-by: Lukas <134181853+bo2themax@users.noreply.github.com>
Co-authored-by: Caleb Spare <cespare@gmail.com>
Co-authored-by: Ulrich Drepper <github@akkadia.org>
Co-authored-by: Alexandre Antonio Juca <corextechnologies@gmail.com>
Co-authored-by: Guilherme Nandi Tiscoski <github@guilhermetiscoski.com>
Co-authored-by: rhodes-b <59537185+rhodes-b@users.noreply.github.com>
Co-authored-by: Leah Amelia Chen <hi@pluie.me>
Co-authored-by: Riccardo Mazzarini <me@noib3.dev>
Co-authored-by: Alaa Ali <alaa@gokarla.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anh Thang Bui <buianhthang89@gmail.com>
Co-authored-by: Jon Parise <jon@indelible.org>
Co-authored-by: Baurzhan Muftakhidinov <baurthefirst@gmail.com>
Co-authored-by: Michielvk <16121929+Michielvk@users.noreply.github.com>
Co-authored-by: Tim Culverhouse <tim@timculverhouse.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: José Miguel Sarasola <alosarjos@gmail.com>
Co-authored-by: 04cb <0x04cb@gmail.com>
Co-authored-by: Ken VanDine <ken@vandine.org>
Co-authored-by: halosatrio <63773815+halosatrio@users.noreply.github.com>
Co-authored-by: Dario Griffo <dariogriffo@users.noreply.github.com>
Co-authored-by: Damien Mehala <gh@sunnymail.cc>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support semantic prompts (OSC 133)

1 participant