Skip to content

Commit 6287d38

Browse files
bors[bot]iDawer
andauthored
Merge #9944
9944: internal: introduce in-place indenting API r=matklad a=iDawer Introduce `edit_in_place::Indent` that uses mutable tree API and intended to replace `edit::AstNodeEdit`. Closes #9903 Co-authored-by: Dawer <[email protected]>
2 parents 49c02b9 + 08694dc commit 6287d38

File tree

3 files changed

+68
-25
lines changed

3 files changed

+68
-25
lines changed

crates/ide_assists/src/handlers/convert_iter_for_each_to_for.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use ide_db::helpers::FamousDefs;
22
use syntax::{
3-
ast::{self, edit::AstNodeEdit, make, ArgListOwner},
3+
ast::{self, edit_in_place::Indent, make, ArgListOwner},
44
AstNode,
55
};
66

@@ -46,24 +46,26 @@ pub(crate) fn convert_iter_for_each_to_for(acc: &mut Assists, ctx: &AssistContex
4646
let body = closure.body()?;
4747

4848
let stmt = method.syntax().parent().and_then(ast::ExprStmt::cast);
49-
let syntax = stmt.as_ref().map_or(method.syntax(), |stmt| stmt.syntax());
49+
let range = stmt.as_ref().map_or(method.syntax(), AstNode::syntax).text_range();
5050

5151
acc.add(
5252
AssistId("convert_iter_for_each_to_for", AssistKind::RefactorRewrite),
5353
"Replace this `Iterator::for_each` with a for loop",
54-
syntax.text_range(),
54+
range,
5555
|builder| {
56-
let indent = stmt.as_ref().map_or(method.indent_level(), |stmt| stmt.indent_level());
56+
let indent =
57+
stmt.as_ref().map_or_else(|| method.indent_level(), ast::ExprStmt::indent_level);
5758

5859
let block = match body {
5960
ast::Expr::BlockExpr(block) => block,
6061
_ => make::block_expr(Vec::new(), Some(body)),
6162
}
62-
.reset_indent()
63-
.indent(indent);
63+
.clone_for_update();
64+
block.reset_indent();
65+
block.indent(indent);
6466

6567
let expr_for_loop = make::expr_for_loop(param, receiver, block);
66-
builder.replace(syntax.text_range(), expr_for_loop.syntax().text())
68+
builder.replace(range, expr_for_loop.to_string())
6769
},
6870
)
6971
}

