From 27c071f7023a529d1c530e2fc3dccc1c0b65c860 Mon Sep 17 00:00:00 2001 From: Andrea Pretto Date: Fri, 25 Jan 2019 23:37:45 +0100 Subject: [PATCH] Fold blocks of mod items. Fixes #572 --- crates/ra_ide_api_light/src/folding_ranges.rs | 60 ++++++++++++++++++- .../ra_lsp_server/src/main_loop/handlers.rs | 1 + 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/crates/ra_ide_api_light/src/folding_ranges.rs b/crates/ra_ide_api_light/src/folding_ranges.rs index 288bba0ce04..0f2f1399b69 100644 --- a/crates/ra_ide_api_light/src/folding_ranges.rs +++ b/crates/ra_ide_api_light/src/folding_ranges.rs @@ -9,6 +9,7 @@ pub enum FoldKind { Comment, Imports, + Mods, Block, } @@ -22,6 +23,7 @@ pub fn folding_ranges(file: &SourceFile) -> Vec { let mut res = vec![]; let mut visited_comments = FxHashSet::default(); let mut visited_imports = FxHashSet::default(); + let mut visited_mods = FxHashSet::default(); for node in file.syntax().descendants() { // Fold items that span multiple lines @@ -53,6 +55,18 @@ pub fn folding_ranges(file: &SourceFile) -> Vec { }) } } + + // Fold groups of mods + if node.kind() == MODULE && !has_visibility(&node) && !visited_mods.contains(&node) { + if let Some(range) = + contiguous_range_for_group_unless(node, has_visibility, &mut visited_mods) + { + res.push(Fold { + range, + kind: FoldKind::Mods, + }) + } + } } res @@ -68,6 +82,10 @@ fn fold_kind(kind: SyntaxKind) -> Option { } } +fn has_visibility(node: &SyntaxNode) -> bool { + return node.descendants().any(|n| n.kind() == VISIBILITY); +} + fn has_newline(node: &SyntaxNode) -> bool { for descendant in node.descendants() { if let Some(ws) = ast::Whitespace::cast(descendant) { @@ -87,6 +105,14 @@ fn has_newline(node: &SyntaxNode) -> bool { fn contiguous_range_for_group<'a>( first: &'a SyntaxNode, visited: &mut FxHashSet<&'a SyntaxNode>, +) -> Option { + contiguous_range_for_group_unless(first, |_| false, visited) +} + +fn contiguous_range_for_group_unless<'a>( + first: &'a SyntaxNode, + unless: impl Fn(&'a SyntaxNode) -> bool, + visited: &mut FxHashSet<&'a SyntaxNode>, ) -> Option { visited.insert(first); @@ -103,7 +129,7 @@ fn contiguous_range_for_group<'a>( } // Stop if we find a node that doesn't belong to the group - if node.kind() != first.kind() { + if node.kind() != first.kind() || unless(node) { break; } @@ -244,6 +270,38 @@ fn main() { do_check(text, folds); } + #[test] + fn test_fold_mods() { + let text = r#" + +pub mod foo; +mod after_pub; +mod after_pub_next; + +mod before_pub; +mod before_pub_next; +pub mod bar; + +mod not_folding_single; +pub mod foobar; +pub not_folding_single_next; + +#[cfg(test)] +mod with_attribute; +mod with_attribute_next; + +fn main() { +}"#; + + let folds = &[ + FoldKind::Mods, + FoldKind::Mods, + FoldKind::Mods, + FoldKind::Block, + ]; + do_check(text, folds); + } + #[test] fn test_fold_import_groups() { let text = r#" diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs index c0fe0216d06..8ea9edc84fb 100644 --- a/crates/ra_lsp_server/src/main_loop/handlers.rs +++ b/crates/ra_lsp_server/src/main_loop/handlers.rs @@ -369,6 +369,7 @@ pub fn handle_folding_range( let kind = match fold.kind { FoldKind::Comment => Some(FoldingRangeKind::Comment), FoldKind::Imports => Some(FoldingRangeKind::Imports), + FoldKind::Mods => None, FoldKind::Block => None, }; let range = fold.range.conv_with(&line_index);