1use std::borrow::Cow;
2use std::ops::{Bound, RangeBounds};
3
4use ropey::{Rope, RopeSlice};
5
6macro_rules! common_rope_ext_trait {
7 () => {
8 fn to_contiguous<'a>(&'a self) -> Cow<'a, str>;
9 fn discontangle<'a, 'b>(&'a self, contiguous: &'b str, s: &'b str) -> RopeSlice<'a>;
10 fn is_empty(&self) -> bool;
11 fn slice_bytes<R>(&self, byte_range: R) -> RopeSlice
12 where
13 R: RangeBounds<usize>;
14
15 fn memchr(&self, needle: u8, offset: usize) -> usize;
18
19 fn find(&self, needle: &str) -> Option<usize>;
22
23 fn rfind(&self, needle: &str) -> Option<usize>;
26 };
27}
28
29pub trait RopeExt {
30 fn push(&mut self, c: char);
31 fn push_str(&mut self, s: &str);
32 fn push_string(&mut self, s: String);
33 common_rope_ext_trait!();
34}
35
36pub trait RopeSliceExt {
37 common_rope_ext_trait!();
38}
39
40macro_rules! common_rope_ext_impl {
41 () => {
42 fn to_contiguous<'a>(&'a self) -> Cow<'a, str> {
43 let mut it = self.chunks();
44 match it.next() {
45 None => Cow::default(),
46 Some(chunk) if it.next().is_none() => chunk.into(),
47 _ => self.to_string().into(),
48 }
49 }
50
51 fn discontangle<'a, 'b>(&'a self, contiguous: &'b str, s: &'b str) -> RopeSlice<'a> {
53 if s.is_empty() {
54 return self.slice(0..0);
55 }
56
57 let offset = s.as_ptr() as usize - contiguous.as_ptr() as usize;
58 let start = self.byte_to_char(offset);
59 let end = self.byte_to_char(offset + s.len());
60 self.slice(start..end)
61 }
62
63 fn is_empty(&self) -> bool {
64 return self.len_bytes() == 0;
65 }
66
67 fn slice_bytes<R>(&self, byte_range: R) -> RopeSlice
68 where
69 R: RangeBounds<usize>,
70 {
71 match (byte_range.start_bound(), byte_range.end_bound()) {
72 (Bound::Included(start), Bound::Excluded(end)) => {
73 self.slice(self.byte_to_char(*start)..self.byte_to_char(*end))
74 }
75 (Bound::Included(start), Bound::Included(end)) => {
76 self.slice(self.byte_to_char(*start)..=self.byte_to_char(*end))
77 }
78 (Bound::Excluded(start), Bound::Included(end)) => {
79 self.slice(self.byte_to_char(*start + 1)..=self.byte_to_char(*end))
80 }
81 (Bound::Excluded(start), Bound::Excluded(end)) => {
82 self.slice(self.byte_to_char(*start + 1)..self.byte_to_char(*end))
83 }
84 (Bound::Unbounded, Bound::Unbounded) => self.slice(..),
85 (Bound::Unbounded, Bound::Included(end)) => self.slice(..=self.byte_to_char(*end)),
86 (Bound::Unbounded, Bound::Excluded(end)) => self.slice(..self.byte_to_char(*end)),
87 (Bound::Included(start), Bound::Unbounded) => {
88 self.slice(self.byte_to_char(*start)..)
89 }
90 (Bound::Excluded(start), Bound::Unbounded) => {
91 self.slice(self.byte_to_char(*start + 1)..)
92 }
93 }
94 }
95
96 fn memchr(&self, needle: u8, offset: usize) -> usize {
97 let mut bygones = offset;
98 let (chunks, chunk_start, _, _) = self.chunks_at_byte(offset);
99 let mut skip = offset - chunk_start;
100
101 for mut chunk in chunks {
102 if skip > 0 {
103 chunk = &chunk[skip..];
104 skip = 0;
105 }
106
107 match memchr::memchr(needle, &chunk.as_bytes()) {
108 Some(index) => return index + bygones,
109 None => {
110 bygones += chunk.len();
111 }
112 }
113 }
114
115 bygones
116 }
117
118 fn find(&self, needle: &str) -> Option<usize> {
119 match self.slice(..).as_str() {
124 Some(s) => s.find(needle),
125 None => self.to_string().find(needle),
126 }
127 }
128
129 fn rfind(&self, needle: &str) -> Option<usize> {
130 match self.slice(..).as_str() {
135 Some(s) => s.rfind(needle),
136 None => self.to_string().rfind(needle),
137 }
138 }
139 };
140}
141
142impl RopeExt for Rope {
143 fn push(&mut self, c: char) {
144 let pos = self.len_chars();
145 self.insert_char(pos, c);
146 }
147
148 fn push_str(&mut self, s: &str) {
149 let pos = self.len_chars();
150 self.insert(pos, s);
151 }
152
153 fn push_string(&mut self, s: String) {
154 self.append(Rope::from(s));
155 }
156
157 common_rope_ext_impl!();
158}
159
160impl RopeSliceExt for RopeSlice<'_> {
161 common_rope_ext_impl!();
162}