aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorKirill Bulatov <[email protected]>2019-07-19 22:20:09 +0100
committerKirill Bulatov <[email protected]>2019-07-20 21:45:26 +0100
commit201b344f2b0c9e84606115d135cd658d0a955d2c (patch)
tree1dc9c308c71ea4d2512d351de12933c6475abba8 /crates
parent761fc71083b9d810aa006210d6df2b0edf95cf33 (diff)
Refactor server api
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_ide_api/src/display/structure.rs27
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs110
-rw-r--r--crates/ra_ide_api/src/lib.rs7
-rw-r--r--crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap63
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs70
5 files changed, 222 insertions, 55 deletions
diff --git a/crates/ra_ide_api/src/display/structure.rs b/crates/ra_ide_api/src/display/structure.rs
index bd2e908da..2ba10b2ef 100644
--- a/crates/ra_ide_api/src/display/structure.rs
+++ b/crates/ra_ide_api/src/display/structure.rs
@@ -1,6 +1,5 @@
1use crate::TextRange; 1use crate::TextRange;
2 2
3use ra_syntax::ast::PatKind;
4use ra_syntax::{ 3use ra_syntax::{
5 algo::visit::{visitor, Visitor}, 4 algo::visit::{visitor, Visitor},
6 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, 5 ast::{self, AttrsOwner, NameOwner, TypeAscriptionOwner, TypeParamsOwner},
@@ -156,32 +155,6 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
156 } 155 }
157 decl(mc) 156 decl(mc)
158 }) 157 })
159 .visit(|let_statement: ast::LetStmt| {
160 let let_syntax = let_statement.syntax();
161
162 let mut label = String::new();
163 collapse_ws(let_syntax, &mut label);
164
165 if let_statement.ascribed_type().is_some() {
166 return None;
167 }
168
169 let pat_range = match let_statement.pat()?.kind() {
170 PatKind::BindPat(bind_pat) => bind_pat.syntax().range(),
171 PatKind::TuplePat(tuple_pat) => tuple_pat.syntax().range(),
172 _ => return None,
173 };
174
175 Some(StructureNode {
176 parent: None,
177 label,
178 navigation_range: pat_range,
179 node_range: let_syntax.range(),
180 kind: let_syntax.kind(),
181 detail: None,
182 deprecated: false,
183 })
184 })
185 .accept(&node)? 158 .accept(&node)?
186} 159}
187 160
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
new file mode 100644
index 000000000..4d1df65d0
--- /dev/null
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -0,0 +1,110 @@
1use ra_syntax::{
2 algo::visit::{visitor, Visitor},
3 ast::{self, PatKind, TypeAscriptionOwner},
4 AstNode, SmolStr, SourceFile, SyntaxNode, TextRange,
5};
6
7#[derive(Debug, PartialEq, Eq)]
8pub enum InlayKind {
9 LetBinding,
10 ClosureParameter,
11}
12
13#[derive(Debug)]
14pub struct InlayHint {
15 pub range: TextRange,
16 pub text: SmolStr,
17 pub inlay_kind: InlayKind,
18}
19
20pub(crate) fn inlay_hints(file: &SourceFile) -> Vec<InlayHint> {
21 file.syntax().descendants().map(|node| get_inlay_hints(&node)).flatten().collect()
22}
23
24fn get_inlay_hints(node: &SyntaxNode) -> Vec<InlayHint> {
25 visitor()
26 .visit(|let_statement: ast::LetStmt| {
27 let let_syntax = let_statement.syntax();
28
29 if let_statement.ascribed_type().is_some() {
30 return Vec::new();
31 }
32
33 let pat_range = match let_statement.pat().map(|pat| pat.kind()) {
34 Some(PatKind::BindPat(bind_pat)) => bind_pat.syntax().text_range(),
35 Some(PatKind::TuplePat(tuple_pat)) => tuple_pat.syntax().text_range(),
36 _ => return Vec::new(),
37 };
38
39 vec![InlayHint {
40 range: pat_range,
41 text: let_syntax.text().to_smol_string(),
42 inlay_kind: InlayKind::LetBinding,
43 }]
44 })
45 .visit(|closure_parameter: ast::LambdaExpr| {
46 if let Some(param_list) = closure_parameter.param_list() {
47 param_list
48 .params()
49 .filter(|closure_param| closure_param.ascribed_type().is_none())
50 .map(|closure_param| {
51 let closure_param_syntax = closure_param.syntax();
52 InlayHint {
53 range: closure_param_syntax.text_range(),
54 text: closure_param_syntax.text().to_smol_string(),
55 inlay_kind: InlayKind::ClosureParameter,
56 }
57 })
58 .collect()
59 } else {
60 Vec::new()
61 }
62 })
63 .accept(&node)
64 .unwrap_or_else(Vec::new)
65}
66
67#[cfg(test)]
68mod tests {
69 use super::*;
70 use insta::assert_debug_snapshot_matches;
71
72 #[test]
73 fn test_inlay_hints() {
74 let file = SourceFile::parse(
75 r#"
76struct OuterStruct {}
77
78fn main() {
79 struct InnerStruct {}
80
81 let test = 54;
82 let test = InnerStruct {};
83 let test = OuterStruct {};
84 let test = vec![222];
85 let mut test = Vec::new();
86 test.push(333);
87 let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();
88 let mut test = 33;
89 let _ = 22;
90 let test: Vec<_> = (0..3).collect();
91
92 let _ = (0..23).map(|i: u32| {
93 let i_squared = i * i;
94 i_squared
95 });
96
97 let test: i32 = 33;
98
99 let (x, c) = (42, 'a');
100 let test = (42, 'a');
101}
102
103"#,
104 )
105 .ok()
106 .unwrap();
107 let hints = inlay_hints(&file);
108 assert_debug_snapshot_matches!("inlay_hints", hints);
109 }
110}
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index c54d574bc..af163088a 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -38,6 +38,7 @@ mod join_lines;
38mod typing; 38mod typing;
39mod matching_brace; 39mod matching_brace;
40mod display; 40mod display;
41mod inlay_hints;
41 42
42#[cfg(test)] 43#[cfg(test)]
43mod marks; 44mod marks;
@@ -64,6 +65,7 @@ pub use crate::{
64 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode}, 65 display::{file_structure, FunctionSignature, NavigationTarget, StructureNode},
65 folding_ranges::{Fold, FoldKind}, 66 folding_ranges::{Fold, FoldKind},
66 hover::HoverResult, 67 hover::HoverResult,
68 inlay_hints::{InlayHint, InlayKind},
67 line_index::{LineCol, LineIndex}, 69 line_index::{LineCol, LineIndex},
68 line_index_utils::translate_offset_with_edit, 70 line_index_utils::translate_offset_with_edit,
69 references::ReferenceSearchResult, 71 references::ReferenceSearchResult,
@@ -396,6 +398,11 @@ impl Analysis {
396 file_structure(&parse.tree()) 398 file_structure(&parse.tree())
397 } 399 }
398 400
401 /// Returns a list of the places in the file where type hints can be displayed.
402 pub fn inlay_hints(&self, file_id: FileId) -> Vec<InlayHint> {
403 inlay_hints::inlay_hints(&self.db.parse(file_id).tree())
404 }
405
399 /// Returns the set of folding ranges. 406 /// Returns the set of folding ranges.
400 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { 407 pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> {
401 let parse = self.db.parse(file_id); 408 let parse = self.db.parse(file_id);
diff --git a/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap b/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap
new file mode 100644
index 000000000..f4d562314
--- /dev/null
+++ b/crates/ra_ide_api/src/snapshots/tests__inlay_hints.snap
@@ -0,0 +1,63 @@
1---
2created: "2019-07-20T20:13:53.385368Z"
3creator: [email protected]
4source: crates/ra_ide_api/src/inlay_hints.rs
5expression: hints
6---
7[
8 InlayHint {
9 range: [71; 75),
10 text: "let test = 54;",
11 inlay_kind: LetBinding,
12 },
13 InlayHint {
14 range: [90; 94),
15 text: "let test = InnerStruct {};",
16 inlay_kind: LetBinding,
17 },
18 InlayHint {
19 range: [121; 125),
20 text: "let test = OuterStruct {};",
21 inlay_kind: LetBinding,
22 },
23 InlayHint {
24 range: [152; 156),
25 text: "let test = vec![222];",
26 inlay_kind: LetBinding,
27 },
28 InlayHint {
29 range: [178; 186),
30 text: "let mut test = Vec::new();",
31 inlay_kind: LetBinding,
32 },
33 InlayHint {
34 range: [229; 233),
35 text: "let test = test.into_iter().map(|i| i * i).collect::<Vec<_>>();",
36 inlay_kind: LetBinding,
37 },
38 InlayHint {
39 range: [258; 259),
40 text: "i",
41 inlay_kind: ClosureParameter,
42 },
43 InlayHint {
44 range: [297; 305),
45 text: "let mut test = 33;",
46 inlay_kind: LetBinding,
47 },
48 InlayHint {
49 range: [417; 426),
50 text: "let i_squared = i * i;",
51 inlay_kind: LetBinding,
52 },
53 InlayHint {
54 range: [500; 506),
55 text: "let (x, c) = (42, \'a\');",
56 inlay_kind: LetBinding,
57 },
58 InlayHint {
59 range: [528; 532),
60 text: "let test = (42, \'a\');",
61 inlay_kind: LetBinding,
62 },
63]
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index ea947417f..1077aafd8 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -9,7 +9,8 @@ use lsp_types::{
9 TextDocumentIdentifier, TextEdit, WorkspaceEdit, 9 TextDocumentIdentifier, TextEdit, WorkspaceEdit,
10}; 10};
11use ra_ide_api::{ 11use ra_ide_api::{
12 AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, Query, RunnableKind, Severity, 12 AssistId, Cancelable, FileId, FilePosition, FileRange, FoldKind, InlayKind, Query,
13 RunnableKind, Severity,
13}; 14};
14use ra_prof::profile; 15use ra_prof::profile;
15use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit}; 16use ra_syntax::{AstNode, SyntaxKind, TextRange, TextUnit};
@@ -685,13 +686,14 @@ pub fn handle_code_lens(
685 params: req::CodeLensParams, 686 params: req::CodeLensParams,
686) -> Result<Option<Vec<CodeLens>>> { 687) -> Result<Option<Vec<CodeLens>>> {
687 let file_id = params.text_document.try_conv_with(&world)?; 688 let file_id = params.text_document.try_conv_with(&world)?;
688 let line_index = world.analysis().file_line_index(file_id); 689 let analysis = world.analysis();
690 let line_index = analysis.file_line_index(file_id);
689 691
690 let mut lenses: Vec<CodeLens> = Default::default(); 692 let mut lenses: Vec<CodeLens> = Default::default();
691 let workspace_root = world.workspace_root_for(file_id); 693 let workspace_root = world.workspace_root_for(file_id);
692 694
693 // Gather runnables 695 // Gather runnables
694 for runnable in world.analysis().runnables(file_id)? { 696 for runnable in analysis.runnables(file_id)? {
695 let title = match &runnable.kind { 697 let title = match &runnable.kind {
696 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => Some("▶️Run Test"), 698 RunnableKind::Test { .. } | RunnableKind::TestMod { .. } => Some("▶️Run Test"),
697 RunnableKind::Bench { .. } => Some("Run Bench"), 699 RunnableKind::Bench { .. } => Some("Run Bench"),
@@ -726,39 +728,51 @@ pub fn handle_code_lens(
726 } 728 }
727 } 729 }
728 730
729 lenses.extend(world.analysis().file_structure(file_id).into_iter().filter_map(|it| { 731 // Handle impls
730 match it.kind { 732 lenses.extend(
731 // Handle impls 733 analysis
732 SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => { 734 .file_structure(file_id)
735 .into_iter()
736 .filter(|it| match it.kind {
737 SyntaxKind::TRAIT_DEF | SyntaxKind::STRUCT_DEF | SyntaxKind::ENUM_DEF => true,
738 _ => false,
739 })
740 .map(|it| {
733 let range = it.node_range.conv_with(&line_index); 741 let range = it.node_range.conv_with(&line_index);
734 let pos = range.start; 742 let pos = range.start;
735 let lens_params = 743 let lens_params =
736 req::TextDocumentPositionParams::new(params.text_document.clone(), pos); 744 req::TextDocumentPositionParams::new(params.text_document.clone(), pos);
737 Some(CodeLens { 745 CodeLens {
738 range, 746 range,
739 command: None, 747 command: None,
740 data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()), 748 data: Some(to_value(CodeLensResolveData::Impls(lens_params)).unwrap()),
741 }) 749 }
742 } 750 }),
743 // handle let statements 751 );
744 SyntaxKind::LET_STMT => world 752
745 .analysis() 753 lenses.extend(
746 .type_of(FileRange { range: it.navigation_range, file_id }) 754 analysis
747 .ok() 755 .inlay_hints(file_id)
748 .and_then(std::convert::identity) 756 .into_iter()
749 .filter(|resolved_type| "{unknown}" != resolved_type) 757 .filter(|hint| hint.inlay_kind == InlayKind::LetBinding)
750 .map(|resolved_type| CodeLens { 758 .filter_map(|inlay_hint| {
751 range: it.node_range.conv_with(&line_index), 759 let resolved_type = analysis
752 command: Some(Command { 760 .type_of(FileRange { range: inlay_hint.range, file_id })
753 title: resolved_type, 761 .ok()
754 command: String::new(), 762 .and_then(std::convert::identity)
755 arguments: None, 763 .filter(|resolved_type| "{unknown}" != resolved_type);
756 }), 764 resolved_type.map(|resolved_type| (resolved_type, inlay_hint.range))
757 data: None, 765 })
766 .map(|(resolved_type, range)| CodeLens {
767 range: range.conv_with(&line_index),
768 command: Some(Command {
769 title: resolved_type,
770 command: String::new(),
771 arguments: None,
758 }), 772 }),
759 _ => None, 773 data: None,
760 } 774 }),
761 })); 775 );
762 Ok(Some(lenses)) 776 Ok(Some(lenses))
763} 777}
764 778