mago_formatter/
settings.rs

1use std::str::FromStr;
2
3use schemars::JsonSchema;
4use serde::Deserialize;
5use serde::Serialize;
6
7/// Format settings for the PHP printer.
8#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, JsonSchema)]
9#[serde(rename_all = "kebab-case", deny_unknown_fields)]
10pub struct FormatSettings {
11    /// Maximum line length that the printer will wrap on.
12    ///
13    /// Default: 120
14    #[serde(default = "default_print_width")]
15    pub print_width: usize,
16
17    /// Number of spaces per indentation level.
18    ///
19    /// Default: 4
20    #[serde(default = "default_tab_width")]
21    pub tab_width: usize,
22
23    /// Whether to use tabs instead of spaces for indentation.
24    ///
25    /// Default: false
26    #[serde(default = "default_false")]
27    pub use_tabs: bool,
28
29    /// End-of-line characters to use.
30    ///
31    /// Default: "lf"
32    #[serde(default)]
33    pub end_of_line: EndOfLine,
34
35    /// Whether to use single quotes instead of double quotes for strings.
36    ///
37    /// The formatter automatically determines which quotes to use based on the string content,
38    /// with a preference for single quotes if this option is enabled.
39    ///
40    /// Decision logic:
41    /// - If the string contains more single quotes than double quotes, double quotes are used
42    /// - If the string contains more double quotes than single quotes, single quotes are used
43    /// - If equal number of both, single quotes are used if this option is true
44    ///
45    /// Default: true
46    #[serde(default = "default_true")]
47    pub single_quote: bool,
48
49    /// Whether to add a trailing comma to the last element in multi-line syntactic structures.
50    ///
51    /// When enabled, trailing commas are added to lists, arrays, parameter lists,
52    /// argument lists, and other similar structures when they span multiple lines.
53    ///
54    /// Default: true
55    #[serde(default = "default_true")]
56    pub trailing_comma: bool,
57
58    /// Whether to remove the trailing PHP close tag (`?>`) from files.
59    ///
60    /// Default: true
61    #[serde(default = "default_true")]
62    pub remove_trailing_close_tag: bool,
63
64    /// Brace placement for control structures (if, for, while, etc.).
65    ///
66    /// Example with `same_line`:
67    /// ```php
68    /// if ($expr) {
69    ///     return 'Hello, world!';
70    /// }
71    /// ```
72    ///
73    /// Example with `next_line`:
74    /// ```php
75    /// if ($expr)
76    /// {
77    ///     return 'Hello, world!';
78    /// }
79    /// ```
80    ///
81    /// Default: `same_line`
82    #[serde(default = "BraceStyle::same_line")]
83    pub control_brace_style: BraceStyle,
84
85    /// Brace placement for closures.
86    ///
87    /// Example with `same_line`:
88    /// ```php
89    /// $closure = function() {
90    ///     return 'Hello, world!';
91    /// };
92    /// ```
93    ///
94    /// Example with `next_line`:
95    /// ```php
96    /// $closure = function()
97    /// {
98    ///     return 'Hello, world!';
99    /// };
100    /// ```
101    ///
102    /// Default: `same_line`
103    #[serde(default = "BraceStyle::same_line")]
104    pub closure_brace_style: BraceStyle,
105
106    /// Brace placement for function declarations.
107    ///
108    /// Example with `same_line`:
109    /// ```php
110    /// function foo() {
111    ///     return 'Hello, world!';
112    /// }
113    /// ```
114    ///
115    /// Example with `next_line`:
116    /// ```php
117    /// function foo()
118    /// {
119    ///     return 'Hello, world!';
120    /// }
121    /// ```
122    ///
123    /// Default: `next_line`
124    #[serde(default = "BraceStyle::next_line")]
125    pub function_brace_style: BraceStyle,
126
127    /// Brace placement for method declarations.
128    ///
129    /// Example with `same_line`:
130    /// ```php
131    /// class Foo
132    /// {
133    ///     public function bar() {
134    ///         return 'Hello, world!';
135    ///     }
136    /// }
137    /// ```
138    ///
139    /// Example with `next_line`:
140    /// ```php
141    /// class Foo
142    /// {
143    ///     public function bar()
144    ///     {
145    ///         return 'Hello, world!';
146    ///     }
147    /// }
148    /// ```
149    ///
150    /// Default: `next_line`
151    #[serde(default = "BraceStyle::next_line")]
152    pub method_brace_style: BraceStyle,
153
154    /// Brace placement for class-like structures (classes, interfaces, traits, enums).
155    ///
156    /// Example with `same_line`:
157    /// ```php
158    /// class Foo {
159    /// }
160    /// ```
161    ///
162    /// Example with `next_line`:
163    /// ```php
164    /// class Foo
165    /// {
166    /// }
167    /// ```
168    ///
169    /// Default: `next_line`
170    #[serde(default = "BraceStyle::next_line")]
171    pub classlike_brace_style: BraceStyle,
172
173    /// Place empty control structure bodies on the same line.
174    ///
175    /// Example with `false`:
176    /// ```php
177    /// if ($expr)
178    /// {
179    /// }
180    /// ```
181    ///
182    /// Example with `true`:
183    /// ```php
184    /// if ($expr) {}
185    /// ```
186    ///
187    /// Default: false
188    #[serde(default = "default_false")]
189    pub inline_empty_control_braces: bool,
190
191    /// Place empty closure bodies on the same line.
192    ///
193    /// Example with `false`:
194    /// ```php
195    /// $closure = function()
196    /// {
197    /// };
198    /// ```
199    ///
200    /// Example with `true`:
201    /// ```php
202    /// $closure = function() {};
203    /// ```
204    ///
205    /// Default: true
206    #[serde(default = "default_true")]
207    pub inline_empty_closure_braces: bool,
208
209    /// Place empty function bodies on the same line.
210    ///
211    /// Example with `false`:
212    /// ```php
213    /// function foo()
214    /// {
215    /// }
216    /// ```
217    ///
218    /// Example with `true`:
219    /// ```php
220    /// function foo() {}
221    /// ```
222    ///
223    /// Default: false
224    #[serde(default = "default_false")]
225    pub inline_empty_function_braces: bool,
226
227    /// Place empty method bodies on the same line.
228    ///
229    /// Example with `false`:
230    /// ```php
231    /// class Foo
232    /// {
233    ///     public function bar()
234    ///     {
235    ///     }
236    /// }
237    /// ```
238    ///
239    /// Example with `true`:
240    /// ```php
241    /// class Foo
242    /// {
243    ///     public function bar() {}
244    /// }
245    /// ```
246    ///
247    /// Default: false
248    #[serde(default = "default_false")]
249    pub inline_empty_method_braces: bool,
250
251    /// Place empty constructor bodies on the same line.
252    ///
253    /// Example with `false`:
254    /// ```php
255    /// class Foo {
256    ///     public function __construct()
257    ///     {
258    ///     }
259    /// }
260    /// ```
261    ///
262    /// Example with `true`:
263    /// ```php
264    /// class Foo {
265    ///     public function __construct() {}
266    /// }
267    /// ```
268    ///
269    /// Default: true
270    #[serde(default = "default_true")]
271    pub inline_empty_constructor_braces: bool,
272
273    /// Place empty class-like bodies on the same line.
274    ///
275    /// Example with `false`:
276    /// ```php
277    /// class Foo
278    /// {
279    /// }
280    /// ```
281    ///
282    /// Example with `true`:
283    /// ```php
284    /// class Foo {}
285    /// ```
286    ///
287    /// Default: true
288    #[serde(default = "default_true")]
289    pub inline_empty_classlike_braces: bool,
290
291    /// Place empty anonymous class bodies on the same line.
292    ///
293    /// Example with `false`:
294    /// ```php
295    /// $anon = new class
296    /// {
297    /// };
298    /// ```
299    ///
300    /// Example with `true`:
301    /// ```php
302    /// $anon = new class {};
303    /// ```
304    ///
305    /// Default: true
306    #[serde(default = "default_true")]
307    pub inline_empty_anonymous_class_braces: bool,
308
309    /// How to format broken method/property chains.
310    ///
311    /// When `next_line`, the first method/property starts on a new line:
312    /// ```php
313    /// $foo
314    ///     ->bar()
315    ///     ->baz();
316    /// ```
317    ///
318    /// When `same_line`, the first method/property stays on the same line:
319    /// ```php
320    /// $foo->bar()
321    ///     ->baz();
322    /// ```
323    ///
324    /// Default: `next_line`
325    #[serde(default)]
326    pub method_chain_breaking_style: MethodChainBreakingStyle,
327
328    /// When method chaining breaks across lines, place the first method on a new line.
329    ///
330    /// This follows PER-CS 4.7: "When [method chaining is] put on separate lines, [...] the first method MUST be on the next line."
331    ///
332    /// When enabled:
333    /// ```php
334    /// $this
335    ///     ->getCache()
336    ///     ->forget();
337    /// ```
338    ///
339    /// When disabled:
340    /// ```php
341    /// $this->getCache()
342    ///     ->forget();
343    /// ```
344    ///
345    /// Default: `true`
346    #[serde(default = "default_true")]
347    pub first_method_chain_on_new_line: bool,
348
349    /// Whether to preserve line breaks in method chains, even if they could fit on a single line.
350    ///
351    /// Default: false
352    #[serde(default = "default_false")]
353    pub preserve_breaking_member_access_chain: bool,
354
355    /// Whether to preserve line breaks in argument lists, even if they could fit on a single line.
356    ///
357    /// Default: false
358    #[serde(default = "default_false")]
359    pub preserve_breaking_argument_list: bool,
360
361    /// Whether to preserve line breaks in array-like structures, even if they could fit on a single line.
362    ///
363    /// Default: true
364    #[serde(default = "default_true")]
365    pub preserve_breaking_array_like: bool,
366
367    /// Whether to preserve line breaks in parameter lists, even if they could fit on a single line.
368    ///
369    /// Default: false
370    #[serde(default = "default_false")]
371    pub preserve_breaking_parameter_list: bool,
372
373    /// Whether to preserve line breaks in attribute lists, even if they could fit on a single line.
374    ///
375    /// Default: false
376    #[serde(default = "default_false")]
377    pub preserve_breaking_attribute_list: bool,
378
379    /// Whether to preserve line breaks in conditional (ternary) expressions.
380    ///
381    /// Default: false
382    #[serde(default = "default_false")]
383    pub preserve_breaking_conditional_expression: bool,
384
385    /// Whether to break a parameter list with one or more promoted properties into multiple lines.
386    ///
387    /// When enabled, parameter lists with promoted properties are always multi-line:
388    /// ```php
389    /// class User {
390    ///     public function __construct(
391    ///         public string $name,
392    ///         public string $email,
393    ///     ) {}
394    /// }
395    /// ```
396    ///
397    /// When disabled, they may be kept on a single line if space allows:
398    /// ```php
399    /// class User {
400    ///     public function __construct(public string $name, public string $email) {}
401    /// }
402    /// ```
403    ///
404    /// Default: true
405    #[serde(default = "default_true")]
406    pub break_promoted_properties_list: bool,
407
408    /// Whether to add a line before binary operators or after when breaking.
409    ///
410    /// When true:
411    /// ```php
412    /// $foo = 'Hello, '
413    ///     . 'world!';
414    /// ```
415    ///
416    /// When false:
417    /// ```php
418    /// $foo = 'Hello, ' .
419    ///     'world!';
420    /// ```
421    ///
422    /// Note: If the right side has a leading comment, this setting is always false.
423    ///
424    /// Default: true
425    #[serde(default = "default_true")]
426    pub line_before_binary_operator: bool,
427
428    /// Whether to always break named argument lists into multiple lines.
429    ///
430    /// When enabled:
431    /// ```php
432    /// $foo = some_function(
433    ///     argument1: 'value1',
434    ///     argument2: 'value2',
435    /// );
436    /// ```
437    ///
438    /// Default: false
439    #[serde(default = "default_false")]
440    pub always_break_named_arguments_list: bool,
441
442    /// Whether to always break named argument lists in attributes into multiple lines.
443    ///
444    /// When enabled:
445    /// ```php
446    /// #[SomeAttribute(
447    ///     argument1: 'value1',
448    ///     argument2: 'value2',
449    /// )]
450    /// class Foo {}
451    /// ```
452    ///
453    /// Default: false
454    #[serde(default = "default_false")]
455    pub always_break_attribute_named_argument_lists: bool,
456
457    /// Whether to use table-style alignment for arrays.
458    ///
459    /// When enabled, array elements are aligned in a table-like format:
460    /// ```php
461    /// $array = [
462    ///     ['foo',  1.2,  123, false],
463    ///     ['bar',  52.4, 456, true],
464    ///     ['baz',  3.6,  789, false],
465    ///     ['qux',  4.8,    1, true],
466    ///     ['quux', 5.0,   12, false],
467    /// ];
468    /// ```
469    ///
470    /// Default: true
471    #[serde(default = "default_true")]
472    pub array_table_style_alignment: bool,
473
474    /// Whether to align consecutive assignment-like constructs in columns.
475    ///
476    /// When enabled, consecutive variable assignments, class properties, class constants,
477    /// global constants, array key-value pairs, and backed enum cases are column-aligned.
478    ///
479    /// Example with `true`:
480    /// ```php
481    /// $foo     = 1;
482    /// $b       = 2;
483    /// $ccccccc = 3;
484    ///
485    /// class X {
486    ///     public string       $foo    = 1;
487    ///     public readonly int $barrrr = 2;
488    /// }
489    /// ```
490    ///
491    /// Example with `false`:
492    /// ```php
493    /// $foo = 1;
494    /// $b = 2;
495    /// $ccccccc = 3;
496    /// ```
497    ///
498    /// Note: Blank lines and comments break alignment runs. In class bodies,
499    /// different member types (properties vs constants) are aligned separately.
500    ///
501    /// Default: false
502    #[serde(default = "default_false")]
503    pub align_assignment_like: bool,
504
505    /// Whether to sort use statements alphabetically.
506    ///
507    /// Default: true
508    #[serde(default = "default_true")]
509    pub sort_uses: bool,
510
511    /// Whether to sort class methods by visibility and name.
512    ///
513    /// When enabled, methods in class-like structures are automatically reordered:
514    /// 1. Constructor (`__construct`) - always first
515    /// 2. Static methods (by visibility: public, protected, private)
516    ///    - Abstract methods before concrete methods
517    ///    - Alphabetically by name within each group
518    /// 3. Instance methods (by visibility: public, protected, private)
519    ///    - Abstract methods before concrete methods
520    ///    - Alphabetically by name within each group
521    /// 4. Other magic methods (e.g., `__toString`, `__get`, `__set`)
522    ///    - Sorted alphabetically by name
523    /// 5. Destructor (`__destruct`) - always last
524    ///
525    /// This applies to all class-like structures: classes, traits, interfaces, and enums.
526    /// Other members (constants, properties, trait uses, enum cases) remain in their original positions.
527    ///
528    /// Default: false
529    #[serde(default = "default_false")]
530    pub sort_class_methods: bool,
531
532    /// Whether to insert a blank line between different types of use statements.
533    ///
534    /// When enabled:
535    /// ```php
536    /// use Foo\Bar;
537    /// use Foo\Baz;
538    ///
539    /// use function Foo\bar;
540    /// use function Foo\baz;
541    ///
542    /// use const Foo\A;
543    /// use const Foo\B;
544    /// ```
545    ///
546    /// When disabled:
547    /// ```php
548    /// use Foo\Bar;
549    /// use Foo\Baz;
550    /// use function Foo\bar;
551    /// use function Foo\baz;
552    /// use const Foo\A;
553    /// use const Foo\B;
554    /// ```
555    ///
556    /// Default: true
557    #[serde(default = "default_true")]
558    pub separate_use_types: bool,
559
560    /// Whether to expand grouped use statements into individual statements.
561    ///
562    /// When enabled:
563    /// ```php
564    /// use Foo\Bar;
565    /// use Foo\Baz;
566    /// ```
567    ///
568    /// When disabled:
569    /// ```php
570    /// use Foo\{Bar, Baz};
571    /// ```
572    ///
573    /// Default: true
574    #[serde(default = "default_true")]
575    pub expand_use_groups: bool,
576
577    /// How to format null type hints.
578    ///
579    /// With `Question`:
580    /// ```php
581    /// function foo(?string $bar) {
582    ///     return $bar;
583    /// }
584    /// ```
585    ///
586    /// With `NullPipe`:
587    /// ```php
588    /// function foo(null|string $bar) {
589    ///     return $bar;
590    /// }
591    /// ```
592    ///
593    /// Default: `Question`
594    #[serde(default)]
595    pub null_type_hint: NullTypeHint,
596
597    /// Whether to include parentheses around `new` when followed by a member access.
598    ///
599    /// Controls whether to use PHP 8.4's shorthand syntax for new expressions
600    /// followed by member access. If PHP version is earlier than 8.4, this is always true.
601    ///
602    /// When enabled:
603    /// ```php
604    /// $foo = (new Foo)->bar();
605    /// ```
606    ///
607    /// When disabled (PHP 8.4+ only):
608    /// ```php
609    /// $foo = new Foo->bar();
610    /// ```
611    ///
612    /// Default: false
613    #[serde(default = "default_false")]
614    pub parentheses_around_new_in_member_access: bool,
615
616    /// Whether to include parentheses in `new` expressions when no arguments are provided.
617    ///
618    /// When enabled:
619    /// ```php
620    /// $foo = new Foo();
621    /// ```
622    ///
623    /// When disabled:
624    /// ```php
625    /// $foo = new Foo;
626    /// ```
627    ///
628    /// Default: true
629    #[serde(default = "default_true")]
630    pub parentheses_in_new_expression: bool,
631
632    /// Whether to include parentheses in `exit` and `die` constructs.
633    ///
634    /// When enabled:
635    /// ```php
636    /// exit();
637    /// die();
638    /// ```
639    ///
640    /// When disabled:
641    /// ```php
642    /// exit;
643    /// die;
644    /// ```
645    ///
646    /// Default: true
647    #[serde(default = "default_true")]
648    pub parentheses_in_exit_and_die: bool,
649
650    /// Whether to include parentheses in attributes with no arguments.
651    ///
652    /// When enabled:
653    /// ```php
654    /// #[SomeAttribute()]
655    /// class Foo {}
656    /// ```
657    ///
658    /// When disabled:
659    /// ```php
660    /// #[SomeAttribute]
661    /// class Foo {}
662    /// ```
663    ///
664    /// Default: false
665    #[serde(default = "default_false")]
666    pub parentheses_in_attribute: bool,
667
668    /// Whether to add a space before the opening parameters in arrow functions.
669    ///
670    /// When enabled: `fn ($x) => $x * 2`
671    /// When disabled: `fn($x) => $x * 2`
672    ///
673    /// Default: false
674    #[serde(default = "default_false")]
675    pub space_before_arrow_function_parameter_list_parenthesis: bool,
676
677    /// Whether to add a space before the opening parameters in closures.
678    ///
679    /// When enabled: `function ($x) use ($y)`
680    /// When disabled: `function($x) use ($y)`
681    ///
682    /// Default: true
683    #[serde(default = "default_true")]
684    pub space_before_closure_parameter_list_parenthesis: bool,
685
686    /// Whether to add a space before the opening parameters in hooks.
687    ///
688    /// When enabled: `$hook ($param)`
689    /// When disabled: `$hook($param)`
690    ///
691    /// Default: false
692    #[serde(default = "default_false")]
693    pub space_before_hook_parameter_list_parenthesis: bool,
694
695    /// Whether to add a space before the opening parenthesis in closure use clause.
696    ///
697    /// When enabled: `function() use ($var)`
698    /// When disabled: `function() use($var)`
699    ///
700    /// Default: true
701    #[serde(default = "default_true")]
702    pub space_before_closure_use_clause_parenthesis: bool,
703
704    /// Whether to add a space after cast operators (int, float, string, etc.).
705    ///
706    /// When enabled: `(int) $foo`
707    /// When disabled: `(int)$foo`
708    ///
709    /// Default: true
710    #[serde(default = "default_true")]
711    pub space_after_cast_unary_prefix_operators: bool,
712
713    /// Whether to add a space after the reference operator (&).
714    ///
715    /// When enabled: `& $foo`
716    /// When disabled: `&$foo`
717    ///
718    /// Default: false
719    #[serde(default = "default_false")]
720    pub space_after_reference_unary_prefix_operator: bool,
721
722    /// Whether to add a space after the error control operator (@).
723    ///
724    /// When enabled: `@ $foo`
725    /// When disabled: `@$foo`
726    ///
727    /// Default: false
728    #[serde(default = "default_false")]
729    pub space_after_error_control_unary_prefix_operator: bool,
730
731    /// Whether to add a space after the logical not operator (!).
732    ///
733    /// When enabled: `! $foo`
734    /// When disabled: `!$foo`
735    ///
736    /// Default: false
737    #[serde(default = "default_false")]
738    pub space_after_logical_not_unary_prefix_operator: bool,
739
740    /// Whether to add a space after the bitwise not operator (~).
741    ///
742    /// When enabled: `~ $foo`
743    /// When disabled: `~$foo`
744    ///
745    /// Default: false
746    #[serde(default = "default_false")]
747    pub space_after_bitwise_not_unary_prefix_operator: bool,
748
749    /// Whether to add a space after the increment prefix operator (++).
750    ///
751    /// When enabled: `++ $i`
752    /// When disabled: `++$i`
753    ///
754    /// Default: false
755    #[serde(default = "default_false")]
756    pub space_after_increment_unary_prefix_operator: bool,
757
758    /// Whether to add a space after the decrement prefix operator (--).
759    ///
760    /// When enabled: `-- $i`
761    /// When disabled: `--$i`
762    ///
763    /// Default: false
764    #[serde(default = "default_false")]
765    pub space_after_decrement_unary_prefix_operator: bool,
766
767    /// Whether to add a space after the additive unary operators (+ and -).
768    ///
769    /// When enabled: `+ $i`
770    /// When disabled: `+$i`
771    ///
772    /// Default: false
773    #[serde(default = "default_false")]
774    pub space_after_additive_unary_prefix_operator: bool,
775
776    /// Whether to add spaces around the concatenation operator (.)
777    ///
778    /// When enabled: `$a . $b`
779    /// When disabled: `$a.$b`
780    ///
781    /// Default: true
782    #[serde(default = "default_true")]
783    pub space_around_concatenation_binary_operator: bool,
784
785    /// Whether to add spaces around the assignment in declare statements.
786    ///
787    /// When enabled: `declare(strict_types = 1)`
788    /// When disabled: `declare(strict_types=1)`
789    ///
790    /// Default: false
791    #[serde(default = "default_false")]
792    pub space_around_assignment_in_declare: bool,
793
794    /// Whether to add spaces within grouping parentheses.
795    ///
796    /// When enabled: `( $expr ) - $expr`
797    /// When disabled: `($expr) - $expr`
798    ///
799    /// Default: false
800    #[serde(default = "default_false")]
801    pub space_within_grouping_parenthesis: bool,
802
803    /// Whether to add an empty line after control structures (if, for, foreach, while, do, switch).
804    ///
805    /// Note: if an empty line already exists, it will be preserved regardless of this
806    /// settings value.
807    ///
808    /// Default: false
809    #[serde(default = "default_false")]
810    pub empty_line_after_control_structure: bool,
811
812    /// Whether to add an empty line after opening tag.
813    ///
814    /// Note: if an empty line already exists, it will be preserved regardless of this
815    /// settings value.
816    ///
817    /// Default: true
818    #[serde(default = "default_true")]
819    pub empty_line_after_opening_tag: bool,
820
821    /// Whether to add an empty line after declare statement.
822    ///
823    /// Note: if an empty line already exists, it will be preserved regardless of this
824    /// settings value.
825    ///
826    /// Default: true
827    #[serde(default = "default_true")]
828    pub empty_line_after_declare: bool,
829
830    /// Whether to add an empty line after namespace.
831    ///
832    /// Note: if an empty line already exists, it will be preserved regardless of this
833    /// settings value.
834    ///
835    /// Default: true
836    #[serde(default = "default_true")]
837    pub empty_line_after_namespace: bool,
838
839    /// Whether to add an empty line after use statements.
840    ///
841    /// Note: if an empty line already exists, it will be preserved regardless of this
842    /// settings value.
843    ///
844    /// Default: true
845    #[serde(default = "default_true")]
846    pub empty_line_after_use: bool,
847
848    /// Whether to add an empty line after symbols (class, enum, interface, trait, function, const).
849    ///
850    /// Note: if an empty line already exists, it will be preserved regardless of this
851    /// settings value.
852    ///
853    /// Default: true
854    #[serde(default = "default_true")]
855    pub empty_line_after_symbols: bool,
856
857    /// Whether to add an empty line between consecutive symbols of the same type.
858    ///
859    /// Only applies when `empty_line_after_symbols` is true.
860    ///
861    /// Default: true
862    #[serde(default = "default_true")]
863    pub empty_line_between_same_symbols: bool,
864
865    /// Whether to add an empty line after class-like constant.
866    ///
867    /// Note: if an empty line already exists, it will be preserved regardless of this
868    /// settings value.
869    ///
870    /// Default: false
871    #[serde(default = "default_false")]
872    pub empty_line_after_class_like_constant: bool,
873
874    /// Whether to add an empty line after enum case.
875    ///
876    /// Note: if an empty line already exists, it will be preserved regardless of this
877    /// settings value.
878    ///
879    /// Default: false
880    #[serde(default = "default_false")]
881    pub empty_line_after_enum_case: bool,
882
883    /// Whether to add an empty line after trait use.
884    ///
885    /// Note: if an empty line already exists, it will be preserved regardless of this
886    /// settings value.
887    ///
888    /// Default: false
889    #[serde(default = "default_false")]
890    pub empty_line_after_trait_use: bool,
891
892    /// Whether to add an empty line after property.
893    ///
894    /// Note: if an empty line already exists, it will be preserved regardless of this
895    /// settings value.
896    ///
897    /// Default: false
898    #[serde(default = "default_false")]
899    pub empty_line_after_property: bool,
900
901    /// Whether to add an empty line after method.
902    ///
903    /// Note: if an empty line already exists, it will be preserved regardless of this
904    /// settings value.
905    ///
906    /// Default: true
907    #[serde(default = "default_true")]
908    pub empty_line_after_method: bool,
909
910    /// Whether to add an empty line before return statements.
911    ///
912    /// Default: false
913    #[serde(default = "default_false")]
914    pub empty_line_before_return: bool,
915
916    /// Whether to add an empty line before dangling comments.
917    ///
918    /// Default: true
919    #[serde(default = "default_true")]
920    pub empty_line_before_dangling_comments: bool,
921
922    /// Whether to separate class-like members of different kinds with a blank line.
923    ///
924    /// Default: true
925    #[serde(default = "default_true")]
926    pub separate_class_like_members: bool,
927}
928
929impl Default for FormatSettings {
930    /// Sets default values to align with best practices.
931    fn default() -> Self {
932        Self {
933            print_width: default_print_width(),
934            tab_width: default_tab_width(),
935            use_tabs: false,
936            end_of_line: EndOfLine::default(),
937            single_quote: true,
938            trailing_comma: true,
939            closure_brace_style: BraceStyle::SameLine,
940            function_brace_style: BraceStyle::NextLine,
941            method_brace_style: BraceStyle::NextLine,
942            classlike_brace_style: BraceStyle::NextLine,
943            control_brace_style: BraceStyle::SameLine,
944            inline_empty_control_braces: false,
945            inline_empty_closure_braces: true,
946            inline_empty_function_braces: false,
947            inline_empty_method_braces: false,
948            inline_empty_constructor_braces: true,
949            inline_empty_classlike_braces: true,
950            inline_empty_anonymous_class_braces: true,
951            null_type_hint: NullTypeHint::default(),
952            break_promoted_properties_list: true,
953            method_chain_breaking_style: MethodChainBreakingStyle::NextLine,
954            first_method_chain_on_new_line: true,
955            line_before_binary_operator: true,
956            sort_uses: true,
957            sort_class_methods: false,
958            separate_use_types: true,
959            expand_use_groups: true,
960            remove_trailing_close_tag: true,
961            parentheses_around_new_in_member_access: false,
962            parentheses_in_new_expression: true,
963            parentheses_in_exit_and_die: true,
964            parentheses_in_attribute: false,
965            array_table_style_alignment: true,
966            align_assignment_like: false,
967            always_break_named_arguments_list: false,
968            always_break_attribute_named_argument_lists: false,
969            preserve_breaking_member_access_chain: false,
970            preserve_breaking_argument_list: false,
971            preserve_breaking_array_like: true,
972            preserve_breaking_parameter_list: false,
973            preserve_breaking_attribute_list: false,
974            preserve_breaking_conditional_expression: false,
975            space_before_arrow_function_parameter_list_parenthesis: false,
976            space_before_closure_parameter_list_parenthesis: true,
977            space_before_closure_use_clause_parenthesis: true,
978            space_around_assignment_in_declare: false,
979            space_within_grouping_parenthesis: false,
980            space_before_hook_parameter_list_parenthesis: false,
981            space_around_concatenation_binary_operator: true,
982            space_after_cast_unary_prefix_operators: true,
983            space_after_reference_unary_prefix_operator: false,
984            space_after_error_control_unary_prefix_operator: false,
985            space_after_logical_not_unary_prefix_operator: false,
986            space_after_bitwise_not_unary_prefix_operator: false,
987            space_after_increment_unary_prefix_operator: false,
988            space_after_decrement_unary_prefix_operator: false,
989            space_after_additive_unary_prefix_operator: false,
990            empty_line_after_control_structure: false,
991            empty_line_after_opening_tag: true,
992            empty_line_after_declare: true,
993            empty_line_after_namespace: true,
994            empty_line_after_use: true,
995            empty_line_after_symbols: true,
996            empty_line_between_same_symbols: true,
997            empty_line_after_class_like_constant: false,
998            empty_line_after_enum_case: false,
999            empty_line_after_trait_use: false,
1000            empty_line_after_property: false,
1001            empty_line_after_method: true,
1002            empty_line_before_return: false,
1003            empty_line_before_dangling_comments: true,
1004            separate_class_like_members: true,
1005        }
1006    }
1007}
1008
1009#[cfg(test)]
1010mod tests {
1011    use super::*;
1012
1013    #[test]
1014    fn consistent_default() {
1015        let default_settings = FormatSettings::default();
1016        let default_deserialized: FormatSettings = serde_json::from_str("{}").unwrap();
1017        assert_eq!(default_settings, default_deserialized);
1018    }
1019}
1020
1021/// Specifies the style of line endings.
1022#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, JsonSchema)]
1023pub enum EndOfLine {
1024    #[default]
1025    #[serde(alias = "auto")]
1026    Auto,
1027    #[serde(alias = "lf")]
1028    Lf,
1029    #[serde(alias = "crlf")]
1030    Crlf,
1031    #[serde(alias = "cr")]
1032    Cr,
1033}
1034
1035/// Specifies the style of line endings.
1036#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, JsonSchema)]
1037pub enum BraceStyle {
1038    #[serde(alias = "same_line")]
1039    SameLine,
1040    #[serde(alias = "next_line")]
1041    NextLine,
1042}
1043
1044#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, JsonSchema)]
1045pub enum MethodChainBreakingStyle {
1046    #[serde(alias = "same_line")]
1047    SameLine,
1048    #[default]
1049    #[serde(alias = "next_line")]
1050    NextLine,
1051}
1052
1053impl BraceStyle {
1054    #[must_use]
1055    pub fn same_line() -> Self {
1056        Self::SameLine
1057    }
1058
1059    #[must_use]
1060    pub fn next_line() -> Self {
1061        Self::NextLine
1062    }
1063
1064    #[inline]
1065    #[must_use]
1066    pub fn is_next_line(&self) -> bool {
1067        *self == Self::NextLine
1068    }
1069}
1070
1071impl MethodChainBreakingStyle {
1072    #[inline]
1073    #[must_use]
1074    pub fn is_next_line(&self) -> bool {
1075        *self == Self::NextLine
1076    }
1077}
1078
1079impl EndOfLine {
1080    #[inline]
1081    #[must_use]
1082    pub const fn as_str(&self) -> &'static str {
1083        match self {
1084            Self::Crlf => "\r\n",
1085            Self::Cr => "\r",
1086            Self::Lf | Self::Auto => "\n",
1087        }
1088    }
1089}
1090
1091impl FromStr for EndOfLine {
1092    type Err = ();
1093
1094    fn from_str(s: &str) -> Result<Self, Self::Err> {
1095        Ok(match s {
1096            "crlf" => Self::Crlf,
1097            "cr" => Self::Cr,
1098            "auto" => Self::Auto,
1099            "lf" => Self::Lf,
1100            _ => Self::default(),
1101        })
1102    }
1103}
1104
1105/// Specifies null type hint style.
1106#[derive(Default, Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord, JsonSchema)]
1107pub enum NullTypeHint {
1108    #[serde(alias = "null_pipe", alias = "pipe", alias = "long", alias = "|")]
1109    NullPipe,
1110    #[default]
1111    #[serde(alias = "question", alias = "short", alias = "?")]
1112    Question,
1113}
1114
1115impl NullTypeHint {
1116    #[must_use]
1117    pub fn is_question(&self) -> bool {
1118        *self == Self::Question
1119    }
1120}
1121
1122fn default_print_width() -> usize {
1123    120
1124}
1125
1126fn default_tab_width() -> usize {
1127    4
1128}
1129
1130fn default_false() -> bool {
1131    false
1132}
1133
1134fn default_true() -> bool {
1135    true
1136}