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}