mirror of
https://github.com/astral-sh/ruff.git
synced 2025-10-01 14:21:24 +00:00
[ty] Add base for "all symbols" implementation
This just copies the existing "workspace symbols" implementation and re-names some things.
This commit is contained in:
parent
046893c186
commit
78db56e362
2 changed files with 179 additions and 0 deletions
177
crates/ty_ide/src/all_symbols.rs
Normal file
177
crates/ty_ide/src/all_symbols.rs
Normal file
|
@ -0,0 +1,177 @@
|
||||||
|
use crate::symbols::{QueryPattern, SymbolInfo, symbols_for_file_global_only};
|
||||||
|
use ruff_db::files::File;
|
||||||
|
use ty_project::Db;
|
||||||
|
|
||||||
|
/// Get all symbols matching the query string.
|
||||||
|
///
|
||||||
|
/// Returns symbols from all files in the workspace and dependencies, filtered
|
||||||
|
/// by the query.
|
||||||
|
pub fn all_symbols(db: &dyn Db, query: &str) -> Vec<AllSymbolInfo> {
|
||||||
|
// If the query is empty, return immediately to avoid expensive file scanning
|
||||||
|
if query.is_empty() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
|
||||||
|
let project = db.project();
|
||||||
|
|
||||||
|
let query = QueryPattern::new(query);
|
||||||
|
let files = project.files(db);
|
||||||
|
let results = std::sync::Mutex::new(Vec::new());
|
||||||
|
{
|
||||||
|
let db = db.dyn_clone();
|
||||||
|
let files = &files;
|
||||||
|
let results = &results;
|
||||||
|
let query = &query;
|
||||||
|
|
||||||
|
rayon::scope(move |s| {
|
||||||
|
// For each file, extract symbols and add them to results
|
||||||
|
for file in files.iter() {
|
||||||
|
let db = db.dyn_clone();
|
||||||
|
s.spawn(move |_| {
|
||||||
|
for (_, symbol) in symbols_for_file_global_only(&*db, *file).search(query) {
|
||||||
|
// It seems like we could do better here than
|
||||||
|
// locking `results` for every single symbol,
|
||||||
|
// but this works pretty well as it is.
|
||||||
|
results.lock().unwrap().push(AllSymbolInfo {
|
||||||
|
symbol: symbol.to_owned(),
|
||||||
|
file: *file,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
results.into_inner().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A symbol found in the workspace and dependencies, including the
|
||||||
|
/// file it was found in.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct AllSymbolInfo {
|
||||||
|
/// The symbol information
|
||||||
|
pub symbol: SymbolInfo<'static>,
|
||||||
|
/// The file containing the symbol
|
||||||
|
pub file: File,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
use crate::tests::CursorTest;
|
||||||
|
use crate::tests::IntoDiagnostic;
|
||||||
|
use insta::assert_snapshot;
|
||||||
|
use ruff_db::diagnostic::{
|
||||||
|
Annotation, Diagnostic, DiagnosticId, LintName, Severity, Span, SubDiagnostic,
|
||||||
|
SubDiagnosticSeverity,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_all_symbols_multi_file() {
|
||||||
|
// We use odd symbol names here so that we can
|
||||||
|
// write queries that target them specifically
|
||||||
|
// and (hopefully) nothing else.
|
||||||
|
let test = CursorTest::builder()
|
||||||
|
.source(
|
||||||
|
"utils.py",
|
||||||
|
"
|
||||||
|
def abcdefghijklmnop():
|
||||||
|
'''A helpful utility function'''
|
||||||
|
pass
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.source(
|
||||||
|
"models.py",
|
||||||
|
"
|
||||||
|
class Abcdefghijklmnop:
|
||||||
|
'''A data model class'''
|
||||||
|
def __init__(self):
|
||||||
|
pass
|
||||||
|
",
|
||||||
|
)
|
||||||
|
.source(
|
||||||
|
"constants.py",
|
||||||
|
"
|
||||||
|
ABCDEFGHIJKLMNOP = 'https://api.example.com'
|
||||||
|
<CURSOR>",
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_snapshot!(test.all_symbols("ufunc"), @r"
|
||||||
|
info[all-symbols]: AllSymbolInfo
|
||||||
|
--> utils.py:2:5
|
||||||
|
|
|
||||||
|
2 | ABCDEFGHIJKLMNOP = 'https://api.example.com'
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
|
||||||
|
info: Function utility_function
|
||||||
|
");
|
||||||
|
|
||||||
|
assert_snapshot!(test.all_symbols("data"), @r"
|
||||||
|
info[all-symbols]: AllSymbolInfo
|
||||||
|
--> models.py:2:7
|
||||||
|
|
|
||||||
|
2 | class Abcdefghijklmnop:
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
3 | '''A data model class'''
|
||||||
|
4 | def __init__(self):
|
||||||
|
|
|
||||||
|
info: Class DataModel
|
||||||
|
");
|
||||||
|
|
||||||
|
info[all-symbols]: AllSymbolInfo
|
||||||
|
--> constants.py:2:1
|
||||||
|
|
|
||||||
|
2 | def abcdefghijklmnop():
|
||||||
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
3 | '''A helpful utility function'''
|
||||||
|
4 | pass
|
||||||
|
|
|
||||||
|
info: Function abcdefghijklmnop
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CursorTest {
|
||||||
|
fn all_symbols(&self, query: &str) -> String {
|
||||||
|
let symbols = all_symbols(&self.db, query);
|
||||||
|
|
||||||
|
if symbols.is_empty() {
|
||||||
|
return "No symbols found".to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
self.render_diagnostics(symbols.into_iter().map(AllSymbolDiagnostic::new))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct AllSymbolDiagnostic {
|
||||||
|
symbol_info: AllSymbolInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AllSymbolDiagnostic {
|
||||||
|
fn new(symbol_info: AllSymbolInfo) -> Self {
|
||||||
|
Self { symbol_info }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IntoDiagnostic for AllSymbolDiagnostic {
|
||||||
|
fn into_diagnostic(self) -> Diagnostic {
|
||||||
|
let symbol_kind_str = self.symbol_info.symbol.kind.to_string();
|
||||||
|
|
||||||
|
let info_text = format!("{} {}", symbol_kind_str, self.symbol_info.symbol.name);
|
||||||
|
|
||||||
|
let sub = SubDiagnostic::new(SubDiagnosticSeverity::Info, info_text);
|
||||||
|
|
||||||
|
let mut main = Diagnostic::new(
|
||||||
|
DiagnosticId::Lint(LintName::of("all-symbols")),
|
||||||
|
Severity::Info,
|
||||||
|
"AllSymbolInfo".to_string(),
|
||||||
|
);
|
||||||
|
main.annotate(Annotation::primary(
|
||||||
|
Span::from(self.symbol_info.file).with_range(self.symbol_info.symbol.name_range),
|
||||||
|
));
|
||||||
|
main.sub(sub);
|
||||||
|
|
||||||
|
main
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,6 +2,7 @@
|
||||||
clippy::disallowed_methods,
|
clippy::disallowed_methods,
|
||||||
reason = "Prefer System trait methods over std methods in ty crates"
|
reason = "Prefer System trait methods over std methods in ty crates"
|
||||||
)]
|
)]
|
||||||
|
mod all_symbols;
|
||||||
mod completion;
|
mod completion;
|
||||||
mod doc_highlights;
|
mod doc_highlights;
|
||||||
mod docstring;
|
mod docstring;
|
||||||
|
@ -24,6 +25,7 @@ mod stub_mapping;
|
||||||
mod symbols;
|
mod symbols;
|
||||||
mod workspace_symbols;
|
mod workspace_symbols;
|
||||||
|
|
||||||
|
pub use all_symbols::{AllSymbolInfo, all_symbols};
|
||||||
pub use completion::completion;
|
pub use completion::completion;
|
||||||
pub use doc_highlights::document_highlights;
|
pub use doc_highlights::document_highlights;
|
||||||
pub use document_symbols::document_symbols;
|
pub use document_symbols::document_symbols;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue