aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_analysis/src/lib.rs5
-rw-r--r--crates/ra_editor/src/folding_ranges.rs86
-rw-r--r--crates/ra_editor/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs98
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};
34pub use ra_editor::{ 34pub 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};
38pub use job::{JobToken, JobHandle}; 39pub 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 @@
1use std::collections::HashSet;
2
3use ra_syntax::{
4 File, TextRange, SyntaxNodeRef,
5 SyntaxKind,
6 algo::{walk, Direction, siblings},
7};
8
9pub enum FoldKind {
10 Comment,
11 Imports,
12}
13
14pub struct Fold {
15 pub range: TextRange,
16 pub kind: FoldKind,
17}
18
19pub 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
56fn 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;
10mod symbols; 10mod symbols;
11mod line_index; 11mod line_index;
12mod edit; 12mod edit;
13mod folding_ranges;
13mod code_actions; 14mod code_actions;
14mod typing; 15mod typing;
15mod completion; 16mod 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 @@
1use std::collections::{HashMap, HashSet}; 1use std::collections::{HashMap};
2 2
3use languageserver_types::{ 3use 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};
10use serde_json::to_value; 10use serde_json::to_value;
11use ra_analysis::{Query, FileId, RunnableKind, JobToken}; 11use ra_analysis::{Query, FileId, RunnableKind, JobToken, FoldKind};
12use ra_syntax::{ 12use 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
18use ::{ 16use ::{
@@ -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
424fn 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
456pub fn handle_code_action( 400pub fn handle_code_action(