foundry_config/
fmt.rs

1//! Configuration specific to the `forge fmt` command and the `forge_fmt` package
2
3use serde::{Deserialize, Serialize};
4
5/// Contains the config and rule set
6#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
7pub struct FormatterConfig {
8    /// Maximum line length where formatter will try to wrap the line
9    pub line_length: usize,
10    /// Number of spaces per indentation level. Ignored if style is Tab
11    pub tab_width: usize,
12    /// Style of indent
13    pub style: IndentStyle,
14    /// Print spaces between brackets
15    pub bracket_spacing: bool,
16    /// Style of uint/int256 types
17    pub int_types: IntTypes,
18    /// Style of multiline function header in case it doesn't fit
19    pub multiline_func_header: MultilineFuncHeaderStyle,
20    /// Style of quotation marks
21    pub quote_style: QuoteStyle,
22    /// Style of underscores in number literals
23    pub number_underscore: NumberUnderscore,
24    /// Style of underscores in hex literals
25    pub hex_underscore: HexUnderscore,
26    /// Style of single line blocks in statements
27    pub single_line_statement_blocks: SingleLineBlockStyle,
28    /// Print space in state variable, function and modifier `override` attribute
29    pub override_spacing: bool,
30    /// Wrap comments on `line_length` reached
31    pub wrap_comments: bool,
32    /// Style of doc comments
33    pub docs_style: DocCommentStyle,
34    /// Globs to ignore
35    pub ignore: Vec<String>,
36    /// Add new line at start and end of contract declarations
37    pub contract_new_lines: bool,
38    /// Sort import statements alphabetically in groups (a group is separated by a newline).
39    pub sort_imports: bool,
40    /// Choose between `import "a" as name` and `import * as name from "a"`
41    pub namespace_import_style: NamespaceImportStyle,
42    /// Whether to suppress spaces around the power operator (`**`).
43    pub pow_no_space: bool,
44    /// Style that determines if a broken list, should keep its elements together on their own
45    /// line, before breaking individually.
46    pub prefer_compact: PreferCompact,
47    /// Keep single imports on a single line even if they exceed line length.
48    pub single_line_imports: bool,
49}
50
51/// Style of integer types.
52#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
53#[serde(rename_all = "snake_case")]
54pub enum IntTypes {
55    /// Use the type defined in the source code.
56    Preserve,
57    /// Print the full length `uint256` or `int256`.
58    #[default]
59    Long,
60    /// Print the alias `uint` or `int`.
61    Short,
62}
63
64/// Style of underscores in number literals
65#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub enum NumberUnderscore {
68    /// Use the underscores defined in the source code
69    #[default]
70    Preserve,
71    /// Remove all underscores
72    Remove,
73    /// Add an underscore every thousand, if greater than 9999
74    /// e.g. 1000 -> 1000 and 10000 -> 10_000
75    Thousands,
76}
77
78impl NumberUnderscore {
79    /// Returns true if the option is `Preserve`
80    #[inline]
81    pub fn is_preserve(self) -> bool {
82        matches!(self, Self::Preserve)
83    }
84
85    /// Returns true if the option is `Remove`
86    #[inline]
87    pub fn is_remove(self) -> bool {
88        matches!(self, Self::Remove)
89    }
90
91    /// Returns true if the option is `Remove`
92    #[inline]
93    pub fn is_thousands(self) -> bool {
94        matches!(self, Self::Thousands)
95    }
96}
97
98/// Style of underscores in hex literals
99#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
100#[serde(rename_all = "snake_case")]
101pub enum HexUnderscore {
102    /// Use the underscores defined in the source code
103    Preserve,
104    /// Remove all underscores
105    #[default]
106    Remove,
107    /// Add underscore as separator between byte boundaries
108    Bytes,
109}
110
111/// Style of doc comments
112#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
113#[serde(rename_all = "snake_case")]
114pub enum DocCommentStyle {
115    /// Preserve the source code style
116    #[default]
117    Preserve,
118    /// Use single-line style (`///`)
119    Line,
120    /// Use block style (`/** .. */`)
121    Block,
122}
123
124/// Style of string quotes
125#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
126#[serde(rename_all = "snake_case")]
127pub enum QuoteStyle {
128    /// Use quotation mark defined in the source code.
129    Preserve,
130    /// Use double quotes where possible.
131    #[default]
132    Double,
133    /// Use single quotes where possible.
134    Single,
135}
136
137impl QuoteStyle {
138    /// Returns the associated quotation mark character.
139    pub const fn quote(self) -> Option<char> {
140        match self {
141            Self::Preserve => None,
142            Self::Double => Some('"'),
143            Self::Single => Some('\''),
144        }
145    }
146}
147
148/// Style of single line blocks in statements
149#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
150#[serde(rename_all = "snake_case")]
151pub enum SingleLineBlockStyle {
152    /// Preserve the original style
153    #[default]
154    Preserve,
155    /// Prefer single line block when possible
156    Single,
157    /// Always use multiline block
158    Multi,
159}
160
161/// Style of function header in case it doesn't fit
162#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
163#[serde(rename_all = "snake_case")]
164pub enum MultilineFuncHeaderStyle {
165    /// Always write function parameters multiline.
166    #[serde(alias = "params_first")] // alias for backwards compatibility
167    ParamsAlways,
168    /// Write function parameters multiline first when there is more than one param.
169    ParamsFirstMulti,
170    /// Write function attributes multiline first.
171    #[default]
172    AttributesFirst,
173    /// If function params or attrs are multiline.
174    /// split the rest
175    All,
176    /// Same as `All` but writes function params multiline even when there is a single param.
177    AllParams,
178}
179
180impl MultilineFuncHeaderStyle {
181    pub fn all(&self) -> bool {
182        matches!(self, Self::All | Self::AllParams)
183    }
184
185    pub fn params_first(&self) -> bool {
186        matches!(self, Self::ParamsAlways | Self::ParamsFirstMulti)
187    }
188
189    pub fn attrib_first(&self) -> bool {
190        matches!(self, Self::AttributesFirst)
191    }
192}
193
194#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
195#[serde(rename_all = "snake_case")]
196pub enum NamespaceImportStyle {
197    /// prefer plain imports: `import "source" as name;`
198    #[default]
199    PreferPlain,
200    /// prefer glob imports: `import * as name from "source";`
201    PreferGlob,
202    /// preserve the original style
203    Preserve,
204}
205
206/// Style that determines if a broken list, should keep its elements together on their own line,
207/// before breaking individually.
208#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
209#[serde(rename_all = "snake_case")]
210pub enum PreferCompact {
211    /// All elements are preferred consistent.
212    None,
213    /// Calls are preferred compact. Events and errors break consistently.
214    Calls,
215    /// Events are preferred compact. Calls and errors break consistently.
216    Events,
217    /// Errors are preferred compact. Calls and events break consistently.
218    Errors,
219    /// Events and errors are preferred compact. Calls break consistently.
220    EventsErrors,
221    /// All elements are preferred compact.
222    #[default]
223    All,
224}
225
226impl PreferCompact {
227    pub fn calls(&self) -> bool {
228        matches!(self, Self::All | Self::Calls)
229    }
230
231    pub fn events(&self) -> bool {
232        matches!(self, Self::All | Self::Events | Self::EventsErrors)
233    }
234
235    pub fn errors(&self) -> bool {
236        matches!(self, Self::All | Self::Errors | Self::EventsErrors)
237    }
238}
239
240/// Style of indent
241#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
242#[serde(rename_all = "snake_case")]
243pub enum IndentStyle {
244    #[default]
245    Space,
246    Tab,
247}
248
249impl Default for FormatterConfig {
250    fn default() -> Self {
251        Self {
252            line_length: 120,
253            tab_width: 4,
254            style: IndentStyle::Space,
255            bracket_spacing: false,
256            int_types: IntTypes::default(),
257            multiline_func_header: MultilineFuncHeaderStyle::default(),
258            quote_style: QuoteStyle::default(),
259            number_underscore: NumberUnderscore::default(),
260            hex_underscore: HexUnderscore::default(),
261            single_line_statement_blocks: SingleLineBlockStyle::default(),
262            override_spacing: false,
263            wrap_comments: false,
264            ignore: vec![],
265            contract_new_lines: false,
266            sort_imports: false,
267            namespace_import_style: NamespaceImportStyle::default(),
268            pow_no_space: false,
269            prefer_compact: PreferCompact::default(),
270            docs_style: DocCommentStyle::default(),
271            single_line_imports: false,
272        }
273    }
274}