Skip to main content

rustfmt_nightly/config/
options.rs

1#![allow(unused_imports)]
2
3use std::collections::{HashSet, hash_set};
4use std::fmt;
5use std::path::{Path, PathBuf};
6use std::str::FromStr;
7
8use itertools::Itertools;
9use rustfmt_config_proc_macro::config_type;
10use serde::de::{SeqAccess, Visitor};
11use serde::ser::SerializeSeq;
12use serde::{Deserialize, Deserializer, Serialize, Serializer};
13
14use crate::config::Config;
15use crate::config::file_lines::FileLines;
16use crate::config::lists::*;
17use crate::config::macro_names::MacroSelectors;
18
19#[config_type]
20pub enum NewlineStyle {
21    /// Auto-detect based on the raw source input.
22    Auto,
23    /// Force CRLF (`\r\n`).
24    Windows,
25    /// Force CR (`\n`).
26    Unix,
27    /// `\r\n` in Windows, `\n` on other platforms.
28    Native,
29}
30
31#[config_type]
32/// Where to put the opening brace of items (`fn`, `impl`, etc.).
33pub enum BraceStyle {
34    /// Put the opening brace on the next line.
35    AlwaysNextLine,
36    /// Put the opening brace on the same line, if possible.
37    PreferSameLine,
38    /// Prefer the same line except where there is a where-clause, in which
39    /// case force the brace to be put on the next line.
40    SameLineWhere,
41}
42
43#[config_type]
44/// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
45pub enum ControlBraceStyle {
46    /// K&R style, Rust community default
47    AlwaysSameLine,
48    /// Stroustrup style
49    ClosingNextLine,
50    /// Allman style
51    AlwaysNextLine,
52}
53
54#[config_type]
55/// How to indent.
56pub enum IndentStyle {
57    /// First line on the same line as the opening brace, all lines aligned with
58    /// the first line.
59    Visual,
60    /// First line is on a new line and all lines align with **block** indent.
61    Block,
62}
63
64#[config_type]
65/// How to place a list-like items.
66/// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
67pub enum Density {
68    /// Fit as much on one line as possible.
69    Compressed,
70    /// Items are placed horizontally if sufficient space, vertically otherwise.
71    Tall,
72    /// Place every item on a separate line.
73    Vertical,
74}
75
76#[config_type]
77/// Spacing around type combinators.
78pub enum TypeDensity {
79    /// No spaces around "=" and "+"
80    Compressed,
81    /// Spaces around " = " and " + "
82    Wide,
83}
84
85#[config_type]
86/// Heuristic settings that can be used to simply
87/// the configuration of the granular width configurations
88/// like `struct_lit_width`, `array_width`, etc.
89pub enum Heuristics {
90    /// Turn off any heuristics
91    Off,
92    /// Turn on max heuristics
93    Max,
94    /// Use scaled values based on the value of `max_width`
95    Default,
96}
97
98#[config_type]
99/// Heuristic settings for doc comments. Same as `Heuristics`, but `Inherit` will inherit the value
100/// from the top-level configuration.
101pub enum DocCodeHeuristics {
102    /// Inherit from the top-level configuration
103    Inherit,
104    /// Turn off any heuristics
105    Off,
106    /// Turn on max heuristics
107    Max,
108    /// Use scaled values based on the value of `max_width`
109    Default,
110}
111
112impl DocCodeHeuristics {
113    pub fn to_heuristics(self) -> Option<Heuristics> {
114        match self {
115            DocCodeHeuristics::Inherit => None,
116            DocCodeHeuristics::Off => Some(Heuristics::Off),
117            DocCodeHeuristics::Max => Some(Heuristics::Max),
118            DocCodeHeuristics::Default => Some(Heuristics::Default),
119        }
120    }
121}
122
123impl Density {
124    pub fn to_list_tactic(self, len: usize) -> ListTactic {
125        match self {
126            Density::Compressed => ListTactic::Mixed,
127            Density::Tall => ListTactic::HorizontalVertical,
128            Density::Vertical if len == 1 => ListTactic::Horizontal,
129            Density::Vertical => ListTactic::Vertical,
130        }
131    }
132}
133
134#[config_type]
135/// Configuration for import groups, i.e. sets of imports separated by newlines.
136pub enum GroupImportsTactic {
137    /// Keep groups as they are.
138    Preserve,
139    /// Discard existing groups, and create new groups for
140    ///  1. `std` / `core` / `alloc` imports
141    ///  2. other imports
142    ///  3. `self` / `crate` / `super` imports
143    StdExternalCrate,
144    /// Discard existing groups, and create a single group for everything
145    One,
146}
147
148#[config_type]
149/// How to merge imports.
150pub enum ImportGranularity {
151    /// Do not merge imports.
152    Preserve,
153    /// Use one `use` statement per crate.
154    Crate,
155    /// Use one `use` statement per module.
156    Module,
157    /// Use one `use` statement per imported item.
158    Item,
159    /// Use one `use` statement including all items.
160    One,
161}
162
163/// Controls how rustfmt should handle case in hexadecimal literals.
164#[config_type]
165pub enum HexLiteralCase {
166    /// Leave the literal as-is
167    Preserve,
168    /// Ensure all literals use uppercase lettering
169    Upper,
170    /// Ensure all literals use lowercase lettering
171    Lower,
172}
173
174/// How to treat trailing zeros in floating-point literals.
175#[config_type]
176pub enum FloatLiteralTrailingZero {
177    /// Leave the literal as-is.
178    Preserve,
179    /// Add a trailing zero to the literal.
180    Always,
181    /// Add a trailing zero by default. If the literal contains an exponent or a suffix, the zero
182    /// and the preceding period are removed.
183    IfNoPostfix,
184    /// Remove the trailing zero. If the literal contains an exponent or a suffix, the preceding
185    /// period is also removed.
186    Never,
187}
188
189#[config_type]
190pub enum ReportTactic {
191    Always,
192    Unnumbered,
193    Never,
194}
195
196/// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
197/// option.
198#[config_type]
199pub enum EmitMode {
200    /// Emits to files.
201    Files,
202    /// Writes the output to stdout.
203    Stdout,
204    /// Displays how much of the input file was processed
205    Coverage,
206    /// Unfancy stdout
207    Checkstyle,
208    /// Writes the resulting diffs in a JSON format. Returns an empty array
209    /// `[]` if there were no diffs.
210    Json,
211    /// Output the changed lines (for internal value only)
212    ModifiedLines,
213    /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
214    /// quits with exit code 1.
215    /// This option is designed to be run in CI where a non-zero exit signifies
216    /// non-standard code formatting. Used for `--check`.
217    Diff,
218}
219
220/// Client-preference for coloured output.
221#[config_type]
222pub enum Color {
223    /// Always use color, whether it is a piped or terminal output
224    Always,
225    /// Never use color
226    Never,
227    /// Automatically use color, if supported by terminal
228    Auto,
229}
230
231#[config_type]
232/// rustfmt format style version.
233pub enum Version {
234    /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
235    One,
236    /// 2.x.y. When specified, rustfmt will format in the latest style.
237    Two,
238}
239
240impl Color {
241    /// Whether we should use a coloured terminal.
242    pub fn use_colored_tty(self) -> bool {
243        match self {
244            Color::Always | Color::Auto => true,
245            Color::Never => false,
246        }
247    }
248}
249
250/// How chatty should Rustfmt be?
251#[config_type]
252pub enum Verbosity {
253    /// Emit more.
254    Verbose,
255    /// Default.
256    Normal,
257    /// Emit as little as possible.
258    Quiet,
259}
260
261#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
262pub struct WidthHeuristics {
263    // Maximum width of the args of a function call before falling back
264    // to vertical formatting.
265    pub(crate) fn_call_width: usize,
266    // Maximum width of the args of a function-like attributes before falling
267    // back to vertical formatting.
268    pub(crate) attr_fn_like_width: usize,
269    // Maximum width in the body of a struct lit before falling back to
270    // vertical formatting.
271    pub(crate) struct_lit_width: usize,
272    // Maximum width in the body of a struct variant before falling back
273    // to vertical formatting.
274    pub(crate) struct_variant_width: usize,
275    // Maximum width of an array literal before falling back to vertical
276    // formatting.
277    pub(crate) array_width: usize,
278    // Maximum length of a chain to fit on a single line.
279    pub(crate) chain_width: usize,
280    // Maximum line length for single line if-else expressions. A value
281    // of zero means always break if-else expressions.
282    pub(crate) single_line_if_else_max_width: usize,
283    // Maximum line length for single line let-else statements. A value of zero means
284    // always format the divergent `else` block over multiple lines.
285    pub(crate) single_line_let_else_max_width: usize,
286}
287
288impl fmt::Display for WidthHeuristics {
289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290        write!(f, "{self:?}")
291    }
292}
293
294impl WidthHeuristics {
295    // Using this WidthHeuristics means we ignore heuristics.
296    pub fn null() -> WidthHeuristics {
297        WidthHeuristics {
298            fn_call_width: usize::MAX,
299            attr_fn_like_width: usize::MAX,
300            struct_lit_width: 0,
301            struct_variant_width: 0,
302            array_width: usize::MAX,
303            chain_width: usize::MAX,
304            single_line_if_else_max_width: 0,
305            single_line_let_else_max_width: 0,
306        }
307    }
308
309    pub fn set(max_width: usize) -> WidthHeuristics {
310        WidthHeuristics {
311            fn_call_width: max_width,
312            attr_fn_like_width: max_width,
313            struct_lit_width: max_width,
314            struct_variant_width: max_width,
315            array_width: max_width,
316            chain_width: max_width,
317            single_line_if_else_max_width: max_width,
318            single_line_let_else_max_width: max_width,
319        }
320    }
321
322    // scale the default WidthHeuristics according to max_width
323    pub fn scaled(max_width: usize) -> WidthHeuristics {
324        const DEFAULT_MAX_WIDTH: usize = 100;
325        let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
326            let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
327            // round to the closest 0.1
328            (ratio * 10.0).round() / 10.0
329        } else {
330            1.0
331        };
332        WidthHeuristics {
333            fn_call_width: (60.0 * max_width_ratio).round() as usize,
334            attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
335            struct_lit_width: (18.0 * max_width_ratio).round() as usize,
336            struct_variant_width: (35.0 * max_width_ratio).round() as usize,
337            array_width: (60.0 * max_width_ratio).round() as usize,
338            chain_width: (60.0 * max_width_ratio).round() as usize,
339            single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
340            single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
341        }
342    }
343}
344
345impl ::std::str::FromStr for WidthHeuristics {
346    type Err = &'static str;
347
348    fn from_str(_: &str) -> Result<Self, Self::Err> {
349        Err("WidthHeuristics is not parsable")
350    }
351}
352
353impl Default for EmitMode {
354    fn default() -> EmitMode {
355        EmitMode::Files
356    }
357}
358
359/// A set of directories, files and modules that rustfmt should ignore.
360#[derive(Default, Clone, Debug, PartialEq)]
361pub struct IgnoreList {
362    /// A set of path specified in rustfmt.toml.
363    path_set: HashSet<PathBuf>,
364    /// A path to rustfmt.toml.
365    rustfmt_toml_path: PathBuf,
366}
367
368impl fmt::Display for IgnoreList {
369    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
370        write!(
371            f,
372            "[{}]",
373            self.path_set
374                .iter()
375                .format_with(", ", |path, f| f(&format_args!(
376                    "{}",
377                    path.to_string_lossy()
378                )))
379        )
380    }
381}
382
383impl Serialize for IgnoreList {
384    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
385    where
386        S: Serializer,
387    {
388        let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
389        for e in &self.path_set {
390            seq.serialize_element(e)?;
391        }
392        seq.end()
393    }
394}
395
396impl<'de> Deserialize<'de> for IgnoreList {
397    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
398    where
399        D: Deserializer<'de>,
400    {
401        struct HashSetVisitor;
402        impl<'v> Visitor<'v> for HashSetVisitor {
403            type Value = HashSet<PathBuf>;
404
405            fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
406                formatter.write_str("a sequence of path")
407            }
408
409            fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
410            where
411                A: SeqAccess<'v>,
412            {
413                let mut path_set = HashSet::new();
414                while let Some(elem) = seq.next_element()? {
415                    path_set.insert(elem);
416                }
417                Ok(path_set)
418            }
419        }
420        Ok(IgnoreList {
421            path_set: deserializer.deserialize_seq(HashSetVisitor)?,
422            rustfmt_toml_path: PathBuf::new(),
423        })
424    }
425}
426
427impl<'a> IntoIterator for &'a IgnoreList {
428    type Item = &'a PathBuf;
429    type IntoIter = hash_set::Iter<'a, PathBuf>;
430
431    fn into_iter(self) -> Self::IntoIter {
432        self.path_set.iter()
433    }
434}
435
436impl IgnoreList {
437    pub fn add_prefix(&mut self, dir: &Path) {
438        self.rustfmt_toml_path = dir.to_path_buf();
439    }
440
441    pub fn rustfmt_toml_path(&self) -> &Path {
442        &self.rustfmt_toml_path
443    }
444}
445
446impl FromStr for IgnoreList {
447    type Err = &'static str;
448
449    fn from_str(_: &str) -> Result<Self, Self::Err> {
450        Err("IgnoreList is not parsable")
451    }
452}
453
454/// Maps client-supplied options to Rustfmt's internals, mostly overriding
455/// values in a config with values from the command line.
456pub trait CliOptions {
457    fn apply_to(self, config: &mut Config);
458
459    /// It is ok if the returned path doesn't exist or is not canonicalized
460    /// (i.e. the callers are expected to handle such cases).
461    fn config_path(&self) -> Option<&Path>;
462    fn edition(&self) -> Option<Edition>;
463    fn style_edition(&self) -> Option<StyleEdition>;
464    fn version(&self) -> Option<Version>;
465}
466
467/// The edition of the syntax and semantics of code (RFC 2052).
468#[config_type]
469pub enum Edition {
470    #[value = "2015"]
471    #[doc_hint = "2015"]
472    /// Edition 2015.
473    Edition2015,
474    #[value = "2018"]
475    #[doc_hint = "2018"]
476    /// Edition 2018.
477    Edition2018,
478    #[value = "2021"]
479    #[doc_hint = "2021"]
480    /// Edition 2021.
481    Edition2021,
482    #[value = "2024"]
483    #[doc_hint = "2024"]
484    /// Edition 2024.
485    Edition2024,
486}
487
488impl Default for Edition {
489    fn default() -> Edition {
490        Edition::Edition2015
491    }
492}
493
494impl From<Edition> for rustc_span::edition::Edition {
495    fn from(edition: Edition) -> Self {
496        match edition {
497            Edition::Edition2015 => Self::Edition2015,
498            Edition::Edition2018 => Self::Edition2018,
499            Edition::Edition2021 => Self::Edition2021,
500            Edition::Edition2024 => Self::Edition2024,
501        }
502    }
503}
504
505impl From<Edition> for StyleEdition {
506    fn from(edition: Edition) -> Self {
507        match edition {
508            Edition::Edition2015 => StyleEdition::Edition2015,
509            Edition::Edition2018 => StyleEdition::Edition2018,
510            Edition::Edition2021 => StyleEdition::Edition2021,
511            Edition::Edition2024 => StyleEdition::Edition2024,
512        }
513    }
514}
515
516impl PartialOrd for Edition {
517    fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
518        rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
519    }
520}
521
522/// Controls how rustfmt should handle leading pipes on match arms.
523#[config_type]
524pub enum MatchArmLeadingPipe {
525    /// Place leading pipes on all match arms
526    Always,
527    /// Never emit leading pipes on match arms
528    Never,
529    /// Preserve any existing leading pipes
530    Preserve,
531}
532
533/// Defines the default values for each config according to the edition of the
534/// [Style Guide] as per [RFC 3338]. Rustfmt output may differ between Style editions.
535///
536/// [Style Guide]: https://doc.rust-lang.org/nightly/style-guide/
537/// [RFC 3338]: https://rust-lang.github.io/rfcs/3338-style-evolution.html
538#[config_type]
539pub enum StyleEdition {
540    #[value = "2015"]
541    #[doc_hint = "2015"]
542    /// [Edition 2015]()
543    Edition2015,
544    #[value = "2018"]
545    #[doc_hint = "2018"]
546    /// [Edition 2018]()
547    Edition2018,
548    #[value = "2021"]
549    #[doc_hint = "2021"]
550    /// [Edition 2021]()
551    Edition2021,
552    #[value = "2024"]
553    #[doc_hint = "2024"]
554    /// [Edition 2024]().
555    Edition2024,
556    #[value = "2027"]
557    #[doc_hint = "2027"]
558    #[unstable_variant]
559    /// [Edition 2027]().
560    Edition2027,
561}
562
563impl From<StyleEdition> for rustc_span::edition::Edition {
564    fn from(edition: StyleEdition) -> Self {
565        match edition {
566            StyleEdition::Edition2015 => Self::Edition2015,
567            StyleEdition::Edition2018 => Self::Edition2018,
568            StyleEdition::Edition2021 => Self::Edition2021,
569            StyleEdition::Edition2024 => Self::Edition2024,
570            // TODO: should update to Edition2027 when it becomes available
571            StyleEdition::Edition2027 => Self::Edition2024,
572        }
573    }
574}
575
576impl PartialOrd for StyleEdition {
577    fn partial_cmp(&self, other: &StyleEdition) -> Option<std::cmp::Ordering> {
578        // FIXME(ytmimi): Update `StyleEdition::Edition2027` logic when
579        // `rustc_span::edition::Edition::Edition2027` becomes available in the compiler
580        match (self, other) {
581            (Self::Edition2027, Self::Edition2027) => Some(std::cmp::Ordering::Equal),
582            (_, Self::Edition2027) => Some(std::cmp::Ordering::Less),
583            (Self::Edition2027, _) => Some(std::cmp::Ordering::Greater),
584            (Self::Edition2015 | Self::Edition2018 | Self::Edition2021 | Self::Edition2024, _) => {
585                rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
586            }
587        }
588    }
589}
590
591/// Defines unit structs to implement `StyleEditionDefault` for.
592#[macro_export]
593macro_rules! config_option_with_style_edition_default {
594    ($name:ident, $config_ty:ty, _ => $default:expr) => {
595        #[allow(unreachable_pub)]
596        pub struct $name;
597        $crate::style_edition_default!($name, $config_ty, _ => $default);
598    };
599    ($name:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => {
600        pub struct $name;
601        $crate::style_edition_default!(
602            $name,
603            $config_ty,
604            Edition2024 => $default_2024,
605            _ => $default_2015
606        );
607    };
608    (
609        $($name:ident, $config_ty:ty, $(Edition2024 => $default_2024:expr,)? _ => $default:expr);*
610        $(;)*
611    ) => {
612        $(
613            config_option_with_style_edition_default!(
614                $name, $config_ty, $(Edition2024 => $default_2024,)? _ => $default
615            );
616        )*
617    };
618}
619
620// TODO(ytmimi) Some of the configuration values have a `Config` suffix, while others don't.
621// I chose to add a `Config` suffix in cases where a type for the config option was already
622// defined. For example, `NewlineStyle` and `NewlineStyleConfig`. There was some discussion
623// about using the `Config` suffix more consistently.
624config_option_with_style_edition_default!(
625    // Fundamental stuff
626    MaxWidth, usize, _ => 100;
627    HardTabs, bool, _ => false;
628    TabSpaces, usize, _ => 4;
629    NewlineStyleConfig, NewlineStyle, _ => NewlineStyle::Auto;
630    IndentStyleConfig, IndentStyle, _ => IndentStyle::Block;
631
632    // Width Heuristics
633    UseSmallHeuristics, Heuristics, _ => Heuristics::Default;
634    WidthHeuristicsConfig, WidthHeuristics, _ => WidthHeuristics::scaled(100);
635    FnCallWidth, usize, _ => 60;
636    AttrFnLikeWidth, usize, _ => 70;
637    StructLitWidth, usize, _ => 18;
638    StructVariantWidth, usize, _ => 35;
639    ArrayWidth, usize, _ => 60;
640    ChainWidth, usize, _ => 60;
641    SingleLineIfElseMaxWidth, usize, _ => 50;
642    SingleLineLetElseMaxWidth, usize, _ => 50;
643
644    // Comments. macros, and strings
645    WrapComments, bool, _ => false;
646    FormatCodeInDocComments, bool, _ => false;
647    DocCommentCodeBlockWidth, usize, _ => 100;
648    DocUseSmallHeuristics, DocCodeHeuristics, _ => DocCodeHeuristics::Inherit;
649    CommentWidth, usize, _ => 80;
650    NormalizeComments, bool, _ => false;
651    NormalizeDocAttributes, bool, _ => false;
652    FormatStrings, bool, _ => false;
653    FormatMacroMatchers, bool, _ => false;
654    FormatMacroBodies, bool, _ => true;
655    SkipMacroInvocations, MacroSelectors, _ => MacroSelectors::default();
656    HexLiteralCaseConfig, HexLiteralCase, _ => HexLiteralCase::Preserve;
657    FloatLiteralTrailingZeroConfig, FloatLiteralTrailingZero, _ =>
658        FloatLiteralTrailingZero::Preserve;
659
660    // Single line expressions and items
661    EmptyItemSingleLine, bool, _ => true;
662    StructLitSingleLine, bool, _ => true;
663    FnSingleLine, bool, _ => false;
664    WhereSingleLine, bool, _ => false;
665
666    // Imports
667    ImportsIndent, IndentStyle, _ => IndentStyle::Block;
668    ImportsLayout, ListTactic, _ => ListTactic::Mixed;
669    ImportsGranularityConfig, ImportGranularity, _ => ImportGranularity::Preserve;
670    GroupImportsTacticConfig, GroupImportsTactic, _ => GroupImportsTactic::Preserve;
671    MergeImports, bool, _ => false;
672
673    // Ordering
674    ReorderImports, bool, _ => true;
675    ReorderModules, bool, _ => true;
676    ReorderImplItems, bool, _ => false;
677
678    // Spaces around punctuation
679    TypePunctuationDensity, TypeDensity, _ => TypeDensity::Wide;
680    SpaceBeforeColon, bool, _ => false;
681    SpaceAfterColon, bool, _ => true;
682    SpacesAroundRanges, bool, _ => false;
683    BinopSeparator, SeparatorPlace, _ => SeparatorPlace::Front;
684
685    // Misc.
686    RemoveNestedParens, bool, _ => true;
687    CombineControlExpr, bool, _ => true;
688    ShortArrayElementWidthThreshold, usize, _ => 10;
689    OverflowDelimitedExpr, bool, _ => false;
690    StructFieldAlignThreshold, usize, _ => 0;
691    EnumDiscrimAlignThreshold, usize, _ => 0;
692    MatchArmBlocks, bool, _ => true;
693    MatchArmLeadingPipeConfig, MatchArmLeadingPipe, _ => MatchArmLeadingPipe::Never;
694    MatchArmIndent, bool, _ => true;
695    ForceMultilineBlocks, bool, _ => false;
696    FnArgsLayout, Density, _ => Density::Tall;
697    FnParamsLayout, Density, _ => Density::Tall;
698    BraceStyleConfig, BraceStyle, _ => BraceStyle::SameLineWhere;
699    ControlBraceStyleConfig, ControlBraceStyle, _ => ControlBraceStyle::AlwaysSameLine;
700    TrailingSemicolon, bool, _ => true;
701    TrailingComma, SeparatorTactic, _ => SeparatorTactic::Vertical;
702    MatchBlockTrailingComma, bool, _ => false;
703    BlankLinesUpperBound, usize, _ => 1;
704    BlankLinesLowerBound, usize, _ => 0;
705    EditionConfig, Edition, _ => Edition::Edition2015;
706    StyleEditionConfig, StyleEdition,
707        Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
708    VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One;
709    InlineAttributeWidth, usize, _ => 0;
710    FormatGeneratedFiles, bool, _ => true;
711    GeneratedMarkerLineSearchLimit, usize, _ => 5;
712
713    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
714    MergeDerives, bool, _ => true;
715    UseTryShorthand, bool, _ => false;
716    UseFieldInitShorthand, bool, _ => false;
717    ForceExplicitAbi, bool, _ => true;
718    CondenseWildcardSuffixes, bool, _ => false;
719
720    // Control options (changes the operation of rustfmt, rather than the formatting)
721    ColorConfig, Color, _ => Color::Auto;
722    RequiredVersion, String, _ => env!("CARGO_PKG_VERSION").to_owned();
723    UnstableFeatures, bool, _ => false;
724    DisableAllFormatting, bool, _ => false;
725    SkipChildren, bool, _ => false;
726    HideParseErrors, bool, _ => false;
727    ShowParseErrors, bool, _ => true;
728    ErrorOnLineOverflow, bool, _ => false;
729    ErrorOnUnformatted, bool, _ => false;
730    Ignore, IgnoreList, _ => IgnoreList::default();
731
732    // Not user-facing
733    Verbose, Verbosity, _ => Verbosity::Normal;
734    FileLinesConfig, FileLines, _ => FileLines::all();
735    EmitModeConfig, EmitMode, _ => EmitMode::Files;
736    MakeBackup, bool, _ => false;
737    PrintMisformattedFileNames, bool, _ => false;
738);
739
740#[test]
741fn style_edition_comparisons() {
742    // Style Edition 2015
743    assert!(StyleEdition::Edition2015 == StyleEdition::Edition2015);
744    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2018);
745    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2021);
746    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2024);
747    assert!(StyleEdition::Edition2015 < StyleEdition::Edition2027);
748
749    // Style Edition 2018
750    assert!(StyleEdition::Edition2018 > StyleEdition::Edition2015);
751    assert!(StyleEdition::Edition2018 == StyleEdition::Edition2018);
752    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2021);
753    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2024);
754    assert!(StyleEdition::Edition2018 < StyleEdition::Edition2027);
755
756    // Style Edition 2021
757    assert!(StyleEdition::Edition2021 > StyleEdition::Edition2015);
758    assert!(StyleEdition::Edition2021 > StyleEdition::Edition2018);
759    assert!(StyleEdition::Edition2021 == StyleEdition::Edition2021);
760    assert!(StyleEdition::Edition2021 < StyleEdition::Edition2024);
761    assert!(StyleEdition::Edition2021 < StyleEdition::Edition2027);
762
763    // Style Edition 2024
764    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2015);
765    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2018);
766    assert!(StyleEdition::Edition2024 > StyleEdition::Edition2021);
767    assert!(StyleEdition::Edition2024 == StyleEdition::Edition2024);
768    assert!(StyleEdition::Edition2024 < StyleEdition::Edition2027);
769
770    // Style Edition 2024
771    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2015);
772    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2018);
773    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2021);
774    assert!(StyleEdition::Edition2027 > StyleEdition::Edition2024);
775    assert!(StyleEdition::Edition2027 == StyleEdition::Edition2027);
776}