prim_fmt/style.rs
1//! Resolved formatting style (FR-3): the single source of configuration the
2//! engine consumes. Built by `prim-cli` from `.editorconfig` and passed into
3//! [`crate::format`]. [`Style::default`] is prim's built-in canonical style
4//! (FR-3.1), applied when no `.editorconfig` is present.
5
6/// The line ending prim emits.
7#[derive(Debug, Clone, Copy, PartialEq, Eq)]
8pub enum LineEnding {
9 /// `\n` — prim's canonical default.
10 Lf,
11 /// `\r\n` — only when `.editorconfig` sets `end_of_line = crlf` (FR-2.3).
12 CrLf,
13}
14
15impl LineEnding {
16 /// The byte sequence for this line ending.
17 pub fn as_str(self) -> &'static str {
18 match self {
19 LineEnding::Lf => "\n",
20 LineEnding::CrLf => "\r\n",
21 }
22 }
23}
24
25/// Indentation unit. Carried for the per-format parsers (FR-1, #9–12); the
26/// whitespace-hygiene pass does not consume it.
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub enum Indent {
29 /// `indent_style = space` with the given `indent_size`.
30 Spaces(usize),
31 /// `indent_style = tab`.
32 Tab,
33}
34
35/// The resolved canonical style for one file.
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
37pub struct Style {
38 /// Line ending to emit (FR-2.3).
39 pub end_of_line: LineEnding,
40 /// Strip trailing whitespace from each line (FR-2.1).
41 pub trim_trailing_whitespace: bool,
42 /// When true, end content with exactly one final line ending; when false,
43 /// strip any final line ending (FR-2.2 / `insert_final_newline`).
44 pub insert_final_newline: bool,
45 /// Indentation unit (carried for FR-1 parsers; unused by hygiene).
46 pub indent: Indent,
47 /// Hard-wrap width (carried for FR-1 Markdown; unused by hygiene). `None`
48 /// means unset — the Markdown formatter falls back to 80.
49 pub max_line_length: Option<usize>,
50}
51
52impl Default for Style {
53 /// prim's built-in canonical style (FR-3.1): LF endings, trailing
54 /// whitespace stripped, exactly one final newline, two-space indent.
55 fn default() -> Self {
56 Style {
57 end_of_line: LineEnding::Lf,
58 trim_trailing_whitespace: true,
59 insert_final_newline: true,
60 indent: Indent::Spaces(2),
61 max_line_length: None,
62 }
63 }
64}
65
66#[cfg(test)]
67mod tests {
68 use super::*;
69
70 #[test]
71 fn default_is_the_canonical_style() {
72 let s = Style::default();
73 assert_eq!(s.end_of_line, LineEnding::Lf);
74 assert!(s.trim_trailing_whitespace);
75 assert!(s.insert_final_newline);
76 assert_eq!(s.indent, Indent::Spaces(2));
77 assert_eq!(s.max_line_length, None);
78 }
79
80 #[test]
81 fn line_ending_bytes() {
82 assert_eq!(LineEnding::Lf.as_str(), "\n");
83 assert_eq!(LineEnding::CrLf.as_str(), "\r\n");
84 }
85}