r/emacs•
mathrick

How to get icomplete-like find-file completion in doom/ivy/selectrum/etc.?

Question

So, I'm in the middle of trying to port my 20 years of emacs config from a homegrown solution based on a fork of grail.el to Doom. And by "port" I really mean "rebuild something familiar enough that I can relearn to use it", as I'd really like to leverage the community-built configs for stuff like python (been writing python in Emacs for 10+ years, and I still can't the experience to be anything better than "rather sucky").

Anyway, a big, big problem for the adoption right now is the fact that, try as I might, I can't get find-file completion to work the way it does in icomplete. By which I mean that if I type ~/D/r-g/sc/, it will complete to ~/Dev/renpy-games/scratchpad. No packages I've tried to migrate to (which so far includes Doom's (ivy +fuzzy +prescient) and selectrum-prescient in my old personal config) have anything like that. They don't seem to match partial directory names, don't recurse into subdirectories, and don't consider / to be a separator. The closest I could find is Ivy's C-j, which inserts the current candidate into the minibuffer, but that's much clunkier and less powerful, since I can't just say "whichever of the candidate directories has the file in it". Is there any way to make it do that? I know that Doom generally expects you to use projectile and there the fuzzy searching works, but my workflow isn't currently built around projects, and I do a lot of ad-hoc editing of files that I know the path of, and don't want to give it up.

Posted Jun 11, 2020, 9:25 PM UTC

311
ave_63•

I think what you want is counsel-fzf. You need to install fzf on your system and counsel in emacs. There is a really useful extension to counsel-fzf on Protesilaos Stavrou's .emacs file that I use: https://protesilaos.com/dotemacs/

I think it's called prot/counsel-fzf-with-rg or something. He demonstrates it on his YouTube channel if you search for fzf rg ivy. Sorry for the bad formatting, I'm on mobile.

2
mathrickOP•

Thanks, I'll check that out.

1
oantolin•

It's not really icomplete that expands ~/D/r-g/sc/ to ~/Dev/renpy-games/scratchpad, that's done by the interaction of the partial-completion completion style with the read-file-name-internal completion table. (One quick way to show it's not icomplete doing it is to turn icomplete-mode off, and try it with Emacs's default tab completion.) I don't think it'll be that easy to get exactly that behavior from external completion frameworks, but hope I'm wrong about that. (External completion frameworks tend to not use Emacs' completion tables instead providing their own notion of completion source, and also tend to not use Emacs' completion styles.)

One thing that might be an acceptable alternative is to use a completion source that recursively lists all files underneath a directory and to use fuzzy matching on it. I'm sure both Counsel and Helm provide something like this.

But there's nothing forcing you to use the same completion UI for everything, you can easily arrange to use icomplete for find-file and, say, Helm for some commands you like from it and Ivy/Counsel for some other commands.

2
mathrickOP•

Right, I've been trying to trace how exactly that happens in the code, but stepping through read-file-name-internal is difficult, as it uses the minibuffer, which messes up Edebug. Never been a fan of how brittle Edebug is. I'm not opposed to porting the completion code to one of the other methods of display, it's just that I can't pinpoint the place it actually happens in.

2
oantolin•

The function to read is completion-pcm--find-all-completions. When doing file name completion the prefix referred to in the code is everything but the last path component, so you are interested in what happens when the prefix is not an actual path but requires further expansion. That part starts with the comment:

;; The prefix has no completions at all, so we should try and fix
;; that first.

Basically, it drops the last character of the prefix (i.e., the slash) and recursively finds all completions of that.

I realize now that when I said "the interaction between partial-completion and read-name-file-internal" I was overstating read-name-file-internal's involvement. It's really mostly this completion-pcm--find-all-completions function.

Oh, and I agree wholeheartedly with your edebug complaint. My addiction to writing completion UIs means I've run against this problem many, many times. I've gone back to what is widely recognized by old school programmers as the best debugging method there is: printf-debugging, or in Emacs Lisp terms, message-debugging. :)

Finally, does the "math" in "mathrick" mean I'm talking to a fellow mathematician?

1
mathrickOP•

Hey, thanks! I've actually got that part figured out before I saw your reply, but it does confirm my understanding.

As for my username, sadly no, at some point in my past I had to choose between CS, maths and linguistics, and chose the first. My knowledge of mathematics never got as deep as I'd like it.

2
mathrickOP•

Also, I just started using icomplete-vertical, which you've written, and so far it's doing exactly what I want it to, so thanks a lot for making it :)

2
oantolin•

I'm glad it's working for you!

1
RoutineInvestment•

The Orderless package has a partial-completion style but you can use it in any of the 3rdparty completion frameworks (or just stick to icomplete or fido?)

2
oantolin•

Sadly, orderless's prefixes matching style won't do this for you in find-file, you'd need a completion source that gave you full paths from the get-go, a sort of recursive-find-file. One such source is project-find-file and indeed orderless-prefixes would work fine with it.

2
dnquark•

First of all, pro-tip / saner binding for Ivy so that you can just press RET and not C-j: (define-key ivy-minibuffer-map (kbd "<return>") 'ivy-alt-done)

Second, I think you could get close to the behavior you want with Ivy by binding / to either ivy-alt-done or ivy-partial or ivy-partial-or-done or, quite possibly, some wrapper that Magically Does What You Want And Handles Possible Corner Cases.

2