Files
ghostty/src/shell-integration
Jon Parise e31615d00b bash: fix extra newlines with readline vi mode indicator
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
2026-03-11 12:46:14 -04:00
..

Shell Integration Code

This is the shell-specific shell-integration code that is used for the shell-integration feature set that Ghostty supports.

This README is meant as developer documentation and not as user documentation. For user documentation, see the main README or ghostty.org

Implementation Details

Bash

Automatic Bash shell integration works by starting Bash in POSIX mode and using the ENV environment variable to load our integration script (bash/ghostty.bash). This prevents Bash from loading its normal startup files, which becomes our script's responsibility (along with disabling POSIX mode).

Bash shell integration can also be sourced manually from bash/ghostty.bash. This also works for older versions of Bash.

# Ghostty shell integration for Bash. This must be at the top of your bashrc!
if [ -n "${GHOSTTY_RESOURCES_DIR}" ]; then
    builtin source "${GHOSTTY_RESOURCES_DIR}/shell-integration/bash/ghostty.bash"
fi

Note

The version of Bash distributed with macOS (/bin/bash) does not support automatic shell integration. You'll need to manually source the shell integration script (as shown above). You can also install a standard version of Bash from Homebrew or elsewhere and set it as your shell.

Elvish

For Elvish, $GHOSTTY_RESOURCES_DIR/src/shell-integration contains an ./elvish/lib/ghostty-integration.elv file.

Elvish, on startup, searches for paths defined in XDG_DATA_DIRS variable for ./elvish/lib/*.elv files and imports them. They are thus made available for use as modules by way of use <filename>.

Ghostty launches Elvish, passing the environment with XDG_DATA_DIRS prepended with $GHOSTTY_RESOURCES_DIR/src/shell-integration. It contains ./elvish/lib/ghostty-integration.elv. The user can then import it by use ghostty-integration every time after shell startup or autostart integration in $XDG_CONFIG_HOME/elvish/rc.elv, which will run the integration routines.

If you decide to autostart ghostty-integration with rc.elv, you should detect whether the terminal is Ghostty or not. To do this, add this to the end of your rc.elv file:

if (eq $E:TERM "xterm-ghostty") {
  try { use ghostty-integration } catch { }
}

The Elvish shell integration is supported by the community and is not officially supported by Ghostty. We distribute it for ease of access and use but do not provide support for it. If you experience issues with the Elvish shell integration, I welcome any contributions to fix them. Thank you!

Fish

For Fish, Ghostty prepends to the XDG_DATA_DIRS directory. Fish automatically loads configuration files in <XDG_DATA_DIR>/fish/vendor_conf.d/*.fish on startup, allowing us to automatically integrate with the shell. For details on the Fish startup process, see the Fish documentation.

Nushell

For Nushell, Ghostty prepends to the XDG_DATA_DIRS directory, making the ghostty module available through Nushell's vendor autoload mechanism. Ghostty then automatically imports the module using the -e "use ghostty *" flag when starting Nushell.

Nushell provides many shell features itself, such as title and cursor, so our integration focuses on Ghostty-specific features like sudo, ssh-env, and ssh-terminfo.

The shell integration is automatically enabled when running Nushell in Ghostty, but you can also load it manually is shell integration is disabled:

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

Zsh

Automatic Zsh integration works by temporarily setting ZDOTDIR to our zsh directory. An existing ZDOTDIR environment variable value will be retained and restored after our shell integration scripts are run.

However, if ZDOTDIR is set in a system-wide file like /etc/zshenv, it will override Ghostty's ZDOTDIR value, preventing the shell integration from being loaded. In this case, the shell integration needs to be loaded manually.

To load the Zsh shell integration manually:

if [[ -n $GHOSTTY_RESOURCES_DIR ]]; then
  source "$GHOSTTY_RESOURCES_DIR"/shell-integration/zsh/ghostty-integration
fi

Shell integration requires Zsh 5.1+.