litcheck_core/diagnostics/
selection.rs1use super::{ColumnIndex, LineIndex};
2
3#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
7pub struct Selection {
8 pub start: Position,
9 pub end: Position,
10}
11
12impl Selection {
13 #[inline]
14 pub fn new(start: Position, end: Position) -> Self {
15 if start <= end {
16 Self { start, end }
17 } else {
18 Self {
19 start: end,
20 end: start,
21 }
22 }
23 }
24
25 pub fn canonicalize(&mut self) {
26 if self.start > self.end {
27 core::mem::swap(&mut self.start, &mut self.end);
28 }
29 }
30}
31
32impl From<core::ops::Range<Position>> for Selection {
33 #[inline]
34 fn from(value: core::ops::Range<Position>) -> Self {
35 Self::new(value.start, value.end)
36 }
37}
38
39impl From<core::ops::Range<LineIndex>> for Selection {
40 #[inline]
41 fn from(value: core::ops::Range<LineIndex>) -> Self {
42 Self::new(value.start.into(), value.end.into())
43 }
44}
45
46#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct Position {
51 pub line: LineIndex,
52 pub character: ColumnIndex,
53}
54
55impl Position {
56 pub const fn new(line: u32, character: u32) -> Self {
57 Self {
58 line: LineIndex(line),
59 character: ColumnIndex(character),
60 }
61 }
62}
63
64impl From<LineIndex> for Position {
65 #[inline]
66 fn from(line: LineIndex) -> Self {
67 Self {
68 line,
69 character: ColumnIndex(0),
70 }
71 }
72}
73
74#[cfg(test)]
75mod tests {
76 use super::*;
77
78 #[test]
79 fn selection_new_orders_bounds_when_reversed() {
80 let a = Position::new(10, 5);
81 let b = Position::new(2, 3);
82 let sel = Selection::new(a, b);
83 assert!(sel.start <= sel.end);
84 assert_eq!(sel.start, b);
85 assert_eq!(sel.end, a);
86 }
87
88 #[test]
89 fn selection_new_keeps_order_when_already_ordered() {
90 let a = Position::new(2, 3);
91 let b = Position::new(10, 5);
92 let sel = Selection::new(a, b);
93 assert_eq!(sel.start, a);
94 assert_eq!(sel.end, b);
95 }
96
97 #[test]
98 fn canonicalize_swaps_only_when_start_greater_than_end() {
99 let a = Position::new(10, 5);
100 let b = Position::new(2, 3);
101 let mut sel = Selection { start: a, end: b };
102 sel.canonicalize();
103 assert!(sel.start <= sel.end);
104 assert_eq!(sel.start, b);
105 assert_eq!(sel.end, a);
106
107 let mut sel2 = Selection { start: b, end: a };
108 sel2.canonicalize();
109 assert_eq!(sel2.start, b);
110 assert_eq!(sel2.end, a);
111 }
112}