Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rename merge_imports to imports_granularity and add a Module option. #4600

Merged
merged 6 commits into from
Jan 10, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 47 additions & 5 deletions Configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -1705,13 +1705,56 @@ pub enum Foo {}
pub enum Foo {}
```

## `merge_imports`
## `imports_granularity`

Merge together related imports based on their paths.

- **Default value**: `Preserve`
- **Possible values**: `Preserve`, `Crate`, `Module`
- **Stable**: No

#### `Preserve` (default):

goffrie marked this conversation as resolved.
Show resolved Hide resolved
Do not perform any merging and preserve the original structure written by the developer.

```rust
use foo::b;
use foo::b::{f, g};
use foo::{a, c, d::e};
use qux::{h, i};
```

#### `Crate`:

Merge multiple imports into a single nested import.
Merge imports from the same crate into a single `use` statement. Conversely, imports from different crates are split into separate statements.

```rust
use foo::{
a, b,
b::{f, g},
c,
d::e,
};
use qux::{h, i};
```

#### `Module`:

Merge imports from the same module into a single `use` statement. Conversely, imports from different modules are split into separate statements.

```rust
use foo::b::{f, g};
use foo::d::e;
use foo::{a, b, c};
use qux::{h, i};
```

## `merge_imports`

This option is deprecated. Use `imports_granularity = "Crate"` instead.

- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: [#3362](/~https://github.com/rust-lang/rustfmt/issues/3362))

#### `false` (default):

Expand All @@ -1727,7 +1770,6 @@ use foo::{e, f};
use foo::{a, b, c, d, e, f, g};
```


## `newline_style`

Unix or Windows line endings
Expand Down Expand Up @@ -2560,7 +2602,7 @@ Enable unstable features on stable and beta channels (unstable features are avai

For example:
```bash
rustfmt src/lib.rs --config unstable_features=true merge_imports=true
rustfmt src/lib.rs --config unstable_features=true imports_granularity=Crate
```

## `use_field_init_shorthand`
Expand Down
81 changes: 69 additions & 12 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,11 @@ create_config! {
// Imports
imports_indent: IndentStyle, IndentStyle::Block, false, "Indent of imports";
imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";
merge_imports: bool, false, false, "Merge imports";
imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
"Merge or split imports to the provided granularity";
group_imports: GroupImportsTactic, GroupImportsTactic::Preserve, false,
"Controls the strategy for how imports are grouped together";
merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";

// Ordering
reorder_imports: bool, true, true, "Reorder import and extern crate statements alphabetically";
Expand Down Expand Up @@ -175,6 +177,7 @@ impl PartialConfig {
// Non-user-facing options can't be specified in TOML
let mut cloned = self.clone();
cloned.file_lines = None;
cloned.merge_imports = None;

::toml::to_string(&cloned).map_err(ToTomlError)
}
Expand Down Expand Up @@ -444,6 +447,10 @@ mod test {
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single \
line if-else expressions. A value of zero means always break if-else expressions.";
// merge_imports deprecation
imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
"Merge imports";
merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";

unstable_features: bool, false, true,
"Enables unstable features on stable and beta channels \
Expand Down Expand Up @@ -595,7 +602,7 @@ fn_single_line = false
where_single_line = false
imports_indent = "Block"
imports_layout = "Mixed"
merge_imports = false
imports_granularity = "Preserve"
group_imports = "Preserve"
reorder_imports = true
reorder_modules = true
Expand Down Expand Up @@ -716,13 +723,13 @@ ignore = []
}
let toml = r#"
unstable_features = true
merge_imports = true
imports_granularity = "Crate"
"#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert_eq!(config.was_set().unstable_features(), true);
assert_eq!(config.was_set().merge_imports(), true);
assert_eq!(config.was_set().imports_granularity(), true);
assert_eq!(config.unstable_features(), true);
assert_eq!(config.merge_imports(), true);
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}

#[test]
Expand All @@ -731,9 +738,10 @@ ignore = []
// This test requires non-nightly
return;
}
let config = Config::from_toml("merge_imports = true", Path::new("")).unwrap();
assert_eq!(config.was_set().merge_imports(), false);
assert_eq!(config.merge_imports(), false);
let config =
Config::from_toml("imports_granularity = \"Crate\"", Path::new("")).unwrap();
assert_eq!(config.was_set().imports_granularity(), false);
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}

