microcad-lang-base 0.5.0

µcad language basics
Documentation
// Copyright © 2026 The µcad authors <info@microcad.xyz>
// SPDX-License-Identifier: AGPL-3.0-or-later

use crate::{HashId, Span, SrcRef, src_ref::LineCol};

/// An index to retrieve the offsets in a line in O(log(n)).
#[derive(Clone, Debug)]
pub struct LineIndex {
    /// Offset (bytes) the beginning of each line, zero-based
    line_offsets: Vec<u32>,
}

impl LineIndex {
    /// Create a new line index from a &str.
    pub fn new(s: &str) -> Self {
        Self {
            line_offsets: std::iter::once(0)
                .chain(s.match_indices('\n').map(|(i, _)| (i + 1) as u32))
                .collect(),
        }
    }

    /// Returns (line, col) of pos.
    ///
    /// The pos is a byte offset, start from 0, e.g. "ab" is 2, "你好" is 6
    pub fn line_col(&self, input: &str, pos: usize) -> LineCol {
        let line = self.line_offsets.partition_point(|&it| it <= pos as u32) - 1;
        let first_offset = self.line_offsets[line] as usize;

        // Get line str from original input, then we can get column offset
        let line_str = &input[first_offset..pos];
        let col = line_str.chars().count();

        LineCol {
            line: line as u32,
            col: (col + 1) as u32,
        }
    }

    pub fn src_ref(&self, text: &str, span: &Span, hash: HashId) -> SrcRef {
        SrcRef::new(span.clone(), self.line_col(text, span.start), hash)
    }
}