4

I use

(global-set-key (kbd "C-c a") '(lambda () (interactive) (ansi-term "/bin/bash")))

to open a bash ansi-term. Unlike M-x shell, this "occupies" the whole buffer/frame. I am wondering if one could adjust the above so that the ansi-term behaves like M-x shell in the sense of opening in a new window (in the current frame -- at the bottom, just like M-x shell does).

2 Answers 2

5

This is a simplified version of a function in my .emacs file:

(defun ml/bash ()
  "Start a terminal emulator in a new window."
  (interactive)
  (split-window-sensibly)
  (other-window 1)
  (ansi-term (executable-find "bash")))

You can bind it to C-c a:

(global-set-key (kbd "C-c a") #'ml/bash)
4

I am wondering if one could adjust the above so that the ansi-term behaves like M-x shell in the sense of opening in a new window (in the current frame -- at the bottom, just like M-x shell does).

The canonical and most flexible way to customise such rules is via display-buffer-alist (see (emacs) Displaying Buffers and its subnodes, as well as the nodes referenced from the Elisp manual).

The problem in this case is that term and ansi-term use switch-to-buffer instead of pop-to-buffer or similar. I consider this a bug and intend to propose an upstream fix soon.

So, whereas you can easily configure shell buffers to be displayed in, say, the same window:

(add-to-list 'display-buffer-alist '("\\`\\*shell" display-buffer-same-window))

The same approach will not work for M-xterm or M-xansi-term.

FWIW, in Emacs 27 you can already work around this limitation using the new user option switch-to-buffer-obey-display-actions:

switch-to-buffer-obey-display-actions is a variable defined in ‘window.el’.
Its value is nil

Documentation:
If non-nil, ‘switch-to-buffer’ runs ‘pop-to-buffer-same-window’ instead.
This means that when switching the buffer it respects display actions
specified by ‘display-buffer-overriding-action’, ‘display-buffer-alist’
and other display related variables.  So ‘switch-to-buffer’ will display
the buffer in the window specified by the rules from these variables.

You can customize this variable.

This variable was introduced, or its default value was changed, in
version 27.1 of Emacs.

Here's how you could use it:

(defun my-term-p (name _action)
  "Determine whether NAME names a `term-mode' buffer."
  (with-current-buffer name
    (derived-mode-p #'term-mode)))

(defun my-ansi-term ()
  "Start Bash in a terminal emulator.
Like `ansi-term', but respect buffer display actions."
  (interactive)
  (let ((switch-to-buffer-obey-display-actions t))
    (ansi-term "/bin/bash")))

(add-to-list 'display-buffer-alist '(my-term-p () (inhibit-same-window . t)))

Of course, you can then bind it to a key of your liking:

(global-set-key (kbd "C-c a") #'my-ansi-term)
3
  • Good information on 27; thanks.
    – phils
    Commented Mar 20, 2019 at 23:10
  • Why the # in the key binding and not just (global-set-key (kbd "C-c a") 'my-ansi-term)?
    – mathlete
    Commented Mar 21, 2019 at 1:02
  • 1
    @MariusHofert Because #' declares this symbol as being a function symbol to the byte-compiler. #'my-ansi-term is equivalent to (function my-ansi-term), whereas 'my-ansi-term is equivalent to (quote my-ansi-term). It's not essential in this particular example, but I recommend quoting function symbols as such in general. See (elisp) Anonymous Functions.
    – Basil
    Commented Mar 21, 2019 at 1:06

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.