diff options
Diffstat (limited to 'crates/ra_ide_api/src/navigation_target.rs')
-rw-r--r-- | crates/ra_ide_api/src/navigation_target.rs | 112 |
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 @@ | |||
1 | use ra_db::{FileId, LocalSyntaxPtr, Cancelable}; | 1 | use ra_db::{FileId, LocalSyntaxPtr, Cancelable}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | SyntaxNode, AstNode, SmolStr, | 3 | SyntaxNode, AstNode, SmolStr, TextRange, ast, |
4 | ast | 4 | SyntaxKind::{self, NAME}, |
5 | }; | 5 | }; |
6 | use hir::{Def, ModuleSource}; | 6 | use hir::{Def, ModuleSource}; |
7 | 7 | ||
8 | use crate::{ | 8 | use 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)] | ||
16 | pub 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 | ||
14 | impl NavigationTarget { | 26 | impl 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 | } |