aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/assists/src/handlers/extract_module_to_file.rs169
-rw-r--r--crates/rust-analyzer/src/config.rs34
2 files changed, 83 insertions, 120 deletions
diff --git a/crates/assists/src/handlers/extract_module_to_file.rs b/crates/assists/src/handlers/extract_module_to_file.rs
index 5fc190fa6..3e67fdca2 100644
--- a/crates/assists/src/handlers/extract_module_to_file.rs
+++ b/crates/assists/src/handlers/extract_module_to_file.rs
@@ -1,5 +1,5 @@
1use ast::edit::IndentLevel; 1use ast::edit::IndentLevel;
2use ide_db::base_db::{AnchoredPathBuf, SourceDatabaseExt}; 2use ide_db::base_db::AnchoredPathBuf;
3use syntax::{ 3use syntax::{
4 ast::{self, edit::AstNodeEdit, NameOwner}, 4 ast::{self, edit::AstNodeEdit, NameOwner},
5 AstNode, 5 AstNode,
@@ -21,43 +21,44 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
21// mod foo; 21// mod foo;
22// ``` 22// ```
23pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 23pub(crate) fn extract_module_to_file(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let assist_id = AssistId("extract_module_to_file", AssistKind::RefactorExtract);
25 let assist_label = "Extract module to file";
26 let db = ctx.db();
27 let module_ast = ctx.find_node_at_offset::<ast::Module>()?; 24 let module_ast = ctx.find_node_at_offset::<ast::Module>()?;
28 let module_items = module_ast.item_list()?;
29 let dedent_module_items_text = module_items.dedent(IndentLevel(1)).to_string();
30 let module_name = module_ast.name()?; 25 let module_name = module_ast.name()?;
26
27 let module_def = ctx.sema.to_def(&module_ast)?;
28 let parent_module = module_def.parent(ctx.db())?;
29
30 let module_items = module_ast.item_list()?;
31 let target = module_ast.syntax().text_range(); 31 let target = module_ast.syntax().text_range();
32 let anchor_file_id = ctx.frange.file_id; 32 let anchor_file_id = ctx.frange.file_id;
33 let sr = db.file_source_root(anchor_file_id);
34 let sr = db.source_root(sr);
35 let file_path = sr.path_for_file(&anchor_file_id)?;
36 let (file_name, file_ext) = file_path.name_and_extension()?;
37 acc.add(assist_id, assist_label, target, |builder| {
38 builder.replace(target, format!("mod {};", module_name));
39 let path = if is_main_or_lib(file_name) {
40 format!("./{}.{}", module_name, file_ext.unwrap())
41 } else {
42 format!("./{}/{}.{}", file_name, module_name, file_ext.unwrap())
43 };
44 let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
45 let contents = update_module_items_string(dedent_module_items_text);
46 builder.create_file(dst, contents);
47 })
48}
49fn is_main_or_lib(file_name: &str) -> bool {
50 file_name == "main".to_string() || file_name == "lib".to_string()
51}
52fn update_module_items_string(items_str: String) -> String {
53 let mut items_string_lines: Vec<&str> = items_str.lines().collect();
54 items_string_lines.pop(); // Delete last line
55 items_string_lines.reverse();
56 items_string_lines.pop(); // Delete first line
57 items_string_lines.reverse();
58 33
59 let string = items_string_lines.join("\n"); 34 acc.add(
60 format!("{}", string) 35 AssistId("extract_module_to_file", AssistKind::RefactorExtract),
36 "Extract module to file",
37 target,
38 |builder| {
39 let path = {
40 let dir = match parent_module.name(ctx.db()) {
41 Some(name) if !parent_module.is_mod_rs(ctx.db()) => format!("{}/", name),
42 _ => String::new(),
43 };
44 format!("./{}{}.rs", dir, module_name)
45 };
46 let contents = {
47 let items = module_items.dedent(IndentLevel(1)).to_string();
48 let mut items =
49 items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
50 if !items.is_empty() {
51 items.push('\n');
52 }
53 items
54 };
55
56 builder.replace(target, format!("mod {};", module_name));
57
58 let dst = AnchoredPathBuf { anchor: anchor_file_id, path };
59 builder.create_file(dst, contents);
60 },
61 )
61} 62}
62 63
63#[cfg(test)] 64#[cfg(test)]
@@ -67,104 +68,66 @@ mod tests {
67 use super::*; 68 use super::*;
68 69
69 #[test] 70 #[test]
70 fn extract_module_to_file_with_basic_module() { 71 fn extract_from_root() {
71 check_assist( 72 check_assist(
72 extract_module_to_file, 73 extract_module_to_file,
73 r#" 74 r#"
74//- /foo.rs crate:foo
75mod tests {<|> 75mod tests {<|>
76 #[test] fn t() {} 76 #[test] fn t() {}
77} 77}
78"#, 78"#,
79 r#" 79 r#"
80//- /foo.rs 80//- /main.rs
81mod tests; 81mod tests;
82//- /foo/tests.rs 82//- /tests.rs
83#[test] fn t() {}"#, 83#[test] fn t() {}
84 )
85 }
86
87 #[test]
88 fn extract_module_to_file_with_file_path() {
89 check_assist(
90 extract_module_to_file,
91 r#"
92//- /src/foo.rs crate:foo
93mod bar {<|>
94 fn f() {
95
96 }
97}
98fn main() {
99 println!("Hello, world!");
100}
101"#, 84"#,
102 r#" 85 );
103//- /src/foo.rs
104mod bar;
105fn main() {
106 println!("Hello, world!");
107}
108//- /src/foo/bar.rs
109fn f() {
110
111}"#,
112 )
113 } 86 }
114 87
115 #[test] 88 #[test]
116 fn extract_module_to_file_with_main_filw() { 89 fn extract_from_submodule() {
117 check_assist( 90 check_assist(
118 extract_module_to_file, 91 extract_module_to_file,
119 r#" 92 r#"
120//- /main.rs 93//- /main.rs
121mod foo {<|> 94mod submodule;
122 fn f() { 95//- /submodule.rs
123 96mod inner<|> {
124 } 97 fn f() {}
125}
126fn main() {
127 println!("Hello, world!");
128} 98}
99fn g() {}
129"#, 100"#,
130 r#" 101 r#"
131//- /main.rs 102//- /submodule.rs
132mod foo; 103mod inner;
133fn main() { 104fn g() {}
134 println!("Hello, world!"); 105//- /submodule/inner.rs
135} 106fn f() {}
136//- /foo.rs 107"#,
137fn f() { 108 );
138
139}"#,
140 )
141 } 109 }
142 110
143 #[test] 111 #[test]
144 fn extract_module_to_file_with_lib_file() { 112 fn extract_from_mod_rs() {
145 check_assist( 113 check_assist(
146 extract_module_to_file, 114 extract_module_to_file,
147 r#" 115 r#"
148//- /lib.rs 116//- /main.rs
149mod foo {<|> 117mod submodule;
150 fn f() { 118//- /submodule/mod.rs
151 119mod inner<|> {
152 } 120 fn f() {}
153}
154fn main() {
155 println!("Hello, world!");
156} 121}
122fn g() {}
157"#, 123"#,
158 r#" 124 r#"
159//- /lib.rs 125//- /submodule/mod.rs
160mod foo; 126mod inner;
161fn main() { 127fn g() {}
162 println!("Hello, world!"); 128//- /submodule/inner.rs
163} 129fn f() {}
164//- /foo.rs 130"#,
165fn f() { 131 );
166
167}"#,
168 )
169 } 132 }
170} 133}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1f4b5c24c..11cdae57f 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -33,7 +33,7 @@ config_data! {
33 callInfo_full: bool = "true", 33 callInfo_full: bool = "true",
34 34
35 /// Automatically refresh project info via `cargo metadata` on 35 /// Automatically refresh project info via `cargo metadata` on
36 /// Cargo.toml changes. 36 /// `Cargo.toml` changes.
37 cargo_autoreload: bool = "true", 37 cargo_autoreload: bool = "true",
38 /// Activate all available features. 38 /// Activate all available features.
39 cargo_allFeatures: bool = "false", 39 cargo_allFeatures: bool = "false",
@@ -52,7 +52,7 @@ config_data! {
52 /// Run specified `cargo check` command for diagnostics on save. 52 /// Run specified `cargo check` command for diagnostics on save.
53 checkOnSave_enable: bool = "true", 53 checkOnSave_enable: bool = "true",
54 /// Check with all features (will be passed as `--all-features`). 54 /// Check with all features (will be passed as `--all-features`).
55 /// Defaults to `rust-analyzer.cargo.allFeatures`. 55 /// Defaults to `#rust-analyzer.cargo.allFeatures#`.
56 checkOnSave_allFeatures: Option<bool> = "null", 56 checkOnSave_allFeatures: Option<bool> = "null",
57 /// Check all targets and tests (will be passed as `--all-targets`). 57 /// Check all targets and tests (will be passed as `--all-targets`).
58 checkOnSave_allTargets: bool = "true", 58 checkOnSave_allTargets: bool = "true",
@@ -61,12 +61,12 @@ config_data! {
61 /// Do not activate the `default` feature. 61 /// Do not activate the `default` feature.
62 checkOnSave_noDefaultFeatures: Option<bool> = "null", 62 checkOnSave_noDefaultFeatures: Option<bool> = "null",
63 /// Check for a specific target. Defaults to 63 /// Check for a specific target. Defaults to
64 /// `rust-analyzer.cargo.target`. 64 /// `#rust-analyzer.cargo.target#`.
65 checkOnSave_target: Option<String> = "null", 65 checkOnSave_target: Option<String> = "null",
66 /// Extra arguments for `cargo check`. 66 /// Extra arguments for `cargo check`.
67 checkOnSave_extraArgs: Vec<String> = "[]", 67 checkOnSave_extraArgs: Vec<String> = "[]",
68 /// List of features to activate. Defaults to 68 /// List of features to activate. Defaults to
69 /// `rust-analyzer.cargo.features`. 69 /// `#rust-analyzer.cargo.features#`.
70 checkOnSave_features: Option<Vec<String>> = "null", 70 checkOnSave_features: Option<Vec<String>> = "null",
71 /// Advanced option, fully override the command rust-analyzer uses for 71 /// Advanced option, fully override the command rust-analyzer uses for
72 /// checking. The command should include `--message-format=json` or 72 /// checking. The command should include `--message-format=json` or
@@ -80,7 +80,7 @@ config_data! {
80 /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc. 80 /// Whether to show postfix snippets like `dbg`, `if`, `not`, etc.
81 completion_postfix_enable: bool = "true", 81 completion_postfix_enable: bool = "true",
82 /// Toggles the additional completions that automatically add imports when completed. 82 /// Toggles the additional completions that automatically add imports when completed.
83 /// Note that your client have to specify the `additionalTextEdits` LSP client capability to truly have this feature enabled. 83 /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
84 completion_autoimport_enable: bool = "true", 84 completion_autoimport_enable: bool = "true",
85 85
86 /// Whether to show native rust-analyzer diagnostics. 86 /// Whether to show native rust-analyzer diagnostics.
@@ -90,13 +90,13 @@ config_data! {
90 diagnostics_enableExperimental: bool = "true", 90 diagnostics_enableExperimental: bool = "true",
91 /// List of rust-analyzer diagnostics to disable. 91 /// List of rust-analyzer diagnostics to disable.
92 diagnostics_disabled: FxHashSet<String> = "[]", 92 diagnostics_disabled: FxHashSet<String> = "[]",
93 /// List of warnings that should be displayed with info severity.\nThe 93 /// List of warnings that should be displayed with info severity.\n\nThe
94 /// warnings will be indicated by a blue squiggly underline in code and 94 /// warnings will be indicated by a blue squiggly underline in code and
95 /// a blue icon in the problems panel. 95 /// a blue icon in the `Problems Panel`.
96 diagnostics_warningsAsHint: Vec<String> = "[]", 96 diagnostics_warningsAsHint: Vec<String> = "[]",
97 /// List of warnings that should be displayed with hint severity.\nThe 97 /// List of warnings that should be displayed with hint severity.\n\nThe
98 /// warnings will be indicated by faded text or three dots in code and 98 /// warnings will be indicated by faded text or three dots in code and
99 /// will not show up in the problems panel. 99 /// will not show up in the `Problems Panel`.
100 diagnostics_warningsAsInfo: Vec<String> = "[]", 100 diagnostics_warningsAsInfo: Vec<String> = "[]",
101 101
102 /// Controls file watching implementation. 102 /// Controls file watching implementation.
@@ -121,7 +121,7 @@ config_data! {
121 121
122 /// Whether to show inlay type hints for method chains. 122 /// Whether to show inlay type hints for method chains.
123 inlayHints_chainingHints: bool = "true", 123 inlayHints_chainingHints: bool = "true",
124 /// Maximum length for inlay hints. 124 /// Maximum length for inlay hints. Default is unlimited.
125 inlayHints_maxLength: Option<usize> = "null", 125 inlayHints_maxLength: Option<usize> = "null",
126 /// Whether to show function parameter name inlay hints at the call 126 /// Whether to show function parameter name inlay hints at the call
127 /// site. 127 /// site.
@@ -145,27 +145,27 @@ config_data! {
145 lens_methodReferences: bool = "false", 145 lens_methodReferences: bool = "false",
146 146
147 /// Disable project auto-discovery in favor of explicitly specified set 147 /// Disable project auto-discovery in favor of explicitly specified set
148 /// of projects. \nElements must be paths pointing to Cargo.toml, 148 /// of projects.\n\nElements must be paths pointing to `Cargo.toml`,
149 /// rust-project.json, or JSON objects in rust-project.json format. 149 /// `rust-project.json`, or JSON objects in `rust-project.json` format.
150 linkedProjects: Vec<ManifestOrProjectJson> = "[]", 150 linkedProjects: Vec<ManifestOrProjectJson> = "[]",
151 /// Number of syntax trees rust-analyzer keeps in memory. 151 /// Number of syntax trees rust-analyzer keeps in memory. Defaults to 128.
152 lruCapacity: Option<usize> = "null", 152 lruCapacity: Option<usize> = "null",
153 /// Whether to show `can't find Cargo.toml` error message. 153 /// Whether to show `can't find Cargo.toml` error message.
154 notifications_cargoTomlNotFound: bool = "true", 154 notifications_cargoTomlNotFound: bool = "true",
155 /// Enable Proc macro support, cargo.loadOutDirsFromCheck must be 155 /// Enable Proc macro support, `#rust-analyzer.cargo.loadOutDirsFromCheck#` must be
156 /// enabled. 156 /// enabled.
157 procMacro_enable: bool = "false", 157 procMacro_enable: bool = "false",
158 158
159 /// Command to be executed instead of 'cargo' for runnables. 159 /// Command to be executed instead of 'cargo' for runnables.
160 runnables_overrideCargo: Option<String> = "null", 160 runnables_overrideCargo: Option<String> = "null",
161 /// Additional arguments to be passed to cargo for runnables such as 161 /// Additional arguments to be passed to cargo for runnables such as
162 /// tests or binaries.\nFor example, it may be '--release'. 162 /// tests or binaries.\nFor example, it may be `--release`.
163 runnables_cargoExtraArgs: Vec<String> = "[]", 163 runnables_cargoExtraArgs: Vec<String> = "[]",
164 164
165 /// Path to the rust compiler sources, for usage in rustc_private projects. 165 /// Path to the rust compiler sources, for usage in rustc_private projects.
166 rustcSource : Option<String> = "null", 166 rustcSource : Option<String> = "null",
167 167
168 /// Additional arguments to rustfmt. 168 /// Additional arguments to `rustfmt`.
169 rustfmt_extraArgs: Vec<String> = "[]", 169 rustfmt_extraArgs: Vec<String> = "[]",
170 /// Advanced option, fully override the command rust-analyzer uses for 170 /// Advanced option, fully override the command rust-analyzer uses for
171 /// formatting. 171 /// formatting.
@@ -758,7 +758,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
758 ], 758 ],
759 "enumDescriptions": [ 759 "enumDescriptions": [
760 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.", 760 "Insert import paths relative to the current module, using up to one `super` prefix if the parent module contains the requested item.",
761 "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name", 761 "Prefix all import paths with `self` if they don't begin with `self`, `super`, `crate` or a crate name.",
762 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to." 762 "Force import paths to be absolute by always starting them with `crate` or the crate name they refer to."
763 ], 763 ],
764 }, 764 },