在Emacs中,我经常发现自己需要在各种源文件之间来回切换到各种终端。但是,我觉得我没有很好的方法来有效地执行此操作,而且只能在Emacs(shell
,eshell
或{中打开一个 shell ,这很笨拙{1}})。
此外,我需要在多个终端和源文件之间进行有效的处理。
我怎样才能做到这一点?
答案 0 :(得分:17)
您当然可以打开多个交互式shell。尝试输入 C-u M-x shell
RET RET 。
答案 1 :(得分:17)
您可以根据需要随时打开多个终端和外壳。只需使用M-x rename-buffer
更改现有*term*
或*shell*
缓冲区的名称,下次执行M-x term
或M-x shell
时,就会有一个全新的缓冲区被创造。在M-x shell
的情况下,前缀参数将使您被提示输入新shell缓冲区的名称,如offby1所示。
几年前,我有一份工作,我必须定期登录名为“host01.foo.com”,“host02.foo.com”等的各种生产服务器。我写了一个像这样的小功能让它们更容易管理:
(defun ssh-to-host (num)
(interactive "P")
(let* ((buffer-name (format "*host%02d*" num))
(buffer (get-buffer buffer-name)))
(if buffer
(switch-to-buffer buffer)
(term "/bin/bash")
(term-send-string
(get-buffer-process (rename-buffer buffer-name))
(format "ssh host%02d.foo.com\r" num)))))
然后我把这个命令绑定到(比方说) s-h (超级H),让我只需输入 M-5 s-h 。如果我还没有名为*host05*
的缓冲区,它将启动一个新的终端仿真器缓冲区,将其重命名为*host05*
,然后将我转发到host05.foo.com。如果缓冲区*host05*
已经存在,它只会将我切换到它。非常方便!
答案 2 :(得分:15)
尝试使用MultiTerm
打开多个shell。
答案 3 :(得分:8)
您可以使用Emacs Lisp Screen来模拟GNU Screen,并提供简单的键绑定以跳转到多个不同的shell之间。
答案 4 :(得分:4)
我使用了很多方法将我的终端生活融入Emacs:
elscreen.el
是一个节省生命的人,如果你有一个像gdb
这样复杂的窗口布局,或者只是变得不知所措,你就会打开一个新的屏幕。在您的情况下,您可以将一个屏幕专用于终端。multi-term.el
使管理终端更容易。shell-pop.el
,一个快速终端访问的好工具。 shell-pop
允许您为打开和关闭特定的shell缓冲区窗口分配一个键,如果您使用了tilda
之类的下拉终端,那么知道这是多么的方便:我的shell-pop
配置的示例和示例,我使用密钥C-t
弹出eshell
:
(require 'shell-pop)
(shell-pop-set-internal-mode "eshell") ; Or "ansi-term" if you prefer
(shell-pop-set-window-height 60) ; Give shell buffer 60% of window
;; If you use "ansi-term" and want to use C-t
;; (defvar ansi-term-after-hook nil)
;; (add-hook 'ansi-term-after-hook
;; '(lambda ()
;; (define-key term-raw-map (kbd "C-t") 'shell-pop)))
;; (defadvice ansi-term (after ansi-term-after-advice (org))
;; (run-hooks 'ansi-term-after-hook))
;; (ad-activate 'ansi-term)
(global-set-key (kbd "C-t") 'shell-pop)
答案 5 :(得分:3)
我通常做一个 M - x server-start
,然后使用emacsclient --no-wait
打开文件。我已经将其与e
混淆了一些装饰,以便它更方便一些。
我在一个终端中完成所有工作,只需使用e
将要编辑的文件“抛出”到Emacs中。在Emacs内部,我使用iswitchb
来玩弄它并且它工作得很好。 YMMV。
答案 6 :(得分:3)
我经常在旧工作场所使用10个左右的贝壳。秘诀是你必须重命名其他shell缓冲区。我在我的.emacs中自动完成了这项操作,在逻辑上创建和命名shell(我为每个项目都有projnameRun和projnameBuild)。与任何事物一起工作得非常好,使得重新绑定正确的shell非常容易(使用项目名称的末尾与r或b结合运行/构建)。
答案 7 :(得分:2)
我没有在emacs中使用多个终端窗口,而是在需要新终端时,我会生成不同的xterm。这当然是可以忍受的,因为我使用一个非常轻量级的终端模拟器(urxvt),它的启动时间不到0.2秒。
然后我使用我的窗口管理器在它们和emacs帧之间切换。可配置的窗口管理器将有很多选项可以调整以在窗口之间切换(非常)。在emacs中,我使用windmove和ido-mode,并且已经将C-tab绑定到切换到最后一个缓冲区的函数(因为我以这种方式使用C-x b)。
嗯,不确定它对你有多大用处,因为它与你的使用模式完全不同,但这对我有用。
答案 8 :(得分:2)
几年前我遇到了完全相同的问题,并没有发现让我感到满意的事情;所以我写了自己的“toggle shell”功能。它在当前帧或窗口配置与系统shell缓冲区之间切换。它还可以将shell放入专用框架,并将pushd
注入当前缓冲区目录。
这是摘自my .emacs:
(defvar --toggle-shell-last-window-conf nil "The last window configuration.")
(defvar --toggle-shell-last-buf nil "The last buffer object in case there's no last window configuration.")
(defvar --toggle-shell-last-frame nil "The frame that was selected when opening a shell buffer.")
(defun --toggle-shell-have-conf ()
(window-configuration-p --toggle-shell-last-window-conf))
(defun --toggle-shell-store-last-conf ()
(setq --toggle-shell-last-buf (current-buffer)
--toggle-shell-last-frame (selected-frame)
--toggle-shell-last-window-conf (current-window-configuration)))
(defun --toggle-shell-restore-last-conf ()
(if (--toggle-shell-have-conf)
(progn (raise-frame --toggle-shell-last-frame)
(set-window-configuration --toggle-shell-last-window-conf))
(let ((bufnam (if (bufferp --toggle-shell-last-buf)
(buffer-name --toggle-shell-last-buf) --toggle-shell-last-buf)))
(if bufnam
(if (get-buffer bufnam) (switch-to-buffer bufnam t)
(message "%s: buffer not available" bufnam))))))
(defun --toggle-shell (&optional display inject-cd)
"Toggles between current buffers and a system shell buffer. With prefix-arg
close the shell.
When DISPLAY is 'vertical splits the shell as vertical window; when 'frame uses
a dedicated frame (default: single window). When INJECT-CD executes a `pushd'
to the working directory of the buffer from which you toggled the shell."
(interactive)
(let* ((shell-buf (get-buffer "*shell*"))
(shell-window ; non-nil when currently displayed
(if shell-buf (get-buffer-window shell-buf t)))
(shell-frame
(if shell-window (window-frame shell-window)))
(in-shell (eq (current-buffer) shell-buf))
(vertical (string= display 'vertical))
(popup-frame (or (string= display 'frame)
(and inject-cd (not (bufferp shell-buf)))
(and (framep shell-frame)
(not (eq shell-frame (selected-frame)))))))
;; With prefix-arg close shell, restore windows. Otherwise (no prefix-arg)
;; toggle shell window; restore windows when called twice in a row, or the
;; current buffer is the shell buffer (`in-shell').
(if current-prefix-arg
(if (bufferp shell-buf)
(progn (message "Exiting shell '%s'" (buffer-name shell-buf))
(kill-buffer shell-buf)
(if in-shell (--toggle-shell-restore-last-conf)))
(error "No shell buffer to kill."))
;; If already in shell-buffer toggle back to stored frame-configuration.
(if (and in-shell (not inject-cd))
(progn
(--toggle-shell-restore-last-conf)
;; Recurse to reopen the shell-buffer in a dedicated frame, or
;; close the dedicated frame and reopen the buffer in a window.
(if (and popup-frame (eq shell-frame (selected-frame)))
(--toggle-shell 'frame inject-cd)
(when (and popup-frame shell-frame)
(delete-frame shell-frame)
(--toggle-shell nil inject-cd))))
;; Not in shell buffer. Warp to it or create new one.
(unless in-shell
(--toggle-shell-store-last-conf))
(if popup-frame
(progn (switch-to-buffer-other-frame (or shell-buf "*shell*"))
(raise-frame
(or shell-frame (window-frame (get-buffer-window "*shell*" t)))))
(if (> (count-windows) 1)
(delete-other-windows)))
;; Finally `cd' into the working directory the current buffer.
(let ((new-shell (not (bufferp shell-buf)))
(new-dir ; `default-directory' of `--toggle-shell-last-buf'
(if --toggle-shell-last-buf
(buffer-local-value 'default-directory --toggle-shell-last-buf))))
;; Open shell, move point to end-of-buffer. The new shell-buffer's
;; `default-directory' will be that of the buffer the shell was
;; launched from.
(when vertical
(if (> (count-windows) 1)
(delete-other-windows))
(split-window-vertically) (other-window 1))
(funcall 'shell)
(when new-shell
(message "New shell %s (%s)" (buffer-name (current-buffer)) new-dir)
(if inject-cd (sit-for 2))) ; wait for prompt
(goto-char (point-max))
;; If on a command-prompt insert and launch a "cd" command (assume no
;; job is running).
(when (and inject-cd new-dir)
(save-excursion
(backward-line-nomark) (end-of-line)
(unless (setq inject-cd (re-search-forward comint-prompt-regexp (point-max) t))
(error "Cannot `pushd', shell is busy")))
(when (and inject-cd)
(let* ((cmd (format
"pushd '%s' %s" (comint-quote-filename new-dir)
(if (buffer-file-name --toggle-shell-last-buf)
(format "# '%s'" (file-name-directory (buffer-file-name --toggle-shell-last-buf)))
""))))
;; `shell-process-cd' set new `default-directory' and set
;; `shell-last-dir' to old. (If the pushd command is
;; successful, a dirs is performed as well; >nul discards this
;; output.)
(shell-process-cd new-dir)
(insert cmd)
(comint-send-input)
(message "%s: cd '%s'" (buffer-name --toggle-shell-last-buf) new-dir))
)
)
)
)
)
)
)
--toggle-shell
是完成这一伎俩的功能。我把它绑定到F12:
;; F12 toggle between shell buffer and current window configuration
;; SHIFT-F12 like before, but let shell buffer appear in a dedicated frame
;; ALT-F12 inject a pushd to change to directory of current buffer
;; CTRL-F12 `shell-command'
(global-set-key [(f12)] '--toggle-shell)
(global-set-key [(shift f12)] '(lambda()(interactive)(--toggle-shell 'frame)))
(global-set-key [(meta f12)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(meta f10)] '(lambda()(interactive)(--toggle-shell nil t)))
(global-set-key [(control f12)] 'shell-command) ; alias M-!
这是一大堆代码,可以在这里发布。但它应该运作良好。
答案 9 :(得分:2)
半相关 - 您可以使用
在所选文件上快速运行shell命令M-shift-!
它为较小的命令chmod等节省了大量时间
答案 10 :(得分:1)
也许我的快速弹出式shell也可以帮到你。 A quick pop-up shell for emacs
答案 11 :(得分:0)
Ecb + eshell将是你想要的!
答案 12 :(得分:0)
我使用vi,但希望这会有所帮助。我可以打开尽可能多的终端(例如在Ubuntu 16.04中):
ctrl + alt + t
我通常打开2个终端,并通过以下方式将一个终端移动(定位)到:
ctrl + super + right-arrow
并通过以下方式将另一个终端移到左侧:
ctrl + super + left-arrow
所以我有2个终端的分屏。