index all rss twitter github linkedin email

Álvaro Ramírez

01 November 2017 Eshell pcomplete company completion

Howard Abrams's Introduction to eshell video prompted me to poke at eshell some more. This time, I got eshell context aware completion by glueing the excellent company and pcomplete packages.

company-pcomplete.png

(require 'cl-lib)
(require 'company)
(require 'dash)
(require 'pcomplete)
(require 's)

(defun company-pcomplete--overlap-tail (a b)
  "When A is \"SomeDev\" and B is \"Developer\\n", return \"eloper\"."
  (let ((prefix a)
        (remaining nil))
    (while (and (not remaining) (> (length prefix) 0))
      (when (s-starts-with? prefix b)
        (setq remaining (substring b (length prefix))))
      (setq prefix (substring prefix 1)))
    remaining))

(defun company-pcomplete--candidates (prefix)
  "Get candidates for PREFIX company completion using `pcomplete'."
  ;; When prefix is: "~/Down" and completion is "Downloads\n", need
  ;; to find common string and join into "~/Downloads/".
  (-map (lambda (item)
          (if (s-starts-with? prefix item)
              item
            (concat prefix (company-pcomplete--overlap-tail prefix item))))
        (all-completions prefix (pcomplete-completions))))

(defun company-pcomplete (command &optional arg &rest ignored)
  "Complete using pcomplete. See `company''s COMMAND ARG and IGNORED for details."
  (interactive (list 'interactive))
  (case command
    (interactive (company-begin-backend 'company-pcomplete))
    (prefix (company-grab-symbol))
    (candidates
     (company-pcomplete--candidates arg))))

Don't forget to add company-pcomplete to company-backends, and if you want an explicit binding, use something like:

(bind-key "<backtab>" #'company-complete eshell-mode-map)