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
The user experiences a frozen UI during the Svelte reactivity step because assigning large arrays to reactive state triggers expensive internal tracking.
32
+
The user experiences a frozen UI during the Svelte reactivity step because assigning large arrays to reactive state
33
+
triggers expensive internal tracking.
32
34
33
35
---
34
36
@@ -115,61 +117,62 @@ Time →
115
117
116
118
### Key design decisions
117
119
118
-
**FileDataStore per pane:**
119
-
Each pane has its own store because:
120
+
**FileDataStore per pane:** Each pane has its own store because:
121
+
120
122
- Panes may show the same folder but with different sorting/filtering
121
123
- Simplifies state management
122
124
123
-
**Item ID = path (not filename):**
124
-
Path is guaranteed unique and handles future cross-directory caching.
125
+
**Item ID = path (not filename):** Path is guaranteed unique and handles future cross-directory caching.
125
126
126
-
**extendedMetadataLoaded flag:**
127
-
Each FileEntry has a flag indicating whether extended metadata is loaded. UI can show placeholder or partial data until extended data arrives.
127
+
**extendedMetadataLoaded flag:** Each FileEntry has a flag indicating whether extended metadata is loaded. UI can show
128
+
placeholder or partial data until extended data arrives.
128
129
129
130
**Hidden files filtering:**
130
-
Cannot know exact visible count until all files are loaded (some may be hidden). Handle gracefully—show what we have, update count as data arrives.
131
+
Cannot know exact visible count until all files are loaded (some may be hidden). Handle gracefully—show what we have,
132
+
update count as data arrives.
131
133
132
-
**Chunk size:**
133
-
5000 files per chunk balances IPC overhead vs. responsiveness. May tune later.
134
+
**Chunk size:** 5000 files per chunk balances IPC overhead vs. responsiveness. May tune later.
134
135
135
-
**Sorting placeholders:**
136
-
Backend sorting (when implemented) happens before chunking so first chunk contains the "best" files for the current sort order.
136
+
**Sorting placeholders:** Backend sorting (when implemented) happens before chunking so first chunk contains the "best"
137
+
files for the current sort order.
137
138
138
139
---
139
140
140
141
## Cancellation
141
142
142
143
**Current state:**
144
+
143
145
- ✅ Frontend: `loadGeneration` counter discards stale results
144
146
- ❌ Backend: Rust `list_directory()` runs to completion even if user navigates away
145
147
146
-
**Future optimization:** Add cancellation flag checked periodically in Rust loop. Not critical for UX since UI doesn't freeze.
148
+
**Future optimization:** Add cancellation flag checked periodically in Rust loop. Not critical for UX since UI doesn't
149
+
freeze.
147
150
148
151
---
149
152
150
153
## Key clues
151
154
152
155
Files and patterns to understand before implementing:
153
156
154
-
| File | Why it matters |
155
-
|------|----------------|
156
-
|`src/lib/file-explorer/FilePane.svelte`| Current loading logic lives here. Look for `loadDirectory()`, `allFilesRaw`, `filesVersion`. This is what you're replacing. |
157
-
|`src/lib/file-explorer/BriefList.svelte`| Virtual scroll for Brief mode. Already calculates `startIndex`/`endIndex`. You'll modify it to request visible range from the store. |
158
-
|`src/lib/file-explorer/FullList.svelte`| Virtual scroll for Full mode. Same pattern as BriefList. |
159
-
|`src-tauri/src/file_system/operations.rs`| Rust session management (`list_directory_start`, `list_directory_next`, etc.). This is where streaming logic lives. |
160
-
|`src-tauri/src/commands/file_system.rs`| Tauri command wrappers that call `operations.rs`. New commands must be added here. |
161
-
|`src-tauri/src/lib.rs`| Command registration. New Rust commands must be registered in the `invoke_handler`. |
162
-
|`src/lib/tauri-commands.ts`| Frontend TypeScript wrappers for Tauri commands. Add new command wrappers here. |
163
-
|`src/lib/file-explorer/types.ts`|`FileEntry` type definition. Add `extendedMetadataLoaded` flag here. |
|`src/lib/file-explorer/FilePane.svelte`| Current loading logic lives here. Look for `loadDirectory()`, `allFilesRaw`, `filesVersion`. This is what you're replacing.|
160
+
|`src/lib/file-explorer/BriefList.svelte`| Virtual scroll for Brief mode. Already calculates `startIndex`/`endIndex`. You'll modify it to request visible range from the store. |
161
+
|`src/lib/file-explorer/FullList.svelte`| Virtual scroll for Full mode. Same pattern as BriefList.|
162
+
|`src-tauri/src/file_system/operations.rs`| Rust session management (`list_directory_start`, `list_directory_next`, etc.). This is where streaming logic lives. |
163
+
|`src-tauri/src/commands/file_system.rs`| Tauri command wrappers that call `operations.rs`. New commands must be added here.|
164
+
|`src-tauri/src/lib.rs`| Command registration. New Rust commands must be registered in the `invoke_handler`.|
165
+
|`src/lib/tauri-commands.ts`| Frontend TypeScript wrappers for Tauri commands. Add new command wrappers here.|
166
+
|`src/lib/file-explorer/types.ts`|`FileEntry` type definition. Add `extendedMetadataLoaded` flag here.|
164
167
165
168
**Where to put `FileDataStore`:** Create it at `src/lib/file-explorer/FileDataStore.ts`.
166
169
167
-
**Verification:** Run `./scripts/check.sh` after each phase to ensure nothing is broken (runs rustfmt, clippy, tests, eslint, svelte-check, etc.).
170
+
**Verification:** Run `./scripts/check.sh` after each phase to ensure nothing is broken (runs rustfmt, clippy, tests,
171
+
eslint, svelte-check, etc.).
168
172
169
173
---
170
174
171
175
## Related documents
172
176
173
177
-[ADR-009: Non-reactive file data store](../adr/009-non-reactive-file-store.md) — why we need FileDataStore
174
178
-[2025-12-28-dir-load-bench-findings.md](./2025-12-28-dir-load-bench-findings.md) — benchmark data
0 commit comments