Skip to content
Open
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ require('fff').setup({
},
git = {
status_text_color = false, -- true to color filenames by git status
support_submodules = true, -- walk into submodules and report their git status; set false to skip them
},
select = {
-- Return winid to open the chosen file in, or nil to open in the original window
Expand Down
34 changes: 33 additions & 1 deletion crates/fff-c/include/fff.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
/**
* Current used version of [`FffCreateOptions`].
*/
#define FFF_CREATE_OPTIONS_VERSION 1
#define FFF_CREATE_OPTIONS_VERSION 2

/**
* Result envelope returned by all `fff_*` functions.
Expand Down Expand Up @@ -133,6 +133,12 @@ typedef struct FffCreateOptions {
* `enable_fs_root_scanning`.
*/
bool enable_home_dir_scanning;
/**
* When `true` (default), submodule directories are walked and reported in
* git status. When `false`, submodule paths are skipped during traversal
* and excluded from git status.
*/
bool support_submodules;
} FffCreateOptions;

/**
Expand Down Expand Up @@ -515,6 +521,32 @@ struct FffResult *fff_create_instance_with(const struct FffCreateOptions *opts);
*/
struct FffResult *fff_create_instance_with_value(struct FffCreateOptions opts);

/**
* Create a new file finder instance (v3, with submodule support toggle).
*
* Identical to [`fff_create_instance2`] except for the trailing
* `support_submodules` flag. When `true` (recommended default), submodule
* directories are walked and reported in git status. When `false`, submodule
* paths are skipped during traversal and excluded from git status.
*
* ## Safety
* String parameters must be valid null-terminated UTF-8 or NULL.
*/
struct FffResult *fff_create_instance3(const char *base_path,
const char *frecency_db_path,
const char *history_db_path,
bool _use_unsafe_no_lock,
bool enable_mmap_cache,
bool enable_content_indexing,
bool watch,
bool ai_mode,
const char *log_file_path,
const char *log_level,
uint64_t cache_budget_max_files,
uint64_t cache_budget_max_bytes,
uint64_t cache_budget_max_file_size,
bool support_submodules);

/**
* Destroy a file finder instance and free all its resources.
*
Expand Down
10 changes: 8 additions & 2 deletions crates/fff-c/src/ffi_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use fff::{
};

/// Current used version of [`FffCreateOptions`].
pub const FFF_CREATE_OPTIONS_VERSION: u32 = 1;
pub const FFF_CREATE_OPTIONS_VERSION: u32 = 2;

/// Options for `fff_create_instance_with`.
///
Expand Down Expand Up @@ -57,7 +57,11 @@ pub struct FffCreateOptions {
/// Allow indexing the user's home directory. Same trade-off as
/// `enable_fs_root_scanning`.
pub enable_home_dir_scanning: bool,
// ----- new version 2+ fields go here, ALWAYS appended -----
// ----- v2 fields -----
/// Track files inside git submodules. When true, submodule contents are
/// indexed and their git status reflected in results.
pub support_submodules: bool,
// ----- new version 3+ fields go here, ALWAYS appended -----
}

impl FffCreateOptions {
Expand All @@ -79,6 +83,7 @@ impl FffCreateOptions {
cache_budget_max_file_size: 0,
enable_fs_root_scanning: false,
enable_home_dir_scanning: false,
support_submodules: true,
}
}
}
Expand Down Expand Up @@ -804,6 +809,7 @@ mod options_layout_tests {
fn fff_create_options_layout_is_stable_64bit() {
assert_eq!(size_of::<FffCreateOptions>(), 88);
assert_eq!(align_of::<FffCreateOptions>(), 8);
assert_eq!(offset_of!(FffCreateOptions, support_submodules), 82);

assert_eq!(offset_of!(FffCreateOptions, version), 0);
assert_eq!(offset_of!(FffCreateOptions, base_path), 8);
Expand Down
51 changes: 49 additions & 2 deletions crates/fff-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,7 @@ pub unsafe extern "C" fn fff_create_instance_with(opts: *const FffCreateOptions)
follow_symlinks: false,
enable_fs_root_scanning: opts.enable_fs_root_scanning,
enable_home_dir_scanning: opts.enable_home_dir_scanning,
support_submodules: opts.support_submodules,
},
) {
return FffResult::err(&format!("Failed to init file picker: {}", e));
Expand All @@ -310,6 +311,50 @@ pub unsafe extern "C" fn fff_create_instance_with(opts: *const FffCreateOptions)
FffResult::ok_handle(fff_handle)
}

/// Create a new file finder instance (v3, with submodule support toggle).
///
/// Identical to [`fff_create_instance2`] except for the trailing
/// `support_submodules` flag. When `true` (recommended default), submodule
/// directories are walked and reported in git status. When `false`, submodule
/// paths are skipped during traversal and excluded from git status.
///
/// ## Safety
/// String parameters must be valid null-terminated UTF-8 or NULL.
#[unsafe(no_mangle)]
#[allow(clippy::too_many_arguments)]
pub unsafe extern "C" fn fff_create_instance3(
base_path: *const c_char,
frecency_db_path: *const c_char,
history_db_path: *const c_char,
_use_unsafe_no_lock: bool,
enable_mmap_cache: bool,
enable_content_indexing: bool,
watch: bool,
ai_mode: bool,
log_file_path: *const c_char,
log_level: *const c_char,
cache_budget_max_files: u64,
cache_budget_max_bytes: u64,
cache_budget_max_file_size: u64,
support_submodules: bool,
) -> *mut FffResult {
let mut opts = FffCreateOptions::defaults();
opts.base_path = base_path;
opts.frecency_db_path = frecency_db_path;
opts.history_db_path = history_db_path;
opts.enable_mmap_cache = enable_mmap_cache;
opts.enable_content_indexing = enable_content_indexing;
opts.watch = watch;
opts.ai_mode = ai_mode;
opts.log_file_path = log_file_path;
opts.log_level = log_level;
opts.cache_budget_max_files = cache_budget_max_files;
opts.cache_budget_max_bytes = cache_budget_max_bytes;
opts.cache_budget_max_file_size = cache_budget_max_file_size;
opts.support_submodules = support_submodules;
unsafe { fff_create_instance_with(&opts as *const FffCreateOptions) }
}

/// Calling-convention adapter for [`fff_create_instance_with`].
///
/// Same logic, but takes the [`FffCreateOptions`] struct **by value**. This
Expand Down Expand Up @@ -1018,7 +1063,7 @@ pub unsafe extern "C" fn fff_restart_index(
Err(e) => return FffResult::err(&format!("Failed to acquire file picker lock: {}", e)),
};

let (warmup_caches, content_indexing, watch, mode, fs_root, home_dir) =
let (warmup_caches, content_indexing, watch, mode, fs_root, home_dir, support_submodules) =
if let Some(ref picker) = *guard {
(
picker.has_mmap_cache(),
Expand All @@ -1027,9 +1072,10 @@ pub unsafe extern "C" fn fff_restart_index(
picker.mode(),
picker.fs_root_scanning_enabled(),
picker.home_dir_scanning_enabled(),
picker.has_submodule_support(),
)
} else {
(false, true, true, FFFMode::default(), false, false)
(false, true, true, FFFMode::default(), false, false, true)
};

drop(guard);
Expand All @@ -1047,6 +1093,7 @@ pub unsafe extern "C" fn fff_restart_index(
follow_symlinks: false,
enable_fs_root_scanning: fs_root,
enable_home_dir_scanning: home_dir,
support_submodules,
},
) {
Ok(()) => FffResult::ok_empty(),
Expand Down
24 changes: 17 additions & 7 deletions crates/fff-core/src/background_watcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ impl BackgroundWatcher {
mode: FFFMode,
enable_fs_root_scanning: bool,
enable_home_dir_scanning: bool,
support_submodules: bool,
trace_span: tracing::Span,
) -> Result<Self, Error> {
info!(
Expand Down Expand Up @@ -94,6 +95,7 @@ impl BackgroundWatcher {
mode,
use_recursive,
watch_tx_for_debouncer,
support_submodules,
)?;

info!("Background file watcher initialized successfully");
Expand Down Expand Up @@ -148,6 +150,7 @@ impl BackgroundWatcher {
&strong_picker,
&owner_frecency,
&owner_git_workdir,
support_submodules,
);

// Transient strong ref drops here, back
Expand All @@ -165,6 +168,7 @@ impl BackgroundWatcher {
})
}

#[allow(clippy::too_many_arguments)]
fn create_debouncer(
base_path: PathBuf,
git_workdir: Option<PathBuf>,
Expand All @@ -173,6 +177,7 @@ impl BackgroundWatcher {
mode: FFFMode,
use_recursive: bool,
watch_tx: mpsc::Sender<PathBuf>,
support_submodules: bool,
) -> Result<Debouncer, Error> {
let config = Config::default()
// do not follow symlinks as then notifiers spawns a bunch of events for symlinked
Expand Down Expand Up @@ -215,6 +220,7 @@ impl BackgroundWatcher {
&strong_picker,
&shared_frecency,
mode,
support_submodules,
);

// every new directory creates had to be reflected in the picker state
Expand Down Expand Up @@ -402,6 +408,7 @@ fn handle_debounced_events(
shared_picker: &SharedFilePicker,
shared_frecency: &SharedFrecency,
mode: FFFMode,
support_submodules: bool,
) -> Vec<PathBuf> {
// this will be called very often, we have to minimiy the lock time for file picker
let repo = git_workdir.as_ref().and_then(|p| Repository::open(p).ok());
Expand Down Expand Up @@ -677,6 +684,7 @@ fn handle_debounced_events(
let status = match GitStatusCache::git_status_for_paths(
&repo,
&files_to_update_git_status,
support_submodules,
) {
Ok(s) => s,
Err(e) => {
Expand Down Expand Up @@ -708,6 +716,7 @@ fn track_files_from_new_directories(
shared_picker: &SharedFilePicker,
shared_frecency: &SharedFrecency,
git_workdir: &Option<PathBuf>,
support_submodules: bool,
) {
let Ok(entries) = std::fs::read_dir(dir) else {
return;
Expand Down Expand Up @@ -744,13 +753,14 @@ fn track_files_from_new_directories(
}

if let Some(repo) = repo.as_ref() {
let status = match GitStatusCache::git_status_for_paths(repo, &files_to_add) {
Ok(status) => status,
Err(e) => {
tracing::error!(?e, "inject_existing_files: git status query failed");
return;
}
};
let status =
match GitStatusCache::git_status_for_paths(repo, &files_to_add, support_submodules) {
Ok(status) => status,
Err(e) => {
tracing::error!(?e, "inject_existing_files: git status query failed");
return;
}
};

if let Ok(mut guard) = shared_picker.write()
&& let Some(ref mut picker) = *guard
Expand Down
Loading
Loading