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
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.
-
3You should probably add that
(add-hook 'eshell-mode-hook '(lambda ()
needs to be wrapped around it.– TimmCommented 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.– OmarCommented Oct 20, 2016 at 22:07
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.
-
Also, I haven't tested it, but I would guess that if
helm
doesn't already insinuate its way intoeshell
tab completion, this fix also applies tohelm
.– OmarCommented Oct 17, 2016 at 5:50 -
This is pretty neat :) Thanks for the tip Commented 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. Commented Oct 19, 2016 at 6:42