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