#![allow(unused_imports)]
use std::collections::{HashSet, hash_set};
use std::fmt;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use itertools::Itertools;
use rustfmt_config_proc_macro::config_type;
use serde::de::{SeqAccess, Visitor};
use serde::ser::SerializeSeq;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::config::Config;
use crate::config::file_lines::FileLines;
use crate::config::lists::*;
use crate::config::macro_names::MacroSelectors;
#[config_type]
pub enum NewlineStyle {
Auto,
Windows,
Unix,
Native,
}
#[config_type]
pub enum BraceStyle {
AlwaysNextLine,
PreferSameLine,
SameLineWhere,
}
#[config_type]
pub enum ControlBraceStyle {
AlwaysSameLine,
ClosingNextLine,
AlwaysNextLine,
}
#[config_type]
pub enum IndentStyle {
Visual,
Block,
}
#[config_type]
pub enum Density {
Compressed,
Tall,
Vertical,
}
#[config_type]
pub enum TypeDensity {
Compressed,
Wide,
}
#[config_type]
pub enum Heuristics {
Off,
Max,
Default,
}
impl Density {
pub fn to_list_tactic(self, len: usize) -> ListTactic {
match self {
Density::Compressed => ListTactic::Mixed,
Density::Tall => ListTactic::HorizontalVertical,
Density::Vertical if len == 1 => ListTactic::Horizontal,
Density::Vertical => ListTactic::Vertical,
}
}
}
#[config_type]
pub enum GroupImportsTactic {
Preserve,
StdExternalCrate,
One,
}
#[config_type]
pub enum ImportGranularity {
Preserve,
Crate,
Module,
Item,
One,
}
#[config_type]
pub enum HexLiteralCase {
Preserve,
Upper,
Lower,
}
#[config_type]
pub enum ReportTactic {
Always,
Unnumbered,
Never,
}
#[config_type]
pub enum EmitMode {
Files,
Stdout,
Coverage,
Checkstyle,
Json,
ModifiedLines,
Diff,
}
#[config_type]
pub enum Color {
Always,
Never,
Auto,
}
#[config_type]
pub enum Version {
One,
Two,
}
impl Color {
pub fn use_colored_tty(self) -> bool {
match self {
Color::Always | Color::Auto => true,
Color::Never => false,
}
}
}
#[config_type]
pub enum Verbosity {
Verbose,
Normal,
Quiet,
}
#[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
pub struct WidthHeuristics {
pub(crate) fn_call_width: usize,
pub(crate) attr_fn_like_width: usize,
pub(crate) struct_lit_width: usize,
pub(crate) struct_variant_width: usize,
pub(crate) array_width: usize,
pub(crate) chain_width: usize,
pub(crate) single_line_if_else_max_width: usize,
pub(crate) single_line_let_else_max_width: usize,
}
impl fmt::Display for WidthHeuristics {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{self:?}")
}
}
impl WidthHeuristics {
pub fn null() -> WidthHeuristics {
WidthHeuristics {
fn_call_width: usize::MAX,
attr_fn_like_width: usize::MAX,
struct_lit_width: 0,
struct_variant_width: 0,
array_width: usize::MAX,
chain_width: usize::MAX,
single_line_if_else_max_width: 0,
single_line_let_else_max_width: 0,
}
}
pub fn set(max_width: usize) -> WidthHeuristics {
WidthHeuristics {
fn_call_width: max_width,
attr_fn_like_width: max_width,
struct_lit_width: max_width,
struct_variant_width: max_width,
array_width: max_width,
chain_width: max_width,
single_line_if_else_max_width: max_width,
single_line_let_else_max_width: max_width,
}
}
pub fn scaled(max_width: usize) -> WidthHeuristics {
const DEFAULT_MAX_WIDTH: usize = 100;
let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
(ratio * 10.0).round() / 10.0
} else {
1.0
};
WidthHeuristics {
fn_call_width: (60.0 * max_width_ratio).round() as usize,
attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
struct_lit_width: (18.0 * max_width_ratio).round() as usize,
struct_variant_width: (35.0 * max_width_ratio).round() as usize,
array_width: (60.0 * max_width_ratio).round() as usize,
chain_width: (60.0 * max_width_ratio).round() as usize,
single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
}
}
}
impl ::std::str::FromStr for WidthHeuristics {
type Err = &'static str;
fn from_str(_: &str) -> Result<Self, Self::Err> {
Err("WidthHeuristics is not parsable")
}
}
impl Default for EmitMode {
fn default() -> EmitMode {
EmitMode::Files
}
}
#[derive(Default, Clone, Debug, PartialEq)]
pub struct IgnoreList {
path_set: HashSet<PathBuf>,
rustfmt_toml_path: PathBuf,
}
impl fmt::Display for IgnoreList {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
f,
"[{}]",
self.path_set
.iter()
.format_with(", ", |path, f| f(&format_args!(
"{}",
path.to_string_lossy()
)))
)
}
}
impl Serialize for IgnoreList {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
for e in &self.path_set {
seq.serialize_element(e)?;
}
seq.end()
}
}
impl<'de> Deserialize<'de> for IgnoreList {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct HashSetVisitor;
impl<'v> Visitor<'v> for HashSetVisitor {
type Value = HashSet<PathBuf>;
fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str("a sequence of path")
}
fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
where
A: SeqAccess<'v>,
{
let mut path_set = HashSet::new();
while let Some(elem) = seq.next_element()? {
path_set.insert(elem);
}
Ok(path_set)
}
}
Ok(IgnoreList {
path_set: deserializer.deserialize_seq(HashSetVisitor)?,
rustfmt_toml_path: PathBuf::new(),
})
}
}
impl<'a> IntoIterator for &'a IgnoreList {
type Item = &'a PathBuf;
type IntoIter = hash_set::Iter<'a, PathBuf>;
fn into_iter(self) -> Self::IntoIter {
self.path_set.iter()
}
}
impl IgnoreList {
pub fn add_prefix(&mut self, dir: &Path) {
self.rustfmt_toml_path = dir.to_path_buf();
}
pub fn rustfmt_toml_path(&self) -> &Path {
&self.rustfmt_toml_path
}
}
impl FromStr for IgnoreList {
type Err = &'static str;
fn from_str(_: &str) -> Result<Self, Self::Err> {
Err("IgnoreList is not parsable")
}
}
pub trait CliOptions {
fn apply_to(self, config: &mut Config);
fn config_path(&self) -> Option<&Path>;
fn edition(&self) -> Option<Edition>;
fn style_edition(&self) -> Option<StyleEdition>;
fn version(&self) -> Option<Version>;
}
#[config_type]
pub enum Edition {
#[value = "2015"]
#[doc_hint = "2015"]
Edition2015,
#[value = "2018"]
#[doc_hint = "2018"]
Edition2018,
#[value = "2021"]
#[doc_hint = "2021"]
Edition2021,
#[value = "2024"]
#[doc_hint = "2024"]
Edition2024,
}
impl Default for Edition {
fn default() -> Edition {
Edition::Edition2015
}
}
impl From<Edition> for rustc_span::edition::Edition {
fn from(edition: Edition) -> Self {
match edition {
Edition::Edition2015 => Self::Edition2015,
Edition::Edition2018 => Self::Edition2018,
Edition::Edition2021 => Self::Edition2021,
Edition::Edition2024 => Self::Edition2024,
}
}
}
impl From<Edition> for StyleEdition {
fn from(edition: Edition) -> Self {
match edition {
Edition::Edition2015 => StyleEdition::Edition2015,
Edition::Edition2018 => StyleEdition::Edition2018,
Edition::Edition2021 => StyleEdition::Edition2021,
Edition::Edition2024 => StyleEdition::Edition2024,
}
}
}
impl PartialOrd for Edition {
fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
}
}
#[config_type]
pub enum MatchArmLeadingPipe {
Always,
Never,
Preserve,
}
#[config_type]
pub enum StyleEdition {
#[value = "2015"]
#[doc_hint = "2015"]
Edition2015,
#[value = "2018"]
#[doc_hint = "2018"]
Edition2018,
#[value = "2021"]
#[doc_hint = "2021"]
Edition2021,
#[value = "2024"]
#[doc_hint = "2024"]
#[unstable_variant]
Edition2024,
}
impl From<StyleEdition> for rustc_span::edition::Edition {
fn from(edition: StyleEdition) -> Self {
match edition {
StyleEdition::Edition2015 => Self::Edition2015,
StyleEdition::Edition2018 => Self::Edition2018,
StyleEdition::Edition2021 => Self::Edition2021,
StyleEdition::Edition2024 => Self::Edition2024,
}
}
}
impl PartialOrd for StyleEdition {
fn partial_cmp(&self, other: &StyleEdition) -> Option<std::cmp::Ordering> {
rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
}
}
#[macro_export]
macro_rules! config_option_with_style_edition_default {
($name:ident, $config_ty:ty, _ => $default:expr) => {
#[allow(unreachable_pub)]
pub struct $name;
$crate::style_edition_default!($name, $config_ty, _ => $default);
};
($name:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => {
pub struct $name;
$crate::style_edition_default!(
$name,
$config_ty,
Edition2024 => $default_2024,
_ => $default_2015
);
};
(
$($name:ident, $config_ty:ty, $(Edition2024 => $default_2024:expr,)? _ => $default:expr);*
$(;)*
) => {
$(
config_option_with_style_edition_default!(
$name, $config_ty, $(Edition2024 => $default_2024,)? _ => $default
);
)*
};
}
config_option_with_style_edition_default!(
MaxWidth, usize, _ => 100;
HardTabs, bool, _ => false;
TabSpaces, usize, _ => 4;
NewlineStyleConfig, NewlineStyle, _ => NewlineStyle::Auto;
IndentStyleConfig, IndentStyle, _ => IndentStyle::Block;
UseSmallHeuristics, Heuristics, _ => Heuristics::Default;
WidthHeuristicsConfig, WidthHeuristics, _ => WidthHeuristics::scaled(100);
FnCallWidth, usize, _ => 60;
AttrFnLikeWidth, usize, _ => 70;
StructLitWidth, usize, _ => 18;
StructVariantWidth, usize, _ => 35;
ArrayWidth, usize, _ => 60;
ChainWidth, usize, _ => 60;
SingleLineIfElseMaxWidth, usize, _ => 50;
SingleLineLetElseMaxWidth, usize, _ => 50;
WrapComments, bool, _ => false;
FormatCodeInDocComments, bool, _ => false;
DocCommentCodeBlockWidth, usize, _ => 100;
CommentWidth, usize, _ => 80;
NormalizeComments, bool, _ => false;
NormalizeDocAttributes, bool, _ => false;
FormatStrings, bool, _ => false;
FormatMacroMatchers, bool, _ => false;
FormatMacroBodies, bool, _ => true;
SkipMacroInvocations, MacroSelectors, _ => MacroSelectors::default();
HexLiteralCaseConfig, HexLiteralCase, _ => HexLiteralCase::Preserve;
EmptyItemSingleLine, bool, _ => true;
StructLitSingleLine, bool, _ => true;
FnSingleLine, bool, _ => false;
WhereSingleLine, bool, _ => false;
ImportsIndent, IndentStyle, _ => IndentStyle::Block;
ImportsLayout, ListTactic, _ => ListTactic::Mixed;
ImportsGranularityConfig, ImportGranularity, _ => ImportGranularity::Preserve;
GroupImportsTacticConfig, GroupImportsTactic, _ => GroupImportsTactic::Preserve;
MergeImports, bool, _ => false;
ReorderImports, bool, _ => true;
ReorderModules, bool, _ => true;
ReorderImplItems, bool, _ => false;
TypePunctuationDensity, TypeDensity, _ => TypeDensity::Wide;
SpaceBeforeColon, bool, _ => false;
SpaceAfterColon, bool, _ => true;
SpacesAroundRanges, bool, _ => false;
BinopSeparator, SeparatorPlace, _ => SeparatorPlace::Front;
RemoveNestedParens, bool, _ => true;
CombineControlExpr, bool, _ => true;
ShortArrayElementWidthThreshold, usize, _ => 10;
OverflowDelimitedExpr, bool, Edition2024 => true, _ => false;
StructFieldAlignThreshold, usize, _ => 0;
EnumDiscrimAlignThreshold, usize, _ => 0;
MatchArmBlocks, bool, _ => true;
MatchArmLeadingPipeConfig, MatchArmLeadingPipe, _ => MatchArmLeadingPipe::Never;
ForceMultilineBlocks, bool, _ => false;
FnArgsLayout, Density, _ => Density::Tall;
FnParamsLayout, Density, _ => Density::Tall;
BraceStyleConfig, BraceStyle, _ => BraceStyle::SameLineWhere;
ControlBraceStyleConfig, ControlBraceStyle, _ => ControlBraceStyle::AlwaysSameLine;
TrailingSemicolon, bool, _ => true;
TrailingComma, SeparatorTactic, _ => SeparatorTactic::Vertical;
MatchBlockTrailingComma, bool, _ => false;
BlankLinesUpperBound, usize, _ => 1;
BlankLinesLowerBound, usize, _ => 0;
EditionConfig, Edition, _ => Edition::Edition2015;
StyleEditionConfig, StyleEdition,
Edition2024 => StyleEdition::Edition2024, _ => StyleEdition::Edition2015;
VersionConfig, Version, Edition2024 => Version::Two, _ => Version::One;
InlineAttributeWidth, usize, _ => 0;
FormatGeneratedFiles, bool, _ => true;
GeneratedMarkerLineSearchLimit, usize, _ => 5;
MergeDerives, bool, _ => true;
UseTryShorthand, bool, _ => false;
UseFieldInitShorthand, bool, _ => false;
ForceExplicitAbi, bool, _ => true;
CondenseWildcardSuffixes, bool, _ => false;
ColorConfig, Color, _ => Color::Auto;
RequiredVersion, String, _ => env!("CARGO_PKG_VERSION").to_owned();
UnstableFeatures, bool, _ => false;
DisableAllFormatting, bool, _ => false;
SkipChildren, bool, _ => false;
HideParseErrors, bool, _ => false;
ShowParseErrors, bool, _ => true;
ErrorOnLineOverflow, bool, _ => false;
ErrorOnUnformatted, bool, _ => false;
Ignore, IgnoreList, _ => IgnoreList::default();
Verbose, Verbosity, _ => Verbosity::Normal;
FileLinesConfig, FileLines, _ => FileLines::all();
EmitModeConfig, EmitMode, _ => EmitMode::Files;
MakeBackup, bool, _ => false;
PrintMisformattedFileNames, bool, _ => false;
);