1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
4pub struct Position {
5 pub line: usize,
6 pub col: usize,
7}
8
9impl Position {
10 pub fn new(line: usize, col: usize) -> Self {
11 Self { line, col }
12 }
13
14 pub fn zero() -> Self {
15 Self { line: 0, col: 0 }
16 }
17}
18
19impl PartialOrd for Position {
20 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
21 Some(self.cmp(other))
22 }
23}
24
25impl Ord for Position {
26 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
27 self.line.cmp(&other.line).then(self.col.cmp(&other.col))
28 }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq)]
35pub struct Selection {
36 pub anchor: Position,
37 pub head: Position,
38}
39
40impl Selection {
41 pub fn cursor(pos: Position) -> Self {
43 Self {
44 anchor: pos,
45 head: pos,
46 }
47 }
48
49 pub fn new(anchor: Position, head: Position) -> Self {
51 Self { anchor, head }
52 }
53
54 pub fn start(&self) -> Position {
56 std::cmp::min(self.anchor, self.head)
57 }
58
59 pub fn end(&self) -> Position {
61 std::cmp::max(self.anchor, self.head)
62 }
63
64 pub fn is_cursor(&self) -> bool {
66 self.anchor == self.head
67 }
68
69 pub fn is_backward(&self) -> bool {
71 self.head < self.anchor
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn position_ordering() {
81 let a = Position::new(0, 5);
82 let b = Position::new(1, 0);
83 let c = Position::new(1, 3);
84 assert!(a < b);
85 assert!(b < c);
86 assert!(a < c);
87 }
88
89 #[test]
90 fn cursor_is_cursor() {
91 let sel = Selection::cursor(Position::new(2, 4));
92 assert!(sel.is_cursor());
93 assert!(!sel.is_backward());
94 assert_eq!(sel.start(), sel.end());
95 }
96
97 #[test]
98 fn forward_selection() {
99 let sel = Selection::new(Position::new(0, 0), Position::new(1, 5));
100 assert!(!sel.is_cursor());
101 assert!(!sel.is_backward());
102 assert_eq!(sel.start(), Position::new(0, 0));
103 assert_eq!(sel.end(), Position::new(1, 5));
104 }
105
106 #[test]
107 fn backward_selection() {
108 let sel = Selection::new(Position::new(3, 2), Position::new(1, 0));
109 assert!(sel.is_backward());
110 assert_eq!(sel.start(), Position::new(1, 0));
111 assert_eq!(sel.end(), Position::new(3, 2));
112 }
113}