diff options
Diffstat (limited to 'crates/ra_analysis')
-rw-r--r-- | crates/ra_analysis/src/hover.rs | 57 | ||||
-rw-r--r-- | crates/ra_analysis/src/imp.rs | 26 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 17 |
3 files changed, 74 insertions, 26 deletions
diff --git a/crates/ra_analysis/src/hover.rs b/crates/ra_analysis/src/hover.rs new file mode 100644 index 000000000..c3825f6ea --- /dev/null +++ b/crates/ra_analysis/src/hover.rs | |||
@@ -0,0 +1,57 @@ | |||
1 | use ra_db::{Cancelable, SyntaxDatabase}; | ||
2 | use ra_syntax::{ast, AstNode}; | ||
3 | |||
4 | use crate::{db::RootDatabase, RangeInfo, FilePosition, FileRange}; | ||
5 | |||
6 | pub(crate) fn hover( | ||
7 | db: &RootDatabase, | ||
8 | position: FilePosition, | ||
9 | ) -> Cancelable<Option<RangeInfo<String>>> { | ||
10 | let mut res = Vec::new(); | ||
11 | let range = if let Some(rr) = db.approximately_resolve_symbol(position)? { | ||
12 | for nav in rr.resolves_to { | ||
13 | res.extend(db.doc_text_for(nav)?) | ||
14 | } | ||
15 | rr.reference_range | ||
16 | } else { | ||
17 | let file = db.source_file(position.file_id); | ||
18 | let expr: ast::Expr = ctry!(ra_editor::find_node_at_offset( | ||
19 | file.syntax(), | ||
20 | position.offset | ||
21 | )); | ||
22 | let frange = FileRange { | ||
23 | file_id: position.file_id, | ||
24 | range: expr.syntax().range(), | ||
25 | }; | ||
26 | res.extend(db.type_of(frange)?); | ||
27 | expr.syntax().range() | ||
28 | }; | ||
29 | if res.is_empty() { | ||
30 | return Ok(None); | ||
31 | } | ||
32 | let res = RangeInfo::new(range, res.join("\n\n---\n")); | ||
33 | Ok(Some(res)) | ||
34 | } | ||
35 | |||
36 | #[cfg(test)] | ||
37 | mod tests { | ||
38 | use ra_syntax::TextRange; | ||
39 | |||
40 | use crate::mock_analysis::single_file_with_position; | ||
41 | |||
42 | #[test] | ||
43 | fn hover_shows_type_of_an_expression() { | ||
44 | let (analysis, position) = single_file_with_position( | ||
45 | " | ||
46 | pub fn foo() -> u32 { 1 } | ||
47 | |||
48 | fn main() { | ||
49 | let foo_test = foo()<|>; | ||
50 | } | ||
51 | ", | ||
52 | ); | ||
53 | let hover = analysis.hover(position).unwrap().unwrap(); | ||
54 | assert_eq!(hover.range, TextRange::from_to(95.into(), 100.into())); | ||
55 | assert_eq!(hover.info, "u32"); | ||
56 | } | ||
57 | } | ||
diff --git a/crates/ra_analysis/src/imp.rs b/crates/ra_analysis/src/imp.rs index 10248013c..eae73c2c4 100644 --- a/crates/ra_analysis/src/imp.rs +++ b/crates/ra_analysis/src/imp.rs | |||
@@ -269,32 +269,6 @@ impl db::RootDatabase { | |||
269 | Ok(result) | 269 | Ok(result) |
270 | } | 270 | } |
271 | 271 | ||
272 | pub(crate) fn hover(&self, position: FilePosition) -> Cancelable<Option<(TextRange, String)>> { | ||
273 | let mut res = Vec::new(); | ||
274 | let range = if let Some(rr) = self.approximately_resolve_symbol(position)? { | ||
275 | for nav in rr.resolves_to { | ||
276 | res.extend(self.doc_text_for(nav)?) | ||
277 | } | ||
278 | rr.reference_range | ||
279 | } else { | ||
280 | let file = self.source_file(position.file_id); | ||
281 | let expr: ast::Expr = ctry!(ra_editor::find_node_at_offset( | ||
282 | file.syntax(), | ||
283 | position.offset | ||
284 | )); | ||
285 | let frange = FileRange { | ||
286 | file_id: position.file_id, | ||
287 | range: expr.syntax().range(), | ||
288 | }; | ||
289 | res.extend(self.type_of(frange)?); | ||
290 | expr.syntax().range() | ||
291 | }; | ||
292 | if res.is_empty() { | ||
293 | return Ok(None); | ||
294 | } | ||
295 | Ok(Some((range, res.join("\n\n---\n")))) | ||
296 | } | ||
297 | |||
298 | pub(crate) fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { | 272 | pub(crate) fn diagnostics(&self, file_id: FileId) -> Cancelable<Vec<Diagnostic>> { |
299 | let syntax = self.source_file(file_id); | 273 | let syntax = self.source_file(file_id); |
300 | 274 | ||
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 1e26a2889..1904ff884 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -21,6 +21,7 @@ mod runnables; | |||
21 | 21 | ||
22 | mod extend_selection; | 22 | mod extend_selection; |
23 | mod syntax_highlighting; | 23 | mod syntax_highlighting; |
24 | mod hover; | ||
24 | 25 | ||
25 | use std::{fmt, sync::Arc}; | 26 | use std::{fmt, sync::Arc}; |
26 | 27 | ||
@@ -260,6 +261,18 @@ impl NavigationTarget { | |||
260 | } | 261 | } |
261 | } | 262 | } |
262 | 263 | ||
264 | #[derive(Debug)] | ||
265 | pub struct RangeInfo<T> { | ||
266 | pub range: TextRange, | ||
267 | pub info: T, | ||
268 | } | ||
269 | |||
270 | impl<T> RangeInfo<T> { | ||
271 | fn new(range: TextRange, info: T) -> RangeInfo<T> { | ||
272 | RangeInfo { range, info } | ||
273 | } | ||
274 | } | ||
275 | |||
263 | /// Result of "goto def" query. | 276 | /// Result of "goto def" query. |
264 | #[derive(Debug)] | 277 | #[derive(Debug)] |
265 | pub struct ReferenceResolution { | 278 | pub struct ReferenceResolution { |
@@ -394,6 +407,10 @@ impl Analysis { | |||
394 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { | 407 | pub fn doc_text_for(&self, nav: NavigationTarget) -> Cancelable<Option<String>> { |
395 | self.db.doc_text_for(nav) | 408 | self.db.doc_text_for(nav) |
396 | } | 409 | } |
410 | /// Returns a short text descrbing element at position. | ||
411 | pub fn hover(&self, position: FilePosition) -> Cancelable<Option<RangeInfo<String>>> { | ||
412 | hover::hover(&*self.db, position) | ||
413 | } | ||
397 | /// Returns a `mod name;` declaration which created the current module. | 414 | /// Returns a `mod name;` declaration which created the current module. |
398 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { | 415 | pub fn parent_module(&self, position: FilePosition) -> Cancelable<Vec<NavigationTarget>> { |
399 | self.db.parent_module(position) | 416 | self.db.parent_module(position) |