2
2
crate :: TextSize ,
3
3
std:: {
4
4
cmp, fmt,
5
- ops:: { Bound , Index , IndexMut , Range , RangeBounds } ,
5
+ ops:: { Bound , Index , IndexMut , Range , RangeBounds , RangeFrom } ,
6
6
} ,
7
7
} ;
8
8
9
9
/// A range in text, represented as a pair of [`TextSize`][struct@TextSize].
10
10
///
11
- /// It is a logical error to have `end() < start()`, but
12
- /// code must not assume this is true for `unsafe` guarantees.
13
- ///
14
11
/// # Translation from `text_unit`
15
12
///
16
- /// - `TextRange::from_to(from, to)` ⟹ `TextRange::from (from.. to)`
17
- /// - `TextRange::offset_len(offset, size)` ⟹ `TextRange::from(offset.. offset + size )`
13
+ /// - `TextRange::from_to(from, to)` ⟹ `TextRange(from, to)`
14
+ /// - `TextRange::offset_len(offset, size)` ⟹ `TextRange::to(size). offset(offset )`
18
15
/// - `range.start()` ⟹ `range.start()`
19
16
/// - `range.end()` ⟹ `range.end()`
20
- /// - `range.len()` ⟹ `range.len()`<sup>†</sup>
17
+ /// - `range.len()` ⟹ `range.len()`
21
18
/// - `range.is_empty()` ⟹ `range.is_empty()`
22
- /// - `a.is_subrange(b)` ⟹ `b.contains (a)`
19
+ /// - `a.is_subrange(b)` ⟹ `b.contains_range (a)`
23
20
/// - `a.intersection(b)` ⟹ `TextRange::intersection(a, b)`
24
21
/// - `a.extend_to(b)` ⟹ `TextRange::covering(a, b)`
25
- /// - `range.contains(offset)` ⟹ `range.contains_exclusive (point)`
22
+ /// - `range.contains(offset)` ⟹ `range.contains (point)`
26
23
/// - `range.contains_inclusive(offset)` ⟹ `range.contains_inclusive(point)`
27
- ///
28
- /// † See the note on [`TextRange::len`] for differing behavior for incorrect reverse ranges.
29
24
#[ derive( Copy , Clone , Eq , PartialEq , Hash ) ]
30
25
pub struct TextRange {
31
26
// Invariant: start <= end
@@ -39,7 +34,7 @@ impl fmt::Debug for TextRange {
39
34
}
40
35
}
41
36
42
- /// Creates a new `TextRange` with given `start` and `end.
37
+ /// Creates a new `TextRange` with the given `start` and `end` (`start..end`) .
43
38
///
44
39
/// # Panics
45
40
///
@@ -50,16 +45,47 @@ pub fn TextRange(start: TextSize, end: TextSize) -> TextRange {
50
45
TextRange { start, end }
51
46
}
52
47
53
- /// Identity methods.
54
48
impl TextRange {
55
- /// Creates a zero-length range at the specified offset.
56
- pub const fn empty ( self , offset : TextSize ) -> TextRange {
49
+ /// Create a zero-length range at the specified offset (`offset..offset`) .
50
+ pub const fn empty ( offset : TextSize ) -> TextRange {
57
51
TextRange {
58
52
start : offset,
59
53
end : offset,
60
54
}
61
55
}
62
56
57
+ /// Create a range up to the given end (`..end`).
58
+ pub const fn before ( end : TextSize ) -> TextRange {
59
+ TextRange {
60
+ start : TextSize :: zero ( ) ,
61
+ end,
62
+ }
63
+ }
64
+
65
+ /// Create a range after the given start (`start..`).
66
+ ///
67
+ /// This returns a std [`RangeFrom`] rather than `TextRange` because
68
+ /// `TextRange` does not support right-unbounded ranges. As such, this
69
+ /// should only be used for direct indexing, and bounded ranges should be
70
+ /// used for persistent ranges (`TextRange(start, TextSize::of(text))`).
71
+ pub const fn after ( start : TextSize ) -> RangeFrom < usize > {
72
+ start. raw as usize ..
73
+ }
74
+
75
+ /// Offset this range by some amount.
76
+ ///
77
+ /// This is typically used to convert a range from one coordinate space to
78
+ /// another, such as from within a substring to within an entire document.
79
+ pub fn offset ( self , offset : TextSize ) -> TextRange {
80
+ TextRange (
81
+ self . start ( ) . checked_add ( offset) . unwrap ( ) ,
82
+ self . end ( ) . checked_add ( offset) . unwrap ( ) ,
83
+ )
84
+ }
85
+ }
86
+
87
+ /// Identity methods.
88
+ impl TextRange {
63
89
/// The start point of this range.
64
90
pub const fn start ( self ) -> TextSize {
65
91
self . start
@@ -76,10 +102,7 @@ impl TextRange {
76
102
TextSize ( self . end ( ) . raw - self . start ( ) . raw )
77
103
}
78
104
79
- /// Check if this range empty or reversed.
80
- ///
81
- /// When `end() < start()`, this returns false.
82
- /// Code should prefer `is_empty()` to `len() == 0`.
105
+ /// Check if this range is empty.
83
106
pub const fn is_empty ( self ) -> bool {
84
107
// HACK for const fn: math on primitives only
85
108
self . start ( ) . raw == self . end ( ) . raw
@@ -99,8 +122,7 @@ impl TextRange {
99
122
///
100
123
/// The end index is considered included.
101
124
pub fn contains_inclusive ( self , offset : TextSize ) -> bool {
102
- let point = offset. into ( ) ;
103
- self . start ( ) <= point && point <= self . end ( )
125
+ self . start ( ) <= offset && offset <= self . end ( )
104
126
}
105
127
106
128
/// Check if this range completely contains another range.
0 commit comments