Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm learning about the more powerful tab-completion and expansion capabilities of zsh, and they don't seem to work when I run zsh under emacs with M-x shell:

cat $PATH<TAB> expands the tab variable in Terminal, but in shell-mode it just beeps.

I poked around the emacs environment and here's what I found:

TAB (translated from ) runs the command completion-at-point, which is an interactive compiled Lisp function in `minibuffer.el'.

It is bound to TAB, .


Perform completion on the text around point. The completion method is determined by `completion-at-point-functions'.

completion-at-point-functions is a variable defined in `minibuffer.el'. Its value is (tags-completion-at-point-function)

So I'm surmising I need to add a function to completion-at-point-functions, but which one?

share|improve this question
up vote 2 down vote accepted

You can't use shell completion inside M-x shell. Emacs sends the input to the shell one line at a time when you press RET. When you press TAB, it's Emacs's built-in completion that's triggered. In shell mode, Emacs tries to keep track of your current directory and completes file names, but that's all.

Depending on what program you're interacting with, shell mode can be nice (because you get all of Emacs's edition features instead of whatever limited capabilities the shell or other program provides) or not so nice (because you don't get whatever nifty capabilities the shell or other program provides. When running zsh, you're in the latter category. Inside Emacs, you can run M-x term to run a more complete terminal emulator inside Emacs, where you interact directly with the underlying program. You gain some, but you also lose some: Term mode's scrollback capabilities are poor.

You can switch between Term mode and Shell mode in the same buffer. You must start the buffer in Term mode, then you can use these functions to toggle between the two. (Note: I didn't write these functions originally, it was contributed to the Emacs Wiki and I have not tracked down the source. I have slightly adapted it; warning: I haven't tested this code.)

(defun term-switch-to-shell-mode ()
  (set-process-filter  (get-buffer-process (current-buffer)) 'comint-output-filter )
  (compilation-shell-minor-mode 1)
(defun shell-switch-to-term-mode ()
  (compilation-shell-minor-mode -1)
  (font-lock-mode -1)
  (set-process-filter  (get-buffer-process (current-buffer)) 'term-emulate-terminal)
  (term-send-raw-string (kbd "C-l")))
share|improve this answer

Try MultiTerm. Its the only Emacs terminal mode that seems to play nice with zsh.

With 'M-x shell' mode you can't use zle (the cool zsh tab completion stuff).

With 'M-x term' (and ansi-term), the terminal captures most of the emacs C- and M- commands that you want routed to emacs.

MultiTerm allows you to easily set which commands you want captured by emacs and which you want routed to the terminal. It comes preloaded with defaults that work very well.

One more tip: Add the following to your .zshrc to allow emacs to track your current directory as you cd around.

if [ -n "$INSIDE_EMACS" ]; then
  chpwd() { print -P "\033AnSiTc %d" }
  print -P "\033AnSiTu %n"
  print -P "\033AnSiTc %d"
share|improve this answer
Could you elaborate on what the zsh snippet is doing? – Joseph Garvin Jan 31 '15 at 18:34

This is a complex problem. Let's look at what really happens behind the sense.

According to Emacs Doc, <Tab> is bound to function completion-at-point. Here is what completion-at-point does:

Perform completion on the text around point.

The completion method is determined by `completion-at-point-functions'.

Check Emacs Doc, the variable completion-at-point-functions goes here:

completion-at-point-functions is a variable defined in `minibuffer.el'.

Its value is (comint-completion-at-point t)

Local in buffer shell; global value is


Then let's check out document of comint-completion-at-point

comint-completion-at-point is an alias for icicle-comint-dynamic-complete' inob-sh.el'.


Dynamically perform completion at point.

Calls the functions in `comint-dynamic-complete-functions', but with

Icicles functions substituted, to perform completion until a function

returns non-nil. Return that value.

So it's clear that you need to add your favourite complete functions to comint-dynamic-complete-functions variable.

      (add-to-list 'comint-dynamic-complete-functions 'icicle-shell-dynamic-complete-filename)
      (add-to-list 'comint-dynamic-complete-functions 'icicle-shell-dynamic-complete-command)
share|improve this answer

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .