Skip to main content

redox_core/buffer/
pos.rs

1//! Position and selection types for the rope-backed buffer.
2//!
3//! These are **logical** positions: (line, column), both 0-based, where column is
4//! a character offset within the line (not a visual column).
5
6/// A stable identifier for positions within a buffer.
7///
8/// This is a *logical* position: line + column (both 0-based).
9/// It is not a byte offset.
10///
11/// Column is a char offset within the line.
12#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
13pub struct Pos {
14    pub line: usize,
15    pub col: usize,
16}
17
18impl Pos {
19    #[inline]
20    pub const fn new(line: usize, col: usize) -> Self {
21        Self { line, col }
22    }
23
24    #[inline]
25    pub const fn zero() -> Self {
26        Self { line: 0, col: 0 }
27    }
28}
29
30/// A selection expressed as an anchor + active cursor.
31///
32/// If `anchor == cursor`, selection is empty.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
34pub struct Selection {
35    pub anchor: Pos,
36    pub cursor: Pos,
37}
38
39impl Selection {
40    #[inline]
41    pub const fn new(anchor: Pos, cursor: Pos) -> Self {
42        Self { anchor, cursor }
43    }
44
45    #[inline]
46    pub const fn empty(at: Pos) -> Self {
47        Self {
48            anchor: at,
49            cursor: at,
50        }
51    }
52
53    /// Returns the ordered range (start <= end).
54    #[inline]
55    pub fn ordered(&self) -> (Pos, Pos) {
56        if self.anchor <= self.cursor {
57            (self.anchor, self.cursor)
58        } else {
59            (self.cursor, self.anchor)
60        }
61    }
62
63    #[inline]
64    pub fn is_empty(&self) -> bool {
65        self.anchor == self.cursor
66    }
67}