]> git.lizzy.rs Git - rust.git/blobdiff - src/config/options.rs
refactor: apply rustc mod parsing changes
[rust.git] / src / config / options.rs
index c927cffba291c92013d9254100367c29b8d14f7c..c0491630c000e2bdd4c5bbbdc87cd80b20a46aa2 100644 (file)
@@ -1,11 +1,13 @@
 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;
@@ -22,62 +24,6 @@ pub enum NewlineStyle {
     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 {
@@ -113,10 +59,11 @@ pub enum IndentStyle {
 
 #[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,
@@ -153,6 +100,31 @@ pub fn to_list_tactic(self, len: usize) -> ListTactic {
     }
 }
 
+#[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,
@@ -172,6 +144,9 @@ pub enum EmitMode {
     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
@@ -197,7 +172,7 @@ pub enum Color {
 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,
 }
 
@@ -205,9 +180,8 @@ impl Color {
     /// 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),
         }
     }
 }
@@ -247,6 +221,12 @@ pub struct WidthHeuristics {
     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 {
@@ -310,16 +290,42 @@ fn default() -> EmitMode {
 }
 
 /// 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
@@ -370,7 +376,7 @@ pub fn rustfmt_toml_path(&self) -> &Path {
     }
 }
 
-impl ::std::str::FromStr for IgnoreList {
+impl FromStr for IgnoreList {
     type Err = &'static str;
 
     fn from_str(_: &str) -> Result<Self, Self::Err> {
@@ -396,6 +402,10 @@ pub enum Edition {
     #[doc_hint = "2018"]
     /// Edition 2018.
     Edition2018,
+    #[value = "2021"]
+    #[doc_hint = "2021"]
+    /// Edition 2021.
+    Edition2021,
 }
 
 impl Default for Edition {
@@ -404,67 +414,29 @@ fn default() -> 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,
 }