You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- Add search scope field: comma-separated folder paths with `!` prefix for excludes, wildcard support in bare names, quoting/escaping for commas
- Ancestor-walk filtering via `parent_id` chain in the in-memory index, with pre-resolved include path IDs and compiled exclude patterns for O(1) per-level checks
- `parse_scope()` parser, `ScopeFilter` with `prepare_scope_filter()`, `parse_search_scope` IPC command
- Scope row in SearchDialog between pattern and filter rows: text input, info `(i)` tooltip with syntax examples, `⌥F` (current folder) and `⌥D` (entire drive) buttons
- Improved AI system prompt: glob-only `*`/`?` limitation (fixes `{a,b}` brace expansion failures), naming convention awareness, category→extension mapping, size inference, macOS screenshot naming, default code exclusions (`node_modules`, `.git`, etc.)
- AI now returns `searchPaths`/`excludeDirs` fields, auto-populating the scope field
- MCP `search` and `ai_search` tools accept optional `scope` parameter
|`search.rs`| Drive search |`prepare_search_index`, `search_files`, `release_search_index`, `translate_search_query`. Thin wrappers over `indexing::search` module. Post-filters directory sizes after `fill_directory_sizes`. |
27
+
|`search.rs`| Drive search |`prepare_search_index`, `search_files`, `release_search_index`, `translate_search_query`, `parse_search_scope`. Thin wrappers over `indexing::search` module. Post-filters directory sizes after `fill_directory_sizes`. |
28
28
|`sync_status.rs`| Cloud sync status |`get_sync_status` — macOS delegates to `file_system::sync_status`; non-macOS returns empty map via `#[cfg]` on the function itself (not the module). |
Copy file name to clipboardExpand all lines: apps/desktop/src-tauri/src/indexing/CLAUDE.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ Full design: `docs/specs/drive-indexing/plan.md`
21
21
-**reconciler.rs** -- Buffers FSEvents during scan (capped at 500K events; overflow sets `buffer_overflow` flag forcing full rescan), replays after scan completes using event IDs to skip stale events. Processes live events for file creates/removes/modifies using integer-keyed write messages (`UpsertEntryV2`, `DeleteEntryById`, `DeleteSubtreeById`, `PropagateDeltaById`). Resolves filesystem paths to entry IDs via `store::resolve_path()` using a read connection passed by callers. Key functions (`process_fs_event`, `emit_dir_updated`) are `pub(super)` so `mod.rs` can call them directly during cold-start replay. `reconcile_subtree()` handles MustScanSubDirs by diffing filesystem vs DB directory-by-directory instead of delete-then-reinsert, making it safe to interrupt at any point.
-**verifier.rs** -- Per-navigation background readdir diff. On each directory navigation, `trigger_verification()` (called from `streaming.rs` and `operations.rs` after enrichment) is fully fire-and-forget: it spawns a task that acquires the `INDEXING` lock (never blocking the navigation thread), checks dedup/debounce via static `VerifierState` (in-flight set + recent timestamps), then spawns a second async task that: (1) reads DB children via `ReadPool`, (2) reads disk via `read_dir` (filtering through `scanner::should_exclude`), (3) diffs by normalized name, sending `UpsertEntryV2`/`DeleteEntryById`/`DeleteSubtreeById`/`PropagateDeltaById` corrections to the writer. New directories are flushed then scanned via `scan_subtree` with delta propagation. Debounce: 30s per path, max 2 concurrent verifications. Only runs after initial scan is complete (checks `scanning` flag). `invalidate()` clears state on shutdown/clear.
24
-
- **search.rs** -- In-memory search index for whole-drive file search. Lazily loads all entries from the index DB into a `Vec<SearchEntry>` for fast parallel scanning with rayon. Filenames are arena-allocated: all names are concatenated into a single `SearchIndex.names: String` buffer, and each `SearchEntry` stores `name_offset: u32` + `name_len: u16` instead of an owned `String`. During load, `row.get_ref(col).as_str()` borrows directly from SQLite's internal buffer (zero per-row heap allocations), then pushes into the arena. `name_folded` is NOT stored in the search index — instead, the search pattern is NFD-normalized at query time on macOS (APFS filenames are already NFD). `SearchIndex::name(&self, entry)` retrieves a `&str` slice from the arena. `search()` is a pure function: compiles glob/regex patterns, parallel-filters entries, sorts by recency. Global `SEARCH_INDEX` state with `Arc<SearchIndex>`, idle timer (5 min after dialog close), backstop timer (10 min with no activity), and load cancellation via `AtomicBool` checked every 100K rows. `WRITER_GENERATION` in writer.rs tracks mutations; stale indexes are detected on search. IPC commands in `commands/search.rs`: `prepare_search_index` (emits `search-index-ready` event when load completes), `search_files`, `release_search_index`, `translate_search_query` (AI natural language → structured query).
24
+
- **search.rs** -- In-memory search index for whole-drive file search. Lazily loads all entries from the index DB into a `Vec<SearchEntry>` for fast parallel scanning with rayon. Filenames are arena-allocated: all names are concatenated into a single `SearchIndex.names: String` buffer, and each `SearchEntry` stores `name_offset: u32` + `name_len: u16` instead of an owned `String`. During load, `row.get_ref(col).as_str()` borrows directly from SQLite's internal buffer (zero per-row heap allocations), then pushes into the arena. `name_folded` is NOT stored in the search index — instead, the search pattern is NFD-normalized at query time on macOS (APFS filenames are already NFD). `SearchIndex::name(&self, entry)` retrieves a `&str` slice from the arena. `search()` is a pure function: compiles glob/regex patterns, parallel-filters entries, sorts by recency. Global `SEARCH_INDEX` state with `Arc<SearchIndex>`, idle timer (5 min after dialog close), backstop timer (10 min with no activity), and load cancellation via `AtomicBool` checked every 100K rows. `WRITER_GENERATION` in writer.rs tracks mutations; stale indexes are detected on search. Scope filtering: `SearchQuery` accepts optional `include_paths` (absolute paths — search only within these subtrees) and `exclude_dir_names` (directory names/patterns to exclude at any depth). `prepare_scope_filter()` pre-resolves include paths to entry IDs and compiles exclude patterns as regexes. `ScopeFilter::matches()` walks the ancestor chain via `id_to_index` (O(1) per level) after all other filters pass. `parse_scope()` parses a user-typed comma-separated scope string (with quoting, escaping, `~` expansion, `!` excludes) into a `ParsedScope` struct. IPC commands in `commands/search.rs`: `prepare_search_index` (emits `search-index-ready` event when load completes), `search_files`, `release_search_index`, `translate_search_query` (AI natural language → structured query), `parse_search_scope` (scope string → structured `ParsedScope`).
25
25
26
26
IPC commands in `commands/indexing.rs` -- thin wrappers over `IndexManager` methods.
0 commit comments