Skip to main content

textlane_core/models/
position.rs

1/// A place in the source: a byte offset, plus the virtual spaces into a tab it sits at.
2#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
3pub struct Point(u32);
4
5// The top two bits hold the virtual spaces (a tab spans at most three of them)
6const VIRTUAL_SHIFT: u32 = 30;
7const OFFSET_MASK: u32 = (1 << VIRTUAL_SHIFT) - 1;
8
9impl Point {
10    /// The largest byte offset a point can hold.
11    pub const MAX_OFFSET: usize = OFFSET_MASK as usize;
12
13    pub fn new(offset: usize, virtual_spaces: usize) -> Self {
14        let offset = offset.min(Self::MAX_OFFSET) as u32;
15        let virtual_spaces = virtual_spaces.min(3) as u32;
16        Self(offset | (virtual_spaces << VIRTUAL_SHIFT))
17    }
18
19    pub fn offset(self) -> usize {
20        (self.0 & OFFSET_MASK) as usize
21    }
22
23    pub fn virtual_spaces(self) -> usize {
24        (self.0 >> VIRTUAL_SHIFT) as usize
25    }
26}
27
28/// Where a node sits: a span of the current source, or a unist position that does not point
29/// into it, such as one a foreign plugin set or one read from a serialized tree.
30#[derive(Clone, Copy, Debug, PartialEq)]
31pub enum Position<'a> {
32    Span { start: Point, end: Point },
33    Unist(&'a UnistPosition),
34}
35
36/// A position as unist writes it: lines and columns from 1, offsets in UTF-16 code units.
37#[derive(Clone, Debug, PartialEq, Eq)]
38pub struct UnistPosition {
39    pub start: UnistPoint,
40    pub end: UnistPoint,
41}
42
43/// A point as unist writes it.
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub struct UnistPoint {
46    pub line: usize,
47    pub column: usize,
48    pub offset: Option<usize>,
49}
50
51impl<'a> Position<'a> {
52    pub fn span(start: Point, end: Point) -> Self {
53        Self::Span { start, end }
54    }
55}