1 use std::collections::{hash_set, HashSet};
3 use std::path::{Path, PathBuf};
5 use itertools::Itertools;
6 use rustfmt_config_proc_macro::config_type;
7 use serde::de::{SeqAccess, Visitor};
8 use serde::ser::SerializeSeq;
9 use serde::{Deserialize, Deserializer, Serialize, Serializer};
11 use crate::config::lists::*;
12 use crate::config::Config;
15 pub enum NewlineStyle {
16 /// Auto-detect based on the raw source input.
18 /// Force CRLF (`\r\n`).
22 /// `\r\n` in Windows, `\n`` on other platforms.
27 /// Where to put the opening brace of items (`fn`, `impl`, etc.).
29 /// Put the opening brace on the next line.
31 /// Put the opening brace on the same line, if possible.
33 /// Prefer the same line except where there is a where-clause, in which
34 /// case force the brace to be put on the next line.
39 /// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
40 pub enum ControlBraceStyle {
41 /// K&R style, Rust community default
51 pub enum IndentStyle {
52 /// First line on the same line as the opening brace, all lines aligned with
55 /// First line is on a new line and all lines align with **block** indent.
60 /// How to place a list-like items.
61 /// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
63 /// Fit as much on one line as possible.
65 /// Items are placed horizontally if sufficient space, vertically otherwise.
67 /// Place every item on a separate line.
72 /// Spacing around type combinators.
73 pub enum TypeDensity {
74 /// No spaces around "=" and "+"
76 /// Spaces around " = " and " + "
81 /// To what extent does rustfmt pursue its heuristics?
83 /// Turn off any heuristics
85 /// Turn on max heuristics
87 /// Use Rustfmt's defaults
92 pub fn to_list_tactic(self, len: usize) -> ListTactic {
94 Density::Compressed => ListTactic::Mixed,
95 Density::Tall => ListTactic::HorizontalVertical,
96 Density::Vertical if len == 1 => ListTactic::Horizontal,
97 Density::Vertical => ListTactic::Vertical,
103 pub enum ReportTactic {
109 /// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
115 /// Writes the output to stdout.
117 /// Displays how much of the input file was processed
121 /// Writes the resulting diffs in a JSON format. Returns an empty array
122 /// `[]` if there were no diffs.
124 /// Output the changed lines (for internal value only)
126 /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
127 /// quits with exit code 1.
128 /// This option is designed to be run in CI where a non-zero exit signifies
129 /// non-standard code formatting. Used for `--check`.
133 /// Client-preference for coloured output.
136 /// Always use color, whether it is a piped or terminal output
140 /// Automatically use color, if supported by terminal
145 /// rustfmt format style version.
147 /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
149 /// 2.x.y. When specified, rustfmt will format in the the latest style.
154 /// Whether we should use a coloured terminal.
155 pub fn use_colored_tty(self) -> bool {
157 Color::Always | Color::Auto => true,
158 Color::Never => false,
163 /// How chatty should Rustfmt be?
170 /// Emit as little as possible.
174 #[derive(Deserialize, Serialize, Clone, Debug, PartialEq)]
175 pub struct WidthHeuristics {
176 // Maximum width of the args of a function call before falling back
177 // to vertical formatting.
178 pub fn_call_width: usize,
179 // Maximum width of the args of a function-like attributes before falling
180 // back to vertical formatting.
181 pub attr_fn_like_width: usize,
182 // Maximum width in the body of a struct lit before falling back to
183 // vertical formatting.
184 pub struct_lit_width: usize,
185 // Maximum width in the body of a struct variant before falling back
186 // to vertical formatting.
187 pub struct_variant_width: usize,
188 // Maximum width of an array literal before falling back to vertical
190 pub array_width: usize,
191 // Maximum length of a chain to fit on a single line.
192 pub chain_width: usize,
193 // Maximum line length for single line if-else expressions. A value
194 // of zero means always break if-else expressions.
195 pub single_line_if_else_max_width: usize,
198 impl fmt::Display for WidthHeuristics {
199 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
200 write!(f, "{:?}", self)
204 impl WidthHeuristics {
205 // Using this WidthHeuristics means we ignore heuristics.
206 pub fn null() -> WidthHeuristics {
208 fn_call_width: usize::max_value(),
209 attr_fn_like_width: usize::max_value(),
211 struct_variant_width: 0,
212 array_width: usize::max_value(),
213 chain_width: usize::max_value(),
214 single_line_if_else_max_width: 0,
218 pub fn set(max_width: usize) -> WidthHeuristics {
220 fn_call_width: max_width,
221 attr_fn_like_width: max_width,
222 struct_lit_width: max_width,
223 struct_variant_width: max_width,
224 array_width: max_width,
225 chain_width: max_width,
226 single_line_if_else_max_width: max_width,
230 // scale the default WidthHeuristics according to max_width
231 pub fn scaled(max_width: usize) -> WidthHeuristics {
232 const DEFAULT_MAX_WIDTH: usize = 100;
233 let max_width_ratio = if max_width > DEFAULT_MAX_WIDTH {
234 let ratio = max_width as f32 / DEFAULT_MAX_WIDTH as f32;
235 // round to the closest 0.1
236 (ratio * 10.0).round() / 10.0
241 fn_call_width: (60.0 * max_width_ratio).round() as usize,
242 attr_fn_like_width: (70.0 * max_width_ratio).round() as usize,
243 struct_lit_width: (18.0 * max_width_ratio).round() as usize,
244 struct_variant_width: (35.0 * max_width_ratio).round() as usize,
245 array_width: (60.0 * max_width_ratio).round() as usize,
246 chain_width: (60.0 * max_width_ratio).round() as usize,
247 single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
252 impl ::std::str::FromStr for WidthHeuristics {
253 type Err = &'static str;
255 fn from_str(_: &str) -> Result<Self, Self::Err> {
256 Err("WidthHeuristics is not parsable")
260 impl Default for EmitMode {
261 fn default() -> EmitMode {
266 /// A set of directories, files and modules that rustfmt should ignore.
267 #[derive(Default, Clone, Debug, PartialEq)]
268 pub struct IgnoreList {
269 /// A set of path specified in rustfmt.toml.
270 path_set: HashSet<PathBuf>,
271 /// A path to rustfmt.toml.
272 rustfmt_toml_path: PathBuf,
275 impl fmt::Display for IgnoreList {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
282 .format_with(", ", |path, f| f(&format_args!(
284 path.to_string_lossy()
290 impl Serialize for IgnoreList {
291 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
295 let mut seq = serializer.serialize_seq(Some(self.path_set.len()))?;
296 for e in &self.path_set {
297 seq.serialize_element(e)?;
303 impl<'de> Deserialize<'de> for IgnoreList {
304 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
306 D: Deserializer<'de>,
308 struct HashSetVisitor;
309 impl<'v> Visitor<'v> for HashSetVisitor {
310 type Value = HashSet<PathBuf>;
312 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
313 formatter.write_str("a sequence of path")
316 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
320 let mut path_set = HashSet::new();
321 while let Some(elem) = seq.next_element()? {
322 path_set.insert(elem);
328 path_set: deserializer.deserialize_seq(HashSetVisitor)?,
329 rustfmt_toml_path: PathBuf::new(),
334 impl<'a> IntoIterator for &'a IgnoreList {
335 type Item = &'a PathBuf;
336 type IntoIter = hash_set::Iter<'a, PathBuf>;
338 fn into_iter(self) -> Self::IntoIter {
344 pub fn add_prefix(&mut self, dir: &Path) {
345 self.rustfmt_toml_path = dir.to_path_buf();
348 pub fn rustfmt_toml_path(&self) -> &Path {
349 &self.rustfmt_toml_path
353 impl ::std::str::FromStr for IgnoreList {
354 type Err = &'static str;
356 fn from_str(_: &str) -> Result<Self, Self::Err> {
357 Err("IgnoreList is not parsable")
361 /// Maps client-supplied options to Rustfmt's internals, mostly overriding
362 /// values in a config with values from the command line.
363 pub trait CliOptions {
364 fn apply_to(self, config: &mut Config);
365 fn config_path(&self) -> Option<&Path>;
368 /// The edition of the syntax and semntics of code (RFC 2052).
381 impl Default for Edition {
382 fn default() -> Edition {
388 pub(crate) fn to_libsyntax_pos_edition(self) -> syntax_pos::edition::Edition {
390 Edition::Edition2015 => syntax_pos::edition::Edition::Edition2015,
391 Edition::Edition2018 => syntax_pos::edition::Edition::Edition2018,