Refactor file explorer operations to use async background tasks#1228
Open
Refactor file explorer operations to use async background tasks#1228
Conversation
Three layered changes to prevent the editor from freezing when the remote filesystem becomes unresponsive: 1. Channel-level request timeout (30s): Wrap response waits in AgentChannel::request() and request_with_data() with tokio::time::timeout(30s), returning ChannelError::Timeout on expiry. This protects all remote operations as a safety net. 2. Async poll_file_tree_changes: Replace the synchronous polling loop with a background task that checks directory mtimes via FsManager::get_single_metadata() (with a 5s batch timeout), then sends changed dirs back via AsyncMessage::FileTreePollResult. The main thread spawns async refreshes for changed dirs. 3. Async file explorer operations: Replace all 6 block_on calls in file_explorer.rs with spawned tokio tasks. toggle_node takes the FileTreeView, runs the toggle async, and sends it back via FileExplorerToggleComplete. Post-mutation refreshes (after create, delete, rename) use spawn_file_explorer_refresh() helper. The mutations themselves remain synchronous since they're one-shot user operations protected by the channel timeout. The code path is identical for local and remote filesystems — only the underlying FileSystem trait implementation differs. https://claude.ai/code/session_01Jy9LQt7vBeSgvSRkJ3nTDb
The async refactor moved refresh_node to background tasks but lost the post-refresh logic: re-selecting next node after delete and navigating to the renamed path after rename. Add FileExplorerRefreshContext to carry operation context through the async message, and restore the post-refresh actions in the handler. Also fix 4 e2e tests to use semantic waiting (wait_until) instead of sleep+render, since the file explorer is now temporarily None during async refresh. https://claude.ai/code/session_01Jy9LQt7vBeSgvSRkJ3nTDb
poll_file_changes was calling filesystem.metadata() synchronously on the main thread for every open buffer. For remote filesystems this does a blocking RPC (request_blocking → Handle::block_on), which freezes the entire editor when the remote agent is slow or unresponsive. Rewrite to match the async pattern already used by poll_file_tree_changes: snapshot paths + stored mtimes on the main thread, spawn a tokio task with a 5s timeout to check mtimes via FsManager::get_single_metadata, and deliver results back via AsyncMessage::FileChangePollResult. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…r bug Add a BlockControl mechanism to SlowFileSystem that can dynamically make all filesystem operations hang (block on a condvar) until unblocked. This enables testing editor behavior when the remote connection stops responding. Add e2e test that reproduces the bug: Editor::save() calls write_file() synchronously on the main thread, so a hung filesystem freezes the entire editor until the 30s request timeout fires. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
65ec840 to
ea02be7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR refactors file explorer operations (toggle, refresh, create, delete, rename) to use non-blocking async background tasks instead of blocking the main thread with
runtime.block_on(). Operations now spawn tokio tasks that send results back via the async message bridge, allowing the UI to remain responsive during file system operations.Key Changes
Async file explorer operations: Converted
toggle_node(),refresh_node(), and file tree polling to spawn background tasks instead of blocking onruntime.block_on()AsyncMessage::FileExplorerToggleCompleteandFileExplorerAsyncRefreshCompletespawn_file_explorer_refresh()helper method to centralize async refresh spawningNon-blocking file tree polling: Refactored
poll_file_tree_changes()to spawn a background task that checks directory mtimes asynchronouslyAsyncMessage::FileTreePollResultfor batch refreshfile_tree_poll_in_progressflag to prevent concurrent pollsSimplified file creation/deletion: Streamlined
file_explorer_new_file(),file_explorer_new_directory(), and delete operationsspawn_file_explorer_refresh()Request timeout protection: Added 30-second timeout to remote channel requests (
REQUEST_TIMEOUT)request(),request_with_data(), and related methodsNew async message handlers: Added handlers for the new async completion messages
handle_file_explorer_toggle_complete(): Restores view and handles post-toggle logic (gitignore loading, decoration rebuild)handle_file_explorer_async_refresh_complete(): Restores view and updates statushandle_file_tree_poll_result(): Processes mtime changes and spawns refreshes for changed directoriesImplementation Details
Option::take()) during async operations and restored when the background task completesfs_manager.get_single_metadata()for async metadata checkshttps://claude.ai/code/session_01Jy9LQt7vBeSgvSRkJ3nTDb