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,
23 Windows,
25 Unix,
27 Native,
29}
30
31#[config_type]
32pub enum BraceStyle {
34 AlwaysNextLine,
36 PreferSameLine,
38 SameLineWhere,
41}
42
43#[config_type]
44pub enum ControlBraceStyle {
46 AlwaysSameLine,
48 ClosingNextLine,
50 AlwaysNextLine,
52}
53
54#[config_type]
55pub enum IndentStyle {
57 Visual,
60 Block,
62}
63
64#[config_type]
65pub enum Density {
68 Compressed,
70 Tall,
72 Vertical,
74}
75
76#[config_type]
77pub enum TypeDensity {
79 Compressed,
81 Wide,
83}
84
85#[config_type]
86pub enum Heuristics {
90 Off,
92 Max,
94 Default,
96}
97
98impl Density {
99 pub fn to_list_tactic(self, len: usize) -> ListTactic {
100 match self {
101 Density::Compressed => ListTactic::Mixed,
102 Density::Tall => ListTactic::HorizontalVertical,
103 Density::Vertical if len == 1 => ListTactic::Horizontal,
104 Density::Vertical => ListTactic::Vertical,
105 }
106 }
107}
108
109#[config_type]
110pub enum GroupImportsTactic {
112 Preserve,
114 StdExternalCrate,
119 One,
121}
122
123#[config_type]
124pub enum ImportGranularity {
126 Preserve,
128 Crate,
130 Module,
132 Item,
134 One,
136}
137
138#[config_type]
140pub enum HexLiteralCase {
141 Preserve,
143 Upper,
145 Lower,
147}
148
149#[config_type]
150pub enum ReportTactic {
151 Always,
152 Unnumbered,
153 Never,
154}
155
156#[config_type]
159pub enum EmitMode {
160 Files,
162 Stdout,
164 Coverage,
166 Checkstyle,
168 Json,
171 ModifiedLines,
173 Diff,
178}
179
180#[config_type]
182pub enum Color {
183 Always,
185 Never,
187 Auto,
189}
190
191#[config_type]
192pub enum Version {
194 One,
196 Two,
198}
199
200impl Color {
201 pub fn use_colored_tty(self) -> bool {
203 match self {
204 Color::Always | Color::Auto => true,
205 Color::Never => false,
206 }
207 }
208}
209
210#[config_type]
212pub enum Verbosity {
213 Verbose,
215 Normal,
217 Quiet,
219}
220
221#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
222pub struct WidthHeuristics {
223 pub(crate) fn_call_width: usize,
226 pub(crate) attr_fn_like_width: usize,
229 pub(crate) struct_lit_width: usize,
232 pub(crate) struct_variant_width: usize,
235 pub(crate) array_width: usize,
238 pub(crate) chain_width: usize,
240 pub(crate) single_line_if_else_max_width: usize,
243 pub(crate) single_line_let_else_max_width: usize,
246}
247
248impl fmt::Display for WidthHeuristics {
249 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
250 write!(f, "{self:?}")
251 }
252}
253
254impl WidthHeuristics {
255 pub fn null() -> WidthHeuristics {
257 WidthHeuristics {
258 fn_call_width: usize::MAX,
259 attr_fn_like_width: usize::MAX,
260 struct_lit_width: 0,
261 struct_variant_width: 0,
262 array_width: usize::MAX,
263 chain_width: usize::MAX,
264 single_line_if_else_max_width: 0,
265 single_line_let_else_max_width: 0,
266 }
267 }
268
269 pub fn set(max_width: usize) -> WidthHeuristics {
270 WidthHeuristics {
271 fn_call_width: max_width,
272 attr_fn_like_width: max_width,
273 struct_lit_width: max_width,
274 struct_variant_width: max_width,
275 array_width: max_width,
276 chain_width: max_width,
277 single_line_if_else_max_width: max_width,
278 single_line_let_else_max_width: max_width,
279 }
280 }
281
282 pub fn scaled(max_width: usize) -> WidthHeuristics {
284 const DEFAULT_MAX_WIDTH: usize = 100;
285 let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
286 let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
287 (ratio * 10.0).round() / 10.0
289 } else {
290 1.0
291 };
292 WidthHeuristics {
293 fn_call_width: (60.0 * max_width_ratio).round() as usize,
294 attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
295 struct_lit_width: (18.0 * max_width_ratio).round() as usize,
296 struct_variant_width: (35.0 * max_width_ratio).round() as usize,
297 array_width: (60.0 * max_width_ratio).round() as usize,
298 chain_width: (60.0 * max_width_ratio).round() as usize,
299 single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
300 single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
301 }
302 }
303}
304
305impl ::std::str::FromStr for WidthHeuristics {
306 type Err = &'static str;
307
308 fn from_str(_: &str) -> Result<Self, Self::Err> {
309 Err("WidthHeuristics is not parsable")
310 }
311}
312
313impl Default for EmitMode {
314 fn default() -> EmitMode {
315 EmitMode::Files
316 }
317}
318
319#[derive(Default, Clone, Debug, PartialEq)]
321pub struct IgnoreList {
322 path_set: HashSet<PathBuf>,
324 rustfmt_toml_path: PathBuf,
326}
327
328impl fmt::Display for IgnoreList {
329 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
330 write!(
331 f,
332 "[{}]",
333 self.path_set
334 .iter()
335 .format_with(", ", |path, f| f(&format_args!(
336 "{}",
337 path.to_string_lossy()
338 )))
339 )
340 }
341}
342
343impl Serialize for IgnoreList {
344 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
345 where
346 S: Serializer,
347 {
348 let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
349 for e in &self.path_set {
350 seq.serialize_element(e)?;
351 }
352 seq.end()
353 }
354}
355
356impl<'de> Deserialize<'de> for IgnoreList {
357 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
358 where
359 D: Deserializer<'de>,
360 {
361 struct HashSetVisitor;
362 impl<'v> Visitor<'v> for HashSetVisitor {
363 type Value = HashSet<PathBuf>;
364
365 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
366 formatter.write_str("a sequence of path")
367 }
368
369 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
370 where
371 A: SeqAccess<'v>,
372 {
373 let mut path_set = HashSet::new();
374 while let Some(elem) = seq.next_element()? {
375 path_set.insert(elem);
376 }
377 Ok(path_set)
378 }
379 }
380 Ok(IgnoreList {
381 path_set: deserializer.deserialize_seq(HashSetVisitor)?,
382 rustfmt_toml_path: PathBuf::new(),
383 })
384 }
385}
386
387impl<'a> IntoIterator for &'a IgnoreList {
388 type Item = &'a PathBuf;
389 type IntoIter = hash_set::Iter<'a, PathBuf>;
390
391 fn into_iter(self) -> Self::IntoIter {
392 self.path_set.iter()
393 }
394}
395
396impl IgnoreList {
397 pub fn add_prefix(&mut self, dir: &Path) {
398 self.rustfmt_toml_path = dir.to_path_buf();
399 }
400
401 pub fn rustfmt_toml_path(&self) -> &Path {
402 &self.rustfmt_toml_path
403 }
404}
405
406impl FromStr for IgnoreList {
407 type Err = &'static str;
408
409 fn from_str(_: &str) -> Result<Self, Self::Err> {
410 Err("IgnoreList is not parsable")
411 }
412}
413
414pub trait CliOptions {
417 fn apply_to(self, config: &mut Config);
418
419 fn config_path(&self) -> Option<&Path>;
422 fn edition(&self) -> Option<Edition>;
423 fn style_edition(&self) -> Option<StyleEdition>;
424 fn version(&self) -> Option<Version>;
425}
426
427#[config_type]
429pub enum Edition {
430 #[value = "2015"]
431 #[doc_hint = "2015"]
432 Edition2015,
434 #[value = "2018"]
435 #[doc_hint = "2018"]
436 Edition2018,
438 #[value = "2021"]
439 #[doc_hint = "2021"]
440 Edition2021,
442 #[value = "2024"]
443 #[doc_hint = "2024"]
444 Edition2024,
446}
447
448impl Default for Edition {
449 fn default() -> Edition {
450 Edition::Edition2015
451 }
452}
453
454impl From<Edition> for rustc_span::edition::Edition {
455 fn from(edition: Edition) -> Self {
456 match edition {
457 Edition::Edition2015 => Self::Edition2015,
458 Edition::Edition2018 => Self::Edition2018,
459 Edition::Edition2021 => Self::Edition2021,
460 Edition::Edition2024 => Self::Edition2024,
461 }
462 }
463}
464
465impl From<Edition> for StyleEdition {
466 fn from(edition: Edition) -> Self {
467 match edition {
468 Edition::Edition2015 => StyleEdition::Edition2015,
469 Edition::Edition2018 => StyleEdition::Edition2018,
470 Edition::Edition2021 => StyleEdition::Edition2021,
471 Edition::Edition2024 => StyleEdition::Edition2024,
472 }
473 }
474}
475
476impl PartialOrd for Edition {
477 fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
478 rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
479 }
480}
481
482#[config_type]
484pub enum MatchArmLeadingPipe {
485 Always,
487 Never,
489 Preserve,
491}
492
493#[config_type]
499pub enum StyleEdition {
500 #[value = "2015"]
501 #[doc_hint = "2015"]
502 Edition2015,
504 #[value = "2018"]
505 #[doc_hint = "2018"]
506 Edition2018,
508 #[value = "2021"]
509 #[doc_hint = "2021"]
510 Edition2021,
512 #[value = "2024"]
513 #[doc_hint = "2024"]
514 Edition2024,
516}
517
518impl From<StyleEdition> for rustc_span::edition::Edition {
519 fn from(edition: StyleEdition) -> Self {
520 match edition {
521 StyleEdition::Edition2015 => Self::Edition2015,
522 StyleEdition::Edition2018 => Self::Edition2018,
523 StyleEdition::Edition2021 => Self::Edition2021,
524 StyleEdition::Edition2024 => Self::Edition2024,
525 }
526 }
527}
528
529impl PartialOrd for StyleEdition {
530 fn partial_cmp(&self, other: &StyleEdition) -> Option<std::cmp::Ordering> {
531 rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
532 }
533}
534
535#[macro_export]
537macro_rules! config_option_with_style_edition_default {
538 ($name:ident, $config_ty:ty, _ => $default:expr) => {
539 #[allow(unreachable_pub)]
540 pub struct $name;
541 $crate::style_edition_default!($name, $config_ty, _ => $default);
542 };
543 ($name:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => {
544 pub struct $name;
545 $crate::style_edition_default!(
546 $name,
547 $config_ty,
548 Edition2024 => $default_2024,
549 _ => $default_2015
550 );
551 };
552 (
553 $($name:ident, $config_ty:ty, $(Edition2024 => $default_2024:expr,)? _ => $default:expr);*
554 $(;)*
555 ) => {
556 $(
557 config_option_with_style_edition_default!(
558 $name, $config_ty, $(Edition2024 => $default_2024,)? _ => $default
559 );
560 )*
561 };
562}
563
564config_option_with_style_edition_default!(
569 MaxWidth, usize, _ => 100;
571 HardTabs, bool, _ => false;
572 TabSpaces, usize, _ => 4;
573 NewlineStyleConfig, NewlineStyle, _ => NewlineStyle::Auto;
574 IndentStyleConfig, IndentStyle, _ => IndentStyle::Block;
575
576 UseSmallHeuristics, Heuristics, _ => Heuristics::Default;
578 WidthHeuristicsConfig, WidthHeuristics, _ => WidthHeuristics::scaled(100);
579 FnCallWidth, usize, _ => 60;
580 AttrFnLikeWidth, usize, _ => 70;
581 StructLitWidth, usize, _ => 18;
582 StructVariantWidth, usize, _ => 35;
583 ArrayWidth, usize, _ => 60;
584 ChainWidth, usize, _ => 60;
585 SingleLineIfElseMaxWidth, usize, _ => 50;
586 SingleLineLetElseMaxWidth, usize, _ => 50;
587
588 WrapComments, bool, _ => false;
590 FormatCodeInDocComments, bool, _ => false;
591 DocCommentCodeBlockWidth, usize, _ => 100;
592 CommentWidth, usize, _ => 80;
593 NormalizeComments, bool, _ => false;
594 NormalizeDocAttributes, bool, _ => false;
595 FormatStrings, bool, _ => false;
596 FormatMacroMatchers, bool, _ => false;
597 FormatMacroBodies, bool, _ => true;
598 SkipMacroInvocations, MacroSelectors, _ => MacroSelectors::default();
599 HexLiteralCaseConfig, HexLiteralCase, _ => HexLiteralCase::Preserve;
600
601 EmptyItemSingleLine, bool, _ => true;
603 StructLitSingleLine, bool, _ => true;
604 FnSingleLine, bool, _ => false;
605 WhereSingleLine, bool, _ => false;
606
607 ImportsIndent, IndentStyle, _ => IndentStyle::Block;
609 ImportsLayout, ListTactic, _ => ListTactic::Mixed;
610 ImportsGranularityConfig, ImportGranularity, _ => ImportGranularity::Preserve;
611 GroupImportsTacticConfig, GroupImportsTactic, _ => GroupImportsTactic::Preserve;
612 MergeImports, bool, _ => false;
613
614 ReorderImports, bool, _ => true;
616 ReorderModules, bool, _ => true;
617 ReorderImplItems, bool, _ => false;
618
619 TypePunctuationDensity, TypeDensity, _ => TypeDensity::Wide;
621 SpaceBeforeColon, bool, _ => false;
622 SpaceAfterColon, bool, _ => true;
623 SpacesAroundRanges, bool, _ => false;
624 BinopSeparator, SeparatorPlace, _ => SeparatorPlace::Front;
625
626 RemoveNestedParens, bool, _ => true;
628 CombineControlExpr, bool, _ => true;
629 ShortArrayElementWidthThreshold, usize, _ => 10;
630 OverflowDelimitedExpr, bool, _ => false;
631 StructFieldAlignThreshold, usize, _ => 0;
632 EnumDiscrimAlignThreshold, usize, _ => 0;
633 MatchArmBlocks, bool, _ => true;
634 MatchArmLeadingPipeConfig, MatchArmLeadingPipe, _ => MatchArmLeadingPipe::Never;
635 ForceMultilineBlocks, bool, _ => false;
636 FnArgsLayout, Density, _ => Density::Tall;
637 FnParamsLayout, Density, _ => Density::Tall;
638 BraceStyleConfig, BraceStyle, _ => BraceStyle::SameLineWhere;
639 ControlBraceStyleConfig, ControlBraceStyle, _ => ControlBraceStyle::AlwaysSameLine;
640 TrailingSemicolon, bool, _ => true;
641 TrailingComma, SeparatorTactic, _ => SeparatorTactic::Vertical;
642 MatchBlockTrailingComma, bool, _ => false;
643 BlankLinesUpperBound, usize, _ => 1;
644 BlankLinesLowerBound, usize, _ => 0;
645 EditionConfig, Edition, _ => Edition::Edition2015;
646 StyleEditionConfig, StyleEdition,
647 Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
648 VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One;
649 InlineAttributeWidth, usize, _ => 0;
650 FormatGeneratedFiles, bool, _ => true;
651 GeneratedMarkerLineSearchLimit, usize, _ => 5;
652
653 MergeDerives, bool, _ => true;
655 UseTryShorthand, bool, _ => false;
656 UseFieldInitShorthand, bool, _ => false;
657 ForceExplicitAbi, bool, _ => true;
658 CondenseWildcardSuffixes, bool, _ => false;
659
660 ColorConfig, Color, _ => Color::Auto;
662 RequiredVersion, String, _ => env!("CARGO_PKG_VERSION").to_owned();
663 UnstableFeatures, bool, _ => false;
664 DisableAllFormatting, bool, _ => false;
665 SkipChildren, bool, _ => false;
666 HideParseErrors, bool, _ => false;
667 ShowParseErrors, bool, _ => true;
668 ErrorOnLineOverflow, bool, _ => false;
669 ErrorOnUnformatted, bool, _ => false;
670 Ignore, IgnoreList, _ => IgnoreList::default();
671
672 Verbose, Verbosity, _ => Verbosity::Normal;
674 FileLinesConfig, FileLines, _ => FileLines::all();
675 EmitModeConfig, EmitMode, _ => EmitMode::Files;
676 MakeBackup, bool, _ => false;
677 PrintMisformattedFileNames, bool, _ => false;
678);