Bash-Autovervollständigung im Emacs-Shell-Modus

91

Im GNOME-Terminal führt Bash eine intelligente automatische Vervollständigung durch. Beispielsweise

apt-get in<TAB>

wird

apt-get install

Im Emacs-Shell-Modus funktioniert diese automatische Vervollständigung nicht, selbst nachdem ich explizit eine Quelle erstellt habe /etc/bash_completion. Das obige Beispiel bleibt inbei einem Dateinamen im aktuellen Verzeichnis oder wird automatisch mit diesem vervollständigt, anstatt einer gültigen apt-getBefehlsoption. Vermutlich liegt dies daran, dass Emacs das Drücken der Tabulatortaste abfängt. Wie aktiviere ich die intelligente automatische Vervollständigung in shell-mode?

Chris Conway
quelle
Für alle, die Emacs noch nicht kennen ... es gibt andere Shell- Modi in Emacs. Wie eshell-modedas hat Tab-Vervollständigung. Weitere Infos hier: masteringemacs.org/articles/2010/11/01/…
Ross
2
Die automatische Vervollständigung von eshell funktioniert nur für lokale Verzeichnisse. Wenn Sie auf einen anderen Computer ssh, verlieren Sie plötzlich diese Fähigkeit.
Hajovonta

Antworten:

92

Ich weiß, dass diese Frage drei Jahre alt ist, aber ich war auch daran interessiert, sie zu lösen. Eine Websuche führte mich zu einem Stück Elisp, das Emacs dazu bringt, Bash für den Abschluss im Shell-Modus zu verwenden. Es funktioniert auf jeden Fall bei mir.

Überprüfen Sie es unter https://github.com/szermatt/emacs-bash-completion .

David Christiansen
quelle
6
+1 für den Mut, eine dreijährige, aber immer noch absolut relevante Frage zu beantworten. Vielen Dank!
Djhaskin987
3
Dies ist bereits in melpa melpa.org/#/bash-completion , die Installation ist unkompliziert M-x package-list-packages, aber am Ende hat es bei mir nicht funktioniert, ich weiß nicht warum, es können meine Emacs (24.3.1) oder sein Bash (4.3.30) Version. In der Dokumentation heißt es "bash-vervollständigung.el reagiert sehr empfindlich auf die Betriebssystem- und BASH-Version ...". Dann gibt es eine Liste, in der meine Versionen fehlen.
Boclodoa
Leider steht das ausstehende Problem Nr. 6 für die aktuelle Anzahl von CLI-Tools nicht so nützlich aus.
Jesse Glick
21

In der Emacs-Shell werden Emacs automatisch vervollständigt und nicht geschlagen. Wenn die Shell und die Emacs nicht synchron sind (z. B. mithilfe von pushd, popd oder einer Bash-Benutzerfunktion, die das aktuelle Verzeichnis der Shell ändert), funktioniert die automatische Vervollständigung nicht mehr.

Um dies zu beheben, geben Sie einfach 'dirs' in die Shell ein und die Dinge werden wieder synchronisiert.

Ich habe auch Folgendes in meinen .emacs:

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

Durch einfaches Drücken von Esc-Return wird die automatische Vervollständigung erneut synchronisiert.

Steve Lacey
quelle
9
Dies ist eine schöne Antwort auf eine andere Frage!
Chris Conway
Vielen Dank. Ich benutze Autojump und das war das Problem, warum die Verzeichnisse nicht mehr synchron waren.
Plankalkül
Chris Conway, ja, zu diesem: emacs.stackexchange.com/questions/30550/… :-)
Unhammer
15

Ich kenne die Antwort darauf nicht. Der Grund dafür, dass es nicht wie erwartet funktioniert, liegt wahrscheinlich darin, dass die Vervollständigung in Emacs-Shells von Emacs intern (von der Funktion comint-dynamic-complete) verwaltet wird und diese intelligenten Vervollständigungsfunktionen nicht integriert sind.

Ich fürchte, es ist nicht einfach, das Problem zu beheben.

Edit: njsfs Vorschlag, den Term-Modus zu verwenden, ist wahrscheinlich so gut wie es nur geht. Beginnen Sie mit

Mx Begriff
Es ist in der Standard-Emacs-Distribution enthalten (und zumindest in emacs21-common oder emacs22-common unter Ubuntu und Debian).

matli
quelle
2
Die Tab-Vervollständigung ist mit noch schlimmer M-x term.
Mcandre
6

Wie Matli sagte, ist es keine leichte Aufgabe, da Bash mit --noediting gestartet wird und TAB an comint-dynamic-complete gebunden ist.

Man könnte TAB möglicherweise mit dem Local-Set-Key wieder an den Self-Insert-Befehl im Shell-Comand-Hook binden und den Shell-Modus nicht mit --noediting by Mx anpassen - Variable RET explizit-bash-args, aber ich vermute das es wird nicht gut mit allen anderen Bearbeitungen zusammenpassen.

