use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
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::lists::*;
use crate::config::Config;
#[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 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 fn_call_width: usize,
pub attr_fn_like_width: usize,
pub struct_lit_width: usize,
pub struct_variant_width: usize,
pub array_width: usize,
pub chain_width: usize,
pub single_line_if_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_value(),
attr_fn_like_width: usize::max_value(),
struct_lit_width: 0,
struct_variant_width: 0,
array_width: usize::max_value(),
chain_width: usize::max_value(),
single_line_if_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,
}
}
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,
}
}
}
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 ::std::str::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>;
}
#[config_type]
pub enum Edition {
#[value = "2015"]
#[doc_hint = "2015"]
Edition2015,
#[value = "2018"]
#[doc_hint = "2018"]
Edition2018,
}
impl Default for Edition {
fn default() -> Edition {
Edition::Edition2015
}
}
impl Edition {
pub(crate) fn to_libsyntax_pos_edition(self) -> rustc_span::edition::Edition {
match self {
Edition::Edition2015 => rustc_span::edition::Edition::Edition2015,
Edition::Edition2018 => rustc_span::edition::Edition::Edition2018,
}
}
}