use std::{env, fs};
use regex::Regex;
+use thiserror::Error;
use crate::config::config_type::ConfigType;
#[allow(unreachable_pub)]
hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
tab_spaces: usize, 4, true, "Number of spaces per tab";
newline_style: NewlineStyle, NewlineStyle::Auto, true, "Unix or Windows line endings";
+ indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items";
+
+ // Width Heuristics
use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different \
formatting for items and expressions if they satisfy a heuristic notion of 'small'";
- indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items";
+ width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
+ "'small' heuristic values";
+ fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \
+ falling back to vertical formatting.";
+ attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \
+ attributes before falling back to vertical formatting.";
+ struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \
+ falling back to vertical formatting.";
+ struct_variant_width: usize, 35, true, "Maximum width in the body of a struct variant before \
+ falling back to vertical formatting.";
+ array_width: usize, 60, true, "Maximum width of an array literal before falling \
+ back to vertical formatting.";
+ chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
+ single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \
+ expressions. A value of zero means always break if-else expressions.";
// Comments. macros, and strings
wrap_comments: bool, false, false, "Break comments to fit on the line";
// Imports
imports_indent: IndentStyle, IndentStyle::Block, false, "Indent of imports";
imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";
- merge_imports: bool, false, false, "Merge imports";
+ imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
+ "Merge or split imports to the provided granularity";
+ group_imports: GroupImportsTactic, GroupImportsTactic::Preserve, false,
+ "Controls the strategy for how imports are grouped together";
+ merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
// Ordering
reorder_imports: bool, true, true, "Reorder import and extern crate statements alphabetically";
"Align enum variants discrims, if their diffs fit within threshold";
match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
the same line with the pattern of arms";
+ match_arm_leading_pipes: MatchArmLeadingPipe, MatchArmLeadingPipe::Never, true,
+ "Determines whether leading pipes are emitted on match arms";
force_multiline_blocks: bool, false, false,
"Force multiline closure bodies and match arms to be wrapped in a block";
- fn_args_density: Density, Density::Tall, false, "Argument density in functions";
+ fn_args_layout: Density, Density::Tall, true,
+ "Control the layout of arguments in a function";
brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
"Brace style for control flow constructs";
file_lines: FileLines, FileLines::all(), false,
"Lines to format; this is not supported in rustfmt.toml, and can only be specified \
via the --file-lines option";
- width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
- "'small' heuristic values";
emit_mode: EmitMode, EmitMode::Files, false,
"What emit Mode to use when none is supplied";
make_backup: bool, false, false, "Backup changed files";
+ print_misformatted_file_names: bool, false, true,
+ "Prints the names of mismatched files that were formatted. Prints the names of \
+ files that would be formated when used with `--check` mode. ";
}
+#[derive(Error, Debug)]
+#[error("Could not output config: {0}")]
+pub struct ToTomlError(toml::ser::Error);
+
impl PartialConfig {
- pub fn to_toml(&self) -> Result<String, String> {
+ pub fn to_toml(&self) -> Result<String, ToTomlError> {
// Non-user-facing options can't be specified in TOML
let mut cloned = self.clone();
cloned.file_lines = None;
cloned.verbose = None;
cloned.width_heuristics = None;
+ cloned.print_misformatted_file_names = None;
+ cloned.merge_imports = None;
- ::toml::to_string(&cloned).map_err(|e| format!("Could not output config: {}", e))
+ ::toml::to_string(&cloned).map_err(ToTomlError)
}
}
create_config! {
// Options that are used by the generated functions
max_width: usize, 100, true, "Maximum width of each line";
- use_small_heuristics: Heuristics, Heuristics::Default, true,
- "Whether to use different formatting for items and \
- expressions if they satisfy a heuristic notion of 'small'.";
license_template_path: String, String::default(), false,
"Beginning of file must match license template";
required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
file_lines: FileLines, FileLines::all(), false,
"Lines to format; this is not supported in rustfmt.toml, and can only be specified \
via the --file-lines option";
+
+ // merge_imports deprecation
+ imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
+ "Merge imports";
+ merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
+
+ // Width Heuristics
+ use_small_heuristics: Heuristics, Heuristics::Default, true,
+ "Whether to use different formatting for items and \
+ expressions if they satisfy a heuristic notion of 'small'.";
width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
"'small' heuristic values";
+ fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \
+ falling back to vertical formatting.";
+ attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \
+ attributes before falling back to vertical formatting.";
+ struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \
+ falling back to vertical formatting.";
+ struct_variant_width: usize, 35, true, "Maximum width in the body of a struct \
+ variant before falling back to vertical formatting.";
+ array_width: usize, 60, true, "Maximum width of an array literal before falling \
+ back to vertical formatting.";
+ chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
+ single_line_if_else_max_width: usize, 50, true, "Maximum line length for single \
+ line if-else expressions. A value of zero means always break if-else expressions.";
+
// Options that are used by the tests
stable_option: bool, false, true, "A stable option";
unstable_option: bool, false, false, "An unstable option";
assert_eq!(s.contains("(unstable)"), true);
}
+ #[test]
+ fn test_empty_string_license_template_path() {
+ let toml = r#"license_template_path = """#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert!(config.license_template.is_none());
+ }
+
+ #[test]
+ fn test_valid_license_template_path() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert!(config.license_template.is_some());
+ }
+
+ #[test]
+ fn test_override_existing_license_with_no_license() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"license_template_path = "tests/license-template/lt.txt""#;
+ let mut config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert!(config.license_template.is_some());
+ config.override_value("license_template_path", "");
+ assert!(config.license_template.is_none());
+ }
+
+ #[test]
+ fn test_dump_default_config() {
+ let default_config = format!(
+ r#"max_width = 100
+hard_tabs = false
+tab_spaces = 4
+newline_style = "Auto"
+indent_style = "Block"
+use_small_heuristics = "Default"
+fn_call_width = 60
+attr_fn_like_width = 70
+struct_lit_width = 18
+struct_variant_width = 35
+array_width = 60
+chain_width = 60
+single_line_if_else_max_width = 50
+wrap_comments = false
+format_code_in_doc_comments = false
+comment_width = 80
+normalize_comments = false
+normalize_doc_attributes = false
+license_template_path = ""
+format_strings = false
+format_macro_matchers = false
+format_macro_bodies = true
+empty_item_single_line = true
+struct_lit_single_line = true
+fn_single_line = false
+where_single_line = false
+imports_indent = "Block"
+imports_layout = "Mixed"
+imports_granularity = "Preserve"
+group_imports = "Preserve"
+reorder_imports = true
+reorder_modules = true
+reorder_impl_items = false
+type_punctuation_density = "Wide"
+space_before_colon = false
+space_after_colon = true
+spaces_around_ranges = false
+binop_separator = "Front"
+remove_nested_parens = true
+combine_control_expr = true
+overflow_delimited_expr = false
+struct_field_align_threshold = 0
+enum_discrim_align_threshold = 0
+match_arm_blocks = true
+match_arm_leading_pipes = "Never"
+force_multiline_blocks = false
+fn_args_layout = "Tall"
+brace_style = "SameLineWhere"
+control_brace_style = "AlwaysSameLine"
+trailing_semicolon = true
+trailing_comma = "Vertical"
+match_block_trailing_comma = false
+blank_lines_upper_bound = 1
+blank_lines_lower_bound = 0
+edition = "2015"
+version = "One"
+inline_attribute_width = 0
+merge_derives = true
+use_try_shorthand = false
+use_field_init_shorthand = false
+force_explicit_abi = true
+condense_wildcard_suffixes = false
+color = "Auto"
+required_version = "{}"
+unstable_features = false
+disable_all_formatting = false
+skip_children = false
+hide_parse_errors = false
+error_on_line_overflow = false
+error_on_unformatted = false
+report_todo = "Never"
+report_fixme = "Never"
+ignore = []
+emit_mode = "Files"
+make_backup = false
+"#,
+ env!("CARGO_PKG_VERSION")
+ );
+ let toml = Config::default().all_options().to_toml().unwrap();
+ assert_eq!(&toml, &default_config);
+ }
+
// FIXME(#2183): these tests cannot be run in parallel because they use env vars.
// #[test]
// fn test_as_not_nightly_channel() {
// assert_eq!(config.unstable_features(), true);
// ::std::env::set_var("CFG_RELEASE_CHANNEL", v);
// }
+
+ #[cfg(test)]
+ mod deprecated_option_merge_imports {
+ use super::*;
+
+ #[test]
+ fn test_old_option_set() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"
+ unstable_features = true
+ merge_imports = true
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
+ }
+
+ #[test]
+ fn test_both_set() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"
+ unstable_features = true
+ merge_imports = true
+ imports_granularity = "Preserve"
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
+ }
+
+ #[test]
+ fn test_new_overridden() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"
+ unstable_features = true
+ merge_imports = true
+ "#;
+ let mut config = Config::from_toml(toml, Path::new("")).unwrap();
+ config.override_value("imports_granularity", "Preserve");
+ assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
+ }
+
+ #[test]
+ fn test_old_overridden() {
+ if !crate::is_nightly_channel!() {
+ return;
+ }
+ let toml = r#"
+ unstable_features = true
+ imports_granularity = "Module"
+ "#;
+ let mut config = Config::from_toml(toml, Path::new("")).unwrap();
+ config.override_value("merge_imports", "true");
+ // no effect: the new option always takes precedence
+ assert_eq!(config.imports_granularity(), ImportGranularity::Module);
+ }
+ }
+
+ #[cfg(test)]
+ mod use_small_heuristics {
+ use super::*;
+
+ #[test]
+ fn test_default_sets_correct_widths() {
+ let toml = r#"
+ use_small_heuristics = "Default"
+ max_width = 200
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 120);
+ assert_eq!(config.attr_fn_like_width(), 140);
+ assert_eq!(config.chain_width(), 120);
+ assert_eq!(config.fn_call_width(), 120);
+ assert_eq!(config.single_line_if_else_max_width(), 100);
+ assert_eq!(config.struct_lit_width(), 36);
+ assert_eq!(config.struct_variant_width(), 70);
+ }
+
+ #[test]
+ fn test_max_sets_correct_widths() {
+ let toml = r#"
+ use_small_heuristics = "Max"
+ max_width = 120
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 120);
+ assert_eq!(config.attr_fn_like_width(), 120);
+ assert_eq!(config.chain_width(), 120);
+ assert_eq!(config.fn_call_width(), 120);
+ assert_eq!(config.single_line_if_else_max_width(), 120);
+ assert_eq!(config.struct_lit_width(), 120);
+ assert_eq!(config.struct_variant_width(), 120);
+ }
+
+ #[test]
+ fn test_off_sets_correct_widths() {
+ let toml = r#"
+ use_small_heuristics = "Off"
+ max_width = 100
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), usize::max_value());
+ assert_eq!(config.attr_fn_like_width(), usize::max_value());
+ assert_eq!(config.chain_width(), usize::max_value());
+ assert_eq!(config.fn_call_width(), usize::max_value());
+ assert_eq!(config.single_line_if_else_max_width(), 0);
+ assert_eq!(config.struct_lit_width(), 0);
+ assert_eq!(config.struct_variant_width(), 0);
+ }
+
+ #[test]
+ fn test_override_works_with_default() {
+ let toml = r#"
+ use_small_heuristics = "Default"
+ array_width = 20
+ attr_fn_like_width = 40
+ chain_width = 20
+ fn_call_width = 90
+ single_line_if_else_max_width = 40
+ struct_lit_width = 30
+ struct_variant_width = 34
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 20);
+ assert_eq!(config.attr_fn_like_width(), 40);
+ assert_eq!(config.chain_width(), 20);
+ assert_eq!(config.fn_call_width(), 90);
+ assert_eq!(config.single_line_if_else_max_width(), 40);
+ assert_eq!(config.struct_lit_width(), 30);
+ assert_eq!(config.struct_variant_width(), 34);
+ }
+
+ #[test]
+ fn test_override_with_max() {
+ let toml = r#"
+ use_small_heuristics = "Max"
+ array_width = 20
+ attr_fn_like_width = 40
+ chain_width = 20
+ fn_call_width = 90
+ single_line_if_else_max_width = 40
+ struct_lit_width = 30
+ struct_variant_width = 34
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 20);
+ assert_eq!(config.attr_fn_like_width(), 40);
+ assert_eq!(config.chain_width(), 20);
+ assert_eq!(config.fn_call_width(), 90);
+ assert_eq!(config.single_line_if_else_max_width(), 40);
+ assert_eq!(config.struct_lit_width(), 30);
+ assert_eq!(config.struct_variant_width(), 34);
+ }
+
+ #[test]
+ fn test_override_with_off() {
+ let toml = r#"
+ use_small_heuristics = "Off"
+ array_width = 20
+ attr_fn_like_width = 40
+ chain_width = 20
+ fn_call_width = 90
+ single_line_if_else_max_width = 40
+ struct_lit_width = 30
+ struct_variant_width = 34
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 20);
+ assert_eq!(config.attr_fn_like_width(), 40);
+ assert_eq!(config.chain_width(), 20);
+ assert_eq!(config.fn_call_width(), 90);
+ assert_eq!(config.single_line_if_else_max_width(), 40);
+ assert_eq!(config.struct_lit_width(), 30);
+ assert_eq!(config.struct_variant_width(), 34);
+ }
+
+ #[test]
+ fn test_fn_call_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 90
+ fn_call_width = 95
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.fn_call_width(), 90);
+ }
+
+ #[test]
+ fn test_attr_fn_like_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 80
+ attr_fn_like_width = 90
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.attr_fn_like_width(), 80);
+ }
+
+ #[test]
+ fn test_struct_lit_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 78
+ struct_lit_width = 90
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.struct_lit_width(), 78);
+ }
+
+ #[test]
+ fn test_struct_variant_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 80
+ struct_variant_width = 90
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.struct_variant_width(), 80);
+ }
+
+ #[test]
+ fn test_array_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 60
+ array_width = 80
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.array_width(), 60);
+ }
+
+ #[test]
+ fn test_chain_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 80
+ chain_width = 90
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.chain_width(), 80);
+ }
+
+ #[test]
+ fn test_single_line_if_else_max_width_config_exceeds_max_width() {
+ let toml = r#"
+ max_width = 70
+ single_line_if_else_max_width = 90
+ "#;
+ let config = Config::from_toml(toml, Path::new("")).unwrap();
+ assert_eq!(config.single_line_if_else_max_width(), 70);
+ }
+
+ #[test]
+ fn test_override_fn_call_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("fn_call_width", "101");
+ assert_eq!(config.fn_call_width(), 100);
+ }
+
+ #[test]
+ fn test_override_attr_fn_like_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("attr_fn_like_width", "101");
+ assert_eq!(config.attr_fn_like_width(), 100);
+ }
+
+ #[test]
+ fn test_override_struct_lit_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("struct_lit_width", "101");
+ assert_eq!(config.struct_lit_width(), 100);
+ }
+
+ #[test]
+ fn test_override_struct_variant_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("struct_variant_width", "101");
+ assert_eq!(config.struct_variant_width(), 100);
+ }
+
+ #[test]
+ fn test_override_array_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("array_width", "101");
+ assert_eq!(config.array_width(), 100);
+ }
+
+ #[test]
+ fn test_override_chain_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("chain_width", "101");
+ assert_eq!(config.chain_width(), 100);
+ }
+
+ #[test]
+ fn test_override_single_line_if_else_max_width_exceeds_max_width() {
+ let mut config = Config::default();
+ config.override_value("single_line_if_else_max_width", "101");
+ assert_eq!(config.single_line_if_else_max_width(), 100);
+ }
+ }
}