Skip to main content

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}