дзеркало
https://github.com/l0ng-ai/openidea.git
синхронізовано 2026-11-08 19:02:17 +02:00
fix(lsp): Find usages in files outside the server's analysis scope
Language servers answer textDocument/references (and rename, incoming calls) only from the files they analyse: their configured scope (Pyright's `include`, a tsconfig, a compilation database) plus the open documents. Usages in other project files were silently missing until the file was opened. Reference searches now also find the project files of the server's languages that mention the symbol's name as a whole word (honouring .gitignore, excluded roots and ignored names; at most 300 files; off the UI thread and cancellable). Those the first answer did not cover and the user does not have open are opened on the server from disk, the request is repeated, and they are closed again. Diagnostics the server publishes for these files (including shortly after the close) never reach Problems, and a user opening such a file mid-search takes it over cleanly. An empty answer while the server reports progress is retried once indexing ends; results that may still be incomplete (server still indexing, or more matching files than searched) carry a note in Find Usages and Show Usages. lsp_references takes a request id so searches are cancelled when their tab closes, a new popup search starts, or the project changes. Find Usages, Show Usages (and Cmd-click on a declaration), usage counts, Safe Delete of a symbol, Rename and incoming Call Hierarchy share the path. File-level Safe Delete scans every symbol of the deleted files and keeps to the server's scope. Fixes #83 Claude-Session: https://claude.ai/code/session_01VUYsdXA2nkF5v6zsC93dpn
Цей коміт міститься в:
1 джерело
4100ab3341
коміт
faf4d2bd36
17 files changed
+1116
-97
No files matched your search
@@ -106,16 +106,25 @@ pub async fn lsp_virtual_document(
|
||||
project!(window, state).lsp.virtual_document(&uri).await
|
||||
}
|
||||
|
||||
/// References of the symbol at `pos`. `project_wide` also searches project files
|
||||
/// outside the language server's analysis scope; bulk scans over many symbols
|
||||
/// leave it off. Cancel with `cancel_request(request)`.
|
||||
#[tauri::command]
|
||||
#[specta::specta]
|
||||
pub async fn lsp_references(
|
||||
window: Window,
|
||||
state: State<'_, AppState>,
|
||||
request: RequestId,
|
||||
doc: DocId,
|
||||
pos: Pos,
|
||||
include_declaration: bool,
|
||||
) -> IdeResult<Vec<Location>> {
|
||||
project!(window, state).lsp.references(doc, pos, include_declaration).await
|
||||
project_wide: bool,
|
||||
) -> IdeResult<References> {
|
||||
let lsp = project!(window, state).lsp.clone();
|
||||
let cancel = state.begin_request(request);
|
||||
let result = lsp.references(doc, pos, include_declaration, project_wide, cancel).await;
|
||||
state.end_request(request);
|
||||
result
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
@@ -442,6 +442,12 @@ impl AppState {
|
||||
content_watchers: Mutex::new(content_watchers),
|
||||
_scratch_watcher: scratch_watcher,
|
||||
});
|
||||
{
|
||||
let weak = Arc::downgrade(&project);
|
||||
project.lsp.set_candidates_hook(Box::new(move |q, cancel| {
|
||||
weak.upgrade().map(|p| p.reference_candidates(q, cancel)).unwrap_or_default()
|
||||
}));
|
||||
}
|
||||
self.projects.write().insert(window.to_owned(), project.clone());
|
||||
Ok(project)
|
||||
}
|
||||
@@ -609,6 +615,33 @@ impl Project {
|
||||
out
|
||||
}
|
||||
|
||||
/// Project files of `q.languages` under `q.root` containing `q.word` as a whole
|
||||
/// word (unsaved buffers included; excluded roots, ignored names and
|
||||
/// `.gitignore`d files skipped): the files a references search opens on its server.
|
||||
pub fn reference_candidates(
|
||||
&self,
|
||||
q: &ide_lsp::CandidateQuery,
|
||||
cancel: &CancellationToken,
|
||||
) -> ide_lsp::CandidateFiles {
|
||||
if !q.root.starts_with(&self.root) {
|
||||
return ide_lsp::CandidateFiles::default();
|
||||
}
|
||||
let query = ide_search::WordQuery {
|
||||
word: q.word.clone(),
|
||||
dir: q.root.clone(),
|
||||
exclude: self.search_excludes(),
|
||||
limit: q.limit,
|
||||
};
|
||||
let filter = |rel: &str| q.languages.contains(&self.languages.detect(&self.root.join(rel), None));
|
||||
match ide_search::files_with_word(&self.root, &query, Some(&filter), &|p| self.documents.text_of(p), cancel) {
|
||||
Ok(found) => ide_lsp::CandidateFiles { files: found.files, limit_hit: found.limit_hit },
|
||||
Err(e) => {
|
||||
tracing::debug!("reference candidates: {}", e.message);
|
||||
ide_lsp::CandidateFiles::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `files.exclude`, the ignored names and the effective excluded roots (user-marked and detected).
|
||||
pub fn exclude_globs(&self) -> Vec<String> {
|
||||
exclude_globs(&self.settings.effective(), &self.detected_roots.read())
|
||||
|
||||
Reference in new issue
Заблокувати користувача