aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide_api/src/display.rs27
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs82
-rw-r--r--crates/ra_ide_api/src/hover.rs110
3 files changed, 110 insertions, 109 deletions
diff --git a/crates/ra_ide_api/src/display.rs b/crates/ra_ide_api/src/display.rs
index f1717b008..b68b3a719 100644
--- a/crates/ra_ide_api/src/display.rs
+++ b/crates/ra_ide_api/src/display.rs
@@ -5,6 +5,7 @@ mod function_signature;
5mod navigation_target; 5mod navigation_target;
6mod structure; 6mod structure;
7 7
8use crate::db::RootDatabase;
8use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}}; 9use ra_syntax::{ast::{self, AstNode, TypeParamsOwner}, SyntaxKind::{ATTR, COMMENT}};
9 10
10pub use navigation_target::NavigationTarget; 11pub use navigation_target::NavigationTarget;
@@ -53,3 +54,29 @@ pub(crate) fn where_predicates<N: TypeParamsOwner>(node: &N) -> Vec<String> {
53 } 54 }
54 res 55 res
55} 56}
57
58pub(crate) fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
59 rust_code_markup_with_doc::<_, &str>(val, None)
60}
61
62pub(crate) fn rust_code_markup_with_doc<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String
63where
64 CODE: AsRef<str>,
65 DOC: AsRef<str>,
66{
67 if let Some(doc) = doc {
68 format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref())
69 } else {
70 format!("```rust\n{}\n```", val.as_ref())
71 }
72}
73
74// FIXME: this should not really use navigation target. Rather, approximately
75// resolved symbol should return a `DefId`.
76pub(crate) fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
77 match (nav.description(db), nav.docs(db)) {
78 (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
79 (None, Some(docs)) => Some(docs),
80 _ => None,
81 }
82}
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index f6d7f3192..3c518faf5 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -1,7 +1,9 @@
1use ra_db::FileId; 1use ra_db::{FileId, SourceDatabase};
2use ra_syntax::{ 2use ra_syntax::{
3 SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, ast, 3 SyntaxNode, SyntaxNodePtr, AstNode, SmolStr, TextRange, TreeArc,
4 SyntaxKind::{self, NAME}, 4 SyntaxKind::{self, NAME},
5 ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner},
6 algo::visit::{visitor, Visitor},
5}; 7};
6use hir::{ModuleSource, FieldSource, Name, ImplItem}; 8use hir::{ModuleSource, FieldSource, Name, ImplItem};
7 9
@@ -248,4 +250,80 @@ impl NavigationTarget {
248 container_name: None, 250 container_name: None,
249 } 251 }
250 } 252 }
253
254 pub(crate) fn node(&self, db: &RootDatabase) -> Option<TreeArc<SyntaxNode>> {
255 let source_file = db.parse(self.file_id());
256 let source_file = source_file.syntax();
257 let node = source_file
258 .descendants()
259 .find(|node| node.kind() == self.kind() && node.range() == self.full_range())?
260 .to_owned();
261 Some(node)
262 }
263
264 pub(crate) fn docs(&self, db: &RootDatabase) -> Option<String> {
265 let node = self.node(db)?;
266 fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> {
267 node.doc_comment_text()
268 }
269
270 visitor()
271 .visit(doc_comments::<ast::FnDef>)
272 .visit(doc_comments::<ast::StructDef>)
273 .visit(doc_comments::<ast::EnumDef>)
274 .visit(doc_comments::<ast::TraitDef>)
275 .visit(doc_comments::<ast::Module>)
276 .visit(doc_comments::<ast::TypeAliasDef>)
277 .visit(doc_comments::<ast::ConstDef>)
278 .visit(doc_comments::<ast::StaticDef>)
279 .visit(doc_comments::<ast::NamedFieldDef>)
280 .visit(doc_comments::<ast::EnumVariant>)
281 .accept(&node)?
282 }
283
284 /// Get a description of this node.
285 ///
286 /// e.g. `struct Name`, `enum Name`, `fn Name`
287 pub(crate) fn description(&self, db: &RootDatabase) -> Option<String> {
288 // FIXME: After type inference is done, add type information to improve the output
289 let node = self.node(db)?;
290
291 fn visit_ascribed_node<T>(node: &T, prefix: &str) -> Option<String>
292 where
293 T: NameOwner + VisibilityOwner + TypeAscriptionOwner,
294 {
295 let mut string = visit_node(node, prefix)?;
296
297 if let Some(type_ref) = node.ascribed_type() {
298 string.push_str(": ");
299 type_ref.syntax().text().push_to(&mut string);
300 }
301
302 Some(string)
303 }
304
305 fn visit_node<T>(node: &T, label: &str) -> Option<String>
306 where
307 T: NameOwner + VisibilityOwner,
308 {
309 let mut string =
310 node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default();
311 string.push_str(label);
312 string.push_str(node.name()?.text().as_str());
313 Some(string)
314 }
315
316 visitor()
317 .visit(|node: &ast::FnDef| Some(crate::display::function_label(node)))
318 .visit(|node: &ast::StructDef| visit_node(node, "struct "))
319 .visit(|node: &ast::EnumDef| visit_node(node, "enum "))
320 .visit(|node: &ast::TraitDef| visit_node(node, "trait "))
321 .visit(|node: &ast::Module| visit_node(node, "mod "))
322 .visit(|node: &ast::TypeAliasDef| visit_node(node, "type "))
323 .visit(|node: &ast::ConstDef| visit_ascribed_node(node, "const "))
324 .visit(|node: &ast::StaticDef| visit_ascribed_node(node, "static "))
325 .visit(|node: &ast::NamedFieldDef| visit_ascribed_node(node, ""))
326 .visit(|node: &ast::EnumVariant| Some(node.name()?.text().to_string()))
327 .accept(&node)?
328 }
251} 329}
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 7d2c57f82..3a8c93b99 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -1,11 +1,11 @@
1use ra_db::SourceDatabase; 1use ra_db::SourceDatabase;
2use ra_syntax::{ 2use ra_syntax::{
3 AstNode, SyntaxNode, TreeArc, ast::{self, NameOwner, VisibilityOwner, TypeAscriptionOwner}, 3 AstNode, ast,
4 algo::{find_covering_element, find_node_at_offset, find_token_at_offset, visit::{visitor, Visitor}}, 4 algo::{find_covering_element, find_node_at_offset, find_token_at_offset},
5}; 5};
6use hir::HirDisplay; 6use hir::HirDisplay;
7 7
8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; 8use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, display::{rust_code_markup, doc_text_for}};
9 9
10/// Contains the results when hovering over an item 10/// Contains the results when hovering over an item
11#[derive(Debug, Clone)] 11#[derive(Debug, Clone)]
@@ -145,110 +145,6 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
145 } 145 }
146} 146}
147 147
148fn rust_code_markup<CODE: AsRef<str>>(val: CODE) -> String {
149 rust_code_markup_with_doc::<_, &str>(val, None)
150}
151
152fn rust_code_markup_with_doc<CODE, DOC>(val: CODE, doc: Option<DOC>) -> String
153where
154 CODE: AsRef<str>,
155 DOC: AsRef<str>,
156{
157 if let Some(doc) = doc {
158 format!("```rust\n{}\n```\n\n{}", val.as_ref(), doc.as_ref())
159 } else {
160 format!("```rust\n{}\n```", val.as_ref())
161 }
162}
163
164// FIXME: this should not really use navigation target. Rather, approximately
165// resolved symbol should return a `DefId`.
166fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Option<String> {
167 match (nav.description(db), nav.docs(db)) {
168 (Some(desc), docs) => Some(rust_code_markup_with_doc(desc, docs)),
169 (None, Some(docs)) => Some(docs),
170 _ => None,
171 }
172}
173
174impl NavigationTarget {
175 fn node(&self, db: &RootDatabase) -> Option<TreeArc<SyntaxNode>> {
176 let source_file = db.parse(self.file_id());
177 let source_file = source_file.syntax();
178 let node = source_file
179 .descendants()
180 .find(|node| node.kind() == self.kind() && node.range() == self.full_range())?
181 .to_owned();
182 Some(node)
183 }
184
185 fn docs(&self, db: &RootDatabase) -> Option<String> {
186 let node = self.node(db)?;
187 fn doc_comments<N: ast::DocCommentsOwner>(node: &N) -> Option<String> {
188 node.doc_comment_text()
189 }
190
191 visitor()
192 .visit(doc_comments::<ast::FnDef>)
193 .visit(doc_comments::<ast::StructDef>)
194 .visit(doc_comments::<ast::EnumDef>)
195 .visit(doc_comments::<ast::TraitDef>)
196 .visit(doc_comments::<ast::Module>)
197 .visit(doc_comments::<ast::TypeAliasDef>)
198 .visit(doc_comments::<ast::ConstDef>)
199 .visit(doc_comments::<ast::StaticDef>)
200 .visit(doc_comments::<ast::NamedFieldDef>)
201 .visit(doc_comments::<ast::EnumVariant>)
202 .accept(&node)?
203 }
204
205 /// Get a description of this node.
206 ///
207 /// e.g. `struct Name`, `enum Name`, `fn Name`
208 fn description(&self, db: &RootDatabase) -> Option<String> {
209 // FIXME: After type inference is done, add type information to improve the output
210 let node = self.node(db)?;
211
212 fn visit_ascribed_node<T>(node: &T, prefix: &str) -> Option<String>
213 where
214 T: NameOwner + VisibilityOwner + TypeAscriptionOwner,
215 {
216 let mut string = visit_node(node, prefix)?;
217
218 if let Some(type_ref) = node.ascribed_type() {
219 string.push_str(": ");
220 type_ref.syntax().text().push_to(&mut string);
221 }
222
223 Some(string)
224 }
225
226 fn visit_node<T>(node: &T, label: &str) -> Option<String>
227 where
228 T: NameOwner + VisibilityOwner,
229 {
230 let mut string =
231 node.visibility().map(|v| format!("{} ", v.syntax().text())).unwrap_or_default();
232 string.push_str(label);
233 string.push_str(node.name()?.text().as_str());
234 Some(string)
235 }
236
237 visitor()
238 .visit(|node: &ast::FnDef| Some(crate::display::function_label(node)))
239 .visit(|node: &ast::StructDef| visit_node(node, "struct "))
240 .visit(|node: &ast::EnumDef| visit_node(node, "enum "))
241 .visit(|node: &ast::TraitDef| visit_node(node, "trait "))
242 .visit(|node: &ast::Module| visit_node(node, "mod "))
243 .visit(|node: &ast::TypeAliasDef| visit_node(node, "type "))
244 .visit(|node: &ast::ConstDef| visit_ascribed_node(node, "const "))
245 .visit(|node: &ast::StaticDef| visit_ascribed_node(node, "static "))
246 .visit(|node: &ast::NamedFieldDef| visit_ascribed_node(node, ""))
247 .visit(|node: &ast::EnumVariant| Some(node.name()?.text().to_string()))
248 .accept(&node)?
249 }
250}
251
252#[cfg(test)] 148#[cfg(test)]
253mod tests { 149mod tests {
254 use ra_syntax::TextRange; 150 use ra_syntax::TextRange;