neek-core 1.0.0

Core fuzzy matching and scoring engine
Documentation
# neek

[jhawthorn/fzy]: https://github.com/jhawthorn/fzy

This is a high-performance, interactive fuzzy finder for the terminal that
started as a faithful reimplementation of [jhawthorn/fzy] with SIMD-accelerated
matching via `memchr` and parallel candidate scoring via Rayon. The workspace
itself features two crates. Those are **neek-core**, the `no_std` core library
that requires only `alloc`, and the interactive TUI with raw terminal mode, and
ANSI highlighting of matched positions,.

## Features

- **Non-interactive filter mode** - drop‑in replacement for `grep`‑style
  pipelines: read candidates from stdin, output the top matches to stdout.
- **Gotoh‑style affine‑gap scoring** - prefers consecutive letters, word
  boundaries (`/`, `-`, `_`, ``), CamelCase transitions, and dots. Produces more
  intuitive rankings than length‑based sorters.
- **SIMD matching** - `has_match` uses `memchr::memchr2` (SSE4.2 / AVX2 on
  x86‑64) for per‑needle‑character scanning, 4–8 times faster than the original
  C `strpbrk` loop.
- **`#![no_std]` core library** - the `neek-core` crate only requires `alloc`,
  making it usable in embedded or kernel contexts.
- **Parallel search** - `rayon::par_iter` distributes `has_match` + `score`
  across all CPU cores.

## Installation

Nix is the recommended way of downloading (and developing!) `neek`. You can
install it using Nix flakes using `nix profile add` if on non-nixos or add
`neek` as a flake input if you are on NixOS.

```nix
{
  # Add neek to your inputs like so:
  inputs.neek.url = "github:NotAShelf/neek";

  outputs = { /* ... */ };
}
```

Then you can get the package from your flake input, and add it to your packages
to make `neek` available in your system.

```nix
{inputs, pkgs, ...}: let
  neekPkg = inputs.neek.packages.${pkgs.stdenv.hostPlatform}.neek;
in {
  environment.systemPackages = [neekPkg];
}
```

If you want to test out the program before running it, `nix shell` will give you
a pretty good sandbox to play with it.

```sh
# Enter a development shell with 'neek' from the repository:
$ nix shell github:notashelf/neek

# Then use it normally:
$ find . -type f | neek
```

### Without Nix

You can also install neek on any of your systems _without_ using Nix. The
easiest method is to build and install from source with Cargo:

```bash
cargo install neek --locked
```

Additionally, you may get neek from source via `cargo install` using
`cargo install --git https://github.com/notashelf/neek --locked` or you may
check out to the repository, and use Cargo to build it. You'll need Rust 1.85.0
or above. Most distributions should package this version already. You may, of
course, prefer to package the built releases if you'd like.

## Usage

```plaintext
neek [OPTIONS]
```

For example, to pipe candidates on stdin:

```sh
# Use neek with find interactively
$ find . -type f | neek
```

Or to filter non‑interactively:

```sh
$ find . -type f | neek -e 'readme'
```

## Interactive keybindings

| Key                                    | Action                              |
| -------------------------------------- | ----------------------------------- |
| `Enter` / `Ctrl-M`                     | Accept selection                    |
| `Esc` / `Ctrl-C` / `Ctrl-D` / `Ctrl-G` | Exit                                |
| `Ctrl-P` / `Ctrl-K` / ``              | Previous match                      |
| `Ctrl-N` / `Ctrl-J` / ``              | Next match                          |
| `Tab` / `Ctrl-I`                       | Autocomplete search to selection    |
| `Backspace` / `Ctrl-H` / `Del`         | Delete character before cursor      |
| `Ctrl-W`                               | Delete word before cursor           |
| `Ctrl-U`                               | Delete to beginning of line         |
| `` / ``                              | Move cursor (jumps word boundaries) |
| `Ctrl-A` / `Home`                      | Beginning of line                   |
| `Ctrl-E` / `End`                       | End of line                         |
| `Page Up` / `Page Down`                | Scroll one page                     |

## Scoring algorithm

We use a variant of **Gotoh's algorithm** (Smith–Waterman–Gotoh with affine gap
penalties). Only insertions into the needle (gaps in the haystack) are
permitted. There is no delegation and no substitutions.

Two DP matrices are maintained:

- `D[i][j]` -> best score **ending with a match** at `haystack[j]` for
  `needle[0..=i]`
- `M[i][j]` -> best possible score for `needle[0..=i]` against `haystack[0..=j]`

`D` tracks consecutive‑match bonuses; `M` propagates the maximum score along the
row with per‑row gap penalties.

[algorithm document]: ./ALGORITHM.md

The `score()` function reserves only two rows of each matrix (O(m) space) using
in‑place pointer aliasing, and avoids zero‑initialisation with `MaybeUninit`.
The `score_positions()` variant stores the full DP table for backtracking when
match positions are needed for highlighting. Further details can be found in the
[algorithm document]. You're also welcome, invited even, to correct my math :)

## License

<!--markdownlint-disable MD059-->

This project is made available under Mozilla Public License (MPL) version 2.0.
See [LICENSE](LICENSE) for more details on the exact conditions. An online copy
is provided [here](https://www.mozilla.org/en-US/MPL/2.0/).

<!--markdownlint-enable MD059-->