diff --git a/tests/test_completion/test_completion_install.py b/tests/test_completion/test_completion_install.py index f6194695fe..6c84ae173d 100644 --- a/tests/test_completion/test_completion_install.py +++ b/tests/test_completion/test_completion_install.py @@ -110,6 +110,49 @@ def test_completion_install_zsh(): ) +@requires_completion_permission +def test_completion_install_zsh_respects_zdotdir(tmp_path: Path): + home_path = tmp_path / "home" + home_path.mkdir() + zdotdir_path = home_path / "not_default_zsh_dir" + zdotdir_path.mkdir() + zshrc_path = zdotdir_path / ".zshrc" + zshrc_path.write_text('echo "custom .zshrc"\n') + result = subprocess.run( + [ + sys.executable, + "-m", + "coverage", + "run", + mod.__file__, + "--install-completion", + "zsh", + ], + capture_output=True, + encoding="utf-8", + env={ + **os.environ, + "HOME": str(home_path), + "ZDOTDIR": str(zdotdir_path), + "_TYPER_COMPLETE_TEST_DISABLE_SHELL_DETECTION": "True", + }, + ) + assert result.returncode == 0 + assert not (home_path / ".zshrc").exists() + new_text = zshrc_path.read_text() + zfunc_fragment = "fpath+=~/.zfunc" + assert zfunc_fragment in new_text + assert "completion installed in" in result.stdout + assert "Completion will take effect once you restart the terminal" in result.stdout + install_source_path = home_path / ".zfunc/_tutorial001_py310.py" + assert install_source_path.is_file() + install_content = install_source_path.read_text() + assert ( + "compdef _tutorial001_py310py_completion tutorial001_py310.py" + in install_content + ) + + @requires_completion_permission def test_completion_install_fish(): script_path = Path(mod.__file__) diff --git a/typer/_completion_shared.py b/typer/_completion_shared.py index 5a81dcf68c..074ffc107c 100644 --- a/typer/_completion_shared.py +++ b/typer/_completion_shared.py @@ -116,9 +116,18 @@ def install_bash(*, prog_name: str, complete_var: str, shell: str) -> Path: return completion_path +def _get_zshrc_path() -> Path: + zdotdir = os.getenv("ZDOTDIR") + if zdotdir: + resolved_zdotdir = Path(os.path.expandvars(zdotdir)).expanduser() + if resolved_zdotdir.is_absolute(): + return resolved_zdotdir / ".zshrc" + return Path.home() / ".zshrc" + + def install_zsh(*, prog_name: str, complete_var: str, shell: str) -> Path: # Setup Zsh and load ~/.zfunc - zshrc_path = Path.home() / ".zshrc" + zshrc_path = _get_zshrc_path() zshrc_path.parent.mkdir(parents=True, exist_ok=True) zshrc_content = "" if zshrc_path.is_file():