Eg. when you're running nice things like Perl or Ruby REPLs, you have code/command completion exposed via GNU Readline. What I want to do is set some elisp/env variable when entering/exiting such a program to indicate that I want shell-mode to pass the TAB key onto those programs.

Note that C-q TAB also does not work, so I think that Readline is also ignoring it because TERM=dumb, but setting it to eg. vt100 also doesn't do the trick, so it might even be looking at EMACS=t.

  • 3
    Comint doesn't work that way. It waits for a line to be sent with RET, then receives output until it recognizes a prompt. Completion must therefore be solved on its side.
    – wasamasa
    Feb 1, 2016 at 6:22
  • Take a look at ESS, or grass-mode to see how completion is handled directly in elisp on the Emacs side, rather than by relying on readline.
    – Tyler
    Feb 1, 2016 at 13:23
  • This would be also useful to Prolog mode, where pressing tab is supposed to prompt the interpreter to generate next solution.
    – wvxvw
    Feb 1, 2016 at 15:28
  • @Tyler the thing is where the knowledge exists elsewhere (eg. in a running interpreter). I guess I could make some sort of readline proxy that could have completion delegated to it from lisp - seems like a lot of work :)
    – Mark
    Feb 2, 2016 at 0:37
  • @MarkAufflick ESS does something like that I think, with most completions provided via elisp, but some special cases/situations passed to the R process. The special cases can result in painfully slow completions.
    – Tyler
    Feb 2, 2016 at 1:23

2 Answers 2


M-x shell works line-at-a-time. It passes a line of input to the external shell process when you press Ret key.

M-x term passes every keystroke to the external shell process, with the exceptions of C-c and I think Esc. When you press Tab it will be seen and interpreted by the external shell process.


As @user20119 pointed out, M-x term might be a good option: it also supports dynamically switching to "line mode" which is somewhat similar to what you get with M-x shell.

M-x eshell also tries to give you a mix of the two behaviors.

I'll also point out that C-q TAB didn't work because all it does is to insert a TAB character in the buffer (rather than sending a TAB to the sub-process). Furthermore, just sending a TAB char to the underlying process wouldn't be sufficient, because the text on the current line hasn't yet been sent to the process, so you might need something like:

(defun my-comint-tab ()
  (let* ((proc (get-buffer-process (current-buffer)))
         (str (buffer-substring (process-mark proc) (point))))
    (process-send-string proc (concat str "\t"))))

and indeed you'll probably also need to convince M-x shell to use a different setting for $TERM.

Your Answer

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

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