Skip to content

Commit dd21ad6

Browse files
Merge #10362
10362: feat: Convert a/mod.rs into a.rs r=Veykril a=longfangsong This is the reverse operation of #10211. ![demo](https://user-images.githubusercontent.com/13777628/134837717-074c23e9-1ca2-4207-b780-8443b2241272.gif) Close #10143. Co-authored-by: longfangsong <[email protected]> Co-authored-by: 龙方淞 <[email protected]>
2 parents 533ca58 + 7e3224f commit dd21ad6

File tree

7 files changed

+186
-40
lines changed

7 files changed

+186
-40
lines changed
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
use ide_db::{
2+
assists::{AssistId, AssistKind},
3+
base_db::AnchoredPathBuf,
4+
};
5+
use syntax::{ast, AstNode};
6+
7+
use crate::{
8+
assist_context::{AssistContext, Assists},
9+
utils::trimmed_text_range,
10+
};
11+
12+
// Assist: move_from_mod_rs
13+
//
14+
// Moves xxx/mod.rs to xxx.rs.
15+
//
16+
// ```
17+
// //- /main.rs
18+
// mod a;
19+
// //- /a/mod.rs
20+
// $0fn t() {}$0
21+
// ```
22+
// ->
23+
// ```
24+
// fn t() {}
25+
// ```
26+
pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
27+
let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
28+
let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
29+
// Enable this assist if the user select all "meaningful" content in the source file
30+
let trimmed_selected_range = trimmed_text_range(&source_file, ctx.frange.range);
31+
let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
32+
if !module.is_mod_rs(ctx.db()) {
33+
cov_mark::hit!(not_mod_rs);
34+
return None;
35+
}
36+
if trimmed_selected_range != trimmed_file_range {
37+
cov_mark::hit!(not_all_selected);
38+
return None;
39+
}
40+
41+
let target = source_file.syntax().text_range();
42+
let module_name = module.name(ctx.db())?.to_string();
43+
let path = format!("../{}.rs", module_name);
44+
let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
45+
acc.add(
46+
AssistId("move_from_mod_rs", AssistKind::Refactor),
47+
format!("Convert {}/mod.rs to {}.rs", module_name, module_name),
48+
target,
49+
|builder| {
50+
builder.move_file(ctx.frange.file_id, dst);
51+
},
52+
)
53+
}
54+
55+
#[cfg(test)]
56+
mod tests {
57+
use crate::tests::{check_assist, check_assist_not_applicable};
58+
59+
use super::*;
60+
61+
#[test]
62+
fn trivial() {
63+
check_assist(
64+
move_from_mod_rs,
65+
r#"
66+
//- /main.rs
67+
mod a;
68+
//- /a/mod.rs
69+
$0fn t() {}
70+
$0"#,
71+
r#"
72+
//- /a.rs
73+
fn t() {}
74+
"#,
75+
);
76+
}
77+
78+
#[test]
79+
fn must_select_all_file() {
80+
cov_mark::check!(not_all_selected);
81+
check_assist_not_applicable(
82+
move_from_mod_rs,
83+
r#"
84+
//- /main.rs
85+
mod a;
86+
//- /a/mod.rs
87+
fn t() {}$0
88+
"#,
89+
);
90+
cov_mark::check!(not_all_selected);
91+
check_assist_not_applicable(
92+
move_from_mod_rs,
93+
r#"
94+
//- /main.rs
95+
mod a;
96+
//- /a/mod.rs
97+
$0fn$0 t() {}
98+
"#,
99+
);
100+
}
101+
102+
#[test]
103+
fn cannot_move_not_mod_rs() {
104+
cov_mark::check!(not_mod_rs);
105+
check_assist_not_applicable(
106+
move_from_mod_rs,
107+
r#"//- /main.rs
108+
mod a;
109+
//- /a.rs
110+
$0fn t() {}$0
111+
"#,
112+
);
113+
}
114+
115+
#[test]
116+
fn cannot_downgrade_main_and_lib_rs() {
117+
check_assist_not_applicable(
118+
move_from_mod_rs,
119+
r#"//- /main.rs
120+
$0fn t() {}$0
121+
"#,
122+
);
123+
check_assist_not_applicable(
124+
move_from_mod_rs,
125+
r#"//- /lib.rs
126+
$0fn t() {}$0
127+
"#,
128+
);
129+
}
130+
}

crates/ide_assists/src/handlers/move_to_mod_rs.rs

Lines changed: 7 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,38 +2,12 @@ use ide_db::{
22
assists::{AssistId, AssistKind},
33
base_db::AnchoredPathBuf,
44
};
5-
use syntax::{
6-
ast::{self, Whitespace},
7-
AstNode, AstToken, SourceFile, TextRange, TextSize,
8-
};
9-
10-
use crate::assist_context::{AssistContext, Assists};
5+
use syntax::{ast, AstNode};
116

12-
/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
13-
fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
14-
let mut trimmed_range = initial_range;
15-
while source_file
16-
.syntax()
17-
.token_at_offset(trimmed_range.start())
18-
.find_map(Whitespace::cast)
19-
.is_some()
20-
&& trimmed_range.start() < trimmed_range.end()
21-
{
22-
let start = trimmed_range.start() + TextSize::from(1);
23-
trimmed_range = TextRange::new(start, trimmed_range.end());
24-
}
25-
while source_file
26-
.syntax()
27-
.token_at_offset(trimmed_range.end())
28-
.find_map(Whitespace::cast)
29-
.is_some()
30-
&& trimmed_range.start() < trimmed_range.end()
31-
{
32-
let end = trimmed_range.end() - TextSize::from(1);
33-
trimmed_range = TextRange::new(trimmed_range.start(), end);
34-
}
35-
trimmed_range
36-
}
7+
use crate::{
8+
assist_context::{AssistContext, Assists},
9+
utils::trimmed_text_range,
10+
};
3711

