Skip to content

Commit 657ec36

Browse files
bors[bot]Luciano Bestiabestia-devcpud36
authored
Merge #7335 #7691
7335: added region folding r=matklad a=LucianoBestia Regions of code that you'd like to be folded can be wrapped with `// #region` and `// #endregion` line comments. This is called "Region Folding". It is originally available for many languages in VSCode. But Rust-analyzer has its own folding function and this is missing. With this Pull Request I am suggesting a simple solution. The regions are a special kind of comments, so I added a bit of code in the comment folding function. The regex to match are: `^\s*//\s*#?region\b` and `^\s*//\s*#?endregion\b`. The number of space characters is not important. There is an optional # character. The line can end with a name of the region. Example: ```rust // 1. some normal comment // region: test // 2. some normal comment calling_function(x,y); // endregion: test ``` I added a test for this new functionality in `folding_ranges.rs`. Please, take a look and comment. I found that these exact regexes are already present in the file `language-configuration.json`, but I don't find a way to read this configuration. So my regex is hardcoded in the code. 7691: Suggest name in extract variable r=matklad a=cpud36 Generate better default name in extract variable assist as was mentioned in issue #1587 # Currently supported (in order of declining precedence) 1. Expr is argument to a function; use corresponding parameter name 2. Expr is result of a function or method call; use this function/method's name 3. Use expr type name (if possible) 4. Fallback to `var_name` otherwise # Showcase ![generate_derive_variable_name_from_method](https://user-images.githubusercontent.com/4218373/108013304-72105400-701c-11eb-9f13-eec52e74d0cc.gif) ![generate_derive_variable_name_from_param](https://user-images.githubusercontent.com/4218373/108013305-72a8ea80-701c-11eb-957e-2214f7f005de.gif) # Questions * Should we more aggressively strip known types? E.g. we already strip `&T -> T`; should we strip `Option<T> -> T`, `Result<T, E> -> T`, and others? * Integers and floats use `var_name` by default. Should we introduce a name, like `i`, `f` etc? * Can we return a list and suggest a name when renaming(like IntelliJ does)? * Should we add counters to remove duplicate variables? E.g. `type`, `type1`, type2`, etc. Co-authored-by: Luciano Bestia <LucianoBestia@gmail.com> Co-authored-by: Luciano <31509965+LucianoBestia@users.noreply.github.com> Co-authored-by: Vladyslav Katasonov <cpud47@gmail.com>
3 parents 91bf5fa + 864fb06 + 7066e6b commit 657ec36

File tree

6 files changed

+1174
-16
lines changed

6 files changed

+1174
-16
lines changed

crates/ide/src/folding_ranges.rs

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use syntax::{
66
ast::{self, AstNode, AstToken, VisibilityOwner},
77
Direction, NodeOrToken, SourceFile,
88
SyntaxKind::{self, *},
9-
SyntaxNode, TextRange,
9+
SyntaxNode, TextRange, TextSize,
1010
};
1111

1212
#[derive(Debug, PartialEq, Eq)]
@@ -16,6 +16,7 @@ pub enum FoldKind {
1616
Mods,
1717
Block,
1818
ArgList,
19+
Region,
1920
}
2021

2122
#[derive(Debug)]
@@ -29,6 +30,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
2930
let mut visited_comments = FxHashSet::default();
3031
let mut visited_imports = FxHashSet::default();
3132
let mut visited_mods = FxHashSet::default();
33+
// regions can be nested, here is a LIFO buffer
34+
let mut regions_starts: Vec<TextSize> = vec![];
3235

