diff --git a/.jules/bolt.md b/.jules/bolt.md new file mode 100644 index 0000000..ec0a256 --- /dev/null +++ b/.jules/bolt.md @@ -0,0 +1,3 @@ +## 2024-05-18 - [Optimize Selection and Clipboard State Checks in FileList] +**Learning:** Checking state conditions using `.some()` iteratively over `selectedItems` and `clipboard.items` inside `.map()` array renders scales O(N*M), severely degrading application performance in directories with high file counts. +**Action:** Replace `.some()` inside loop checks with O(1) checks against a `Set` built utilizing `useMemo`. This prevents O(N*M) calculation complexity for item render attributes like `isSelected` and `isCut` when rendering children in large collections. \ No newline at end of file diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..c5739b7 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +ignoredBuiltDependencies: + - esbuild diff --git a/src-tauri/src/commands/permission_commands.rs b/src-tauri/src/commands/permission_commands.rs index 015722f..02982df 100644 --- a/src-tauri/src/commands/permission_commands.rs +++ b/src-tauri/src/commands/permission_commands.rs @@ -1,3 +1,4 @@ +#[cfg(target_os = "macos")] use std::process::Command; #[tauri::command] diff --git a/src-tauri/src/commands/volume_operations_commands.rs b/src-tauri/src/commands/volume_operations_commands.rs index 6fd3acb..af74e75 100644 --- a/src-tauri/src/commands/volume_operations_commands.rs +++ b/src-tauri/src/commands/volume_operations_commands.rs @@ -137,6 +137,7 @@ pub fn get_system_volumes_information() -> Vec { #[cfg(test)] mod tests { use super::*; + use crate::log_info; #[test] fn test_get_volumes() { diff --git a/src-tauri/src/search_engine/search_core.rs b/src-tauri/src/search_engine/search_core.rs index 71521f3..8175f47 100644 --- a/src-tauri/src/search_engine/search_core.rs +++ b/src-tauri/src/search_engine/search_core.rs @@ -643,6 +643,7 @@ impl SearchCore { path ); + #[allow(unused_assignments)] #[allow(unused_variables)] let mut removed_count = 1; @@ -672,11 +673,13 @@ impl SearchCore { self.remove_paths_recursive(&path_to_remove); - removed_count += 1; + #[allow(unused_assignments)] + { removed_count += 1; } } else { self.remove_path(&path_to_remove); - removed_count += 1; + #[allow(unused_assignments)] + { removed_count += 1; } } } @@ -886,6 +889,7 @@ impl SearchCore { } let mut seen: HashSet = self.results_buffer.iter().map(|(p, _)| p.clone()).collect(); + #[allow(unused_assignments)] #[allow(unused_variables)] let mut added_fuzzy = 0; @@ -893,7 +897,8 @@ impl SearchCore { if !seen.contains(&p) { seen.insert(p.clone()); self.results_buffer.push((p, s)); - added_fuzzy += 1; + #[allow(unused_assignments)] + { added_fuzzy += 1; } } } diff --git a/src-tauri/src/state/mod.rs b/src-tauri/src/state/mod.rs index 537af8e..5f8c008 100644 --- a/src-tauri/src/state/mod.rs +++ b/src-tauri/src/state/mod.rs @@ -9,7 +9,7 @@ use logging::Logger; use crate::state::searchengine_data::SearchEngineState; use meta_data::MetaDataState; use std::sync::{Arc, Mutex}; -use tauri::{Builder, Wry, Manager}; +use tauri::{Builder, Wry}; pub fn setup_app_state(app: Builder) -> Builder { // Create our shared state instances diff --git a/src/components/explorer/FileList.jsx b/src/components/explorer/FileList.jsx index c6b37ac..3b17660 100644 --- a/src/components/explorer/FileList.jsx +++ b/src/components/explorer/FileList.jsx @@ -579,6 +579,16 @@ const FileList = ({ data, isLoading, viewMode = 'grid', isSearching = false, sea handleItemClickRef.current(item, index, true); }, []); + // ⚡ Bolt: O(1) lookups for selection and clipboard state to avoid O(N*M) complexity in rendering loop + const selectedPaths = useMemo(() => { + return new Set(selectedItems.map(item => item.path)); + }, [selectedItems]); + + const cutPaths = useMemo(() => { + if (clipboard?.operation !== 'cut' || !clipboard?.items) return new Set(); + return new Set(clipboard.items.map(item => item.path)); + }, [clipboard]); + return (
{sortedItems.map((item, index) => { - const isCut = clipboard?.operation === 'cut' && - clipboard.items?.some(clipItem => clipItem.path === item.path); + const isCut = cutPaths.has(item.path); return ( selected.path === item.path)} + isSelected={selectedPaths.has(item.path)} isFocused={focusedItem && focusedItem.path === item.path} - isCut={!!isCut} + isCut={isCut} onItemClick={stableOnItemClick} onItemDoubleClick={stableOnItemDoubleClick} />