4

I recently started using the fish shell. I tried using it in term-mode in Emacs. One characteristic of this shell is that it shortens the current working directory before printing it as the prompt. For example, if the current directory is /media, the prompt will contain /media but if the current working directory is /media/directory, the prompt will be /m/directory.

Because of this, Dirtrack mode in Emacs cannot keep track of the current directory, so default-directory is not updated. This affects some commands like C-c C-f which, as a prompt, suggests default-directory. Since this variable is not updated, the prompt will be the directory from where I started term-mode and not the current working directory in the shell.

I want default-directory to be updated when I change directory in the shell just like how it works with bash. How can I do this?

Caveats:

  • I like this shortening feature of fish-shell and I don't want to change the prompt style.

  • Since Emacs sends every key-stroke to the shell (with some exceptions), I thought to run a function every time <Ret> is pressed. But I couldn't find out how this can be done. Suggestions on this approach are welcome.

3 Answers 3

3

i had to fiddle with it for a while, but here's a working version of Gilles's answer. just stuff this at the end of your ~/.config/fish/config.fish.

# emacs dir tracking
if [ -n "$INSIDE_EMACS" ]
  function prompt_AnSiT -e fish_prompt
    printf "\eAnSiTc %s\n" "$PWD"
  end
  printf "\eAnSiTu %s\n" "$USER"
end

the relevant differences are...

  1. this uses the $INSIDE_EMACS variable being set, instead of relying on the value of $TERM. either approach should work unless you've configured emacs to mimic some other terminal, in which case this should still work, but the other version won't. up to you which you want to use.
  2. this also prints an escape code of your current user which is what i'm assuming was causing the earlier TRAMP error. you'll notice the string it's complaining about has a host but lacks a username.
  3. you gotta have a space between the escape character and the value.
0
2

You could try the procfs approach. If you'd use the shell command, this should work.

(defun shell-procfs-dirtrack (str)
  (prog1 str
    (when (string-match comint-prompt-regexp str)
      (let ((directory (file-symlink-p
                        (format "/proc/%s/cwd"
                                (process-id
                                 (get-buffer-process
                                  (current-buffer)))))))
        (when (file-directory-p directory)
          (cd directory))))))

(define-minor-mode shell-procfs-dirtrack-mode
  "Track shell directory by inspecting procfs."
  nil nil nil
  (cond (shell-procfs-dirtrack-mode
         (when (bound-and-true-p shell-dirtrack-mode)
           (shell-dirtrack-mode 0))
         (when (bound-and-true-p dirtrack-mode)
           (dirtrack-mode 0))
         (add-hook 'comint-preoutput-filter-functions
                   'shell-procfs-dirtrack nil t))
        (t
         (remove-hook 'comint-preoutput-filter-functions
                      'shell-procfs-dirtrack t))))
6
  • Awesome idea. But for some reason, hook is setup, shell-procfs-dirtrack works properly but default-directory doesn't change
    – nitishch
    Jun 13, 2015 at 14:03
  • comint-prompt-regexp probably doesn't match. Just C-u C-M-x it and see what's going on.
    – politza
    Jun 13, 2015 at 14:05
  • It says comint-promt-regexp is not defined
    – nitishch
    Jun 13, 2015 at 14:18
  • So, I removed the line with string-match temporarily. Then, value of comint-preoutput-filter-functions is (shell-procfs-dirtrack t), but the value of default-directory doesn't change. But after doing a cd, if I run (shell-procfs-dirtrack t), value of default-directory changes.
    – nitishch
    Jun 13, 2015 at 14:25
  • I've just noticed that you're using term-mode and not shell with comint in the background.
    – politza
    Jun 13, 2015 at 18:59
1

In Term mode, you can use Term mode's own directory tracking feature. I can't find it documented in the manual. There is some example code in the source code. The program running in the terminal can emit escape AnSiT sequences to notify the terminal about its location:

  • \eAnSiTc ${PWD}\n to indicate the current directory
  • \eAnSiTh ${HOSTNAME}\n to indicate the current host
  • \eAnSiTu ${USER}\n to indicate the current user

In your ~/.config/fish/config.fish, add code to the fish_prompt event handler to emit this escape sequence. Untested:

switch $TERM
  case eterm eterm-color
    function -e fish_prompt prompt_AnSiT
      printf '\eAnSiTc %s\n' "$PWD"
    end
end
1
  • Wow I didn't know this. But this doesn't work. fish-shell in a terminal works fine but when I start term-mode, it gives an error error in process filter: Not a Tramp file: "/@HOSTNAME:/path/to/home/folder/.config/fish"
    – nitishch
    Jun 15, 2015 at 14:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.