aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ide/Cargo.toml4
-rw-r--r--crates/ide/src/folding_ranges.rs76
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
3 files changed, 73 insertions, 9 deletions
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index bb28cca4d..6ec106426 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -31,6 +31,10 @@ assists = { path = "../assists", version = "0.0.0" }
31ssr = { path = "../ssr", version = "0.0.0" } 31ssr = { path = "../ssr", version = "0.0.0" }
32completion = { path = "../completion", version = "0.0.0" } 32completion = { path = "../completion", version = "0.0.0" }
33 33
34lazy_static = "1.4.0"
35regex = "1.4.3"
36env_logger = { version = "0.8.1", default-features = false }
37
34# ide should depend only on the top-level `hir` package. if you need 38# ide should depend only on the top-level `hir` package. if you need
35# something from some `hir_xxx` subpackage, reexport the API via `hir`. 39# something from some `hir_xxx` subpackage, reexport the API via `hir`.
36hir = { path = "../hir", version = "0.0.0" } 40hir = { path = "../hir", version = "0.0.0" }
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 45170dd29..99f0c3c99 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -6,9 +6,11 @@ use syntax::{
6 ast::{self, AstNode, AstToken, VisibilityOwner}, 6 ast::{self, AstNode, AstToken, VisibilityOwner},
7 Direction, NodeOrToken, SourceFile, 7 Direction, NodeOrToken, SourceFile,
8 SyntaxKind::{self, *}, 8 SyntaxKind::{self, *},
9 SyntaxNode, TextRange, 9 SyntaxNode, TextRange, TextSize,
10}; 10};
11 11
12use lazy_static::lazy_static;
13
12#[derive(Debug, PartialEq, Eq)] 14#[derive(Debug, PartialEq, Eq)]
13pub enum FoldKind { 15pub enum FoldKind {
14 Comment, 16 Comment,
@@ -16,6 +18,7 @@ pub enum FoldKind {
16 Mods, 18 Mods,
17 Block, 19 Block,
18 ArgList, 20 ArgList,
21 Region,
19} 22}
20 23
21#[derive(Debug)] 24#[derive(Debug)]
@@ -29,6 +32,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
29 let mut visited_comments = FxHashSet::default(); 32 let mut visited_comments = FxHashSet::default();
30 let mut visited_imports = FxHashSet::default(); 33 let mut visited_imports = FxHashSet::default();
31 let mut visited_mods = FxHashSet::default(); 34 let mut visited_mods = FxHashSet::default();
35 // regions can be nested, here is a LIFO buffer
36 let mut regions_starts: Vec<TextSize> = vec![];
32 37
33 for element in file.syntax().descendants_with_tokens() { 38 for element in file.syntax().descendants_with_tokens() {
34 // Fold items that span multiple lines 39 // Fold items that span multiple lines
@@ -48,10 +53,32 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
48 // Fold groups of comments 53 // Fold groups of comments
49 if let Some(comment) = ast::Comment::cast(token) { 54 if let Some(comment) = ast::Comment::cast(token) {
50 if !visited_comments.contains(&comment) { 55 if !visited_comments.contains(&comment) {
51 if let Some(range) = 56 // regions are not really comments
52 contiguous_range_for_comment(comment, &mut visited_comments) 57 use regex::Regex;
53 { 58 lazy_static! {
54 res.push(Fold { range, kind: FoldKind::Comment }) 59 static ref RE_START: Regex =
60 Regex::new(r"^\s*//\s*#?region\b").unwrap();
61 static ref RE_END: Regex =
62 Regex::new(r"^\s*//\s*#?endregion\b").unwrap();
63 }
64 if RE_START.is_match(comment.text()) {
65 regions_starts.push(comment.syntax().text_range().start());
66 } else if RE_END.is_match(comment.text()) {
67 if !regions_starts.is_empty() {
68 res.push(Fold {
69 range: TextRange::new(
70 regions_starts.pop().unwrap(),
71 comment.syntax().text_range().end(),
72 ),
73 kind: FoldKind::Region,
74 })
75 }
76 } else {
77 if let Some(range) =
78 contiguous_range_for_comment(comment, &mut visited_comments)
79 {
80 res.push(Fold { range, kind: FoldKind::Comment })
81 }
55 } 82 }
56 } 83 }
57 } 84 }
@@ -175,9 +202,21 @@ fn contiguous_range_for_comment(
175 } 202 }
176 if let Some(c) = ast::Comment::cast(token) { 203 if let Some(c) = ast::Comment::cast(token) {
177 if c.kind() == group_kind { 204 if c.kind() == group_kind {
178 visited.insert(c.clone()); 205 // regions are not really comments
179 last = c; 206 use regex::Regex;
180 continue; 207 lazy_static! {
208 static ref RE_START: Regex =
209 Regex::new(r"^\s*//\s*#?region\b").unwrap();
210 static ref RE_END: Regex =
211 Regex::new(r"^\s*//\s*#?endregion\b").unwrap();
212 }
213 if RE_START.is_match(c.text()) || RE_END.is_match(c.text()) {
214 break;
215 } else {
216 visited.insert(c.clone());
217 last = c;
218 continue;
219 }
181 } 220 }
182 } 221 }
183 // The comment group ends because either: 222 // The comment group ends because either:
@@ -224,6 +263,7 @@ mod tests {
224 FoldKind::Mods => "mods", 263 FoldKind::Mods => "mods",
225 FoldKind::Block => "block", 264 FoldKind::Block => "block",
226 FoldKind::ArgList => "arglist", 265 FoldKind::ArgList => "arglist",
266 FoldKind::Region => "region",
227 }; 267 };
228 assert_eq!(kind, &attr.unwrap()); 268 assert_eq!(kind, &attr.unwrap());
229 } 269 }
@@ -418,4 +458,24 @@ fn foo<fold arglist>(
418"#, 458"#,
419 ) 459 )
420 } 460 }
461
462 #[test]
463 fn fold_region() {
464 log_init_for_test_debug();
465 // only error level log is printed on the terminal
466 log::error!("test fold_region");
467 check(
468 r#"
469// 1. some normal comment
470<fold region>// region: test
471// 2. some normal comment
472calling_function(x,y);
473// endregion: test</fold>
474"#,
475 )
476 }
477
478 fn log_init_for_test_debug() {
479 let _ = env_logger::builder().is_test(true).try_init();
480 }
421} 481}
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1ff2d3fea..c903ab523 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -465,7 +465,7 @@ pub(crate) fn folding_range(
465 let kind = match fold.kind { 465 let kind = match fold.kind {
466 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 466 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
467 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 467 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
468 FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None, 468 FoldKind::Mods | FoldKind::Block | FoldKind::ArgList | FoldKind::Region => None,
469 }; 469 };
470 470
471 let range = range(line_index, fold.range); 471 let range = range(line_index, fold.range);