Vielleicht möchten Sie den Term-Modus ausprobieren, aber es gibt noch andere Probleme, da einige der anderen regulären Tastenkombinationen vom Term-Modus überholt werden.

BEARBEITEN: Mit anderen regulären Keybidings, die vom Term-Modus überholt werden, meine ich alle außer Cc, was zur Flucht wird, um Puffer wechseln zu können. Anstelle von Cx k müssten Sie also Cx Cx k verwenden, um den Puffer zu töten. Oder um zu einem anderen Puffer 'Cc Cx o' oder 'Cc Cx 2' zu wechseln

njsf
quelle
Selbsteinfügungsbefehl ist es nicht: Er fügt das TAB-Zeichen ein, anstatt den TAB-Tastendruck an Bash weiterzuleiten.
Chris Conway
Ich habe keinen Term-Mode-Befehl und kann nicht herausfinden, wo ich ihn bekommen kann.
Chris Conway
6

Bitte M-x termdenken Sie an einen anderen Modus , wie ich ihn 2011 bei einem Trefferproblem gemacht habe. Ich habe versucht, alle Anstrengungen über Inet zu sammeln, damit die Shell mit der Bash-Vervollständigung funktioniert, einschließlich dieser Frage. Aber seit term-modeich angesichts dessen eine Alternative entdeckt habe, möchte ich es nicht einmal versuchen eshell.

Es ist ein vollständiger Terminalemulator, sodass Sie ein interaktives Programm wie Midnight Commander ausführen können. Oder wechseln Sie zum zshAbschluss, damit Sie bei der Emacs-Konfiguration keine Zeit verlieren.

Sie erhalten die TAB-Vervollständigung in Bash kostenlos. Wichtiger ist jedoch, dass Sie die volle Readline-Leistung erhalten, z. B. inkrementelle oder vorangestellte Befehlssuche . Um dieses Setup bequemer zu gestalten, überprüfen Sie meine .inputrc , .bashrc , .emacs .

Wesentlicher Bestandteil von .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(JA! Es gibt Dabbrev in Bash von jedem Wort in ~/.bash_history):

set -o emacs

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

.emacs um die Navigation im Term Buffer komfortabel zu gestalten:

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

Wie alle üblichen Befehle, C-x odie im Terminalemulationsmodus nicht funktionieren, habe ich die Keymap erweitert mit:

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

Beachten Sie, dass ich superSchlüssel verwende, damit term-raw-mapmöglicherweise keine andere Keymap mit meinen Tastenkombinationen in Konflikt steht. Um einen superSchlüssel aus dem linken WinSchlüssel zu machen, benutze ich .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

Sie sollten sich nur zwei Befehle merken: C-c C-j- um in den normalen Emacs-Bearbeitungsmodus zu wechseln (zum Kopieren oder Greifen in Puffertext), C-c C-k- um zum Terminalemulationsmodus zurückzukehren.

Mausauswahl und Shift-InsertArbeit wie in xterm.

Gavenkoa
quelle
1
Danke, das ist Gold! vor allem das .inputrcteil!
cmantas
1

Ich benutze Prelude und wenn ich Meta + Tab drücke, ist es für mich abgeschlossen.

Auch Strg + i scheint dasselbe zu tun.

Duma
quelle
1

Ich weiß, dass dieser Beitrag jetzt über 11 Jahre alt ist. Aber ich habe eine Funktion erstellt, um die native Shell in Emacs zu vervollständigen. Es sendet lediglich eine Tabulatortaste an den zugrunde liegenden Prozess und fängt die Ausgabe ab, sodass sie genau so ist, wie Sie sie in der Shell selbst erhalten würden.

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

Prgrm.celeritas
quelle
0

Ich benutze den Steuermodus. Es hat diese Funktionalität (nach Drücken von "TAB"): Geben Sie hier die Bildbeschreibung ein

a_subscriber
quelle
-2

Ich behaupte nicht, ein Emacs-Experte zu sein, aber dies sollte Ihr Problem lösen:

Erstellen Sie: ~ / .emacs

Fügen Sie hinzu:

(erfordert 'Shell-Befehl) (Shell-Befehl-Abschluss-Modus)

Emacs übernimmt die Shell, damit die BASH-Einstellungen nicht übernommen werden. Dadurch wird die automatische Vervollständigung für EMACS selbst festgelegt.

Scott Alan Miller
quelle
Nein, das löst das Problem nicht. Es funktioniert nur mit dem Shell-Befehl, nicht im Shell-Modus. Außerdem wird die in der Frage angeforderte intelligente Vervollständigung nicht aktiviert (es werden nur Befehle und Dateinamen vervollständigt).
Matli
1
Der Shell-Befehl-Vervollständigungsmodus vervollständigt den Dateinamen und ist standardmäßig aktiviert. Ich möchte die Vervollständigungsfunktion von Bash (die erweiterbar ist, um beispielsweise Unterbefehle für apt-get und svn einzuschließen).
Chris Conway