string_width/
options.rs

1/// How to treat ambiguous width characters
2///
3/// Some Unicode characters have ambiguous width properties, meaning their
4/// display width depends on the context (terminal, font, locale, etc.).
5/// This enum allows you to specify how such characters should be treated.
6///
7/// # Examples
8///
9/// ```rust
10/// use string_width::{AmbiguousWidthTreatment, StringWidthOptions, string_width_with_options};
11///
12/// let text = "±×÷";  // Ambiguous width characters
13///
14/// let narrow_options = StringWidthOptions {
15///     count_ansi: false,
16///     ambiguous_width: AmbiguousWidthTreatment::Narrow,
17/// };
18/// assert_eq!(string_width_with_options(text, narrow_options), 3);
19///
20/// let wide_options = StringWidthOptions {
21///     count_ansi: false,
22///     ambiguous_width: AmbiguousWidthTreatment::Wide,
23/// };
24/// assert_eq!(string_width_with_options(text, wide_options), 6);
25/// ```
26#[derive(Debug, Clone, Copy, PartialEq, Eq)]
27pub enum AmbiguousWidthTreatment {
28    /// Treat ambiguous characters as narrow (width 1)
29    Narrow,
30    /// Treat ambiguous characters as wide (width 2)
31    Wide,
32}
33
34impl Default for AmbiguousWidthTreatment {
35    /// Returns the default treatment for ambiguous width characters.
36    ///
37    /// The default is `Narrow`, which treats ambiguous characters as having width 1.
38    /// This is the most common behavior in terminal applications.
39    fn default() -> Self {
40        Self::Narrow
41    }
42}
43
44/// Configuration options for string width calculation
45///
46/// This struct contains all the options that control how string width is calculated.
47/// It provides fine-grained control over various aspects of width calculation.
48///
49/// # Examples
50///
51/// ```rust
52/// use string_width::{StringWidthOptions, AmbiguousWidthTreatment, string_width_with_options};
53///
54/// // Default options
55/// let options = StringWidthOptions::default();
56/// assert_eq!(string_width_with_options("Hello", options), 5);
57///
58/// // Custom options
59/// let options = StringWidthOptions {
60///     count_ansi: true,  // Count ANSI escape sequences
61///     ambiguous_width: AmbiguousWidthTreatment::Wide,  // Treat ambiguous as wide
62/// };
63/// ```
64#[derive(Debug, Clone, Default)]
65pub struct StringWidthOptions {
66    /// Whether to count ANSI escape sequences in width calculation
67    ///
68    /// When `false` (default), ANSI escape sequences are stripped before
69    /// calculating width. When `true`, they are included in the calculation.
70    pub count_ansi: bool,
71
72    /// How to treat ambiguous width characters
73    ///
74    /// Controls whether characters with ambiguous width properties
75    /// are treated as narrow (width 1) or wide (width 2).
76    pub ambiguous_width: AmbiguousWidthTreatment,
77}
78
79impl StringWidthOptions {
80    /// Creates a new builder for StringWidthOptions
81    ///
82    /// The builder pattern provides a fluent API for configuring options.
83    ///
84    /// # Examples
85    ///
86    /// ```rust
87    /// use string_width::StringWidthOptions;
88    ///
89    /// let options = StringWidthOptions::builder()
90    ///     .count_ansi(true)
91    ///     .ambiguous_as_wide()
92    ///     .build();
93    /// ```
94    pub fn builder() -> StringWidthOptionsBuilder {
95        StringWidthOptionsBuilder::default()
96    }
97}
98
99/// Builder for StringWidthOptions following the builder pattern
100///
101/// Provides a fluent API for configuring string width calculation options.
102///
103/// # Examples
104///
105/// ```rust
106/// use string_width::{StringWidthOptions, AmbiguousWidthTreatment};
107///
108/// // Basic usage
109/// let options = StringWidthOptions::builder()
110///     .count_ansi(true)
111///     .ambiguous_as_wide()
112///     .build();
113///
114/// // All options
115/// let options = StringWidthOptions::builder()
116///     .count_ansi(false)
117///     .ambiguous_width(AmbiguousWidthTreatment::Narrow)
118///     .build();
119/// ```
120#[derive(Debug, Clone, Default)]
121pub struct StringWidthOptionsBuilder {
122    count_ansi: bool,
123    ambiguous_width: AmbiguousWidthTreatment,
124}
125
126impl StringWidthOptionsBuilder {
127    /// Creates a new builder with default values
128    ///
129    /// This is equivalent to calling `StringWidthOptionsBuilder::default()`.
130    ///
131    /// # Examples
132    ///
133    /// ```rust
134    /// use string_width::{StringWidthOptions, StringWidthOptionsBuilder};
135    ///
136    /// let builder = StringWidthOptions::builder();
137    /// // or
138    /// let builder = StringWidthOptionsBuilder::new();
139    /// ```
140    pub fn new() -> Self {
141        Self::default()
142    }
143
144    /// Sets whether to count ANSI escape sequences in width calculation
145    ///
146    /// When set to `true`, ANSI escape sequences will be included in the width
147    /// calculation. When `false` (default), they are stripped and ignored.
148    ///
149    /// # Arguments
150    ///
151    /// * `count_ansi` - Whether to count ANSI sequences
152    ///
153    /// # Examples
154    ///
155    /// ```rust
156    /// use string_width::{StringWidthOptions, string_width_with_options};
157    ///
158    /// let options = StringWidthOptions::builder()
159    ///     .count_ansi(true)
160    ///     .build();
161    ///
162    /// // ANSI sequences are counted
163    /// assert_eq!(string_width_with_options("\x1b[31mRed\x1b[0m", options), 12);
164    /// ```
165    pub fn count_ansi(mut self, count_ansi: bool) -> Self {
166        self.count_ansi = count_ansi;
167        self
168    }
169
170    /// Sets how ambiguous width characters should be treated
171    ///
172    /// Allows explicit control over ambiguous width character treatment.
173    ///
174    /// # Arguments
175    ///
176    /// * `ambiguous_width` - The treatment strategy for ambiguous characters
177    ///
178    /// # Examples
179    ///
180    /// ```rust
181    /// use string_width::{StringWidthOptions, AmbiguousWidthTreatment, string_width_with_options};
182    ///
183    /// let options = StringWidthOptions::builder()
184    ///     .ambiguous_width(AmbiguousWidthTreatment::Wide)
185    ///     .build();
186    ///
187    /// assert_eq!(string_width_with_options("±", options), 2);
188    /// ```
189    pub fn ambiguous_width(mut self, ambiguous_width: AmbiguousWidthTreatment) -> Self {
190        self.ambiguous_width = ambiguous_width;
191        self
192    }
193
194    /// Sets ambiguous width characters to be treated as narrow (convenience method)
195    ///
196    /// This is a convenience method equivalent to calling
197    /// `.ambiguous_width(AmbiguousWidthTreatment::Narrow)`.
198    ///
199    /// # Examples
200    ///
201    /// ```rust
202    /// use string_width::{StringWidthOptions, string_width_with_options};
203    ///
204    /// let options = StringWidthOptions::builder()
205    ///     .ambiguous_as_narrow()
206    ///     .build();
207    ///
208    /// assert_eq!(string_width_with_options("±", options), 1);
209    /// ```
210    pub fn ambiguous_as_narrow(mut self) -> Self {
211        self.ambiguous_width = AmbiguousWidthTreatment::Narrow;
212        self
213    }
214
215    /// Sets ambiguous width characters to be treated as wide (convenience method)
216    ///
217    /// This is a convenience method equivalent to calling
218    /// `.ambiguous_width(AmbiguousWidthTreatment::Wide)`.
219    ///
220    /// # Examples
221    ///
222    /// ```rust
223    /// use string_width::{StringWidthOptions, string_width_with_options};
224    ///
225    /// let options = StringWidthOptions::builder()
226    ///     .ambiguous_as_wide()
227    ///     .build();
228    ///
229    /// assert_eq!(string_width_with_options("±", options), 2);
230    /// ```
231    pub fn ambiguous_as_wide(mut self) -> Self {
232        self.ambiguous_width = AmbiguousWidthTreatment::Wide;
233        self
234    }
235
236    /// Builds the final StringWidthOptions instance
237    ///
238    /// Consumes the builder and returns the configured `StringWidthOptions`.
239    ///
240    /// # Examples
241    ///
242    /// ```rust
243    /// use string_width::StringWidthOptions;
244    ///
245    /// let options = StringWidthOptions::builder()
246    ///     .count_ansi(true)
247    ///     .ambiguous_as_wide()
248    ///     .build();
249    /// ```
250    pub fn build(self) -> StringWidthOptions {
251        StringWidthOptions {
252            count_ansi: self.count_ansi,
253            ambiguous_width: self.ambiguous_width,
254        }
255    }
256}