Skip to content

Commit 2fb98d1

Browse files
committed
feat: Directories and mixed files & directories search
1 parent cebacb3 commit 2fb98d1

File tree

17 files changed

+2712
-97
lines changed

17 files changed

+2712
-97
lines changed

crates/fff-c/include/fff.h

Lines changed: 220 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,7 @@ typedef struct FffScore {
8787
int32_t distance_penalty;
8888
int32_t current_file_penalty;
8989
int32_t combo_match_boost;
90+
int32_t path_alignment_bonus;
9091
bool exact_match;
9192
char *match_type;
9293
} FffScore;
@@ -221,14 +222,116 @@ typedef struct FffGrepResult {
221222

222223
/**
223224
* Scan progress returned by `fff_get_scan_progress`.
224-
*
225225
* The caller must free this with `fff_free_scan_progress`.
226226
*/
227227
typedef struct FffScanProgress {
228228
uint64_t scanned_files_count;
229229
bool is_scanning;
230+
bool is_watcher_ready;
231+
bool is_warmup_complete;
230232
} FffScanProgress;
231233

234+
/**
235+
* A directory item returned by `fff_search_directories`.
236+
*
237+
* All string fields are heap-allocated and owned by the parent `FffDirSearchResult`.
238+
* Free the entire result with `fff_free_dir_search_result`.
239+
*/
240+
typedef struct FffDirItem {
241+
char *relative_path;
242+
char *dir_name;
243+
int32_t max_access_frecency;
244+
} FffDirItem;
245+
246+
/**
247+
* Directory search result returned by `fff_search_directories`.
248+
*
249+
* The caller must free this with `fff_free_dir_search_result`.
250+
*/
251+
typedef struct FffDirSearchResult {
252+
/**
253+
* Pointer to a heap-allocated array of `FffDirItem` (length = `count`).
254+
*/
255+
struct FffDirItem *items;
256+
/**
257+
* Pointer to a heap-allocated array of `FffScore` (length = `count`).
258+
*/
259+
struct FffScore *scores;
260+
/**
261+
* Number of items/scores in the arrays.
262+
*/
263+
uint32_t count;
264+
/**
265+
* Total number of directories that matched the query.
266+
*/
267+
uint32_t total_matched;
268+
/**
269+
* Total number of indexed directories.
270+
*/
271+
uint32_t total_dirs;
272+
} FffDirSearchResult;
273+
274+
/**
275+
* A single item in a mixed (files + directories) search result.
276+
*
277+
* `item_type`: 0 = file, 1 = directory.
278+
* All string fields are heap-allocated and owned by the parent `FffMixedSearchResult`.
279+
*/
280+
typedef struct FffMixedItem {
281+
/**
282+
* 0 = file, 1 = directory.
283+
*/
284+
uint8_t item_type;
285+
char *relative_path;
286+
/**
287+
* Filename for files, last directory segment for directories.
288+
*/
289+
char *display_name;
290+
char *git_status;
291+
uint64_t size;
292+
uint64_t modified;
293+
int64_t access_frecency_score;
294+
int64_t modification_frecency_score;
295+
int64_t total_frecency_score;
296+
bool is_binary;
297+
} FffMixedItem;
298+
299+
/**
300+
* Mixed search result returned by `fff_search_mixed`.
301+
*
302+
* The caller must free this with `fff_free_mixed_search_result`.
303+
*/
304+
typedef struct FffMixedSearchResult {
305+
/**
306+
* Pointer to a heap-allocated array of `FffMixedItem` (length = `count`).
307+
*/
308+
struct FffMixedItem *items;
309+
/**
310+
* Pointer to a heap-allocated array of `FffScore` (length = `count`).
311+
*/
312+
struct FffScore *scores;
313+
/**
314+
* Number of items/scores in the arrays.
315+
*/
316+
uint32_t count;
317+
/**
318+
* Total number of items (files + dirs) that matched the query.
319+
*/
320+
uint32_t total_matched;
321+
/**
322+
* Total number of indexed files.
323+
*/
324+
uint32_t total_files;
325+
/**
326+
* Total number of indexed directories.
327+
*/
328+
uint32_t total_dirs;
329+
/**
330+
* Location parsed from the query string.
331+
*/
332+
struct FffLocation location;
333+
} FffMixedSearchResult;
334+
232335
/**
233336
* Create a new file finder instance.
234337
*
@@ -289,6 +392,60 @@ struct FffResult *fff_search(void *fff_handle,
289392
int32_t combo_boost_multiplier,
290393
uint32_t min_combo_count);
291394

395+
/**
396+
* Perform fuzzy search on indexed directories.
397+
*
398+
* # Parameters
399+
*
400+
* * `fff_handle` – instance from `fff_create_instance`
401+
* * `query` – search query string
402+
* * `current_file` – path of the currently open file for distance scoring (NULL/empty to skip)
403+
* * `max_threads` – maximum worker threads (0 = auto-detect)
404+
* * `page_index` – pagination offset (0 = first page)
405+
* * `page_size` – results per page (0 = default 100)
406+
*
407+
* ## Safety
408+
* * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
409+
* * `query` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
410+
*/
411+
struct FffResult *fff_search_directories(void *fff_handle,
412+
const char *query,
413+
const char *current_file,
414+
uint32_t max_threads,
415+
uint32_t page_index,
416+
uint32_t page_size);
417+
418+
/**
419+
* Perform a mixed fuzzy search across both files and directories.
420+
*
421+
* Returns a single flat list where files and directories are interleaved
422+
* by total score in descending order. Each item has an `item_type` field
423+
* (0 = file, 1 = directory).
424+
*
425+
* # Parameters
426+
*
427+
* * `fff_handle` – instance from `fff_create_instance`
428+
* * `query` – search query string
429+
* * `current_file` – path of the currently open file (NULL/empty to skip)
430+
* * `max_threads` – maximum worker threads (0 = auto-detect)
431+
* * `page_index` – pagination offset (0 = first page)
432+
* * `page_size` – results per page (0 = default 100)
433+
* * `combo_boost_multiplier` – score multiplier for combo matches (0 = default 100)
434+
* * `min_combo_count` – minimum combo count before boost applies (0 = default 3)
435+
*
436+
* ## Safety
437+
* * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
438+
* * `query` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
439+
*/
440+
struct FffResult *fff_search_mixed(void *fff_handle,
441+
const char *query,
442+
const char *current_file,
443+
uint32_t max_threads,
444+
uint32_t page_index,
445+
uint32_t page_size,
446+
int32_t combo_boost_multiplier,
447+
uint32_t min_combo_count);
448+
292449
/**
293450
* Perform content search (grep) across indexed files.
294451
*
@@ -405,6 +562,14 @@ struct FffResult *fff_get_scan_progress(void *fff_handle);
405562
*/
406563
struct FffResult *fff_wait_for_scan(void *fff_handle, uint64_t timeout_ms);
407564

565+
/**
566+
* Wait for the background file watcher to be ready.
567+
*
568+
* ## Safety
569+
* `fff_handle` must be a valid instance pointer from `fff_create_instance`.
570+
*/
571+
struct FffResult *fff_wait_for_watcher(void *fff_handle, uint64_t timeout_ms);
572+
408573
/**
409574
* Restart indexing in a new directory.
410575
*
@@ -545,4 +710,58 @@ void fff_free_result(struct FffResult *result_ptr);
545710
*/
546711
void fff_free_string(char *s);
547712

713+
/**
714+
* Free a directory search result returned by `fff_search_directories`.
715+
*
716+
* ## Safety
717+
* `result` must be a valid pointer previously returned via `FffResult.handle`
718+
* from `fff_search_directories`, or null (no-op).
719+
*/
720+
void fff_free_dir_search_result(struct FffDirSearchResult *result);
721+
722+
/**
723+
* Get a pointer to the `index`-th `FffDirItem` in a directory search result.
724+
*
725+
* ## Safety
726+
* `result` must be a valid `FffDirSearchResult` pointer from `fff_search_directories`.
727+
*/
728+
const struct FffDirItem *fff_dir_search_result_get_item(const struct FffDirSearchResult *result,
729+
uint32_t index);
730+
731+
/**
732+
* Get a pointer to the `index`-th `FffScore` in a directory search result.
733+
*
734+
* ## Safety
735+
* `result` must be a valid `FffDirSearchResult` pointer from `fff_search_directories`.
736+
*/
737+
const struct FffScore *fff_dir_search_result_get_score(const struct FffDirSearchResult *result,
738+
uint32_t index);
739+
740+
/**
741+
* Free a mixed search result returned by `fff_search_mixed`.
742+
*
743+
* ## Safety
744+
* `result` must be a valid pointer previously returned via `FffResult.handle`
745+
* from `fff_search_mixed`, or null (no-op).
746+
*/
747+
void fff_free_mixed_search_result(struct FffMixedSearchResult *result);
748+
749+
/**
750+
* Get a pointer to the `index`-th `FffMixedItem` in a mixed search result.
751+
*
752+
* ## Safety
753+
* `result` must be a valid `FffMixedSearchResult` pointer from `fff_search_mixed`.
754+
*/
755+
const struct FffMixedItem *fff_mixed_search_result_get_item(const struct FffMixedSearchResult *result,
756+
uint32_t index);
757+
758+
/**
759+
* Get a pointer to the `index`-th `FffScore` in a mixed search result.
760+
*
761+
* ## Safety
762+
* `result` must be a valid `FffMixedSearchResult` pointer from `fff_search_mixed`.
763+
*/
764+
const struct FffScore *fff_mixed_search_result_get_score(const struct FffMixedSearchResult *result,
765+
uint32_t index);
766+
548767
#endif /* FFF_C_H */

0 commit comments

Comments
 (0)