From 9f44d4c56d51fdae1ff073df261b8c897b27c824 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sat, 5 Jan 2019 17:33:31 +0300 Subject: fold doc_comment into hover --- crates/ra_analysis/src/hover.rs | 111 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 108 insertions(+), 3 deletions(-) (limited to 'crates/ra_analysis/src/hover.rs') diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs index c3825f6ea..c99d87da6 100644 --- a/crates/ra_analysis/src/hover.rs +++ b/crates/ra_analysis/src/hover.rs @@ -1,7 +1,11 @@ use ra_db::{Cancelable, SyntaxDatabase}; -use ra_syntax::{ast, AstNode}; +use ra_syntax::{ + AstNode, SyntaxNode, + ast::{self, NameOwner}, + algo::visit::{visitor, Visitor}, +}; -use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange}; +use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange, NavigationTarget}; pub(crate) fn hover( db: &RootDatabase, @@ -10,7 +14,7 @@ pub(crate) fn hover( let mut res = Vec::new(); let range = if let Some(rr) = db.approximately_resolve_symbol(position)? { for nav in rr.resolves_to { - res.extend(db.doc_text_for(nav)?) + res.extend(doc_text_for(db, nav)?) } rr.reference_range } else { @@ -33,6 +37,107 @@ pub(crate) fn hover( Ok(Some(res)) } +// FIXME: this should not really use navigation target. Rather, approximatelly +// resovled symbol should return a `DefId`. +fn doc_text_for(db: &RootDatabase, nav: NavigationTarget) -> Cancelable> { + let result = match (nav.description(db), nav.docs(db)) { + (Some(desc), Some(docs)) => Some("```rust\n".to_string() + &*desc + "\n```\n\n" + &*docs), + (Some(desc), None) => Some("```rust\n".to_string() + &*desc + "\n```"), + (None, Some(docs)) => Some(docs), + _ => None, + }; + + Ok(result) +} + +impl NavigationTarget { + fn node(&self, db: &RootDatabase) -> Option { + let source_file = db.source_file(self.file_id); + let source_file = source_file.syntax(); + let node = source_file + .descendants() + .find(|node| node.kind() == self.kind && node.range() == self.range)? + .owned(); + Some(node) + } + + fn docs(&self, db: &RootDatabase) -> Option { + let node = self.node(db)?; + let node = node.borrowed(); + fn doc_comments<'a, N: ast::DocCommentsOwner<'a>>(node: N) -> Option { + let comments = node.doc_comment_text(); + if comments.is_empty() { + None + } else { + Some(comments) + } + } + + visitor() + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .visit(doc_comments::) + .accept(node)? + } + + /// Get a description of this node. + /// + /// e.g. `struct Name`, `enum Name`, `fn Name` + fn description(&self, db: &RootDatabase) -> Option { + // TODO: After type inference is done, add type information to improve the output + let node = self.node(db)?; + let node = node.borrowed(); + // TODO: Refactor to be have less repetition + visitor() + .visit(|node: ast::FnDef| { + let mut string = "fn ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::StructDef| { + let mut string = "struct ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::EnumDef| { + let mut string = "enum ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::TraitDef| { + let mut string = "trait ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::Module| { + let mut string = "mod ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::TypeDef| { + let mut string = "type ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::ConstDef| { + let mut string = "const ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .visit(|node: ast::StaticDef| { + let mut string = "static ".to_string(); + node.name()?.syntax().text().push_to(&mut string); + Some(string) + }) + .accept(node)? + } +} + #[cfg(test)] mod tests { use ra_syntax::TextRange; -- cgit v1.2.3