Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ When doing code make sure to REDUCE SIZE OF COMMENTS. This is very important. Ev
- Do not make public structs if something can be private


## Style guide

- NO MODULES COMMENTS
- NO TOP FILE COMMENTS
- NO COMMENT LONGER THAN 2 LINES UNLESS ASKED EXPLICITLY
- UTILITY FUNCTIONS GO INTO THE END OF FILE

## Architecture

Everything that is performance critical happens in rust world, everything that is neovim specific happens in the lua code.
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,7 @@ require('fff').setup({
preview_scroll_down = '<C-d>',
toggle_debug = '<F2>',
cycle_grep_modes = '<S-Tab>',
insert_newline_escape = '<C-CR>',
-- grep mode only: jump cursor to first match of next/prev file group
grep_jump_to_next_file = { '<C-A-n>', '<A-Down>' },
grep_jump_to_prev_file = { '<C-A-p>', '<A-Up>' },
Expand Down
4 changes: 4 additions & 0 deletions crates/fff-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ name = "glob_bench"
harness = false
required-features = ["zlob"]

[[bench]]
name = "grep_bench"
harness = false

[features]
# `ripgrep` is the pure-Rust walker/glob backend and is on by default so
# consumers build without a Zig toolchain. CI/release opt into zlob via
Expand Down
105 changes: 105 additions & 0 deletions crates/fff-core/benches/grep_bench.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
use criterion::{Criterion, criterion_group, criterion_main};
use fff_search::file_picker::{FilePicker, FilePickerOptions};
use fff_search::{GrepMode, GrepSearchOptions, parse_grep_query};
use std::io::Write;

/// Synthetic repo: half the files contain the needle on every line (stresses
/// the per-match find/highlight path), half are pure noise (stresses the
/// whole-file prefilter path).
fn setup_repo(dir: &std::path::Path) {
for i in 0..400 {
let mut f = std::fs::File::create(dir.join(format!("match_{i}.rs"))).unwrap();
for j in 0..100 {
writeln!(
f,
"fn handle_{j}() {{ let controller = Controller::new({j}); controller.run(); }}"
)
.unwrap();
}
}
for i in 0..400 {
let mut f = std::fs::File::create(dir.join(format!("noise_{i}.rs"))).unwrap();
for j in 0..100 {
writeln!(
f,
"fn compute_{j}() {{ let value = {j} * 42; process(value); }}"
)
.unwrap();
}
}
}

fn options(mode: GrepMode) -> GrepSearchOptions {
GrepSearchOptions {
// Force a full scan of every file so we measure matcher/sink work,
// not pagination early-exit.
page_limit: usize::MAX,
max_matches_per_file: 0,
mode,
..Default::default()
}
}

fn bench_grep(c: &mut Criterion) {
let dir = tempfile::tempdir().unwrap();
setup_repo(dir.path());

let mut picker = FilePicker::new(FilePickerOptions {
base_path: dir.path().to_str().unwrap().into(),
watch: false,
..Default::default()
})
.unwrap();
picker.collect_files().unwrap();
assert_eq!(picker.get_files().len(), 800);

let mut group = c.benchmark_group("grep_e2e");
group.sample_size(30);

// Case-sensitive, 40k matched lines: hottest find_at/highlight path
let query = parse_grep_query("Controller");
let opts = options(GrepMode::PlainText);
group.bench_function("plain_case_sensitive_many_matches", |b| {
b.iter(|| {
let r = picker.grep(&query, &opts);
assert_eq!(r.files_with_matches, 400);
std::hint::black_box(r.matches.len())
});
});

// Case-insensitive (SIMD folding path), 120k matched spans
let query = parse_grep_query("controller");
group.bench_function("plain_case_insensitive_many_matches", |b| {
b.iter(|| {
let r = picker.grep(&query, &opts);
assert_eq!(r.files_with_matches, 400);
std::hint::black_box(r.matches.len())
});
});

// No matches anywhere: whole-file prefilter dominates
let query = parse_grep_query("Qqzyx");
group.bench_function("plain_no_matches", |b| {
b.iter(|| {
let r = picker.grep(&query, &opts);
assert_eq!(r.files_with_matches, 0);
std::hint::black_box(r.total_files_searched)
});
});

// Regex mode: must be unaffected by NeedleFinder changes
let query = parse_grep_query("Contr[a-z]+ller");
let regex_opts = options(GrepMode::Regex);
group.bench_function("regex_many_matches", |b| {
b.iter(|| {
let r = picker.grep(&query, &regex_opts);
assert_eq!(r.files_with_matches, 400);
std::hint::black_box(r.matches.len())
});
});

group.finish();
}

criterion_group!(benches, bench_grep);
criterion_main!(benches);
2 changes: 1 addition & 1 deletion crates/fff-core/src/file_picker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@

use crate::FFFStringStorage;
use crate::background_watcher::BackgroundWatcher;
use crate::bigram_filter::{BigramFilter, BigramOverlay};
use crate::constants::{MAX_OVERFLOW_FILES, PATH_BUF_SIZE};
use crate::error::Error;
use crate::frecency::FrecencyTracker;
use crate::git::GitStatusCache;
use crate::grep::{GrepResult, GrepSearchOptions, grep_search, multi_grep_search};
use crate::index::{BigramFilter, BigramOverlay};
use crate::query_tracker::QueryTracker;
use crate::scan::{ScanConfig, ScanJob, ScanSignals};
use crate::score::fuzzy_match_and_score_files;
Expand Down
6 changes: 3 additions & 3 deletions crates/fff-core/src/grep/fuzzy_grep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ use rayon::prelude::*;
use std::path::Path;
use std::sync::atomic::{AtomicBool, Ordering};

use super::grep::{
GrepMatch, GrepSearchOptions, char_indices_to_byte_offsets, classify_definition,
use super::sink::{
char_indices_to_byte_offsets, classify_definition, strip_line_terminators,
truncate_display_bytes,
};
use super::utils::{GrepResult, strip_line_terminators};
use super::types::{GrepMatch, GrepResult, GrepSearchOptions};

#[allow(clippy::too_many_arguments)]
pub(super) fn fuzzy_grep_search<'a>(
Expand Down
Loading
Loading