659: Fold blocks of mod items r=matklad a=eulerdisk

Fixes #572

As requested, we ignore `mod`s with a visibility specifier.

Co-authored-by: Andrea Pretto <eulerdisk@gmail.com>
This commit is contained in:
bors[bot] 2019-01-26 12:49:08 +00:00
commit 3feaf2a008
2 changed files with 64 additions and 1 deletions

View File

@ -9,6 +9,7 @@ use ra_syntax::{
pub enum FoldKind {
Comment,
Imports,
Mods,
Block,
}
@ -22,6 +23,7 @@ pub fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
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> {
})
}
}
// 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,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
}
}
fn has_visibility(node: &SyntaxNode) -> bool {
use ast::VisibilityOwner;
return ast::Module::cast(node)
.and_then(|m| m.visibility())
.is_some();
}
fn has_newline(node: &SyntaxNode) -> bool {
for descendant in node.descendants() {
if let Some(ws) = ast::Whitespace::cast(descendant) {
@ -87,6 +109,14 @@ fn has_newline(node: &SyntaxNode) -> bool {
fn contiguous_range_for_group<'a>(
first: &'a SyntaxNode,
visited: &mut FxHashSet<&'a SyntaxNode>,
) -> Option<TextRange> {
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<TextRange> {
visited.insert(first);
@ -103,7 +133,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 +274,38 @@ fn main() <fold>{
do_check(text, folds);
}
#[test]
fn test_fold_mods() {
let text = r#"
pub mod foo;
<fold>mod after_pub;
mod after_pub_next;</fold>
<fold>mod before_pub;
mod before_pub_next;</fold>
pub mod bar;
mod not_folding_single;
pub mod foobar;
pub not_folding_single_next;
<fold>#[cfg(test)]
mod with_attribute;
mod with_attribute_next;</fold>
fn main() <fold>{
}</fold>"#;
let folds = &[
FoldKind::Mods,
FoldKind::Mods,
FoldKind::Mods,
FoldKind::Block,
];
do_check(text, folds);
}
#[test]
fn test_fold_import_groups() {
let text = r#"

View File

@ -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);