Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide/src/folding_ranges.rs')
-rwxr-xr-xcrates/ide/src/folding_ranges.rs146
1 files changed, 106 insertions, 40 deletions
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 194e8c968f..c081796d07 100755
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -2,7 +2,7 @@ use ide_db::{FxHashSet, syntax_helpers::node_ext::vis_eq};
use syntax::{
Direction, NodeOrToken, SourceFile,
SyntaxKind::{self, *},
- TextRange, TextSize,
+ SyntaxNode, TextRange, TextSize,
ast::{self, AstNode, AstToken},
match_ast,
};
@@ -16,16 +16,22 @@ const REGION_END: &str = "// endregion";
pub enum FoldKind {
Comment,
Imports,
- Mods,
+ Region,
Block,
ArgList,
- Region,
- Consts,
- Statics,
Array,
WhereClause,
ReturnType,
MatchArm,
+ Function,
+ // region: item runs
+ Modules,
+ Consts,
+ Statics,
+ TypeAliases,
+ TraitAliases,
+ ExternCrates,
+ // endregion: item runs
}
#[derive(Debug)]
@@ -41,10 +47,8 @@ pub struct Fold {
pub(crate) 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();
- let mut visited_consts = FxHashSet::default();
- let mut visited_statics = FxHashSet::default();
+ let mut visited_nodes = FxHashSet::default();
+ let mut merged_fn_bodies = FxHashSet::default();
// regions can be nested, here is a LIFO buffer
let mut region_starts: Vec<TextSize> = vec![];
@@ -57,6 +61,32 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
NodeOrToken::Token(token) => token.text().contains('\n'),
};
if is_multiline {
+ // for the func with multiline param list
+ if matches!(element.kind(), FN) {
+ if let NodeOrToken::Node(node) = &element {
+ if let Some(fn_node) = ast::Fn::cast(node.clone()) {
+ if !fn_node
+ .param_list()
+ .map(|param_list| param_list.syntax().text().contains_char('\n'))
+ .unwrap_or(false)
+ {
+ continue;
+ }
+
+ if let Some(body) = fn_node.body() {
+ res.push(Fold {
+ range: TextRange::new(
+ node.text_range().start(),
+ node.text_range().end(),
+ ),
+ kind: FoldKind::Function,
+ });
+ merged_fn_bodies.insert(body.syntax().text_range());
+ continue;
+ }
+ }
+ }
+ }
res.push(Fold { range: element.text_range(), kind });
continue;
}
@@ -93,30 +123,40 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
if module.item_list().is_none() {
if let Some(range) = contiguous_range_for_item_group(
module,
- &mut visited_mods,
+ &mut visited_nodes,
) {
- res.push(Fold { range, kind: FoldKind::Mods })
+ res.push(Fold { range, kind: FoldKind::Modules })
}
}
},
ast::Use(use_) => {
- if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_imports) {
+ if let Some(range) = contiguous_range_for_item_group(use_, &mut visited_nodes) {
res.push(Fold { range, kind: FoldKind::Imports })
}
},
ast::Const(konst) => {
- if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_consts) {
+ if let Some(range) = contiguous_range_for_item_group(konst, &mut visited_nodes) {
res.push(Fold { range, kind: FoldKind::Consts })
}
},
ast::Static(statik) => {
- if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_statics) {
+ if let Some(range) = contiguous_range_for_item_group(statik, &mut visited_nodes) {
res.push(Fold { range, kind: FoldKind::Statics })
}
},
- ast::WhereClause(where_clause) => {
- if let Some(range) = fold_range_for_where_clause(where_clause) {
- res.push(Fold { range, kind: FoldKind::WhereClause })
+ ast::TypeAlias(alias) => {
+ if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
+ res.push(Fold { range, kind: FoldKind::TypeAliases })
+ }
+ },
+ ast::TraitAlias(alias) => {
+ if let Some(range) = contiguous_range_for_item_group(alias, &mut visited_nodes) {
+ res.push(Fold { range, kind: FoldKind::TraitAliases })
+ }
+ },
+ ast::ExternCrate(extern_crate) => {
+ if let Some(range) = contiguous_range_for_item_group(extern_crate, &mut visited_nodes) {
+ res.push(Fold { range, kind: FoldKind::ExternCrates })
}
},
ast::MatchArm(match_arm) => {
@@ -137,9 +177,11 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
match kind {
COMMENT => Some(FoldKind::Comment),
- ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
+ ARG_LIST | PARAM_LIST | GENERIC_ARG_LIST | GENERIC_PARAM_LIST => Some(FoldKind::ArgList),
ARRAY_EXPR => Some(FoldKind::Array),
RET_TYPE => Some(FoldKind::ReturnType),
+ FN => Some(FoldKind::Function),
+ WHERE_CLAUSE => Some(FoldKind::WhereClause),
ASSOC_ITEM_LIST
| RECORD_FIELD_LIST
| RECORD_PAT_FIELD_LIST
@@ -155,11 +197,14 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
}
}
-fn contiguous_range_for_item_group<N>(first: N, visited: &mut FxHashSet<N>) -> Option<TextRange>
+fn contiguous_range_for_item_group<N>(
+ first: N,
+ visited: &mut FxHashSet<SyntaxNode>,
+) -> Option<TextRange>
where
N: ast::HasVisibility + Clone + Hash + Eq,
{
- if !visited.insert(first.clone()) {
+ if !visited.insert(first.syntax().clone()) {
return None;
}
@@ -183,7 +228,7 @@ where
if let Some(next) = N::cast(node) {
let next_vis = next.visibility();
if eq_visibility(next_vis.clone(), last_vis) {
- visited.insert(next.clone());
+ visited.insert(next.syntax().clone());
last_vis = next_vis;
last = next;
continue;
@@ -259,18 +304,6 @@ fn contiguous_range_for_comment(
}
}
-fn fold_range_for_where_clause(where_clause: ast::WhereClause) -> Option<TextRange> {
- let first_where_pred = where_clause.predicates().next();
- let last_where_pred = where_clause.predicates().last();
-
- if first_where_pred != last_where_pred {
- let start = where_clause.where_token()?.text_range().end();
- let end = where_clause.syntax().text_range().end();
- return Some(TextRange::new(start, end));
- }
- None
-}
-
fn fold_range_for_multiline_match_arm(match_arm: ast::MatchArm) -> Option<TextRange> {
if fold_kind(match_arm.expr()?.syntax().kind()).is_some() {
None
@@ -287,6 +320,7 @@ mod tests {
use super::*;
+ #[track_caller]
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
let (ranges, text) = extract_tags(ra_fixture, "fold");
@@ -307,22 +341,43 @@ mod tests {
let kind = match fold.kind {
FoldKind::Comment => "comment",
FoldKind::Imports => "imports",
- FoldKind::Mods => "mods",
+ FoldKind::Modules => "mods",
FoldKind::Block => "block",
FoldKind::ArgList => "arglist",
FoldKind::Region => "region",
FoldKind::Consts => "consts",
FoldKind::Statics => "statics",
+ FoldKind::TypeAliases => "typealiases",
FoldKind::Array => "array",
FoldKind::WhereClause => "whereclause",
FoldKind::ReturnType => "returntype",
FoldKind::MatchArm => "matcharm",
+ FoldKind::Function => "function",
+ FoldKind::TraitAliases => "traitaliases",
+ FoldKind::ExternCrates => "externcrates",
};
assert_eq!(kind, &attr.unwrap());
}
}
#[test]
+ fn test_fold_func_with_multiline_param_list() {
+ check(
+ r#"
+<fold function>fn func<fold arglist>(
+ a: i32,
+ b: i32,
+ c: i32,
+)</fold> <fold block>{
+
+
+
+}</fold></fold>
+"#,
+ );
+ }
+
+ #[test]
fn test_fold_comments() {
check(
r#"
@@ -534,10 +589,10 @@ const _: S = S <fold block>{
fn fold_multiline_params() {
check(
r#"
-fn foo<fold arglist>(
+<fold function>fn foo<fold arglist>(
x: i32,
y: String,
-)</fold> {}
+)</fold> {}</fold>
"#,
)
}
@@ -594,19 +649,18 @@ static SECOND_STATIC: &str = "second";</fold>
#[test]
fn fold_where_clause() {
- // fold multi-line and don't fold single line.
check(
r#"
fn foo()
-where<fold whereclause>
+<fold whereclause>where
A: Foo,
B: Foo,
C: Foo,
D: Foo,</fold> {}
fn bar()
-where
- A: Bar, {}
+<fold whereclause>where
+ A: Bar,</fold> {}
"#,
)
}
@@ -624,4 +678,16 @@ fn bar() -> (bool, bool) { (true, true) }
"#,
)
}
+
+ #[test]
+ fn fold_generics() {
+ check(
+ r#"
+type Foo<T, U> = foo<fold arglist><
+ T,
+ U,
+></fold>;
+"#,
+ )
+ }
}