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 itertools::Itertools;
+use rustfmt_config_proc_macro::config_type;
use serde::de::{SeqAccess, Visitor};
-use serde::{Deserialize, Deserializer, Serialize};
+use serde::ser::SerializeSeq;
+use serde::{Deserialize, Deserializer, Serialize, Serializer};
use crate::config::lists::*;
use crate::config::Config;
Native,
}
-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"),
- }
- }
-}
-
#[config_type]
/// Where to put the opening brace of items (`fn`, `impl`, etc.).
pub enum BraceStyle {
#[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.
Compressed,
- /// Use more lines.
+ /// Items are placed horizontally if sufficient space, vertically otherwise.
Tall,
/// Place every item on a separate line.
Vertical,
}
}
+#[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,
Coverage,
/// Unfancy stdout
Checkstyle,
+ /// 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
pub enum Version {
/// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0.
One,
- /// 2.x.y. When specified, rustfmt will formatin the the latest style.
+ /// 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),
}
}
}
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> {
#[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,
}