Skip to content

Implement style_edition config #5787

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

Closed
wants to merge 1 commit into from
Closed
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
14 changes: 14 additions & 0 deletions Configurations.md
Original file line number Diff line number Diff line change
Expand Up @@ -2593,6 +2593,20 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi

See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)

## `style_edition`

The style edition used to format your code. rustfmt output may differ between style editions.

- **Default value**: `"2015"`
- **Possible values**: `"2015"`, `"2018"`, `"2021"`, `"2024"`
- **Stable**: Yes

The `style_edition` can be specified using the `--style-edition` CLI option or via your `rustfmt.toml`

```toml
style_edition = "2021"
```

## `tab_spaces`

Number of spaces per tab
Expand Down
70 changes: 70 additions & 0 deletions Contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,73 @@ the config struct and parse a config file, etc. Checking an option is done by
accessing the correct field on the config struct, e.g., `config.max_width()`. Most
functions have a `Config`, or one can be accessed via a visitor or context of
some kind.

###### Adding `style_edition` support for your new config

`style_edition` is the mechanism used by rustfmt to maintain backwards compatability, while allowing
room to change formatting over time. All configuration options must implement the `StyleEditionDefault` triat.
If you're definig a new config you can use the `#[style_edition]` attribute to help you automatically define the trait.

When defining a new configuration option it should be sufficient to only define the default value which applies to
all `style_edtions`.

For simple cases you can define a new unit struct that defines the `style_edition` defaults for your new
configuration option.

```rust
#[style_edition(100)]
struct MaxWidth;
```

If your new config is an enum you can set the defulats similarly to how you'd set it for a unit struct.

```rust
/// Controls how rustfmt should handle case in hexadecimal literals.
#[style_edition(HexLiteralCase::Preserve)]
#[config_type]
pub enum HexLiteralCase {
/// Leave the literal as-is
Preserve,
/// Ensure all literals use uppercase lettering
Upper,
/// Ensure all literals use lowercase lettering
Lower,
}
```

You can alternatively set the default directly on the enum variant itself.

```rust
/// Client-preference for coloured output.
#[style_edition]
#[config_type]
pub enum Color {
/// Always use color, whether it is a piped or terminal output
Always,
/// Never use color
Never,
#[se_default]
/// Automatically use color, if supported by terminal
Auto,
}
```

In cases where your default value is a more complex type you'll have to implement `StyleEditionDefault` by hand.

```rust
/// A set of directories, files and modules that rustfmt should ignore.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct IgnoreList {
/// A set of path specified in rustfmt.toml.
path_set: HashSet<PathBuf>,
/// A path to rustfmt.toml.
rustfmt_toml_path: PathBuf,
}

impl StyleEditionDefault for IgnoreList {
type ConfigType = Self;
fn style_edition_default(_style_edition: StyleEdition) -> Self::ConfigType {
IgnoreList::default()
}
}
```
2 changes: 1 addition & 1 deletion config_proc_macro/src/attrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
}
}

fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
pub fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
match &attr.meta {
syn::Meta::Path(path) if path.is_ident(name) => true,
_ => false,
Expand Down
12 changes: 12 additions & 0 deletions config_proc_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod attrs;
mod config_type;
mod item_enum;
mod item_struct;
mod style_edition;
mod utils;

use std::str::FromStr;
Expand Down Expand Up @@ -82,3 +83,14 @@ pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStre
token_stream
}
}

/// Implement the StyleEditionDefault trait for the given item;
#[proc_macro_attribute]
pub fn style_edition(args: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as syn::Item);
let args = parse_macro_input!(args as style_edition::StyleEditionDefault);

let output = style_edition::define_style_edition(args, input).unwrap();
let result = TokenStream::from(output);
result
}
Loading