links_notation/
format_config.rs

1/// FormatConfig for Lino notation formatting.
2///
3/// Provides configuration options for controlling how Link objects are formatted.
4#[derive(Debug, Clone)]
5pub struct FormatConfig {
6    /// If true, omit parentheses where safe (default: false)
7    pub less_parentheses: bool,
8
9    /// Maximum line length before auto-indenting (default: 80)
10    pub max_line_length: usize,
11
12    /// If true, indent lines exceeding max_line_length (default: false)
13    pub indent_long_lines: bool,
14
15    /// Maximum number of references before auto-indenting (default: None = unlimited)
16    pub max_inline_refs: Option<usize>,
17
18    /// If true, group consecutive links with same ID (default: false)
19    pub group_consecutive: bool,
20
21    /// String to use for indentation (default: "  " = two spaces)
22    pub indent_string: String,
23
24    /// If true, prefer inline format when under thresholds (default: true)
25    pub prefer_inline: bool,
26}
27
28impl Default for FormatConfig {
29    fn default() -> Self {
30        Self {
31            less_parentheses: false,
32            max_line_length: 80,
33            indent_long_lines: false,
34            max_inline_refs: None,
35            group_consecutive: false,
36            indent_string: "  ".to_string(),
37            prefer_inline: true,
38        }
39    }
40}
41
42impl FormatConfig {
43    /// Create a new FormatConfig with default values
44    pub fn new() -> Self {
45        Self::default()
46    }
47
48    /// Create a new FormatConfig with custom values using builder pattern
49    pub fn builder() -> FormatConfigBuilder {
50        FormatConfigBuilder::new()
51    }
52
53    /// Check if line should be indented based on length.
54    ///
55    /// # Arguments
56    /// * `line` - The line to check
57    ///
58    /// # Returns
59    /// True if line should be indented based on length threshold
60    pub fn should_indent_by_length(&self, line: &str) -> bool {
61        if !self.indent_long_lines {
62            return false;
63        }
64        // Count characters
65        line.chars().count() > self.max_line_length
66    }
67
68    /// Check if link should be indented based on reference count.
69    ///
70    /// # Arguments
71    /// * `ref_count` - Number of references in the link
72    ///
73    /// # Returns
74    /// True if link should be indented based on reference count threshold
75    pub fn should_indent_by_ref_count(&self, ref_count: usize) -> bool {
76        match self.max_inline_refs {
77            None => false,
78            Some(max) => ref_count > max,
79        }
80    }
81}
82
83/// Builder for FormatConfig
84pub struct FormatConfigBuilder {
85    config: FormatConfig,
86}
87
88impl FormatConfigBuilder {
89    pub fn new() -> Self {
90        Self {
91            config: FormatConfig::default(),
92        }
93    }
94
95    pub fn less_parentheses(mut self, value: bool) -> Self {
96        self.config.less_parentheses = value;
97        self
98    }
99
100    pub fn max_line_length(mut self, value: usize) -> Self {
101        self.config.max_line_length = value;
102        self
103    }
104
105    pub fn indent_long_lines(mut self, value: bool) -> Self {
106        self.config.indent_long_lines = value;
107        self
108    }
109
110    pub fn max_inline_refs(mut self, value: Option<usize>) -> Self {
111        self.config.max_inline_refs = value;
112        self
113    }
114
115    pub fn group_consecutive(mut self, value: bool) -> Self {
116        self.config.group_consecutive = value;
117        self
118    }
119
120    pub fn indent_string(mut self, value: String) -> Self {
121        self.config.indent_string = value;
122        self
123    }
124
125    pub fn prefer_inline(mut self, value: bool) -> Self {
126        self.config.prefer_inline = value;
127        self
128    }
129
130    pub fn build(self) -> FormatConfig {
131        self.config
132    }
133}
134
135impl Default for FormatConfigBuilder {
136    fn default() -> Self {
137        Self::new()
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    #[test]
146    fn test_default_values() {
147        let config = FormatConfig::default();
148        assert!(!config.less_parentheses);
149        assert_eq!(config.max_line_length, 80);
150        assert!(!config.indent_long_lines);
151    }
152
153    #[test]
154    fn test_builder() {
155        let config = FormatConfig::builder()
156            .less_parentheses(true)
157            .max_line_length(100)
158            .build();
159
160        assert!(config.less_parentheses);
161        assert_eq!(config.max_line_length, 100);
162    }
163
164    #[test]
165    fn test_should_indent_by_length() {
166        let config = FormatConfig::builder()
167            .indent_long_lines(true)
168            .max_line_length(80)
169            .build();
170
171        assert!(!config.should_indent_by_length("short"));
172        assert!(config.should_indent_by_length(&"a".repeat(100)));
173    }
174
175    #[test]
176    fn test_should_indent_by_ref_count() {
177        let config = FormatConfig::builder().max_inline_refs(Some(3)).build();
178
179        assert!(!config.should_indent_by_ref_count(2));
180        assert!(!config.should_indent_by_ref_count(3));
181        assert!(config.should_indent_by_ref_count(4));
182    }
183}