1use crate::id;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
10pub enum MotionShape {
11 Characterwise { inclusive: bool },
12 Linewise,
13}
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
18pub struct Range {
19 pub start: id::ByteOffset,
20 pub end: id::ByteOffset,
21 pub shape: MotionShape,
22}
23
24impl Range {
25 pub fn charwise(start: impl Into<id::ByteOffset>, end: impl Into<id::ByteOffset>) -> Self {
26 let (start, end) = (start.into(), end.into());
27 debug_assert!(start <= end);
28 Self {
29 start,
30 end,
31 shape: MotionShape::Characterwise { inclusive: false },
32 }
33 }
34 pub fn linewise(start: impl Into<id::ByteOffset>, end: impl Into<id::ByteOffset>) -> Self {
35 let (start, end) = (start.into(), end.into());
36 debug_assert!(start <= end);
37 Self {
38 start,
39 end,
40 shape: MotionShape::Linewise,
41 }
42 }
43 pub fn is_linewise(&self) -> bool {
44 matches!(self.shape, MotionShape::Linewise)
45 }
46 pub fn with_inclusive(mut self, inclusive: bool) -> Self {
48 if let MotionShape::Characterwise { inclusive: i } = &mut self.shape {
49 *i = inclusive;
50 }
51 self
52 }
53 pub fn inclusive(&self) -> bool {
54 matches!(self.shape, MotionShape::Characterwise { inclusive: true })
55 }
56 pub fn len(&self) -> usize {
58 self.end - self.start
59 }
60 pub fn is_empty(&self) -> bool {
61 self.start == self.end
62 }
63}