Skip to main content

sourceannot/snippet/
chars.rs

1use super::utils::build_with_char_iter;
2use super::{ControlCharStyle, Snippet};
3
4impl Snippet {
5    /// Creates a [`Snippet`] from a [`char`] sequence.
6    ///
7    /// # Source units and spans
8    ///
9    /// The *source unit* for this builder is a **[`char`]** of the original
10    /// `source`. Any annotation span you pass later (a `Range<usize>`) is
11    /// interpreted as [`char`]s indices into this original `source`.
12    ///
13    /// # Line breaks
14    ///
15    /// - `\n` and `\r\n` are treated as line breaks.
16    /// - A lone `\r` is *not* a line break; it is handled like any other control
17    ///   character.
18    ///
19    /// # Control characters
20    ///
21    /// Control characters are those for which
22    /// [`char_should_be_replaced()`](crate::char_should_be_replaced)
23    /// returns `true`.
24    ///
25    /// - Tabs (U+0009) are replaced with `tab_width` spaces.
26    /// - ZERO WIDTH JOINER (U+200D) is replaced with nothing (but still accounts
27    ///   for its original source unit length).
28    /// - When `control_char_style` is [`ControlCharStyle::Replacement`], C0
29    ///   controls (U+0000 to U+001F, excluding tab) and DEL (U+007F) are
30    ///   replaced with their Unicode Control Pictures (␀, ␁, ...).
31    /// - Any other control character, and C0 controls when `control_char_style`
32    ///   is [`ControlCharStyle::Codepoint`], are represented with the hexadecimal
33    ///   value of their code point, in angle brackets, with at least four digits
34    ///   (`<U+XXXX>`).
35    ///
36    /// Control characters are rendered as alternate text when `control_char_alt` is
37    /// `true`, with the exception of tabs, which are never marked as alternate text.
38    ///
39    /// # Examples
40    ///
41    /// If `source` is a [`char`] slice:
42    /// ```
43    /// # let chars = ['x'];
44    /// let snippet = sourceannot::Snippet::with_chars(
45    ///     1,
46    ///     chars.iter().copied(),
47    ///     4,
48    ///     sourceannot::ControlCharStyle::Codepoint,
49    ///     true,
50    /// );
51    /// ```
52    ///
53    /// If `source` is a UTF-8 ([`str`]) slice, but you want source units to be
54    /// [`char`]s instead of bytes:
55    /// ```
56    /// # let source = "x";
57    /// let snippet = sourceannot::Snippet::with_chars(
58    ///     1,
59    ///     source.chars(),
60    ///     4,
61    ///     sourceannot::ControlCharStyle::Codepoint,
62    ///     true,
63    /// );
64    /// ```
65    pub fn with_chars<I>(
66        start_line: usize,
67        source: I,
68        tab_width: usize,
69        control_char_style: ControlCharStyle,
70        control_char_alt: bool,
71    ) -> Self
72    where
73        I: IntoIterator<Item = char>,
74    {
75        let mut builder = Snippet::builder(start_line);
76        build_with_char_iter::<32>(
77            &mut builder,
78            source,
79            tab_width,
80            control_char_style,
81            control_char_alt,
82        );
83        builder.finish()
84    }
85}