crates/syntax/src/ast/edit.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -117,9 +117,8 @@ impl IndentLevel {
117117
/// }
118118
/// ```
119119
/// if you indent the block, the `{` token would stay put.
120-
fn increase_indent(self, node: SyntaxNode) -> SyntaxNode {
121-
let res = node.clone_subtree().clone_for_update();
122-
let tokens = res.preorder_with_tokens().filter_map(|event| match event {
120+
pub(super) fn increase_indent(self, node: &SyntaxNode) {
121+
let tokens = node.preorder_with_tokens().filter_map(|event| match event {
123122
rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
124123
_ => None,
125124
});
@@ -131,12 +130,10 @@ impl IndentLevel {
131130
}
132131
}
133132
}
134-
res.clone_subtree()
135133
}
136134

137-
fn decrease_indent(self, node: SyntaxNode) -> SyntaxNode {
138-
let res = node.clone_subtree().clone_for_update();
139-
let tokens = res.preorder_with_tokens().filter_map(|event| match event {
135+
pub(super) fn decrease_indent(self, node: &SyntaxNode) {
136+
let tokens = node.preorder_with_tokens().filter_map(|event| match event {
140137
rowan::WalkEvent::Leave(NodeOrToken::Token(it)) => Some(it),
141138
_ => None,
142139
});
@@ -150,25 +147,37 @@ impl IndentLevel {
150147
}
151148
}
152149
}
153-
res.clone_subtree()
154150
}
155151
}
156152

157153
fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
158154
iter::successors(Some(token), |token| token.prev_token())
159155
}
160156

157+
/// Soft-deprecated in favor of mutable tree editing API `edit_in_place::Ident`.
161158
pub trait AstNodeEdit: AstNode + Clone + Sized {
162159
fn indent_level(&self) -> IndentLevel {
163160
IndentLevel::from_node(self.syntax())
164161
}
165162
#[must_use]
166163
fn indent(&self, level: IndentLevel) -> Self {
167-
Self::cast(level.increase_indent(self.syntax().clone())).unwrap()
164+
fn indent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode {
165+
let res = node.clone_subtree().clone_for_update();
166+
level.increase_indent(&res);
167+
res.clone_subtree()
168+
}
169+
170+
Self::cast(indent_inner(self.syntax(), level)).unwrap()
168171
}
169172
#[must_use]
170173
fn dedent(&self, level: IndentLevel) -> Self {
171-
Self::cast(level.decrease_indent(self.syntax().clone())).unwrap()
174+
fn dedent_inner(node: &SyntaxNode, level: IndentLevel) -> SyntaxNode {
175+
let res = node.clone_subtree().clone_for_update();
176+
level.decrease_indent(&res);
177+
res.clone_subtree()
178+
}
179+
180+
Self::cast(dedent_inner(self.syntax(), level)).unwrap()
172181
}
173182
#[must_use]
174183
fn reset_indent(&self) -> Self {

crates/syntax/src/ast/edit_in_place.rs

+40-8
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@ use rowan::SyntaxElement;
77

88
use crate::{
99
algo::neighbor,
10-
ast::{
11-
self,
12-
edit::{AstNodeEdit, IndentLevel},
13-
make, GenericParamsOwner,
14-
},
10+
ast::{self, edit::IndentLevel, make, GenericParamsOwner},
1511
ted::{self, Position},
1612
AstNode, AstToken, Direction,
1713
SyntaxKind::{ATTR, COMMENT, WHITESPACE},
@@ -20,7 +16,7 @@ use crate::{
2016

2117
use super::NameOwner;
2218

23-
pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit {
19+
pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner {
2420
fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
2521
fn get_or_create_where_clause(&self) -> ast::WhereClause;
2622
}
@@ -198,7 +194,7 @@ fn create_generic_param_list(position: Position) -> ast::GenericParamList {
198194
gpl
199195
}
200196

201-
pub trait AttrsOwnerEdit: ast::AttrsOwner + AstNodeEdit {
197+
pub trait AttrsOwnerEdit: ast::AttrsOwner {
202198
fn remove_attrs_and_docs(&self) {
203199
remove_attrs_and_docs(self.syntax());
204200

@@ -222,7 +218,7 @@ pub trait AttrsOwnerEdit: ast::AttrsOwner + AstNodeEdit {
222218
}
223219
}
224220

225-
impl<T: ast::AttrsOwner + AstNodeEdit> AttrsOwnerEdit for T {}
221+
impl<T: ast::AttrsOwner> AttrsOwnerEdit for T {}
226222

227223
impl ast::GenericParamList {
228224
pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
@@ -487,6 +483,24 @@ fn normalize_ws_between_braces(node: &SyntaxNode) -> Option<()> {
487483
Some(())
488484
}
489485

486+
pub trait Indent: AstNode + Clone + Sized {
487+
fn indent_level(&self) -> IndentLevel {
488+
IndentLevel::from_node(self.syntax())
489+
}
490+
fn indent(&self, level: IndentLevel) {
491+
level.increase_indent(self.syntax());
492+
}
493+
fn dedent(&self, level: IndentLevel) {
494+
level.decrease_indent(self.syntax());
495+
}
496+
fn reset_indent(&self) {
497+
let level = IndentLevel::from_node(self.syntax());
498+
self.dedent(level);
499+
}
500+
}
501+
502+
impl<N: AstNode + Clone> Indent for N {}
503+
490504
#[cfg(test)]
491505
mod tests {
492506
use std::fmt;
@@ -526,4 +540,22 @@ mod tests {
526540
check_create_gpl::<ast::Enum>("enum E", "enum E<>");
527541
check_create_gpl::<ast::Enum>("enum E {", "enum E<> {");
528542
}
543+
544+
#[test]
545+
fn test_increase_indent() {
546+
let arm_list = ast_mut_from_text::<ast::Fn>(
547+
"fn foo() {
548+
;
549+
;
550+
}",
551+
);
552+
arm_list.indent(IndentLevel(2));
553+
assert_eq!(
554+
arm_list.to_string(),
555+
"fn foo() {
556+
;
557+
;
558+
}",
559+
);
560+
}
529561
}

0 commit comments

Comments
 (0)