]> git.lizzy.rs Git - rust.git/blob - src/config.rs
Make listItem contain option
[rust.git] / src / config.rs
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.
4 //
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.
10
11 extern crate toml;
12
13 use lists::{SeparatorTactic, ListTactic};
14
15 macro_rules! configuration_option_enum{
16     ($e:ident: $( $x:ident ),+ $(,)*) => {
17         #[derive(Copy, Clone, Eq, PartialEq, Debug)]
18         pub enum $e {
19             $( $x ),+
20         }
21
22         impl_enum_decodable!($e, $( $x ),+);
23     }
24 }
25
26 configuration_option_enum! { NewlineStyle:
27     Windows, // \r\n
28     Unix, // \n
29 }
30
31 configuration_option_enum! { BraceStyle:
32     AlwaysNextLine,
33     PreferSameLine,
34     // Prefer same line except where there is a where clause, in which case force
35     // the brace to the next line.
36     SameLineWhere,
37 }
38
39 // How to indent a function's return type.
40 configuration_option_enum! { ReturnIndent:
41     // Aligned with the arguments
42     WithArgs,
43     // Aligned with the where clause
44     WithWhereClause,
45 }
46
47 // How to stle a struct literal.
48 configuration_option_enum! { StructLitStyle:
49     // First line on the same line as the opening brace, all lines aligned with
50     // the first line.
51     Visual,
52     // First line is on a new line and all lines align with block indent.
53     Block,
54     // FIXME Maybe we should also have an option to align types.
55 }
56
57 configuration_option_enum! { BlockIndentStyle:
58     // Same level as parent.
59     Inherit,
60     // One level deeper than parent.
61     Tabbed,
62     // Aligned with block open.
63     Visual,
64 }
65
66 configuration_option_enum! { Density:
67     // Fit as much on one line as possible.
68     Compressed,
69     // Use more lines.
70     Tall,
71     // Try to compress if the body is empty.
72     CompressedIfEmpty,
73 }
74
75 impl Density {
76     pub fn to_list_tactic(self) -> ListTactic {
77         match self {
78             Density::Compressed => ListTactic::Mixed,
79             Density::Tall | Density::CompressedIfEmpty => ListTactic::HorizontalVertical,
80         }
81     }
82 }
83
84 configuration_option_enum! { LicensePolicy:
85     // Do not place license text at top of files
86     NoLicense,
87     // Use the text in "license" field as the license
88     TextLicense,
89     // Use a text file as the license text
90     FileLicense,
91 }
92
93 configuration_option_enum! { MultilineStyle:
94     // Use horizontal layout if it fits in one line, fall back to vertical
95     PreferSingle,
96     // Use vertical layout
97     ForceMulti,
98 }
99
100 impl MultilineStyle {
101     pub fn to_list_tactic(self) -> ListTactic {
102         match self {
103             MultilineStyle::PreferSingle => ListTactic::HorizontalVertical,
104             MultilineStyle::ForceMulti => ListTactic::Vertical,
105         }
106     }
107 }
108
109 configuration_option_enum! { ReportTactic:
110     Always,
111     Unnumbered,
112     Never,
113 }
114
115 // This trait and the following impl blocks are there so that we an use
116 // UCFS inside the get_docs() function on types for configs.
117 pub trait ConfigType {
118     fn get_variant_names() -> String;
119 }
120
121 impl ConfigType for bool {
122     fn get_variant_names() -> String {
123         String::from("<boolean>")
124     }
125 }
126
127 impl ConfigType for usize {
128     fn get_variant_names() -> String {
129         String::from("<unsigned integer>")
130     }
131 }
132
133 impl ConfigType for String {
134     fn get_variant_names() -> String {
135         String::from("<string>")
136     }
137 }
138
139 pub struct ConfigHelpItem {
140     option_name: &'static str,
141     doc_string: &'static str,
142     variant_names: String,
143     default: &'static str,
144 }
145
146 impl ConfigHelpItem {
147     pub fn option_name(&self) -> &'static str {
148         self.option_name
149     }
150
151     pub fn doc_string(&self) -> &'static str {
152         self.doc_string
153     }
154
155     pub fn variant_names(&self) -> &String {
156         &self.variant_names
157     }
158
159     pub fn default(&self) -> &'static str {
160         self.default
161     }
162 }
163
164 macro_rules! create_config {
165     ($($i:ident: $ty:ty, $def:expr, $( $dstring:expr ),+ );+ $(;)*) => (
166         #[derive(RustcDecodable, Clone)]
167         pub struct Config {
168             $(pub $i: $ty),+
169         }
170
171         // Just like the Config struct but with each property wrapped
172         // as Option<T>. This is used to parse a rustfmt.toml that doesn't
173         // specity all properties of `Config`.
174         // We first parse into `ParsedConfig`, then create a default `Config`
175         // and overwrite the properties with corresponding values from `ParsedConfig`
176         #[derive(RustcDecodable, Clone)]
177         pub struct ParsedConfig {
178             $(pub $i: Option<$ty>),+
179         }
180
181         impl Config {
182
183             fn fill_from_parsed_config(mut self, parsed: ParsedConfig) -> Config {
184             $(
185                 if let Some(val) = parsed.$i {
186                     self.$i = val;
187                 }
188             )+
189                 self
190             }
191
192             pub fn from_toml(toml: &str) -> Config {
193                 let parsed = toml.parse().unwrap();
194                 let parsed_config:ParsedConfig = match toml::decode(parsed) {
195                     Some(decoded) => decoded,
196                     None => {
197                         println!("Decoding config file failed. Config:\n{}", toml);
198                         let parsed: toml::Value = toml.parse().unwrap();
199                         println!("\n\nParsed:\n{:?}", parsed);
200                         panic!();
201                     }
202                 };
203                 Config::default().fill_from_parsed_config(parsed_config)
204             }
205
206             pub fn override_value(&mut self, key: &str, val: &str) {
207                 match key {
208                     $(
209                         stringify!($i) => {
210                             self.$i = val.parse::<$ty>().unwrap();
211                         }
212                     )+
213                     _ => panic!("Bad config key!")
214                 }
215             }
216
217             pub fn print_docs() {
218                 use std::cmp;
219                 let max = 0;
220                 $( let max = cmp::max(max, stringify!($i).len()+1); )+
221                 let mut space_str = String::with_capacity(max);
222                 for _ in 0..max {
223                     space_str.push(' ');
224                 }
225                 println!("\nConfiguration Options:");
226                 $(
227                     let name_raw = stringify!($i);
228                     let mut name_out = String::with_capacity(max);
229                     for _ in name_raw.len()..max-1 {
230                         name_out.push(' ')
231                     }
232                     name_out.push_str(name_raw);
233                     name_out.push(' ');
234                     println!("{}{} Default: {:?}",
235                              name_out,
236                              <$ty>::get_variant_names(),
237                              $def);
238                     $(
239                         println!("{}{}", space_str, $dstring);
240                     )+
241                     println!("");
242                 )+
243             }
244         }
245
246         // Template for the default configuration
247         impl Default for Config {
248             fn default() -> Config {
249                 Config {
250                     $(
251                         $i: $def,
252                     )+
253                 }
254             }
255         }
256     )
257 }
258
259 create_config! {
260     max_width: usize, 100, "Maximum width of each line";
261     ideal_width: usize, 80, "Ideal width of each line";
262     tab_spaces: usize, 4, "Number of spaces per tab";
263     fn_call_width: usize, 55,
264         "Maximum width of the args of a function call before faling back to vertical formatting";
265     struct_lit_width: usize, 16,
266         "Maximum width in the body of a struct lit before faling back to vertical formatting";
267     newline_style: NewlineStyle, NewlineStyle::Unix, "Unix or Windows line endings";
268     fn_brace_style: BraceStyle, BraceStyle::SameLineWhere, "Brace style for functions";
269     fn_return_indent: ReturnIndent, ReturnIndent::WithArgs,
270         "Location of return type in function declaration";
271     fn_args_paren_newline: bool, true, "If function argument parenthases goes on a newline";
272     fn_args_density: Density, Density::Tall, "Argument density in functions";
273     fn_args_layout: StructLitStyle, StructLitStyle::Visual, "Layout of function arguments";
274     fn_arg_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indent on function arguments";
275     // Should we at least try to put the where clause on the same line as the rest of the
276     // function decl?
277     where_density: Density, Density::CompressedIfEmpty, "Density of a where clause";
278     // Visual will be treated like Tabbed
279     where_indent: BlockIndentStyle, BlockIndentStyle::Tabbed, "Indentation of a where clause";
280     where_layout: ListTactic, ListTactic::Vertical, "Element layout inside a where clause";
281     where_pred_indent: BlockIndentStyle, BlockIndentStyle::Visual,
282         "Indentation style of a where predicate";
283     generics_indent: BlockIndentStyle, BlockIndentStyle::Visual, "Indentation of generics";
284     struct_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
285         "If there is a trailing comma on structs";
286     struct_lit_trailing_comma: SeparatorTactic, SeparatorTactic::Vertical,
287         "If there is a trailing comma on literal structs";
288     struct_lit_style: StructLitStyle, StructLitStyle::Block, "Style of struct definition";
289     struct_lit_multiline_style: MultilineStyle, MultilineStyle::PreferSingle,
290         "Multilline style on literal structs";
291     enum_trailing_comma: bool, true, "Put a trailing comma on enum declarations";
292     report_todo: ReportTactic, ReportTactic::Always,
293         "Report all occurences of TODO in source file comments";
294     report_fixme: ReportTactic, ReportTactic::Never,
295         "Report all occurences of FIXME in source file comments";
296     // Alphabetically, case sensitive.
297     reorder_imports: bool, false, "Reorder import statements alphabetically";
298     single_line_if_else: bool, false, "Put else on same line as closing brace for if statements";
299     format_strings: bool, true, "Format string literals, or leave as is";
300     chains_overflow_last: bool, true, "Allow last call in method chain to break the line";
301     take_source_hints: bool, true, "Retain some formatting characteristics from the source code";
302     hard_tabs: bool, false, "Use tab characters for indentation, spaces for alignment";
303 }