Skip to main content

substrate_data/forms/text/
line_col.rs

1//! [`LineCol`]: a 1-based line and column.
2
3use std::fmt;
4
5/// A 1-based line and column (in characters).
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub struct LineCol {
8    /// The line, from 1.
9    pub line: u32,
10    /// The column in characters, from 1.
11    pub col: u32,
12}
13
14impl LineCol {
15    /// Where byte `offset` of `text` is.
16    #[must_use]
17    pub fn of(text: &str, offset: usize) -> LineCol {
18        let offset = offset.min(text.len());
19        let before = &text.as_bytes()[..offset];
20        let lines = before.split(|&b| b == b'\n').count();
21        let line_start = before
22            .iter()
23            .rposition(|&b| b == b'\n')
24            .map_or(0, |i| i + 1);
25        let col = text
26            .get(line_start..offset)
27            .map_or(offset - line_start, |s| s.chars().count())
28            + 1;
29        LineCol {
30            line: u32::try_from(lines).unwrap_or(u32::MAX),
31            col: u32::try_from(col).unwrap_or(u32::MAX),
32        }
33    }
34}
35
36impl fmt::Display for LineCol {
37    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38        write!(f, "{}:{}", self.line, self.col)
39    }
40}