Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
sashimacs committed Jul 18, 2024
2 parents eed712a + 6223294 commit 9b1cac9
Show file tree
Hide file tree
Showing 7 changed files with 333 additions and 509 deletions.
8 changes: 5 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@ jobs:
emacs_version: ['27.1', '28.1', 'snapshot']
steps:
- name: Set up Emacs
uses: purcell/setup-emacs@master
uses: purcell/setup-emacs@v6.0
with:
version: ${{ matrix.emacs_version }}
- name: Install Eldev
run: curl -fsSL https://raw.github.com/doublep/eldev/master/webinstall/github-eldev | sh
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Run tests
run: |
eldev --trace --color=always compile --warnings-as-errors
eldev --loading=built-source --trace --color=always test --undercover codecov,dontsend
- name: Upload coverage
uses: codecov/codecov-action@v2
uses: codecov/codecov-action@v4
with:
token: ${{ secrets.CODECOV_TOKEN }}
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
/.eldev
/Eldev-local

/build
/hotfuzz-module.so
19 changes: 6 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
cmake_minimum_required(VERSION 3.19)
project(hotfuzz C)

if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.")
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE
STRING "Choose the type of build." FORCE)
endif()

find_program(EMACS_PROGRAM emacs)
if(EMACS_PROGRAM)
get_filename_component(EMACS_PROGRAM ${EMACS_PROGRAM} REALPATH)
get_filename_component(EMACS_PROGRAM_DIR ${EMACS_PROGRAM} DIRECTORY)
get_filename_component(EMACS_PROGRAM_DIR ${EMACS_PROGRAM_DIR} DIRECTORY)
find_program(EMACS_EXECUTABLE emacs)
if(EMACS_EXECUTABLE)
file(REAL_PATH ${EMACS_EXECUTABLE} EMACS_EXECUTABLE)
set(EMACS_PROGRAM_DIR ${EMACS_EXECUTABLE}/../..)
endif()

find_path(EMACS_INCLUDE_DIR emacs-module.h
Expand All @@ -26,8 +19,8 @@ find_package(Threads REQUIRED)
add_library(hotfuzz-module MODULE hotfuzz-module.c)
set_target_properties(hotfuzz-module PROPERTIES
C_STANDARD 11
POSITION_INDEPENDENT_CODE ON
C_STANDARD_REQUIRED ON
PREFIX ""
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR})
target_include_directories(hotfuzz-module PRIVATE ${EMACS_INCLUDE_DIR})
target_include_directories(hotfuzz-module SYSTEM PRIVATE ${EMACS_INCLUDE_DIR})
target_link_libraries(hotfuzz-module PRIVATE Threads::Threads)
103 changes: 57 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# hotfuzz

