Autouzupełnianie Bash w trybie powłoki Emacsa

93

W terminalu GNOME Bash wykonuje inteligentne automatyczne uzupełnianie. Na przykład

apt-get in<TAB>

staje się

apt-get install

W trybie powłoki Emacsa to automatyczne uzupełnianie nie działa, nawet po jawnym źródle /etc/bash_completion. Powyższy przykład zachowuje się jako inlub automatycznie uzupełnia nazwę pliku w bieżącym katalogu, a nie prawidłową apt-getopcję polecenia. Prawdopodobnie dzieje się tak dlatego, że Emacs przechwytuje naciśnięcie klawisza Tab. Jak włączyć inteligentne autouzupełnianie w shell-mode?

Chris Conway
źródło
Dla każdego, kto jest nowy w emacsie ... w emacsie są inne tryby powłoki . Na przykład, eshell-modektóry ma uzupełnianie kart. Więcej informacji tutaj: masteringemacs.org/articles/2010/11/01/…
Ross
3
Funkcja autouzupełniania eshell działa tylko w przypadku katalogów lokalnych, jeśli ssh na inny komputer, nagle tracisz tę zdolność.
hajovonta

Odpowiedzi:

93

Wiem, że to pytanie ma trzy lata, ale jest to coś, czym też byłem zainteresowany rozwiązaniem. Wyszukiwanie w Internecie skierowało mnie do fragmentu elisp, który sprawia, że ​​Emacs używa basha do uzupełniania w trybie powłoki. W każdym razie to działa dla mnie.

Sprawdź to na https://github.com/szermatt/emacs-bash-completion .

David Christiansen
źródło
6
+1 za odwagę, by odpowiedzieć na pytanie trzylatka, ale wciąż bardzo istotne. Dzięki!
djhaskin987
3
To jest już w melpa melpa.org/#/bash-completion , instalacja jest prosta w użyciu M-x package-list-packages, ale ostatecznie nie zadziałała dla mnie, nie wiem dlaczego, może to być mój emacs (24.3.1) lub bash (4.3.30) wersja. Dokumentacja mówi, że „bash-Complete.el jest dość wrażliwy na wersje systemu operacyjnego i BASH…”, a następnie jest lista, na której nie ma moich wersji.
boclodoa
Niestety, nierozstrzygnięty problem # 6 wydaje się nie być tak przydatny dla aktualnego zbioru narzędzi CLI.
Jesse Glick
Ten numer 6 został zamknięty jako <przynajmniej w większości naprawiony / przykład, że nie działał potrzebny> (parafrazując).
Matthew Elvey
21

W powłoce emacsa to właśnie emacs wykonuje automatyczne uzupełnianie, a nie bash. Jeśli powłoka i emacs nie są zsynchronizowane (np. Przez użycie pushd, popd lub jakiejś funkcji użytkownika bash, która zmienia bieżący katalog powłoki), wówczas autouzupełnianie przestaje działać.

Aby to naprawić, po prostu wpisz „dirs” w powłoce i wszystko wróci do synchronizacji.

Mam również w moim .emacs:

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

Następnie naciśnięcie Esc-return powoduje ponowne zsynchronizowanie automatycznego uzupełniania.

Steve Lacey
źródło
9
To miła odpowiedź na inne pytanie!
Chris Conway
Dzięki. Używam autojumpa i to był problem, dlaczego katalogi nie były zsynchronizowane.
Plankalkül
Chris Conway, tak, do tego: emacs.stackexchange.com/questions/30550/... :-)
unhammer
15

Nie znam odpowiedzi na to. Ale powodem, dla którego nie działa tak, jak się spodziewasz, jest prawdopodobnie to, że uzupełnianie w powłokach emacsa jest obsługiwane wewnętrznie przez emacsa (przez funkcję comint-dynamic-complete) i nie ma wbudowanych funkcji inteligentnego uzupełniania.

Obawiam się, że nie jest to łatwe do naprawienia.

Edycja: sugestia njsf dotycząca używania trybu termicznego jest prawdopodobnie tak dobra, jak to tylko możliwe. Zacznij od

Termin MX
Jest zawarty w standardowej dystrybucji emacsa (i przynajmniej w emacs21-common lub emacs22-common na Ubuntu i Debianie).

matli
źródło
2
Wypełnianie kart jest jeszcze gorsze w przypadku M-x term.
mcandre,
7

Proszę, rozważ inny tryb M-x term, tak jak zrobiłem to, gdy napotkałem problem w 2011. Próbowałem zebrać wszystkie wysiłki w tym czasie na Inet, aby powłoka działała z uzupełnianiem Bash, w tym to pytanie. Ale odkąd w obliczu term-modeznalazłem alternatywę, nawet nie chcę próbować eshell.

