mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-26 04:53:34 +00:00
MergeBehavior -> ImportGranularity
This commit is contained in:
parent
e3d0d89d7e
commit
64f7072c25
8 changed files with 75 additions and 38 deletions
|
@ -4,7 +4,10 @@ use expect_test::expect;
|
||||||
use hir::Semantics;
|
use hir::Semantics;
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
|
base_db::{fixture::WithFixture, FileId, FileRange, SourceDatabaseExt},
|
||||||
helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap},
|
helpers::{
|
||||||
|
insert_use::{ImportGranularity, InsertUseConfig},
|
||||||
|
SnippetCap,
|
||||||
|
},
|
||||||
source_change::FileSystemEdit,
|
source_change::FileSystemEdit,
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
|
@ -21,7 +24,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
|
||||||
snippet_cap: SnippetCap::new(true),
|
snippet_cap: SnippetCap::new(true),
|
||||||
allowed: None,
|
allowed: None,
|
||||||
insert_use: InsertUseConfig {
|
insert_use: InsertUseConfig {
|
||||||
merge: Some(MergeBehavior::Crate),
|
granularity: ImportGranularity::Crate,
|
||||||
prefix_kind: hir::PrefixKind::Plain,
|
prefix_kind: hir::PrefixKind::Plain,
|
||||||
group: true,
|
group: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,10 @@
|
||||||
use hir::{PrefixKind, Semantics};
|
use hir::{PrefixKind, Semantics};
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
|
base_db::{fixture::ChangeFixture, FileLoader, FilePosition},
|
||||||
helpers::{insert_use::InsertUseConfig, merge_imports::MergeBehavior, SnippetCap},
|
helpers::{
|
||||||
|
insert_use::{ImportGranularity, InsertUseConfig},
|
||||||
|
SnippetCap,
|
||||||
|
},
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
@ -20,7 +23,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
|
||||||
add_call_argument_snippets: true,
|
add_call_argument_snippets: true,
|
||||||
snippet_cap: SnippetCap::new(true),
|
snippet_cap: SnippetCap::new(true),
|
||||||
insert_use: InsertUseConfig {
|
insert_use: InsertUseConfig {
|
||||||
merge: Some(MergeBehavior::Crate),
|
granularity: ImportGranularity::Crate,
|
||||||
prefix_kind: PrefixKind::Plain,
|
prefix_kind: PrefixKind::Plain,
|
||||||
group: true,
|
group: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -15,9 +15,32 @@ use crate::{
|
||||||
|
|
||||||
pub use hir::PrefixKind;
|
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<MergeBehavior> {
|
||||||
|
match self {
|
||||||
|
ImportGranularity::Crate => Some(MergeBehavior::Crate),
|
||||||
|
ImportGranularity::Module => Some(MergeBehavior::Module),
|
||||||
|
ImportGranularity::Preserve | ImportGranularity::Item => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub struct InsertUseConfig {
|
pub struct InsertUseConfig {
|
||||||
pub merge: Option<MergeBehavior>,
|
pub granularity: ImportGranularity,
|
||||||
pub prefix_kind: PrefixKind,
|
pub prefix_kind: PrefixKind,
|
||||||
pub group: bool,
|
pub group: bool,
|
||||||
}
|
}
|
||||||
|
@ -73,7 +96,7 @@ pub fn insert_use<'a>(scope: &ImportScope, path: ast::Path, cfg: InsertUseConfig
|
||||||
let use_item =
|
let use_item =
|
||||||
make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
|
make::use_(None, make::use_tree(path.clone(), None, None, false)).clone_for_update();
|
||||||
// merge into existing imports if possible
|
// 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) {
|
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) {
|
if let Some(merged) = try_merge_imports(&existing_use, &use_item, mb) {
|
||||||
ted::replace(existing_use.syntax(), merged.syntax());
|
ted::replace(existing_use.syntax(), merged.syntax());
|
||||||
|
|
|
@ -21,7 +21,7 @@ use crate::bar::A;
|
||||||
use self::bar::A;
|
use self::bar::A;
|
||||||
use super::bar::A;
|
use super::bar::A;
|
||||||
use external_crate2::bar::A;",
|
use external_crate2::bar::A;",
|
||||||
None,
|
ImportGranularity::Item,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -36,7 +36,7 @@ fn insert_not_group_empty() {
|
||||||
r"use external_crate2::bar::A;
|
r"use external_crate2::bar::A;
|
||||||
|
|
||||||
",
|
",
|
||||||
None,
|
ImportGranularity::Item,
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
@ -281,7 +281,7 @@ fn insert_empty_module() {
|
||||||
r"{
|
r"{
|
||||||
use foo::bar;
|
use foo::bar;
|
||||||
}",
|
}",
|
||||||
None,
|
ImportGranularity::Item,
|
||||||
true,
|
true,
|
||||||
true,
|
true,
|
||||||
)
|
)
|
||||||
|
@ -635,7 +635,7 @@ fn check(
|
||||||
path: &str,
|
path: &str,
|
||||||
ra_fixture_before: &str,
|
ra_fixture_before: &str,
|
||||||
ra_fixture_after: &str,
|
ra_fixture_after: &str,
|
||||||
mb: Option<MergeBehavior>,
|
granularity: ImportGranularity,
|
||||||
module: bool,
|
module: bool,
|
||||||
group: bool,
|
group: bool,
|
||||||
) {
|
) {
|
||||||
|
@ -651,21 +651,21 @@ fn check(
|
||||||
.find_map(ast::Path::cast)
|
.find_map(ast::Path::cast)
|
||||||
.unwrap();
|
.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();
|
let result = file.as_syntax_node().to_string();
|
||||||
assert_eq_text!(ra_fixture_after, &result);
|
assert_eq_text!(ra_fixture_after, &result);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_crate(path: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
|
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) {
|
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) {
|
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) {
|
fn check_merge_only_fail(ra_fixture0: &str, ra_fixture1: &str, mb: MergeBehavior) {
|
||||||
|
|
|
@ -12,8 +12,7 @@ use std::{ffi::OsString, iter, path::PathBuf};
|
||||||
use flycheck::FlycheckConfig;
|
use flycheck::FlycheckConfig;
|
||||||
use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
|
use ide::{AssistConfig, CompletionConfig, DiagnosticsConfig, HoverConfig, InlayHintsConfig};
|
||||||
use ide_db::helpers::{
|
use ide_db::helpers::{
|
||||||
insert_use::{InsertUseConfig, PrefixKind},
|
insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||||
merge_imports::MergeBehavior,
|
|
||||||
SnippetCap,
|
SnippetCap,
|
||||||
};
|
};
|
||||||
use lsp_types::{ClientCapabilities, MarkupKind};
|
use lsp_types::{ClientCapabilities, MarkupKind};
|
||||||
|
@ -35,8 +34,9 @@ use crate::{
|
||||||
config_data! {
|
config_data! {
|
||||||
struct ConfigData {
|
struct ConfigData {
|
||||||
/// The strategy to use when inserting new imports or merging imports.
|
/// The strategy to use when inserting new imports or merging imports.
|
||||||
|
assist_importGranularity |
|
||||||
assist_importMergeBehavior |
|
assist_importMergeBehavior |
|
||||||
assist_importMergeBehaviour: MergeBehaviorDef = "\"crate\"",
|
assist_importMergeBehaviour: ImportGranularityDef = "\"preserve\"",
|
||||||
/// The path structure for newly inserted paths to use.
|
/// The path structure for newly inserted paths to use.
|
||||||
assist_importPrefix: ImportPrefixDef = "\"plain\"",
|
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.
|
/// 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 {
|
fn insert_use_config(&self) -> InsertUseConfig {
|
||||||
InsertUseConfig {
|
InsertUseConfig {
|
||||||
merge: match self.data.assist_importMergeBehavior {
|
granularity: match self.data.assist_importGranularity {
|
||||||
MergeBehaviorDef::None => None,
|
ImportGranularityDef::Preserve => ImportGranularity::Preserve,
|
||||||
MergeBehaviorDef::Crate => Some(MergeBehavior::Crate),
|
ImportGranularityDef::Item => ImportGranularity::Item,
|
||||||
MergeBehaviorDef::Module => Some(MergeBehavior::Module),
|
ImportGranularityDef::Crate => ImportGranularity::Crate,
|
||||||
|
ImportGranularityDef::Module => ImportGranularity::Module,
|
||||||
},
|
},
|
||||||
prefix_kind: match self.data.assist_importPrefix {
|
prefix_kind: match self.data.assist_importPrefix {
|
||||||
ImportPrefixDef::Plain => PrefixKind::Plain,
|
ImportPrefixDef::Plain => PrefixKind::Plain,
|
||||||
|
@ -717,8 +718,10 @@ enum ManifestOrProjectJson {
|
||||||
|
|
||||||
#[derive(Deserialize, Debug, Clone)]
|
#[derive(Deserialize, Debug, Clone)]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
enum MergeBehaviorDef {
|
enum ImportGranularityDef {
|
||||||
None,
|
#[serde(alias = "none")]
|
||||||
|
Item,
|
||||||
|
Preserve,
|
||||||
#[serde(alias = "full")]
|
#[serde(alias = "full")]
|
||||||
Crate,
|
Crate,
|
||||||
#[serde(alias = "last")]
|
#[serde(alias = "last")]
|
||||||
|
@ -737,7 +740,7 @@ macro_rules! _config_data {
|
||||||
(struct $name:ident {
|
(struct $name:ident {
|
||||||
$(
|
$(
|
||||||
$(#[doc=$doc:literal])*
|
$(#[doc=$doc:literal])*
|
||||||
$field:ident $(| $alias:ident)?: $ty:ty = $default:expr,
|
$field:ident $(| $alias:ident)*: $ty:ty = $default:expr,
|
||||||
)*
|
)*
|
||||||
}) => {
|
}) => {
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
|
@ -749,7 +752,7 @@ macro_rules! _config_data {
|
||||||
$field: get_field(
|
$field: get_field(
|
||||||
&mut json,
|
&mut json,
|
||||||
stringify!($field),
|
stringify!($field),
|
||||||
None$(.or(Some(stringify!($alias))))?,
|
None$(.or(Some(stringify!($alias))))*,
|
||||||
$default,
|
$default,
|
||||||
),
|
),
|
||||||
)*}
|
)*}
|
||||||
|
|
|
@ -13,7 +13,10 @@
|
||||||
use std::{convert::TryFrom, sync::Arc};
|
use std::{convert::TryFrom, sync::Arc};
|
||||||
|
|
||||||
use ide::{Change, CompletionConfig, FilePosition, TextSize};
|
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 test_utils::project_root;
|
||||||
use vfs::{AbsPathBuf, VfsPath};
|
use vfs::{AbsPathBuf, VfsPath};
|
||||||
|
|
||||||
|
@ -133,7 +136,7 @@ fn integrated_completion_benchmark() {
|
||||||
add_call_argument_snippets: true,
|
add_call_argument_snippets: true,
|
||||||
snippet_cap: SnippetCap::new(true),
|
snippet_cap: SnippetCap::new(true),
|
||||||
insert_use: InsertUseConfig {
|
insert_use: InsertUseConfig {
|
||||||
merge: Some(MergeBehavior::Crate),
|
granularity: ImportGranularity::Crate,
|
||||||
prefix_kind: hir::PrefixKind::ByCrate,
|
prefix_kind: hir::PrefixKind::ByCrate,
|
||||||
group: true,
|
group: true,
|
||||||
},
|
},
|
||||||
|
@ -166,7 +169,7 @@ fn integrated_completion_benchmark() {
|
||||||
add_call_argument_snippets: true,
|
add_call_argument_snippets: true,
|
||||||
snippet_cap: SnippetCap::new(true),
|
snippet_cap: SnippetCap::new(true),
|
||||||
insert_use: InsertUseConfig {
|
insert_use: InsertUseConfig {
|
||||||
merge: Some(MergeBehavior::Crate),
|
granularity: ImportGranularity::Crate,
|
||||||
prefix_kind: hir::PrefixKind::ByCrate,
|
prefix_kind: hir::PrefixKind::ByCrate,
|
||||||
group: true,
|
group: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -1145,7 +1145,7 @@ mod tests {
|
||||||
|
|
||||||
use ide::Analysis;
|
use ide::Analysis;
|
||||||
use ide_db::helpers::{
|
use ide_db::helpers::{
|
||||||
insert_use::{InsertUseConfig, PrefixKind},
|
insert_use::{ImportGranularity, InsertUseConfig, PrefixKind},
|
||||||
SnippetCap,
|
SnippetCap,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1177,7 +1177,7 @@ mod tests {
|
||||||
add_call_argument_snippets: true,
|
add_call_argument_snippets: true,
|
||||||
snippet_cap: SnippetCap::new(true),
|
snippet_cap: SnippetCap::new(true),
|
||||||
insert_use: InsertUseConfig {
|
insert_use: InsertUseConfig {
|
||||||
merge: None,
|
granularity: ImportGranularity::Item,
|
||||||
prefix_kind: PrefixKind::Plain,
|
prefix_kind: PrefixKind::Plain,
|
||||||
group: true,
|
group: true,
|
||||||
},
|
},
|
||||||
|
|
|
@ -385,19 +385,21 @@
|
||||||
"markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
|
"markdownDescription": "Optional settings passed to the debug engine. Example: `{ \"lldb\": { \"terminal\":\"external\"} }`"
|
||||||
},
|
},
|
||||||
"$generated-start": false,
|
"$generated-start": false,
|
||||||
"rust-analyzer.assist.importMergeBehavior": {
|
"rust-analyzer.assist.importGranularity": {
|
||||||
"markdownDescription": "The strategy to use when inserting new imports or merging imports.",
|
"markdownDescription": "How imports should be grouped into use statements.",
|
||||||
"default": "crate",
|
"default": "preserve",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
"none",
|
"preserve",
|
||||||
"crate",
|
"crate",
|
||||||
"module"
|
"module",
|
||||||
|
"item"
|
||||||
],
|
],
|
||||||
"enumDescriptions": [
|
"enumDescriptions": [
|
||||||
"Do not merge imports at all.",
|
"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.",
|
"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."
|
"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": {
|
"rust-analyzer.assist.importPrefix": {
|
||||||
|
|
Loading…
Reference in a new issue