Bash autocompletado en modo shell de Emacs

93

En la Terminal GNOME, Bash realiza la autocompletación inteligente. Por ejemplo

apt-get in<TAB>

se convierte en

apt-get install

En el modo shell de Emacs, este autocompletado no funciona, incluso después de haber obtenido explícitamente /etc/bash_completion. El ejemplo anterior se adhiere ino se completa automáticamente con un nombre de archivo en el directorio actual en lugar de una apt-getopción de comando válida . Presumiblemente, esto se debe a que Emacs está interceptando la pulsación de la tecla Tab. ¿Cómo habilito la finalización automática inteligente en shell-mode?

Chris Conway
fuente
Para cualquiera que sea nuevo en emacs ... hay otros modos de shell en emacs. Por ejemplo, eshell-modeque tiene finalización de pestaña. Más información aquí: masteringemacs.org/articles/2010/11/01/…
Ross
3
El autocompletado de eshell solo funciona para directorios locales, si ssh a otra máquina, de repente pierde esta capacidad.
hajovonta

Respuestas:

92

Sé que esta pregunta tiene tres años, pero es algo que también me ha interesado resolver. Una búsqueda en la Web me dirigió a una pieza de elisp que hace que Emacs use bash para completar en modo shell. En cualquier caso, funciona para mí.

Compruébalo en https://github.com/szermatt/emacs-bash-completion .

David Christiansen
fuente
6
+1 por tener el coraje de responder a una pregunta de tres años, pero aún totalmente relevante. ¡Gracias!
djhaskin987
3
Esto ya está en melpa melpa.org/#/bash-completion , la instalación es sencilla de usar M-x package-list-packages, pero al final no funcionó para mí, no sé por qué, puede ser mi emacs (24.3.1) o versión bash (4.3.30). La documentación dice que "bash -mentation.el es bastante sensible al sistema operativo y la versión de BASH ..." y luego hay una lista donde mis versiones están ausentes.
boclodoa
Desafortunadamente, el número 6 pendiente no parece tan útil para la cosecha actual de herramientas CLI.
Jesse Glick
21

En el shell de emacs, en realidad es emacs el que realiza el autocompletado, no bash. Si el shell y emacs no están sincronizados (por ejemplo, al usar pushd, popd o alguna función de usuario de bash que cambia el directorio actual del shell), la finalización automática deja de funcionar.

Para solucionar esto, simplemente escriba 'dirs' en el shell y las cosas se volverán a sincronizar.

También tengo lo siguiente en mi .emacs:

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

Luego, simplemente presionando Esc-return resincroniza el autocompletado.

Steve Lacey
fuente
9
¡Esta es una buena respuesta a una pregunta diferente!
Chris Conway
Gracias. Utilizo autojump y ese era el problema por el que los directorios no estaban sincronizados.
Plankalkül
Chris Conway, sí, a este: emacs.stackexchange.com/questions/30550/… :-)
unhammer
15

No sé la respuesta a esto. Pero la razón por la que no funciona como esperabas es probablemente porque emacs maneja internamente la finalización en shells emacs (mediante la función comint-dynamic-complete) y no tiene incorporadas esas funciones de finalización inteligente.

Me temo que no es fácil de arreglar.

Editar: la sugerencia de njsf de usar el modo de término es probablemente tan buena como parece. Empiece con

Término mx
Está incluido en la distribución estándar de emacs (y al menos en emacs21-common o emacs22-common en Ubuntu y Debian).

matli
fuente
2
La finalización de tabulación es aún peor con M-x term.
mcandre
6

Como dijo Matli, no es una tarea fácil, ya que bash se inicia con --noediting y TAB está obligado a comint-dynamic-complete.

Uno podría posiblemente volver a vincular TAB a self-insert-command en shell-comand-hook con local-set-key y hacer que el modo shell no comience con --noediting por Mx custom-variable RET explicit-bash-args, pero sospecho que no quedará bien con todas las demás ediciones.

