supa_mdx_lint/
rope.rs

1use std::ops::{Deref, DerefMut};
2
3/// This is publicly exposed because we need it for the interactive fixing
4/// feature, but should _not_ be considered part of the public API. There are
5/// no guarantees about the stability of this type and its methods.
6#[doc(hidden)]
7#[derive(Debug, Default, Clone, Eq, PartialEq)]
8pub struct Rope(crop::Rope);
9
10/// This is publicly exposed because we need it for the interactive fixing
11/// feature, but should _not_ be considered part of the public API. There are
12/// no guarantees about the stability of this type and its methods.
13#[doc(hidden)]
14pub use crop::RopeSlice;
15
16impl Deref for Rope {
17    type Target = crop::Rope;
18
19    fn deref(&self) -> &Self::Target {
20        &self.0
21    }
22}
23
24impl DerefMut for Rope {
25    fn deref_mut(&mut self) -> &mut Self::Target {
26        &mut self.0
27    }
28}
29
30impl From<crop::Rope> for Rope {
31    fn from(rope: crop::Rope) -> Self {
32        Self(rope)
33    }
34}
35
36impl From<Rope> for crop::Rope {
37    fn from(rope: Rope) -> Self {
38        rope.0
39    }
40}
41
42impl From<&str> for Rope {
43    fn from(s: &str) -> Self {
44        Self(crop::Rope::from(s))
45    }
46}
47
48impl From<String> for Rope {
49    fn from(s: String) -> Self {
50        Self(crop::Rope::from(s))
51    }
52}
53
54impl Rope {
55    pub fn line_column_of_byte(&self, byte_offset: usize) -> (usize, usize) {
56        self.byte_slice(..).line_column_of_byte(byte_offset)
57    }
58}
59
60/// This is publicly exposed because we need it for the interactive fixing
61/// feature, but should _not_ be considered part of the public API. There are
62/// no guarantees about the stability of this type and its methods.
63#[doc(hidden)]
64pub trait RopeSliceExt {
65    fn eq_str(&self, s: &str) -> bool;
66    fn line_column_of_byte(&self, byte_offset: usize) -> (usize, usize);
67}
68
69impl RopeSliceExt for RopeSlice<'_> {
70    fn eq_str(&self, s: &str) -> bool {
71        let mut this = self.bytes();
72        let mut s = s.as_bytes().iter();
73
74        loop {
75            match (this.next(), s.next()) {
76                (Some(this_byte), Some(s_byte)) => {
77                    if this_byte != *s_byte {
78                        return false;
79                    }
80                    continue;
81                }
82                (None, None) => return true,
83                _ => return false,
84            }
85        }
86    }
87
88    fn line_column_of_byte(&self, byte_offset: usize) -> (usize, usize) {
89        let line = self.line_of_byte(byte_offset);
90        let start_of_line = self.byte_of_line(line);
91        let column = byte_offset - start_of_line;
92        (line, column)
93    }
94}
95
96#[cfg(test)]
97mod tests {
98    use crate::rope::{Rope, RopeSliceExt as _};
99
100    #[test]
101    fn test_eq_str() {
102        let rope = Rope::from("hello world");
103        assert!(rope.byte_slice(0..5).eq_str("hello"));
104        assert!(rope.byte_slice(6..11).eq_str("world"));
105        assert!(rope.byte_slice(..).eq_str("hello world"));
106        assert!(!rope.byte_slice(0..4).eq_str("hello"));
107        assert!(!rope.byte_slice(0..5).eq_str("world"));
108        assert!(!rope.byte_slice(6..11).eq_str("hello worlds"));
109    }
110}