Skip to content

Commit 89e1f97

Browse files
bors[bot]bnjjjeminence
authored
Merge #4207 #4253
4207: Add unwrap block assist #4156 r=matklad a=bnjjj close issue #4156 4253: Remove `workspaceLoaded` setting r=matklad a=eminence The `workspaceLoaded` notification setting was originally designed to control the display of a popup message that said: "workspace loaded, {} rust packages" This popup was removed and replaced by a much sleeker message in the VSCode status bar that provides a real-time status while loading: rust-analyzer: {}/{} packages This was done as part of #3587 The change in this PR simply renames this setting from `workspaceLoaded` to `progress` to better describe what it actually controls. At the moment, the only type of progress message that is controlled by this setting is the initial load messages, but in theory other messages could also be controlled by this setting. Reviewer notes: * If we didn't like the idea of causing minor breaking to user's config, we could keep the setting name as `workspaceLoaded` * I think we can now close both #2719 and #3176 since the notification dialog in question no longer exists (actually I think you can close those issues even if you reject this PR 😄 ) Co-authored-by: Benjamin Coenen <[email protected]> Co-authored-by: Andrew Chin <[email protected]>
3 parents a2ae2bb + fdf8663 + 65234e8 commit 89e1f97

File tree

8 files changed

+390
-14
lines changed

8 files changed

+390
-14
lines changed

