From 9f1d341ee9bf399fa8fa2a5d2fb5f91e1b319702 Mon Sep 17 00:00:00 2001 From: Luciano Bestia Date: Mon, 18 Jan 2021 19:45:42 +0100 Subject: added region folding --- crates/ide/src/folding_ranges.rs | 76 +++++++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 8 deletions(-) (limited to 'crates/ide/src') 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::{ 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, @@ -16,6 +18,7 @@ pub enum FoldKind { Mods, Block, ArgList, + Region, } #[derive(Debug)] @@ -29,6 +32,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { 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 = vec![]; for element in file.syntax().descendants_with_tokens() { // Fold items that span multiple lines @@ -48,10 +53,32 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec { // 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 }) + } } } } @@ -175,9 +202,21 @@ fn contiguous_range_for_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: @@ -224,6 +263,7 @@ mod tests { FoldKind::Mods => "mods", FoldKind::Block => "block", FoldKind::ArgList => "arglist", + FoldKind::Region => "region", }; assert_eq!(kind, &attr.unwrap()); } @@ -418,4 +458,24 @@ fn foo( "#, ) } + + #[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 +// region: test +// 2. some normal comment +calling_function(x,y); +// endregion: test +"#, + ) + } + + fn log_init_for_test_debug() { + let _ = env_logger::builder().is_test(true).try_init(); + } } -- cgit v1.2.3