Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
187 lines (169 sloc) 7.29 KB
;;; helm-eshell.el --- pcomplete and eshell completion for helm.
;; Copyright (C) 2012 Thierry Volpiatto <>
;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <>.
;; Enable like this in .emacs:
;; (add-hook 'eshell-mode-hook
;; #'(lambda ()
;; (define-key eshell-mode-map [remap pcomplete] 'helm-esh-pcomplete)))
;;; Code:
(eval-when-compile (require 'cl))
(require 'helm)
(require 'helm-elisp)
(require 'helm-regexp)
(declare-function eshell-read-aliases-list "em-alias")
(declare-function eshell-send-input "esh-mode" (&optional use-region queue-p no-newline))
(declare-function eshell-bol "esh-mode")
(defvar helm-eshell-history-map
(let ((map (make-sparse-keymap)))
(set-keymap-parent map helm-map)
(define-key map (kbd "M-p") 'helm-next-line)
"Keymap for `helm-eshell-history'.")
(defvar helm-c-source-esh
'((name . "Eshell completions")
(init . (lambda ()
(setq pcomplete-current-completions nil
pcomplete-last-completion-raw nil)
;; Eshell-command add this hook in all minibuffers
;; Remove it for the helm one. (Fixed in Emacs24)
(remove-hook 'minibuffer-setup-hook 'eshell-mode)))
(candidates . helm-esh-get-candidates)
(lambda (candidates _sources)
(loop for i in candidates collect
(cons (abbreviate-file-name i) i))))
(action . helm-ec-insert))
"Helm source for Eshell completion.")
;; Internal.
(defvar helm-ec-target "")
(defun helm-ec-insert (candidate)
"Replace text at point with CANDIDATE.
The function that call this should set `helm-ec-target' to thing at point."
(let ((pt (point)))
(when (and helm-ec-target
(search-backward helm-ec-target nil t)
(string= (buffer-substring (point) pt) helm-ec-target))
(delete-region (point) pt)))
(if (string-match "\\`~/" helm-ec-target)
(insert (helm-quote-whitespace (abbreviate-file-name candidate)))
(insert (helm-quote-whitespace candidate))))
(defun helm-esh-get-candidates ()
"Get candidates for eshell completion using `pcomplete'."
(catch 'pcompleted
(let* ((pcomplete-stub)
pcomplete-seen pcomplete-norm-func
pcomplete-args pcomplete-last pcomplete-index
(pcomplete-autolist pcomplete-autolist)
(pcomplete-suffix-list pcomplete-suffix-list))
(loop with table = (pcomplete-completions)
with entry = (condition-case nil
;; On Emacs24 `try-completion' return
;; pattern when more than one result.
;; Otherwise Emacs23 return nil, which
;; is wrong, in this case use pattern
;; to behave like Emacs24.
(or (try-completion helm-pattern
;; In Emacs23 `pcomplete-entries' may fail
;; with error, so try this instead.
(let ((fc (car (last
;; Check if last arg require fname completion.
(and (file-name-directory fc) fc))))
for i in (all-completions pcomplete-stub table)
for file-cand = (and entry
(if (file-remote-p i) i
i (file-name-directory entry))))
if (and file-cand (or (file-remote-p file-cand)
(file-exists-p file-cand)))
collect file-cand into ls
else collect i into ls
finally return
(if (and entry (not (string= entry "")) (file-exists-p entry))
(append (list (expand-file-name entry default-directory)) ls)
;;; Eshell history.
(defvar helm-c-source-eshell-history
`((name . "Eshell history")
(init . (lambda ()
(let (eshell-hist-ignoredups)
;; Write the content's of ring to file.
(eshell-write-history eshell-history-file-name t)
(with-current-buffer (helm-candidate-buffer 'global)
(insert-file-contents eshell-history-file-name)))
;; Same comment as in `helm-c-source-esh'
(remove-hook 'minibuffer-setup-hook 'eshell-mode)))
(keymap . ,helm-eshell-history-map)
(filtered-candidate-transformer . (lambda (candidates sources)
(reverse candidates)))
(candidate-number-limit . 9999)
(action . (lambda (candidate)
(insert candidate))))
"Helm source for Eshell history.")
(defun helm-esh-pcomplete ()
"Preconfigured helm to provide helm completion in eshell."
(let* ((helm-quit-if-no-candidate t)
(helm-execute-action-at-once-if-one t)
(target (thing-at-point 'symbol))
(end (point))
(beg (or (and target (- end (length target)))
;; Nothing at point.
(progn (insert " ") (point)))))
(setq helm-ec-target (or target " "))
(with-helm-show-completion beg end
(helm :sources 'helm-c-source-esh
:buffer "*helm pcomplete*"
:resume 'noresume
:input (helm-ff-set-pattern ; Handle tramp filenames.
(car (last (ignore-errors ; Needed in lisp symbols completion.
(defun helm-eshell-history ()
"Preconfigured helm for eshell history."
(let* ((end (point))
(beg (save-excursion (eshell-bol) (point)))
(input (buffer-substring beg end))
(when (eq beg end)
(insert " ")
(setq flag-empty t)
(setq end (point)))
(with-helm-show-completion beg end
(helm :sources 'helm-c-source-eshell-history
:buffer "*Eshell history*"
:resume 'noresume
:input input))
(when (and flag-empty
(looking-back " "))
(delete-char -1)))))
(provide 'helm-eshell)
;; Local Variables:
;; coding: utf-8
;; indent-tabs-mode: nil
;; byte-compile-dynamic: t
;; End:
;;; helm-eshell ends here
Something went wrong with that request. Please try again.