3336
for element in file.syntax().descendants_with_tokens() {
3437
// Fold items that span multiple lines
@@ -48,10 +51,25 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
4851
// Fold groups of comments
4952
if let Some(comment) = ast::Comment::cast(token) {
5053
if !visited_comments.contains(&comment) {
51-
if let Some(range) =
52-
contiguous_range_for_comment(comment, &mut visited_comments)
53-
{
54-
res.push(Fold { range, kind: FoldKind::Comment })
54+
// regions are not real comments
55+
if comment.text().trim().starts_with("// region:") {
56+
regions_starts.push(comment.syntax().text_range().start());
57+
} else if comment.text().trim().starts_with("// endregion") {
58+
if let Some(region) = regions_starts.pop() {
59+
res.push(Fold {
60+
range: TextRange::new(
61+
region,
62+
comment.syntax().text_range().end(),
63+
),
64+
kind: FoldKind::Region,
65+
})
66+
}
67+
} else {
68+
if let Some(range) =
69+
contiguous_range_for_comment(comment, &mut visited_comments)
70+
{
71+
res.push(Fold { range, kind: FoldKind::Comment })
72+
}
5573
}
5674
}
5775
}
@@ -175,9 +193,16 @@ fn contiguous_range_for_comment(
175193
}
176194
if let Some(c) = ast::Comment::cast(token) {
177195
if c.kind() == group_kind {
178-
visited.insert(c.clone());
179-
last = c;
180-
continue;
196+
// regions are not real comments
197+
if c.text().trim().starts_with("// region:")
198+
|| c.text().trim().starts_with("// endregion")
199+
{
200+
break;
201+
} else {
202+
visited.insert(c.clone());
203+
last = c;
204+
continue;
205+
}
181206
}
182207
}
183208
// The comment group ends because either:
@@ -224,6 +249,7 @@ mod tests {
224249
FoldKind::Mods => "mods",
225250
FoldKind::Block => "block",
226251
FoldKind::ArgList => "arglist",
252+
FoldKind::Region => "region",
227253
};
228254
assert_eq!(kind, &attr.unwrap());
229255
}
@@ -415,6 +441,19 @@ fn foo<fold arglist>(
415441
x: i32,
416442
y: String,
417443
)</fold> {}
444+
"#,
445+
)
446+
}
447+
448+
#[test]
449+
fn fold_region() {
450+
check(
451+
r#"
452+
// 1. some normal comment
453+
<fold region>// region: test
454+
// 2. some normal comment
455+
calling_function(x,y);
456+
// endregion: test</fold>
418457
"#,
419458
)
420459
}

crates/ide_assists/src/handlers/extract_variable.rs

Lines changed: 202 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use syntax::{
88
};
99
use test_utils::mark;
1010

11-
use crate::{AssistContext, AssistId, AssistKind, Assists};
11+
use crate::{utils::suggest_name, AssistContext, AssistId, AssistKind, Assists};
1212

1313
// Assist: extract_variable
1414
//
@@ -54,7 +54,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
5454

5555
let var_name = match &field_shorthand {
5656
Some(it) => it.to_string(),
57-
None => "var_name".to_string(),
57+
None => suggest_name::variable(&to_extract, &ctx.sema),
5858
};
5959
let expr_range = match &field_shorthand {
6060
Some(it) => it.syntax().text_range().cover(to_extract.syntax().text_range()),
@@ -274,8 +274,8 @@ fn foo() {
274274
"#,
275275
r#"
276276
fn foo() {
277-
let $0var_name = bar(1 + 1);
278-
var_name
277+
let $0bar = bar(1 + 1);
278+
bar
279279
}
280280
"#,
281281
)
@@ -401,8 +401,8 @@ fn main() {
401401
",
402402
"
403403
fn main() {
404-
let $0var_name = bar.foo();
405-
let v = var_name;
404+
let $0foo = bar.foo();
405+
let v = foo;
406406
}
407407
",
408408
);
@@ -556,6 +556,202 @@ fn main() {
556556
)
557557
}
558558

