Skip to content

Commit 610ec04

Browse files
committed
feat: Allow rust paths in symbol search
1 parent 9b40d83 commit 610ec04

File tree

2 files changed

+724
-12
lines changed

2 files changed

+724
-12
lines changed

crates/hir/src/symbols.rs

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use hir_def::{
99
ModuleDefId, ModuleId, TraitId,
1010
db::DefDatabase,
1111
item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob},
12+
nameres::crate_def_map,
1213
per_ns::Item,
1314
src::{HasChildSource, HasSource},
1415
visibility::{Visibility, VisibilityExplicitness},
@@ -20,9 +21,12 @@ use hir_ty::{
2021
};
2122
use intern::Symbol;
2223
use rustc_hash::FxHashMap;
23-
use syntax::{AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ToSmolStr, ast::HasName};
24+
use syntax::{
25+
AstNode, AstPtr, SyntaxNode, SyntaxNodePtr, ToSmolStr,
26+
ast::{HasModuleItem, HasName},
27+
};
2428

25-
use crate::{HasCrate, Module, ModuleDef, Semantics};
29+
use crate::{Crate, HasCrate, Module, ModuleDef, Semantics};
2630

2731
/// The actual data that is stored in the index. It should be as compact as
2832
/// possible.
@@ -57,6 +61,70 @@ impl DeclarationLocation {
5761
}
5862
}
5963

64+
impl<'db> FileSymbol<'db> {
65+
/// Create a `FileSymbol` representing a crate's root module.
66+
/// This is used for crate search queries like `::` or `::foo`.
67+
pub fn for_crate_root(db: &'db dyn HirDatabase, krate: Crate) -> Option<FileSymbol<'db>> {
68+
let display_name = krate.display_name(db)?;
69+
let crate_name = display_name.crate_name();
70+
let root_module = krate.root_module(db);
71+
let def_map = crate_def_map(db, krate.into());
72+
let module_data = &def_map[root_module.into()];
73+
74+
// Get the definition source (the source file for crate roots)
75+
let definition = module_data.origin.definition_source(db);
76+
let hir_file_id = definition.file_id;
77+
78+
// For a crate root, the "declaration" is the source file itself
79+
// We use the entire file's syntax node as the location
80+
let syntax_node = definition.value.node();
81+
let ptr = SyntaxNodePtr::new(&syntax_node);
82+
83+
// For the name, we need to create a synthetic name pointer.
84+
// We'll use the first token of the file as a placeholder since crate roots
85+
// don't have an explicit name in the source.
86+
// We create a name_ptr pointing to the start of the file.
87+
let name_ptr = match &definition.value {
88+
crate::ModuleSource::SourceFile(sf) => {
89+
// Try to find the first item with a name as a reasonable location for focus
90+
// This is a bit of a hack but works for navigation purposes
91+
let first_item: Option<syntax::ast::Item> = sf.items().next();
92+
if let Some(item) = first_item {
93+
if let Some(name) = item.syntax().children().find_map(syntax::ast::Name::cast) {
94+
AstPtr::new(&name).wrap_left()
95+
} else {
96+
// No name found, try to use a NameRef instead
97+
if let Some(name_ref) =
98+
item.syntax().descendants().find_map(syntax::ast::NameRef::cast)
99+
{
100+
AstPtr::new(&name_ref).wrap_right()
101+
} else {
102+
return None;
103+
}
104+
}
105+
} else {
106+
return None;
107+
}
108+
}
109+
_ => return None,
110+
};
111+
112+
let loc = DeclarationLocation { hir_file_id, ptr, name_ptr };
113+
114+
Some(FileSymbol {
115+
name: Symbol::intern(crate_name.as_str()),
116+
def: ModuleDef::Module(root_module),
117+
loc,
118+
container_name: None,
119+
is_alias: false,
120+
is_assoc: false,
121+
is_import: false,
122+
do_not_complete: Complete::Yes,
123+
_marker: PhantomData,
124+
})
125+
}
126+
}
127+
60128
/// Represents an outstanding module that the symbol collector must collect symbols from.
61129
#[derive(Debug)]
62130
struct SymbolCollectorWork {

0 commit comments

Comments
 (0)