diff options
author | Luciano Bestia <[email protected]> | 2021-01-18 18:45:42 +0000 |
---|---|---|
committer | Luciano Bestia <[email protected]> | 2021-01-18 18:45:42 +0000 |
commit | 9f1d341ee9bf399fa8fa2a5d2fb5f91e1b319702 (patch) | |
tree | 2aef832786e9d6eaccfe7cf566113fd35421a46a | |
parent | a1c72451bb8b657f4e5a015428112090402de106 (diff) |
added region folding
-rw-r--r-- | Cargo.lock | 23 | ||||
-rw-r--r-- | crates/ide/Cargo.toml | 4 | ||||
-rw-r--r-- | crates/ide/src/folding_ranges.rs | 76 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 2 |
4 files changed, 92 insertions, 13 deletions
diff --git a/Cargo.lock b/Cargo.lock index aac473191..674c75450 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -16,6 +16,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
16 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" | 16 | checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e" |
17 | 17 | ||
18 | [[package]] | 18 | [[package]] |
19 | name = "aho-corasick" | ||
20 | version = "0.7.15" | ||
21 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
22 | checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" | ||
23 | dependencies = [ | ||
24 | "memchr", | ||
25 | ] | ||
26 | |||
27 | [[package]] | ||
19 | name = "ansi_term" | 28 | name = "ansi_term" |
20 | version = "0.12.1" | 29 | version = "0.12.1" |
21 | source = "registry+https://github.com/rust-lang/crates.io-index" | 30 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -634,16 +643,19 @@ dependencies = [ | |||
634 | "cfg", | 643 | "cfg", |
635 | "completion", | 644 | "completion", |
636 | "either", | 645 | "either", |
646 | "env_logger", | ||
637 | "expect-test", | 647 | "expect-test", |
638 | "hir", | 648 | "hir", |
639 | "ide_db", | 649 | "ide_db", |
640 | "indexmap", | 650 | "indexmap", |
641 | "itertools 0.10.0", | 651 | "itertools 0.10.0", |
652 | "lazy_static", | ||
642 | "log", | 653 | "log", |
643 | "oorandom", | 654 | "oorandom", |
644 | "profile", | 655 | "profile", |
645 | "pulldown-cmark", | 656 | "pulldown-cmark", |
646 | "pulldown-cmark-to-cmark", | 657 | "pulldown-cmark-to-cmark", |
658 | "regex", | ||
647 | "rustc-hash", | 659 | "rustc-hash", |
648 | "ssr", | 660 | "ssr", |
649 | "stdx", | 661 | "stdx", |
@@ -1301,11 +1313,14 @@ checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" | |||
1301 | 1313 | ||
1302 | [[package]] | 1314 | [[package]] |
1303 | name = "regex" | 1315 | name = "regex" |
1304 | version = "1.4.2" | 1316 | version = "1.4.3" |
1305 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1317 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1306 | checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" | 1318 | checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a" |
1307 | dependencies = [ | 1319 | dependencies = [ |
1320 | "aho-corasick", | ||
1321 | "memchr", | ||
1308 | "regex-syntax", | 1322 | "regex-syntax", |
1323 | "thread_local", | ||
1309 | ] | 1324 | ] |
1310 | 1325 | ||
1311 | [[package]] | 1326 | [[package]] |
@@ -1320,9 +1335,9 @@ dependencies = [ | |||
1320 | 1335 | ||
1321 | [[package]] | 1336 | [[package]] |
1322 | name = "regex-syntax" | 1337 | name = "regex-syntax" |
1323 | version = "0.6.21" | 1338 | version = "0.6.22" |
1324 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1339 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1325 | checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" | 1340 | checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581" |
1326 | 1341 | ||
1327 | [[package]] | 1342 | [[package]] |
1328 | name = "rowan" | 1343 | name = "rowan" |
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" } | |||
31 | ssr = { path = "../ssr", version = "0.0.0" } | 31 | ssr = { path = "../ssr", version = "0.0.0" } |
32 | completion = { path = "../completion", version = "0.0.0" } | 32 | completion = { path = "../completion", version = "0.0.0" } |
33 | 33 | ||
34 | lazy_static = "1.4.0" | ||
35 | regex = "1.4.3" | ||
36 | env_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`. |
36 | hir = { path = "../hir", version = "0.0.0" } | 40 | hir = { 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 | ||
12 | use lazy_static::lazy_static; | ||
13 | |||
12 | #[derive(Debug, PartialEq, Eq)] | 14 | #[derive(Debug, PartialEq, Eq)] |
13 | pub enum FoldKind { | 15 | pub 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 | ||
472 | calling_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); |