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}