diff options
author | Lukas Wirth <[email protected]> | 2021-06-18 22:11:56 +0100 |
---|---|---|
committer | Lukas Wirth <[email protected]> | 2021-06-18 22:11:56 +0100 |
commit | 2ee090faaf69474a2baadf0494ef3c6ed4fdbcbc (patch) | |
tree | e67e1f3404fefb2dc3999b94f86bc9cbcca33dd1 | |
parent | 84507a0b9c2e8f6e632ad9ec649cd1f21a7e0887 (diff) |
Allow to disable import insertion on single path glob imports
-rw-r--r-- | crates/ide_assists/src/handlers/auto_import.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs | 2 | ||||
-rw-r--r-- | crates/ide_assists/src/tests.rs | 1 | ||||
-rw-r--r-- | crates/ide_completion/src/item.rs | 2 | ||||
-rw-r--r-- | crates/ide_completion/src/tests.rs | 1 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use.rs | 8 | ||||
-rw-r--r-- | crates/ide_db/src/helpers/insert_use/tests.rs | 72 | ||||
-rw-r--r-- | crates/rust-analyzer/src/config.rs | 4 | ||||
-rw-r--r-- | crates/rust-analyzer/src/integrated_benchmarks.rs | 2 | ||||
-rw-r--r-- | crates/rust-analyzer/src/to_proto.rs | 1 | ||||
-rw-r--r-- | crates/syntax/src/ast/node_ext.rs | 9 | ||||
-rw-r--r-- | docs/user/generated_config.adoc | 5 | ||||
-rw-r--r-- | editors/code/package.json | 5 |
14 files changed, 99 insertions, 17 deletions
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs index d4748ef3a..6c7348178 100644 --- a/crates/ide_assists/src/handlers/auto_import.rs +++ b/crates/ide_assists/src/handlers/auto_import.rs | |||
@@ -104,7 +104,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
104 | ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), | 104 | ImportScope::File(it) => ImportScope::File(builder.make_mut(it)), |
105 | ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), | 105 | ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)), |
106 | }; | 106 | }; |
107 | insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); | 107 | insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use); |
108 | }, | 108 | }, |
109 | ); | 109 | ); |
110 | } | 110 | } |
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs index d3ff7b65c..da6df9106 100644 --- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -235,7 +235,7 @@ fn apply_references( | |||
235 | import: Option<(ImportScope, hir::ModPath)>, | 235 | import: Option<(ImportScope, hir::ModPath)>, |
236 | ) { | 236 | ) { |
237 | if let Some((scope, path)) = import { | 237 | if let Some((scope, path)) = import { |
238 | insert_use(&scope, mod_path_to_ast(&path), insert_use_cfg); | 238 | insert_use(&scope, mod_path_to_ast(&path), &insert_use_cfg); |
239 | } | 239 | } |
240 | // deep clone to prevent cycle | 240 | // deep clone to prevent cycle |
241 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); | 241 | let path = make::path_from_segments(iter::once(segment.clone_subtree()), false); |
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs index 39f5eb4ff..26019c793 100644 --- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -43,7 +43,7 @@ pub(crate) fn replace_qualified_name_with_use( | |||
43 | let syntax = builder.make_syntax_mut(syntax.clone()); | 43 | let syntax = builder.make_syntax_mut(syntax.clone()); |
44 | if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { | 44 | if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { |
45 | shorten_paths(&syntax, &path.clone_for_update()); | 45 | shorten_paths(&syntax, &path.clone_for_update()); |
46 | insert_use(import_scope, path, ctx.config.insert_use); | 46 | insert_use(import_scope, path, &ctx.config.insert_use); |
47 | } | 47 | } |
48 | }, | 48 | }, |
49 | ) | 49 | ) |
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index 29bd4a563..b6f224b21 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs | |||
@@ -28,6 +28,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { | |||
28 | prefix_kind: hir::PrefixKind::Plain, | 28 | prefix_kind: hir::PrefixKind::Plain, |
29 | enforce_granularity: true, | 29 | enforce_granularity: true, |
30 | group: true, | 30 | group: true, |
31 | skip_glob_imports: true, | ||
31 | }, | 32 | }, |
32 | }; | 33 | }; |
33 | 34 | ||
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs index 99edb9499..ae63d132e 100644 --- a/crates/ide_completion/src/item.rs +++ b/crates/ide_completion/src/item.rs | |||
@@ -378,7 +378,7 @@ impl ImportEdit { | |||
378 | let _p = profile::span("ImportEdit::to_text_edit"); | 378 | let _p = profile::span("ImportEdit::to_text_edit"); |
379 | 379 | ||
380 | let new_ast = self.scope.clone_for_update(); | 380 | let new_ast = self.scope.clone_for_update(); |
381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), cfg); | 381 | insert_use::insert_use(&new_ast, mod_path_to_ast(&self.import.import_path), &cfg); |
382 | let mut import_insert = TextEdit::builder(); | 382 | let mut import_insert = TextEdit::builder(); |
383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) | 383 | algo::diff(self.scope.as_syntax_node(), new_ast.as_syntax_node()) |
384 | .into_text_edit(&mut import_insert); | 384 | .into_text_edit(&mut import_insert); |
diff --git a/crates/ide_completion/src/tests.rs b/crates/ide_completion/src/tests.rs index 1ea6017ce..211c89c40 100644 --- a/crates/ide_completion/src/tests.rs +++ b/crates/ide_completion/src/tests.rs | |||
@@ -36,6 +36,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { | |||
36 | prefix_kind: PrefixKind::Plain, | 36 | prefix_kind: PrefixKind::Plain, |
37 | enforce_granularity: true, | 37 | enforce_granularity: true, |
38 | group: true, | 38 | group: true, |
39 | skip_glob_imports: true, | ||
39 | }, | 40 | }, |
40 | }; | 41 | }; |
41 | 42 | ||
diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 10bbafe77..4da058cb2 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs | |||
@@ -36,6 +36,7 @@ pub struct InsertUseConfig { | |||
36 | pub enforce_granularity: bool, | 36 | pub enforce_granularity: bool, |
37 | pub prefix_kind: PrefixKind, | 37 | pub prefix_kind: PrefixKind, |
38 | pub group: bool, | 38 | pub group: bool, |
39 | pub skip_glob_imports: bool, | ||
39 | } | 40 | } |
40 | 41 | ||
41 | #[derive(Debug, Clone)] | 42 | #[derive(Debug, Clone)] |
@@ -153,7 +154,7 @@ enum ImportGranularityGuess { | |||
153 | } | 154 | } |
154 | 155 | ||
155 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. | 156 | /// Insert an import path into the given file/node. A `merge` value of none indicates that no import merging is allowed to occur. |
156 | pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig) { | 157 | pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: &InsertUseConfig) { |
157 | let _p = profile::span("insert_use"); | 158 | let _p = profile::span("insert_use"); |
158 | let mut mb = match cfg.granularity { | 159 | let mut mb = match cfg.granularity { |
159 | ImportGranularity::Crate => Some(MergeBehavior::Crate), | 160 | ImportGranularity::Crate => Some(MergeBehavior::Crate), |
@@ -175,7 +176,10 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig | |||
175 | make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); | 176 | make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); |
176 | // merge into existing imports if possible | 177 | // merge into existing imports if possible |
177 | if let Some(mb) = mb { | 178 | if let Some(mb) = mb { |
178 | for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { | 179 | let filter = |it: &_| !(cfg.skip_glob_imports && ast::Use::is_simple_glob(it)); |
180 | for existing_use in | ||
181 | scope.as_syntax_node().children().filter_map(ast::Use::cast).filter(filter) | ||
182 | { | ||
179 | if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { | 183 | if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { |
180 | ted::replace(existing_use.syntax(), merged.syntax()); | 184 | ted::replace(existing_use.syntax(), merged.syntax()); |
181 | return; | 185 | return; |
diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 5a88ec742..263edcdc9 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs | |||
@@ -4,6 +4,23 @@ use hir::PrefixKind; | |||
4 | use test_utils::assert_eq_text; | 4 | use test_utils::assert_eq_text; |
5 | 5 | ||
6 | #[test] | 6 | #[test] |
7 | fn insert_skips_lone_glob_imports() { | ||
8 | check( | ||
9 | "use foo::baz::A", | ||
10 | r" | ||
11 | use foo::bar::*; | ||
12 | ", | ||
13 | r" | ||
14 | use foo::bar::*; | ||
15 | use foo::baz::A; | ||
16 | ", | ||
17 | ImportGranularity::Crate, | ||
18 | false, | ||
19 | false, | ||
20 | ); | ||
21 | } | ||
22 | |||
23 | #[test] | ||
7 | fn insert_not_group() { | 24 | fn insert_not_group() { |
8 | cov_mark::check!(insert_no_grouping_last); | 25 | cov_mark::check!(insert_no_grouping_last); |
9 | check( | 26 | check( |
@@ -534,17 +551,37 @@ fn merge_groups_self() { | |||
534 | 551 | ||
535 | #[test] | 552 | #[test] |
536 | fn merge_mod_into_glob() { | 553 | fn merge_mod_into_glob() { |
537 | check_crate( | 554 | check_with_config( |
538 | "token::TokenKind", | 555 | "token::TokenKind", |
539 | r"use token::TokenKind::*;", | 556 | r"use token::TokenKind::*;", |
540 | r"use token::TokenKind::{*, self};", | 557 | r"use token::TokenKind::{*, self};", |
558 | false, | ||
559 | &InsertUseConfig { | ||
560 | granularity: ImportGranularity::Crate, | ||
561 | enforce_granularity: true, | ||
562 | prefix_kind: PrefixKind::Plain, | ||
563 | group: false, | ||
564 | skip_glob_imports: false, | ||
565 | }, | ||
541 | ) | 566 | ) |
542 | // FIXME: have it emit `use token::TokenKind::{self, *}`? | 567 | // FIXME: have it emit `use token::TokenKind::{self, *}`? |
543 | } | 568 | } |
544 | 569 | ||
545 | #[test] | 570 | #[test] |
546 | fn merge_self_glob() { | 571 | fn merge_self_glob() { |
547 | check_crate("self", r"use self::*;", r"use self::{*, self};") | 572 | check_with_config( |
573 | "self", | ||
574 | r"use self::*;", | ||
575 | r"use self::{*, self};", | ||
576 | false, | ||
577 | &InsertUseConfig { | ||
578 | granularity: ImportGranularity::Crate, | ||
579 | enforce_granularity: true, | ||
580 | prefix_kind: PrefixKind::Plain, | ||
581 | group: false, | ||
582 | skip_glob_imports: false, | ||
583 | }, | ||
584 | ) | ||
548 | // FIXME: have it emit `use {self, *}`? | 585 | // FIXME: have it emit `use {self, *}`? |
549 | } | 586 | } |
550 | 587 | ||
@@ -757,13 +794,12 @@ use foo::bar::qux; | |||
757 | ); | 794 | ); |
758 | } | 795 | } |
759 | 796 | ||
760 | fn check( | 797 | fn check_with_config( |
761 | path: &str, | 798 | path: &str, |
762 | ra_fixture_before: &str, | 799 | ra_fixture_before: &str, |
763 | ra_fixture_after: &str, | 800 | ra_fixture_after: &str, |
764 | granularity: ImportGranularity, | ||
765 | module: bool, | 801 | module: bool, |
766 | group: bool, | 802 | config: &InsertUseConfig, |
767 | ) { | 803 | ) { |
768 | let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); | 804 | let mut syntax = ast::SourceFile::parse(ra_fixture_before).tree().syntax().clone(); |
769 | if module { | 805 | if module { |
@@ -777,18 +813,32 @@ fn check( | |||
777 | .find_map(ast::Path::cast) | 813 | .find_map(ast::Path::cast) |
778 | .unwrap(); | 814 | .unwrap(); |
779 | 815 | ||
780 | insert_use( | 816 | insert_use(&file, path, config); |
781 | &file, | 817 | let result = file.as_syntax_node().to_string(); |
818 | assert_eq_text!(ra_fixture_after, &result); | ||
819 | } | ||
820 | |||
821 | fn check( | ||
822 | path: &str, | ||
823 | ra_fixture_before: &str, | ||
824 | ra_fixture_after: &str, | ||
825 | granularity: ImportGranularity, | ||
826 | module: bool, | ||
827 | group: bool, | ||
828 | ) { | ||
829 | check_with_config( | ||
782 | path, | 830 | path, |
783 | InsertUseConfig { | 831 | ra_fixture_before, |
832 | ra_fixture_after, | ||
833 | module, | ||
834 | &InsertUseConfig { | ||
784 | granularity, | 835 | granularity, |
785 | enforce_granularity: true, | 836 | enforce_granularity: true, |
786 | prefix_kind: PrefixKind::Plain, | 837 | prefix_kind: PrefixKind::Plain, |
787 | group, | 838 | group, |
839 | skip_glob_imports: true, | ||
788 | }, | 840 | }, |
789 | ); | 841 | ) |
790 | let result = file.as_syntax_node().to_string(); | ||
791 | assert_eq_text!(ra_fixture_after, &result); | ||
792 | } | 842 | } |
793 | 843 | ||
794 | fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { | 844 | fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { |
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index c4757a1cb..16c295639 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs | |||
@@ -44,6 +44,9 @@ config_data! { | |||
44 | assist_importPrefix: ImportPrefixDef = "\"plain\"", | 44 | assist_importPrefix: ImportPrefixDef = "\"plain\"", |
45 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. | 45 | /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. |
46 | assist_importGroup: bool = "true", | 46 | assist_importGroup: bool = "true", |
47 | /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. | ||
48 | assist_allowMergingIntoGlobImports: bool = "true", | ||
49 | |||
47 | /// Show function name and docs in parameter hints. | 50 | /// Show function name and docs in parameter hints. |
48 | callInfo_full: bool = "true", | 51 | callInfo_full: bool = "true", |
49 | 52 | ||
@@ -672,6 +675,7 @@ impl Config { | |||
672 | ImportPrefixDef::BySelf => PrefixKind::BySelf, | 675 | ImportPrefixDef::BySelf => PrefixKind::BySelf, |
673 | }, | 676 | }, |
674 | group: self.data.assist_importGroup, | 677 | group: self.data.assist_importGroup, |
678 | skip_glob_imports: !self.data.assist_allowMergingIntoGlobImports, | ||
675 | } | 679 | } |
676 | } | 680 | } |
677 | pub fn completion(&self) -> CompletionConfig { | 681 | pub fn completion(&self) -> CompletionConfig { |
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index 8ddeb59f7..f8afc930a 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs | |||
@@ -143,6 +143,7 @@ fn integrated_completion_benchmark() { | |||
143 | prefix_kind: hir::PrefixKind::ByCrate, | 143 | prefix_kind: hir::PrefixKind::ByCrate, |
144 | enforce_granularity: true, | 144 | enforce_granularity: true, |
145 | group: true, | 145 | group: true, |
146 | skip_glob_imports: true, | ||
146 | }, | 147 | }, |
147 | }; | 148 | }; |
148 | let position = | 149 | let position = |
@@ -178,6 +179,7 @@ fn integrated_completion_benchmark() { | |||
178 | prefix_kind: hir::PrefixKind::ByCrate, | 179 | prefix_kind: hir::PrefixKind::ByCrate, |
179 | enforce_granularity: true, | 180 | enforce_granularity: true, |
180 | group: true, | 181 | group: true, |
182 | skip_glob_imports: true, | ||
181 | }, | 183 | }, |
182 | }; | 184 | }; |
183 | let position = | 185 | let position = |
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index e53cd3c7b..310d8c6d2 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs | |||
@@ -1187,6 +1187,7 @@ mod tests { | |||
1187 | prefix_kind: PrefixKind::Plain, | 1187 | prefix_kind: PrefixKind::Plain, |
1188 | enforce_granularity: true, | 1188 | enforce_granularity: true, |
1189 | group: true, | 1189 | group: true, |
1190 | skip_glob_imports: true, | ||
1190 | }, | 1191 | }, |
1191 | }, | 1192 | }, |
1192 | ide_db::base_db::FilePosition { file_id, offset }, | 1193 | ide_db::base_db::FilePosition { file_id, offset }, |
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index b057e6624..3c92a486f 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs | |||
@@ -281,6 +281,15 @@ impl ast::Path { | |||
281 | successors(self.qualifier(), |p| p.qualifier()) | 281 | successors(self.qualifier(), |p| p.qualifier()) |
282 | } | 282 | } |
283 | } | 283 | } |
284 | |||
285 | impl ast::Use { | ||
286 | pub fn is_simple_glob(&self) -> bool { | ||
287 | self.use_tree() | ||
288 | .map(|use_tree| use_tree.use_tree_list().is_none() && use_tree.star_token().is_some()) | ||
289 | .unwrap_or(false) | ||
290 | } | ||
291 | } | ||
292 | |||
284 | impl ast::UseTree { | 293 | impl ast::UseTree { |
285 | pub fn is_simple_path(&self) -> bool { | 294 | pub fn is_simple_path(&self) -> bool { |
286 | self.use_tree_list().is_none() && self.star_token().is_none() | 295 | self.use_tree_list().is_none() && self.star_token().is_none() |
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 34a91486b..18ea77266 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc | |||
@@ -18,6 +18,11 @@ The path structure for newly inserted paths to use. | |||
18 | -- | 18 | -- |
19 | Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. | 19 | Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. |
20 | -- | 20 | -- |
21 | [[rust-analyzer.assist.allowMergingIntoGlobImports]]rust-analyzer.assist.allowMergingIntoGlobImports (default: `true`):: | ||
22 | + | ||
23 | -- | ||
24 | Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`. | ||
25 | -- | ||
21 | [[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: | 26 | [[rust-analyzer.callInfo.full]]rust-analyzer.callInfo.full (default: `true`):: |
22 | + | 27 | + |
23 | -- | 28 | -- |
diff --git a/editors/code/package.json b/editors/code/package.json index 1fac700be..c077bd2c0 100644 --- a/editors/code/package.json +++ b/editors/code/package.json | |||
@@ -432,6 +432,11 @@ | |||
432 | "default": true, | 432 | "default": true, |
433 | "type": "boolean" | 433 | "type": "boolean" |
434 | }, | 434 | }, |
435 | "rust-analyzer.assist.allowMergingIntoGlobImports": { | ||
436 | "markdownDescription": "Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.", | ||
437 | "default": true, | ||
438 | "type": "boolean" | ||
439 | }, | ||
435 | "rust-analyzer.callInfo.full": { | 440 | "rust-analyzer.callInfo.full": { |
436 | "markdownDescription": "Show function name and docs in parameter hints.", | 441 | "markdownDescription": "Show function name and docs in parameter hints.", |
437 | "default": true, | 442 | "default": true, |