From f1ec87a5117b40bf2947850d5ce115df7186a565 Mon Sep 17 00:00:00 2001 From: Chad Horohoe Date: Fri, 10 Oct 2025 09:44:04 -0700 Subject: [PATCH] Support ZDOTDIR when installing zsh completion This both supports the correct location of .zshrc, as well as putting .zfunc as a subdirectory of ZDOTDIR. Tested with ZDOTDIR set to ~/.config/zsh and everything worked as expected. Fixes #171 --- typer/_completion_shared.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/typer/_completion_shared.py b/typer/_completion_shared.py index cc0add992c..aaeb959b22 100644 --- a/typer/_completion_shared.py +++ b/typer/_completion_shared.py @@ -123,12 +123,22 @@ def install_bash(*, prog_name: str, complete_var: str, shell: str) -> Path: def install_zsh(*, prog_name: str, complete_var: str, shell: str) -> Path: # Setup Zsh and load ~/.zfunc - zshrc_path = Path.home() / ".zshrc" - zshrc_path.parent.mkdir(parents=True, exist_ok=True) + zdotdir = os.getenv("ZDOTDIR") + zdotdir_path = Path(zdotdir).expanduser() if zdotdir else Path.home() + zshrc_path = zdotdir_path / ".zshrc" + zfunc_path = zdotdir_path / ".zfunc" + zfunc_path.mkdir(parents=True, exist_ok=True) + + # If zfunc_path is in home, replace it with ~ for the fpath line + if zfunc_path.is_relative_to(Path.home()): + fpath = zfunc_path.as_posix().replace(Path.home().as_posix(), "~") + else: + fpath = zfunc_path.as_posix() + zshrc_content = "" if zshrc_path.is_file(): zshrc_content = zshrc_path.read_text() - completion_line = "fpath+=~/.zfunc; autoload -Uz compinit; compinit" + completion_line = f"fpath+={fpath}; autoload -Uz compinit; compinit" if completion_line not in zshrc_content: zshrc_content += f"\n{completion_line}\n" style_line = "zstyle ':completion:*' menu select" @@ -140,8 +150,7 @@ def install_zsh(*, prog_name: str, complete_var: str, shell: str) -> Path: zshrc_content = f"{zshrc_content.strip()}\n" zshrc_path.write_text(zshrc_content) # Install completion under ~/.zfunc/ - path_obj = Path.home() / f".zfunc/_{prog_name}" - path_obj.parent.mkdir(parents=True, exist_ok=True) + path_obj = zfunc_path / f"_{prog_name}" script_content = get_completion_script( prog_name=prog_name, complete_var=complete_var, shell=shell )