aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_ide_api/src/hover.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_ide_api/src/hover.rs')
-rw-r--r--crates/ra_ide_api/src/hover.rs110
1 files changed, 3 insertions, 107 deletions
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;