16

I'm very fond of ivy for completion and love that a simple (ivy-mode 1) is enough to get ivy almost everywhere that Emacs uses some sort of completion (that is acomplished by overriding completeing-read, I believe). But this doesn't setup eshell to use ivy for tab completion. I do like eshell's list of completion candidates, but would prefer the ivy UI to pick among them. Is there some way to reuse whatever eshell does to produce completion candidates and hand that off to `ivy'?

2 Answers 2

12

This should work fine:

(define-key eshell-mode-map (kbd "<tab>") 'completion-at-point)

I don't know why the above isn't the default. But I use only shell-mode and term-mode anyway.

2
  • 3
    You should probably add that (add-hook 'eshell-mode-hook '(lambda () needs to be wrapped around it.
    – Timm
    Oct 20, 2016 at 18:04
  • Thanks, that's a little neater than what I had. The reason it's not the default is probably just that someone at some point in the past prefered pcomplete over the standard completion UI.
    – Omar
    Oct 20, 2016 at 22:07
6

I found something that seems to work OK upon initial testing: essentially rebind <tab> to pcomplete-std-complete, but since that function isn't interactive for some reason, you need to wrap it:

(define-key eshell-mode-map (kbd "<tab>")
  (lambda () (interactive) (pcomplete-std-complete)))

The pcompete-std-complete tries to use the completions written for pcomplete with the standard completion UI, which ivy by default will override (with the very recent update, they appear in a nice overlay right in the eshell buffer near point!).

The comments in the source code of pcomplete-completions-at-point (which pcomplete-std-complete depends on) mention a couple of potential problems:

;; FIXME: it only completes the text before point, whereas the
;; standard UI may also consider text after point.
;; FIXME: the `pcomplete' UI may be used internally during
;; pcomplete-completions and then throw to `pcompleted', thus
;; imposing the pcomplete UI over the standard UI.

I think the first one won't affect me, since I don't think I ever press <tab> except at the end of the input line. I haven't seen the second problem surface either, so far.

EDIT: For those unfamiliar with eshell's quirks (this is a euphemism), maybe I should add that to rebind eshell's key as suggested above you should put this in your init file:

(add-hook 'eshell-mode-hook
  (lambda () 
    (define-key eshell-mode-map (kbd "<tab>")
      (lambda () (interactive) (pcomplete-std-complete)))))

Before you yell at me for the wasteful keybindings-in-a-hook antipattern, let me explain that eshell declares its keymap with (defvar eshell-mode-map nil) and then does (setq-local eshell-mode-map (sparse-keymap)) inside eshell-mode! (The code has a helpful ;; FIXME: What the hell!?.) That means that you can't rebind keys until after eshell-mode runs! Hence the hook.

3
  • Also, I haven't tested it, but I would guess that if helm doesn't already insinuate its way into eshell tab completion, this fix also applies to helm.
    – Omar
    Oct 17, 2016 at 5:50
  • This is pretty neat :) Thanks for the tip Oct 17, 2016 at 15:28
  • That “What the he'll!?” comment made my day :) Also, I'd like to note this should also work for other completion frameworks, like helm. Oct 19, 2016 at 6:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.