diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs index 0d3969c36d..bb1ca0b3d4 100644 --- a/crates/ide_assists/src/tests.rs +++ b/crates/ide_assists/src/tests.rs @@ -4,7 +4,10 @@ use expect_test::expect; use hir::Semantics; use ide_db::{ base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt}, - helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}, + helpers::{ + insert_use::{ImportGranularity, InsertUseConfig}, + SnippetCap, + }, source_change::FileSystemEdit, RootDatabase, }; @@ -21,7 +24,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig { snippet_cap: SnippetCap::new(true), allowed: None, insert_use: InsertUseConfig { - merge: Some(MergeBehavior::Crate), + granularity: ImportGranularity::Crate, prefix_kind: hir::PrefixKind::Plain, group: true, }, diff --git a/crates/ide_completion/src/test_utils.rs b/crates/ide_completion/src/test_utils.rs index 939fb2d470..b150a5c3fd 100644 --- a/crates/ide_completion/src/test_utils.rs +++ b/crates/ide_completion/src/test_utils.rs @@ -3,7 +3,10 @@ use hir::{PrefixKind, Semantics}; use ide_db::{ base_db::{fixture::ChangeFixture, FileLoader, FilePosition}, - helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}, + helpers::{ + insert_use::{ImportGranularity, InsertUseConfig}, + SnippetCap, + }, RootDatabase, }; use itertools::Itertools; @@ -20,7 +23,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig { add_call_argument_snippets: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { - merge: Some(MergeBehavior::Crate), + granularity: ImportGranularity::Crate, prefix_kind: PrefixKind::Plain, group: true, }, diff --git a/crates/ide_db/src/helpers/insert_use.rs b/crates/ide_db/src/helpers/insert_use.rs index 55cdc4da3f..a4eb31815e 100644 --- a/crates/ide_db/src/helpers/insert_use.rs +++ b/crates/ide_db/src/helpers/insert_use.rs @@ -15,9 +15,32 @@ use crate::{ pub use hir::PrefixKind; +/// How imports should be grouped into use statements. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ImportGranularity { + /// Do not change the granularity of any imports and preserve the original structure written by the developer. + Preserve, + /// Merge imports from the same crate into a single use statement. + Crate, + /// Merge imports from the same module into a single use statement. + Module, + /// Flatten imports so that each has its own use statement. + Item, +} + +impl ImportGranularity { + pub fn merge_behavior(self) -> Option { + match self { + ImportGranularity::Crate => Some(MergeBehavior::Crate), + ImportGranularity::Module => Some(MergeBehavior::Module), + ImportGranularity::Preserve | ImportGranularity::Item => None, + } + } +} + #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct InsertUseConfig { - pub merge: Option, + pub granularity: ImportGranularity, pub prefix_kind: PrefixKind, pub group: bool, } @@ -73,7 +96,7 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig let use_item = make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update(); // merge into existing imports if possible - if let Some(mb) = cfg.merge { + if let Some(mb) = cfg.granularity.merge_behavior() { for existing_use in scope.as_syntax_node().children().filter_map(ast::Use::cast) { if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) { ted::replace(existing_use.syntax(), merged.syntax()); diff --git a/crates/ide_db/src/helpers/insert_use/tests.rs b/crates/ide_db/src/helpers/insert_use/tests.rs index 248227d295..f99857a89f 100644 --- a/crates/ide_db/src/helpers/insert_use/tests.rs +++ b/crates/ide_db/src/helpers/insert_use/tests.rs @@ -21,7 +21,7 @@ use crate::bar::A; use self::bar::A; use super::bar::A; use external_crate2::bar::A;", - None, + ImportGranularity::Item, false, false, ); @@ -36,7 +36,7 @@ fn insert_not_group_empty() { r"use external_crate2::bar::A; ", - None, + ImportGranularity::Item, false, false, ); @@ -281,7 +281,7 @@ fn insert_empty_module() { r"{ use foo::bar; }", - None, + ImportGranularity::Item, true, true, ) @@ -635,7 +635,7 @@ fn check( path: &str, ra_fixture_before: &str, ra_fixture_after: &str, - mb: Option, + granularity: ImportGranularity, module: bool, group: bool, ) { @@ -651,21 +651,21 @@ fn check( .find_map(ast::Path::cast) .unwrap(); - insert_use(&file, path, InsertUseConfig { merge: mb, prefix_kind: PrefixKind::Plain, group }); + insert_use(&file, path, InsertUseConfig { granularity, prefix_kind: PrefixKind::Plain, group }); let result = file.as_syntax_node().to_string(); assert_eq_text!(ra_fixture_after, &result); } fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Crate), false, true) + check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Crate, false, true) } fn check_module(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, Some(MergeBehavior::Module), false, true) + check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Module, false, true) } fn check_none(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) { - check(path, ra_fixture_before, ra_fixture_after, None, false, true) + check(path, ra_fixture_before, ra_fixture_after, ImportGranularity::Item, false, true) } fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) { diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index a3866c1baf..e72387257f 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -12,8 +12,7 @@ use std::{ffi::OsString, iter, path::PathBuf}; use flycheck::FlycheckConfig; use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig}; use ide_db::helpers::{ - insert_use::{InsertUseConfig, PrefixKind}, - merge_imports::MergeBehavior, + insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, SnippetCap, }; use lsp_types::{ClientCapabilities, MarkupKind}; @@ -35,8 +34,9 @@ use crate::{ config_data! { struct ConfigData { /// The strategy to use when inserting new imports or merging imports. + assist_importGranularity | assist_importMergeBehavior | - assist_importMergeBehaviour: MergeBehaviorDef = "\"crate\"", + assist_importMergeBehaviour: ImportGranularityDef = "\"preserve\"", /// The path structure for newly inserted paths to use. assist_importPrefix: ImportPrefixDef = "\"plain\"", /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines. @@ -609,10 +609,11 @@ impl Config { } fn insert_use_config(&self) -> InsertUseConfig { InsertUseConfig { - merge: match self.data.assist_importMergeBehavior { - MergeBehaviorDef::None => None, - MergeBehaviorDef::Crate => Some(MergeBehavior::Crate), - MergeBehaviorDef::Module => Some(MergeBehavior::Module), + granularity: match self.data.assist_importGranularity { + ImportGranularityDef::Preserve => ImportGranularity::Preserve, + ImportGranularityDef::Item => ImportGranularity::Item, + ImportGranularityDef::Crate => ImportGranularity::Crate, + ImportGranularityDef::Module => ImportGranularity::Module, }, prefix_kind: match self.data.assist_importPrefix { ImportPrefixDef::Plain => PrefixKind::Plain, @@ -717,8 +718,10 @@ enum ManifestOrProjectJson { #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "snake_case")] -enum MergeBehaviorDef { - None, +enum ImportGranularityDef { + #[serde(alias = "none")] + Item, + Preserve, #[serde(alias = "full")] Crate, #[serde(alias = "last")] @@ -737,7 +740,7 @@ macro_rules! _config_data { (struct $name:ident { $( $(#[doc=$doc:literal])* - $field:ident $(| $alias:ident)?: $ty:ty = $default:expr, + $field:ident $(| $alias:ident)*: $ty:ty = $default:expr, )* }) => { #[allow(non_snake_case)] @@ -749,7 +752,7 @@ macro_rules! _config_data { $field: get_field( &mut json, stringify!($field), - None$(.or(Some(stringify!($alias))))?, + None$(.or(Some(stringify!($alias))))*, $default, ), )*} diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs index ba2790acbd..cd0b8d559f 100644 --- a/crates/rust-analyzer/src/integrated_benchmarks.rs +++ b/crates/rust-analyzer/src/integrated_benchmarks.rs @@ -13,7 +13,10 @@ use std::{convert::TryFrom, sync::Arc}; use ide::{Change, CompletionConfig, FilePosition, TextSize}; -use ide_db::helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap}; +use ide_db::helpers::{ + insert_use::{ImportGranularity, InsertUseConfig}, + SnippetCap, +}; use test_utils::project_root; use vfs::{AbsPathBuf, VfsPath}; @@ -133,7 +136,7 @@ fn integrated_completion_benchmark() { add_call_argument_snippets: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { - merge: Some(MergeBehavior::Crate), + granularity: ImportGranularity::Crate, prefix_kind: hir::PrefixKind::ByCrate, group: true, }, @@ -166,7 +169,7 @@ fn integrated_completion_benchmark() { add_call_argument_snippets: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { - merge: Some(MergeBehavior::Crate), + granularity: ImportGranularity::Crate, prefix_kind: hir::PrefixKind::ByCrate, group: true, }, diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs index 9dec46c789..64d5f9e2e4 100644 --- a/crates/rust-analyzer/src/to_proto.rs +++ b/crates/rust-analyzer/src/to_proto.rs @@ -1145,7 +1145,7 @@ mod tests { use ide::Analysis; use ide_db::helpers::{ - insert_use::{InsertUseConfig, PrefixKind}, + insert_use::{ImportGranularity, InsertUseConfig, PrefixKind}, SnippetCap, }; @@ -1177,7 +1177,7 @@ mod tests { add_call_argument_snippets: true, snippet_cap: SnippetCap::new(true), insert_use: InsertUseConfig { - merge: None, + granularity: ImportGranularity::Item, prefix_kind: PrefixKind::Plain, group: true, }, diff --git a/editors/code/package.json b/editors/code/package.json index 2e67b67755..81179ff9b5 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -385,19 +385,21 @@ "markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`" }, "$generated-start": false, - "rust-analyzer.assist.importMergeBehavior": { - "markdownDescription": "The strategy to use when inserting new imports or merging imports.", - "default": "crate", + "rust-analyzer.assist.importGranularity": { + "markdownDescription": "How imports should be grouped into use statements.", + "default": "preserve", "type": "string", "enum": [ - "none", + "preserve", "crate", - "module" + "module", + "item" ], "enumDescriptions": [ - "Do not merge imports at all.", - "Merge imports from the same crate into a single `use` statement.", - "Merge imports from the same module into a single `use` statement." + "Do not change the granularity of any imports and preserve the original structure written by the developer.", + "Merge imports from the same crate into a single use statement. Conversely, imports from different crates are split into separate statements.", + "Merge imports from the same module into a single use statement. Conversely, imports from different modules are split into separate statements.", + "Flatten imports so that each has its own use statement." ] }, "rust-analyzer.assist.importPrefix": {