Commit Graph

185 Commits

Author SHA1 Message Date
Jon Parise
059bd54a5d 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:
https://github.com/elves/elvish/pull/1917

See: #10523
2026-03-07 20:34:20 -05:00
Jon Parise
42540f44cd fix: zsh shell integration when sudo and ssh aliases are defined (#11185)
I encountered an issue related to
https://github.com/ghostty-org/ghostty/discussions/8641 and
https://github.com/ghostty-org/ghostty/pull/8647, but in `zsh` instead
of `bash`.

One of my aliases is:

```bash
alias sudo='sudo '
```

Which causes following error when sourcing the zsh shell integrations:

```shell
source /usr/share/ghostty/shell-integration/zsh/ghostty-integration
/usr/share/ghostty/shell-integration/zsh/ghostty-integration:149: defining function based on alias `sudo'
/usr/share/ghostty/shell-integration/zsh/ghostty-integration:233: parse error near `()'
```
2026-03-05 09:08:21 -05:00
Mitchell Hashimoto
226d0b9918 zsh: fix extra newlines with leading-newline prompts (#11166)
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: #11003
2026-03-04 11:09:10 -08:00
Jon Parise
9386fa6499 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: #10555
2026-03-04 12:48:02 -05:00
Jon Parise
9a3dbe10b0 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: #11003
2026-03-04 12:47:05 -05:00
Michielvk
e07aefa601 fix: zsh shell integration when sudo and ssh aliases are defined 2026-03-04 18:22:29 +01:00
Michael Engelhard
875985dbd7 zsh: fix ssh-terminfo shell integration to not interpret escape characters 2026-02-26 13:06:07 +01:00
Mitchell Hashimoto
7895bf1d02 shell-integration: respect cursor-style-blink (#10643)
The `cursor` shell feature always used a blinking bar (beam), often to
the surprise of users who set `cursor-style-blink = false`.

This change extends our GHOSTTY_SHELL_FEATURES format to include either
`cursor:blink` (default) or `cursor:steady` based on cursor-style-blink
when the `cursor` feature is enabled, and all shell integrations have
been updated to use that additional information to choose the DECSCUSR
cursor value (5=blinking bar, 6=steady bar).

I also considered passing a DECSCUSR value in GHOSTTY_SHELL_FEATURES
(e.g. `cursor:5`). This mostly worked well, but zsh also needs the blink
state on its own for its block cursor. We also don't support any other
shell feature cursor configurability (e.g. the shape), so this was an
over generalization.

This does change the behavior for users who like the blinking bar in the
shell but have `cursor-blink-style = false` for other reasons. We could
provide additional `cursor` shell feature configurability (e.g.
`cursor:blink` in `shell-integration-features`), but I'll propose that
as its own change.

See: #2812
Closes: #8681

---

**AI Disclosure:** I did a lot of rubber ducking with Claude Code while
trying out various ideas. It was particularly useful for this kind of
feature because I could try out one thing and have it evaluate the
impact on all of the shell integration scripts at once.
2026-02-16 14:08:23 -08:00
Jon Parise
e5e063c89d zsh: update PS1 substitution to include 'cl=line'
Our PS1 cleanup code (where we remove any markers we added) was still
looking for the previous 133;A form. Update it to include 'cl=line',
which was added in 8595558.
2026-02-16 16:49:03 -05:00
Jon Parise
897b918f67 bash: remove redundant out-of-band OSC 133;A
The printf was part of the original script (9d6121245), and at the time,
this was the only place we'd emit the 133;A mark.

A PS1-based 133;P;k=i mark was introduced in 2bf1f80f7, and then it
become a full 133;A mark in aa47047a6, making the original printf line
redundant (because bash will also redraw PS1 on SIGWINCH).

The PS1-based 133;A was only missing the aid= option, and with that
added, it handles all of our cases (prompts, initial draw, and resizes).
2026-02-16 13:46:55 -05:00
Jon Parise
a271f85cd2 bash: preserve existing PS0 value
We were previously overwriting PS0 on every PROMPT_COMMAND. We now
append to PS0, but only if it doesn't already contain our hook.

This is also more consistent with the bash-preexec behavior we maintain
for older bash versions.
2026-02-12 12:02:23 -05:00
Jon Parise
3cfb9d64d1 shell-integration: respect cursor-style-blink
The `cursor` shell feature always used a blinking bar (beam), often to
the surprise of users who set `cursor-style-blink = false`.

This change extends our GHOSTTY_SHELL_FEATURES format to include either
`cursor:blink` (default) or `cursor:steady` based on cursor-style-blink
when the `cursor` feature is enabled, and all shell integrations have
been updated to use that additional information to choose the DECSCUSR
cursor value (5=blinking bar, 6=steady bar).

I also considered passing a DECSCUSR value in GHOSTTY_SHELL_FEATURES
(e.g. `cursor:5`). This mostly worked well, but zsh also needs the blink
state on its own for its block cursor. We also don't support any other
shell feature cursor configurability (e.g. the shape), so this was an
over generalization.

This does change the behavior for users who like the blinking bar in the
shell but have `cursor-blink-style = false` for other reasons. We could
provide additional `cursor` shell feature configurability, but I think
that's best left to a separate change.
2026-02-10 18:46:36 -05:00
Mitchell Hashimoto
f831258c0f elvish: improve the sudoedit detection code (#10587)
The previous logic didn't detect the `e` option when it was combined
with other flags (e.g. `-ie`). This change also attempts to improve the
general readability of this code to be a bit more explicit.
2026-02-10 15:36:36 -08:00
Jon Parise
d0b403304d bash: use PROMPT_COMMAND array form in bash 5.1+
PROMPT_COMMAND array support for introduced in bash 5.1, and it's the
preferred format moving forward. Using the string form is also fine, but
it's easy to be a modern bash citizen here, so let's do so.
2026-02-08 09:40:05 -05:00
Jon Parise
5425569a19 bash: remove dependency on bash-preexec for bash 4.4+
bash-preexec implements support for its "precmd" and "preexec" hooks
using a combination of PROMPT_COMMAND and a DEBUG trap. The latter is
unfortunately quick slow (in a relative sense), and the overall system
is a bit more generalized than what we need for our shell integration
(e.g. supporting multiple function hooks, subshells, etc.).

Bash 4.4 introduced the PS0 variable, which is expanded and displayed by
interactive shells after reading a complete command but before executing
it. This is all we need to implement our own shell integration hooks.

In Bash 5.1, PROMPT_COMMAND can be an array variable, each element of
which can contain a command to be executed like a string PROMPT_COMMAND
variable. When adding our hook to PROMPT_COMMAND, we preserve its type
(string or array) to be minimally intrusive. This also matches direnv's
approach.

Bash 5.3 introduced support for function substitution, which is an even
more efficient way to run code from PS0, so we use that when available.
Otherwise, we use the more traditional command substitution approach.

Earlier versions of bash (such as 3.2, which still ships with macOS)
continue to use the bash-preexec path. This gives us two code paths to
maintain, but I think that's preferable to fully maintaining our own
DEBUG trap-based system for older bash versions given that bash-preexec
has proven to work reliably in those environments. We also wouldn't
unlock any other user benefits aside from removing the bash-preexec
script dependency.

See: #3724, #7734
2026-02-07 15:29:04 -05:00
Jeffrey C. Ollie
290ad05ea6 fix fish shell integration when cancelling a command
Cancelling a command should not send `OSC 133;A` as that starts a new
line.

Fixes #10544
2026-02-06 09:49:13 -06:00
Jon Parise
95a4d1675b elvish: improve the sudoedit detection code
The previous logic didn't detect the `e` option when it was combined
with other flags (e.g. `-ie`). This change also attempts to improve the
general readability of this code to be a bit more explicit.
2026-02-05 11:07:49 -05:00
Mitchell Hashimoto
51897c0cd5 elvish: simplify XDG_DATA_DIRS cleanup (#10546)
We always add GHOSTTY_SHELL_INTEGRATION_XDG_DIR to XDG_DATA_DIRS with a
tailing colon (via our prependEnv routine), so we can greatly simplify
this cleanup code with a single str:replace call.
2026-02-02 20:02:24 -08:00
Jon Parise
6a04662303 elvish: simplify XDG_DATA_DIRS cleanup
We always add GHOSTTY_SHELL_INTEGRATION_XDG_DIR to XDG_DATA_DIRS with a
tailing colon (via our prependEnv routine), so we can greatly simplify
this cleanup code with a single str:replace call.
2026-02-02 20:24:25 -05:00
Mitchell Hashimoto
8595558653 shell-integration/zsh: support cl=line 2026-02-02 15:13:37 -08:00
Mitchell Hashimoto
2fa9eff0ef shell-integration/bash: advertise cl=line support 2026-02-02 13:36:29 -08:00
Mitchell Hashimoto
608d312651 Support OSC133 click_events Kitty extension (supported by Fish) (#10536)
This adds support for the `OSC 133 A click_events=1` extension
introduced by Kitty and supported by Fish.[^1]

**What this means:** If the shell advertises `click_events=1` support,
Ghostty will _unconditionally_ (no modifier required) send mouse events
to the shell for clicks on a prompt line, delegating to the supporting
shell to move the cursor as needed. For Fish 4.1+ this means that
clicking on the prompt line moves the cursor (see demo video below).

This PR also contains:

* A minor fix in `cl` parsing but we don't yet implement the logic there
* Updated inspector to show the semantic prompt click mode

## Demo


https://github.com/user-attachments/assets/03ef8975-7ad9-441f-aaa2-9d0eb5c5e36d

## Implementation Details

`click_events` is wildly underspecified, so here are the details the
best I understand them. This itself is not a specification (I omit
details) but adds some more context to it.

The `click_events=1` option can be specified with `OSC 133 A` (Ghostty
also allows it on OSC 133 N). When that is specified, it flags for all
future prompts that the screen supports click events for semantic
prompts. If both `click_events` and `cl` are specified, `click_events`
takes priority if true. If `click_events=0` (disable), then any set `cl`
will take priority.

When a mouse click comes in, we check for the following conditions:

1. The screen supports click events
2. The screen cursor is currently at a prompt
3. The mouse click was at or below the starting prompt line of the
current prompt

If those are met, we encode an SGR mouse event with: left button, press,
coordinates of click. It is up to the shell after that to handle it. Out
of prompt bounds SGR events are possible (specifically below). The shell
should robustly handle this.

[^1]: I don't know any other terminal or shell that supports it at the
moment.
2026-02-02 10:57:30 -08:00
Mitchell Hashimoto
e20a8ee797 shell-integration: fish sets click_events=1 for Fish >= 4.1 2026-02-02 10:44:35 -08:00
Jeffrey C. Ollie
93f12b675c elvish: improve shell integration instructions (#10534)
Wrapping `use ghostty-integration` in a `try .. catch` here makes this
suggestion more resilient to environments where we didn't inject our
resource directory into XDG_DATA_DIRS (but are still running Ghostty).
2026-02-02 11:40:41 -06:00
Mitchell Hashimoto
8bc3cdcf7d nushell: refactor ssh wrapper for clarity (#10490)
The ssh wrapper previously used a separate set_ssh_terminfo function
that returned a record to be merged, which result in some redundant
control flow and TERM assignments.

This inlines the terminfo logic and builds env/opts incrementally based
on feature flags. TERM is set to a fallback early and only overridden on
success, which simplifies our error handling and avoids mutable variable
capture issues in closures.

Lastly, warnings are now consistently written to stderr, and I made
various other control flow and syntax improvements.
2026-02-02 08:37:47 -08:00
Jon Parise
95c6fca0a7 elvish: improve shell integration instructions
Wrapping `use ghostty-integration` in a `try .. catch` here makes this
suggestion more resilient to environments where we didn't inject our
resource directory into XDG_DATA_DIRS (but are still running Ghostty).
2026-02-02 11:33:40 -05:00
Jon Parise
37a534b747 elvish: always report current directory changes
This reporting shouldn't have been tied to the 'title' shell features.
That's a different feature where we change the window title (icon) to
reflect the current command using OSC 2.
2026-02-02 11:06:47 -05:00
Mitchell Hashimoto
92d6dde583 shell-integration/zsh: set proper input and secondary prompt marks 2026-01-31 19:34:02 -08:00
Mitchell Hashimoto
918c2934a3 terminal: add redraw=last for bash for OSC133 2026-01-31 15:26:14 -08:00
Mitchell Hashimoto
4bee8202a8 shell-integration/bash: mark each line in multiline prompts as secondary
Insert OSC 133 A k=s marks after each newline in PS1, so that all lines
following the first are marked as secondary prompts. This prevents ghostty
from erasing leading lines during terminal resize.
2026-01-31 14:46:18 -08:00
Jon Parise
984ff2b402 nushell: refactor ssh wrapper for clarity
The ssh wrapper previously used a separate set_ssh_terminfo function
that returned a record to be merged, which result in some redundant
control flow and TERM assignments.

This inlines the terminfo logic and builds env/opts incrementally based
on feature flags. TERM is set to a fallback early and only overridden on
success, which simplifies our error handling and avoids mutable variable
capture issues in closures.

Lastly, warnings are now consistently written to stderr, and I made
various other control flow and syntax improvements.
2026-01-29 15:03:05 -05:00
David Matos
675fa34e66 unnecesary bind 2026-01-27 00:59:39 +01:00
David Matos
d70eef69f9 address changes 2026-01-27 00:51:50 +01:00
David Matos
0a2b90ed64 Expand Readme to reflect new changes 2026-01-21 13:31:08 +01:00
David Matos
b87e8d8172 Update to new nu ssh ghostty integration 2026-01-21 13:19:53 +01:00
David Matos
6d1125951e Merge branch 'main' into nu-ssh-support 2026-01-21 09:06:42 +01:00
Mitchell Hashimoto
63075c926e shell-integration: initial nushell shell integration (#10274)
Nushell <https://www.nushell.sh/> is a modern interactive shell that
provides many shell features out-of-the-box, like `title` support. Our
shell integration therefore focuses on Ghostty-specific features like
`sudo`.

We use Nushell's module system to provide a `ghostty` module containing
our shell integration features. This module is automatically loaded from
$XDG_DATA_DIRS/nushell/vendor/autoload/ when `nushell` shell integration
is enabled.

Exported module functions need to be explicitly "used" before they're
available to the interactive shell environment. We do that automatically
by adding `--execute "use ghostty *"` to the `nu` command line.

This imports all available functions, and individual shell features are
runtime-guarded by the script code (using $GHOSTTY_SHELL_FEATURES). We
can consider further refining this later.

When automatic shell integration is disabled, users can still manually
source and enable the shell integration module:

source
$GHOSTTY_RESOURCES_DIR/shell-integration/nushell/vendor/autoload/ghostty.nu
    use ghostty *

This initial work implements our TERMINFO-aware `sudo` wrapper (via the
`sudo` shell feature). Support for additional features, like `ssh-env`
and `ssh-terminfo`, will follow (#9604).
2026-01-20 08:33:13 -08:00
Jon Parise
ca924f4f45 zsh: improve title-related comment 2026-01-16 08:53:18 -05:00
Julian Haag
3ca8b97ca7 fix(zsh): strip control characters from window title
The zsh shell integration was using `${(V)1}` parameter expansion to set
the window title, which converts control characters to their visible
escape sequence representations. This caused commands ending with a
newline to display as `command\n` in the title bar.

Changed to use `${1//[[:cntrl:]]}` which strips control characters
entirely, matching the behavior of the bash integration.
2026-01-16 10:53:50 +01:00
Jon Parise
7e3c9f4d5a shell-integration: initial nushell shell integration
Nushell <https://www.nushell.sh/> is a modern interactive shell that
provides many shell features out-of-the-box, like `title` support. Our
shell integration therefore focuses on Ghostty-specific features like
`sudo`.

We use Nushell's module system to provide a `ghostty` module containing
our shell integration features. This module is automatically loaded from
$XDG_DATA_DIRS/nushell/vendor/autoload/ when `nushell` shell integration
is enabled.

Exported module functions need to be explicitly "used" before they're
available to the interactive shell environment. We do that automatically
by adding `--execute "use ghostty *"` to the `nu` command line.

This imports all available functions, and individual shell features are
runtime-guarded by the script code (using $GHOSTTY_SHELL_FEATURES). We
can consider further refining this later.

When automatic shell integration is disabled, users can still manually
source and enable the shell integration module:

    source $GHOSTTY_RESOURCES_DIR/shell-integration/nushell/vendor/autoload/ghostty.nu
    use ghostty *

This initial work implements our TERMINFO-aware `sudo` wrapper (via the
`sudo` shell feature). Support for additional features, like `ssh-env`
and `ssh-terminfo`, will follow.
2026-01-11 11:27:19 -05:00
Mitchell Hashimoto
8ed7cce203 zsh: removed unused self_dir variable (#9924)
This came from the original Kitty script on which ours is based, but we
don't use it.
2025-12-16 06:38:56 -08:00
Jon Parise
c4cd2ca81d zsh: removed unused self_dir variable
This came from the original Kitty script on which ours is based, but we
don't use it.
2025-12-16 08:27:00 -05:00
Jon Parise
b0c053cfb7 zsh: document unsupported system-level ZDOTDIR
We rely on temporarily setting ZDOTDIR to our `zsh` resource directory
to implement automatic shell integration. Setting ZDOTDIR in a system
file like /etc/zshenv overrides our ZDOTDIR value, preventing our shell
integration from being loaded.

The only way to prevent /etc/zshenv from being run is via the --no-rcs
flag. (The --no-globalrcs only applies to system-level files _after_
/etc/zshenv is loaded.) Unfortunately, there doesn't appear to be a way
to run a "bootstrap" script (to reimplement the Zsh startup sequence
manually, similar to how our bash integration works) and then enter an
interactive shell session.

https://zsh.sourceforge.io/Doc/Release/Files.html

Given all of the above, document this as an unsupported configuration
for automatic shell integration and point affected users at our manual
shell integration option.
2025-12-14 20:24:41 -05:00
definfo
4a04efaff1 fix: explicitly allow preservation for TERMINFO in shell-integration
Due to security issues, `sudo` implementations may not preserve
environment variables unless appended with `--preserve-env=list`.

Signed-off-by: definfo <hjsdbb1@gmail.com>
2025-12-13 16:55:41 +08:00
David Matos
07f4ef8e47 Alternative approach by unconditionally setting xdgDataDirs and checking features with nu 2025-12-06 00:48:14 +01:00
David Matos
d69e16c168 Use external cmd
Remove redundant `into record`
2025-12-04 13:08:04 +01:00
David
fdf0f5278c Merge and fix conflict on README 2025-12-03 22:26:07 +01:00
David
a521819882 Address changes
fixes logic bug when adding cache
2025-12-03 22:04:52 +01:00
Mitchell Hashimoto
8d25ab0ae3 zsh: improve ZDOTDIR documentation (#9779)
The main thing to emphasize is that end users should never source
.zshenv directly; it's only meant to be used as part of our shell
injection environment.

At the moment, there's no way to guard against accidentally use, but we
can consider making e.g. GHOSTTY_SHELL_FEATURES always defined in this
environment to that it can be used to differentiate the cases.

In practice, it's unlikely that people actually source this .zshenv
script directly, so hopefully this additional documentation clarifies
things well enough.
2025-12-02 11:13:10 -08:00
Jon Parise
6babcc97f5 zsh: move version check to ghostty-integration
The ghostty-integration script can be manually sourced, and it uses the
Zsh 5.1+ features, so that's a better place to guard against older Zsh
versions.

This also keeps the .zshenv script focused on just bootstrapping our
automatic shell integration.

I also changed the version check to a slightly more idiomatic pattern.
2025-12-01 20:34:55 -05:00