crates/ra_assists/src/doc_tests/generated.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,3 +728,22 @@ use std::{collections::HashMap};
728728
"#####,
729729
)
730730
}
731+
732+
#[test]
733+
fn doctest_unwrap_block() {
734+
check(
735+
"unwrap_block",
736+
r#####"
737+
fn foo() {
738+
if true {<|>
739+
println!("foo");
740+
}
741+
}
742+
"#####,
743+
r#####"
744+
fn foo() {
745+
println!("foo");
746+
}
747+
"#####,
748+
)
749+
}
Lines changed: 348 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,348 @@
1+
use crate::{Assist, AssistCtx, AssistId};
2+
3+
use ast::{BlockExpr, Expr, ForExpr, IfExpr, LoopBodyOwner, LoopExpr, WhileExpr};
4+
use ra_fmt::unwrap_trivial_block;
5+
use ra_syntax::{ast, AstNode, TextRange, T};
6+
7+
// Assist: unwrap_block
8+
//
9+
// This assist removes if...else, for, while and loop control statements to just keep the body.
10+
//
11+
// ```
12+
// fn foo() {
13+
// if true {<|>
14+
// println!("foo");
15+
// }
16+
// }
17+
// ```
18+
// ->
19+
// ```
20+
// fn foo() {
21+
// println!("foo");
22+
// }
23+
// ```
24+
pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> {
25+
let l_curly_token = ctx.find_token_at_offset(T!['{'])?;
26+
27+
let res = if let Some(if_expr) = l_curly_token.ancestors().find_map(IfExpr::cast) {
28+
// if expression
29+
let expr_to_unwrap = if_expr.blocks().find_map(|expr| extract_expr(ctx.frange.range, expr));
30+
let expr_to_unwrap = expr_to_unwrap?;
31+
// Find if we are in a else if block
32+
let ancestor = if_expr.syntax().ancestors().skip(1).find_map(ast::IfExpr::cast);
33+
34+
if let Some(ancestor) = ancestor {
35+
Some((ast::Expr::IfExpr(ancestor), expr_to_unwrap))
36+
} else {
37+
Some((ast::Expr::IfExpr(if_expr), expr_to_unwrap))
38+
}
39+
} else if let Some(for_expr) = l_curly_token.ancestors().find_map(ForExpr::cast) {
40+
// for expression
41+
let block_expr = for_expr.loop_body()?;
42+
extract_expr(ctx.frange.range, block_expr)
43+
.map(|expr_to_unwrap| (ast::Expr::ForExpr(for_expr), expr_to_unwrap))
44+
} else if let Some(while_expr) = l_curly_token.ancestors().find_map(WhileExpr::cast) {
45+
// while expression
46+
let block_expr = while_expr.loop_body()?;
47+
extract_expr(ctx.frange.range, block_expr)
48+
.map(|expr_to_unwrap| (ast::Expr::WhileExpr(while_expr), expr_to_unwrap))
49+
} else if let Some(loop_expr) = l_curly_token.ancestors().find_map(LoopExpr::cast) {
50+
// loop expression
51+
let block_expr = loop_expr.loop_body()?;
52+
extract_expr(ctx.frange.range, block_expr)
53+
.map(|expr_to_unwrap| (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap))
54+
} else {
55+
None
56+
};
57+
58+
let (expr, expr_to_unwrap) = res?;
59+
ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| {
60+
edit.set_cursor(expr.syntax().text_range().start());
61+
edit.target(expr_to_unwrap.syntax().text_range());
62+
63+
let pat_start: &[_] = &[' ', '{', '\n'];
64+
let expr_to_unwrap = expr_to_unwrap.to_string();
65+
let expr_string = expr_to_unwrap.trim_start_matches(pat_start);
66+
let mut expr_string_lines: Vec<&str> = expr_string.lines().collect();
67+
expr_string_lines.pop(); // Delete last line
68+
69+
let expr_string = expr_string_lines
70+
.into_iter()
71+
.map(|line| line.replacen(" ", "", 1)) // Delete indentation
72+
.collect::<Vec<String>>()
73+
.join("\n");
74+
75+
edit.replace(expr.syntax().text_range(), expr_string);
76+
})
77+
}
78+
79+
fn extract_expr(cursor_range: TextRange, block: BlockExpr) -> Option<Expr> {
80+
let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range);
81+
82+
if cursor_in_range {
83+
Some(unwrap_trivial_block(block))
84+
} else {
85+
None
86+
}
87+
}
88+
89+
#[cfg(test)]
90+
mod tests {
91+
use crate::helpers::{check_assist, check_assist_not_applicable};
92+
93+
use super::*;
94+
95+
#[test]
96+
fn simple_if() {
97+
check_assist(
98+
unwrap_block,
99+
r#"
100+
fn main() {
101+
bar();
102+
if true {<|>
103+
foo();
104+
105+
//comment
106+
bar();
107+
} else {
108+
println!("bar");
109+
}
110+
}
111+
"#,
112+
r#"
113+
fn main() {
114+
bar();
115+
<|>foo();
116+
117+
//comment
118+
bar();
119+
}
120+
"#,
121+
);
122+
}
123+
124+
#[test]
125+
fn simple_if_else() {
126+
check_assist(
127+
unwrap_block,
128+
r#"
129+
fn main() {
130+
bar();
131+
if true {
132+
foo();
133+
134+
//comment
135+
bar();
136+
} else {<|>
137+
println!("bar");
138+
}
139+
}
140+
"#,
141+
r#"
142+
fn main() {
143+
bar();
144+
<|>println!("bar");
145+
}
146+
"#,
147+
);
148+
}
149+
150+
#[test]
151+
fn simple_if_else_if() {
152+
check_assist(
153+
unwrap_block,
154+
r#"
155+
fn main() {
156+
//bar();
157+
if true {
158+
println!("true");
159+
160+
//comment
161+
//bar();
162+
} else if false {<|>
163+
println!("bar");
164+
} else {
165+
println!("foo");
166+
}
167+
}
168+
"#,
169+
r#"
170+
fn main() {
171+
//bar();
172+
<|>println!("bar");
173+
}
174+
"#,
175+
);
176+
}
177+
178+
#[test]
179+
fn simple_if_bad_cursor_position() {
180+
check_assist_not_applicable(
181+
unwrap_block,
182+
r#"
183+
fn main() {
184+
bar();<|>
185+
if true {
186+
foo();
187+
188+
//comment
189+
bar();
190+
} else {
191+
println!("bar");
192+
}
193+
}
194+
"#,
195+
);
196+
}
197+
198+
#[test]
199+
fn simple_for() {
200+
check_assist(
201+
unwrap_block,
202+
r#"
203+
fn main() {
204+
for i in 0..5 {<|>
205+
if true {
206+
foo();
207+
208+
//comment
209+
bar();
210+
} else {
211+
println!("bar");
212+
}
213+
}
214+
}
215+
"#,
216+
r#"
217+
fn main() {
218+
<|>if true {
219+
foo();
220+
221+
//comment
222+
bar();
223+
} else {
224+
println!("bar");
225+
}
226+
}
227+
"#,
228+
);
229+
}
230+
231+
#[test]
232+
fn simple_if_in_for() {
233+
check_assist(
234+
unwrap_block,
235+
r#"
236+
fn main() {
237+
for i in 0..5 {
238+
if true {<|>
239+
foo();
240+
241+
//comment
242+
bar();
243+
} else {
244+
println!("bar");
245+
}
246+
}
247+
}
248+
"#,
249+
r#"
250+
fn main() {
251+
for i in 0..5 {
252+
<|>foo();
253+
254+
//comment
255+
bar();
256+
}
257+
}
258+
"#,
259+
);
260+
}
261+
262+
#[test]
263+
fn simple_loop() {
264+
check_assist(
265+
unwrap_block,
266+
r#"
267+
fn main() {
268+
loop {<|>
269+
if true {
270+
foo();
271+
272+
//comment
273+
bar();
274+
} else {
275+
println!("bar");
276+
}
277+
}
278+
}
279+
"#,
280+
r#"
281+
fn main() {
282+
<|>if true {
283+
foo();
284+
285+
//comment
286+
bar();
287+
} else {
288+
println!("bar");
289+
}
290+
}
291+
"#,
292+
);
293+
}
294+
295+
#[test]
296+
fn simple_while() {
297+
check_assist(
298+
unwrap_block,
299+
r#"
300+
fn main() {
301+
while true {<|>
302+
if true {
303+
foo();
304+
305+
//comment
306+
bar();
307+
} else {
308+
println!("bar");
309+
}
310+
}
311+
}
312+
"#,
313+
r#"
314+
fn main() {
315+
<|>if true {
316+
foo();
317+
318+
//comment
319+
bar();
320+
} else {
321+
println!("bar");
322+
}
323+
}
324+
"#,
325+
);
326+
}
327+
328+
#[test]
329+
fn simple_if_in_while_bad_cursor_position() {
330+
check_assist_not_applicable(
331+
unwrap_block,
332+
r#"
333+
fn main() {
334+
while true {
335+
if true {
336+
foo();<|>
337+
338+
//comment
339+
bar();
340+
} else {
341+
println!("bar");
342+
}
343+
}
344+
}
345+
"#,
346+
);
347+
}
348+
}

crates/ra_assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ mod handlers {
143143
mod split_import;
144144
mod add_from_impl_for_enum;
145145
mod reorder_fields;
146+
mod unwrap_block;
146147

147148
pub(crate) fn all() -> &'static [AssistHandler] {
148149
&[
@@ -181,6 +182,7 @@ mod handlers {
181182
replace_unwrap_with_match::replace_unwrap_with_match,
182183
split_import::split_import,
183184
add_from_impl_for_enum::add_from_impl_for_enum,
185+
unwrap_block::unwrap_block,
184186
// These are manually sorted for better priorities
185187
add_missing_impl_members::add_missing_impl_members,
186188
add_missing_impl_members::add_missing_default_members,

crates/ra_syntax/src/ast/expr_extensions.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ impl ast::IfExpr {
4343
Some(res)
4444
}
4545

46-
fn blocks(&self) -> AstChildren<ast::BlockExpr> {
46+
pub fn blocks(&self) -> AstChildren<ast::BlockExpr> {
4747
support::children(self.syntax())
4848
}
4949
}

0 commit comments

Comments
 (0)