Skip to content

zsh cd widget calls zsh's chpwd hook functions twice #4879

Description

@lucc

Checklist

  • I have read through the manual page (man fzf)
  • I have searched through the existing issues
  • For bug reports, I have checked if the bug is reproducible in the latest version of fzf

Output of fzf --version

0.74 (devel) # git descript = v0.74.1-22-gb6615382

OS

  • Linux
  • macOS
  • Windows
  • Etc.

Shell

  • bash
  • zsh
  • fish

Problem / Steps to reproduce

context

In zsh the fzf-cd-widget (bound to alt-c by default) executes cd twice. Once in a subshell to find the correct logical dir to change to and then once it is pushed onto the editor stack and executed by the line editor. This "double call to cd" was introduced in 7d647c7.

problem

I have a function registered with zsh that runs on every directory change. The feature in zsh is called "hook function" and the relevant function one has to define is chpwd (or list several function names in the array $chpwd_functions).

This function is now executed twice when I use the widget/key binding. Depending on what the hook function does this might be bad.

repoduce

  1. load the fzf bindings: source <(fzf --zsh)
  2. define a chpwd function: chpwd() { echo hook is running; }
  3. use the key binding alt-c
  4. select entry
  5. observe the output "hook is running" twice, once before the shell prompt and "builtin cd ..." command line that the fzf-cd-widget injects (to set the dir variabel in the widget) and once after it (for the actual directory change in the shell).

proposed solution

The zsh cd builtin has a -q option that stops the shell from executing the hooks for this particular directory change. So I propose this change:

diff --git a/shell/key-bindings.zsh b/shell/key-bindings.zsh
index 85a3821b..21c2ea12 100644
--- a/shell/key-bindings.zsh
+++ b/shell/key-bindings.zsh
@@ -115,7 +115,7 @@ fzf-cd-widget() {
   # working directory.
   # If failed, fallback to the unexpanded path to surface the error to the user.
   # NOTE: Don't use the `:a` modifier as it resolves symlinks like `pwd -P`.
-  dir=$(builtin cd >/dev/null -- "${dir}" && echo "${PWD}" || echo "${dir}")
+  dir=$(builtin cd -q >/dev/null -- "${dir}" && echo "${PWD}" || echo "${dir}")
   zle push-line # Clear buffer. Auto-restored on next prompt.
   BUFFER="builtin cd -- ${(q)dir}"
   zle accept-line

I would also suggest a test case that executes the steps I described in the reproduction and then checks that the output from the hook is only seen once. Sadly I do not know enough ruby to write that down just now.

No activity

Activity on this issue will appear here.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingshellShell scripts

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions