web-dev-qa-db-fra.com

Bash autocompletion en mode shell Emacs

Dans le terminal GNOME, Bash effectue la saisie automatique intelligente. Par exemple

apt-get in<TAB>

devient

apt-get install

En mode shell Emacs, cette complétion automatique ne fonctionne pas, même après que je source explicitement /etc/bash_completion. L'exemple ci-dessus reste identique à in ou se termine automatiquement avec un nom de fichier dans le répertoire en cours plutôt qu'une option de commande apt-get valide. C'est probablement parce qu'Emacs intercepte la touche Tab. Comment activer l'auto-complétion intelligente dans Shell-mode?

81
Chris Conway

Je sais que cette question a trois ans, mais je souhaite également résoudre ce problème. Une recherche sur le Web m'a dirigé vers un morceau d'elisp qui oblige Emacs à utiliser bash pour l'achèvement en mode Shell. Cela fonctionne pour moi, en tout cas.

Découvrez-le sur https://github.com/szermatt/emacs-bash-completion .

84
David Christiansen

Dans le shell emacs, c’est en fait emacs qui effectue l’auto-complétion, pas bash. Si Shell et emacs ne sont pas synchronisés (par exemple, en utilisant pushd, popd ou une fonction utilisateur bash qui modifie le répertoire actuel du shell), la complétion automatique cesse de fonctionner.

Pour résoudre ce problème, il suffit de taper "dirs" dans le shell et les choses sont synchronisées.

J'ai aussi ce qui suit dans mes .emacs:

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

Il suffit ensuite d'appuyer sur Echap-retour pour resynchroniser la saisie semi-automatique.

17
Steve Lacey

Je ne connais pas la réponse à cela. Mais la raison pour laquelle cela ne fonctionne pas comme prévu est probablement due au fait que l'achèvement dans les shells emacs est géré en interne par emacs (par la fonction comint-dynamic-complete) et ne comporte pas ces fonctions d'achèvement intelligentes.

Je crains que ce ne soit pas une chose facile à réparer.

Edit: la suggestion du njsf d'utiliser le mode terme est probablement aussi valable qu'elle le peut. Commencez avec 

M-x terme
Il est inclus dans la distribution standard emacs (et au moins dans emacs21-common ou emacs22-common sur Ubuntu et Debian au moins).

13
matli

Veuillez envisager un autre mode M-x term, comme ce fut le cas lorsque j'ai eu ce problème en 2011. J'essayais alors de rassembler tous les efforts sur Inet pour que Shell fonctionne avec la complétion de Bash, y compris cette question. Mais depuis que j'ai découvert une alternative face à term-mode, je ne veux même pas essayer eshell.

C'est un émulateur de terminal complet, vous pouvez donc exécuter un programme interactif à l'intérieur, comme Midnight Commander. Ou passez en mode zsh pour ne pas perdre de temps sur la configuration d'Emacs.

Vous obtenez la complétion de TAB en bash gratuitement. Mais plus important encore, vous obtenez le plein pouvoir Readline, comme incrémental ou la recherche avec préfixe. Pour rendre cette configuration plus pratique, vérifiez mes .inputrc , .bashrc , .emacs .

Partie essentielle 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 (YEA! Il y a dabbrev dans Bash de n'importe quel mot dans ~/.bash_history):

set -o emacs

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

.emacs pour rendre la navigation confortable dans la mémoire tampon de termes:

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

Comme toutes les commandes habituelles comme C-x o ne fonctionnent pas en mode d’émulation de terminal, j’ai étendu le keymap avec:

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

Notez que j'utilise la clé super pour que term-raw-map et éventuellement tout autre clavier ne soient pas en conflit avec mes raccourcis clavier. Pour créer la clé super à partir de la clé Win de gauche, j'utilise .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

Vous devez juste vous rappeler de 2 commandes: C-c C-j - pour entrer en mode d’édition normal d’Emacs (pour la copie ou l’enregistrement dans du texte tampon), C-c C-k - pour revenir au mode d’émulation de terminal.

La sélection de la souris et Shift-Insert fonctionnent comme dans xterm.

6
gavenkoa

Comme Matli l'a dit, ce n'est pas une tâche facile, puisque bash est lancé avec --noediting et que TAB est lié à comint-dynamic-complete.

On pourrait éventuellement relier TAB à self-insert-command dans Shell-comand-hook avec local-set-key Et faire en sorte que le mode Shell ne commence pas par --noediting par Mx custom-variable RET explicit-bash-args, mais Je soupçonne que cela ne se mariera pas bien avec toutes les autres montages.

Vous voudrez peut-être essayer le mode terme, mais cela pose un autre ensemble de problèmes, car certaines des autres associations de touches normales sont dépassées par le mode terme.

EDIT: Par autres enchères au clavier normales dépassées par le terme-mode, je veux dire tout sauf C-c qui devient l’échappement pour pouvoir changer de tampon. Donc, au lieu de C-x k pour tuer le tampon, vous devez C-C C-x k. Ou pour passer à un autre tampon 'C-C C-x o' ou 'C-C C-x 2'

6
njsf

J'utilise Prelude et lorsque je frappe sur Meta + Tab, cela se termine pour moi.

En outre, Ctrl + i semble faire la même chose.

1
duma

J'utilise le mode barre. Il a cette fonctionnalité (après avoir appuyé sur "TAB"):  enter image description here

0
Alexei