Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/minad/affe

:monkey: affe.el - Asynchronous Fuzzy Finder for Emacs
https://github.com/minad/affe

Last synced: about 1 month ago
JSON representation

:monkey: affe.el - Asynchronous Fuzzy Finder for Emacs

Awesome Lists containing this project

README

        

#+title: affe.el - Asynchronous Fuzzy Finder for Emacs
#+author: Daniel Mendler
#+language: en
#+export_file_name: affe.texi
#+texinfo_dir_category: Emacs misc features
#+texinfo_dir_title: Affe: (affe).
#+texinfo_dir_desc: Asynchronous Fuzzy Finder for Emacs.

#+html: GNU Emacs
#+html: MELPA
#+html: MELPA Stable

#+html:

This package provides an asynchronous fuzzy finder similar to the [[https://github.com/junegunn/fzf][fzf
command-line fuzzy finder]], written in pure Elisp. A producer process is
started in the background, e.g., ~find~ or ~grep~. The output produced by this
process is filtered by an external asynchronous Emacs process. The Emacs UI
always stays responsive since the work is off-loaded to other processes. The
results are presented in the minibuffer using [[https://github.com/minad/consult][Consult]], which allows to quickly
select from the available items. Note that Affe is an experimental package and a
demonstrator of asynchronous processing outside of Emacs in a separate process.
Generally I recommend to use =consult-grep= or =consult-ripgrep=, since these
commands will perform better for large projects. The Consult package itself is
more mature.

#+toc: headlines 8

* Installation and Configuration

The package is available on MELPA and can be installed using the Emacs package
manager. If files should not be automatically previewed, a manual preview key
should be set for ~affe-grep~.

#+begin_src emacs-lisp
(use-package affe
:config
;; Manual preview key for `affe-grep'
(consult-customize affe-grep :preview-key "M-."))
#+end_src

The default regular expression transformation of Consult is limited. It is
recommended to configure [[https://github.com/oantolin/orderless][Orderless]] as =affe-regexp-compiler= in Consult.

#+begin_src emacs-lisp
(defun affe-orderless-regexp-compiler (input _type _ignorecase)
(setq input (cdr (orderless-compile input)))
(cons input (apply-partially #'orderless--highlight input t)))
(setq affe-regexp-compiler #'affe-orderless-regexp-compiler)
#+end_src

Affe requires the ~rg~ ("ripgrep") command line program to be available. The
producer processes can be customized by adjusting the variables
~affe-find-command~ and ~affe-grep-command~.

* Available commands

- ~affe-grep~: Filters the content of all text files in the current directory, similar to ~consult-grep~.
- ~affe-find~: Filters the file paths of all files in the current directory, similar to ~consult-find~.

* Related packages

Affe depends on Consult and works best with the Vertico and the Mct completion
UIs.

- [[https://github.com/minad/consult][Consult]]: Useful search and navigation commands (Dependency of Affe).
- [[https://github.com/minad/marginalia][Marginalia]]: File annotations in the minibuffer.
- [[https://github.com/oantolin/embark][Embark]]: Minibuffer actions on files.
- [[https://github.com/oantolin/orderless][Orderless]]: Advanced completion style, can be plugged together with Affe.
- [[https://github.com/minad/vertico][Vertico]] or [[https://git.sr.ht/~protesilaos/mct][Mct]]: Vertical completion systems

* Details

The Affe frontend transforms the input string to a list of regular expressions
by calling the ~affe-regexp-function~. The regular expressions are passed to the
Affe backend via the ~emacsclient~ protocol. The backend controls a producer
process, which generates lines of text. The lines are filtered using the regular
expressions submitted by the frontend. For performance reasons,
~all-completions~ is used for the filtering. The backend returns only a limited
amount of matching candidates, hopefully the most plausible ones. The frontend
calls the ~affe-highlight-function~ on the returned matches, to highlight the
input pattern.

Affe uses a more primitive matching technique than ~fzf~, which uses the
[[https://en.wikipedia.org/wiki/Smith%E2%80%93Waterman_algorithm][Smith-Waterman algorithm]]. Affe does not perform any ranking or sorting; it
matches the lines in the order returned by the producer process against a list
of regular expressions. On the upside, this allows plugging Affe together with
the [[https://github.com/oantolin/orderless][Orderless]] completion style, which can give a consistent fuzzy filtering
experience across all Emacs commands, including synchronous and asynchronous
commands.

As possible enhancement of Affe, one could implement alphabetical and sorting by
length in the backend. By using a bucket sorting technique the sorting
complexity will stay sufficiently linear such that the performance impact should
be acceptable. However implementing a scoring-based sorting is probably not
feasible since this requires heavier computations in Elisp. But maybe nativecomp
Emacs is a game changer here?

* Alternatives

- [[https://github.com/minad/consult][consult-grep/consult-find]]: Perform the filtering in the frontend.
- [[https://github.com/abo-abo/swiper][counsel-fzf]]: Ivy-specific, restarts find+fzf when updating the input pattern.
- [[https://github.com/bling/fzf.el][fzf.el]]: Runs the fzf command line program in an Emacs terminal
- [[https://github.com/10sr/fuzzy-finder-el][fuzzy-finder.el]]: Similar to fzf.el