Recently, as I replaced more of my Emacs-helm configuration with counsel and ivy, I noticed that ivy-switch-buffer, when augmented by ivy-rich, was not showing the directories of the buffers it was listing.

After some Lisp spelunking, I discovered that it was because ivy-rich relies on the presence of either the projectile package, something I do not wish to have in my Emacs configuration, or on project.el, which I also do not use.

In this post, I show how you can get full buffer filenames and project names with the lighter-than-projectile and more-robust-than-project.el find-file-in-project, or how you can bypass the project name functionality completely and just get buffer filenames with no extra packages.

(There are a number of long-standing PRs on ivy-rich, so I decided against investing my time there, instead making the fix available directly on this blog.)

### Wednesday 2020-11-18

Indeed Yevgnen (ivy-rich’s author) merged my PR, so everything in this post should be fixed if you update your ivy-rich from melpa.

### Tuesday 2020-11-17

Probably due to my post on reddit.com/r/emacs/, ivy-rich’s author added find-file-in-project support with this commit!

On its part, this motivated me to create a PR to ivy-rich with my improved buffer directory extraction.

If that PR gets merged, you can ignore the rest of this post.

## The result

We want the ivy-switch-buffer display to look like the one in the screenshot below. Each buffer has its full filename, if available, on the right.

Here’s another screenshot with all-the-icons-ivy-rich installed and active:

## The code

Note: This section is here purely for reference purposes. The fixes documented here have now been merged into the ivy-rich package.

I have the following code in my init.el.

In it, two of the ivy-rich functions are overwritten with improved versions.

  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52  (use-package ivy-rich :ensure t :config (ivy-rich-mode 1) ;; abbreviate turns home into ~ (for example) ;; buffers still only get the buffer basename (setq ivy-virtual-abbreviate 'abbreviate ivy-rich-path-style 'abbrev) ;; use buffer-file-name and list-buffers-directory instead of default-directory ;; so that special buffers, e.g. *scratch* don't get a directory (we return nil in those cases) (defun ivy-rich--switch-buffer-directory (candidate) "Return directory of file visited by buffer named CANDIDATE, or nil if no file." (let* ((buffer (get-buffer candidate)) (fn (buffer-file-name buffer))) ;; if valid filename, i.e. buffer visiting file: (if fn ;; return containing directory (directory-file-name fn) ;; else if mode explicitly offering list-buffers-directory, return that; else nil. ;; buffers that don't explicitly visit files, but would like to show a filename, ;; e.g. magit or dired, set the list-buffers-directory variable (buffer-local-value 'list-buffers-directory buffer)))) ;; override ivy-rich project root finding to use FFIP or to skip completely (defun ivy-rich-switch-buffer-root (candidate) ;; 1. changed let* to when-let*; if our directory func above returns nil, ;; we don't want to try and find project root (when-let* ((dir (ivy-rich--switch-buffer-directory candidate))) (unless (or (and (file-remote-p dir) (not ivy-rich-parse-remote-buffer)) ;; Workaround for browse-url-emacs' buffers , it changes ;; default-directory' to "http://" (#25) (string-match "https?://" dir)) (cond ;; 2. replace the project-root-finding ;; a. add FFIP for projectile-less project-root finding (on my setup much faster) ... ((require 'find-file-in-project nil t) (let ((default-directory dir)) (ffip-project-root))) ;; b. OR disable project-root-finding altogether (t "") ((bound-and-true-p projectile-mode) (let ((project (or (ivy-rich--local-values candidate 'projectile-project-root) (projectile-project-root dir)))) (unless (string= project "-") project))) ((require 'project nil t) (when-let ((project (project-current nil dir))) (car (project-roots project)))) )))))