Jest to pełny emulator terminala, więc możesz w nim uruchomić interaktywny program, taki jak Midnight Commander. Lub przejdź do zshzakończenia, aby nie tracić czasu na konfigurację Emacsa.

Uzupełnianie TAB w bash jest bezpłatne. Ale ważniejsze jest, aby uzyskać pełną moc Readline, taką jak wyszukiwanie poleceń przyrostowych lub z prefiksem . Aby uczynić tę konfigurację wygodniejszą, sprawdź moje .inputrc , .bashrc , .emacs .

Istotna część .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(TAK! W Bash jest dabbrev z dowolnego słowa w ~/.bash_history):

set -o emacs

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

.emacs aby nawigacja była wygodna w buforze terminowym:

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

Jak wszystkie zwykłe polecenia, C-x októre nie działają w trybie emulacji terminala, rozszerzyłem mapę klawiszy 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)

Zauważ, że używam superklawisza, więc term-raw-mapprawdopodobnie żadna inna mapa klawiszy nie koliduje z moimi przypisaniami klawiszy. Aby zrobić superklucz z lewego Winklawisza, używam .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

Powinieneś tylko pamiętać o 2 poleceniach: C-c C-j- aby wejść do normalnego trybu edycji Emacsa (do kopiowania lub grepowania w tekście bufora), C-c C-k- aby powrócić do trybu emulacji terminala.

Wybór myszy i Shift-Insertpraca jak w xterm.

gavenkoa
źródło
1
Dziękuję, to jest złoto! zwłaszcza .inputrcczęść!
cmantas
6

Jak powiedział Matli, nie jest to łatwe zadanie, ponieważ bash rozpoczyna się od --noediting, a TAB jest powiązany z comint-dynamic-complete.

Można by przypuszczalnie ponownie powiązać TAB z self-insert-command w shell-comand-hook z lokalnym-set-key i sprawić, by tryb powłoki nie zaczynał się od --noediting przez Mx zmienna dostosowywania RET jawne-bash-args, ale podejrzewam, że nie będzie pasować do wszystkich innych edycji.

Możesz chcieć wypróbować tryb terminowy, ale wiąże się to z innym zestawem problemów, ponieważ niektóre inne zwykłe przypisania klawiszy są zastępowane przez tryb terminowy.

EDYCJA: Przez inne regularne klucze są przejmowane przez tryb terminowy, mam na myśli wszystko oprócz Cc, które staje się ucieczką, aby móc przełączać bufory. Więc zamiast Cx k, aby zabić bufor, musiałbyś Cc Cx k. Lub przełączenie do innego bufora „Cc Cx o” lub „Cc Cx 2”

njsf
źródło
nie jest to samo polecenie wstawiania: wstawia znak TAB zamiast przekazywania klawisza TAB do Bash.
Chris Conway,
Nie mam polecenia trybu terminowego i nie mogę dowiedzieć się, skąd je wziąć.
Chris Conway,
2

Wiem, że ten post ma już ponad 11 lat. Ale stworzyłem funkcję, która daje natywne uzupełnianie powłoki w Emacsie. Po prostu wysyła klucz tabulacji do podstawowego procesu i przechwytuje dane wyjściowe, więc jest dokładnie taki sam, jak w samej powłoce.

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

Prgrm.celeritas
źródło
Łał! Niesamowity ! (Pierwsze wrażenie na podstawie podglądu.)
Matthew Elvey
1

Używam Prelude i kiedy naciskam Meta + Tab, kończy się za mnie.

Wydaje się, że Ctrl + i robi to samo.

duma
źródło
0

Używam trybu steru. Ma taką funkcjonalność (po wciśnięciu "TAB"): wprowadź opis obrazu tutaj

a_subscriber
źródło
-2

Nie twierdzę, że jestem ekspertem od emacsa, ale to powinno rozwiązać twój problem:

Utwórz: ~ / .emacs

Dodaj do tego:

(wymaga 'polecenia-powłoki) (tryb-uzupełniania-polecenia-powłoki)

Emacs przejmuje powłokę, więc ustawienia BASH nie są przenoszone. Spowoduje to ustawienie automatycznego uzupełniania dla samego EMACS.

Scott Alan Miller
źródło
Nie, to nie rozwiązuje problemu. Działa tylko z poleceniem powłoki, a nie w trybie powłoki. Poza tym nie włącza inteligentnego uzupełniania żądanego w pytaniu (będzie wypełniać tylko polecenia i nazwy plików).
matli
1
tryb-uzupełniania-polecenia-powłoki wykonuje uzupełnianie nazw plików i jest domyślnie włączony. Chcę funkcji uzupełniania Bash (którą można rozszerzyć, aby zawierała np. Komendy podrzędne dla apt-get i svn).
Chris Conway