#[test]
Expand Down Expand Up @@ -778,12 +786,12 @@ ignore = []
}
let mut config = Config::default();
assert_eq!(config.unstable_features(), false);
config.override_value("merge_imports", "true");
assert_eq!(config.merge_imports(), false);
config.override_value("imports_granularity", "Crate");
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
config.override_value("unstable_features", "true");
assert_eq!(config.unstable_features(), true);
config.override_value("merge_imports", "true");
assert_eq!(config.merge_imports(), true);
config.override_value("imports_granularity", "Crate");
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}

#[test]
Expand Down Expand Up @@ -1036,4 +1044,53 @@ ignore = []
assert_eq!(config.single_line_if_else_max_width(), 100);
}
}

#[cfg(test)]
mod deprecated_option_merge_imports {
use super::*;

#[test]
fn test_old_option_set() {
let toml = r#"
unstable_features = true
merge_imports = true
"#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
}

#[test]
fn test_both_set() {
let toml = r#"
unstable_features = true
merge_imports = true
imports_granularity = "Preserve"
"#;
let config = Config::from_toml(toml, Path::new("")).unwrap();
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}

#[test]
fn test_new_overridden() {
let toml = r#"
unstable_features = true
merge_imports = true
"#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
config.override_value("imports_granularity", "Preserve");
assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
}

#[test]
fn test_old_overridden() {
let toml = r#"
unstable_features = true
imports_granularity = "Module"
"#;
let mut config = Config::from_toml(toml, Path::new("")).unwrap();
config.override_value("merge_imports", "true");
// no effect: the new option always takes precedence
assert_eq!(config.imports_granularity(), ImportGranularity::Module);
}
}
}
27 changes: 26 additions & 1 deletion src/config/config_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,12 @@ macro_rules! update_config {
$config.ignore.2 = old_ignored.merge_into(new_ignored);
};

($config:ident, merge_imports = $val:ident, $dir:ident) => {
$config.merge_imports.1 = true;
$config.merge_imports.2 = $val;
$config.set_merge_imports();
};

($config:ident, $i:ident = $val:ident, $dir:ident) => {
$config.$i.1 = true;
$config.$i.2 = $val;
Expand Down Expand Up @@ -121,6 +127,7 @@ macro_rules! create_config {
| "array_width"
| "chain_width" => self.0.set_heuristics(),
"license_template_path" => self.0.set_license_template(),
"merge_imports" => self.0.set_merge_imports(),
&_ => (),
}
}
Expand Down Expand Up @@ -272,14 +279,16 @@ macro_rules! create_config {
| "array_width"
| "chain_width" => self.set_heuristics(),
"license_template_path" => self.set_license_template(),
"merge_imports" => self.set_merge_imports(),
&_ => (),
}
}

#[allow(unreachable_pub)]
pub fn is_hidden_option(name: &str) -> bool {
const HIDE_OPTIONS: [&str; 1] = [
const HIDE_OPTIONS: [&str; 2] = [
"file_lines",
"merge_imports",
];
HIDE_OPTIONS.contains(&name)
}
Expand Down Expand Up @@ -423,6 +432,22 @@ macro_rules! create_config {
}
}

fn set_merge_imports(&mut self) {
if self.was_set().merge_imports() {
eprintln!(
"Warning: the `merge_imports` option is deprecated. \
Use `imports_granularity=Crate` instead"
);
if !self.was_set().imports_granularity() {
self.imports_granularity.2 = if self.merge_imports() {
ImportGranularity::Crate
} else {
ImportGranularity::Preserve
};
}
}
}

#[allow(unreachable_pub)]
/// Returns `true` if the config key was explicitly set and is the default value.
pub fn is_default(&self, key: &str) -> bool {
Expand Down
14 changes: 13 additions & 1 deletion src/config/options.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;

use rustfmt_config_proc_macro::config_type;
use serde::de::{SeqAccess, Visitor};
Expand Down Expand Up @@ -118,6 +119,17 @@ pub enum GroupImportsTactic {
StdExternalCrate,
}

#[config_type]
/// How to merge imports.
pub enum ImportGranularity {
/// Do not merge imports.
Preserve,
/// Use one `use` statement per crate.
Crate,
/// Use one `use` statement per module.
Module,
}

#[config_type]
pub enum ReportTactic {
Always,
Expand Down Expand Up @@ -317,7 +329,7 @@ impl IgnoreList {
}
}

impl std::str::FromStr for IgnoreList {
impl FromStr for IgnoreList {
type Err = &'static str;

fn from_str(_: &str) -> Result<Self, Self::Err> {
Expand Down
Loading