1use super::*;
4
5impl Text {
6 pub fn insert(&mut self, at: usize, s: &str) {
8 let at = at.min(self.text.len());
9 if s.is_empty() {
10 return;
11 }
12 let n = s.len();
13 self.text.insert_str(at, s);
14 for span in &mut self.marks {
15 if at <= span.range.start {
16 span.range.start += n;
17 span.range.end += n;
18 } else if at <= span.range.end {
19 span.range.end += n;
21 }
22 }
23 self.normalize_marks();
24 }
25
26 pub fn remove(&mut self, range: Range<usize>) {
28 let range = self.clamp(range);
29 if range.is_empty() {
30 return;
31 }
32 self.text.replace_range(range.clone(), "");
33 let shift = |offset: usize| {
34 if offset <= range.start {
35 offset
36 } else if offset >= range.end {
37 offset - range.len()
38 } else {
39 range.start
40 }
41 };
42 for span in &mut self.marks {
43 span.range = shift(span.range.start)..shift(span.range.end);
44 }
45 self.normalize_marks();
46 }
47
48 pub fn toggle(&mut self, range: Range<usize>, mark: Mark) {
50 let range = self.clamp(range);
51 if range.is_empty() {
52 return;
53 }
54 if self.covered_by(&range, &mark) {
55 self.marks = std::mem::take(&mut self.marks)
56 .into_iter()
57 .flat_map(|span| subtract(span, &range, &mark))
58 .collect();
59 } else {
60 self.marks.push(MarkSpan { range, mark });
61 }
62 self.normalize_marks();
63 }
64
65 pub fn covered_by(&self, range: &Range<usize>, mark: &Mark) -> bool {
67 !range.is_empty()
68 && self.marks.iter().any(|span| {
69 span.mark == *mark && span.range.start <= range.start && span.range.end >= range.end
70 })
71 }
72
73 pub fn split_off(&mut self, at: usize) -> Text {
75 let at = at.min(self.text.len());
76 let mut tail = Text {
77 text: self.text.split_off(at),
78 marks: Vec::new(),
79 };
80 let mut head = Vec::new();
81 for span in std::mem::take(&mut self.marks) {
82 if span.range.start < at {
83 head.push(MarkSpan {
84 range: span.range.start..span.range.end.min(at),
85 mark: span.mark.clone(),
86 });
87 }
88 if span.range.end > at {
89 tail.marks.push(MarkSpan {
90 range: span.range.start.saturating_sub(at)..span.range.end - at,
91 mark: span.mark,
92 });
93 }
94 }
95 self.marks = head;
96 self.normalize_marks();
97 tail.normalize_marks();
98 tail
99 }
100
101 pub fn append(&mut self, other: Text) {
103 let offset = self.text.len();
104 self.text.push_str(&other.text);
105 self.marks
106 .extend(other.marks.into_iter().map(|span| MarkSpan {
107 range: span.range.start + offset..span.range.end + offset,
108 mark: span.mark,
109 }));
110 self.normalize_marks();
111 }
112
113 pub(super) fn clamp(&self, range: Range<usize>) -> Range<usize> {
114 let start = range.start.min(self.text.len());
115 let end = range.end.clamp(start, self.text.len());
116 start..end
117 }
118
119 pub(crate) fn normalize_marks(&mut self) {
125 for ix in 0..self.marks.len() {
131 if !matches!(
132 self.marks[ix].mark,
133 Mark::Bold | Mark::Italic | Mark::Strike | Mark::Code
134 ) {
135 continue;
136 }
137 let range = self.marks[ix].range.clone();
138 if range.end > self.text.len() {
139 continue;
140 }
141 let slice = &self.text[range.clone()];
142 let start = range.start + (slice.len() - slice.trim_start().len());
143 let end = (range.end - (slice.len() - slice.trim_end().len())).max(start);
144 self.marks[ix].range = start..end;
145 }
146
147 let len = self.text.len();
148 self.marks.retain(|span| {
149 span.range.end <= len && (!span.range.is_empty() || matches!(span.mark, Mark::Image(_)))
150 });
151
152 let code: Vec<Range<usize>> = self
156 .marks
157 .iter()
158 .filter(|span| span.mark == Mark::Code)
159 .map(|span| span.range.clone())
160 .collect();
161 for span in &mut self.marks {
162 if span.mark == Mark::Code {
163 continue;
164 }
165 for range in &code {
166 let crosses = span.range.start > range.start && span.range.start < range.end
167 || span.range.end > range.start && span.range.end < range.end;
168 if crosses {
169 span.range.start = span.range.start.min(range.start);
170 span.range.end = span.range.end.max(range.end);
171 }
172 }
173 }
174
175 for _ in 0..self.marks.len().max(1) {
182 let mut crossed = false;
183 for a in 0..self.marks.len() {
184 for b in 0..self.marks.len() {
185 let (first, second) = (&self.marks[a].range, &self.marks[b].range);
186 if second.start > first.start
187 && second.start < first.end
188 && second.end > first.end
189 {
190 let end = second.end;
191 self.marks[a].range.end = end;
192 crossed = true;
193 }
194 }
195 }
196 if !crossed {
197 break;
198 }
199 }
200
201 for _ in 0..self.marks.len().max(1) {
208 let mut nudged = false;
209 for a in 0..self.marks.len() {
210 let end = self.marks[a].range.end;
211 let followed_by_word = self.text[end..]
212 .chars()
213 .next()
214 .is_some_and(char::is_alphanumeric);
215 let shared = self.marks.iter().enumerate().any(|(b, other)| {
216 b != a
217 && other.range.end == end
218 && other.range.start > self.marks[a].range.start
219 });
220 if followed_by_word && shared {
221 let extra = self.text[end..]
222 .find(|c: char| !c.is_alphanumeric())
223 .unwrap_or(self.text.len() - end);
224 self.marks[a].range.end = end + extra;
225 nudged = true;
226 }
227 }
228 if !nudged {
229 break;
230 }
231 }
232
233 let mut ix = 0;
234 while ix < self.marks.len() {
235 let mut merged = None;
236 for other in ix + 1..self.marks.len() {
237 let (a, b) = (&self.marks[ix], &self.marks[other]);
238 if a.mark == b.mark
239 && a.range.start <= b.range.end
240 && b.range.start <= a.range.end
241 && !matches!(a.mark, Mark::Image(_) | Mark::Mention { .. })
242 {
243 merged = Some((
244 other,
245 a.range.start.min(b.range.start),
246 a.range.end.max(b.range.end),
247 ));
248 break;
249 }
250 }
251 match merged {
252 Some((other, start, end)) => {
253 self.marks[ix].range = start..end;
254 self.marks.remove(other);
255 }
256 None => ix += 1,
257 }
258 }
259
260 self.marks.sort_by(|a, b| {
265 a.range
266 .start
267 .cmp(&b.range.start)
268 .then(b.range.end.cmp(&a.range.end))
269 });
270 }
271}
272
273fn subtract(span: MarkSpan, range: &Range<usize>, mark: &Mark) -> Vec<MarkSpan> {
275 if span.mark != *mark || span.range.end <= range.start || span.range.start >= range.end {
276 return vec![span];
277 }
278 let mut out = Vec::new();
279 if span.range.start < range.start {
280 out.push(MarkSpan {
281 range: span.range.start..range.start,
282 mark: span.mark.clone(),
283 });
284 }
285 if span.range.end > range.end {
286 out.push(MarkSpan {
287 range: range.end..span.range.end,
288 mark: span.mark,
289 });
290 }
291 out
292}