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)]
23pub struct History {
24 moments: Vec<Moment>,
25 cur_moment: usize,
26 new_changes: Option<(Vec<Change>, (usize, [i32; 3]))>,
27 unproc_changes: Option<(Vec<Change>, (usize, [i32; 3]))>,
29 unproc_moments: Vec<Moment>,
30}
31
32impl History {
33 pub fn new() -> Self {
35 Self::default()
36 }
37
38 pub fn apply_change(&mut self, guess_i: Option<usize>, change: Change) -> usize {
49 let (changes, shift_state) = self.unproc_changes.get_or_insert_default();
50 add_change(changes, guess_i, change.clone(), shift_state);
51
52 let (changes, shift_state) = self.new_changes.get_or_insert_default();
53 add_change(changes, guess_i, change, shift_state)
54 }
55
56 pub fn new_moment(&mut self) {
59 let Some((mut new_changes, (sh_from, shift))) = self.new_changes.take() else {
60 return;
61 };
62 finish_shifting(&mut new_changes, sh_from, shift);
63
64 if let Some((mut unproc_changes, (sh_from, shift))) = self.unproc_changes.take() {
65 finish_shifting(&mut unproc_changes, sh_from, shift);
66 self.unproc_moments.push(Moment {
67 changes: Box::leak(Box::from(unproc_changes)),
68 is_fwd: true,
69 });
70 }
71
72 self.moments.truncate(self.cur_moment);
73
74 self.moments.push(Moment {
75 changes: Box::leak(Box::from(new_changes)),
76 is_fwd: true,
77 });
78 self.cur_moment += 1;
79 }
80
81 pub fn move_forward(&mut self) -> Option<Moment> {
86 self.new_moment();
87 if self.cur_moment == self.moments.len() {
88 None
89 } else {
90 self.cur_moment += 1;
91 self.unproc_moments.push(self.moments[self.cur_moment - 1]);
92 Some(self.moments[self.cur_moment - 1])
93 }
94 }
95
96 pub fn move_backwards(&mut self) -> Option<Moment> {
102 self.new_moment();
103 if self.cur_moment == 0 {
104 None
105 } else {
106 self.cur_moment -= 1;
107 let mut moment = self.moments[self.cur_moment];
108 moment.is_fwd = false;
109 self.unproc_moments.push(moment);
110 Some(moment)
111 }
112 }
113
114 pub fn unprocessed_moments(&mut self) -> Vec<Moment> {
115 let fresh_moment = self
116 .unproc_changes
117 .take()
118 .map(|(mut changes, (sh_from, shift))| {
119 finish_shifting(&mut changes, sh_from, shift);
120
121 Moment {
122 changes: Box::leak(Box::from(changes)),
123 is_fwd: true,
124 }
125 });
126
127 self.unproc_moments.extend(fresh_moment);
128
129 std::mem::take(&mut self.unproc_moments)
130 }
131
132 pub fn has_unprocessed_changes(&self) -> bool {
133 self.unproc_changes.as_ref().is_some()
134 }
135}
136
137impl<Context> Decode<Context> for History {
138 fn decode<D: bincode::de::Decoder<Context = Context>>(
139 decoder: &mut D,
140 ) -> Result<Self, bincode::error::DecodeError> {
141 Ok(History {
142 moments: Decode::decode(decoder)?,
143 cur_moment: Decode::decode(decoder)?,
144 new_changes: Decode::decode(decoder)?,
145 unproc_changes: Decode::decode(decoder)?,
146 unproc_moments: Decode::decode(decoder)?,
147 })
148 }
149}
150
151#[derive(Clone, Copy, Default, Debug, Encode)]
157pub struct Moment {
158 changes: &'static [Change],
159 is_fwd: bool,
160}
161
162impl Moment {
163 pub fn changes(&self) -> impl ExactSizeIterator<Item = Change<&str>> + '_ {
168 let mut shift = [0; 3];
169 self.changes.iter().map(move |change| {
170 if self.is_fwd {
171 change.as_ref()
172 } else {
173 let mut change = change.as_ref().reverse();
174 change.shift_by(shift);
175
176 shift = add_shifts(shift, change.shift());
177
178 change
179 }
180 })
181 }
182
183 #[allow(clippy::len_without_is_empty)]
187 pub fn len(&self) -> usize {
188 self.changes.len()
189 }
190}
191
192impl<Context> Decode<Context> for Moment {
193 fn decode<D: bincode::de::Decoder<Context = Context>>(
194 decoder: &mut D,
195 ) -> Result<Self, bincode::error::DecodeError> {
196 Ok(Moment {
197 changes: Vec::decode(decoder)?.leak(),
198 is_fwd: Decode::decode(decoder)?,
199 })
200 }
201}
202
203fn add_change(
206 changes: &mut Vec<Change>,
207 guess_i: Option<usize>,
208 mut change: Change,
209 shift_state: &mut (usize, [i32; 3]),
210) -> usize {
211 let (sh_from, shift) = std::mem::take(shift_state);
212 let new_shift = change.shift();
213
214 let c_range = merging_range_by_guess_and_lazy_shift(
216 (changes, changes.len()),
217 (guess_i.unwrap_or(0), [change.start(), change.taken_end()]),
218 (sh_from, shift, [0; 3], Point::shift_by),
219 (Change::start, Change::added_end),
220 );
221
222 if sh_from < c_range.end && shift != [0; 3] {
225 for change in &mut changes[sh_from..c_range.end] {
226 change.shift_by(shift);
227 }
228 } else if sh_from > c_range.end && new_shift != [0; 3] {
235 let shift = change.shift();
236 for change in &mut changes[c_range.end..sh_from] {
237 change.shift_by(shift);
238 }
239 }
240
241 for c in changes.drain(c_range.clone()).rev() {
242 change.try_merge(c);
243 }
244
245 let changes_taken = c_range.clone().count();
246 let new_sh_from = if !(change.added_str() == "" && change.taken_str() == "") {
247 changes.insert(c_range.start, change);
248 sh_from.saturating_sub(changes_taken).max(c_range.start) + 1
249 } else {
250 sh_from.saturating_sub(changes_taken).max(c_range.start)
251 };
252 if new_sh_from < changes.len() {
254 let shift = add_shifts(shift, new_shift);
255 *shift_state = (new_sh_from, shift);
256 }
257
258 c_range.start
259}
260
261#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Encode, Decode)]
263pub struct Change<S = String> {
264 start: Point,
265 added: S,
266 taken: S,
267 added_end: Point,
268 taken_end: Point,
269}
270
271impl Change {
272 pub fn new(edit: impl ToString, [p0, p1]: [Point; 2], text: &Text) -> Self {
274 let added = {
275 let edit = edit.to_string();
276 if p1 == text.len() && !edit.ends_with('\n') {
278 edit + "\n"
279 } else {
280 edit
281 }
282 };
283
284 let taken = text.strs(p0.byte()..p1.byte()).collect();
285 let added_end = p0 + Point::len_of(&added);
286 Change {
287 start: p0,
288 added,
289 taken,
290 added_end,
291 taken_end: p1,
292 }
293 }
294
295 pub fn as_ref(&self) -> Change<&str> {
297 Change {
298 start: self.start,
299 added: &self.added,
300 taken: &self.taken,
301 added_end: self.added_end,
302 taken_end: self.taken_end,
303 }
304 }
305
306 pub fn try_merge(&mut self, mut older: Self) {
311 if has_start_of(older.added_range(), self.taken_range()) {
312 let fixed_end = older.added_end().min(self.taken_end());
313
314 let start = self.start - older.start;
315 let end = fixed_end - older.start;
316 let range = start.byte()..end.byte();
317 older.added.replace_range(range, &self.added);
318
319 let range = (fixed_end.byte() - self.start.byte())..;
320 older.taken.push_str(&self.taken[range]);
321
322 *self = older;
323 } else if has_start_of(self.taken_range(), older.added_range()) {
324 let fixed_end = self.taken_end().min(older.added_end());
325
326 let start = older.start - self.start;
327 let end = fixed_end - self.start;
328 let range = start.byte()..end.byte();
329 self.taken.replace_range(range, &older.taken);
330
331 let range = (fixed_end.byte() - older.start.byte())..;
332
333 self.added.push_str(&older.added[range]);
334 } else {
335 unreachable!("Changes chosen that don't interact");
336 }
337 self.added_end = self.start + Point::len_of(&self.added);
338 self.taken_end = self.start + Point::len_of(&self.taken);
339 }
340}
341
342impl<'a> Change<&'a str> {
343 pub fn str_insert(added_str: &'a str, start: Point) -> Self {
345 Self {
346 start,
347 added: added_str,
348 taken: "",
349 added_end: start + Point::len_of(added_str),
350 taken_end: start,
351 }
352 }
353
354 pub(super) fn remove_last_nl(len: Point) -> Self {
355 Self {
356 start: len.rev('\n'),
357 added: "",
358 taken: "\n",
359 added_end: len.rev('\n'),
360 taken_end: len,
361 }
362 }
363}
364
365impl<S: AsRef<str>> Change<S> {
366 pub fn reverse(self) -> Change<S> {
368 Change {
369 start: self.start,
370 added: self.taken,
371 taken: self.added,
372 added_end: self.taken_end,
373 taken_end: self.added_end,
374 }
375 }
376
377 pub fn start(&self) -> Point {
379 self.start
380 }
381
382 pub(crate) fn shift_by(&mut self, shift: [i32; 3]) {
384 self.start = self.start.shift_by(shift);
385 self.added_end = self.added_end.shift_by(shift);
386 self.taken_end = self.taken_end.shift_by(shift);
387 }
388
389 pub fn taken_end(&self) -> Point {
391 self.taken_end
392 }
393
394 pub fn added_end(&self) -> Point {
396 self.added_end
397 }
398
399 pub fn taken_range(&self) -> Range<usize> {
401 self.start.byte()..self.taken_end().byte()
402 }
403
404 pub fn added_range(&self) -> Range<usize> {
406 self.start.byte()..self.added_end().byte()
407 }
408
409 pub fn added_str(&self) -> &str {
411 self.added.as_ref()
412 }
413
414 pub fn taken_str(&self) -> &str {
416 self.taken.as_ref()
417 }
418
419 pub fn shift(&self) -> [i32; 3] {
421 [
422 self.added_end().byte() as i32 - self.taken_end().byte() as i32,
423 self.added_end().char() as i32 - self.taken_end().char() as i32,
424 self.added_end().line() as i32 - self.taken_end().line() as i32,
425 ]
426 }
427}
428
429fn has_start_of(lhs: Range<usize>, rhs: Range<usize>) -> bool {
431 lhs.start <= rhs.start && rhs.start <= lhs.end
432}
433
434fn finish_shifting(changes: &mut [Change], sh_from: usize, shift: [i32; 3]) {
435 if shift != [0; 3] {
436 for change in changes[sh_from..].iter_mut() {
437 change.shift_by(shift);
438 }
439 }
440}