In #7808, we stopped using PS0 to reset the cursor shape because restoring PS0 in __ghostty_preexec was causing issues (#7802). The alternate approach of printing the cursor reset escape sequence directly from __ghostty_preexec caused a new issue: the input cursor would persist longer than intended, such as when a suspended vim process was restored to the foreground. This change takes a different approach. We now conditionally add the cursor shape escape sequences to PS0 (and PS1, for consistency) when they don't already appear. The fixes the cursor shape reset problem. The main downside to this approach is that PS0 will continue to contain this escape sequence; it won't be cleared/reset in __ghostty_preexec for the reasons described in #7808. This feels like an acceptable outcome because there's no harm in the modified PS0 existing for the life of the bash session (rather than it being modified and then restored for each command cycle), and it's consistent with how some other terminals' bash integration works (e.g. kitty).
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_DIRSprepended
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") {
use ghostty-integration
}
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.
Zsh
For zsh, Ghostty sets ZDOTDIR so that it loads our configuration
from the zsh directory. The existing ZDOTDIR is retained so that
after loading the Ghostty shell integration the normal Zsh loading
sequence occurs.
if [[ -n $GHOSTTY_RESOURCES_DIR ]]; then
source "$GHOSTTY_RESOURCES_DIR"/shell-integration/zsh/ghostty-integration
fi