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
13 changes: 8 additions & 5 deletions 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 @@ -100,10 +100,7 @@ typedef struct FffCreateOptions {
*/
bool ai_mode;
/**
* Path-shape hint for the per-session log file. Each call writes a fresh
* sibling file `<stem>+<UTC-timestamp>+<pid>.<ext>` next to this path.
* The literal path is never written to, so concurrent processes get
* unique per-pid files. NULL/empty to skip log init.
* Tracing log file path. NULL/empty to skip log init.
*/
const char *log_file_path;
/**
Expand Down Expand Up @@ -133,6 +130,12 @@ typedef struct FffCreateOptions {
* `enable_fs_root_scanning`.
*/
bool enable_home_dir_scanning;
/**
* Follow symlinks during scan and watcher walks. Off by default —
* enabling this without external loop protection can wedge the watcher
* on cyclic symlink graphs. Caller is responsible for the trade-off.
*/
bool follow_symlinks;
} FffCreateOptions;

/**
Expand Down
11 changes: 9 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,12 @@ 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 -----
/// Follow symlinks during scan and watcher walks. Off by default —
/// enabling this without external loop protection can wedge the watcher
/// on cyclic symlink graphs. Caller is responsible for the trade-off.
pub follow_symlinks: bool,
// ----- new version 3+ fields go here, ALWAYS appended -----
}

impl FffCreateOptions {
Expand All @@ -79,6 +84,7 @@ impl FffCreateOptions {
cache_budget_max_file_size: 0,
enable_fs_root_scanning: false,
enable_home_dir_scanning: false,
follow_symlinks: false,
}
}
}
Expand Down Expand Up @@ -820,5 +826,6 @@ mod options_layout_tests {
assert_eq!(offset_of!(FffCreateOptions, cache_budget_max_file_size), 72);
assert_eq!(offset_of!(FffCreateOptions, enable_fs_root_scanning), 80);
assert_eq!(offset_of!(FffCreateOptions, enable_home_dir_scanning), 81);
assert_eq!(offset_of!(FffCreateOptions, follow_symlinks), 82);
}
}
9 changes: 5 additions & 4 deletions crates/fff-c/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ pub unsafe extern "C" fn fff_create_instance_with(opts: *const FffCreateOptions)
watch: opts.watch,
mode,
cache_budget,
follow_symlinks: false,
follow_symlinks: opts.version >= 2 && opts.follow_symlinks,
enable_fs_root_scanning: opts.enable_fs_root_scanning,
enable_home_dir_scanning: opts.enable_home_dir_scanning,
},
Expand Down Expand Up @@ -1018,7 +1018,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, follow_symlinks) =
if let Some(ref picker) = *guard {
(
picker.has_mmap_cache(),
Expand All @@ -1027,9 +1027,10 @@ pub unsafe extern "C" fn fff_restart_index(
picker.mode(),
picker.fs_root_scanning_enabled(),
picker.home_dir_scanning_enabled(),
picker.follows_symlinks(),
)
} else {
(false, true, true, FFFMode::default(), false, false)
(false, true, true, FFFMode::default(), false, false, false)
};

drop(guard);
Expand All @@ -1044,7 +1045,7 @@ pub unsafe extern "C" fn fff_restart_index(
watch,
mode,
cache_budget: None,
follow_symlinks: false,
follow_symlinks,
enable_fs_root_scanning: fs_root,
enable_home_dir_scanning: home_dir,
},
Expand Down
7 changes: 6 additions & 1 deletion crates/fff-mcp/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ pub(crate) struct Args {
#[arg(long = "max-cached-files", env = "FFF_MAX_CACHED_FILES")]
max_cached_files: Option<usize>,

/// Follow symlinks during scan and watcher walks. Off by default —
/// enabling on cyclic symlink layouts can wedge the watcher.
#[arg(long = "follow-symlinks")]
follow_symlinks: bool,

/// Run a health check and print diagnostic information, then exit.
#[arg(long = "healthcheck")]
pub(crate) healthcheck: bool,
Expand Down Expand Up @@ -262,7 +267,7 @@ async fn main() -> Result<(), Box<dyn std::error::Error>> {
cache_budget: args
.max_cached_files
.map(fff::ContentCacheBudget::new_for_repo),
follow_symlinks: false,
follow_symlinks: args.follow_symlinks,
..Default::default()
},
)
Expand Down
11 changes: 7 additions & 4 deletions crates/fff-python/src/finder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ impl FileFinder {
cache_budget_max_file_size=0,
enable_fs_root_scanning=false,
enable_home_dir_scanning=false,
follow_symlinks=false,
))]
#[allow(clippy::too_many_arguments)]
fn new(
Expand All @@ -194,6 +195,7 @@ impl FileFinder {
cache_budget_max_file_size: u64,
enable_fs_root_scanning: bool,
enable_home_dir_scanning: bool,
follow_symlinks: bool,
) -> PyResult<Self> {
let shared_picker = SharedFilePicker::default();
let shared_frecency = SharedFrecency::default();
Expand Down Expand Up @@ -243,7 +245,7 @@ impl FileFinder {
cache_budget_max_bytes,
cache_budget_max_file_size,
),
follow_symlinks: false,
follow_symlinks,
enable_fs_root_scanning,
enable_home_dir_scanning,
},
Expand Down Expand Up @@ -742,7 +744,7 @@ impl FileFinder {
}
let canonical = fff::path_utils::canonicalize(&new_path).map_err(py_err)?;

let (warmup_caches, content_indexing, watch, mode, fs_root, home_dir) = {
let (warmup_caches, content_indexing, watch, mode, fs_root, home_dir, follow_symlinks) = {
let guard = picker.read().map_err(py_err)?;
if let Some(ref picker) = *guard {
(
Expand All @@ -752,9 +754,10 @@ impl FileFinder {
picker.mode(),
picker.fs_root_scanning_enabled(),
picker.home_dir_scanning_enabled(),
picker.follows_symlinks(),
)
} else {
(false, true, true, FFFMode::default(), false, false)
(false, true, true, FFFMode::default(), false, false, false)
}
};

Expand All @@ -772,7 +775,7 @@ impl FileFinder {
cache_budget_max_bytes,
cache_budget_max_file_size,
),
follow_symlinks: false,
follow_symlinks,
enable_fs_root_scanning: fs_root,
enable_home_dir_scanning: home_dir,
},
Expand Down
16 changes: 7 additions & 9 deletions packages/fff-bun/src/fff-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,15 @@ export interface InitOptions {
/** Override for the per-file byte cap in the content cache. */
cacheBudgetMaxFileSize?: number;
/**
* Allow indexing the filesystem root (`/`). Off by default — root is
* rarely the intended target and floods the watcher with churn-prone
* events. Setting this true is opt-in and the caller is responsible for
* the resulting fs-event volume.
*/
* Allow indexing the filesystem root (`/`). Off by default, having fff instance at the large folder
* will generally require file watcher
* */