[![test](https://github.com/axelf4/hotfuzz/actions/workflows/test.yml/badge.svg)](https://github.com/axelf4/hotfuzz/actions/workflows/test.yml)
[![codecov](https://codecov.io/gh/axelf4/hotfuzz/branch/master/graph/badge.svg?token=OV1BqTB7QL)](https://codecov.io/gh/axelf4/hotfuzz)
[![codecov](https://codecov.io/gh/axelf4/hotfuzz/graph/badge.svg?token=OV1BqTB7QL)](https://codecov.io/gh/axelf4/hotfuzz)
[![MELPA](https://melpa.org/packages/hotfuzz-badge.svg)](https://melpa.org/#/hotfuzz)

This is a fuzzy Emacs completion style similar to the built-in `flex` style,
Expand All @@ -13,63 +13,62 @@ To use hotfuzz, add it to the `completion-styles` list:
```elisp
(setq completion-styles '(hotfuzz))
```

Or, if using
[Fido](https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html),
add hotfuzz to the `completion-styles` list this way:

If using [Fido], its insistence on using `flex` needs to be thwarted:
```elisp
(add-hook 'icomplete-minibuffer-setup-hook
(lambda () (setq-local completion-styles '(hotfuzz))))
```
or, if using [Selectrum], enable `hotfuzz-selectrum-mode`.

**Note:** Highlighting of the matched characters is only applied to
the first `hotfuzz-max-highlighted-completions` completions, out of
performance concerns. The default value is large enough so that
generally you will need to scroll the list of completions beyond the
second page to first see non-highlighted completions. If you are
annoyed by this you can make it highlight all completions instead
using
```elisp
(setq hotfuzz-max-highlighted-completions most-positive-fixnum)
(lambda () (kill-local-variable 'completion-styles)))
```
provided you are completing small enough lists and/or do not encounter
performance problems.
This is a non-issue when using `hotfuzz-selectrum-mode` since
Selectrum supports lazy highlighting.

## Customization

Hotfuzz adheres to a few of the default Emacs completion configuration options:
* `completion-ignore-case` specifies whether case should be considered
significant when matching.
* The face `completions-common-part` is used for highlighting the
characters of a candidate that the search string matched.
The following ordinary Emacs completion options are adhered to:
* `completion-ignore-case` specifies whether matching is case-insignificant.
* The `completions-common-part` face is used to highlight
what characters of a candidate the search string matched.

Unless the completion UI supports `completion-lazy-hilit`, as i.a.
[Vertico] and [Corfu] do, only the first
`hotfuzz-max-highlighted-completions` completions will be
highlighted out of performance concerns. The default value is large
enough that generally the list of completions will need to be
scrolled beyond the second page to reach non-highlighted
completions, but this optimization may be disabled with:
```elisp
(setq hotfuzz-max-highlighted-completions most-positive-fixnum)
```

## Dynamic module

Optionally, you may compile the bundled dynamic module
to greatly improve the performance of filtering.
Once the shared object is available in `load-path`
it will automatically be picked up when hotfuzz is loaded,
or you may evaluate `(require 'hotfuzz-module)`
if hotfuzz already has been loaded.
To compile, make sure GCC, CMake and GNU Make or similar are present,
and run
for improved performance.
Ensure GCC, CMake and GNU Make or similar are present, and run

```sh
mkdir build
cd build
cmake -DCMAKE_C_FLAGS='-O3 -march=native' .. \
&& cmake --build .
cmake -B build -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_FLAGS=-march=native . &&
cmake --build build
```

and place the resulting shared library somewhere in `load-path`.
It will be automatically picked up,
or you may evaluate `(require 'hotfuzz-module)`
if hotfuzz has already been loaded.

Unlike the Lisp implementation,
the dynamic module uses an unstable sorting algorithm.

> [!NOTE]
> Dynamic modules are unable to access invalid Unicode strings.
>
> [Consult] appends invisible so-called *tofus* to disambiguate
> completions and encode line numbers. Problematically, characters
> outside the Unicode range, unlikely to be matched by a search
> string, are used. Using e.g. the Supplementary Private Use Area-B
> instead circumvents the encoding issues:
> ```elisp
> (setq consult--tofu-char #x100000
> consult--tofu-range #x00fffe)
> ```
## Related projects

### The `flex` completion style
Expand All @@ -82,19 +81,27 @@ the matched characters in a candidate could look like

> x**f**xxx**o**xxx**o**xfoox
which would score low even though
there is a contiguous match later in the string.
which would score low despite the later contiguous match.

### flx

The [flx] package - which out-of-the-box only supports [Ido] -
has scoring criteria similar to those used by hotfuzz,
but works a little differently.
Its bountiful use of caching
means it can be faster at scoring long candidates.
Its bountiful use of caching means it can be faster at scoring long candidates.
Since the ordering of completions differs between flx and hotfuzz
you are encouraged to try both.

### fussy

The [fussy] completion style is generic over different fuzzy scoring backends,
flx and the Emacs Lisp implementation of hotfuzz being two of them.
fussy also implements caching of filtered candidates.
Although some of the scoring backends are implemented as dynamic modules,
hotfuzz has the advantage of passing all completion candidates
to its dynamic module en masse,
allowing sorting and filtering to be parallelized.

### orderless

The [orderless] completion style allows
Expand All @@ -103,10 +110,14 @@ to match according to any other completion style.
It is very customizable,
but does no sorting and allows the individual sub-patterns to overlap
(`"foo foo"` filters no additional items compared to `"foo"`).
Hotfuzz on the other hand tries to be more *clever* about sorting,
Hotfuzz on the other hand tries to be more clever about sorting,
and so users who dislike that may prefer orderless.

[Selectrum]: https://github.com/raxod502/selectrum
[flx]: https://github.com/lewang/flx
[Vertico]: https://github.com/minad/vertico
[Corfu]: https://github.com/minad/corfu
[Ido]: https://www.gnu.org/software/emacs/manual/html_node/ido/index.html
[Fido]: https://www.gnu.org/software/emacs/manual/html_node/emacs/Icomplete.html
[Consult]: https://github.com/minad/consult
[flx]: https://github.com/lewang/flx
[fussy]: https://github.com/jojojames/fussy
[orderless]: https://github.com/oantolin/orderless
Loading

0 comments on commit 9b1cac9

Please sign in to comment.