use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
+use std::str::FromStr;
-use atty;
-use config_proc_macro::config_type;
-use serde::de::{Deserialize, Deserializer, SeqAccess, Visitor};
+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, // Auto-detect based on the raw source input
- Windows, // \r\n
- Unix, // \n
- Native, // \r\n in Windows, \n on other platforms
-}
-
-impl NewlineStyle {
- fn auto_detect(raw_input_text: &str) -> NewlineStyle {
- if let Some(pos) = raw_input_text.find('\n') {
- let pos = pos.saturating_sub(1);
- if let Some('\r') = raw_input_text.chars().nth(pos) {
- NewlineStyle::Windows
- } else {
- NewlineStyle::Unix
- }
- } else {
- NewlineStyle::Native
- }
- }
-
- fn native() -> NewlineStyle {
- if cfg!(windows) {
- NewlineStyle::Windows
- } else {
- NewlineStyle::Unix
- }
- }
-
- /// Apply this newline style to the formatted text. When the style is set
- /// to `Auto`, the `raw_input_text` is used to detect the existing line
- /// endings.
- ///
- /// If the style is set to `Auto` and `raw_input_text` contains no
- /// newlines, the `Native` style will be used.
- pub(crate) fn apply(self, formatted_text: &mut String, raw_input_text: &str) {
- use crate::NewlineStyle::*;
- let mut style = self;
- if style == Auto {
- style = Self::auto_detect(raw_input_text);
- }
- if style == Native {
- style = Self::native();
- }
- match style {
- Windows => {
- let mut transformed = String::with_capacity(2 * formatted_text.capacity());
- for c in formatted_text.chars() {
- match c {
- '\n' => transformed.push_str("\r\n"),
- '\r' => continue,
- c => transformed.push(c),
- }
- }
- *formatted_text = transformed;
- }
- Unix => return,
- Native => unreachable!("NewlineStyle::Native"),
- Auto => unreachable!("NewlineStyle::Auto"),
- }
- }
+ /// Auto-detect based on the raw source input.
+ Auto,
+ /// Force CRLF (`\r\n`).
+ Windows,
+ /// Force CR (`\n).
+ Unix,
+ /// `\r\n` in Windows, `\n`` on other platforms.
+ Native,
}
#[config_type]
+/// Where to put the opening brace of items (`fn`, `impl`, etc.).
pub enum BraceStyle {
+ /// Put the opening brace on the next line.
AlwaysNextLine,
+ /// Put the opening brace on the same line, if possible.
PreferSameLine,
- // Prefer same line except where there is a where-clause, in which case force
- // the brace to the next line.
+ /// Prefer the same line except where there is a where-clause, in which
+ /// case force the brace to be put on the next line.
SameLineWhere,
}
#[config_type]
+/// Where to put the opening brace of conditional expressions (`if`, `match`, etc.).
pub enum ControlBraceStyle {
- // K&R style, Rust community default
+ /// K&R style, Rust community default
AlwaysSameLine,
- // Stroustrup style
+ /// Stroustrup style
ClosingNextLine,
- // Allman style
+ /// Allman style
AlwaysNextLine,
}
#[config_type]
+/// How to indent.
pub enum IndentStyle {
- // First line on the same line as the opening brace, all lines aligned with
- // the first line.
+ /// First line on the same line as the opening brace, all lines aligned with
+ /// the first line.
Visual,
- // First line is on a new line and all lines align with block indent.
+ /// First line is on a new line and all lines align with **block** indent.
Block,
}
#[config_type]
+/// How to place a list-like items.
+/// FIXME: Issue-3581: this should be renamed to ItemsLayout when publishing 2.0
pub enum Density {
- // Fit as much on one line as possible.
+ /// Fit as much on one line as possible.
Compressed,
- // Use more lines.
+ /// Items are placed horizontally if sufficient space, vertically otherwise.
Tall,
- // Place every item on a separate line.
+ /// Place every item on a separate line.
Vertical,
}
#[config_type]
+/// Spacing around type combinators.
pub enum TypeDensity {
- // No spaces around "=" and "+"
+ /// No spaces around "=" and "+"
Compressed,
- // Spaces around " = " and " + "
+ /// Spaces around " = " and " + "
Wide,
}
#[config_type]
+/// To what extent does rustfmt pursue its heuristics?
pub enum Heuristics {
- // Turn off any heuristics
+ /// Turn off any heuristics
Off,
- // Turn on max heuristics
+ /// Turn on max heuristics
Max,
- // Use Rustfmt's defaults
+ /// Use Rustfmt's defaults
Default,
}
}
}
+#[config_type]
+/// Configuration for import groups, i.e. sets of imports separated by newlines.
+pub enum GroupImportsTactic {
+ /// Keep groups as they are.
+ Preserve,
+ /// Discard existing groups, and create new groups for
+ /// 1. `std` / `core` / `alloc` imports
+ /// 2. other imports
+ /// 3. `self` / `crate` / `super` imports
+ StdExternalCrate,
+}
+
+#[config_type]
+/// How to merge imports.
+pub enum ImportGranularity {
+ /// Do not merge imports.
+ Preserve,
+ /// Use one `use` statement per crate.
+ Crate,
+ /// Use one `use` statement per module.
+ Module,
+ /// Use one `use` statement per imported item.
+ Item,
+}
+
#[config_type]
pub enum ReportTactic {
Always,
Never,
}
-// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
-// option.
+/// What Rustfmt should emit. Mostly corresponds to the `--emit` command line
+/// option.
#[config_type]
pub enum EmitMode {
- // Emits to files.
+ /// Emits to files.
Files,
- // Writes the output to stdout.
+ /// Writes the output to stdout.
Stdout,
- // Displays how much of the input file was processed
+ /// Displays how much of the input file was processed
Coverage,
- // Unfancy stdout
+ /// Unfancy stdout
Checkstyle,
- // Output the changed lines (for internal value only)
+ /// Writes the resulting diffs in a JSON format. Returns an empty array
+ /// `[]` if there were no diffs.
+ Json,
+ /// Output the changed lines (for internal value only)
ModifiedLines,
- // Checks if a diff can be generated. If so, rustfmt outputs a diff and quits with exit code 1.
- // This option is designed to be run in CI where a non-zero exit signifies non-standard code
- // formatting. Used for `--check`.
+ /// Checks if a diff can be generated. If so, rustfmt outputs a diff and
+ /// quits with exit code 1.
+ /// This option is designed to be run in CI where a non-zero exit signifies
+ /// non-standard code formatting. Used for `--check`.
Diff,
}
-// Client-preference for coloured output.
+/// Client-preference for coloured output.
#[config_type]
pub enum Color {
- // Always use color, whether it is a piped or terminal output
+ /// Always use color, whether it is a piped or terminal output
Always,
- // Never use color
+ /// Never use color
Never,
- // Automatically use color, if supported by terminal
+ /// Automatically use color, if supported by terminal
Auto,
}
#[config_type]
+/// rustfmt format style version.
pub enum Version {
- // 1.x.y
+ /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
One,
- // 2.x.y
+ /// 2.x.y. When specified, rustfmt will format in the the latest style.
Two,
}
/// Whether we should use a coloured terminal.
pub fn use_colored_tty(self) -> bool {
match self {
- Color::Always => true,
+ Color::Always | Color::Auto => true,
Color::Never => false,
- Color::Auto => atty::is(atty::Stream::Stdout),
}
}
}
-// How chatty should Rustfmt be?
+/// How chatty should Rustfmt be?
#[config_type]
pub enum Verbosity {
- // Emit more.
+ /// Emit more.
Verbose,
+ /// Default.
Normal,
- // Emit as little as possible.
+ /// Emit as little as possible.
Quiet,
}
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 {
// Using this WidthHeuristics means we ignore heuristics.
pub fn null() -> WidthHeuristics {
}
/// A set of directories, files and modules that rustfmt should ignore.
-#[derive(Default, Serialize, Clone, Debug, PartialEq)]
+#[derive(Default, Clone, Debug, PartialEq)]
pub struct IgnoreList {
/// A set of path specified in rustfmt.toml.
- #[serde(flatten)]
path_set: HashSet<PathBuf>,
/// A path to rustfmt.toml.
- #[serde(skip_serializing)]
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
}
}
-impl ::std::str::FromStr for IgnoreList {
+impl FromStr for IgnoreList {
type Err = &'static str;
fn from_str(_: &str) -> Result<Self, Self::Err> {
fn config_path(&self) -> Option<&Path>;
}
-// The edition of the compiler (RFC 2052)
+/// The edition of the syntax and semntics of code (RFC 2052).
#[config_type]
pub enum Edition {
#[value = "2015"]
#[doc_hint = "2015"]
+ /// Edition 2015.
Edition2015,
#[value = "2018"]
#[doc_hint = "2018"]
+ /// Edition 2018.
Edition2018,
+ #[value = "2021"]
+ #[doc_hint = "2021"]
+ /// Edition 2021.
+ Edition2021,
}
impl Default for Edition {
}
}
-impl Edition {
- pub(crate) fn to_libsyntax_pos_edition(self) -> syntax_pos::edition::Edition {
- match self {
- Edition::Edition2015 => syntax_pos::edition::Edition::Edition2015,
- Edition::Edition2018 => syntax_pos::edition::Edition::Edition2018,
+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,
}
}
}
-#[test]
-fn test_newline_style_auto_detect() {
- let lf = "One\nTwo\nThree";
- let crlf = "One\r\nTwo\r\nThree";
- let none = "One Two Three";
-
- assert_eq!(NewlineStyle::Unix, NewlineStyle::auto_detect(lf));
- assert_eq!(NewlineStyle::Windows, NewlineStyle::auto_detect(crlf));
- assert_eq!(NewlineStyle::Native, NewlineStyle::auto_detect(none));
-}
-
-#[test]
-fn test_newline_style_auto_apply() {
- let auto = NewlineStyle::Auto;
-
- let formatted_text = "One\nTwo\nThree";
- let raw_input_text = "One\nTwo\nThree";
-
- let mut out = String::from(formatted_text);
- auto.apply(&mut out, raw_input_text);
- assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
-
- let formatted_text = "One\nTwo\nThree";
- let raw_input_text = "One\r\nTwo\r\nThree";
-
- let mut out = String::from(formatted_text);
- auto.apply(&mut out, raw_input_text);
- assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
-
- #[cfg(not(windows))]
- {
- let formatted_text = "One\nTwo\nThree";
- let raw_input_text = "One Two Three";
-
- let mut out = String::from(formatted_text);
- auto.apply(&mut out, raw_input_text);
- assert_eq!(
- "One\nTwo\nThree", &out,
- "auto-native-unix should detect 'lf'"
- );
+impl PartialOrd for Edition {
+ fn partial_cmp(&self, other: &Edition) -> Option<std::cmp::Ordering> {
+ rustc_span::edition::Edition::partial_cmp(&(*self).into(), &(*other).into())
}
+}
- #[cfg(windows)]
- {
- let formatted_text = "One\nTwo\nThree";
- let raw_input_text = "One Two Three";
-
- let mut out = String::from(formatted_text);
- auto.apply(&mut out, raw_input_text);
- assert_eq!(
- "One\r\nTwo\r\nThree", &out,
- "auto-native-windows should detect 'crlf'"
- );
- }
+/// Controls how rustfmt should handle leading pipes on match arms.
+#[config_type]
+pub enum MatchArmLeadingPipe {
+ /// Place leading pipes on all match arms
+ Always,
+ /// Never emit leading pipes on match arms
+ Never,
+ /// Preserve any existing leading pipes
+ Preserve,
}