enableFsRootScanning?: boolean;
/**
* Allow indexing the user's home directory. Same trade-off as
* `enableFsRootScanning`.
*/
/** Allow indexing the user's home directory. Same trade-off as `enableFsRootScanning`. */
enableHomeDirScanning?: boolean;
/** Follow symlinks for directories */
followSymlinks?: boolean;
}

/**
Expand Down
16 changes: 7 additions & 9 deletions packages/fff-node/src/fff-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,17 +97,15 @@ export interface InitOptions {
/** Override for the per-file byte cap in the content cache. */
cacheBudgetMaxFileSize?: number;
/**
* Allow indexing the filesystem root (`/`). Off by default — root is
* rarely the intended target and floods the watcher with churn-prone
* events. Setting this true is opt-in and the caller is responsible for
* the resulting fs-event volume.
*/
* Allow indexing the filesystem root (`/`). Off by default, having fff instance at the large folder
* will generally require file watcher
* */

enableFsRootScanning?: boolean;
/**
* Allow indexing the user's home directory. Same trade-off as
* `enableFsRootScanning`.
*/
/** Allow indexing the user's home directory. Same trade-off as `enableFsRootScanning`. */
enableHomeDirScanning?: boolean;
/** Follow symlinks for directories */
followSymlinks?: boolean;
}

