Emacs shell模式下的Bash自动补全


92

在GNOME终端中,Bash进行智能自动补全。例如

apt-get in<TAB>

变成

apt-get install

在Emacs shell模式下,即使在我显式获得source之后,这种自动完成也不起作用/etc/bash_completion。上面的示例in使用当前目录中的文件名(而不是有效的apt-get命令选项)粘贴或自动完成。大概是因为Emacs截获了Tab键。如何在中启用智能自动完成功能shell-mode


对于任何不熟悉emacs的人... emacs中还有其他shell模式。如eshell-mode其中有制表符补全。此处的更多信息:masteringemacs.org/articles/2010/11/01/…–
罗斯

3
eshell的自动完成功能仅适用于本地目录,如果ssh到另一台计算机,则会突然失去此功能。
hajovonta

Answers:


92

我知道这个问题已经三岁了,但是我也一直对解决这个问题感兴趣。一次网络搜索将我引向了elisp的片段,该片段使Emacs在外壳模式下使用bash完成操作。无论如何,它对我有用。

https://github.com/szermatt/emacs-bash-completion上进行检查。


6
+1有勇气回答一个三岁但仍然完全相关的问题。谢谢!
djhaskin987

3
这已经在melpa melpa.org/#/bash-completion中,使用可以直接安装M-x package-list-packages,但是最后它对我不起作用,我不知道为什么,可能是我的emacs(24.3.1)或bash(4.3.30)版本。该文档说“ bash-completion.el对操作系统和BASH版本非常敏感...”,然后列出了我的版本不存在的列表。
boclodoa 2014年

不幸的是,第6个问题尚未解决,这对于当前大量的CLI工具似乎不太有用。
杰西·格里克

21

在emacs shell中,实际上是emacs执行自动完成,而不是bash。如果shell和emacs不同步(例如,通过使用push,popd或某些bash用户函数来更改shell的当前目录),则自动完成功能将停止工作。

要解决此问题,只需在外壳程序中键入“ dirs”,然后一切恢复同步。

.emacs中也包含以下内容:

(global-set-key "\M-\r" 'shell-resync-dirs)

然后只需按Esc-return即可重新同步自动完成。


9
这是一个不同问题的好答案!
克里斯·康威

谢谢。我使用自动跳转,这就是为什么目录不同步的问题。
Plankalkül

克里斯·康威(Chris Conway),对,这是一个:emacs.stackexchange.com/questions/30550/… :-)
不为所动

15

我不知道答案。但是,它无法按预期工作的原因可能是因为emacs shell中的完成是由emacs内部处理(通过comint-dynamic-complete函数),并且没有内置的智能完成功能。

恐怕这不是一件容易的事情。

编辑:njsf关于使用term-mode的建议可能与它一样好。从开始

Mx词
它包含在标准的emacs发行版中(至少在Ubuntu和Debian上的emacs21-common或emacs22-common中)。


2
使用时,制表符补全甚至更糟M-x term
mcandre

6

就像Matli所说的那样,这不是一件容易的事,因为bash以--noediting开始,而TAB必然是comint-dynamic-complete。

一个人可能可以使用本地设置键将TAB重新绑定到shell-comand-hook的self-insert-command中,并使shell模式不以--noxing开头,由Mx custom-variable RET显式bash-args进行编辑,但我怀疑与所有其他编辑配合使用时效果不佳。

您可能想尝试term-mode,但是它还有另一组问题,因为term-mode已取代了其他一些常规的键绑定。

编辑:通过术语模式超越其他常规的键盘设置,我的意思是除Cc之外的所有密钥都可以转储缓冲区。因此,您不必Cx k来杀死缓冲区,而必须Cc Cx k。或切换到另一个缓冲区“ Cc Cx o”或“ Cc Cx 2”


self-insert-command不是:它插入TAB字符,而不是将TAB按键传递给Bash。
克里斯·康威

我没有任期模式命令,也无法弄清楚从何处获得该命令。
克里斯·康威

6

请考虑另一种模式M-x term,就像我在2011年遇到问题时所做的那样。当时我试图在Inet上进行所有努力,以使Shell与Bash完成一起工作,包括这个问题。但是因为面对面对发现替代方案,term-mode我甚至不想尝试eshell

它是完整的终端模拟器,因此您可以在内部运行交互式程序,例如Midnight commander。或切换到zsh完成状态,这样您就不会在Emacs配置上浪费时间。

您可以免费获得bash中的TAB完成。但更重要的是,您具有Readline的全部功能,例如增量或前缀命令搜索。为了使此设置更方便,请检查.inputrc.bashrc.emacs

必不可少的部分.inputrc

# I like this!
set editing-mode emacs

# Don't strip characters to 7 bits when reading.
set input-meta on

# Allow iso-latin1 characters to be inserted rather than converted to
# prefix-meta sequences.
set convert-meta off

# Display characters with the eighth bit set directly rather than as
# meta-prefixed characters.
set output-meta on

# Ignore hidden files.
set match-hidden-files off

# Ignore case (on/off).
set completion-ignore-case on

set completion-query-items 100

# First tab suggests ambiguous variants.
set show-all-if-ambiguous on

# Replace common prefix with ...
set completion-prefix-display-length 1

set skip-completed-text off

# If set to 'on', completed directory names have a slash appended. The default is 'on'.
set mark-directories on
set mark-symlinked-directories on

# If set to 'on', a character denoting a file's type is appended to the
# filename when listing possible completions. The default is 'off'.
set visible-stats on

