2 assists::{AssistId, AssistKind},
3 base_db::AnchoredPathBuf,
6 ast::{self, Whitespace},
7 AstNode, AstToken, SourceFile, TextRange, TextSize,
10 use crate::assist_context::{AssistContext, Assists};
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;
17 .token_at_offset(trimmed_range.start())
18 .find_map(Whitespace::cast)
20 && trimmed_range.start() < trimmed_range.end()
22 let start = trimmed_range.start() + TextSize::from(1);
23 trimmed_range = TextRange::new(start, trimmed_range.end());
27 .token_at_offset(trimmed_range.end())
28 .find_map(Whitespace::cast)
30 && trimmed_range.start() < trimmed_range.end()
32 let end = trimmed_range.end() - TextSize::from(1);
33 trimmed_range = TextRange::new(trimmed_range.start(), end);
38 // Assist: move_to_mod_rs
40 // Moves xxx.rs to xxx/mod.rs.
52 pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
53 let source_file = ctx.find_node_at_offset::<ast::SourceFile>()?;
54 let module = ctx.sema.to_module_def(ctx.frange.file_id)?;
55 // Enable this assist if the user select all "meaningful" content in the source file
56 let trimmed_selected_range = trimmed_text_range(&source_file, ctx.frange.range);
57 let trimmed_file_range = trimmed_text_range(&source_file, source_file.syntax().text_range());
58 if module.is_mod_rs(ctx.db()) {
59 cov_mark::hit!(already_mod_rs);
62 if trimmed_selected_range != trimmed_file_range {
63 cov_mark::hit!(not_all_selected);
67 let target = TextRange::new(
68 source_file.syntax().text_range().start(),
69 source_file.syntax().text_range().end(),
71 let module_name = module.name(ctx.db())?.to_string();
72 let path = format!("./{}/mod.rs", module_name);
73 let dst = AnchoredPathBuf { anchor: ctx.frange.file_id, path };
75 AssistId("move_to_mod_rs", AssistKind::Refactor),
76 format!("Turn {}.rs to {}/mod.rs", module_name, module_name),
79 builder.move_file(ctx.frange.file_id, dst);
86 use crate::tests::{check_assist, check_assist_not_applicable};
108 fn must_select_all_file() {
109 cov_mark::check!(not_all_selected);
110 check_assist_not_applicable(
119 cov_mark::check!(not_all_selected);
120 check_assist_not_applicable(
132 fn cannot_promote_mod_rs() {
133 cov_mark::check!(already_mod_rs);
134 check_assist_not_applicable(
145 fn cannot_promote_main_and_lib_rs() {
146 check_assist_not_applicable(
152 check_assist_not_applicable(
162 // note: /a/b.rs remains untouched