在其他窗口中打开Shell

9
在先前的Emacs版本中," M-x shell "在当前窗口打开一个shell缓冲区。但是最近我将我的Emacs升级到GNU Emacs 26.0.50.2后," M-x shell "会在另一个窗口中新建一个shell缓冲区。我在谷歌上搜索,但找不到答案。有人知道如何防止这种行为吗?

尝试将变量pop-up-windows设置为nil。那样能解决问题吗? - Drew
3个回答

14
在你的 .emacs 文件中添加这一行:
(push (cons "\\*shell\\*" display-buffer--same-window-action) display-buffer-alist)

这对我很有帮助。我正在Mac上使用eMacs 25.2 (9.0),当只有一个框架时,终端会在另一个框架甚至新的框架中打开,这让我非常恼火。这是我从中得到答案的来源


1
也对我有用。谢谢! - Adam Erickson

10

除非你正在自定义你的shell缓冲区名称,否则这就是你所需要的:

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

为了处理所有的shell缓冲区,不管它们的名称是什么,您可以使用以下建议:

(defun shell-same-window-advice (orig-fn &optional buffer)
  "Advice to make `shell' reuse the current window.

Intended as :around advice."
  (let* ((buffer-regexp
          (regexp-quote
           (cond ((bufferp buffer)  (buffer-name buffer))
                 ((stringp buffer)  buffer)
                 (:else             "*shell*"))))
         (display-buffer-alist
          (cons `(,buffer-regexp display-buffer-same-window)
                display-buffer-alist)))
    (funcall orig-fn buffer)))

(advice-add 'shell :around #'shell-same-window-advice)

3
原因是 shell 使用了(pop-to-buffer buffer)而不是(switch-to-buffer buffer)。我不知道如何建议该函数,所以我不能给你一个恰当的答案。但是,如果你只想让shell按照你的要求运行,你可以在配置文件中添加整个函数。
也许其他人可以用advice替换该函数。我对这种解决方案很感兴趣。
(defun shell (&optional buffer)
  "Run an inferior shell, with I/O through BUFFER (which defaults to `*shell*').
Interactively, a prefix arg means to prompt for BUFFER.
If `default-directory' is a remote file name, it is also prompted
to change if called with a prefix arg.

If BUFFER exists but shell process is not running, make new shell.
If BUFFER exists and shell process is running, just switch to BUFFER.
Program used comes from variable `explicit-shell-file-name',
 or (if that is nil) from the ESHELL environment variable,
 or (if that is nil) from `shell-file-name'.
If a file `~/.emacs_SHELLNAME' exists, or `~/.emacs.d/init_SHELLNAME.sh',
it is given as initial input (but this may be lost, due to a timing
error, if the shell discards input when it starts up).
The buffer is put in Shell mode, giving commands for sending input
and controlling the subjobs of the shell.  See `shell-mode'.
See also the variable `shell-prompt-pattern'.

To specify a coding system for converting non-ASCII characters
in the input and output to the shell, use \\[universal-coding-system-argument]
before \\[shell].  You can also specify this with \\[set-buffer-process-coding-system]
in the shell buffer, after you start the shell.
The default comes from `process-coding-system-alist' and
`default-process-coding-system'.

The shell file name (sans directories) is used to make a symbol name
such as `explicit-csh-args'.  If that symbol is a variable,
its value is used as a list of arguments when invoking the shell.
Otherwise, one argument `-i' is passed to the shell.

\(Type \\[describe-mode] in the shell buffer for a list of commands.)"
  (interactive
   (list
    (and current-prefix-arg
         (prog1
             (read-buffer "Shell buffer: "
                          ;; If the current buffer is an inactive
                          ;; shell buffer, use it as the default.
                          (if (and (eq major-mode 'shell-mode)
                                   (null (get-buffer-process (current-buffer))))
                              (buffer-name)
                            (generate-new-buffer-name "*shell*")))
           (if (file-remote-p default-directory)
               ;; It must be possible to declare a local default-directory.
               ;; FIXME: This can't be right: it changes the default-directory
               ;; of the current-buffer rather than of the *shell* buffer.
               (setq default-directory
                     (expand-file-name
                      (read-directory-name
                       "Default directory: " default-directory default-directory
                       t nil))))))))
  (setq buffer (if (or buffer (not (derived-mode-p 'shell-mode))
                       (comint-check-proc (current-buffer)))
                   (get-buffer-create (or buffer "*shell*"))
                 ;; If the current buffer is a dead shell buffer, use it.
                 (current-buffer)))

  ;; On remote hosts, the local `shell-file-name' might be useless.
  (if (and (called-interactively-p 'any)
           (file-remote-p default-directory)
           (null explicit-shell-file-name)
           (null (getenv "ESHELL")))
      (with-current-buffer buffer
        (set (make-local-variable 'explicit-shell-file-name)
             (file-remote-p
              (expand-file-name
               (read-file-name
                "Remote shell path: " default-directory shell-file-name
                t shell-file-name))
              'localname))))

  ;; The buffer's window must be correctly set when we call comint (so
  ;; that comint sets the COLUMNS env var properly).
  (switch-to-buffer buffer)
  (unless (comint-check-proc buffer)
    (let* ((prog (or explicit-shell-file-name
                     (getenv "ESHELL") shell-file-name))
           (name (file-name-nondirectory prog))
           (startfile (concat "~/.emacs_" name))
           (xargs-name (intern-soft (concat "explicit-" name "-args"))))
      (unless (file-exists-p startfile)
        (setq startfile (concat user-emacs-directory "init_" name ".sh")))
      (apply 'make-comint-in-buffer "shell" buffer prog
             (if (file-exists-p startfile) startfile)
             (if (and xargs-name (boundp xargs-name))
                 (symbol-value xargs-name)
               '("-i")))
      (shell-mode)))
  buffer)

这个答案没有解释为什么 OP 之前没有看到相同的行为。Emacs 命令 shell 一直使用 pop-to-buffer,至少从 Emacs 20 开始就是这样。 - Drew
3
最近的Emacs版本中,shell命令使用了pop-to-buffer-same-window - Drew
有趣。也许您可以使用“defadvice”或在这种情况下需要使用的任何其他方式来编辑答案? - bertfred

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接