diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/gen_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_editor/src/folding_ranges.rs | 142 | ||||
-rw-r--r-- | crates/ra_editor/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/Cargo.toml | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/caps.rs | 6 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 44 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/mod.rs | 1 |
8 files changed, 195 insertions, 9 deletions
diff --git a/crates/gen_lsp_server/Cargo.toml b/crates/gen_lsp_server/Cargo.toml index 4eb508fc0..6580ba6e4 100644 --- a/crates/gen_lsp_server/Cargo.toml +++ b/crates/gen_lsp_server/Cargo.toml | |||
@@ -4,7 +4,7 @@ version = "0.1.0" | |||
4 | authors = ["Aleksey Kladov <[email protected]>"] | 4 | authors = ["Aleksey Kladov <[email protected]>"] |
5 | 5 | ||
6 | [dependencies] | 6 | [dependencies] |
7 | languageserver-types = "0.50.0" | 7 | languageserver-types = "0.51.0" |
8 | log = "0.4.3" | 8 | log = "0.4.3" |
9 | 9 | ||
10 | failure = "0.1.2" | 10 | failure = "0.1.2" |
diff --git a/crates/ra_analysis/src/lib.rs b/crates/ra_analysis/src/lib.rs index 4da55ab26..b4c7db476 100644 --- a/crates/ra_analysis/src/lib.rs +++ b/crates/ra_analysis/src/lib.rs | |||
@@ -34,6 +34,7 @@ use imp::{AnalysisImpl, AnalysisHostImpl, FileResolverImp}; | |||
34 | pub use ra_editor::{ | 34 | pub use ra_editor::{ |
35 | StructureNode, LineIndex, FileSymbol, | 35 | StructureNode, LineIndex, FileSymbol, |
36 | Runnable, RunnableKind, HighlightedRange, CompletionItem, | 36 | Runnable, RunnableKind, HighlightedRange, CompletionItem, |
37 | Fold, FoldKind | ||
37 | }; | 38 | }; |
38 | pub use job::{JobToken, JobHandle}; | 39 | pub use job::{JobToken, JobHandle}; |
39 | 40 | ||
@@ -224,6 +225,10 @@ impl Analysis { | |||
224 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { | 225 | pub fn diagnostics(&self, file_id: FileId) -> Vec<Diagnostic> { |
225 | self.imp.diagnostics(file_id) | 226 | self.imp.diagnostics(file_id) |
226 | } | 227 | } |
228 | pub fn folding_ranges(&self, file_id: FileId) -> Vec<Fold> { | ||
229 | let file = self.imp.file_syntax(file_id); | ||
230 | ra_editor::folding_ranges(&file) | ||
231 | } | ||
227 | } | 232 | } |
228 | 233 | ||
229 | #[derive(Debug)] | 234 | #[derive(Debug)] |
diff --git a/crates/ra_editor/src/folding_ranges.rs b/crates/ra_editor/src/folding_ranges.rs new file mode 100644 index 000000000..817da28d1 --- /dev/null +++ b/crates/ra_editor/src/folding_ranges.rs | |||
@@ -0,0 +1,142 @@ | |||
1 | use std::collections::HashSet; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | File, TextRange, SyntaxNodeRef, | ||
5 | SyntaxKind, | ||
6 | algo::{walk, Direction, siblings}, | ||
7 | }; | ||
8 | |||
9 | #[derive(Debug, PartialEq, Eq)] | ||
10 | pub enum FoldKind { | ||
11 | Comment, | ||
12 | Imports, | ||
13 | } | ||
14 | |||
15 | #[derive(Debug)] | ||
16 | pub struct Fold { | ||
17 | pub range: TextRange, | ||
18 | pub kind: FoldKind, | ||
19 | } | ||
20 | |||
21 | pub fn folding_ranges(file: &File) -> Vec<Fold> { | ||
22 | let syntax = file.syntax(); | ||
23 | |||
24 | let mut res = vec![]; | ||
25 | let mut visited = HashSet::new(); | ||
26 | |||
27 | for node in walk::preorder(syntax) { | ||
28 | if visited.contains(&node) { | ||
29 | continue; | ||
30 | } | ||
31 | |||
32 | let range_and_kind = match node.kind() { | ||
33 | SyntaxKind::COMMENT => ( | ||
34 | contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), | ||
35 | Some(FoldKind::Comment), | ||
36 | ), | ||
37 | SyntaxKind::USE_ITEM => ( | ||
38 | contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), | ||
39 | Some(FoldKind::Imports), | ||
40 | ), | ||
41 | _ => (None, None), | ||
42 | }; | ||
43 | |||
44 | match range_and_kind { | ||
45 | (Some(range), Some(kind)) => { | ||
46 | res.push(Fold { | ||
47 | range: range, | ||
48 | kind: kind | ||
49 | }); | ||
50 | } | ||
51 | _ => {} | ||
52 | } | ||
53 | } | ||
54 | |||
55 | res | ||
56 | } | ||
57 | |||
58 | fn contiguous_range_for<'a>( | ||
59 | kind: SyntaxKind, | ||
60 | node: SyntaxNodeRef<'a>, | ||
61 | visited: &mut HashSet<SyntaxNodeRef<'a>>, | ||
62 | ) -> Option<TextRange> { | ||
63 | visited.insert(node); | ||
64 | |||
65 | let left = node; | ||
66 | let mut right = node; | ||
67 | for node in siblings(node, Direction::Forward) { | ||
68 | visited.insert(node); | ||
69 | match node.kind() { | ||
70 | SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | ||
71 | k => { | ||
72 | if k == kind { | ||
73 | right = node | ||
74 | } else { | ||
75 | break; | ||
76 | } | ||
77 | } | ||
78 | } | ||
79 | } | ||
80 | if left != right { | ||
81 | Some(TextRange::from_to( | ||
82 | left.range().start(), | ||
83 | right.range().end(), | ||
84 | )) | ||
85 | } else { | ||
86 | None | ||
87 | } | ||
88 | } | ||
89 | |||
90 | #[cfg(test)] | ||
91 | mod tests { | ||
92 | use super::*; | ||
93 | |||
94 | #[test] | ||
95 | fn test_fold_comments() { | ||
96 | let text = r#" | ||
97 | // Hello | ||
98 | // this is a multiline | ||
99 | // comment | ||
100 | // | ||
101 | |||
102 | // But this is not | ||
103 | |||
104 | fn main() { | ||
105 | // We should | ||
106 | // also | ||
107 | // fold | ||
108 | // this one. | ||
109 | }"#; | ||
110 | |||
111 | let file = File::parse(&text); | ||
112 | let folds = folding_ranges(&file); | ||
113 | assert_eq!(folds.len(), 2); | ||
114 | assert_eq!(folds[0].range.start(), 1.into()); | ||
115 | assert_eq!(folds[0].range.end(), 46.into()); | ||
116 | assert_eq!(folds[0].kind, FoldKind::Comment); | ||
117 | |||
118 | assert_eq!(folds[1].range.start(), 84.into()); | ||
119 | assert_eq!(folds[1].range.end(), 137.into()); | ||
120 | assert_eq!(folds[1].kind, FoldKind::Comment); | ||
121 | } | ||
122 | |||
123 | #[test] | ||
124 | fn test_fold_imports() { | ||
125 | let text = r#" | ||
126 | use std::str; | ||
127 | use std::vec; | ||
128 | use std::io as iop; | ||
129 | |||
130 | fn main() { | ||
131 | }"#; | ||
132 | |||
133 | let file = File::parse(&text); | ||
134 | let folds = folding_ranges(&file); | ||
135 | assert_eq!(folds.len(), 1); | ||
136 | assert_eq!(folds[0].range.start(), 1.into()); | ||
137 | assert_eq!(folds[0].range.end(), 48.into()); | ||
138 | assert_eq!(folds[0].kind, FoldKind::Imports); | ||
139 | } | ||
140 | |||
141 | |||
142 | } \ No newline at end of file | ||
diff --git a/crates/ra_editor/src/lib.rs b/crates/ra_editor/src/lib.rs index 78ed34c7c..de929d73a 100644 --- a/crates/ra_editor/src/lib.rs +++ b/crates/ra_editor/src/lib.rs | |||
@@ -10,6 +10,7 @@ mod extend_selection; | |||
10 | mod symbols; | 10 | mod symbols; |
11 | mod line_index; | 11 | mod line_index; |
12 | mod edit; | 12 | mod edit; |
13 | mod folding_ranges; | ||
13 | mod code_actions; | 14 | mod code_actions; |
14 | mod typing; | 15 | mod typing; |
15 | mod completion; | 16 | mod completion; |
@@ -36,6 +37,7 @@ pub use self::{ | |||
36 | }, | 37 | }, |
37 | typing::{join_lines, on_eq_typed}, | 38 | typing::{join_lines, on_eq_typed}, |
38 | completion::{scope_completion, CompletionItem}, | 39 | completion::{scope_completion, CompletionItem}, |
40 | folding_ranges::{Fold, FoldKind, folding_ranges} | ||
39 | }; | 41 | }; |
40 | 42 | ||
41 | #[derive(Debug)] | 43 | #[derive(Debug)] |
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml index b851f70e1..32463e499 100644 --- a/crates/ra_lsp_server/Cargo.toml +++ b/crates/ra_lsp_server/Cargo.toml | |||
@@ -15,7 +15,7 @@ crossbeam-channel = "0.2.4" | |||
15 | flexi_logger = "0.9.1" | 15 | flexi_logger = "0.9.1" |
16 | log = "0.4.3" | 16 | log = "0.4.3" |
17 | url_serde = "0.2.0" | 17 | url_serde = "0.2.0" |
18 | languageserver-types = "0.50.0" | 18 | languageserver-types = "0.51.0" |
19 | walkdir = "2.2.0" | 19 | walkdir = "2.2.0" |
20 | im = "12.0.0" | 20 | im = "12.0.0" |
21 | cargo_metadata = "0.6.0" | 21 | cargo_metadata = "0.6.0" |
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs index 7456aea8a..3c628f29c 100644 --- a/crates/ra_lsp_server/src/caps.rs +++ b/crates/ra_lsp_server/src/caps.rs | |||
@@ -1,5 +1,7 @@ | |||
1 | use languageserver_types::{ | 1 | use languageserver_types::{ |
2 | ServerCapabilities, | 2 | ServerCapabilities, |
3 | CodeActionProviderCapability, | ||
4 | FoldingRangeProviderCapability, | ||
3 | TextDocumentSyncCapability, | 5 | TextDocumentSyncCapability, |
4 | TextDocumentSyncOptions, | 6 | TextDocumentSyncOptions, |
5 | TextDocumentSyncKind, | 7 | TextDocumentSyncKind, |
@@ -32,7 +34,7 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
32 | document_highlight_provider: None, | 34 | document_highlight_provider: None, |
33 | document_symbol_provider: Some(true), | 35 | document_symbol_provider: Some(true), |
34 | workspace_symbol_provider: Some(true), | 36 | workspace_symbol_provider: Some(true), |
35 | code_action_provider: Some(true), | 37 | code_action_provider: Some(CodeActionProviderCapability::Simple(true)), |
36 | code_lens_provider: None, | 38 | code_lens_provider: None, |
37 | document_formatting_provider: None, | 39 | document_formatting_provider: None, |
38 | document_range_formatting_provider: None, | 40 | document_range_formatting_provider: None, |
@@ -40,10 +42,12 @@ pub fn server_capabilities() -> ServerCapabilities { | |||
40 | first_trigger_character: "=".to_string(), | 42 | first_trigger_character: "=".to_string(), |
41 | more_trigger_character: None, | 43 | more_trigger_character: None, |
42 | }), | 44 | }), |
45 | folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), | ||
43 | rename_provider: None, | 46 | rename_provider: None, |
44 | color_provider: None, | 47 | color_provider: None, |
45 | execute_command_provider: Some(ExecuteCommandOptions { | 48 | execute_command_provider: Some(ExecuteCommandOptions { |
46 | commands: vec!["apply_code_action".to_string()], | 49 | commands: vec!["apply_code_action".to_string()], |
47 | }), | 50 | }), |
51 | workspace: None, | ||
48 | } | 52 | } |
49 | } | 53 | } |
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index b2ebc9cdc..51061543c 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,15 +1,16 @@ | |||
1 | use std::collections::HashMap; | 1 | use std::collections::{HashMap}; |
2 | 2 | ||
3 | use languageserver_types::{ | 3 | use languageserver_types::{ |
4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, | 4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, |
5 | Command, TextDocumentIdentifier, | 5 | CodeActionResponse, Command, TextDocumentIdentifier, |
6 | SymbolInformation, Position, Location, TextEdit, | 6 | SymbolInformation, Position, Location, TextEdit, |
7 | CompletionItem, InsertTextFormat, CompletionItemKind, | 7 | CompletionItem, InsertTextFormat, CompletionItemKind, |
8 | FoldingRange, FoldingRangeParams, FoldingRangeKind | ||
8 | }; | 9 | }; |
9 | use serde_json::to_value; | 10 | use serde_json::to_value; |
10 | use ra_analysis::{Query, FileId, RunnableKind, JobToken}; | 11 | use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind}; |
11 | use ra_syntax::{ | 12 | use ra_syntax::{ |
12 | text_utils::contains_offset_nonstrict, | 13 | text_utils::contains_offset_nonstrict |
13 | }; | 14 | }; |
14 | 15 | ||
15 | use ::{ | 16 | use ::{ |
@@ -177,6 +178,7 @@ pub fn handle_workspace_symbol( | |||
177 | world, &line_index | 178 | world, &line_index |
178 | )?, | 179 | )?, |
179 | container_name: None, | 180 | container_name: None, |
181 | deprecated: None, | ||
180 | }; | 182 | }; |
181 | res.push(info); | 183 | res.push(info); |
182 | }; | 184 | }; |
@@ -365,11 +367,41 @@ pub fn handle_completion( | |||
365 | Ok(Some(req::CompletionResponse::Array(items))) | 367 | Ok(Some(req::CompletionResponse::Array(items))) |
366 | } | 368 | } |
367 | 369 | ||
370 | pub fn handle_folding_range( | ||
371 | world: ServerWorld, | ||
372 | params: FoldingRangeParams, | ||
373 | _token: JobToken, | ||
374 | ) -> Result<Option<Vec<FoldingRange>>> { | ||
375 | let file_id = params.text_document.try_conv_with(&world)?; | ||
376 | let line_index = world.analysis().file_line_index(file_id); | ||
377 | |||
378 | let res = Some(world.analysis() | ||
379 | .folding_ranges(file_id) | ||
380 | .into_iter() | ||
381 | .map(|fold| { | ||
382 | let kind = match fold.kind { | ||
383 | FoldKind::Comment => FoldingRangeKind::Comment, | ||
384 | FoldKind::Imports => FoldingRangeKind::Imports | ||
385 | }; | ||
386 | let range = fold.range.conv_with(&line_index); | ||
387 | FoldingRange { | ||
388 | start_line: range.start.line, | ||
389 | start_character: Some(range.start.character), | ||
390 | end_line: range.end.line, | ||
391 | end_character: Some(range.start.character), | ||
392 | kind: Some(kind) | ||
393 | } | ||
394 | }) | ||
395 | .collect()); | ||
396 | |||
397 | Ok(res) | ||
398 | } | ||
399 | |||
368 | pub fn handle_code_action( | 400 | pub fn handle_code_action( |
369 | world: ServerWorld, | 401 | world: ServerWorld, |
370 | params: req::CodeActionParams, | 402 | params: req::CodeActionParams, |
371 | _token: JobToken, | 403 | _token: JobToken, |
372 | ) -> Result<Option<Vec<Command>>> { | 404 | ) -> Result<Option<CodeActionResponse>> { |
373 | let file_id = params.text_document.try_conv_with(&world)?; | 405 | let file_id = params.text_document.try_conv_with(&world)?; |
374 | let line_index = world.analysis().file_line_index(file_id); | 406 | let line_index = world.analysis().file_line_index(file_id); |
375 | let range = params.range.conv_with(&line_index); | 407 | let range = params.range.conv_with(&line_index); |
@@ -392,7 +424,7 @@ pub fn handle_code_action( | |||
392 | res.push(cmd); | 424 | res.push(cmd); |
393 | } | 425 | } |
394 | 426 | ||
395 | Ok(Some(res)) | 427 | Ok(Some(CodeActionResponse::Commands(res))) |
396 | } | 428 | } |
397 | 429 | ||
398 | pub fn publish_diagnostics( | 430 | pub fn publish_diagnostics( |
diff --git a/crates/ra_lsp_server/src/main_loop/mod.rs b/crates/ra_lsp_server/src/main_loop/mod.rs index 2b2279e97..abc58b70e 100644 --- a/crates/ra_lsp_server/src/main_loop/mod.rs +++ b/crates/ra_lsp_server/src/main_loop/mod.rs | |||
@@ -253,6 +253,7 @@ fn on_request( | |||
253 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? | 253 | .on::<req::DecorationsRequest>(handlers::handle_decorations)? |
254 | .on::<req::Completion>(handlers::handle_completion)? | 254 | .on::<req::Completion>(handlers::handle_completion)? |
255 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? | 255 | .on::<req::CodeActionRequest>(handlers::handle_code_action)? |
256 | .on::<req::FoldingRangeRequest>(handlers::handle_folding_range)? | ||
256 | .finish(); | 257 | .finish(); |
257 | match req { | 258 | match req { |
258 | Ok((id, handle)) => { | 259 | Ok((id, handle)) => { |