diff options
-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 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 50 |
4 files changed, 83 insertions, 67 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) |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 2fc4d3649..ffca3f51c 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -9,7 +9,7 @@ use languageserver_types::{ | |||
9 | Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, | 9 | Range, WorkspaceEdit, ParameterInformation, ParameterLabel, SignatureInformation, Hover, |
10 | HoverContents, DocumentFormattingParams, DocumentHighlight, | 10 | HoverContents, DocumentFormattingParams, DocumentHighlight, |
11 | }; | 11 | }; |
12 | use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity, NavigationTarget}; | 12 | use ra_analysis::{FileId, FoldKind, Query, RunnableKind, FileRange, FilePosition, Severity}; |
13 | use ra_syntax::{TextUnit, text_utils::intersect}; | 13 | use ra_syntax::{TextUnit, text_utils::intersect}; |
14 | use ra_text_edit::text_utils::contains_offset_nonstrict; | 14 | use ra_text_edit::text_utils::contains_offset_nonstrict; |
15 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
@@ -509,36 +509,18 @@ pub fn handle_hover( | |||
509 | world: ServerWorld, | 509 | world: ServerWorld, |
510 | params: req::TextDocumentPositionParams, | 510 | params: req::TextDocumentPositionParams, |
511 | ) -> Result<Option<Hover>> { | 511 | ) -> Result<Option<Hover>> { |
512 | // TODO: Cut down on number of allocations | ||
513 | let position = params.try_conv_with(&world)?; | 512 | let position = params.try_conv_with(&world)?; |
514 | let line_index = world.analysis().file_line_index(position.file_id); | 513 | let info = match world.analysis().hover(position)? { |
515 | let rr = match world.analysis().approximately_resolve_symbol(position)? { | ||
516 | None => return Ok(None), | 514 | None => return Ok(None), |
517 | Some(it) => it, | 515 | Some(info) => info, |
518 | }; | 516 | }; |
519 | let mut result = Vec::new(); | 517 | let line_index = world.analysis.file_line_index(position.file_id); |
520 | let file_id = params.text_document.try_conv_with(&world)?; | 518 | let range = info.range.conv_with(&line_index); |
521 | let file_range = FileRange { | 519 | let res = Hover { |
522 | file_id, | 520 | contents: HoverContents::Scalar(MarkedString::String(info.info)), |
523 | range: rr.reference_range, | 521 | range: Some(range), |
524 | }; | 522 | }; |
525 | if let Some(type_name) = get_type(&world, file_range) { | 523 | Ok(Some(res)) |
526 | result.push(type_name); | ||
527 | } | ||
528 | for nav in rr.resolves_to { | ||
529 | if let Some(docs) = get_doc_text(&world, nav) { | ||
530 | result.push(docs); | ||
531 | } | ||
532 | } | ||
533 | |||
534 | let range = rr.reference_range.conv_with(&line_index); | ||
535 | if result.len() > 0 { | ||
536 | return Ok(Some(Hover { | ||
537 | contents: HoverContents::Scalar(MarkedString::String(result.join("\n\n---\n"))), | ||
538 | range: Some(range), | ||
539 | })); | ||
540 | } | ||
541 | Ok(None) | ||
542 | } | 524 | } |
543 | 525 | ||
544 | /// Test doc comment | 526 | /// Test doc comment |
@@ -762,17 +744,3 @@ fn to_diagnostic_severity(severity: Severity) -> DiagnosticSeverity { | |||
762 | WeakWarning => DiagnosticSeverity::Hint, | 744 | WeakWarning => DiagnosticSeverity::Hint, |
763 | } | 745 | } |
764 | } | 746 | } |
765 | |||
766 | fn get_type(world: &ServerWorld, file_range: FileRange) -> Option<String> { | ||
767 | match world.analysis().type_of(file_range) { | ||
768 | Ok(result) => result, | ||
769 | _ => None, | ||
770 | } | ||
771 | } | ||
772 | |||
773 | fn get_doc_text(world: &ServerWorld, nav: NavigationTarget) -> Option<String> { | ||
774 | match world.analysis().doc_text_for(nav) { | ||
775 | Ok(result) => result, | ||
776 | _ => None, | ||
777 | } | ||
778 | } | ||