source_cache/text/
display.rs

1use super::*;
2
3impl Debug for SourceSpan {
4    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
5        f.debug_struct("FileSpan").field("start", &self.start).field("end", &self.end).field("file", &self.file).finish()
6    }
7}
8
9impl Display for SourceSpan {
10    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
11        write!(f, "FileSpan(0x{:X}, {}..{})", self.file.hash, self.start, self.end)
12    }
13}
14
15impl<S: Into<String>> From<S> for SourceText {
16    /// Generate a [`SourceText`] from the given [`str`].
17    ///
18    /// Note that this function can be expensive for long strings. Use an implementor of [`Cache`] where possible.
19    fn from(source: S) -> Self {
20        let text = source.into();
21        let mut offset = 0;
22        // (Last line, last line ends with CR)
23        let mut last_line: Option<(SourceLine, bool)> = None;
24        let mut lines: Vec<SourceLine> = text
25            .split_inclusive([
26                '\r',       // Carriage return
27                '\n',       // Line feed
28                '\x0B',     // Vertical tab
29                '\x0C',     // Form feed
30                '\u{0085}', // Next line
31                '\u{2028}', // Line separator
32                '\u{2029}', // Paragraph separator
33            ])
34            .flat_map(|line| {
35                // Returns last line and set `last_line` to current `line`
36                // A hack that makes `flat_map` deals with consecutive lines
37
38                if let Some((last, ends_with_cr)) = last_line.as_mut() {
39                    if *ends_with_cr && line == "\n" {
40                        last.length += 1;
41                        offset += 1;
42                        return core::mem::replace(&mut last_line, None).map(|(l, _)| l);
43                    }
44                }
45
46                let len = line.len();
47                let ends_with_cr = line.ends_with('\r');
48                let line = SourceLine { offset, length: len as u32, text: line.trim_end().to_owned() };
49                offset += line.length;
50                core::mem::replace(&mut last_line, Some((line, ends_with_cr))).map(|(l, _)| l)
51            })
52            .collect();
53
54        if let Some((l, _)) = last_line {
55            lines.push(l);
56        }
57
58        Self { path: SourcePath::Anonymous, raw: text, lines, length: offset, dirty: false }
59    }
60}