Search code examples
shellemacscd

Use z (jump around) in Emacs to find directories


Z is a popular shell tool for jumping around commonly used directories. It uses "frecency" as a metric for determining which directory you intend to jump to based on keyword completions. So if I commonly cd to ~/.ssh, I can z ssh to jump there.

My question is how can I get the same functionality to work inside Emacs? That is, I want to be able to use ido-find-file or something similar but only have to type a few characters to jump to the directory I intended. Hopefully the solution can incorporate z itself so it makes use of the frecency metric already recorded by z.


Solution

  • I used z once but then I found fasd, which is inspired by autojump, z or v, and which I found much more powerful, if I remember well it is because:

    • it not only finds directories but also files
    • it can cd a result or use mplayer or your editor or another command
    • the completion is better, specially for zsh (again, if I remember well). The thing is, I constantly use the d alias to change directories.

    Anyway, there's an emacs package to find files with it: https://github.com/steckerhalter/emacs-fasd That's cool, but it isn't as interactive as I would like.

    edit: then I had to update the package and:

    (setq fasd-enable-initial-prompt nil)  ;; don't ask for first query but fire fuzzy completion straight away.
    

    There's a still a use case that isn't filled:

    How to use fasd (or autojump or z) with completion in an emacs shell ?

    I often use emacs' shell-mode. When I use my favorite alias d, it works, but I don't have completion at all. Here, zsh's completion is clearly missing. So I would like to use ido completion, for instance. I wrote a little function which you can easily adapt for z:

    edit: finished the command and added ido completion triggered by TAB. Now type d (d followed by a space). If it keeps changing and if I manage to create a minor mode I'll post the link to my gitlab repo.

    edit: I created a mode for this feature: https://gitlab.com/emacs-stuff/fasd-shell/tree/master

        ;; Use the fasd command line utility to change recently visited directories and more.
    
    (defun fasd-get-path-list (pattern)
      "call fasd with pattern and return the list of possibilities"
      (s-split "\n" (s-trim (shell-command-to-string (format "fasd -l -R %s" pattern))))
    )
    
    (defun fasd ()
      "If current shell command is `d something' call fasd"
      (interactive)
      (let* ((user-input (buffer-substring-no-properties (comint-line-beginning-position)
                                                         (point-max))))
        (if (and (string= (substring user-input 0 2) "d "))  ;; todo: mapping to use something else than d and change directory.
            (progn
              ;; get what is after "d "
              (setq fasd-pattern (buffer-substring-no-properties (+ (comint-line-beginning-position) 2) (point-max)))
              (setq fasd-command (concat "cd " (ido-completing-read "cd to: " (fasd-get-path-list fasd-pattern))))
              (comint-kill-input)
              (insert fasd-command)
              (comint-send-input)
              ))))
    
    ;; Use TAB as in normal shell. Now we have even better completion than in zsh !
    (define-key shell-mode-map (kbd "<tab>") 'fasd)  ;; works like a charm :)
    

    As a side note, I don't use it very often because I open shells in the directory of the current buffer with shell-here and shell-pop (a drop-down terminal like guake for gnome).