SiteMap Search ElispArea HowTo Glossary RecentChanges News Problems Suggestions
Jordan, Independence Day, Argentina, National Day

EshellCompletion

Customization

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

Remote Files

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

Miscellaneous

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

This happens because you haven’t modified eshell-prompt-regexp accordingly (see the documentation for eshell-prompt-function). This should work:
 (setq eshell-prompt-regexp "^[^#$\n]*[#$] ")
See EshellFunctions for more examples. – MattHodges

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

I use:
 (setq eshell-cmpl-cycle-completions nil)
to avoid completion cycling. – MattHodges

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:

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

CategoryEshell