559+
#[test]
560+
fn extract_var_name_from_type() {
561+
check_assist(
562+
extract_variable,
563+
r#"
564+
struct Test(i32);
565+
566+
fn foo() -> Test {
567+
$0{ Test(10) }$0
568+
}
569+
"#,
570+
r#"
571+
struct Test(i32);
572+
573+
fn foo() -> Test {
574+
let $0test = { Test(10) };
575+
test
576+
}
577+
"#,
578+
)
579+
}
580+
581+
#[test]
582+
fn extract_var_name_from_parameter() {
583+
check_assist(
584+
extract_variable,
585+
r#"
586+
fn bar(test: u32, size: u32)
587+
588+
fn foo() {
589+
bar(1, $01+1$0);
590+
}
591+
"#,
592+
r#"
593+
fn bar(test: u32, size: u32)
594+
595+
fn foo() {
596+
let $0size = 1+1;
597+
bar(1, size);
598+
}
599+
"#,
600+
)
601+
}
602+
603+
#[test]
604+
fn extract_var_parameter_name_has_precedence_over_type() {
605+
check_assist(
606+
extract_variable,
607+
r#"
608+
struct TextSize(u32);
609+
fn bar(test: u32, size: TextSize)
610+
611+
fn foo() {
612+
bar(1, $0{ TextSize(1+1) }$0);
613+
}
614+
"#,
615+
r#"
616+
struct TextSize(u32);
617+
fn bar(test: u32, size: TextSize)
618+
619+
fn foo() {
620+
let $0size = { TextSize(1+1) };
621+
bar(1, size);
622+
}
623+
"#,
624+
)
625+
}
626+
627+
#[test]
628+
fn extract_var_name_from_function() {
629+
check_assist(
630+
extract_variable,
631+
r#"
632+
fn is_required(test: u32, size: u32) -> bool
633+
634+
fn foo() -> bool {
635+
$0is_required(1, 2)$0
636+
}
637+
"#,
638+
r#"
639+
fn is_required(test: u32, size: u32) -> bool
640+
641+
fn foo() -> bool {
642+
let $0is_required = is_required(1, 2);
643+
is_required
644+
}
645+
"#,
646+
)
647+
}
648+
649+
#[test]
650+
fn extract_var_name_from_method() {
651+
check_assist(
652+
extract_variable,
653+
r#"
654+
struct S;
655+
impl S {
656+
fn bar(&self, n: u32) -> u32 { n }
657+
}
658+
659+
fn foo() -> u32 {
660+
$0S.bar(1)$0
661+
}
662+
"#,
663+
r#"
664+
struct S;
665+
impl S {
666+
fn bar(&self, n: u32) -> u32 { n }
667+
}
668+
669+
fn foo() -> u32 {
670+
let $0bar = S.bar(1);
671+
bar
672+
}
673+
"#,
674+
)
675+
}
676+
677+
#[test]
678+
fn extract_var_name_from_method_param() {
679+
check_assist(
680+
extract_variable,
681+
r#"
682+
struct S;
683+
impl S {
684+
fn bar(&self, n: u32, size: u32) { n }
685+
}
686+
687+
fn foo() {
688+
S.bar($01 + 1$0, 2)
689+
}
690+
"#,
691+
r#"
692+
struct S;
693+
impl S {
694+
fn bar(&self, n: u32, size: u32) { n }
695+
}
696+
697+
fn foo() {
698+
let $0n = 1 + 1;
699+
S.bar(n, 2)
700+
}
701+
"#,
702+
)
703+
}
704+
705+
#[test]
706+
fn extract_var_name_from_ufcs_method_param() {
707+
check_assist(
708+
extract_variable,
709+
r#"
710+
struct S;
711+
impl S {
712+
fn bar(&self, n: u32, size: u32) { n }
713+
}
714+
715+
fn foo() {
716+
S::bar(&S, $01 + 1$0, 2)
717+
}
718+
"#,
719+
r#"
720+
struct S;
721+
impl S {
722+
fn bar(&self, n: u32, size: u32) { n }
723+
}
724+
725+
fn foo() {
726+
let $0n = 1 + 1;
727+
S::bar(&S, n, 2)
728+
}
729+
"#,
730+
)
731+
}
732+
733+
#[test]
734+
fn extract_var_parameter_name_has_precedence_over_function() {
735+
check_assist(
736+
extract_variable,
737+
r#"
738+
fn bar(test: u32, size: u32)
739+
740+
fn foo() {
741+
bar(1, $0symbol_size(1, 2)$0);
742+
}
743+
"#,
744+
r#"
745+
fn bar(test: u32, size: u32)
746+
747+
fn foo() {
748+
let $0size = symbol_size(1, 2);
749+
bar(1, size);
750+
}
751+
"#,
752+
)
753+
}
754+
559755
#[test]
560756
fn test_extract_var_for_return_not_applicable() {
561757
check_assist_not_applicable(extract_variable, "fn foo() { $0return$0; } ");

0 commit comments

Comments
 (0)