mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-21 03:06:15 +03:00

The intention of #5075 was to create a less intrusive, more hermetic environment in which to source the bash startup files. This caused problems for multiple people, and I believe that's because the general expectation is that these files are sourced at global (not function) scope. For example, when a file is sourced from within a function scope, any variables that weren't explicitly exported into the global environment won't be available outside of the scope of the function. Most system and personal startup files aren't written with that constraint because it's not how bash itself loads these files. As a small improvement over the original code, `rcfile` has been renamed to `__ghostty_rcfile`. Avoiding leaking this variable while sourcing these files was a goal of #5075, and prefixing it make it much less of a potential issue. This change also reverts the $HOME to ~/ change. While the ~/ notation is more concise, using $HOME is more common and easier to implement safely with regard to quoting.
175 lines
6.4 KiB
Bash
175 lines
6.4 KiB
Bash
# Parts of this script are based on Kitty's bash integration. Kitty is
|
|
# distributed under GPLv3, so this file is also distributed under GPLv3.
|
|
# The license header is reproduced below:
|
|
#
|
|
# This program is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# We need to be in interactive mode and we need to have the Ghostty
|
|
# resources dir set which also tells us we're running in Ghostty.
|
|
if [[ "$-" != *i* ]] ; then builtin return; fi
|
|
if [ -z "$GHOSTTY_RESOURCES_DIR" ]; then builtin return; fi
|
|
|
|
# When automatic shell integration is active, we were started in POSIX
|
|
# mode and need to manually recreate the bash startup sequence.
|
|
if [ -n "$GHOSTTY_BASH_INJECT" ]; then
|
|
# Store a temporary copy of our startup flags and unset these global
|
|
# environment variables so we can safely handle reentrancy.
|
|
builtin declare __ghostty_bash_flags="$GHOSTTY_BASH_INJECT"
|
|
builtin unset ENV GHOSTTY_BASH_INJECT
|
|
|
|
# Restore bash's default 'posix' behavior. Also reset 'inherit_errexit',
|
|
# which doesn't happen as part of the 'posix' reset.
|
|
builtin set +o posix
|
|
builtin shopt -u inherit_errexit 2>/dev/null
|
|
|
|
# Unexport HISTFILE if it was set by the shell integration code.
|
|
if [[ -n "$GHOSTTY_BASH_UNEXPORT_HISTFILE" ]]; then
|
|
builtin export -n HISTFILE
|
|
builtin unset GHOSTTY_BASH_UNEXPORT_HISTFILE
|
|
fi
|
|
|
|
# Manually source the startup files. See INVOCATION in bash(1) and
|
|
# run_startup_files() in shell.c in the Bash source code.
|
|
if builtin shopt -q login_shell; then
|
|
if [[ $__ghostty_bash_flags != *"--noprofile"* ]]; then
|
|
[ -r /etc/profile ] && builtin source "/etc/profile"
|
|
for __ghostty_rcfile in "$HOME/.bash_profile" "$HOME/.bash_login" "$HOME/.profile"; do
|
|
[ -r "$__ghostty_rcfile" ] && { builtin source "$__ghostty_rcfile"; break; }
|
|
done
|
|
fi
|
|
else
|
|
if [[ $__ghostty_bash_flags != *"--norc"* ]]; then
|
|
# The location of the system bashrc is determined at bash build
|
|
# time via -DSYS_BASHRC and can therefore vary across distros:
|
|
# Arch, Debian, Ubuntu use /etc/bash.bashrc
|
|
# Fedora uses /etc/bashrc sourced from ~/.bashrc instead of SYS_BASHRC
|
|
# Void Linux uses /etc/bash/bashrc
|
|
# Nixos uses /etc/bashrc
|
|
for __ghostty_rcfile in /etc/bash.bashrc /etc/bash/bashrc /etc/bashrc; do
|
|
[ -r "$__ghostty_rcfile" ] && { builtin source "$__ghostty_rcfile"; break; }
|
|
done
|
|
if [[ -z "$GHOSTTY_BASH_RCFILE" ]]; then GHOSTTY_BASH_RCFILE="$HOME/.bashrc"; fi
|
|
[ -r "$GHOSTTY_BASH_RCFILE" ] && builtin source "$GHOSTTY_BASH_RCFILE"
|
|
fi
|
|
fi
|
|
|
|
builtin unset __ghostty_rcfile
|
|
builtin unset __ghostty_bash_flags
|
|
builtin unset GHOSTTY_BASH_RCFILE
|
|
fi
|
|
|
|
# Sudo
|
|
if [[ "$GHOSTTY_SHELL_INTEGRATION_NO_SUDO" != "1" && -n "$TERMINFO" ]]; then
|
|
# Wrap `sudo` command to ensure Ghostty terminfo is preserved.
|
|
#
|
|
# This approach supports wrapping a `sudo` alias, but the alias definition
|
|
# must come _after_ this function is defined. Otherwise, the alias expansion
|
|
# will take precedence over this function, and it won't be wrapped.
|
|
function sudo {
|
|
builtin local sudo_has_sudoedit_flags="no"
|
|
for arg in "$@"; do
|
|
# Check if argument is '-e' or '--edit' (sudoedit flags)
|
|
if [[ "$arg" == "-e" || $arg == "--edit" ]]; then
|
|
sudo_has_sudoedit_flags="yes"
|
|
builtin break
|
|
fi
|
|
# Check if argument is neither an option nor a key-value pair
|
|
if [[ "$arg" != -* && "$arg" != *=* ]]; then
|
|
builtin break
|
|
fi
|
|
done
|
|
if [[ "$sudo_has_sudoedit_flags" == "yes" ]]; then
|
|
builtin command sudo "$@";
|
|
else
|
|
builtin command sudo TERMINFO="$TERMINFO" "$@";
|
|
fi
|
|
}
|
|
fi
|
|
|
|
# Import bash-preexec, safe to do multiple times
|
|
builtin source "$GHOSTTY_RESOURCES_DIR/shell-integration/bash/bash-preexec.sh"
|
|
|
|
# This is set to 1 when we're executing a command so that we don't
|
|
# send prompt marks multiple times.
|
|
_ghostty_executing=""
|
|
_ghostty_last_reported_cwd=""
|
|
|
|
function __ghostty_precmd() {
|
|
local ret="$?"
|
|
if test "$_ghostty_executing" != "0"; then
|
|
_GHOSTTY_SAVE_PS0="$PS0"
|
|
_GHOSTTY_SAVE_PS1="$PS1"
|
|
_GHOSTTY_SAVE_PS2="$PS2"
|
|
|
|
# Marks
|
|
PS1=$PS1'\[\e]133;B\a\]'
|
|
PS2=$PS2'\[\e]133;B\a\]'
|
|
|
|
# bash doesn't redraw the leading lines in a multiline prompt so
|
|
# mark the last line as a secondary prompt (k=s) to prevent the
|
|
# preceding lines from being erased by ghostty after a resize.
|
|
if [[ "${PS1}" == *"\n"* || "${PS1}" == *$'\n'* ]]; then
|
|
PS1=$PS1'\[\e]133;A;k=s\a\]'
|
|
fi
|
|
|
|
# Cursor
|
|
if test "$GHOSTTY_SHELL_INTEGRATION_NO_CURSOR" != "1"; then
|
|
PS1=$PS1'\[\e[5 q\]'
|
|
PS0=$PS0'\[\e[0 q\]'
|
|
fi
|
|
|
|
# Title (working directory)
|
|
if [[ "$GHOSTTY_SHELL_INTEGRATION_NO_TITLE" != 1 ]]; then
|
|
PS1=$PS1'\[\e]2;\w\a\]'
|
|
fi
|
|
fi
|
|
|
|
if test "$_ghostty_executing" != ""; then
|
|
# End of current command. Report its status.
|
|
builtin printf "\e]133;D;%s;aid=%s\a" "$ret" "$BASHPID"
|
|
fi
|
|
|
|
# unfortunately bash provides no hooks to detect cwd changes
|
|
# in particular this means cwd reporting will not happen for a
|
|
# command like cd /test && cat. PS0 is evaluated before cd is run.
|
|
if [[ "$_ghostty_last_reported_cwd" != "$PWD" ]]; then
|
|
_ghostty_last_reported_cwd="$PWD"
|
|
builtin printf "\e]7;kitty-shell-cwd://%s%s\a" "$HOSTNAME" "$PWD"
|
|
fi
|
|
|
|
# Fresh line and start of prompt.
|
|
builtin printf "\e]133;A;aid=%s\a" "$BASHPID"
|
|
_ghostty_executing=0
|
|
}
|
|
|
|
function __ghostty_preexec() {
|
|
builtin local cmd="$1"
|
|
|
|
PS0="$_GHOSTTY_SAVE_PS0"
|
|
PS1="$_GHOSTTY_SAVE_PS1"
|
|
PS2="$_GHOSTTY_SAVE_PS2"
|
|
|
|
# Title (current command)
|
|
if [[ -n $cmd && "$GHOSTTY_SHELL_INTEGRATION_NO_TITLE" != 1 ]]; then
|
|
builtin printf "\e]2;%s\a" "${cmd//[[:cntrl:]]}"
|
|
fi
|
|
|
|
# End of input, start of output.
|
|
builtin printf "\e]133;C;\a"
|
|
_ghostty_executing=1
|
|
}
|
|
|
|
preexec_functions+=(__ghostty_preexec)
|
|
precmd_functions+=(__ghostty_precmd)
|