aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/navigation_target.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/navigation_target.rs')
-rw-r--r--crates/ra_ide_api/src/navigation_target.rs112
1 files changed, 88 insertions, 24 deletions
diff --git a/crates/ra_ide_api/src/navigation_target.rs b/crates/ra_ide_api/src/navigation_target.rs
index 09a723d68..943e62eb8 100644
--- a/crates/ra_ide_api/src/navigation_target.rs
+++ b/crates/ra_ide_api/src/navigation_target.rs
@@ -1,27 +1,98 @@
1use ra_db::{FileId, LocalSyntaxPtr, Cancelable}; 1use ra_db::{FileId, LocalSyntaxPtr, Cancelable};
2use ra_syntax::{ 2use ra_syntax::{
3 SyntaxNode, AstNode, SmolStr, 3 SyntaxNode, AstNode, SmolStr, TextRange, ast,
4 ast 4 SyntaxKind::{self, NAME},
5}; 5};
6use hir::{Def, ModuleSource}; 6use hir::{Def, ModuleSource};
7 7
8use crate::{ 8use crate::{FileSymbol, db::RootDatabase};
9 NavigationTarget, 9
10 FileSymbol, 10/// `NavigationTarget` represents and element in the editor's UI which you can
11 db::RootDatabase, 11/// click on to navigate to a particular piece of code.
12}; 12///
13/// Typically, a `NavigationTarget` corresponds to some element in the source
14/// code, like a function or a struct, but this is not strictly required.
15#[derive(Debug, Clone)]
16pub struct NavigationTarget {
17 file_id: FileId,
18 name: SmolStr,
19 kind: SyntaxKind,
20 range: TextRange,
21 focus_range: Option<TextRange>,
22 // Should be DefId ideally
23 ptr: Option<LocalSyntaxPtr>,
24}
13 25
14impl NavigationTarget { 26impl NavigationTarget {
27 pub fn name(&self) -> &SmolStr {
28 &self.name
29 }
30
31 pub fn kind(&self) -> SyntaxKind {
32 self.kind
33 }
34
35 pub fn file_id(&self) -> FileId {
36 self.file_id
37 }
38
39 pub fn range(&self) -> TextRange {
40 self.range
41 }
42
43 /// A "most interesting" range withing the `range`.
44 ///
45 /// Typically, `range` is the whole syntax node, including doc comments, and
46 /// `focus_range` is the range of the identifier.
47 pub fn focus_range(&self) -> Option<TextRange> {
48 self.focus_range
49 }
50
15 pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget { 51 pub(crate) fn from_symbol(symbol: FileSymbol) -> NavigationTarget {
16 NavigationTarget { 52 NavigationTarget {
17 file_id: symbol.file_id, 53 file_id: symbol.file_id,
18 name: symbol.name.clone(), 54 name: symbol.name.clone(),
19 kind: symbol.ptr.kind(), 55 kind: symbol.ptr.kind(),
20 range: symbol.ptr.range(), 56 range: symbol.ptr.range(),
57 focus_range: None,
21 ptr: Some(symbol.ptr.clone()), 58 ptr: Some(symbol.ptr.clone()),
22 } 59 }
23 } 60 }
24 61
62 pub(crate) fn from_scope_entry(
63 file_id: FileId,
64 entry: &hir::ScopeEntryWithSyntax,
65 ) -> NavigationTarget {
66 NavigationTarget {
67 file_id,
68 name: entry.name().to_string().into(),
69 range: entry.ptr().range(),
70 focus_range: None,
71 kind: NAME,
72 ptr: None,
73 }
74 }
75
76 pub(crate) fn from_module(
77 db: &RootDatabase,
78 module: hir::Module,
79 ) -> Cancelable<NavigationTarget> {
80 let (file_id, source) = module.definition_source(db)?;
81 let name = module
82 .name(db)?
83 .map(|it| it.to_string().into())
84 .unwrap_or_default();
85 let res = match source {
86 ModuleSource::SourceFile(node) => {
87 NavigationTarget::from_syntax(file_id, name, None, node.syntax())
88 }
89 ModuleSource::Module(node) => {
90 NavigationTarget::from_syntax(file_id, name, None, node.syntax())
91 }
92 };
93 Ok(res)
94 }
95
25 // TODO once Def::Item is gone, this should be able to always return a NavigationTarget 96 // TODO once Def::Item is gone, this should be able to always return a NavigationTarget
26 pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> { 97 pub(crate) fn from_def(db: &RootDatabase, def: Def) -> Cancelable<Option<NavigationTarget>> {
27 let res = match def { 98 let res = match def {
@@ -41,21 +112,7 @@ impl NavigationTarget {
41 let (file_id, node) = f.source(db)?; 112 let (file_id, node) = f.source(db)?;
42 NavigationTarget::from_named(file_id.original_file(db), &*node) 113 NavigationTarget::from_named(file_id.original_file(db), &*node)
43 } 114 }
44 Def::Module(m) => { 115 Def::Module(m) => NavigationTarget::from_module(db, m)?,
45 let (file_id, source) = m.definition_source(db)?;
46 let name = m
47 .name(db)?
48 .map(|it| it.to_string().into())
49 .unwrap_or_default();
50 match source {
51 ModuleSource::SourceFile(node) => {
52 NavigationTarget::from_syntax(file_id, name, node.syntax())
53 }
54 ModuleSource::Module(node) => {
55 NavigationTarget::from_syntax(file_id, name, node.syntax())
56 }
57 }
58 }
59 Def::Item => return Ok(None), 116 Def::Item => return Ok(None),
60 }; 117 };
61 Ok(Some(res)) 118 Ok(Some(res))
@@ -63,15 +120,22 @@ impl NavigationTarget {
63 120
64 fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget { 121 fn from_named(file_id: FileId, node: &impl ast::NameOwner) -> NavigationTarget {
65 let name = node.name().map(|it| it.text().clone()).unwrap_or_default(); 122 let name = node.name().map(|it| it.text().clone()).unwrap_or_default();
66 NavigationTarget::from_syntax(file_id, name, node.syntax()) 123 let focus_range = node.name().map(|it| it.syntax().range());
124 NavigationTarget::from_syntax(file_id, name, focus_range, node.syntax())
67 } 125 }
68 126
69 fn from_syntax(file_id: FileId, name: SmolStr, node: &SyntaxNode) -> NavigationTarget { 127 fn from_syntax(
128 file_id: FileId,
129 name: SmolStr,
130 focus_range: Option<TextRange>,
131 node: &SyntaxNode,
132 ) -> NavigationTarget {
70 NavigationTarget { 133 NavigationTarget {
71 file_id, 134 file_id,
72 name, 135 name,
73 kind: node.kind(), 136 kind: node.kind(),
74 range: node.range(), 137 range: node.range(),
138 focus_range,
75 ptr: Some(LocalSyntaxPtr::new(node)), 139 ptr: Some(LocalSyntaxPtr::new(node)),
76 } 140 }
77 } 141 }