Es posible que desee probar el modo de término, pero tiene otro conjunto de problemas, porque algunas de las otras combinaciones de teclas regulares son superadas por el modo de término.

EDITAR: Por otras ofertas de teclas regulares superadas por el modo de término, me refiero a todas menos Cc, que se convierte en el escape para poder cambiar de búfer. Entonces, en lugar de Cx k para matar el búfer, tendrías que Cc Cx k. O para cambiar a otro búfer 'Cc Cx o' o 'Cc Cx 2'

njsf
fuente
self-insert-command no es así: inserta el carácter TAB en lugar de pasar la pulsación de la tecla TAB hasta Bash.
Chris Conway
No tengo un comando de modo de término y no puedo averiguar dónde conseguirlo.
Chris Conway
6

Por favor, considere otro modo M-x term, como lo hice cuando tuve un problema en 2011. Intenté reunir todos los esfuerzos sobre Inet en ese momento para que el shell funcionara con la finalización de Bash, incluida esta pregunta. Pero desde que descubrí la alternativa term-mode, ni siquiera quiero intentarlo eshell.

Es un emulador de terminal completo, por lo que puede ejecutar un programa interactivo en su interior, como Midnight Commander. O cambie a la zshfinalización para no perder tiempo en la configuración de Emacs.

Obtienes la finalización de TAB en bash de forma gratuita. Pero lo que es más importante, obtiene toda la potencia de Readline, como la búsqueda de comandos incrementales o con prefijos . Para que esta configuración sea más conveniente, consulte mi .inputrc , .bashrc , .emacs .

Parte esencial de .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(¡SÍ! Hay dabbrev en Bash de cualquier palabra en ~/.bash_history):

set -o emacs

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

.emacs para que la navegación sea cómoda en el búfer de términos:

(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)

Como cualquier comando habitual C-x ono funciona en el modo de emulación de terminal, extendí el mapa de teclas con:

(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)

Tenga en cuenta que utilizo la superclave term-raw-mapy posiblemente cualquier otro mapa de teclas no entre en conflicto con mis combinaciones de teclas. Para hacer la superclave desde la tecla izquierda Winutilizo .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

Solo debe recordar 2 comandos: C-c C-j- para ingresar al modo de edición normal de Emacs (para copiar o hacer grepping en el texto del búfer), C-c C-k- para regresar al modo de emulación de terminal.

Selección del mouse y Shift-Inserttrabajo como en xterm.

Gavenkoa
fuente
1
¡Gracias, esto es oro! especialmente la .inputrcparte!
cmantas
1

Uso Preludio y cuando presiono Meta + Tab se completa para mí.

Además, Ctrl + i parece hacer lo mismo.

duma
fuente
1

Sé que esta publicación tiene más de 11 años. Pero he creado una función para completar el shell nativo en Emacs. Simplemente envía una tecla de tabulación al proceso subyacente e intercepta la salida, por lo que es exactamente lo mismo que obtendría en el propio shell.

https://github.com/CeleritasCelery/emacs-native-shell-complete

Prgrm.celeritas
fuente
0

Yo uso el modo timón. Tiene esta funcionalidad (después de presionar "TAB"): ingrese la descripción de la imagen aquí

un_suscriptor
fuente
-2

No pretendo ser un experto en emacs, pero esto debería resolver su problema:

Crear: ~ / .emacs

Añádalo:

(requiere 'comando de shell) (modo de finalización de comando de shell)

Emacs se hace cargo del shell para que la configuración de BASH no se lleve a cabo. Esto establecerá la finalización automática para EMACS.

Scott Alan Miller
fuente
No, esto no resuelve el problema. Solo funciona en shell-command, no en modo shell. Y además, no habilita la finalización inteligente que se solicitó en la pregunta (solo completará comandos y nombres de archivo).
matli
1
shell-command-deployment-mode completa el nombre de archivo y está habilitado de forma predeterminada. Quiero la función de finalización de Bash (que es extensible para incluir, por ejemplo, subcomandos para apt-get y svn).
Chris Conway