Completamento automatico di Bash in modalità shell di Emacs


93

Nel terminale GNOME, Bash esegue l'auto-completamento intelligente. Per esempio

apt-get in<TAB>

diventa

apt-get install

Nella modalità shell di Emacs, questo completamento automatico non funziona, anche dopo aver fornito esplicitamente il codice sorgente /etc/bash_completion. L'esempio sopra si attacca come ino si completa automaticamente con un nome di file nella directory corrente piuttosto che con apt-getun'opzione di comando valida . Presumibilmente, questo è perché Emacs sta intercettando la pressione del tasto Tab. Come si abilita il completamento automatico intelligente in shell-mode?


Per chiunque sia nuovo in emacs ... ci sono altre modalità shell in emacs. Ad esempio, eshell-modeche ha il completamento della scheda. Maggiori informazioni qui: masteringemacs.org/articles/2010/11/01/…
Ross

3
L'autocompletamento di eshell funziona solo per le directory locali, se esegui ssh su un'altra macchina, perdi improvvisamente questa capacità.
hajovonta

Risposte:


92

So che questa domanda è vecchia di tre anni, ma è qualcosa che mi interessava anche risolvere. Una ricerca sul Web mi ha indirizzato a un pezzo di elisp che fa usare a Emacs bash per il completamento in modalità shell. In ogni caso per me funziona.

Dai un'occhiata a https://github.com/szermatt/emacs-bash-completion .


6
+1 per aver avuto il coraggio di rispondere a una domanda di tre anni, ma ancora del tutto pertinente. Grazie!
djhaskin987

3
Questo è già in melpa melpa.org/#/bash-completion , l'installazione è semplice da usare M-x package-list-packages, ma alla fine non ha funzionato per me, non so perché, potrebbe essere il mio emacs (24.3.1) o bash (4.3.30) versione. La documentazione dice "bash-completamento.el è abbastanza sensibile al sistema operativo e alla versione BASH ..." quindi è un elenco in cui le mie versioni sono assenti.
boclodoa

Sfortunatamente in attesa del numero 6, questo non sembra così utile per l'attuale raccolto di strumenti CLI.
Jesse Glick,

21

Nella shell di emacs, in realtà è emacs che esegue l'auto-completamento, non bash. Se la shell e emacs non sono sincronizzati (es. Usando pushd, popd o qualche funzione utente bash che cambia la directory corrente della shell), l'auto-completamento smette di funzionare.

Per risolvere questo problema, digita semplicemente "dirs" nella shell e le cose tornano sincronizzate.

Ho anche quanto segue nel mio .emacs:

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

Quindi basta premere Esc-return per risincronizzare l'auto-completamento.


9
Questa è una bella risposta a una domanda diversa!
Chris Conway,

Grazie. Uso l'autojump e questo era il problema per cui le directory non erano sincronizzate.
Plankalkül

Chris Conway, sì, a questo: emacs.stackexchange.com/questions/30550/… :-)
unhammer

15

Non conosco la risposta a questo. Ma la ragione per cui non funziona come ti aspetti è probabilmente perché il completamento nelle shell di emacs è gestito internamente da emacs (dalla funzione comint-dynamic-complete), e non ha quelle funzioni di completamento intelligente integrate.

Temo che non sia una cosa facile da risolvere.

Modifica: il suggerimento di njsf di utilizzare la modalità termine è probabilmente il migliore possibile. Inizia con

Termine Mx
È incluso nella distribuzione standard di emacs (e almeno in emacs21-common o emacs22-common su Ubuntu e Debian).


2
Il completamento con tabulazione è anche peggio con M-x term.
mcandre

6

Come ha detto Matli, non è un compito facile, poiché bash inizia con --noediting e TAB è destinato a comint-dynamic-complete.

Si potrebbe eventualmente riassociare TAB al comando auto-inserimento in shell-comand-hook con local-set-key e fare in modo che la modalità shell non inizi con --noediting di Mx personalizza-variabile RET esplicito-bash-args, ma sospetto che non si adatterà bene a tutte le altre modifiche.

Potresti voler provare la modalità termine, ma ha un altro insieme di problemi, perché alcune delle altre combinazioni di tasti regolari vengono sostituite dalla modalità termine.

EDIT: Con altre offerte di tasti regolari che vengono superate dalla modalità termine, intendo tutto tranne Cc che diventa la via di fuga per poter cambiare buffer. Quindi invece di Cx k per uccidere il buffer dovresti Cc Cx k. O per passare a un altro buffer 'Cc Cx o' o 'Cc Cx 2'


self-insert-command non è vero: inserisce il carattere TAB invece di passare il tasto TAB a Bash.
Chris Conway

Non ho un comando in modalità termine e non riesco a capire dove trovarlo.
Chris Conway

6

Per favore, considera un'altra modalità M-x term, come ho fatto io quando ho riscontrato il problema nel 2011. Ho cercato di raccogliere tutti gli sforzi su Inet in quel momento per far funzionare la shell con il completamento di Bash, compresa questa domanda. Ma da quando term-modeho scoperto un'alternativa di fronte a non ho nemmeno voglia di provarci eshell.

È un emulatore di terminale completo, quindi puoi eseguire programmi interattivi all'interno, come Midnight Commander. Oppure passa al zshcompletamento in modo da non perdere tempo con la configurazione di Emacs.

Ottieni il completamento TAB in bash gratuitamente. Ma ancora più importante, ottieni la piena potenza di Readline, come la ricerca di comandi incrementale o con prefisso . Per rendere questa configurazione più comoda controlla i miei .inputrc , .bashrc , .emacs .

Parte essenziale di .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ì! C'è dabbrev in Bash da qualsiasi parola in ~/.bash_history):

set -o emacs

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

.emacs per rendere confortevole la navigazione nel buffer dei termini:

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

Come tutti i comandi usuali che C-x onon funzionano in modalità di emulazione del terminale, ho esteso la mappa dei tasti 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)

Nota che io uso la superchiave così term-raw-mape possibilmente qualsiasi altra mappa di tasti non è in conflitto con le mie associazioni di tasti. Per creare la superchiave dal Wintasto sinistro uso .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

Dovresti solo ricordare 2 comandi: C-c C-j- per entrare nella normale modalità di modifica di Emacs (per copiare o grepping nel testo del buffer), C-c C-k- per tornare alla modalità di emulazione del terminale.

Selezione del mouse e Shift-Insertlavoro come in xterm.


1
Grazie, questo è oro! soprattutto la .inputrcparte!
cmantas

1

Uso Prelude e quando premo Meta + Tab si completa per me.

Inoltre, Ctrl + i sembra fare la stessa cosa.



0

Uso la modalità timone. Ha questa funzionalità (dopo aver premuto "TAB"): inserisci qui la descrizione dell'immagine


-2

Non pretendo di essere un esperto di emacs ma questo dovrebbe risolvere il tuo problema:

Crea: ~ / .emacs

Aggiungi ad esso:

(richiede 'comando-shell) (modalità-completamento-comando-shell)

Emacs prende il controllo della shell in modo che le impostazioni BASH non vengano eseguite. Questo imposterà il completamento automatico per EMACS stesso.


No, questo non risolve il problema. Funziona solo con il comando di shell, non in modalità shell. Inoltre, non abilita il completamento intelligente richiesto nella domanda (completerà solo comandi e nomi di file).
matli

1
shell-command-completamento-mode esegue il completamento del nome del file ed è abilitato per impostazione predefinita. Voglio la funzionalità di completamento di Bash (che è estensibile per includere, ad esempio, i sottocomandi per apt-get e svn).
Chris Conway
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.