@@ -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 */
227227typedef 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 */
406563struct 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 */
546711void 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