1use std::{
2 cmp::Ordering,
3 fmt::Debug,
4 ops::{Bound, Range, RangeBounds},
5};
6
7#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd)]
9pub struct TextRange {
10 pub start: usize,
11 pub end: usize,
12}
13
14impl Ord for TextRange {
15 fn cmp(&self, other: &Self) -> Ordering {
16 match self.start.cmp(&other.start) {
17 Ordering::Less => Ordering::Less,
18 Ordering::Equal => self.end.cmp(&other.end),
19 Ordering::Greater => Ordering::Greater,
20 }
21 }
22}
23
24impl RangeBounds<usize> for TextRange {
25 fn start_bound(&self) -> Bound<&usize> {
26 Bound::Included(&self.start)
27 }
28
29 fn end_bound(&self) -> Bound<&usize> {
30 Bound::Excluded(&self.start)
31 }
32}
33
34impl<T: Into<usize>> From<Range<T>> for TextRange {
35 fn from(range: Range<T>) -> Self {
36 Self {
37 start: range.start.into(),
38 end: range.end.into(),
39 }
40 }
41}
42impl<T: Into<usize>> From<(T, T)> for TextRange {
43 fn from((start, end): (T, T)) -> Self {
44 Self {
45 start: start.into(),
46 end: end.into(),
47 }
48 }
49}
50
51impl TextRange {
52 pub fn new(start: usize, end: usize) -> Self {
54 if start <= end {
55 Self { start, end }
56 } else {
57 Self {
58 start: end,
59 end: start,
60 }
61 }
62 }
63
64 pub fn as_range(&self) -> Range<usize> {
65 self.start..self.end
66 }
67
68 pub fn contains(&self, pos: usize) -> bool {
69 self.start <= pos && pos < self.end
70 }
71
72 pub fn strict_order(&self, other: &Self) -> Option<Ordering> {
73 if self.end <= other.start {
74 return Some(Ordering::Less);
75 }
76 if self.start >= other.end {
77 return Some(Ordering::Greater);
78 }
79 None
80 }
81 pub fn split_at(&mut self, position: usize, left: bool) -> Self {
85 if left {
86 let start = self.start;
87 self.start = position;
88 Self::new(start, position)
89 } else {
90 let end = self.end;
91 self.end = position;
92 Self::new(position, end)
93 }
94 }
95
96 pub fn intersects(&self, other: Self) -> bool {
97 self.end > other.start && self.start < other.end
98 }
99 pub fn intersection_uncheck(&self, other: Self) -> Self {
100 Self::new(self.start.max(other.start), self.end.min(other.end))
101 }
102 pub fn intersection(&self, other: Self) -> Option<Self> {
103 self.intersects(other)
104 .then(|| self.intersection_uncheck(other))
105 }
106
107 pub fn advance(&mut self, offset: usize) {
108 self.start += offset;
109 self.end += offset;
110 }
111 pub fn move_back(&self, offset: usize) -> Self {
112 Self::new(self.start + offset, self.end + offset)
113 }
114}