diff --git a/kitty/shell_integration.py b/kitty/shell_integration.py index 502d83d50..4d31c77d9 100644 --- a/kitty/shell_integration.py +++ b/kitty/shell_integration.py @@ -68,23 +68,32 @@ def setup_fish_env(env: Dict[str, str]) -> None: def is_new_zsh_install(env: Dict[str, str]) -> bool: + # if ZDOTDIR is empty, zsh will read user rc files from / + # if there aren't any, it'll run zsh-newuser-install + # the latter will bail if there are rc files in $HOME zdotdir = env.get('ZDOTDIR') - base = zdotdir or os.path.expanduser('~') + if not zdotdir: + zdotdir = os.path.expanduser('~') + if zdotdir == '~': + return True for q in ('.zshrc', '.zshenv', '.zprofile', '.zlogin'): - if os.path.exists(os.path.join(base, q)): + if os.path.exists(os.path.join(zdotdir, q)): return False return True def setup_zsh_env(env: Dict[str, str]) -> None: - zdotdir = env.get('ZDOTDIR') - base = zdotdir or os.path.expanduser('~') if is_new_zsh_install(env): # dont prevent zsh-newuser-install from running + # zsh-newuser-install never runs as root but we assume that it does return + zdotdir = env.get('ZDOTDIR') if zdotdir is not None: env['KITTY_ORIG_ZDOTDIR'] = zdotdir - env['KITTY_ZSH_BASE'] = base + else: + # KITTY_ORIG_ZDOTDIR can be set at this point if, for example, the global + # zshenv overrides ZDOTDIR; we try to limit the damage in this case + env.pop('KITTY_ORIG_ZDOTDIR', None) env['ZDOTDIR'] = os.path.join(shell_integration_dir, 'zsh') diff --git a/shell-integration/zsh/.zshenv b/shell-integration/zsh/.zshenv index 468204026..d152a2596 100644 --- a/shell-integration/zsh/.zshenv +++ b/shell-integration/zsh/.zshenv @@ -1,9 +1,32 @@ -if [[ -o interactive && -v ZDOTDIR && -r "$ZDOTDIR/kitty.zsh" ]]; then source "$ZDOTDIR/kitty.zsh"; fi -if [[ -v KITTY_ORIG_ZDOTDIR ]]; then - export ZDOTDIR="$KITTY_ORIG_ZDOTDIR" +# Don't use [[ -v ... ]] because it doesn't work in zsh < 5.4. +if (( ${+KITTY_ORIG_ZDOTDIR} )); then + # Normally ZDOTDIR shouldn't be exported but it was in the environment + # of Kitty, so we export it. + export ZDOTDIR=$KITTY_ORIG_ZDOTDIR unset KITTY_ORIG_ZDOTDIR else unset ZDOTDIR fi -if [[ -v KITTY_ZSH_BASE && -r "$KITTY_ZSH_BASE/.zshenv" ]]; then source "$KITTY_ZSH_BASE/.zshenv"; fi -unset KITTY_ZSH_BASE + +# Use try-always to have the right error code. +{ + # Zsh treats empty $ZDOTDIR as if it was "/". We do the same. + # + # Source the user's zshenv before sourcing kitty.zsh because the former + # might set fpath and other things without which kitty.zsh won't work. + # + # Use typeset in case we are in a function with warn_create_global in + # effect. Unlikely but better safe than sorry. + typeset _ksi_source=${ZDOTDIR-~}/.zshenv + # Zsh ignores unreadable rc files. We do the same. + # Zsh ignores rc files that are directories, and so does source. + [[ ! -r $_ksi_source ]] || source -- "$_ksi_source" +} always { + if [[ -o interactive ]]; then + # ${(%):-%x} is the path to the current file. + # On top of it we add :a:h to get the directory. + typeset _ksi_source=${${(%):-%x}:A:h}/kitty.zsh + [[ ! -r $_ksi_source ]] || source -- "$_ksi_source" + fi + unset _ksi_source +}