1#![feature(decl_macro, iter_order_by)]
12
13use std::ops::Range;
14
15use duat_core::{
16 Plugin, Plugins,
17 buffer::{Buffer, BufferTracker, Parser},
18 hook,
19};
20use gapbuf::GapBuffer;
21
22#[derive(Default)]
29pub struct JumpList;
30
31impl Plugin for JumpList {
32 fn plug(self, _: &Plugins) {
33 hook::add::<Buffer>(|pa, handle| handle.add_parser(pa, Jumps::new));
34 }
35}
36
37#[derive(Clone, Debug)]
46pub enum Jump {
47 Single(Range<usize>),
48 Multiple(Vec<Range<usize>>, usize),
49}
50
51impl Jump {
52 fn shift(&mut self, changes: &Changes) -> bool {
53 match self {
54 Jump::Single(selection) => {
55 if let Some(new) = changes.shift_selection(selection.clone()) {
56 *selection = new;
57 true
58 } else {
59 false
60 }
61 }
62 Jump::Multiple(selections, _) => {
63 changes.shift_selections(selections);
64 !selections.is_empty()
65 }
66 }
67 }
68}
69
70#[derive(Debug)]
71struct Jumps {
72 list: GapBuffer<Saved>,
73 tracker: BufferTracker,
74 cur: usize,
75}
76
77impl Jumps {
78 fn new(tracker: BufferTracker) -> Self {
79 Self { list: GapBuffer::new(), tracker, cur: 0 }
80 }
81}
82
83impl Parser for Jumps {
84 fn parse(&mut self) -> bool {
85 false
86 }
87
88 fn before_get(&mut self) {
89 self.tracker.update();
90
91 if self.list.is_empty() || self.tracker.moment().is_empty() {
94 return;
95 }
96 self.list.truncate(self.cur);
97
98 if self.cur == 0 {
99 return;
100 }
101
102 let changes = if let Saved::Changes(changes) = &mut self.list[self.cur - 1] {
103 changes
104 } else {
105 self.list.insert(self.cur, Saved::Changes(Box::default()));
106 self.cur += 1;
107 let Some(Saved::Changes(changes)) = self.list.get_mut(self.cur - 1) else {
108 unreachable!();
109 };
110 changes
111 };
112
113 for change in self.tracker.moment().changes() {
114 let change = (
115 change.start().byte() as i32,
116 change.taken_end().byte() as i32,
117 change.added_end().byte() as i32,
118 );
119 changes.add_change(change);
120 }
121 }
122
123 fn before_try_get(&mut self) -> bool {
124 self.before_get();
125 true
126 }
127}
128
129#[derive(Debug)]
130enum Saved {
131 Jump(Jump),
132 Changes(Box<Changes>),
133}
134
135pub trait BufferJumps {
144 fn record_selections(&mut self, allow_duplicates: bool) -> bool;
154
155 fn jump_selections_by(&mut self, by: i32) -> Option<Jump>;
166
167 fn jump_to_selections(&mut self, n: usize) -> Option<Jump>;
178}
179
180impl BufferJumps for Buffer {
181 fn record_selections(&mut self, allow_duplicates: bool) -> bool {
182 self.write_parser(|jumps: &mut Jumps| {
183 let selections = self.selections();
184
185 if !allow_duplicates {
186 for i in [Some(jumps.cur), jumps.cur.checked_sub(1)]
187 .into_iter()
188 .flatten()
189 {
190 let Some(Saved::Jump(jump)) = jumps.list.get(i) else {
191 continue;
192 };
193
194 match jump {
195 Jump::Single(sel) => {
196 if selections.len() == 1
197 && selections.get_main().unwrap().byte_range(self.bytes()) == *sel
198 {
199 return false;
200 }
201 }
202 Jump::Multiple(sels, main) => {
203 if *main == selections.main_index()
204 && sels.iter().eq_by(selections.iter(), |lhs, (rhs, _)| {
205 *lhs == rhs.byte_range(self.bytes())
206 })
207 {
208 return false;
209 }
210 }
211 }
212 }
213 }
214
215 if selections.len() == 1 {
216 jumps.list.insert(
217 jumps.cur,
218 Saved::Jump(Jump::Single(
219 selections.get_main().unwrap().byte_range(self.bytes()),
220 )),
221 );
222 } else if selections.len() > 1 {
223 jumps.list.insert(
224 jumps.cur,
225 Saved::Jump(Jump::Multiple(
226 selections
227 .iter()
228 .map(|(sel, _)| sel.byte_range(self.bytes()))
229 .collect(),
230 selections.main_index(),
231 )),
232 );
233 }
234 jumps.cur += 1;
235
236 true
237 })
238 .unwrap()
239 }
240
241 fn jump_selections_by(&mut self, mut by: i32) -> Option<Jump> {
242 self.write_parser(|jumps: &mut Jumps| {
243 let mut changes = Changes::default();
244 let mut last_seen = None;
245
246 let jump = if by >= 0 {
247 loop {
248 match jumps.list.get_mut(jumps.cur) {
249 Some(Saved::Jump(jump)) => {
250 if by == 0 {
251 break Some(jump.clone());
252 } else if jumps.cur + 1 < jumps.list.len() {
253 last_seen = Some(jumps.cur);
254 by -= 1;
255 jumps.cur += 1;
256 } else {
257 break None;
258 }
259 }
260 Some(Saved::Changes(_)) => unreachable!(),
261 None => break None,
262 }
263 }
264 } else {
265 loop {
266 match jumps.cur.checked_sub(1).and_then(|j| jumps.list.get_mut(j)) {
267 Some(Saved::Jump(jump)) => {
268 jumps.cur -= 1;
269 if jump.shift(&changes) {
270 by += 1;
271 if by == 0 {
272 let jump = jump.clone();
273 if !changes.list.is_empty() && jumps.cur > 0 {
274 jumps
275 .list
276 .insert(jumps.cur, Saved::Changes(Box::new(changes)));
277 jumps.cur += 1;
278 }
279 break Some(jump);
280 } else {
281 last_seen = Some(jumps.cur);
282 }
283 } else {
284 if let Some(last_seen) = last_seen.as_mut() {
285 *last_seen -= 1;
286 }
287 jumps.list.remove(jumps.cur);
288 }
289 }
290 Some(Saved::Changes(_)) => {
291 if let Some(last_seen) = last_seen.as_mut() {
292 *last_seen -= 1;
293 }
294 jumps.cur -= 1;
295 let Saved::Changes(rev) = jumps.list.remove(jumps.cur) else {
296 unreachable!();
297 };
298 changes.merge(*rev);
299 }
300 None => break None,
301 }
302 }
303 };
304
305 jump.or_else(|| {
306 last_seen.map(|i| {
307 let Some(Saved::Jump(jump)) = jumps.list.get(i) else {
308 unreachable!();
309 };
310 jump.clone()
311 })
312 })
313 })
314 .flatten()
315 }
316
317 fn jump_to_selections(&mut self, n: usize) -> Option<Jump> {
318 let cur_n = self.write_parser(|jumps: &mut Jumps| {
319 jumps
320 .list
321 .iter()
322 .take(jumps.cur)
323 .filter(|s| matches!(s, Saved::Jump(_)))
324 .count()
325 })?;
326
327 self.jump_selections_by(n as i32 - cur_n as i32)
328 }
329}
330
331#[derive(Default, Debug)]
332struct Changes {
333 list: GapBuffer<(i32, i32, i32)>,
334 from: usize,
335 by: i32,
336}
337
338impl Changes {
339 fn add_change(&mut self, (start, taken_end, added_end): (i32, i32, i32)) {
340 let m_range = duat_core::utils::merging_range_by_guess_and_lazy_shift(
341 (&self.list, self.list.len()),
342 (0, [start, taken_end]),
343 (self.from, self.by, 0, std::ops::Add::add),
344 (|(start, ..)| *start, |(.., added_end)| *added_end),
345 );
346
347 if self.by != 0 && self.from < m_range.end {
348 for (start, taken_end, added_end) in &mut self.list.range_mut(self.from..m_range.end) {
349 *start += self.by;
350 *taken_end += self.by;
351 *added_end += self.by;
352 }
353 } else if self.by != 0 && m_range.end < self.from {
354 for (start, taken_end, added_end) in &mut self.list.range_mut(self.from..m_range.end) {
355 *start -= self.by;
356 *taken_end -= self.by;
357 *added_end -= self.by;
358 }
359 }
360
361 let (start, taken_end, added_end) = if m_range.start < m_range.end {
362 let (first_start, ..) = self.list[m_range.start];
363 let (_, last_taken_end, last_added_end) = self.list[m_range.end - 1];
364 (
365 start.min(first_start),
366 taken_end.max(last_taken_end),
367 added_end.max(last_added_end),
368 )
369 } else {
370 (start, taken_end, added_end)
371 };
372
373 self.list.splice(
374 m_range.clone(),
375 (taken_end != added_end).then_some((start, taken_end, added_end)),
376 );
377
378 let new_from = m_range.start + (taken_end != added_end) as usize;
379 if new_from < self.list.len() {
380 self.from = new_from;
381 } else {
382 self.from = 0;
383 self.by = 0;
384 }
385 }
386
387 fn merge(&mut self, other: Self) {
388 for change in other.iter() {
389 self.add_change(change);
390 }
391 }
392
393 fn iter(&self) -> impl Iterator<Item = (i32, i32, i32)> {
394 self.list
395 .iter()
396 .enumerate()
397 .map(|(i, &(start, taken_end, added_end))| {
398 if self.by != 0 && i >= self.from {
399 (start + self.by, taken_end + self.by, added_end + self.by)
400 } else {
401 (start, taken_end, added_end)
402 }
403 })
404 }
405
406 fn shift_selection(&self, mut selection: Range<usize>) -> Option<Range<usize>> {
407 for change in self.iter() {
408 selection = shift_selection(selection.clone(), change)?;
409
410 if change.0 as usize >= selection.end {
411 break;
412 }
413 }
414
415 Some(selection)
416 }
417
418 fn shift_selections(&self, selections: &mut Vec<Range<usize>>) {
419 let mut total_shift = 0;
420 let mut changes = self.iter().peekable();
421
422 selections.retain_mut(|selection| {
423 selection.start = (selection.start as i32 + total_shift) as usize;
424 selection.end = (selection.end as i32 + total_shift) as usize;
425
426 while let Some(&change) = changes.peek() {
427 let Some(new) = shift_selection(selection.clone(), change) else {
428 return false;
429 };
430 *selection = new;
431
432 if change.1 as usize <= selection.start {
433 changes.next();
434 total_shift += change.2 - change.1;
435 } else if change.0 as usize >= selection.end {
436 break;
437 }
438 }
439
440 true
441 });
442 }
443}
444
445fn shift_selection(
446 mut selection: Range<usize>,
447 (start, taken_end, added_end): (i32, i32, i32),
448) -> Option<Range<usize>> {
449 let shift = added_end - taken_end;
450 let (start, taken_end) = (start as usize, taken_end as usize);
451
452 if taken_end <= selection.start {
453 selection.start = (selection.start as i32 + shift) as usize;
454 selection.end = (selection.end as i32 + shift) as usize;
455 } else if taken_end < selection.end {
456 selection.start = added_end as usize;
457 selection.end = (selection.end as i32 + shift) as usize;
458 } else if start <= selection.start {
459 return None;
460 } else if start < selection.end {
461 selection.end = start
462 }
463 Some(selection)
464}