1use std::ops::Range;
15
16use bincode::{Decode, Encode};
17
18use super::{Point, Text};
19use crate::{add_shifts, merging_range_by_guess_and_lazy_shift};
20
21#[derive(Default, Debug, Clone, Encode, Decode)]
23pub struct History {
24 moments: Vec<Moment>,
25 cur_moment: usize,
26 new_moment: Option<(Moment, (usize, [i32; 3]))>,
27 unproc_moment: Option<(Moment, (usize, [i32; 3]))>,
29}
30
31impl History {
32 pub fn new() -> Self {
34 Self::default()
35 }
36
37 pub fn apply_change(&mut self, guess_i: Option<usize>, change: Change<String>) -> usize {
48 let (moment, shift_state) = self.unproc_moment.get_or_insert_default();
49 moment.add_change(guess_i, change.clone(), shift_state);
50
51 let (moment, shift_state) = self.new_moment.get_or_insert_default();
52 moment.add_change(guess_i, change, shift_state)
53 }
54
55 pub fn new_moment(&mut self) {
58 let Some((mut new_moment, (sh_from, shift))) = self.new_moment.take() else {
59 return;
60 };
61 if shift != [0; 3] {
62 for change in new_moment.0[sh_from..].iter_mut() {
63 change.shift_by(shift);
64 }
65 }
66
67 self.moments.truncate(self.cur_moment);
68 self.moments.push(new_moment);
69 self.cur_moment += 1;
70 }
71
72 pub fn move_forward(&mut self) -> Option<Vec<Change<&str>>> {
77 self.new_moment();
78 if self.cur_moment == self.moments.len() {
79 None
80 } else {
81 self.cur_moment += 1;
82 Some(
83 self.moments[self.cur_moment - 1]
84 .0
85 .iter()
86 .map(|c| c.as_ref())
87 .collect(),
88 )
89 }
90 }
91
92 pub fn move_backwards(&mut self) -> Option<Vec<Change<&str>>> {
98 self.new_moment();
99 if self.cur_moment == 0 {
100 None
101 } else {
102 self.cur_moment -= 1;
103
104 let mut shift = [0; 3];
105 let iter = self.moments[self.cur_moment].0.iter().map(move |change| {
106 let mut change = change.as_ref();
107 change.shift_by(shift);
108
109 shift = add_shifts(shift, change.reverse().shift());
110
111 change.reverse()
112 });
113 Some(iter.collect())
114 }
115 }
116
117 pub fn unprocessed_changes(&mut self) -> Option<Vec<Change<String>>> {
118 self.unproc_moment
119 .take()
120 .map(|(mut moment, (sh_from, shift))| {
121 if shift != [0; 3] {
122 for change in moment.0[sh_from..].iter_mut() {
123 change.shift_by(shift);
124 }
125 }
126 moment.0
127 })
128 }
129
130 pub fn has_unprocessed_changes(&self) -> bool {
131 self.unproc_moment.as_ref().is_some()
132 }
133}
134
135#[derive(Default, Debug, Clone, Encode, Decode)]
141pub struct Moment(Vec<Change<String>>);
142
143impl Moment {
144 fn add_change(
147 &mut self,
148 guess_i: Option<usize>,
149 mut change: Change<String>,
150 shift_state: &mut (usize, [i32; 3]),
151 ) -> usize {
152 let (sh_from, shift) = std::mem::take(shift_state);
153 let new_shift = change.shift();
154
155 let c_range = merging_range_by_guess_and_lazy_shift(
157 (&self.0, self.0.len()),
158 (guess_i.unwrap_or(0), [change.start(), change.taken_end()]),
159 (sh_from, shift, [0; 3], Point::shift_by),
160 (Change::start, Change::added_end),
161 );
162
163 if sh_from < c_range.end && shift != [0; 3] {
166 for change in &mut self.0[sh_from..c_range.end] {
167 change.shift_by(shift);
168 }
169 } else if sh_from > c_range.end && new_shift != [0; 3] {
176 for change in &mut self.0[c_range.end..sh_from] {
177 change.shift_by(shift);
178 }
179 }
180
181 for c in self.0.drain(c_range.clone()).rev() {
182 change.try_merge(c);
183 }
184
185 let changes_taken = c_range.clone().count();
186 let new_sh_from = if !(change.added_text() == "" && change.taken_text() == "") {
187 self.0.insert(c_range.start, change);
188 sh_from.saturating_sub(changes_taken).max(c_range.start) + 1
189 } else {
190 sh_from.saturating_sub(changes_taken).max(c_range.start)
191 };
192 if new_sh_from < self.0.len() {
194 let shift = add_shifts(shift, new_shift);
195 *shift_state = (new_sh_from, shift);
196 }
197
198 c_range.start
199 }
200
201 pub fn changes(&self) -> &[Change<String>] {
202 &self.0
203 }
204}
205
206#[derive(Default, Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
208pub struct Change<S: AsRef<str>> {
209 start: Point,
210 added: S,
211 taken: S,
212 added_end: Point,
213 taken_end: Point,
214}
215
216impl Change<String> {
217 pub fn new(edit: impl ToString, [p0, p1]: [Point; 2], text: &Text) -> Self {
219 let added = {
220 let edit = edit.to_string();
221 if p1 == text.len() && !edit.ends_with('\n') {
223 edit + "\n"
224 } else {
225 edit
226 }
227 };
228
229 let taken = text.strs(p0.byte()..p1.byte()).collect();
230 let added_end = p0 + Point::len_of(&added);
231 Change {
232 start: p0,
233 added,
234 taken,
235 added_end,
236 taken_end: p1,
237 }
238 }
239
240 pub fn as_ref(&self) -> Change<&str> {
242 Change {
243 start: self.start,
244 added: &self.added,
245 taken: &self.taken,
246 added_end: self.added_end,
247 taken_end: self.taken_end,
248 }
249 }
250
251 pub fn try_merge(&mut self, mut older: Self) {
256 if has_start_of(older.added_range(), self.taken_range()) {
257 let fixed_end = older.added_end().min(self.taken_end());
258
259 let start = self.start - older.start;
260 let end = fixed_end - older.start;
261 let range = start.byte()..end.byte();
262 older.added.replace_range(range, &self.added);
263
264 let range = (fixed_end.byte() - self.start.byte())..;
265 older.taken.push_str(&self.taken[range]);
266
267 *self = older;
268 } else if has_start_of(self.taken_range(), older.added_range()) {
269 let fixed_end = self.taken_end().min(older.added_end());
270
271 let start = older.start - self.start;
272 let end = fixed_end - self.start;
273 let range = start.byte()..end.byte();
274 self.taken.replace_range(range, &older.taken);
275
276 let range = (fixed_end.byte() - older.start.byte())..;
277
278 self.added.push_str(&older.added[range]);
279 } else {
280 unreachable!("Changes chosen that don't interact");
281 }
282 self.added_end = self.start + Point::len_of(&self.added);
283 self.taken_end = self.start + Point::len_of(&self.taken);
284 }
285}
286
287impl<'a> Change<&'a str> {
288 pub fn str_insert(added_text: &'a str, start: Point) -> Self {
290 Self {
291 start,
292 added: added_text,
293 taken: "",
294 added_end: start + Point::len_of(added_text),
295 taken_end: start,
296 }
297 }
298
299 pub(super) fn remove_nl(p0: Point) -> Self {
301 Change {
302 start: p0,
303 added: "",
304 taken: "\n",
305 added_end: p0,
306 taken_end: p0 + Point::len_of("\n"),
307 }
308 }
309}
310
311impl<S: AsRef<str>> Change<S> {
312 pub fn reverse(self) -> Change<S> {
314 Change {
315 start: self.start,
316 added: self.taken,
317 taken: self.added,
318 added_end: self.taken_end,
319 taken_end: self.added_end,
320 }
321 }
322
323 pub fn start(&self) -> Point {
325 self.start
326 }
327
328 pub(crate) fn shift_by(&mut self, shift: [i32; 3]) {
330 self.start = self.start.shift_by(shift);
331 self.added_end = self.added_end.shift_by(shift);
332 self.taken_end = self.taken_end.shift_by(shift);
333 }
334
335 pub fn taken_end(&self) -> Point {
337 self.taken_end
338 }
339
340 pub fn added_end(&self) -> Point {
342 self.added_end
343 }
344
345 pub fn taken_range(&self) -> Range<usize> {
347 self.start.byte()..self.taken_end().byte()
348 }
349
350 pub fn added_range(&self) -> Range<usize> {
352 self.start.byte()..self.added_end().byte()
353 }
354
355 pub fn added_text(&self) -> &str {
357 self.added.as_ref()
358 }
359
360 pub fn taken_text(&self) -> &str {
362 self.taken.as_ref()
363 }
364
365 pub fn shift(&self) -> [i32; 3] {
367 [
368 self.added_end().byte() as i32 - self.taken_end().byte() as i32,
369 self.added_end().char() as i32 - self.taken_end().char() as i32,
370 self.added_end().line() as i32 - self.taken_end().line() as i32,
371 ]
372 }
373}
374
375impl Copy for Change<&str> {}
376
377fn has_start_of(lhs: Range<usize>, rhs: Range<usize>) -> bool {
379 lhs.start <= rhs.start && rhs.start <= lhs.end
380}