Emacs shell 模式下的 Bash 自动补全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/163591/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Bash autocompletion in Emacs shell-mode
提问by Chris Conway
In the GNOME Terminal, Bash does smart auto-completion. For example
在 GNOME 终端中,Bash 执行智能自动完成。例如
apt-get in<TAB>
becomes
变成
apt-get install
In Emacs shell-mode, this auto-completion doesn't work, even after I explicitly source /etc/bash_completion
. The above example sticks as in
or auto-completes with a filename in the current directory rather than a valid apt-get
command option. Presumably, this is because Emacs is intercepting the Tab key-press. How do I enable smart auto-completion in shell-mode
?
在 Emacs shell 模式下,即使在我明确使用/etc/bash_completion
. 上面的例子坚持in
或自动完成当前目录中的文件名而不是有效的apt-get
命令选项。据推测,这是因为 Emacs 正在拦截 Tab 按键。如何在 中启用智能自动完成shell-mode
?
回答by David Christiansen
I know this question is three years old, but it's something that I've also been interested in solving. A Web search directed me to a piece of elisp that makes Emacs use bash for completion in shell mode. It works for me, in any case.
我知道这个问题已经三年了,但我也有兴趣解决这个问题。网络搜索将我定向到了一个使 Emacs 在 shell 模式下使用 bash 完成的 elisp。无论如何,它对我有用。
Check it out at https://github.com/szermatt/emacs-bash-completion.
回答by Steve Lacey
In the emacs shell, it's actually emacs doing the auto-completion, not bash. If the shell and emacs are out of sync (e.g. by using pushd, popd or some bash user function that changes the shell's current directory), then auto-completion stops working.
在 emacs shell 中,它实际上是 emacs 执行自动完成,而不是 bash。如果 shell 和 emacs 不同步(例如,通过使用 pushd、popd 或某些更改 shell 当前目录的 bash 用户函数),则自动完成将停止工作。
To fix this, just type 'dirs' into the shell and things get back in sync.
要解决这个问题,只需在 shell 中输入“dirs”,一切就会恢复同步。
I also have the following in my .emacs:
我的 .emacs 中还有以下内容:
(global-set-key "\M-\r" 'shell-resync-dirs)
Then just hitting Esc-return resyncs the auto-completion.
然后只需点击 Esc-return 即可重新同步自动完成。
回答by matli
I don't know the answer to this. But the reason that it doesn't work as you expect is probably because the completion in emacs shells is handled by emacs internally (by the comint-dynamic-complete function), and doesn't have those smart completion functions built-in.
我不知道这个问题的答案。但是它没有像您期望的那样工作的原因可能是因为 emacs shell 中的完成是由 emacs 内部处理的(通过 comint-dynamic-complete 函数),并且没有内置那些智能完成功能。
I'm afraid it is not an easy thing to fix.
恐怕这不是一件容易解决的事情。
Edit: njsf's suggestion of using term-mode is probably as good as it gets. Start it with
编辑:njsf 使用 term-mode 的建议可能是最好的。开始吧
M-x term它包含在标准的 emacs 发行版中(至少在 Ubuntu 和 Debian 上包含在 emacs21-common 或 emacs22-common 中)。
回答by njsf
Like Matli said, it is not an easy task, since bash is started with --noediting and TAB is bound to comint-dynamic-complete.
就像 Matli 所说的,这不是一件容易的事,因为 bash 是从 --noediting 开始的,而 TAB 绑定到 comint-dynamic-complete。
One could possibly rebind TAB to self-insert-command in shell-comand-hook with local-set-key and make shell-mode not start with --noediting by M-x customize-variable RET explicit-bash-args, but I suspect that it will not sit well with all other editing.
可以将 TAB 重新绑定到带有 local-set-key 的 shell-comand-hook 中的 self-insert-command,并使 shell-mode 不以 --noediting 通过 Mx 自定义变量 RET 显式 bash-args 开始,但我怀疑它不适用于所有其他编辑。
You might want to try term-mode, but it has another set of problems, because some of the other regular keybindings are overtaken by term-mode.
您可能想尝试 term-mode,但它有另一组问题,因为一些其他常规键绑定已被 term-mode 取代。
EDIT: By other regular keybidings being overtaken by term-mode, I mean all but C-c which becomes the escape to be able to switch buffers. So instead of C-x k to kill the buffer you'd have to C-c C-x k. Or to switch to another buffer 'C-c C-x o' or 'C-c C-x 2'
编辑:通过术语模式取代其他常规键控,我的意思是除 Cc 之外的所有键,它成为能够切换缓冲区的转义符。因此,您必须 Cc Cx k 而不是 Cx k 来终止缓冲区。或者切换到另一个缓冲区“Cc Cx o”或“Cc Cx 2”
回答by gavenkoa
Please, consider another mode M-x term
, like I did this when hit problem in 2011. I tried to gather all efforts over Inet at that time to make shell work with Bash completion, including this question. But since discovering alternative in face of term-mode
I don't even want to try eshell
.
请考虑另一种模式M-x term
,就像我在 2011 年遇到问题时所做的那样。当时我试图在 Inet 上集中所有的努力,使 shell 与 Bash 完成工作,包括这个问题。但是自从在面对term-mode
我时发现了替代方案后,我什至不想尝试eshell
.
It is full terminal emulator, so you can run interactive program inside, like Midnight commander. Or switch to zsh
completion so you won't lose time on Emacs configuration.
它是完整的终端模拟器,因此您可以在其中运行交互式程序,例如午夜指挥官。或者切换到zsh
完成,这样您就不会在 Emacs 配置上浪费时间。
You get TAB completion in bash for free. But more important you get full Readline power, like incremental or prefixed command search. To make this setup more convenient check my .inputrc, .bashrc, .emacs.
您可以免费获得 bash 中的 TAB 补全。但更重要的是,您可以获得完整的 Readline 功能,例如增量或前缀命令搜索。为了使此设置更方便,请检查我的.inputrc、.bashrc、.emacs。
Essential part of .inputrc
:
的重要部分.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
(YEA! There is dabbrev in Bash from any word in ~/.bash_history
):
.bashrc
(是的!Bash 中的任何单词都有 dabbrev ~/.bash_history
):
set -o emacs
if [[ $- == *i* ]]; then
bind '"\e/": dabbrev-expand'
bind '"\ee": edit-and-execute-command'
fi
.emacs
to make navigation comfortable in term buffer:
.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)
As any usual commands as C-x o
aren't working in terminal emulation mode I extended keymap with:
由于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)
Note that I use super
key so term-raw-map
and possibly any other keymap don't conflict with my key bindings. To make super
key from left Win
key I use .xmodmaprc
:
请注意,我使用super
键,因此term-raw-map
可能任何其他键映射都不会与我的键绑定发生冲突。要从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
You just should remember 2 commands: C-c C-j
- to enter to normal Emacs editing mode (for copying or grepping in buffer text), C-c C-k
- to return to terminal emulation mode.
您只需要记住 2 个命令:C-c C-j
- 进入正常的 Emacs 编辑模式(用于在缓冲区文本中复制或 grepping),C-c C-k
- 返回终端仿真模式。
Mouse selection and Shift-Insert
work as in xterm
.
鼠标选择和Shift-Insert
工作如xterm
.
回答by duma
I use Prelude and when I hit Meta+Tab it completes for me.
我使用 Prelude,当我点击 Meta+Tab 时,它会为我完成。
Also, Ctrl+i seems to do the same thing.
此外, Ctrl+i 似乎也做同样的事情。
回答by Prgrm.celeritas
I know this post is over 11 years old now. But I have created a function to give native shell completion in Emacs. It just sends a tab key to the underlying process and intercepts the output, so it is the exact same as you would get in the shell itself.
我知道这篇文章已经超过 11 年了。但是我创建了一个函数来在 Emacs 中提供本机 shell 完成。它只是向底层进程发送一个制表键并拦截输出,因此它与您在 shell 本身中得到的完全相同。
https://github.com/CeleritasCelery/emacs-native-shell-complete
https://github.com/CeleritasCelery/emacs-native-shell-complete
回答by a_subscriber
回答by Scott Alan Miller
I make no claims to being an emacs expert but this should solve your problem:
我不声称自己是 emacs 专家,但这应该可以解决您的问题:
Create: ~/.emacs
创建:~/.emacs
Add to it:
添加到它:
(require 'shell-command) (shell-command-completion-mode)
(需要 'shell-command) (shell-command-completion-mode)
Emacs takes over the shell so BASH settings don't carry through. This will set auto completion for EMACS itself.
Emacs 接管了 shell,因此 BASH 设置不会继续执行。这将为 EMACS 本身设置自动完成。