Bash tự động hoàn thành trong chế độ shell của Emacs


93

Trong GNOME Terminal, Bash tự động hoàn thành thông minh. Ví dụ

apt-get in<TAB>

trở thành

apt-get install

Trong chế độ shell của Emacs, tính năng tự động hoàn thành này không hoạt động, ngay cả sau khi tôi ghi rõ nguồn /etc/bash_completion. Ví dụ trên gắn với inhoặc tự động hoàn thành với một tên tệp trong thư mục hiện tại chứ không phải là một apt-gettùy chọn lệnh hợp lệ . Có lẽ, điều này là do Emacs đang chặn phím Tab. Làm cách nào để bật tính năng tự động hoàn thành thông minh trong shell-mode?


Đối với bất kỳ ai mới sử dụng emacs ... có các chế độ shell khác trong emacs. Chẳng hạn như eshell-modeđã hoàn thành tab. Xem thêm thông tin ở đây: masteringemacs.org/articles/2010/11/01/...
Ross

3
Tính năng tự động hoàn thành của eshell chỉ hoạt động đối với các thư mục cục bộ, nếu bạn ssh sang máy khác, bạn đột nhiên mất khả năng này.
hajovonta

Câu trả lời:


92

Tôi biết câu hỏi này đã có từ ba năm trước, nhưng đó là điều mà tôi cũng muốn giải quyết. Một tìm kiếm trên Web đã hướng tôi đến một đoạn elisp khiến Emacs sử dụng bash để hoàn thành ở chế độ shell. Nó hoạt động cho tôi, trong mọi trường hợp.

Hãy xem tại https://github.com/szermatt/emacs-bash-completion .


6
+1 vì có can đảm trả lời câu hỏi của đứa trẻ ba tuổi nhưng vẫn hoàn toàn phù hợp. Cảm ơn!
djhaskin987

3
Cái này đã có trong melpa melpa.org/#/bash-completion , cài đặt dễ dàng sử dụng M-x package-list-packages, nhưng cuối cùng nó không hoạt động với tôi, tôi không biết tại sao, nó có thể là emac của tôi (24.3.1) hoặc phiên bản bash (4.3.30). Tài liệu cho biết "bash-complete.el khá nhạy cảm với phiên bản OS và BASH ..." sau đó là danh sách mà các phiên bản của tôi vắng mặt.
boclodoa

Rất tiếc, vấn đề # 6 đang chờ xử lý, điều này có vẻ không hữu ích cho các công cụ CLI hiện tại.
Jesse Glick vào

21

Trong emacs shell, nó thực sự là emacs thực hiện tự động hoàn thành, không phải bash. Nếu shell và emac không đồng bộ (ví dụ: bằng cách sử dụng pushd, popd hoặc một số hàm người dùng bash thay đổi thư mục hiện tại của shell), thì tính năng tự động hoàn thành sẽ ngừng hoạt động.

Để khắc phục điều này, chỉ cần nhập 'dirs' vào shell và mọi thứ sẽ trở lại đồng bộ.

Tôi cũng có những thứ sau trong .emac của mình:

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

Sau đó, chỉ cần nhấn Esc-return đồng bộ hóa lại quá trình tự động hoàn thành.


9
Đây là một câu trả lời hay cho một câu hỏi khác!
Chris Conway

Cảm ơn. Tôi sử dụng autojump và đó là vấn đề tại sao dirs không đồng bộ.
Plankalkül

Chris Conway, vâng, với cái này: emacs.stackexchange.com/questions/30550/… :-)
bất hạnh

15

Tôi không biết câu trả lời cho điều này. Nhưng lý do mà nó không hoạt động như bạn mong đợi có thể là do việc hoàn thành trong trình bao emacs được xử lý bởi emac bên trong (bởi chức năng comint-dynamic-complete) và không được tích hợp sẵn các chức năng hoàn thành thông minh đó.

Tôi e rằng nó không phải là một điều dễ dàng để sửa chữa.

Chỉnh sửa: đề xuất của njsf về việc sử dụng chế độ kỳ hạn có lẽ tốt như nó được. Bắt đầu nó với

Mx hạn
Nó được bao gồm trong bản phân phối emacs tiêu chuẩn (và ít nhất là trong emacs21-common hoặc emacs22-common trên Ubuntu và Debian).


2
Việc hoàn thành tab thậm chí còn tệ hơn với M-x term.
mcandre

6

Giống như Matli đã nói, đây không phải là một nhiệm vụ dễ dàng, vì bash được bắt đầu với --noediting và TAB bị ràng buộc với comint-dynamic-complete.

