Bash autocompletion in Emacs shell-mode

后端 未结 9 1405
有刺的猬
有刺的猬 2020-12-04 08:14

In the GNOME Terminal, Bash does smart auto-completion. For example

apt-get in

becomes

apt-get install


        
相关标签:
9条回答
  • 2020-12-04 09:11

    Please, consider another mode M-x term, like I did this when hit problem in 2011. I tried to gather all efforts over Inet at that time to make shell work with Bash completion, including this question. But since discovering alternative in face of term-mode I don't even want to try eshell.

    It is full terminal emulator, so you can run interactive program inside, like Midnight commander. Or switch to zsh completion so you won't lose time on Emacs configuration.

    You get TAB completion in bash for free. But more important you get full Readline power, like incremental or prefixed command search. To make this setup more convenient check my .inputrc, .bashrc, .emacs.

    Essential part of .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! There is dabbrev in Bash from any word in ~/.bash_history):

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

    .emacs to make navigation comfortable in term buffer:

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

    As any usual commands as C-x o aren't working in terminal emulation mode I extended keymap with:

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

    Note that I use super key so term-raw-map and possibly any other keymap don't conflict with my key bindings. To make super key from left Win key I use .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
    

    You just should remember 2 commands: C-c C-j - to enter to normal Emacs editing mode (for copying or grepping in buffer text), C-c C-k - to return to terminal emulation mode.

    Mouse selection and Shift-Insert work as in xterm.

    0 讨论(0)
  • 2020-12-04 09:11

    I know this post is over 11 years old now. But I have created a function to give native shell completion in Emacs. It just sends a tab key to the underlying process and intercepts the output, so it is the exact same as you would get in the shell itself.

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

    0 讨论(0)
  • 2020-12-04 09:12

    I make no claims to being an emacs expert but this should solve your problem:

    Create: ~/.emacs

    Add to it:

    (require 'shell-command) (shell-command-completion-mode)

    Emacs takes over the shell so BASH settings don't carry through. This will set auto completion for EMACS itself.

    0 讨论(0)
提交回复
热议问题