Автозавершення Bash в режимі оболонки Emacs


93

У терміналі GNOME Bash виконує розумне автоматичне заповнення. Наприклад

apt-get in<TAB>

стає

apt-get install

У режимі оболонки Emacs це автозаповнення не працює, навіть після явного я джерела /etc/bash_completion. Наведений вище приклад дотримується як inабо автоматично заповнює ім'я файлу в поточному каталозі, а не дійсний apt-getпараметр команди. Імовірно, це тому, що Emacs перехоплює натискання клавіші Tab. Як увімкнути розумне автозаповнення в shell-mode?


Для тих, хто новачок у emacs ... у emacs існують інші режими оболонки . Такі, eshell-modeякі мають заповнення вкладки. Більше інформації тут: masteringemacs.org/articles/2010/11/01/…
Росс,

3
Автозаповнення eshell працює лише для локальних каталогів, якщо ви перейдете на іншу машину, ви раптом втратите цю здатність.
хаджовонта

Відповіді:


92

Я знаю, що цьому питанню три роки, але це те, що мені також було цікаво вирішити. Веб-пошук спрямував мене на шматок elisp, який змушує Emacs використовувати bash для завершення в режимі оболонки. У мене це працює в будь-якому випадку.

Перевірте це на https://github.com/szermatt/emacs-bash-completion .


6
+1 за сміливість відповісти на трирічне, але все ще доречне запитання. Дякую!
djhaskin987

3
Це вже в melpa melpa.org/#/bash-completion , установка використовується просто M-x package-list-packages, але врешті-решт це не спрацювало для мене, не знаю чому, це може бути мій emacs (24.3.1) або версія bash (4.3.30). У документації сказано: "bash-complete.el досить чутливий до версії ОС та BASH ...", тоді є список, де мої версії відсутні.
boclodoa

На жаль, до випуску № 6 це здається не настільки корисним для поточної культури інструментів CLI.
Jesse Glick

21

У оболонці emacs насправді emacs виконує автозавершення, а не bash. Якщо оболонка та emacs не синхронізовані (наприклад, за допомогою pushd, popd або якоїсь функції користувача bash, яка змінює поточний каталог оболонки), то автозавершення перестає працювати.

Щоб це виправити, просто введіть у оболонку "dirs", і все буде синхронізовано.

У моєму .emacs також є таке:

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

Потім просто натиснувши клавішу Esc-return, повторно синхронізує автозавершення.


9
Це гарна відповідь на інше питання!
Кріс Конвей

Дякую. Я використовую автоперехід, і саме в цьому була проблема, чому папки не синхронізувались.
Plankalkül

Кріс Конвей, так, до цього: emacs.stackexchange.com/questions/30550/… :-)
unhammer

15

Я не знаю відповіді на це. Але причина в тому, що він не працює так, як ви очікуєте, можливо, тому, що завершення в оболонках emacs обробляється emacs внутрішньо (функцією comint-dynamic-complete) і не має вбудованих функцій розумного завершення.

Боюсь, це виправити непросто.

Редагувати: пропозиція njsf використовувати термін-режим, напевно, настільки хороша, наскільки це можливо. Почніть з

Mx термін
Він включений до стандартного розподілу emacs (і принаймні до emacs21-common або emacs22-common на Ubuntu та Debian).


2
Завершення вкладки ще гірше з M-x term.
mcandre

6

Як сказав Матлі, це непросте завдання, оскільки bash розпочинається з --noediting, а TAB - до comint-dynamic-complete.

Можливо, можна перев’язати TAB до самовставки-команди в оболонці comand-hook за допомогою local-set-key і зробити так, щоб режим оболонки не починався з --noediting за допомогою Mx customize-variable RET eksplicit-bash-args, але я підозрюю, що це не буде добре поєднуватися з усіма іншими редагуваннями.

Можливо, ви захочете спробувати терміновий режим, але у нього є інший набір проблем, оскільки деякі інші звичайні прив'язки клавіш випереджаються терміновим режимом.

РЕДАГУВАТИ: Під іншими регулярними заборонами клавіш, які витісняються терміновим режимом, я маю на увазі все, крім Cc, що стає втечею, щоб мати можливість перемикати буфери. Отже, замість Cx k, щоб убити буфер, вам доведеться Cc Cx k. Або перейти на інший буфер 'Cc Cx o' або 'Cc Cx 2'


self-insert-command - це не так: він вставляє символ TAB, а не передає клавішу TAB і натискає на Bash.
Кріс Конвей

У мене немає команди термінового режиму, і я не можу зрозуміти, де її взяти.
Кріс Конвей

6

Будь ласка, розгляньте інший режим M-x term, як я це зробив, коли потрапила проблема в 2011 році. Я намагався зібрати всі зусилля над Inet на той час, щоб змусити працювати оболонку із завершенням Bash, включаючи це питання. Але з моменту відкриття альтернативи term-modeя навіть не хочу намагатися eshell.

Це повноцінний емулятор терміналу, тому ви можете запускати інтерактивну програму всередині, як Midnight Commander. Або перейдіть до zshзавершення, щоб не втратити час на конфігурацію Emacs.

Ви отримуєте заповнення TAB в bash безкоштовно. Але що важливіше, ви отримуєте повну потужність Readline, наприклад, додатковий або префіксний пошук команд . Щоб зробити це налаштування зручнішим, перевірте мої .inputrc , .bashrc , .emacs .

Основна частина .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(ТАК! У Bash є даббрев від будь-якого слова в ~/.bash_history):

set -o emacs

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

.emacs щоб зробити навігацію комфортною в терміновому буфері:

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

Як і будь-які звичайні команди, C-x 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)

Зверніть увагу, що я використовую superключ, term-raw-mapі, можливо, будь-яка інша карта ключів не суперечить моїм прив'язкам ключів. Щоб зробити superключ з лівої Winклавіші, я використовую .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

Вам просто слід запам’ятати 2 команди: C-c C-j- перейти до звичайного режиму редагування Emacs (для копіювання або копіювання тексту буфера), C-c C-k- повернутися до режиму емуляції терміналу.

Вибір миші та Shift-Insertробота як у xterm.


1
Дякую, це золото! особливо .inputrcчастина!
cmantas

1

Я використовую Prelude, і коли я натискаю Meta + Tab, він завершується для мене.

Крім того, Ctrl + i, схоже, робить те саме.


1

Я знаю, що цій посаді вже понад 11 років. Але я створив функцію, яка надає рідну оболонку завершення в Emacs. Він просто надсилає ключ вкладки до основного процесу і перехоплює вихідні дані, тому він точно такий же, як і в самій оболонці.

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


0

Я використовую режим керма. Він має таку функціональність (після натискання "TAB"): введіть тут опис зображення


-2

Я не претендую на те, щоб бути експертом emacs, але це має вирішити вашу проблему:

Створити: ~ / .emacs

Додайте до нього:

(потрібно 'оболонка-команда) (режим оболонки-команда-завершення)

Emacs бере на себе оболонку, тому налаштування BASH не виконуються. Це встановить автоматичне заповнення для самого EMACS.


Ні, це не вирішує проблему. Він працює лише з командою оболонки, а не в режимі оболонки. І крім того, він не включає розумне завершення, про яке запитувалось у питанні (воно буде виконувати лише команди та імена файлів).
matli

1
режим оболонки-команди-завершення виконує завершення імені файлу і вмикається за замовчуванням. Я хочу, щоб функція завершення Bash (яку можна розширити, включаючи, наприклад, підкоманди для apt-get та svn).
Кріс Конвей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.