Last edit
Summary: Add example for auto-completion in eshell
Added:
> == AutoComplete ==
> I use the amazing AutoComplete package for completion. Eshell provides
> completion through the ProgrammableCompletion package. I did not found
> a suitable auto-complete source for pcomplete, so I use the following
> code:
> <pre>
> (defun ac-pcomplete ()
> ;; eshell uses `insert-and-inherit' to insert a \t if no completion
> ;; can be found, but this must not happen as auto-complete source
> (flet ((insert-and-inherit (&rest args)))
> ;; this code is stolen from `pcomplete' in pcomplete.el
> (let* (tramp-mode ;; do not automatically complete remote stuff
> (pcomplete-stub)
> (pcomplete-show-list t) ;; inhibit patterns like * being deleted
> pcomplete-seen pcomplete-norm-func
> pcomplete-args pcomplete-last pcomplete-index
> (pcomplete-autolist pcomplete-autolist)
> (pcomplete-suffix-list pcomplete-suffix-list)
> (candidates (pcomplete-completions))
> (beg (pcomplete-begin))
> ;; note, buffer text and completion argument may be
> ;; different because the buffer text may bet transformed
> ;; before being completed (e.g. variables like $HOME may be
> ;; expanded)
> (buftext (buffer-substring beg (point)))
> (arg (nth pcomplete-index pcomplete-args)))
> ;; we auto-complete only if the stub is non-empty and matches
> ;; the end of the buffer text
> (when (and (not (zerop (length pcomplete-stub)))
> (or (string= pcomplete-stub ; Emacs 23
> (substring buftext
> (max 0
> (- (length buftext)
> (length pcomplete-stub)))))
> (string= pcomplete-stub ; Emacs 24
> (substring arg
> (max 0
> (- (length arg)
> (length pcomplete-stub)))))))
> ;; Collect all possible completions for the stub. Note that
> ;; `candidates` may be a function, that's why we use
> ;; `all-completions`.
> (let* ((cnds (all-completions pcomplete-stub candidates))
> (bnds (completion-boundaries pcomplete-stub
> candidates
> nil
> ""))
> (skip (- (length pcomplete-stub) (car bnds))))
> ;; We replace the stub at the beginning of each candidate by
> ;; the real buffer content.
> (mapcar #'(lambda (cand) (concat buftext (substring cand skip)))
> cnds))))))
> (defvar ac-source-pcomplete
> '((candidates . ac-pcomplete)))
> (add-hook 'eshell-mode-hook #'(lambda () (setq ac-sources '(ac-source-pcomplete)))
> (add-to-list 'ac-modes 'eshell-mode)
> </pre>
Eshell offers you completion of filenames. If several filenames are possible, the most recently modified file will be used first.
This is determined by ‘eshell-cmpl-compare-entry-function’ and defaults to ‘file-newer-than-file-p’. The idea is that once you start working with a certain file, you will want it to appear first in your completion list.
Here’s some untested code to reverse this order, and to take ‘completion-ignored-extensions’ into account.
(setq eshell-cmpl-compare-entry-function
(function
(lambda (left right)
(let ((exts completion-ignored-extensions) found)
(while exts
(if (string-match (concat "\\" (car exts) "$") right)
(setq found t exts nil))
(setq exts (cdr exts)))
(if found
nil
(file-newer-than-file-p left right))))))Contributors: KaiGrossjohann, JohnWiegley
If I want to change directory to /scratch, then pressing TAB after typing “cd /sc” leads to TrampMode trying to open a connection. This is because the tramp-completion-file-name-handler entry in file-name-handler-alist leads to:
(file-name-all-completions "sc" "/") =>
("scpx:" "scp2_old:" "scp1_old:" "scp2:" "scp1:" "scp:" "scratch/")and pcomplete tries to run file-directory-p on all these entries.
One way to avoid this is to use the following:
(defadvice pcomplete (around avoid-remote-connections activate)
(let ((file-name-handler-alist (copy-alist file-name-handler-alist)))
(setq file-name-handler-alist
(delete (rassoc 'tramp-completion-file-name-handler
file-name-handler-alist) file-name-handler-alist))
ad-do-it))Note that completion of “cd su::” still works because this is handled by tramp-file-name-handler.
Perhaps there are better ways of doing this? – Matt Hodges
If I set my own prompt, like this:
(setq eshell-prompt-function
(lambda ()
(concat "[" (user-login-name) "@" (system-name) " " (eshell/pwd) "]"
(if (= (user-uid) 0) "# " "$ "))))completion stops working. When I press tab, I get the message “Text is read-only”. Can anyone explain this? – bkhl
(setq eshell-prompt-regexp "^[^#$\n]*[#$] ")
Ok, thanks. I like pcomplete-list better than the completion cycling. I tried this:
(add-hook 'eshell-mode-hook
'(lambda () (define-key eshell-mode-map "\t" 'pcomplete-list)))but it doesn’t work. How should this be done properly? – bkhl
(setq eshell-cmpl-cycle-completions nil)
I use the amazing AutoComplete package for completion. Eshell provides completion through the ProgrammableCompletion package. I did not found a suitable auto-complete source for pcomplete, so I use the following code:
(defun ac-pcomplete ()
;; eshell uses `insert-and-inherit' to insert a \t if no completion
;; can be found, but this must not happen as auto-complete source
(flet ((insert-and-inherit (&rest args)))
;; this code is stolen from `pcomplete' in pcomplete.el
(let* (tramp-mode ;; do not automatically complete remote stuff
(pcomplete-stub)
(pcomplete-show-list t) ;; inhibit patterns like * being deleted
pcomplete-seen pcomplete-norm-func
pcomplete-args pcomplete-last pcomplete-index
(pcomplete-autolist pcomplete-autolist)
(pcomplete-suffix-list pcomplete-suffix-list)
(candidates (pcomplete-completions))
(beg (pcomplete-begin))
;; note, buffer text and completion argument may be
;; different because the buffer text may bet transformed
;; before being completed (e.g. variables like $HOME may be
;; expanded)
(buftext (buffer-substring beg (point)))
(arg (nth pcomplete-index pcomplete-args)))
;; we auto-complete only if the stub is non-empty and matches
;; the end of the buffer text
(when (and (not (zerop (length pcomplete-stub)))
(or (string= pcomplete-stub ; Emacs 23
(substring buftext
(max 0
(- (length buftext)
(length pcomplete-stub)))))
(string= pcomplete-stub ; Emacs 24
(substring arg
(max 0
(- (length arg)
(length pcomplete-stub)))))))
;; Collect all possible completions for the stub. Note that
;; `candidates` may be a function, that's why we use
;; `all-completions`.
(let* ((cnds (all-completions pcomplete-stub candidates))
(bnds (completion-boundaries pcomplete-stub
candidates
nil
""))
(skip (- (length pcomplete-stub) (car bnds))))
;; We replace the stub at the beginning of each candidate by
;; the real buffer content.
(mapcar #'(lambda (cand) (concat buftext (substring cand skip)))
cnds))))))
(defvar ac-source-pcomplete
'((candidates . ac-pcomplete)))
(add-hook 'eshell-mode-hook #'(lambda () (setq ac-sources '(ac-source-pcomplete)))
(add-to-list 'ac-modes 'eshell-mode)