Người ta có thể liên kết lại TAB để tự chèn lệnh trong shell-comand-hook với local-set-key và làm cho chế độ shell không bắt đầu với - được chú ý bởi Mx tùy biến RET explicit-bash-args, nhưng tôi nghi ngờ rằng nó sẽ không phù hợp với tất cả các chỉnh sửa khác.

Bạn có thể muốn thử chế độ kỳ hạn, nhưng nó có một loạt vấn đề khác, vì một số liên kết khóa thông thường khác đã bị chế độ kỳ hạn vượt qua.

CHỈNH SỬA: Bởi các thao tác gõ phím thông thường khác đang bị chế độ kỳ hạn vượt qua, ý tôi là tất cả trừ Cc trở thành lối thoát để có thể chuyển đổi bộ đệm. Vì vậy, thay vì Cx k để giết bộ đệm, bạn phải Cc Cx k. Hoặc để chuyển sang bộ đệm khác 'Cc Cx o' hoặc 'Cc Cx 2'


self-insert-command phải không: nó chèn ký tự TAB thay vì chuyển phím nhấn TAB tới Bash.
Chris Conway

Tôi không có lệnh chế độ kỳ hạn và tôi không thể tìm ra nơi để lấy nó.
Chris Conway

6

Vui lòng xem xét một chế độ khác M-x term, như tôi đã làm điều này khi gặp sự cố vào năm 2011. Tôi đã cố gắng tập hợp mọi nỗ lực trên Inet vào thời điểm đó để làm cho shell hoạt động với việc hoàn thành Bash, bao gồm cả câu hỏi này. Nhưng kể từ khi phát hiện ra sự thay thế khi đối mặt với term-modetôi, tôi thậm chí không muốn thử eshell.

Nó là trình giả lập thiết bị đầu cuối đầy đủ, vì vậy bạn có thể chạy chương trình tương tác bên trong, như chỉ huy lúc nửa đêm. Hoặc chuyển sang zshhoàn thành để bạn không mất thời gian cấu hình Emacs.

Bạn nhận được hoàn thành TAB trong bash miễn phí. Nhưng điều quan trọng hơn là bạn nhận được toàn bộ sức mạnh của Readline, như tìm kiếm lệnh tăng dần hoặc có tiền tố . Để thiết lập này thuận tiện hơn, hãy kiểm tra .inputrc , .bashrc , .emacs của tôi .

Phần thiết yếu của .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! Có dabbrev trong Bash từ bất kỳ từ nào trong ~/.bash_history):

set -o emacs

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

.emacs để làm cho điều hướng thoải mái trong bộ đệm thuật ngữ:

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

Như bất kỳ lệnh thông thường C-x onào không hoạt động trong chế độ mô phỏng đầu cuối, tôi đã mở rộng sơ đồ bàn phím với:

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

Lưu ý rằng tôi sử dụng superphím như vậy term-raw-mapvà có thể bất kỳ sơ đồ bàn phím nào khác không xung đột với các ràng buộc khóa của tôi. Để tạo superchìa khóa từ Winphím bên trái, tôi sử dụng .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

Bạn chỉ nên nhớ 2 lệnh: C-c C-j- để vào chế độ chỉnh sửa Emacs bình thường (để sao chép hoặc ghi xám trong văn bản đệm), C-c C-k- để quay lại chế độ mô phỏng đầu cuối.

Chọn chuột và Shift-Inserthoạt động như trong xterm.


1
Cảm ơn bạn, đây là vàng! đặc biệt là .inputrcphần!
cmantas

1

Tôi sử dụng Prelude và khi tôi nhấn Meta + Tab, nó sẽ hoàn tất cho tôi.

Ngoài ra, Ctrl + i dường như cũng làm điều tương tự.



0

Tôi sử dụng chế độ lái. Nó có chức năng này (sau khi nhấn "TAB"): nhập mô tả hình ảnh ở đây


-2

Tôi không tuyên bố mình là chuyên gia emacs nhưng điều này sẽ giải quyết được vấn đề của bạn:

Tạo: ~ / .emacs

Thêm vào đó:

(request 'shell-command) (shell-command-complete-mode)

Emacs tiếp quản shell để cài đặt BASH không thực hiện được. Điều này sẽ đặt tự động hoàn thành cho chính EMACS.


Không, điều này không giải quyết được vấn đề. Nó chỉ hoạt động trên lệnh shell, không hoạt động ở chế độ shell. Và bên cạnh đó, nó không cho phép hoàn thành thông minh được yêu cầu trong câu hỏi (nó sẽ chỉ hoàn thành các lệnh và tên tệp).
matli

1
shell-command-complete-mode không hoàn thành tên tệp và được bật theo mặc định. Tôi muốn tính năng hoàn thành của Bash (có thể mở rộng để bao gồm, ví dụ: các lệnh con cho apt-get và svn).
Chris Conway
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.