Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 26 additions & 5 deletions E2E_BUGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,32 @@ regression still fails loudly.
typescript-language-server (js/ts). This is the single most common
exception across the suite.

2. **Workspace-symbol search (`grep`) returns nothing before indexing
finishes.** clangd, vtsls, pylyzer, pyright, EmmyLua all report empty
`matches` for `workspace/symbol` queries issued immediately after startup,
since none exposes a synchronous "ready" signal — the server hasn't
indexed the workspace yet when the query fires.
2. ~~**Workspace-symbol search (`grep`) returns nothing before indexing
finishes.**~~ **Fixed for clangd, vtsls, and pyright.** clangd, vtsls,
pylyzer, pyright, and EmmyLua used to report empty `matches` for
`workspace/symbol` queries issued immediately after startup, since none
exposes a synchronous "ready" signal. This turned out to be the same
class of bug as item 3 below rather than a pure server quirk:
`run_workspace_symbol_query` (`src/commands/symbol_query.rs`) already had
a prime-and-retry path (`prime_workspace_document`, opening a workspace
file to give the server something to index) but it only triggered when
the first `workspace/symbol` call *errored* — an empty-but-successful
`[]` response was accepted as final. Changed the condition to also prime
and retry on an empty result, with a short poll (a few hundred-ms-spaced
attempts) after priming since indexing an opened document is still
asynchronous. Verified against live clangd (`E2E_CASES="cpp/clangd,c/clangd"`,
also spot-checked `objc`/`objcpp`/`cuda`, which share clangd's exact code
path): `grep Order` now reliably returns real matches instead of `[]`,
even from a cold index, across repeated runs. Removed the `grep`
empty-matches exceptions for clangd (cpp/c/objc/objcpp/cuda), vtsls
(typescript/javascript), and pyright/pylyzer (python) — the same fix
applies architecturally to all of them since they're all document-driven
analyzers with no true "ready" signal. vtsls, pyright, and pylyzer
weren't available to verify locally in this sandbox, so those removals
are provisional pending CI; if any disagrees, revert just that server's
exception (same discipline as the Rust `callees` revert below). EmmyLua's
`grep` exception was left in place — untouched pending separate
investigation.

3. ~~**ts_ls (typescript-language-server) "No Project" errors.**~~ **Fixed.**
For both TS and JS, ts_ls used to throw `No Project` on `grep`,
Expand Down
40 changes: 32 additions & 8 deletions src/commands/symbol_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ mod tests;

use kinds::{CallHierarchyDirection, LocationQueryKind};

const PRIME_RETRY_ATTEMPTS: u32 = 5;
const PRIME_RETRY_DELAY: Duration = Duration::from_millis(750);

pub(super) use render::{
render_file_list_json, render_list_symbols_json, render_paths_text,
render_symbol_match_paths_text, render_symbol_matches_text, render_symbol_names_text,
Expand Down Expand Up @@ -66,15 +69,36 @@ pub(super) fn run_workspace_symbol_query(
config,
|workspace, initialize, client| {
ensure_workspace_symbol_support(initialize)?;
let response = if let Ok(response) = client.workspace_symbol(query) {
response
} else {
prime_workspace_document(&args.query.directory, config, workspace, client)?;
client.workspace_symbol(query).map_err(|error| {
let matches = client
.workspace_symbol(query)
.ok()
.map(|response| symbol_matches_from_response(&response))
.transpose()?
.unwrap_or_default();
if !matches.is_empty() {
return Ok(matches);
}

prime_workspace_document(&args.query.directory, config, workspace, client)?;

// A freshly opened document can take a moment for the server to
// fold into its workspace-wide symbol index (e.g. clangd indexes
// headers pulled in by the opened file asynchronously), so poll
// briefly rather than giving up on the first still-empty result.
let mut matches = Vec::new();
for attempt in 0..PRIME_RETRY_ATTEMPTS {
if attempt > 0 {
std::thread::sleep(PRIME_RETRY_DELAY);
}
let response = client.workspace_symbol(query).map_err(|error| {
error.with_prefix(format!("failed to query {}", workspace.server.server))
})?
};
symbol_matches_from_response(&response)
})?;
matches = symbol_matches_from_response(&response)?;
if !matches.is_empty() {
break;
}
}
Ok(matches)
},
)?;

Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: clangd may not publish workspace symbols before background indexing completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/cpp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: clangd may not publish workspace symbols before background indexing completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/cuda.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: clangd may not publish workspace symbols before background indexing completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/javascript.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: vtsls returns no workspace symbols before project analysis completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/objc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: clangd may not publish workspace symbols before background indexing completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/objcpp.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: clangd may not publish workspace symbols before background indexing completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
6 changes: 0 additions & 6 deletions tests/e2e/cases/python.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: pylyzer returns no immediate workspace-symbol matches
- command: callers
outcome: empty-matches
reason: pylyzer returns no incoming call-hierarchy edges for the fixture function
Expand All @@ -53,9 +50,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: pyright advertises workspace symbols but returns no matches before background analysis completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down
3 changes: 0 additions & 3 deletions tests/e2e/cases/typescript.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ pairs:
smoke:
status: queries
exceptions:
- command: grep
outcome: empty-matches
reason: vtsls returns no workspace symbols before project analysis completes
- command: build-index
outcome: failure
message: background-work progress
Expand Down