set horizontal-scroll-mode off

$if Bash
"\C-x\C-e": edit-and-execute-command
$endif

# Define my favorite Emacs key bindings.
"\C-@": set-mark
"\C-w": kill-region
"\M-w": copy-region-as-kill

# Ctrl+Left/Right to move by whole words.
"\e[1;5C": forward-word
"\e[1;5D": backward-word
# Same with Shift pressed.
"\e[1;6C": forward-word
"\e[1;6D": backward-word

# Ctrl+Backspace/Delete to delete whole words.
"\e[3;5~": kill-word
"\C-_": backward-kill-word

# UP/DOWN filter history by typed string as prefix.
"\e[A": history-search-backward
"\C-p": history-search-backward
"\eOA": history-search-backward
"\e[B": history-search-forward
"\C-n": history-search-forward
"\eOB": history-search-forward

# Bind 'Shift+TAB' to complete as in Python TAB was need for another purpose.
"\e[Z": complete
# Cycling possible completion forward and backward in place.
"\e[1;3C": menu-complete                    # M-Right
"\e[1;3D": menu-complete-backward           # M-Left
"\e[1;5I": menu-complete                    # C-TAB

.bashrc(是的!~/.bash_history)中的任何单词在Bash中都有dabbrev :

set -o emacs

if [[ $- == *i* ]]; then
  bind '"\e/": dabbrev-expand'
  bind '"\ee": edit-and-execute-command'
fi

.emacs 使导航在术语缓冲区中更舒适:

(setq term-buffer-maximum-size (lsh 1 14))

(eval-after-load 'term
  '(progn
    (defun my-term-send-delete-word-forward () (interactive) (term-send-raw-string "\ed"))
    (defun my-term-send-delete-word-backward () (interactive) (term-send-raw-string "\e\C-h"))
    (define-key term-raw-map [C-delete] 'my-term-send-delete-word-forward)
    (define-key term-raw-map [C-backspace] 'my-term-send-delete-word-backward)
    (defun my-term-send-forward-word () (interactive) (term-send-raw-string "\ef"))
    (defun my-term-send-backward-word () (interactive) (term-send-raw-string "\eb"))
    (define-key term-raw-map [C-left] 'my-term-send-backward-word)
    (define-key term-raw-map [C-right] 'my-term-send-forward-word)
    (defun my-term-send-m-right () (interactive) (term-send-raw-string "\e[1;3C"))
    (defun my-term-send-m-left () (interactive) (term-send-raw-string "\e[1;3D"))
    (define-key term-raw-map [M-right] 'my-term-send-m-right)
    (define-key term-raw-map [M-left] 'my-term-send-m-left)
    ))

(defun my-term-mode-hook ()
  (goto-address-mode 1))
(add-hook 'term-mode-hook #'my-term-mode-hook)

C-x o在终端仿真模式下无法正常运行的所有常见命令一样,我使用以下命令扩展了键盘映射:

(unless
    (ignore-errors
      (require 'ido)
      (ido-mode 1)
      (global-set-key [?\s-d] #'ido-dired)
      (global-set-key [?\s-f] #'ido-find-file)
      t)
  (global-set-key [?\s-d] #'dired)
  (global-set-key [?\s-f] #'find-file))

(defun my--kill-this-buffer-maybe-switch-to-next ()
  "Kill current buffer. Switch to next buffer if previous command
was switching to next buffer or this command itself allowing
sequential closing of uninteresting buffers."
  (interactive)
  (let ( (cmd last-command) )
    (kill-buffer (current-buffer))
    (when (memq cmd (list 'next-buffer this-command))
      (next-buffer))))
(global-set-key [s-delete] 'my--kill-this-buffer-maybe-switch-to-next)
(defun my--backward-other-window ()
  (interactive)
  (other-window -1))
(global-set-key [s-up] #'my--backward-other-window)
(global-set-key [s-down] #'other-window)
(global-set-key [s-tab] 'other-window)

请注意,我使用superkey,因此term-raw-map其他任何keymap都可能与我的key绑定不冲突。要从super左键制作键,Win我使用.xmodmaprc

! To load this config run:
!   $ xmodmap .xmodmaprc

! Win key.
clear mod3
clear mod4

keycode 133 = Super_L
keycode 134 = Hyper_R
add mod3 = Super_L
add mod4 = Hyper_R

您只应该记住2条命令:C-c C-j-进入普通的Emacs编辑模式(用于复制或grep缓冲文本),C-c C-k-返回终端仿真模式。

鼠标选择和Shift-Insert工作方式与相同xterm


1
谢谢,这是金子!特别是那.inputrc部分!
cmantas

1

我使用Prelude,当我按下Meta + Tab时,它会为我完成。

另外,Ctrl + i似乎也可以做同样的事情。




-2

我没有声称自己是emacs专家,但这应该可以解决您的问题:

创建:〜/ .emacs

添加到它:

(需要'shell-command)(shell-command-completion-mode)

Emacs接管了外壳程序,因此BASH设置不会保留下来。这将为EMACS本身设置自动完成。


不,这不能解决问题。它仅适用于shell命令,不适用于shell模式。此外,它不会启用问题中要求的智能完成功能(只会完成命令和文件名)。
matli

1
shell-command-completion-mode会完成文件名并默认启用。我想要Bash的完成功能(可扩展为包括apt-get和svn的子命令)。
克里斯·康威
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.