1use std::{
12 collections::HashMap,
13 ops::Range,
14 sync::atomic::{AtomicUsize, Ordering},
15};
16
17use duat_core::{
18 Plugin, Plugins,
19 buffer::{Buffer, BufferParts, BufferTracker, PerBuffer},
20 context::Handle,
21 data::Pass,
22 hook::{self, BufferClosed, BufferOpened},
23};
24use gapbuf::GapBuffer;
25
26static TRACKER: BufferTracker = BufferTracker::new();
27static PARSERS: PerBuffer<Parser> = PerBuffer::new();
28
29#[derive(Default)]
36pub struct JumpList;
37
38impl Plugin for JumpList {
39 fn plug(self, _: &Plugins) {
40 hook::add::<BufferOpened>(|pa, handle| {
41 TRACKER.register_buffer(handle.write(pa));
42 PARSERS.register(pa, handle, Parser::new());
43 });
44
45 hook::add::<BufferClosed>(|pa, handle| {
46 PARSERS.unregister(pa, handle);
47 });
48 }
49}
50
51#[derive(Clone, Debug)]
60pub enum Jump {
61 Single(Range<usize>),
62 Multiple(Vec<Range<usize>>, usize),
63}
64
65impl Jump {
66 pub fn is_eq(&self, buf: &Buffer) -> bool {
71 match self {
72 Jump::Single(range) => {
73 buf.selections().len() == 1
74 && buf.selections().main().byte_range(buf.bytes()) == *range
75 }
76 Jump::Multiple(ranges, main_i) => {
77 buf.selections().len() == ranges.len()
78 && buf.selections().iter().zip(ranges.iter()).enumerate().all(
79 |(i, ((sel, is_main), range))| {
80 sel.byte_range(buf.bytes()) == *range && ((i == *main_i) == is_main)
81 },
82 )
83 }
84 }
85 }
86
87 pub fn apply(&self, pa: &mut Pass, handle: &Handle) {
91 match self {
92 Jump::Single(selection) => {
93 handle.write(pa).selections_mut().remove_extras();
94 handle.edit_main(pa, |mut c| {
95 let start = c.text().point_at_byte(selection.start);
96 let end = c.text().point_at_byte(selection.end);
97 c.move_to(start..end)
98 });
99 }
100 Jump::Multiple(selections, main) => {
101 handle.write(pa).selections_mut().remove_extras();
102
103 handle.edit_main(pa, |mut c| {
104 let mut is_first = true;
105 for selection in selections {
106 if !is_first {
107 c.copy();
108 }
109
110 let start = c.text().point_at_byte(selection.start);
111 let end = c.text().point_at_byte(selection.end);
112 c.move_to(start..end);
113 is_first = false;
114 }
115 });
116 handle.write(pa).selections_mut().set_main(*main);
117 }
118 }
119 }
120
121 fn shift(&mut self, changes: &Changes) -> bool {
122 match self {
123 Jump::Single(selection) => {
124 if let Some(new) = changes.shift_selection(selection.clone()) {
125 *selection = new;
126 true
127 } else {
128 false
129 }
130 }
131 Jump::Multiple(selections, _) => {
132 changes.shift_selections(selections);
133 !selections.is_empty()
134 }
135 }
136 }
137}
138
139#[derive(Debug)]
140struct Parser(HashMap<JumpListId, (GapBuffer<Saved>, usize)>);
141
142impl Parser {
143 fn new() -> Self {
144 Self(HashMap::new())
145 }
146
147 fn update(&mut self, parts: BufferParts) {
148 if parts.changes.len() == 0 || self.0.values().all(|(list, _)| list.is_empty()) {
151 return;
152 }
153
154 for (list, cur) in self.0.values_mut() {
155 list.truncate(*cur);
156
157 if *cur == 0 {
158 continue;
159 }
160
161 let changes = if let Saved::Changes(changes) = &mut list[*cur - 1] {
162 changes
163 } else {
164 list.insert(*cur, Saved::Changes(Box::default()));
165 *cur += 1;
166 let Some(Saved::Changes(changes)) = list.get_mut(*cur - 1) else {
167 unreachable!();
168 };
169 changes
170 };
171
172 for change in parts.changes.clone() {
173 let change = (
174 change.start().byte() as i32,
175 change.taken_end().byte() as i32,
176 change.added_end().byte() as i32,
177 );
178 changes.add_change(change);
179 }
180 }
181 }
182}
183
184#[derive(Debug)]
185enum Saved {
186 Jump(Jump, JumpId),
187 Changes(Box<Changes>),
188}
189
190pub trait BufferJumps {
199 fn record_jump(
211 &self,
212 pa: &mut Pass,
213 jump_list_id: JumpListId,
214 allow_duplicates: bool,
215 ) -> Option<JumpId>;
216
217 fn move_jumps_by(&self, pa: &mut Pass, jump_list_id: JumpListId, by: i32) -> Option<Jump>;
228
229 fn go_to_jump(&self, pa: &mut Pass, jump_list_id: JumpListId, id: JumpId) -> Option<Jump>;
243
244 fn get_jump(&self, pa: &mut Pass, jump_list_id: JumpListId, id: JumpId) -> Option<Jump>;
255
256 fn record_or_get_current_jump(&self, pa: &mut Pass, jump_list_id: JumpListId) -> JumpId;
259}
260
261impl BufferJumps for Handle {
262 fn record_jump(
263 &self,
264 pa: &mut Pass,
265 jump_list_id: JumpListId,
266 allow_duplicates: bool,
267 ) -> Option<JumpId> {
268 let (parser, buffer) = PARSERS.write(pa, self).unwrap();
269 parser.update(TRACKER.parts(buffer).unwrap());
270
271 let selections = buffer.selections();
272 let (list, cur) = parser.0.entry(jump_list_id).or_default();
273
274 if !allow_duplicates {
275 for i in [Some(*cur), cur.checked_sub(1)].into_iter().flatten() {
276 let Some(Saved::Jump(jump, _)) = list.get(i) else {
277 continue;
278 };
279
280 match jump {
281 Jump::Single(sel) => {
282 if selections.len() == 1
283 && selections.main().byte_range(buffer.bytes()) == *sel
284 {
285 return None;
286 }
287 }
288 Jump::Multiple(sels, main) => {
289 if *main == selections.main_index()
290 && sels.len() == selections.len()
291 && sels
292 .iter()
293 .zip(selections.iter())
294 .all(|(lhs, (rhs, _))| *lhs == rhs.byte_range(buffer.bytes()))
295 {
296 return None;
297 }
298 }
299 }
300 }
301 }
302
303 list.truncate(*cur);
304 let jump_id = JumpId::new();
305
306 if selections.len() == 1 {
307 list.push_back(Saved::Jump(
308 Jump::Single(selections.main().byte_range(buffer.bytes())),
309 jump_id,
310 ));
311 *cur += 1;
312 } else if selections.len() > 1 {
313 list.push_back(Saved::Jump(
314 Jump::Multiple(
315 selections
316 .iter()
317 .map(|(sel, _)| sel.byte_range(buffer.bytes()))
318 .collect(),
319 selections.main_index(),
320 ),
321 jump_id,
322 ));
323 *cur += 1;
324 }
325
326 Some(jump_id)
327 }
328
329 fn move_jumps_by(&self, pa: &mut Pass, jump_list_id: JumpListId, mut by: i32) -> Option<Jump> {
330 let (parser, buffer) = PARSERS.write(pa, self).unwrap();
331 parser.update(TRACKER.parts(buffer).unwrap());
332
333 let mut changes = Changes::default();
334 let mut last_seen = None;
335
336 let (list, cur) = parser.0.entry(jump_list_id).or_default();
337
338 let jump = if by >= 0 {
339 loop {
340 match list.get_mut(*cur) {
341 Some(Saved::Jump(jump, _)) => {
342 if by == 0 {
343 break Some(jump.clone());
344 } else if *cur + 1 < list.len() {
345 last_seen = Some(*cur);
346 by -= 1;
347 *cur += 1;
348 } else {
349 break None;
350 }
351 }
352 Some(Saved::Changes(_)) => unreachable!(),
353 None => break None,
354 }
355 }
356 } else {
357 loop {
358 match cur.checked_sub(1).and_then(|j| list.get_mut(j)) {
359 Some(Saved::Jump(jump, _)) => {
360 *cur -= 1;
361 if jump.shift(&changes) {
362 by += 1;
363 if by == 0 {
364 let jump = jump.clone();
365 if !changes.list.is_empty() && *cur > 0 {
366 list.insert(*cur, Saved::Changes(Box::new(changes)));
367 *cur += 1;
368 }
369 break Some(jump);
370 } else {
371 last_seen = Some(*cur);
372 }
373 } else {
374 if let Some(last_seen) = last_seen.as_mut() {
375 *last_seen -= 1;
376 }
377 list.remove(*cur);
378 }
379 }
380 Some(Saved::Changes(_)) => {
381 if let Some(last_seen) = last_seen.as_mut() {
382 *last_seen -= 1;
383 }
384 *cur -= 1;
385 let Saved::Changes(rev) = list.remove(*cur) else {
386 unreachable!();
387 };
388 changes.merge(*rev);
389 }
390 None => break None,
391 }
392 }
393 };
394
395 jump.or_else(|| {
396 last_seen.map(|i| {
397 let Some(Saved::Jump(jump, _)) = list.get(i) else {
398 unreachable!();
399 };
400 jump.clone()
401 })
402 })
403 }
404
405 fn go_to_jump(&self, pa: &mut Pass, jump_list_id: JumpListId, id: JumpId) -> Option<Jump> {
406 get_jump(self, pa, jump_list_id, id, true)
407 }
408
409 fn get_jump(&self, pa: &mut Pass, jump_list_id: JumpListId, id: JumpId) -> Option<Jump> {
410 get_jump(self, pa, jump_list_id, id, false)
411 }
412
413 fn record_or_get_current_jump(&self, pa: &mut Pass, jump_list_id: JumpListId) -> JumpId {
414 if let Some(jump_id) = self.record_jump(pa, jump_list_id, false) {
415 jump_id
416 } else {
417 let (parser, buffer) = PARSERS.write(pa, self).unwrap();
418 parser.update(TRACKER.parts(buffer).unwrap());
419
420 let (list, cur) = parser.0.get_mut(&jump_list_id).unwrap();
421
422 list.range(..(*cur + 1).min(list.len()))
423 .iter()
424 .rev()
425 .find_map(|saved| {
426 if let Saved::Jump(_, jump_id) = saved {
427 Some(*jump_id)
428 } else {
429 None
430 }
431 })
432 .unwrap()
433 }
434 }
435}
436
437fn get_jump(
438 handle: &Handle,
439 pa: &mut Pass,
440 jump_list_id: JumpListId,
441 id: JumpId,
442 do_jump: bool,
443) -> Option<Jump> {
444 let (parser, buffer) = PARSERS.write(pa, handle).unwrap();
445 parser.update(TRACKER.parts(buffer).unwrap());
446
447 let (list, cur) = parser.0.entry(jump_list_id).or_default();
448
449 let mut changes = Changes::default();
450 let mut new_cur = *cur;
451
452 let jump = (|| {
453 loop {
457 match list.get_mut(new_cur) {
458 Some(Saved::Jump(jump, other)) => {
459 if jump.shift(&changes) {
460 if *other == id {
461 let jump = jump.clone();
462 if !changes.list.is_empty() && new_cur > 0 {
463 list.insert(*cur, Saved::Changes(Box::new(changes)));
464 *cur += 1;
465 }
466 break Some(jump);
467 } else if *other < id && *cur <= new_cur {
468 new_cur += 1;
469 } else if *other > id && *cur >= new_cur {
470 new_cur = new_cur.checked_sub(1)?;
471 } else {
472 if !changes.list.is_empty() && new_cur > 0 {
473 list.insert(*cur, Saved::Changes(Box::new(changes)));
474 *cur += 1;
475 }
476 return None;
477 }
478 } else {
479 list.remove(new_cur);
480 *cur = cur.checked_sub(1)?;
481 new_cur -= 1;
482 }
483 }
484 Some(Saved::Changes(_)) => {
485 let Saved::Changes(rev) = list.remove(new_cur) else {
486 unreachable!();
487 };
488 *cur -= 1;
489 new_cur -= 1;
490 changes.merge(*rev);
491 }
492 None if *cur >= new_cur => new_cur = new_cur.checked_sub(1)?,
493 None => break None,
494 }
495 }
496 })();
497
498 if jump.is_some() && do_jump {
499 *cur = new_cur
500 }
501
502 jump
503}
504
505#[derive(Default, Debug)]
506struct Changes {
507 list: GapBuffer<(i32, i32, i32)>,
508 from: usize,
509 by: i32,
510}
511
512impl Changes {
513 fn add_change(&mut self, (start, taken_end, added_end): (i32, i32, i32)) {
514 let m_range = duat_core::utils::merging_range_by_guess_and_lazy_shift(
515 (&self.list, self.list.len()),
516 (0, [start, taken_end]),
517 (self.from, self.by, 0, std::ops::Add::add),
518 (|(start, ..)| *start, |(.., added_end)| *added_end),
519 );
520
521 if self.by != 0 && self.from < m_range.end {
522 for (start, taken_end, added_end) in &mut self.list.range_mut(self.from..m_range.end) {
523 *start += self.by;
524 *taken_end += self.by;
525 *added_end += self.by;
526 }
527 } else if self.by != 0 && m_range.end < self.from {
528 for (start, taken_end, added_end) in &mut self.list.range_mut(self.from..m_range.end) {
529 *start -= self.by;
530 *taken_end -= self.by;
531 *added_end -= self.by;
532 }
533 }
534
535 let (start, taken_end, added_end) = if m_range.start < m_range.end {
536 let (first_start, ..) = self.list[m_range.start];
537 let (_, last_taken_end, last_added_end) = self.list[m_range.end - 1];
538 (
539 start.min(first_start),
540 taken_end.max(last_taken_end),
541 added_end.max(last_added_end),
542 )
543 } else {
544 (start, taken_end, added_end)
545 };
546
547 self.list.splice(
548 m_range.clone(),
549 (taken_end != added_end).then_some((start, taken_end, added_end)),
550 );
551
552 let new_from = m_range.start + (taken_end != added_end) as usize;
553 if new_from < self.list.len() {
554 self.from = new_from;
555 } else {
556 self.from = 0;
557 self.by = 0;
558 }
559 }
560
561 fn merge(&mut self, other: Self) {
562 for change in other.iter() {
563 self.add_change(change);
564 }
565 }
566
567 fn iter(&self) -> impl Iterator<Item = (i32, i32, i32)> {
568 self.list
569 .iter()
570 .enumerate()
571 .map(|(i, &(start, taken_end, added_end))| {
572 if self.by != 0 && i >= self.from {
573 (start + self.by, taken_end + self.by, added_end + self.by)
574 } else {
575 (start, taken_end, added_end)
576 }
577 })
578 }
579
580 fn shift_selection(&self, mut selection: Range<usize>) -> Option<Range<usize>> {
581 for change in self.iter() {
582 selection = shift_selection(selection.clone(), change)?;
583
584 if change.0 as usize >= selection.end {
585 break;
586 }
587 }
588
589 Some(selection)
590 }
591
592 fn shift_selections(&self, selections: &mut Vec<Range<usize>>) {
593 let mut total_shift = 0;
594 let mut changes = self.iter().peekable();
595
596 selections.retain_mut(|selection| {
597 selection.start = (selection.start as i32 + total_shift) as usize;
598 selection.end = (selection.end as i32 + total_shift) as usize;
599
600 while let Some(&change) = changes.peek() {
601 let Some(new) = shift_selection(selection.clone(), change) else {
602 return false;
603 };
604 *selection = new;
605
606 if change.1 as usize <= selection.start {
607 changes.next();
608 total_shift += change.2 - change.1;
609 } else if change.0 as usize >= selection.end {
610 break;
611 }
612 }
613
614 true
615 });
616 }
617}
618
619fn shift_selection(
620 mut selection: Range<usize>,
621 (start, taken_end, added_end): (i32, i32, i32),
622) -> Option<Range<usize>> {
623 let shift = added_end - taken_end;
624 let (start, taken_end) = (start as usize, taken_end as usize);
625
626 if taken_end <= selection.start {
627 selection.start = (selection.start as i32 + shift) as usize;
628 selection.end = (selection.end as i32 + shift) as usize;
629 } else if taken_end < selection.end {
630 selection.start = added_end as usize;
631 selection.end = (selection.end as i32 + shift) as usize;
632 } else if start <= selection.start {
633 return None;
634 } else if start < selection.end {
635 selection.end = start
636 }
637 Some(selection)
638}
639
640#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
642pub struct JumpId(usize);
643
644impl JumpId {
645 fn new() -> Self {
647 static COUNT: AtomicUsize = AtomicUsize::new(0);
648 Self(COUNT.fetch_add(1, Ordering::Relaxed))
649 }
650}
651
652#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
657pub struct JumpListId(usize);
658
659impl JumpListId {
660 pub fn new() -> Self {
669 static COUNT: AtomicUsize = AtomicUsize::new(0);
670 Self(COUNT.fetch_add(1, Ordering::Relaxed))
671 }
672}
673
674impl Default for JumpListId {
675 fn default() -> Self {
676 Self::new()
677 }
678}