cargo_cargofmt/config/
mod.rs1use std::io;
2use std::path::Path;
3use std::path::PathBuf;
4
5pub mod lists;
6pub mod options;
7
8#[derive(serde::Deserialize)]
9#[serde(default)]
10pub struct Config {
11 pub disable_all_formatting: bool,
12 pub newline_style: options::NewlineStyle,
13 pub format_generated_files: bool,
14 pub generated_marker_line_search_limit: usize,
15 pub blank_lines_lower_bound: usize,
16 pub blank_lines_upper_bound: usize,
17 pub trailing_comma: lists::SeparatorTactic,
18 pub hard_tabs: bool,
19 pub tab_spaces: usize,
20 pub max_width: usize,
21 pub array_width: Option<usize>,
22 pub use_small_heuristics: options::UseSmallHeuristics,
23}
24
25impl Config {
26 pub fn array_width(&self) -> usize {
34 self.array_width
35 .unwrap_or_else(|| self.heuristic_width(0.6))
36 }
37
38 fn heuristic_width(&self, percent: f64) -> usize {
39 match self.use_small_heuristics {
40 options::UseSmallHeuristics::Default => (self.max_width as f64 * percent) as usize,
41 options::UseSmallHeuristics::Off => 0,
42 options::UseSmallHeuristics::Max => self.max_width,
43 }
44 }
45}
46
47impl Default for Config {
48 fn default() -> Self {
49 Self {
50 disable_all_formatting: false,
51 newline_style: options::NewlineStyle::default(),
52 format_generated_files: false,
53 generated_marker_line_search_limit: 5,
54 blank_lines_lower_bound: 0,
55 blank_lines_upper_bound: 1,
56 trailing_comma: lists::SeparatorTactic::Vertical,
57 hard_tabs: false,
58 tab_spaces: 4,
59 max_width: 100,
60 array_width: None,
61 use_small_heuristics: options::UseSmallHeuristics::default(),
62 }
63 }
64}
65
66#[tracing::instrument]
67pub fn load_config(search_start: &Path) -> Result<Config, io::Error> {
68 let Some(path) = find_config(search_start) else {
69 return Ok(Config::default());
70 };
71
72 let content = std::fs::read_to_string(&path)?;
73 let config = toml::de::from_str(&content).map_err(io::Error::other)?;
74 Ok(config)
75}
76
77fn find_config(mut path: &Path) -> Option<PathBuf> {
78 if path.is_file() {
79 path = path.parent()?;
80 }
81
82 loop {
83 let mut config_path = path.join("");
84 for name in CONFIG_FILE_NAMES {
85 config_path.set_file_name(name);
86 if config_path.is_file() {
87 return Some(config_path);
88 }
89 }
90
91 path = path.parent()?;
92 }
93}
94
95const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
96
97#[cfg(test)]
98mod test {
99 use super::*;
100
101 #[test]
102 fn max_width() {
103 assert_eq!(Config::default().max_width, 100);
104
105 let config: Config = toml::de::from_str("max_width = 80").unwrap();
106 assert_eq!(config.max_width, 80);
107 }
108
109 #[test]
110 fn array_width_uses_heuristics() {
111 let config = Config::default();
113 assert_eq!(config.array_width, None);
114 assert_eq!(config.array_width(), 60); let config: Config = toml::de::from_str("max_width = 80").unwrap();
117 assert_eq!(config.array_width(), 48); let config: Config = toml::de::from_str("max_width = 100\narray_width = 70").unwrap();
121 assert_eq!(config.array_width(), 70);
122 }
123
124 #[test]
125 fn use_small_heuristics_max() {
126 let config: Config =
127 toml::de::from_str("max_width = 100\nuse_small_heuristics = \"Max\"").unwrap();
128 assert_eq!(config.array_width(), 100); }
130
131 #[test]
132 fn use_small_heuristics_off() {
133 let config: Config =
134 toml::de::from_str("max_width = 100\nuse_small_heuristics = \"Off\"").unwrap();
135 assert_eq!(config.array_width(), 0); }
137}