Emacs minibuffer selection (in miniature)
Switch branches/tags
Nothing to show
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Failed to load latest commit information.
LICENSE Add license Aug 27, 2018
README.org Another screenshot Aug 28, 2018
example.gif Add screenshot Aug 28, 2018
example2.gif Another screenshot Aug 28, 2018
raven.el Add a read-file-name-function Sep 7, 2018

README.org

Raven 🐦

Raven is a flexible tool for selecting candidates from the Emacs minibuffer. It supports multiple candidate sources and multiple actions, and is well-integrated with Evil mode. It also supports dummy candidates, which are similar to Helm’s dummy sources (except that they are candidates, not sources, and therefore one might include multiple dummy candidates within a single selection). It is also reasonably quick (works fairly well with 100,000 candidates when testing).

Raven is not:

  • An alternate completing-read, as it neither reads nor completes. Raven selects from a list of choices. A function raven-completing-read is provided to handle the many cases of completing-read that are merely selection (for example, in academic-phrases), but it will fail in cases that supply a completion function, such as find-file. Use custom commands in these cases.
  • Asynchronous. Caching of candidate lists should (and easily can) be handled elsewhere.
  • Intended for all audiences. Raven is tailored to my needs and preferences in many ways. Particularly, Raven’s minibuffer interface uses Evil. It should be easy to change this, but the defaults will always assume an Evil-based configuration.
  • All that large. Check out the source!

Future Work

  • Figure out how to bind action keys in only some Evil states. Naively using evil-define-key on the source-specific keymap interacts poorly (read: it doesn’t work) when the keymap is activated with set-transient-map.
  • More interesting prebuilt sources (probably in another package).

Example A - raven-mini?

(defun me/raven-unaffiliated-buffers ()
  (raven-source "Buffers" (me/unaffiliated-buffers) raven-buffer-actions))

(defun me/raven-project-buffers ()
  (raven-source "Project Buffers"
                (when (projectile-project-p) (remove-if 'me/buffer-boring-p (projectile-project-buffer-names)))
                raven-buffer-actions))

(defun me/raven-project-files ()
  (raven-source "Project Files"
                (when (projectile-project-p)
                  (cl-loop with root = (projectile-project-root)
                           for display in (projectile-current-project-files)
                           collect (cons display (expand-file-name display root))))
                raven-file-actions))

(defun me/raven-create-file-or-buffer ()
  (raven-source "Other"
                '((buffer . "Create buffer")
                  (file . "Create file"))
                (list (lambda (a)
                        (cond ((eq a 'buffer)
                               (switch-to-buffer (raven-input)))
                              ((eq a 'file)
                               (find-file (raven-input))))))))

(defun me/navigate ()
  (interactive)
  (raven (list (me/raven-project-buffers)
               (me/raven-unaffiliated-buffers)
               (me/raven-project-files)
               (raven-recentf-source)
               (me/raven-create-file-or-buffer)))))

Projectile buffers, projectile files, Recentf, and file/buffer creation, all in one convenient minibuffer interface with modal line-editing and navigation!

In my actual configs, I use a setup similar to above, but with even more sources, such as active/inactive Circe IRC buffers and EXWM windows.

Example B - Web Browser

(defvar me/bookmarks
  '(("github" . "https://github.com")
    ("example" . "http://example.com")))

(defun me/raven-bookmarks ()
  (raven-source "Bookmarks"
                me/bookmarks
                '(browse-url)))

(defun me/raven-browser-actions ()
  (raven-source
   "Other"
   '((ddg . "Search DuckDuckGo")
     (browse . "Browse URL"))
   (list (lambda (a)
           (cond ((eq a 'ddg)
                  (browse-url (concat "https://duckduckgo.com/?q="
                                      (raven-input))))
                 ((eq a 'browse)
                  (browse-url (raven-input))))))))

(defun me/browser ()
  (interactive)
  (raven (list (me/raven-bookmarks)
               (me/raven-browser-actions))))

Screenshots

example.gif

example2.gif