@@ -104,26 +104,76 @@ fn default_i32(val: i32, default: i32) -> i32 {
104104 if val == 0 { default } else { val }
105105}
106106
107- /// Create a new file finder instance.
107+ /// Create a new file finder instance (legacy signature).
108+ ///
109+ /// @deprecated prefer `fff_create_instance2`, which also exposes log file and
110+ /// cache-budget configuration. This function delegates to `fff_create_instance2`
111+ /// with NULL log paths and auto cache budget, so behaviour is unchanged.
112+ ///
113+ /// ## Safety
114+ /// See `fff_create_instance2`.
115+ #[ unsafe( no_mangle) ]
116+ pub unsafe extern "C" fn fff_create_instance (
117+ base_path : * const c_char ,
118+ frecency_db_path : * const c_char ,
119+ history_db_path : * const c_char ,
120+ use_unsafe_no_lock : bool ,
121+ enable_mmap_cache : bool ,
122+ enable_content_indexing : bool ,
123+ watch : bool ,
124+ ai_mode : bool ,
125+ ) -> * mut FffResult {
126+ unsafe {
127+ fff_create_instance2 (
128+ base_path,
129+ frecency_db_path,
130+ history_db_path,
131+ use_unsafe_no_lock,
132+ enable_mmap_cache,
133+ enable_content_indexing,
134+ watch,
135+ ai_mode,
136+ std:: ptr:: null ( ) ,
137+ std:: ptr:: null ( ) ,
138+ 0 ,
139+ 0 ,
140+ 0 ,
141+ )
142+ }
143+ }
144+
145+ /// Create a new file finder instance (v2, with full options).
108146///
109147/// Returns an opaque pointer that must be passed to all other `fff_*` calls
110148/// and eventually freed with `fff_destroy`.
111149///
112150/// # Parameters
113151///
114- /// * `base_path` – directory to index (required)
115- /// * `frecency_db_path` – path to frecency LMDB database (NULL/empty to skip)
116- /// * `history_db_path` – path to query history LMDB database (NULL/empty to skip)
117- /// * `use_unsafe_no_lock` – use MDB_NOLOCK for LMDB (useful in single-process setups)
118- /// * `enable_mmap_cache` – pre-populate mmap caches after the initial scan
119- /// * `enable_content_indexing` – build content index after the initial scan
120- /// * `watch` – start a background file-system watcher for live updates
121- /// * `ai_mode` – enable AI-agent optimizations (auto-track frecency on modifications)
152+ /// * `base_path` – directory to index (required)
153+ /// * `frecency_db_path` – frecency LMDB database path (NULL/empty to skip)
154+ /// * `history_db_path` – query history LMDB database path (NULL/empty to skip)
155+ /// * `use_unsafe_no_lock` – use MDB_NOLOCK for LMDB (useful in single-process setups)
156+ /// * `enable_mmap_cache` – pre-populate mmap caches after the initial scan
157+ /// * `enable_content_indexing` – build content index after the initial scan
158+ /// * `watch` – start a background file-system watcher for live updates
159+ /// * `ai_mode` – enable AI-agent optimizations
160+ /// * `log_file_path` – tracing log file path (NULL/empty to skip).
161+ /// Only the first successful call in a process installs the subscriber;
162+ /// subsequent calls are no-ops at the log layer.
163+ /// * `log_level` – `"trace"`, `"debug"`, `"info"`, `"warn"`, `"error"`
164+ /// (NULL/empty defaults to `"info"`). Ignored when `log_file_path` is not set.
165+ /// * `cache_budget_max_files` – content cache file-count cap (0 = auto)
166+ /// * `cache_budget_max_bytes` – content cache byte cap (0 = auto)
167+ /// * `cache_budget_max_file_size` – per-file byte cap (0 = auto)
168+ ///
169+ /// When all three `cache_budget_*` values are 0 the budget is auto-computed
170+ /// from repo size after the initial scan. Otherwise an explicit budget is
171+ /// used: any field left at 0 falls back to its `unlimited()` default.
122172///
123173/// ## Safety
124174/// String parameters must be valid null-terminated UTF-8 or NULL.
125175#[ unsafe( no_mangle) ]
126- pub unsafe extern "C" fn fff_create_instance (
176+ pub unsafe extern "C" fn fff_create_instance2 (
127177 base_path : * const c_char ,
128178 frecency_db_path : * const c_char ,
129179 history_db_path : * const c_char ,
@@ -132,12 +182,24 @@ pub unsafe extern "C" fn fff_create_instance(
132182 enable_content_indexing : bool ,
133183 watch : bool ,
134184 ai_mode : bool ,
185+ log_file_path : * const c_char ,
186+ log_level : * const c_char ,
187+ cache_budget_max_files : u64 ,
188+ cache_budget_max_bytes : u64 ,
189+ cache_budget_max_file_size : u64 ,
135190) -> * mut FffResult {
136191 let base_path_str = match unsafe { cstr_to_str ( base_path) } {
137192 Some ( s) if !s. is_empty ( ) => s. to_string ( ) ,
138193 _ => return FffResult :: err ( "base_path is null or empty" ) ,
139194 } ;
140195
196+ if let Some ( log_path) = unsafe { optional_cstr ( log_file_path) } {
197+ let level = unsafe { optional_cstr ( log_level) } ;
198+ if let Err ( e) = fff:: log:: init_tracing ( log_path, level) {
199+ return FffResult :: err ( & format ! ( "Failed to init tracing: {}" , e) ) ;
200+ }
201+ }
202+
141203 let frecency_path = unsafe { optional_cstr ( frecency_db_path) } . map ( |s| s. to_string ( ) ) ;
142204 let history_path = unsafe { optional_cstr ( history_db_path) } . map ( |s| s. to_string ( ) ) ;
143205
@@ -185,6 +247,12 @@ pub unsafe extern "C" fn fff_create_instance(
185247 FFFMode :: Neovim
186248 } ;
187249
250+ let cache_budget = fff:: ContentCacheBudget :: from_overrides (
251+ cache_budget_max_files as usize ,
252+ cache_budget_max_bytes,
253+ cache_budget_max_file_size,
254+ ) ;
255+
188256 // Initialize file picker (writes directly into shared_picker)
189257 if let Err ( e) = FilePicker :: new_with_shared_state (
190258 shared_picker. clone ( ) ,
@@ -195,7 +263,7 @@ pub unsafe extern "C" fn fff_create_instance(
195263 enable_content_indexing,
196264 watch,
197265 mode,
198- cache_budget : None ,
266+ cache_budget,
199267 } ,
200268 ) {
201269 return FffResult :: err ( & format ! ( "Failed to init file picker: {}" , e) ) ;
0 commit comments