Skip to main content

microcad_lang_base/src_ref/
line_index.rs

1// Copyright © 2026 The µcad authors <info@microcad.xyz>
2// SPDX-License-Identifier: AGPL-3.0-or-later
3
4use crate::{HashId, Span, SrcRef, src_ref::LineCol};
5
6/// An index to retrieve the offsets in a line in O(log(n)).
7#[derive(Clone, Debug)]
8pub struct LineIndex {
9    /// Offset (bytes) the beginning of each line, zero-based
10    line_offsets: Vec<u32>,
11}
12
13impl LineIndex {
14    /// Create a new line index from a &str.
15    pub fn new(s: &str) -> Self {
16        Self {
17            line_offsets: std::iter::once(0)
18                .chain(s.match_indices('\n').map(|(i, _)| (i + 1) as u32))
19                .collect(),
20        }
21    }
22
23    /// Returns (line, col) of pos.
24    ///
25    /// The pos is a byte offset, start from 0, e.g. "ab" is 2, "你好" is 6
26    pub fn line_col(&self, input: &str, pos: usize) -> LineCol {
27        let line = self.line_offsets.partition_point(|&it| it <= pos as u32) - 1;
28        let first_offset = self.line_offsets[line] as usize;
29
30        // Get line str from original input, then we can get column offset
31        let line_str = &input[first_offset..pos];
32        let col = line_str.chars().count();
33
34        LineCol {
35            line: line as u32,
36            col: (col + 1) as u32,
37        }
38    }
39
40    pub fn src_ref(&self, text: &str, span: &Span, hash: HashId) -> SrcRef {
41        SrcRef::new(span.clone(), self.line_col(text, span.start), hash)
42    }
43}