aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/display.rs11
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs4
-rw-r--r--crates/ra_ide_api/src/hover.rs180
3 files changed, 165 insertions, 30 deletions
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
index f11af0a0b..882518838 100644
--- a/crates/ra_ide_api/src/display.rs
+++ b/crates/ra_ide_api/src/display.rs
@@ -13,6 +13,7 @@ pub use structure::{StructureNode, file_structure};
13pub use function_signature::FunctionSignature; 13pub use function_signature::FunctionSignature;
14 14
15pub(crate) use short_label::ShortLabel; 15pub(crate) use short_label::ShortLabel;
16pub(crate) use navigation_target::{docs_from_symbol, description_from_symbol};
16 17
17pub(crate) fn function_label(node: &ast::FnDef) -> String { 18pub(crate) fn function_label(node: &ast::FnDef) -> String {
18 FunctionSignature::from(node).to_string() 19 FunctionSignature::from(node).to_string()
@@ -72,13 +73,3 @@ where
72 format!("```rust\n{}\n```", val.as_ref()) 73 format!("```rust\n{}\n```", val.as_ref())
73 } 74 }
74} 75}
75
76// FIXME: this should not really use navigation target. Rather, approximately
77// resolved symbol should return a `DefId`.
78pub(crate) fn doc_text_for(nav: NavigationTarget) -> Option<String> {
79 match (nav.description(), nav.docs()) {
80 (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
81 (None, Some(docs)) => Some(docs.to_string()),
82 _ => None,
83 }
84}
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index 983ebe788..cfd3f5478 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -413,7 +413,7 @@ impl NavigationTarget {
413 } 413 }
414} 414}
415 415
416fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 416pub(crate) fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
417 let file = db.parse(symbol.file_id).tree; 417 let file = db.parse(symbol.file_id).tree;
418 let node = symbol.ptr.to_node(file.syntax()).to_owned(); 418 let node = symbol.ptr.to_node(file.syntax()).to_owned();
419 419
@@ -439,7 +439,7 @@ fn docs_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
439/// Get a description of a symbol. 439/// Get a description of a symbol.
440/// 440///
441/// e.g. `struct Name`, `enum Name`, `fn Name` 441/// e.g. `struct Name`, `enum Name`, `fn Name`
442fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> { 442pub(crate) fn description_from_symbol(db: &RootDatabase, symbol: &FileSymbol) -> Option<String> {
443 let file = db.parse(symbol.file_id).tree; 443 let file = db.parse(symbol.file_id).tree;
444 let node = symbol.ptr.to_node(file.syntax()).to_owned(); 444 let node = symbol.ptr.to_node(file.syntax()).to_owned();
445 445
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index cb676eb12..fbabeb194 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,14 +1,15 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, ast, 3 AstNode, ast::{self, DocCommentsOwner},
4 algo::{find_covering_element, find_node_at_offset, ancestors_at_offset}, 4 algo::{find_covering_element, find_node_at_offset, ancestors_at_offset, visit::{visitor, Visitor}},
5}; 5};
6use hir::HirDisplay; 6use hir::HirDisplay;
7 7
8use crate::{ 8use crate::{
9 db::RootDatabase, 9 db::RootDatabase,
10 RangeInfo, FilePosition, FileRange, 10 RangeInfo, FilePosition, FileRange,
11 display::{rust_code_markup, doc_text_for}, 11 display::{rust_code_markup, rust_code_markup_with_doc, ShortLabel, docs_from_symbol, description_from_symbol},
12 name_ref_kind::{NameRefKind::*, classify_name_ref},
12}; 13};
13 14
14/// Contains the results when hovering over an item 15/// Contains the results when hovering over an item
@@ -77,34 +78,177 @@ impl HoverResult {
77 } 78 }
78} 79}
79 80
81fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
82 match (desc, docs) {
83 (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
84 (None, Some(docs)) => Some(docs.to_string()),
85 _ => None,
86 }
87}
88
80pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 89pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
81 let file = db.parse(position.file_id).tree; 90 let file = db.parse(position.file_id).tree;
82 let mut res = HoverResult::new(); 91 let mut res = HoverResult::new();
83 92
84 let mut range = None; 93 let mut range = None;
85 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 94 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
86 use crate::goto_definition::{ReferenceResult::*, reference_definition}; 95 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
87 let ref_result = reference_definition(db, position.file_id, name_ref); 96
88 match ref_result { 97 match classify_name_ref(db, &analyzer, name_ref) {
89 Exact(nav) => res.extend(doc_text_for(nav)), 98 Some(Method(it)) => {
90 Approximate(navs) => { 99 let it = it.source(db).1;
91 // We are no longer exact 100 res.extend(hover_text(it.doc_comment_text(), it.short_label()));
92 res.exact = false; 101 }
93 102 Some(Macro(it)) => {
94 for nav in navs { 103 let it = it.source(db).1;
95 res.extend(doc_text_for(nav)) 104 res.extend(hover_text(it.doc_comment_text(), None));
105 }
106 Some(FieldAccess(it)) => {
107 let it = it.source(db).1;
108 if let hir::FieldSource::Named(it) = it {
109 res.extend(hover_text(it.doc_comment_text(), it.short_label()));
110 }
111 }
112 Some(AssocItem(it)) => match it {
113 hir::ImplItem::Method(it) => {
114 let it = it.source(db).1;
115 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
116 }
117 hir::ImplItem::Const(it) => {
118 let it = it.source(db).1;
119 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
120 }
121 hir::ImplItem::TypeAlias(it) => {
122 let it = it.source(db).1;
123 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
124 }
125 },
126 Some(Def(it)) => {
127 match it {
128 hir::ModuleDef::Module(it) => {
129 let it = it.definition_source(db).1;
130 if let hir::ModuleSource::Module(it) = it {
131 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
132 }
133 }
134 hir::ModuleDef::Function(it) => {
135 let it = it.source(db).1;
136 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
137 }
138 hir::ModuleDef::Struct(it) => {
139 let it = it.source(db).1;
140 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
141 }
142 hir::ModuleDef::Union(it) => {
143 let it = it.source(db).1;
144 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
145 }
146 hir::ModuleDef::Enum(it) => {
147 let it = it.source(db).1;
148 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
149 }
150 hir::ModuleDef::EnumVariant(it) => {
151 let it = it.source(db).1;
152 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
153 }
154 hir::ModuleDef::Const(it) => {
155 let it = it.source(db).1;
156 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
157 }
158 hir::ModuleDef::Static(it) => {
159 let it = it.source(db).1;
160 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
161 }
162 hir::ModuleDef::Trait(it) => {
163 let it = it.source(db).1;
164 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
165 }
166 hir::ModuleDef::TypeAlias(it) => {
167 let it = it.source(db).1;
168 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
169 }
170 hir::ModuleDef::BuiltinType(_) => {
171 // FIXME: hover for builtin Type ?
172 }
96 } 173 }
97 } 174 }
175 Some(SelfType(ty)) => {
176 if let Some((adt_def, _)) = ty.as_adt() {
177 match adt_def {
178 hir::AdtDef::Struct(it) => {
179 let it = it.source(db).1;
180 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
181 }
182 hir::AdtDef::Union(it) => {
183 let it = it.source(db).1;
184 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
185 }
186 hir::AdtDef::Enum(it) => {
187 let it = it.source(db).1;
188 res.extend(hover_text(it.doc_comment_text(), it.short_label()))
189 }
190 }
191 }
192 }
193 Some(Pat(_)) => {
194 res.extend(None);
195 }
196 Some(SelfParam(_)) => {
197 res.extend(None);
198 }
199 Some(GenericParam(_)) => {
200 // FIXME: Hover for generic param
201 }
202 None => {}
98 } 203 }
204
205 if res.is_empty() {
206 // Fallback index based approach:
207 let symbols = crate::symbol_index::index_resolve(db, name_ref);
208 for sym in symbols {
209 let docs = docs_from_symbol(db, &sym);
210 let desc = description_from_symbol(db, &sym);
211 res.extend(hover_text(docs, desc));
212 }
213 }
214
99 if !res.is_empty() { 215 if !res.is_empty() {
100 range = Some(name_ref.syntax().range()) 216 range = Some(name_ref.syntax().range())
101 } 217 }
102 } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) { 218 } else if let Some(name) = find_node_at_offset::<ast::Name>(file.syntax(), position.offset) {
103 let navs = crate::goto_definition::name_definition(db, position.file_id, name); 219 if let Some(parent) = name.syntax().parent() {
104 220 let text = visitor()
105 if let Some(navs) = navs { 221 .visit(|node: &ast::StructDef| {
106 for nav in navs { 222 hover_text(node.doc_comment_text(), node.short_label())
107 res.extend(doc_text_for(nav)) 223 })
224 .visit(|node: &ast::EnumDef| {
225 hover_text(node.doc_comment_text(), node.short_label())
226 })
227 .visit(|node: &ast::EnumVariant| {
228 hover_text(node.doc_comment_text(), node.short_label())
229 })
230 .visit(|node: &ast::FnDef| hover_text(node.doc_comment_text(), node.short_label()))
231 .visit(|node: &ast::TypeAliasDef| {
232 hover_text(node.doc_comment_text(), node.short_label())
233 })
234 .visit(|node: &ast::ConstDef| {
235 hover_text(node.doc_comment_text(), node.short_label())
236 })
237 .visit(|node: &ast::StaticDef| {
238 hover_text(node.doc_comment_text(), node.short_label())
239 })
240 .visit(|node: &ast::TraitDef| {
241 hover_text(node.doc_comment_text(), node.short_label())
242 })
243 .visit(|node: &ast::NamedFieldDef| {
244 hover_text(node.doc_comment_text(), node.short_label())
245 })
246 .visit(|node: &ast::Module| hover_text(node.doc_comment_text(), node.short_label()))
247 .visit(|node: &ast::MacroCall| hover_text(node.doc_comment_text(), None))
248 .accept(parent);
249
250 if let Some(text) = text {
251 res.extend(text);
108 } 252 }
109 } 253 }
110 254