Skip to content

fix(tui): bound @-completion file-index walk with a wall-clock budget (#4365)#4367

Open
LeoLin990405 wants to merge 1 commit into
Hmbown:mainfrom
LeoLin990405:fix/issue-4365-completion-walk-time-budget
Open

fix(tui): bound @-completion file-index walk with a wall-clock budget (#4365)#4367
LeoLin990405 wants to merge 1 commit into
Hmbown:mainfrom
LeoLin990405:fix/issue-4365-completion-walk-time-budget

Conversation

@LeoLin990405

Copy link
Copy Markdown
Contributor

Problem

Fixes #4365@-mentioning a large non-workspace directory freezes the TUI (reporter saw an unresponsive terminal on pwsh7). The mention completion pulls the full subtree eagerly.

Root cause

The fuzzy-completion index (Workspace::build_file_index in working_set.rs) is rebuilt synchronously on the input thread whenever the walk root changes — which is every keystroke while typing an @-path outside the workspace. FILE_INDEX_MAX_ENTRIES = 50_000 caps the result size but not the time to reach it: a large external tree with no .gitignore can spend seconds walking before it hits 50k entries, and that whole time the UI is blocked.

Fix

Add a 150ms wall-clock budget (COMPLETION_WALK_BUDGET) checked alongside the existing entry cap in every walk loop of build_file_index. Once the budget is exceeded the build returns the partial index instead of continuing — partial completions are far better than an unresponsive terminal, and the next keystroke re-walks (from cache when the root is unchanged). The dot-dir and local_reference_paths passes are skipped once over budget so they can't reintroduce the freeze.

build_file_index is split into build_file_index_with_budget(budget) so the behavior is unit-testable; the public path calls it with COMPLETION_WALK_BUDGET, so nothing else changes for normal-sized workspaces (the budget is a no-op there, same as the entry cap).

Testing

  • New build_file_index_respects_time_budget: a generous budget indexes every file; a zero budget stops the walk early (returns fewer entries) — proving the build can't block. Deterministic, no reliance on a real slow filesystem.
  • cargo clippy -p codewhale-tui --all-features clean; cargo test -p codewhale-tui --all-features working_set green (44 passed).

Note: I couldn't reproduce the actual freeze on macOS (the report is pwsh7/Windows on a huge external tree), but the time budget is platform-agnostic hardening of the exact synchronous walk named in the issue. Happy to adjust the 150ms value or the approach (e.g. debounce until the path is committed, per the reporter's suggestion) if you'd prefer.

…Hmbown#4365)

The @-mention fuzzy-completion index is built synchronously on the input
thread whenever the walk root changes, e.g. @-mentioning a non-workspace
directory. The existing FILE_INDEX_MAX_ENTRIES cap bounds the result
size but not the time to reach it: walking a large external tree with no
.gitignore can spend seconds before hitting 50k entries, freezing the
TUI (pwsh7 in the report).

Add a 150ms wall-clock budget checked alongside the entry cap in every
walk loop of build_file_index; over budget, return the partial index
rather than blocking. Partial completions beat an unresponsive terminal,
and the next keystroke re-walks from cache. Extract build_file_index_with_budget
so the budget is unit-testable, and add a deterministic test.
@LeoLin990405 LeoLin990405 requested a review from Hmbown as a code owner July 14, 2026 06:00
@github-actions

Copy link
Copy Markdown

Thanks @LeoLin990405 for taking the time to contribute.

This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant recurring PR access by commenting /lgtm on a pull request.

@Hmbown Hmbown left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for taking on #4365. I cannot merge this version yet because the wall-clock check happens inside each for body, after the iterator has already completed next(). A single slow filesystem read can therefore still block the input thread past the budget. local_reference_paths(...) is also materialized before its loop can check elapsed time, and a partial cache miss may repeat the synchronous walk on later input.

Please move completion discovery off the UI/input thread (with serialized scans and stale-result protection), or make the traversal itself genuinely interruptible before a blocking next(). The regression should prove that key handling stays responsive while discovery is stalled, in addition to checking partial results. The current Lint and Windows jobs are also red. I am happy to re-review a focused update, and your contribution will retain credit when the complete fix lands.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

@ file watcher scans entire directory tree eagerly, causing terminal lag/freeze on large paths

2 participants