1 use crate::config::file_lines::FileLines;
2 use crate::config::options::{IgnoreList, WidthHeuristics};
4 /// Trait for types that can be used in `Config`.
5 pub(crate) trait ConfigType: Sized {
6 /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
7 /// pipe-separated list of variants; for other types it returns "<type>".
8 fn doc_hint() -> String;
11 impl ConfigType for bool {
12 fn doc_hint() -> String {
13 String::from("<boolean>")
17 impl ConfigType for usize {
18 fn doc_hint() -> String {
19 String::from("<unsigned integer>")
23 impl ConfigType for isize {
24 fn doc_hint() -> String {
25 String::from("<signed integer>")
29 impl ConfigType for String {
30 fn doc_hint() -> String {
31 String::from("<string>")
35 impl ConfigType for FileLines {
36 fn doc_hint() -> String {
37 String::from("<json>")
41 impl ConfigType for WidthHeuristics {
42 fn doc_hint() -> String {
47 impl ConfigType for IgnoreList {
48 fn doc_hint() -> String {
49 String::from("[<string>,..]")
53 macro_rules! create_config {
54 ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
56 use std::collections::HashSet;
59 use serde::{Deserialize, Serialize};
62 #[allow(unreachable_pub)]
64 // if a license_template_path has been specified, successfully read, parsed and compiled
65 // into a regex, it will be stored here
66 pub license_template: Option<Regex>,
67 // For each config item, we store a bool indicating whether it has
68 // been accessed and the value, and a bool whether the option was
69 // manually initialised, or taken from the default,
70 $($i: (Cell<bool>, bool, $ty, bool)),+
73 // Just like the Config struct but with each property wrapped
74 // as Option<T>. This is used to parse a rustfmt.toml that doesn't
75 // specify all properties of `Config`.
76 // We first parse into `PartialConfig`, then create a default `Config`
77 // and overwrite the properties with corresponding values from `PartialConfig`.
78 #[derive(Deserialize, Serialize, Clone)]
79 #[allow(unreachable_pub)]
80 pub struct PartialConfig {
81 $(pub $i: Option<$ty>),+
84 // Macro hygiene won't allow us to make `set_$i()` methods on Config
85 // for each item, so this struct is used to give the API to set values:
86 // `config.set().option(false)`. It's pretty ugly. Consider replacing
87 // with `config.set_option(false)` if we ever get a stable/usable
88 // `concat_idents!()`.
89 #[allow(unreachable_pub)]
90 pub struct ConfigSetter<'a>(&'a mut Config);
92 impl<'a> ConfigSetter<'a> {
94 #[allow(unreachable_pub)]
95 pub fn $i(&mut self, value: $ty) {
96 (self.0).$i.2 = value;
97 match stringify!($i) {
99 | "use_small_heuristics"
101 | "single_line_if_else_max_width"
102 | "attr_fn_like_width"
104 | "struct_variant_width"
106 | "chain_width" => self.0.set_heuristics(),
107 "license_template_path" => self.0.set_license_template(),
108 "merge_imports" => self.0.set_merge_imports(),
115 // Query each option, returns true if the user set the option, false if
116 // a default was used.
117 #[allow(unreachable_pub)]
118 pub struct ConfigWasSet<'a>(&'a Config);
120 impl<'a> ConfigWasSet<'a> {
122 #[allow(unreachable_pub)]
123 pub fn $i(&self) -> bool {
131 #[allow(unreachable_pub)]
132 pub fn $i(&self) -> $ty {
138 #[allow(unreachable_pub)]
139 pub fn set(&mut self) -> ConfigSetter<'_> {
143 #[allow(unreachable_pub)]
144 pub fn was_set(&self) -> ConfigWasSet<'_> {
148 fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
150 if let Some(val) = parsed.$i {
155 if crate::is_nightly_channel!() {
159 eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \
160 available in nightly channel.", stringify!($i), val);
165 self.set_heuristics();
166 self.set_license_template();
167 self.set_ignore(dir);
168 self.set_merge_imports();
172 /// Returns a hash set initialized with every user-facing config option name.
174 pub(crate) fn hash_set() -> HashSet<String> {
175 let mut hash_set = HashSet::new();
177 hash_set.insert(stringify!($i).to_owned());
182 pub(crate) fn is_valid_name(name: &str) -> bool {
185 stringify!($i) => true,
191 #[allow(unreachable_pub)]
192 pub fn is_valid_key_val(key: &str, val: &str) -> bool {
195 stringify!($i) => val.parse::<$ty>().is_ok(),
201 #[allow(unreachable_pub)]
202 pub fn used_options(&self) -> PartialConfig {
205 $i: if self.$i.0.get() {
206 Some(self.$i.2.clone())
214 #[allow(unreachable_pub)]
215 pub fn all_options(&self) -> PartialConfig {
218 $i: Some(self.$i.2.clone()),
223 #[allow(unreachable_pub)]
224 pub fn override_value(&mut self, key: &str, val: &str)
230 self.$i.2 = val.parse::<$ty>()
231 .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
237 _ => panic!("Unknown config key in override: {}", key)
242 | "use_small_heuristics"
244 | "single_line_if_else_max_width"
245 | "attr_fn_like_width"
247 | "struct_variant_width"
249 | "chain_width" => self.set_heuristics(),
250 "license_template_path" => self.set_license_template(),
251 "merge_imports" => self.set_merge_imports(),
256 #[allow(unreachable_pub)]
257 pub fn is_hidden_option(name: &str) -> bool {
258 const HIDE_OPTIONS: [&str; 5] =
259 ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"];
260 HIDE_OPTIONS.contains(&name)
263 #[allow(unreachable_pub)]
264 pub fn print_docs(out: &mut dyn Write, include_unstable: bool) {
267 $( let max = cmp::max(max, stringify!($i).len()+1); )+
268 let space_str = " ".repeat(max);
269 writeln!(out, "Configuration Options:").unwrap();
271 if $stb || include_unstable {
272 let name_raw = stringify!($i);
274 if !Config::is_hidden_option(name_raw) {
275 let mut name_out = String::with_capacity(max);
276 for _ in name_raw.len()..max-1 {
279 name_out.push_str(name_raw);
281 let mut default_str = format!("{}", $def);
282 if default_str.is_empty() {
283 default_str = String::from("\"\"");
286 "{}{} Default: {}{}",
290 if !$stb { " (unstable)" } else { "" }).unwrap();
292 writeln!(out, "{}{}", space_str, $dstring).unwrap();
294 writeln!(out).unwrap();
300 fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
301 let max_width = self.max_width.2;
302 let get_width_value = |
304 override_value: usize,
305 heuristic_value: usize,
309 return heuristic_value;
311 if override_value > max_width {
313 "`{0}` cannot have a value that exceeds `max_width`. \
314 `{0}` will be set to the same value as `max_width`",
322 let fn_call_width = get_width_value(
323 self.was_set().fn_call_width(),
324 self.fn_call_width.2,
325 heuristics.fn_call_width,
328 self.fn_call_width.2 = fn_call_width;
330 let attr_fn_like_width = get_width_value(
331 self.was_set().attr_fn_like_width(),
332 self.attr_fn_like_width.2,
333 heuristics.attr_fn_like_width,
334 "attr_fn_like_width",
336 self.attr_fn_like_width.2 = attr_fn_like_width;
338 let struct_lit_width = get_width_value(
339 self.was_set().struct_lit_width(),
340 self.struct_lit_width.2,
341 heuristics.struct_lit_width,
344 self.struct_lit_width.2 = struct_lit_width;
346 let struct_variant_width = get_width_value(
347 self.was_set().struct_variant_width(),
348 self.struct_variant_width.2,
349 heuristics.struct_variant_width,
350 "struct_variant_width",
352 self.struct_variant_width.2 = struct_variant_width;
354 let array_width = get_width_value(
355 self.was_set().array_width(),
357 heuristics.array_width,
360 self.array_width.2 = array_width;
362 let chain_width = get_width_value(
363 self.was_set().chain_width(),
365 heuristics.chain_width,
368 self.chain_width.2 = chain_width;
370 let single_line_if_else_max_width = get_width_value(
371 self.was_set().single_line_if_else_max_width(),
372 self.single_line_if_else_max_width.2,
373 heuristics.single_line_if_else_max_width,
374 "single_line_if_else_max_width",
376 self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
379 fn set_heuristics(&mut self) {
380 let max_width = self.max_width.2;
381 match self.use_small_heuristics.2 {
382 Heuristics::Default =>
383 self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
384 Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
385 Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
389 fn set_license_template(&mut self) {
390 if self.was_set().license_template_path() {
391 let lt_path = self.license_template_path();
392 if lt_path.len() > 0 {
393 match license::load_and_compile_template(<_path) {
394 Ok(re) => self.license_template = Some(re),
395 Err(msg) => eprintln!("Warning for license template file {:?}: {}",
399 self.license_template = None;
404 fn set_ignore(&mut self, dir: &Path) {
405 self.ignore.2.add_prefix(dir);
408 fn set_merge_imports(&mut self) {
409 if self.was_set().merge_imports() {
411 "Warning: the `merge_imports` option is deprecated. \
412 Use `imports_granularity=\"Crate\"` instead"
414 if !self.was_set().imports_granularity() {
415 self.imports_granularity.2 = if self.merge_imports() {
416 ImportGranularity::Crate
418 ImportGranularity::Preserve
424 #[allow(unreachable_pub)]
425 /// Returns `true` if the config key was explicitly set and is the default value.
426 pub fn is_default(&self, key: &str) -> bool {
428 if let stringify!($i) = key {
429 return self.$i.1 && self.$i.2 == $def;
436 // Template for the default configuration
437 impl Default for Config {
438 fn default() -> Config {
440 license_template: None,
442 $i: (Cell::new(false), false, $def, $stb),