Create modules in correct directory for nested modules in move_module assist

This commit is contained in:
Lukas Wirth 2021-06-17 12:09:28 +02:00
parent d6b8af4482
commit cd5f4121e3
2 changed files with 60 additions and 13 deletions

View file

@ -1,5 +1,8 @@
use std::iter;
use ast::edit::IndentLevel; use ast::edit::IndentLevel;
use ide_db::base_db::AnchoredPathBuf; use ide_db::base_db::AnchoredPathBuf;
use itertools::Itertools;
use stdx::format_to; use stdx::format_to;
use syntax::{ use syntax::{
ast::{self, edit::AstNodeEdit, NameOwner}, ast::{self, edit::AstNodeEdit, NameOwner},
@ -34,7 +37,10 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
let module_name = module_ast.name()?; let module_name = module_ast.name()?;
let module_def = ctx.sema.to_def(&module_ast)?; // get to the outermost module syntax so we can grab the module of file we are in
let outermost_mod_decl =
iter::successors(Some(module_ast.clone()), |module| module.parent()).last()?;
let module_def = ctx.sema.to_def(&outermost_mod_decl)?;
let parent_module = module_def.parent(ctx.db())?; let parent_module = module_def.parent(ctx.db())?;
acc.add( acc.add(
@ -43,11 +49,19 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
target, target,
|builder| { |builder| {
let path = { let path = {
let dir = match parent_module.name(ctx.db()) { let mut buf = String::from("./");
Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name), match parent_module.name(ctx.db()) {
_ => String::new(), Some(name) if !parent_module.is_mod_rs(ctx.db()) => {
}; format_to!(buf, "{}/", name)
format!("./{}{}.rs", dir, module_name) }
_ => (),
}
let segments = iter::successors(Some(module_ast.clone()), |module| module.parent())
.filter_map(|it| it.name())
.collect::<Vec<_>>();
format_to!(buf, "{}", segments.into_iter().rev().format("/"));
format_to!(buf, ".rs");
buf
}; };
let contents = { let contents = {
let items = module_items.dedent(IndentLevel(1)).to_string(); let items = module_items.dedent(IndentLevel(1)).to_string();
@ -59,14 +73,13 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Opt
items items
}; };
let mut buf = String::new(); let buf = format!("mod {};", module_name);
format_to!(buf, "mod {};", module_name);
let replacement_start = if let Some(mod_token) = module_ast.mod_token() { let replacement_start = match module_ast.mod_token() {
mod_token.text_range().start() Some(mod_token) => mod_token.text_range(),
} else { None => module_ast.syntax().text_range(),
module_ast.syntax().text_range().start() }
}; .start();
builder.replace( builder.replace(
TextRange::new(replacement_start, module_ast.syntax().text_range().end()), TextRange::new(replacement_start, module_ast.syntax().text_range().end()),
@ -209,6 +222,32 @@ mod $0tests {
mod tests; mod tests;
//- /tests.rs //- /tests.rs
#[test] fn t() {} #[test] fn t() {}
"#,
);
}
#[test]
fn extract_nested() {
check_assist(
move_module_to_file,
r#"
//- /lib.rs
mod foo;
//- /foo.rs
mod bar {
mod baz {
mod qux$0 {}
}
}
"#,
r#"
//- /foo.rs
mod bar {
mod baz {
mod qux;
}
}
//- /foo/bar/baz/qux.rs
"#, "#,
); );
} }

View file

@ -675,6 +675,14 @@ impl ast::LifetimeParam {
} }
} }
impl ast::Module {
/// Returns the parent ast::Module, this is different than the semantic parent in that this only
/// considers parent declarations in the AST
pub fn parent(&self) -> Option<ast::Module> {
self.syntax().ancestors().nth(2).and_then(ast::Module::cast)
}
}
impl ast::RangePat { impl ast::RangePat {
pub fn start(&self) -> Option<ast::Pat> { pub fn start(&self) -> Option<ast::Pat> {
self.syntax() self.syntax()