3812
// Assist: move_to_mod_rs
3913
//
@@ -64,16 +38,13 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<(
6438
return None;
6539
}
6640

67-
let target = TextRange::new(
68-
source_file.syntax().text_range().start(),
69-
source_file.syntax().text_range().end(),
70-
);
41+
let target = source_file.syntax().text_range();
7142
let module_name = module.name(ctx.db())?.to_string();
7243
let path = format!("./{}/mod.rs", module_name);
7344
let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
7445
acc.add(
7546
AssistId("move_to_mod_rs", AssistKind::Refactor),
76-
format!("Turn {}.rs to {}/mod.rs", module_name, module_name),
47+
format!("Convert {}.rs to {}/mod.rs", module_name, module_name),
7748
target,
7849
|builder| {
7950
builder.move_file(ctx.frange.file_id, dst);

crates/ide_assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ mod handlers {
154154
mod move_guard;
155155
mod move_module_to_file;
156156
mod move_to_mod_rs;
157+
mod move_from_mod_rs;
157158
mod pull_assignment_up;
158159
mod qualify_path;
159160
mod raw_string;
@@ -229,6 +230,7 @@ mod handlers {
229230
move_guard::move_guard_to_arm_body,
230231
move_module_to_file::move_module_to_file,
231232
move_to_mod_rs::move_to_mod_rs,
233+
move_from_mod_rs::move_from_mod_rs,
232234
pull_assignment_up::pull_assignment_up,
233235
qualify_path::qualify_path,
234236
raw_string::add_hash,

crates/ide_assists/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
169169
let sr = db.source_root(sr);
170170
let mut base = sr.path_for_file(&dst.anchor).unwrap().clone();
171171
base.pop();
172-
let created_file_path = format!("{}{}", base.to_string(), &dst.path[1..]);
172+
let created_file_path = base.join(&dst.path).unwrap();
173173
format_to!(buf, "//- {}\n", created_file_path);
174174
buf.push_str(&contents);
175175
}

crates/ide_assists/src/tests/generated.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1296,6 +1296,22 @@ fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
12961296
)
12971297
}
12981298

1299+
#[test]
1300+
fn doctest_move_from_mod_rs() {
1301+
check_doc_test(
1302+
"move_from_mod_rs",
1303+
r#####"
1304+
//- /main.rs
1305+
mod a;
1306+
//- /a/mod.rs
1307+
$0fn t() {}$0
1308+
"#####,
1309+
r#####"
1310+
fn t() {}
1311+
"#####,
1312+
)
1313+
}
1314+
12991315
#[test]
13001316
fn doctest_move_guard_to_arm_body() {
13011317
check_doc_test(

crates/ide_assists/src/utils.rs

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ use syntax::{
1414
self,
1515
edit::{self, AstNodeEdit},
1616
edit_in_place::AttrsOwnerEdit,
17-
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds,
17+
make, HasArgList, HasAttrs, HasGenericParams, HasName, HasTypeBounds, Whitespace,
1818
},
19-
ted, AstNode, Direction, SmolStr,
19+
ted, AstNode, AstToken, Direction, SmolStr, SourceFile,
2020
SyntaxKind::*,
21-
SyntaxNode, TextSize, T,
21+
SyntaxNode, TextRange, TextSize, T,
2222
};
2323

2424
use crate::assist_context::{AssistBuilder, AssistContext};
@@ -500,3 +500,29 @@ pub(crate) fn get_methods(items: &ast::AssocItemList) -> Vec<ast::Fn> {
500500
.filter(|f| f.name().is_some())
501501
.collect()
502502
}
503+
504+
/// Trim(remove leading and trailing whitespace) `initial_range` in `source_file`, return the trimmed range.
505+
pub(crate) fn trimmed_text_range(source_file: &SourceFile, initial_range: TextRange) -> TextRange {
506+
let mut trimmed_range = initial_range;
507+
while source_file
508+
.syntax()
509+
.token_at_offset(trimmed_range.start())
510+
.find_map(Whitespace::cast)
511+
.is_some()
512+
&& trimmed_range.start() < trimmed_range.end()
513+
{
514+
let start = trimmed_range.start() + TextSize::from(1);
515+
trimmed_range = TextRange::new(start, trimmed_range.end());
516+
}
517+
while source_file
518+
.syntax()
519+
.token_at_offset(trimmed_range.end())
520+
.find_map(Whitespace::cast)
521+
.is_some()
522+
&& trimmed_range.start() < trimmed_range.end()
523+
{
524+
let end = trimmed_range.end() - TextSize::from(1);
525+
trimmed_range = TextRange::new(trimmed_range.start(), end);
526+
}
527+
trimmed_range
528+
}

crates/vfs/src/vfs_path.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,7 @@ impl VirtualPath {
359359
}
360360
path = &path["../".len()..]
361361
}
362+
path = path.trim_start_matches("./");
362363
res.0 = format!("{}/{}", res.0, path);
363364
Some(res)
364365
}

0 commit comments

Comments
 (0)