Skip to main content

agd_core/document/
source.rs

1//! Positions in a document's source: `ByteSpan`, `SourceLine`, and the split of
2//! the source into numbered lines.
3//!
4//! Spans are byte offsets into the exact source. A line's `content` leaves out
5//! its `\n` or `\r\n` and its `full` span includes it.
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
8pub struct ByteSpan {
9    pub start: usize,
10    pub end: usize,
11}
12
13#[derive(Clone, Debug)]
14pub struct SourceLine {
15    pub number: usize,
16    pub full: ByteSpan,
17    pub content: ByteSpan,
18}
19
20pub(super) fn source_lines(source: &str) -> Vec<SourceLine> {
21    let mut lines = Vec::new();
22    let mut start = 0;
23    for (index, segment) in source.split_inclusive('\n').enumerate() {
24        let end = start + segment.len();
25        let content_end = if segment.ends_with("\r\n") {
26            end - 2
27        } else if segment.ends_with('\n') {
28            end - 1
29        } else {
30            end
31        };
32        lines.push(SourceLine {
33            number: index + 1,
34            full: ByteSpan { start, end },
35            content: ByteSpan {
36                start,
37                end: content_end,
38            },
39        });
40        start = end;
41    }
42    lines
43}