/**
Expand Down
5 changes: 4 additions & 1 deletion packages/fff-node/src/ffi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,11 @@ const FFF_CREATE_OPTIONS_STRUCT = {
cache_budget_max_file_size: DataType.U64,
enable_fs_root_scanning: DataType.U8,
enable_home_dir_scanning: DataType.U8,
follow_symlinks: DataType.U8,
};

// ALWAYS KEEP IN SYNC WITH fff.h
const FFF_CREATE_OPTIONS_VERSION = 1;
const FFF_CREATE_OPTIONS_VERSION = 2;

/** Grep mode constants matching the C API (u8). */
const GREP_MODE_PLAIN = 0;
Expand Down Expand Up @@ -359,6 +360,7 @@ export function ffiCreate(
cacheBudgetMaxFileSize: number,
enableFsRootScanning: boolean,
enableHomeDirScanning: boolean,
followSymlinks: boolean,
): Result<NativeHandle> {
loadLibrary();

Expand All @@ -378,6 +380,7 @@ export function ffiCreate(
cache_budget_max_file_size: cacheBudgetMaxFileSize,
enable_fs_root_scanning: enableFsRootScanning ? 1 : 0,
enable_home_dir_scanning: enableHomeDirScanning ? 1 : 0,
follow_symlinks: followSymlinks ? 1 : 0,
};

const rawPtr = load({
Expand Down
1 change: 1 addition & 0 deletions packages/fff-node/src/finder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ export class FileFinder implements FileFinderApi {
options.cacheBudgetMaxFileSize ?? 0,
options.enableFsRootScanning ?? false,
options.enableHomeDirScanning ?? false,
options.followSymlinks ?? false,
);

if (!result.ok) {
Expand Down
5 changes: 1 addition & 4 deletions packages/pi-fff/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -944,10 +944,7 @@ export default function fffExtension(pi: ExtensionAPI) {
if (!arg) {
const mode = getMode();
const flag = pi.getFlag("fff-mode") ?? "unset";
ctx.ui.notify(
`Current mode: '${mode}' (flag: ${flag})`,
"info",
);
ctx.ui.notify(`Current mode: '${mode}' (flag: ${flag})`, "info");
return;
}

Expand Down
34 changes: 16 additions & 18 deletions packages/shared/fff-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,23 +43,17 @@ export interface InitOptions {
frecencyDbPath?: string;
/** Path to query history database (optional, omit to skip query tracker initialization) */
historyDbPath?: string;
/**
* @deprecated No-op. The no-lock LMDB flags showed no measurable win under
* realistic contention and are now ignored. Kept for source-compat.
*/
/** @deprecated no-op */
useUnsafeNoLock?: boolean;
/**
* Disable mmap cache warmup after the initial scan. When mmap cache is
* enabled (the default), the first grep search is as fast as subsequent
* ones at the cost of a longer scan time and higher initial memory usage.
* (default: false)
*/
disableMmapCache?: boolean;
/**
* Disable the content index built after the initial scan.
* Content indexing enables faster content-aware filtering during grep.
* When omitted, follows `disableMmapCache` for backward compatibility.
* (default: follows `disableMmapCache`)
*/
disableContentIndexing?: boolean;
/**
Expand Down Expand Up @@ -91,17 +85,15 @@ export interface InitOptions {
/** Override for the per-file byte cap in the content cache. */
cacheBudgetMaxFileSize?: number;
/**
* Allow indexing the filesystem root (`/`). Off by default — root is
* rarely the intended target and floods the watcher with churn-prone
* events. Setting this true is opt-in and the caller is responsible for
* the resulting fs-event volume.
*/
* Allow indexing the filesystem root (`/`).
* Off by default, having fff instance at the large folder will generally require
* file watcher and indexing which will consume a lot of resources if performed uncontrolled
**/
enableFsRootScanning?: boolean;
/**
* Allow indexing the user's home directory. Same trade-off as
* `enableFsRootScanning`.
*/
/** Allow indexing the user's home directory. Same trade-off as `enableFsRootScanning`. */
enableHomeDirScanning?: boolean;
/** Follow symlinks for directories */
followSymlinks?: boolean;
}

/**
Expand Down Expand Up @@ -547,10 +539,16 @@ export interface FileFinderApi {
glob(pattern: string, options?: GlobOptions): Result<SearchResult>;

/** Fuzzy directory search. */
directorySearch(query: string, options?: DirSearchOptions): Result<DirSearchResult>;
directorySearch(
query: string,
options?: DirSearchOptions,
): Result<DirSearchResult>;

/** Fuzzy search over files and directories interleaved by score. */
mixedSearch(query: string, options?: SearchOptions): Result<MixedSearchResult>;
mixedSearch(
query: string,
options?: SearchOptions,
): Result<MixedSearchResult>;

/** Content search (live grep). */
grep(query: string, options?: GrepOptions): Result<GrepResult>;
Expand Down
Loading