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