1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
13 use std::cell::RefCell;
14 use std::collections::HashSet;
18 use file_lines::FileLines;
19 use lists::{SeparatorTactic, ListTactic};
21 macro_rules! configuration_option_enum{
22 ($e:ident: $( $x:ident ),+ $(,)*) => {
23 #[derive(Copy, Clone, Eq, PartialEq, Debug)]
28 impl_enum_decodable!($e, $( $x ),+);
32 configuration_option_enum! { Style:
33 Rfc, // Follow the style RFCs style.
34 Default, // Follow the traditional Rustfmt style.
37 configuration_option_enum! { NewlineStyle:
40 Native, // \r\n in Windows, \n on other platforms
43 configuration_option_enum! { BraceStyle:
46 // Prefer same line except where there is a where clause, in which case force
47 // the brace to the next line.
51 configuration_option_enum! { ControlBraceStyle:
52 // K&R style, Rust community default
60 // How to indent a function's return type.
61 configuration_option_enum! { ReturnIndent:
62 // Aligned with the arguments
64 // Aligned with the where clause
68 configuration_option_enum! { IndentStyle:
69 // First line on the same line as the opening brace, all lines aligned with
72 // First line is on a new line and all lines align with block indent.
76 configuration_option_enum! { Density:
77 // Fit as much on one line as possible.
81 // Try to compress if the body is empty.
83 // Place every item on a separate line.
87 configuration_option_enum! { TypeDensity:
88 // No spaces around "=" and "+"
90 // Spaces around " = " and " + "
96 pub fn to_list_tactic(self) -> ListTactic {
98 Density::Compressed => ListTactic::Mixed,
100 Density::CompressedIfEmpty => ListTactic::HorizontalVertical,
101 Density::Vertical => ListTactic::Vertical,
106 configuration_option_enum! { LicensePolicy:
107 // Do not place license text at top of files
109 // Use the text in "license" field as the license
111 // Use a text file as the license text
115 configuration_option_enum! { MultilineStyle:
116 // Use horizontal layout if it fits in one line, fall back to vertical
118 // Use vertical layout
122 impl MultilineStyle {
123 pub fn to_list_tactic(self) -> ListTactic {
125 MultilineStyle::PreferSingle => ListTactic::HorizontalVertical,
126 MultilineStyle::ForceMulti => ListTactic::Vertical,
131 configuration_option_enum! { ReportTactic:
137 configuration_option_enum! { WriteMode:
138 // Backs the original file up and overwrites the original.
140 // Overwrites original file without backup.
142 // Writes the output to stdout.
144 // Writes the diff to stdout.
146 // Displays how much of the input file was processed
150 // Outputs a checkstyle XML file.
154 /// Trait for types that can be used in `Config`.
155 pub trait ConfigType: Sized {
156 /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
157 /// pipe-separated list of variants; for other types it returns "<type>".
158 fn doc_hint() -> String;
161 impl ConfigType for bool {
162 fn doc_hint() -> String {
163 String::from("<boolean>")
167 impl ConfigType for usize {
168 fn doc_hint() -> String {
169 String::from("<unsigned integer>")
173 impl ConfigType for isize {
174 fn doc_hint() -> String {
175 String::from("<signed integer>")
179 impl ConfigType for String {
180 fn doc_hint() -> String {
181 String::from("<string>")
185 impl ConfigType for FileLines {
186 fn doc_hint() -> String {
187 String::from("<json>")
191 pub struct ConfigHelpItem {
192 option_name: &'static str,
193 doc_string: &'static str,
194 variant_names: String,
195 default: &'static str,
198 impl ConfigHelpItem {
199 pub fn option_name(&self) -> &'static str {
203 pub fn doc_string(&self) -> &'static str {
207 pub fn variant_names(&self) -> &String {
211 pub fn default(&self) -> &'static str {
216 /// This is used by Config to track which config parameters are accessed during
217 /// formatting. It uses a RefCell for interior mutability, as we don't want to
218 /// require a mutable reference to Config in order to access configuration.
219 #[derive(Clone, Default)]
220 struct ConfigTracker {
221 set: RefCell<HashSet<&'static str>>,
225 fn mark_accessed(&self, name: &'static str) {
226 // We don't ever expect borrowing to fail, as our use of RefCell is very
228 let mut set = self.set.borrow_mut();
232 fn was_accessed(&self, name: &'static str) -> bool {
233 self.set.borrow().contains(name)
237 macro_rules! create_config {
238 ($($i:ident: $ty:ty, $def:expr, $( $dstring:expr ),+ );+ $(;)*) => (
239 #[derive(Deserialize, Clone)]
241 #[serde(skip_deserializing)]
242 tracker: ConfigTracker,
247 // Just like the Config struct but with each property wrapped
248 // as Option<T>. This is used to parse a rustfmt.toml that doesn't
249 // specity all properties of `Config`.
250 // We first parse into `ParsedConfig`, then create a default `Config`
251 // and overwrite the properties with corresponding values from `ParsedConfig`
252 #[derive(Deserialize, Clone)]
253 pub struct ParsedConfig {
254 $(pub $i: Option<$ty>),+
260 pub fn $i(&self) -> $ty {
261 self.tracker.mark_accessed(stringify!($i));
266 fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
268 if let Some(val) = parsed.$i {
275 pub fn from_toml(toml: &str) -> Result<Config, String> {
276 let parsed: toml::Value =
277 toml.parse().map_err(|e| format!("Could not parse TOML: {}", e))?;
278 let mut err: String = String::new();
282 .ok_or(String::from("Parsed config was not table"))?;
283 for (key, _) in table {
286 stringify!($i) => (),
290 &format!("Warning: Unknown configuration option `{}`\n",
297 match parsed.try_into() {
299 Ok(Config::default().fill_from_parsed_config(parsed_config)),
301 err.push_str("Error: Decoding config file failed:\n");
302 err.push_str(format!("{}\n", e).as_str());
303 err.push_str("Please check your config file.\n");
309 pub fn override_value(&mut self, key: &str, val: &str)
310 -> result::Result<(), Box<error::Error + Send + Sync>>
314 stringify!($i) => self.$i = val.parse::<$ty>()?,
316 _ => panic!("Unknown config key in override: {}", key)
321 pub fn print_docs() {
324 $( let max = cmp::max(max, stringify!($i).len()+1); )+
325 let mut space_str = String::with_capacity(max);
329 println!("Configuration Options:");
331 let name_raw = stringify!($i);
332 let mut name_out = String::with_capacity(max);
333 for _ in name_raw.len()..max-1 {
336 name_out.push_str(name_raw);
338 println!("{}{} Default: {:?}",
343 println!("{}{}", space_str, $dstring);
350 // Template for the default configuration
351 impl Default for Config {
352 fn default() -> Config {
354 tracker: ConfigTracker::default(),
365 verbose: bool, false, "Use verbose output";
366 disable_all_formatting: bool, false, "Don't reformat anything";
367 skip_children: bool, false, "Don't reformat out of line modules";
368 file_lines: FileLines, FileLines::all(),
369 "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
370 via the --file-lines option";
371 max_width: usize, 100, "Maximum width of each line";
372 error_on_line_overflow: bool, true, "Error if unable to get all lines within max_width";
373 tab_spaces: usize, 4, "Number of spaces per tab";
374 fn_call_width: usize, 60,
375 "Maximum width of the args of a function call before falling back to vertical formatting";
376 struct_lit_width: usize, 18,
377 "Maximum width in the body of a struct lit before falling back to vertical formatting";
378 struct_variant_width: usize, 35,
379 "Maximum width in the body of a struct variant before falling back to vertical formatting";
380 force_explicit_abi: bool, true, "Always print the abi for extern items";
381 newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
382 fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
383 item_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for structs and enums";
384 control_style: Style, Style::Default, "Indent style for control flow statements";
385 control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine,
386 "Brace style for control flow constructs";
387 impl_empty_single_line: bool, true, "Put empty-body implementations on a single line";
388 trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
389 "How to handle trailing commas for lists";
390 fn_empty_single_line: bool, true, "Put empty-body functions on a single line";
391 fn_single_line: bool, false, "Put single-expression functions on a single line";
392 fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
393 "Location of return type in function declaration";
394 fn_args_paren_newline: bool, true, "If function argument parenthesis goes on a newline";
395 fn_args_density: Density, Density::Tall, "Argument density in functions";
396 fn_args_layout: IndentStyle, IndentStyle::Visual,
397 "Layout of function arguments and tuple structs";
398 array_layout: IndentStyle, IndentStyle::Visual, "Indent on arrays";
399 array_width: usize, 60,
400 "Maximum width of an array literal before falling back to vertical formatting";
401 type_punctuation_density: TypeDensity, TypeDensity::Wide,
402 "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
403 where_style: Style, Style::Default, "Overall strategy for where clauses";
405 // 1. Should we at least try to put the where clause on the same line as the rest of the
407 // 2. Currently options `Tall` and `Vertical` produce the same output.
408 where_density: Density, Density::CompressedIfEmpty, "Density of a where clause";
409 where_layout: ListTactic, ListTactic::Vertical, "Element layout inside a where clause";
410 where_pred_indent: IndentStyle, IndentStyle::Visual,
411 "Indentation style of a where predicate";
412 generics_indent: IndentStyle, IndentStyle::Visual, "Indentation of generics";
413 struct_lit_style: IndentStyle, IndentStyle::Block, "Style of struct definition";
414 struct_lit_multiline_style: MultilineStyle, MultilineStyle::PreferSingle,
415 "Multiline style on literal structs";
416 fn_call_style: IndentStyle, IndentStyle::Visual, "Indentation for function calls, etc.";
417 report_todo: ReportTactic, ReportTactic::Never,
418 "Report all, none or unnumbered occurrences of TODO in source file comments";
419 report_fixme: ReportTactic, ReportTactic::Never,
420 "Report all, none or unnumbered occurrences of FIXME in source file comments";
421 chain_indent: IndentStyle, IndentStyle::Block, "Indentation of chain";
422 chain_one_line_max: usize, 60, "Maximum length of a chain to fit on a single line";
423 reorder_imports: bool, false, "Reorder import statements alphabetically";
424 reorder_imported_names: bool, false,
425 "Reorder lists of names in import statements alphabetically";
426 single_line_if_else_max_width: usize, 50, "Maximum line length for single line if-else \
427 expressions. A value of zero means always break \
428 if-else expressions.";
429 format_strings: bool, false, "Format string literals where necessary";
430 force_format_strings: bool, false, "Always format string literals";
431 take_source_hints: bool, false, "Retain some formatting characteristics from the source code";
432 hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
433 wrap_comments: bool, false, "Break comments to fit on the line";
434 comment_width: usize, 80, "Maximum length of comments. No effect unless wrap_comments = true";
435 normalize_comments: bool, false, "Convert /* */ comments to // comments where possible";
436 wrap_match_arms: bool, true, "Wrap multiline match arms in blocks";
437 match_block_trailing_comma: bool, false,
438 "Put a trailing comma after a block based match arm (non-block arms are not affected)";
439 indent_match_arms: bool, true, "Indent match arms instead of keeping them at the same \
440 indentation level as the match keyword";
441 closure_block_indent_threshold: isize, 7, "How many lines a closure must have before it is \
442 block indented. -1 means never use block indent.";
443 space_before_type_annotation: bool, false,
444 "Leave a space before the colon in a type annotation";
445 space_after_type_annotation_colon: bool, true,
446 "Leave a space after the colon in a type annotation";
447 space_before_bound: bool, false, "Leave a space before the colon in a trait or lifetime bound";
448 space_after_bound_colon: bool, true,
449 "Leave a space after the colon in a trait or lifetime bound";
450 spaces_around_ranges: bool, false, "Put spaces around the .. and ... range operators";
451 spaces_within_angle_brackets: bool, false, "Put spaces within non-empty generic arguments";
452 spaces_within_square_brackets: bool, false, "Put spaces within non-empty square brackets";
453 spaces_within_parens: bool, false, "Put spaces within non-empty parentheses";
454 use_try_shorthand: bool, false, "Replace uses of the try! macro by the ? shorthand";
455 write_mode: WriteMode, WriteMode::Replace,
456 "What Write Mode to use when none is supplied: Replace, Overwrite, Display, Diff, Coverage";
457 condense_wildcard_suffices: bool, false, "Replace strings of _ wildcards by a single .. in \