# What Search Algorithms Does FFF Use for Fuzzy Matching?

> Discover the search algorithms FFF uses for fuzzy matching. Explore SIMD-accelerated file-path search and Smith-Waterman for content grep operations powered by neo_frizbee.

- Repository: [Dmitriy Kovalenko/fff](https://github.com/dmtrKovalenko/fff)
- Tags: internals
- Published: 2026-06-02

---

**FFF relies on the `neo_frizbee` crate to power its fuzzy matching, utilizing SIMD-accelerated algorithms for file-path search and Smith-Waterman dynamic programming for content grep operations.**

The [dmtrKovalenko/fff](https://github.com/dmtrKovalenko/fff) repository implements a high-performance fuzzy finder for Neovim by leveraging the Rust-based `neo_frizbee` library (version 0.10.2), which provides optimized search algorithms capable of handling large codebases with minimal latency.

## FFF's Core Fuzzy Matching Engine

At the foundation of FFF's search capability lies the **`neo_frizbee`** crate, a Rust port of the original frizbee library. This dependency is declared in the workspace [`Cargo.toml`](https://github.com/dmtrKovalenko/fff/blob/main/Cargo.toml) and exposes two distinct algorithmic approaches tailored to different search contexts. The crate handles both path-based file selection and content-based line matching through SIMD-optimized implementations that run across multiple CPU cores.

In [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs), FFF initializes the matching engine by constructing a `neo_frizbee::Config` struct and invoking `neo_frizbee::match_list_parallel_resolved` to process queries against file lists. This architecture allows FFF to separate the pre-filtering phase from the scoring phase, maximizing throughput while maintaining typo tolerance.

## File-Path Search: SIMD-Accelerated Fuzzy Matching

For file-path selection in the picker UI, FFF employs a **SIMD-accelerated fuzzy matching** algorithm that tolerates dropped characters and reordered fragments. According to the implementation in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs), the algorithm executes in two distinct phases:

- **SIMD Pre-Filter**: The query is split into "chunks" and processed using vectorized byte-wise comparisons to instantly discard impossible candidates. This vectorized approach enables sub-millisecond filtering even on directories containing hundreds of thousands of files.

- **Scoring Refinement**: Surviving candidates pass through a lightweight scoring phase using the `neo_frizbee::Scoring` struct, which calculates match quality based on consecutive character matches and position bonuses.

The parallel variant `match_list_parallel_resolved` distributes this workload across available CPU cores, ensuring that full-project scans remain responsive regardless of repository size.

## Content Search: Smith-Waterman Dynamic Programming

When performing fuzzy grep operations via `:FffGrep`, FFF switches to the **Smith-Waterman** algorithm, a classic dynamic-programming approach for local sequence alignment. As implemented in [`crates/fff-core/src/grep.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/grep.rs), this algorithm produces typo-tolerant similarity scores for each line in the searched files.

The Smith-Waterman implementation within `neo_frizbee` runs on SIMD-enabled code paths, allowing it to compute the dynamic-programming matrix in a few CPU cycles per line rather than relying on naive iterative comparisons. This provides the same alignment quality as traditional fuzzy grep tools while maintaining the performance characteristics required for interactive search.

## Parallel Processing and Configuration

FFF exposes configurable tolerance parameters through the `neo_frizbee::Config` struct, which the Lua UI layer modifies before passing to Rust via FFI. Key configuration options include:

- **`max_typos`**: Controls the maximum allowable edit distance for a match to be considered valid.
- **`case_sensitive`**: Determines whether the SIMD comparisons respect character case.
- **Parallel batch processing**: All matching operations use the `*_parallel_resolved` variants to batch-process candidates across CPU cores.

The scoring logic in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs) combines these fuzzy match scores with **frecency weights** (backed by LMDB) to produce the final ranking presented to users.

## Practical Implementation Examples

To invoke the SIMD-accelerated path search from Lua:

```lua
local fff = require('fff')
-- Opens picker; queries matched using frizbee's SIMD fuzzy algorithm
fff.find_files({ cwd = vim.fn.getcwd() })

```

For fuzzy grep with Smith-Waterman scoring:

```lua
local fff = require('fff')
-- Searches lines ranked by neo_frizbee's Smith-Waterman implementation
fff.grep({
  query = 'async await',
  cwd   = vim.fn.getcwd(),
  fuzzy = true,  -- Enables typo-tolerant mode
})

```

Internally, the Rust core constructs the matching configuration as follows:

```rust
let config = neo_frizbee::Config {
    case_sensitive: false,
    max_typos: 2,
    ..Default::default()
};

let matches = neo_frizbee::match_list_parallel_resolved(&query, &paths, &config);

```

## Summary

- **File-path search** utilizes SIMD-accelerated fuzzy matching with a vectorized pre-filter phase implemented in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs).
- **Content grep** employs Smith-Waterman dynamic programming alignment for typo-tolerant line matching, found in [`crates/fff-core/src/grep.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/grep.rs).
- Both algorithms leverage the `neo_frizbee` crate (version 0.10.2) and run on SIMD-enabled parallel code paths via `match_list_parallel_resolved`.
- The `neo_frizbee::Config` struct controls tolerance settings including `max_typos` and `case_sensitive`.
- FFF combines fuzzy scores with LMDB-backed frecency data to rank results.

## Frequently Asked Questions

### What is the difference between FFF's path search and grep search algorithms?

Path search uses a SIMD-accelerated fuzzy matcher optimized for file paths, which splits queries into chunks for vectorized byte-wise comparison. Grep search uses the Smith-Waterman algorithm, a dynamic-programming approach designed for local sequence alignment of text lines. Both algorithms tolerate typos but serve different data structures: directory hierarchies versus file contents.

### How does FFF achieve fast fuzzy matching on large repositories?

FFF achieves speed through three mechanisms: SIMD vectorization that processes multiple bytes simultaneously in `neo_frizbee`, a pre-filter phase that eliminates impossible candidates before scoring, and parallel batch processing across CPU cores using `match_list_parallel_resolved`. These optimizations allow sub-millisecond response times even on projects with hundreds of thousands of files.

### Can I configure the fuzziness tolerance in FFF?

Yes. FFF exposes the `neo_frizbee::Config` struct to the Lua layer, allowing you to set `max_typos` for edit distance tolerance and `case_sensitive` for character matching rules. These parameters are passed from Lua through FFI to the Rust core in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs), affecting both path and grep search behaviors.

### Where does FFF store the frecency data used for ranking?

FFF stores frecency weights in an LMDB-backed database. The scoring logic in [`crates/fff-core/src/score.rs`](https://github.com/dmtrKovalenko/fff/blob/main/crates/fff-core/src/score.rs) combines these pre-computed frequency/recency weights with the raw fuzzy match scores from `neo_frizbee` to determine the final presentation order of results.