source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ee2a4ec343196209d6594e19543ae87a39f96d5534d7174822a3ad825dd6ed7e"
+[[package]]
+name = "aho-corasick"
+version = "0.7.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
+dependencies = [
+ "memchr",
+]
+
[[package]]
name = "ansi_term"
version = "0.12.1"
"cfg",
"completion",
"either",
+ "env_logger",
"expect-test",
"hir",
"ide_db",
"indexmap",
"itertools 0.10.0",
+ "lazy_static",
"log",
"oorandom",
"profile",
"pulldown-cmark",
"pulldown-cmark-to-cmark",
+ "regex",
"rustc-hash",
"ssr",
"stdx",
[[package]]
name = "regex"
-version = "1.4.2"
+version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c"
+checksum = "d9251239e129e16308e70d853559389de218ac275b515068abc96829d05b948a"
dependencies = [
+ "aho-corasick",
+ "memchr",
"regex-syntax",
+ "thread_local",
]
[[package]]
[[package]]
name = "regex-syntax"
-version = "0.6.21"
+version = "0.6.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189"
+checksum = "b5eb417147ba9860a96cfe72a0b93bf88fee1744b5636ec99ab20c1aa9376581"
[[package]]
name = "rowan"
ast::{self, AstNode, AstToken, VisibilityOwner},
Direction, NodeOrToken, SourceFile,
SyntaxKind::{self, *},
- SyntaxNode, TextRange,
+ SyntaxNode, TextRange, TextSize,
};
+use lazy_static::lazy_static;
+
#[derive(Debug, PartialEq, Eq)]
pub enum FoldKind {
Comment,
Mods,
Block,
ArgList,
+ Region,
}
#[derive(Debug)]
let mut visited_comments = FxHashSet::default();
let mut visited_imports = FxHashSet::default();
let mut visited_mods = FxHashSet::default();
+ // regions can be nested, here is a LIFO buffer
+ let mut regions_starts: Vec<TextSize> = vec![];
for element in file.syntax().descendants_with_tokens() {
// Fold items that span multiple lines
// Fold groups of comments
if let Some(comment) = ast::Comment::cast(token) {
if !visited_comments.contains(&comment) {
- if let Some(range) =
- contiguous_range_for_comment(comment, &mut visited_comments)
- {
- res.push(Fold { range, kind: FoldKind::Comment })
+ // regions are not really comments
+ use regex::Regex;
+ lazy_static! {
+ static ref RE_START: Regex =
+ Regex::new(r"^\s*//\s*#?region\b").unwrap();
+ static ref RE_END: Regex =
+ Regex::new(r"^\s*//\s*#?endregion\b").unwrap();
+ }
+ if RE_START.is_match(comment.text()) {
+ regions_starts.push(comment.syntax().text_range().start());
+ } else if RE_END.is_match(comment.text()) {
+ if !regions_starts.is_empty() {
+ res.push(Fold {
+ range: TextRange::new(
+ regions_starts.pop().unwrap(),
+ comment.syntax().text_range().end(),
+ ),
+ kind: FoldKind::Region,
+ })
+ }
+ } else {
+ if let Some(range) =
+ contiguous_range_for_comment(comment, &mut visited_comments)
+ {
+ res.push(Fold { range, kind: FoldKind::Comment })
+ }
}
}
}
}
if let Some(c) = ast::Comment::cast(token) {
if c.kind() == group_kind {
- visited.insert(c.clone());
- last = c;
- continue;
+ // regions are not really comments
+ use regex::Regex;
+ lazy_static! {
+ static ref RE_START: Regex =
+ Regex::new(r"^\s*//\s*#?region\b").unwrap();
+ static ref RE_END: Regex =
+ Regex::new(r"^\s*//\s*#?endregion\b").unwrap();
+ }
+ if RE_START.is_match(c.text()) || RE_END.is_match(c.text()) {
+ break;
+ } else {
+ visited.insert(c.clone());
+ last = c;
+ continue;
+ }
}
}
// The comment group ends because either:
FoldKind::Mods => "mods",
FoldKind::Block => "block",
FoldKind::ArgList => "arglist",
+ FoldKind::Region => "region",
};
assert_eq!(kind, &attr.unwrap());
}
"#,
)
}
+
+ #[test]
+ fn fold_region() {
+ log_init_for_test_debug();
+ // only error level log is printed on the terminal
+ log::error!("test fold_region");
+ check(
+ r#"
+// 1. some normal comment
+<fold region>// region: test
+// 2. some normal comment
+calling_function(x,y);
+// endregion: test</fold>
+"#,
+ )
+ }
+
+ fn log_init_for_test_debug() {
+ let _ = env_logger::builder().is_test(true).try_init();
+ }
}