diff options
-rw-r--r-- | crates/ra_analysis/src/lib.rs | 5 | ||||
-rw-r--r-- | crates/ra_editor/src/folding_ranges.rs | 86 | ||||
-rw-r--r-- | crates/ra_editor/src/lib.rs | 2 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/main_loop/handlers.rs | 98 |
4 files changed, 114 insertions, 77 deletions
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..4518e8d24 --- /dev/null +++ b/crates/ra_editor/src/folding_ranges.rs | |||
@@ -0,0 +1,86 @@ | |||
1 | use std::collections::HashSet; | ||
2 | |||
3 | use ra_syntax::{ | ||
4 | File, TextRange, SyntaxNodeRef, | ||
5 | SyntaxKind, | ||
6 | algo::{walk, Direction, siblings}, | ||
7 | }; | ||
8 | |||
9 | pub enum FoldKind { | ||
10 | Comment, | ||
11 | Imports, | ||
12 | } | ||
13 | |||
14 | pub struct Fold { | ||
15 | pub range: TextRange, | ||
16 | pub kind: FoldKind, | ||
17 | } | ||
18 | |||
19 | pub fn folding_ranges(file: &File) -> Vec<Fold> { | ||
20 | let syntax = file.syntax(); | ||
21 | |||
22 | let mut res = vec![]; | ||
23 | let mut visited = HashSet::new(); | ||
24 | |||
25 | for node in walk::preorder(syntax) { | ||
26 | if visited.contains(&node) { | ||
27 | continue; | ||
28 | } | ||
29 | |||
30 | let range_and_kind = match node.kind() { | ||
31 | SyntaxKind::COMMENT => ( | ||
32 | contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), | ||
33 | Some(FoldKind::Comment), | ||
34 | ), | ||
35 | SyntaxKind::USE_ITEM => ( | ||
36 | contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), | ||
37 | Some(FoldKind::Imports), | ||
38 | ), | ||
39 | _ => (None, None), | ||
40 | }; | ||
41 | |||
42 | match range_and_kind { | ||
43 | (Some(range), Some(kind)) => { | ||
44 | res.push(Fold { | ||
45 | range: range, | ||
46 | kind: kind | ||
47 | }); | ||
48 | } | ||
49 | _ => {} | ||
50 | } | ||
51 | } | ||
52 | |||
53 | res | ||
54 | } | ||
55 | |||
56 | fn contiguous_range_for<'a>( | ||
57 | kind: SyntaxKind, | ||
58 | node: SyntaxNodeRef<'a>, | ||
59 | visited: &mut HashSet<SyntaxNodeRef<'a>>, | ||
60 | ) -> Option<TextRange> { | ||
61 | visited.insert(node); | ||
62 | |||
63 | let left = node; | ||
64 | let mut right = node; | ||
65 | for node in siblings(node, Direction::Forward) { | ||
66 | visited.insert(node); | ||
67 | match node.kind() { | ||
68 | SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | ||
69 | k => { | ||
70 | if k == kind { | ||
71 | right = node | ||
72 | } else { | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | } | ||
77 | } | ||
78 | if left != right { | ||
79 | Some(TextRange::from_to( | ||
80 | left.range().start(), | ||
81 | right.range().end(), | ||
82 | )) | ||
83 | } else { | ||
84 | None | ||
85 | } | ||
86 | } \ 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/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index 36cdeda38..51061543c 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use std::collections::{HashMap, HashSet}; | 1 | use std::collections::{HashMap}; |
2 | 2 | ||
3 | use languageserver_types::{ | 3 | use languageserver_types::{ |
4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, | 4 | Diagnostic, DiagnosticSeverity, DocumentSymbol, |
@@ -8,11 +8,9 @@ use languageserver_types::{ | |||
8 | FoldingRange, FoldingRangeParams, FoldingRangeKind | 8 | FoldingRange, FoldingRangeParams, FoldingRangeKind |
9 | }; | 9 | }; |
10 | use serde_json::to_value; | 10 | use serde_json::to_value; |
11 | use ra_analysis::{Query, FileId, RunnableKind, JobToken}; | 11 | use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind}; |
12 | use ra_syntax::{ | 12 | use ra_syntax::{ |
13 | algo::{siblings, walk, Direction}, | 13 | text_utils::contains_offset_nonstrict |
14 | text_utils::contains_offset_nonstrict, | ||
15 | SyntaxKind, SyntaxNodeRef, TextRange | ||
16 | }; | 14 | }; |
17 | 15 | ||
18 | use ::{ | 16 | use ::{ |
@@ -375,82 +373,28 @@ pub fn handle_folding_range( | |||
375 | _token: JobToken, | 373 | _token: JobToken, |
376 | ) -> Result<Option<Vec<FoldingRange>>> { | 374 | ) -> Result<Option<Vec<FoldingRange>>> { |
377 | let file_id = params.text_document.try_conv_with(&world)?; | 375 | let file_id = params.text_document.try_conv_with(&world)?; |
378 | let file = world.analysis().file_syntax(file_id); | ||
379 | let line_index = world.analysis().file_line_index(file_id); | 376 | let line_index = world.analysis().file_line_index(file_id); |
380 | let syntax = file.syntax(); | ||
381 | |||
382 | let mut res = vec![]; | ||
383 | let mut visited = HashSet::new(); | ||
384 | |||
385 | for node in walk::preorder(syntax) { | ||
386 | if visited.contains(&node) { | ||
387 | continue; | ||
388 | } | ||
389 | |||
390 | let range_and_kind = match node.kind() { | ||
391 | SyntaxKind::COMMENT => ( | ||
392 | contiguous_range_for(SyntaxKind::COMMENT, node, &mut visited), | ||
393 | Some(FoldingRangeKind::Comment), | ||
394 | ), | ||
395 | SyntaxKind::USE_ITEM => ( | ||
396 | contiguous_range_for(SyntaxKind::USE_ITEM, node, &mut visited), | ||
397 | Some(FoldingRangeKind::Imports), | ||
398 | ), | ||
399 | _ => (None, None), | ||
400 | }; | ||
401 | 377 | ||
402 | match range_and_kind { | 378 | let res = Some(world.analysis() |
403 | (Some(range), Some(kind)) => { | 379 | .folding_ranges(file_id) |
404 | let range = range.conv_with(&line_index); | 380 | .into_iter() |
405 | res.push(FoldingRange { | 381 | .map(|fold| { |
406 | start_line: range.start.line, | 382 | let kind = match fold.kind { |
407 | start_character: Some(range.start.character), | 383 | FoldKind::Comment => FoldingRangeKind::Comment, |
408 | end_line: range.end.line, | 384 | FoldKind::Imports => FoldingRangeKind::Imports |
409 | end_character: Some(range.start.character), | 385 | }; |
410 | kind: Some(kind), | 386 | let range = fold.range.conv_with(&line_index); |
411 | }); | 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) | ||
412 | } | 393 | } |
413 | _ => {} | 394 | }) |
414 | } | 395 | .collect()); |
415 | } | ||
416 | |||
417 | if res.is_empty() { | ||
418 | Ok(None) | ||
419 | } else { | ||
420 | Ok(Some(res)) | ||
421 | } | ||
422 | } | ||
423 | 396 | ||
424 | fn contiguous_range_for<'a>( | 397 | Ok(res) |
425 | kind: SyntaxKind, | ||
426 | node: SyntaxNodeRef<'a>, | ||
427 | visited: &mut HashSet<SyntaxNodeRef<'a>>, | ||
428 | ) -> Option<TextRange> { | ||
429 | visited.insert(node); | ||
430 | |||
431 | let left = node; | ||
432 | let mut right = node; | ||
433 | for node in siblings(node, Direction::Forward) { | ||
434 | visited.insert(node); | ||
435 | match node.kind() { | ||
436 | SyntaxKind::WHITESPACE if !node.leaf_text().unwrap().as_str().contains("\n\n") => (), | ||
437 | k => { | ||
438 | if k == kind { | ||
439 | right = node | ||
440 | } else { | ||
441 | break; | ||
442 | } | ||
443 | } | ||
444 | } | ||
445 | } | ||
446 | if left != right { | ||
447 | Some(TextRange::from_to( | ||
448 | left.range().start(), | ||
449 | right.range().end(), | ||
450 | )) | ||
451 | } else { | ||
452 | None | ||
453 | } | ||
454 | } | 398 | } |
455 | 399 | ||
456 | pub fn handle_code_action( | 400 | pub fn handle_code_action( |