1use std::sync::Mutex;
16
17use gap_buf::{GapBuffer, gap_buffer};
18
19pub use self::cursor::{Selection, VPoint};
20use crate::{
21 buffer::Change,
22 text::{Point, Strs, TextRange},
23 utils::{add_shifts, merging_range_by_guess_and_lazy_shift},
24};
25
26#[derive(bincode::Decode, bincode::Encode)]
42pub struct Selections {
43 buf: GapBuffer<Selection>,
44 main_i: usize,
45 shift: Mutex<Shift>,
46}
47
48impl Selections {
49 pub(crate) fn new(main: Selection) -> Self {
51 Self {
52 buf: gap_buffer![main],
53 main_i: 0,
54 shift: Mutex::default(),
55 }
56 }
57
58 pub(crate) const fn new_empty() -> Self {
60 Self {
61 buf: GapBuffer::new(),
62 main_i: 0,
63 shift: Mutex::new(Shift { from: 0, by: [0; 3] }),
64 }
65 }
66
67 pub fn set_main(&mut self, new: usize) {
71 self.main_i = new.min(self.buf.len().saturating_sub(1));
72 }
73
74 pub fn rotate_main(&mut self, amount: i32) {
76 if !self.buf.is_empty() {
77 self.main_i = (self.main_i as i32 + amount).rem_euclid(self.buf.len() as i32) as usize
78 }
79 }
80
81 pub fn clear(&mut self) {
83 self.buf = GapBuffer::new();
84 *self.shift.get_mut().unwrap() = Shift::default();
85 }
86
87 pub fn reset(&mut self) {
92 self.remove_extras();
93 self.buf[self.main_i] = Selection::default();
94 }
95
96 pub fn remove_extras(&mut self) {
98 if !self.is_empty() {
99 let cursor = self.buf.remove(self.main_i);
100 let shift = std::mem::take(self.shift.get_mut().unwrap());
101 if shift.from <= self.main_i && shift.by != [0; 3] {
102 cursor.shift_by(shift.by);
103 }
104 self.buf = gap_buffer![cursor];
105 }
106 self.main_i = 0;
107 }
108
109 pub(crate) fn correct_all(&mut self, strs: &Strs) {
112 for selection in &mut self.buf {
113 selection.correct(strs)
114 }
115 }
116
117 #[track_caller]
126 pub fn main(&self) -> &Selection {
127 match self.get(self.main_i) {
128 Some(main) => main,
129 None => panic!("No main selection"),
130 }
131 }
132
133 pub fn get_main(&self) -> Option<&Selection> {
138 self.get(self.main_i)
139 }
140
141 pub fn get(&self, n: usize) -> Option<&Selection> {
143 if n >= self.len() {
144 return None;
145 }
146 let mut shift = self.shift.lock().unwrap();
147 if n >= shift.from && shift.by != [0; 3] {
148 for cursor in self.buf.range(shift.from..n + 1).iter() {
149 cursor.shift_by(shift.by);
150 }
151 if n + 1 < self.buf.len() {
152 shift.from = n + 1;
153 } else {
154 *shift = Shift::default();
155 }
156 }
157
158 self.buf.get(n)
159 }
160
161 pub fn iter(&self) -> impl Iterator<Item = (&Selection, bool)> {
166 let mut shift = *self.shift.lock().unwrap();
167
168 self.buf.iter().enumerate().map(move |(i, selection)| {
169 if i >= shift.from && shift.by != [0; 3] {
170 selection.shift_by(shift.by);
171 if i + 1 < self.buf.len() {
172 self.shift.lock().unwrap().from = i + 1;
173 shift.from = i + 1;
174 } else {
175 *self.shift.lock().unwrap() = Shift::default();
176 }
177 }
178
179 (selection, i == self.main_i)
180 })
181 }
182
183 pub fn iter_within(
191 &self,
192 range: impl TextRange,
193 ) -> impl Iterator<Item = (usize, &Selection, bool)> {
194 let shift = *self.shift.lock().unwrap();
195 let range = range.to_range(u32::MAX as usize);
196
197 let m_range = merging_range_by_guess_and_lazy_shift(
198 (&self.buf, self.buf.len()),
199 (0, [range.start, range.end]),
200 (shift.from, shift.by[0], 0, |byte, shift| {
201 (byte as i32 + shift) as usize
202 }),
203 (
204 |sel| sel.start_point().byte(),
205 |sel| sel.end_point_excl().byte(),
206 ),
207 );
208
209 let (s0, s1) = self.buf.range(m_range.clone()).as_slices();
210 let iter = [s0, s1].into_iter().flatten().enumerate();
211 iter.map(move |(i, selection)| {
212 let i = i + m_range.start;
213 if i >= shift.from && shift.by != [0; 3] {
214 selection.shift_by(shift.by);
215 if i + 1 < self.buf.len() {
216 self.shift.lock().unwrap().from = i + 1;
217 } else {
218 *self.shift.lock().unwrap() = Shift::default();
219 }
220 }
221
222 (i, selection, i == self.main_i)
223 })
224 }
225
226 pub fn main_index(&self) -> usize {
228 self.main_i
229 }
230
231 pub fn len(&self) -> usize {
233 self.buf.len()
234 }
235
236 #[must_use]
238 pub fn is_empty(&self) -> bool {
239 self.len() == 0
240 }
241
242 pub(crate) fn insert(
246 &mut self,
247 guess_i: usize,
248 sel: Selection,
249 main: bool,
250 ) -> ([usize; 2], bool) {
251 let mut shift = self.shift.lock().unwrap();
252 let shift_from = shift.from.min(self.len());
253
254 let m_range = merging_range_by_guess_and_lazy_shift(
256 (&self.buf, self.buf.len()),
257 (guess_i, [sel.start_point(), sel.end_point_excl()]),
258 (shift_from, shift.by, [0; 3], Point::shift_by),
259 (Selection::start_point, Selection::end_point_excl),
260 );
261
262 if shift_from < m_range.end && shift.by != [0; 3] {
264 for cursor in self.buf.range(shift_from..m_range.end).into_iter() {
265 cursor.shift_by(shift.by);
266 }
267 }
268
269 let (caret, anchor, last_cursor_overhangs) = {
272 let mut c_range = m_range.clone();
273 let first = c_range.next().and_then(|i| self.buf.get(i));
274 let last = c_range.last().and_then(|i| self.buf.get(i)).or(first);
275 let start = first
276 .map(|first| first.lazy_v_start().min(sel.lazy_v_start()))
277 .unwrap_or(sel.lazy_v_start());
278 let (end, last_sel_overhangs) = if let Some(last) = last
279 && last.lazy_v_end() >= sel.lazy_v_end()
280 {
281 (last.lazy_v_end(), true)
282 } else {
283 (sel.lazy_v_end(), false)
284 };
285
286 if let Some(anchor) = sel.anchor() {
287 match sel.caret() < anchor {
288 true => (start, Some(end), last_sel_overhangs),
289 false => (end, Some(start), last_sel_overhangs),
290 }
291 } else {
292 (end, (start != end).then_some(start), last_sel_overhangs)
293 }
294 };
295
296 let selection = Selection::from_v(caret, anchor, sel.change_i);
297 self.buf.splice(m_range.clone(), [selection]);
298
299 if main {
300 self.main_i = m_range.start;
301 } else if self.main_i >= m_range.start {
302 self.main_i = (self.main_i + 1 - m_range.clone().count()).max(m_range.start)
303 }
304
305 let cursors_taken = m_range.clone().count();
308 let new_shift_from = shift_from.saturating_sub(cursors_taken).max(m_range.start) + 1;
309 if new_shift_from < self.buf.len() {
310 shift.from = new_shift_from;
311 } else {
312 *shift = Shift::default()
313 }
314
315 ([m_range.start, cursors_taken], last_cursor_overhangs)
316 }
317
318 pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
322 let mut shift = self.shift.lock().unwrap();
323 let shift_from = shift.from.min(self.len());
324
325 let c_range = merging_range_by_guess_and_lazy_shift(
327 (&self.buf, self.buf.len()),
328 (guess_i, [change.start(), change.taken_end()]),
329 (shift_from, shift.by, [0; 3], Point::shift_by),
330 (Selection::start_point, Selection::end_point_excl),
331 );
332
333 if c_range.end > shift_from && shift.by != [0; 3] {
338 for cursor in self.buf.range(shift_from..c_range.end).into_iter() {
339 cursor.shift_by(shift.by);
340 }
341 }
342 let range = c_range.start..c_range.end.max(shift_from);
343 for cursor in self.buf.range(range).into_iter() {
344 cursor.shift_by_change(change);
345 }
346
347 let (cursors_taken, cursors_added) = {
348 let mut cursors_taken = self.buf.splice(c_range.clone(), []);
349 if let Some(first) = cursors_taken.next() {
350 let last = cursors_taken.next_back().unwrap_or(first.clone());
351 let (start, end) = (first.start_point(), last.end_point_excl());
352 let merged = Selection::new(start, (start < end).then_some(end));
353 drop(cursors_taken);
354 self.buf.insert(c_range.start, merged);
355
356 (c_range.len(), 1)
357 } else {
358 (0, 0)
359 }
360 };
361
362 let from = shift_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
363 if from < self.buf.len() {
364 *shift = Shift {
365 from,
366 by: add_shifts(shift.by, change.shift()),
367 };
368 } else {
369 *shift = Shift::default()
370 }
371
372 cursors_taken - cursors_added
373 }
374
375 pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
377 if i >= self.buf.len() {
378 return None;
379 }
380 let shift = self.shift.get_mut().unwrap();
381
382 if i >= shift.from && shift.by != [0; 3] {
383 for cursor in self.buf.range(shift.from..i + 1).iter() {
384 cursor.shift_by(shift.by);
385 }
386 if i + 1 < self.buf.len() {
387 shift.from = i;
390 } else {
391 *shift = Shift::default()
392 }
393 } else if i < shift.from {
394 shift.from -= 1;
397 }
398
399 let was_main = self.main_i == i;
400 if self.main_i >= i {
401 self.main_i = self.main_i.saturating_sub(1);
402 }
403 Some((self.buf.remove(i), was_main))
404 }
405
406 pub(crate) fn populate(&mut self) {
408 if self.buf.is_empty() {
409 self.main_i = 0;
410 self.buf = gap_buffer![Selection::default()];
411 }
412 }
413}
414
415impl Clone for Selections {
416 fn clone(&self) -> Self {
417 Self {
418 buf: self.buf.clone(),
419 main_i: self.main_i,
420 shift: Mutex::new(*self.shift.lock().unwrap()),
421 }
422 }
423}
424
425mod cursor {
426 use std::{cmp::Ordering, ops::Range, sync::Mutex};
427
428 use bincode::{Decode, Encode};
429
430 use crate::{
431 buffer::Change,
432 opts::PrintOpts,
433 text::{Point, Strs, Text, TextIndex},
434 ui::Area,
435 };
436
437 #[derive(Default, Encode, Decode)]
440 pub struct Selection {
441 caret: Mutex<LazyVPoint>,
442 anchor: Mutex<Option<LazyVPoint>>,
443 pub(in crate::mode::cursor) change_i: Option<u32>,
444 }
445
446 impl Selection {
447 pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
449 Self {
450 caret: Mutex::new(LazyVPoint::Unknown(caret)),
451 anchor: Mutex::new(anchor.map(LazyVPoint::Unknown)),
452 change_i: None,
453 }
454 }
455
456 pub(super) fn from_v(
457 caret: LazyVPoint,
458 anchor: Option<LazyVPoint>,
459 change_i: Option<u32>,
460 ) -> Self {
461 Self {
462 caret: Mutex::new(caret),
463 anchor: Mutex::new(anchor),
464 change_i,
465 }
466 }
467
468 #[track_caller]
470 pub fn move_to(&mut self, idx: impl TextIndex, text: &Text) {
471 let byte = idx.to_byte_index();
472 if byte == self.caret().byte() {
473 return;
474 }
475 *self.caret.get_mut().unwrap() =
476 LazyVPoint::Unknown(text.point_at_byte(byte.min(text.len() - 1)));
477 }
478
479 pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
483 let by = by as isize;
484 if by == 0 {
485 return 0;
486 };
487
488 let caret = self.caret.get_mut().unwrap();
489
490 let target_char = caret.point().char().saturating_add_signed(by);
494
495 let point = if target_char == 0 {
496 Point::default()
497 } else if target_char >= text.last_point().char() {
498 text.last_point()
499 } else if by.abs() < 500 {
500 if by > 0 {
501 text[caret.point()..]
502 .chars()
503 .take(by as usize)
504 .fold(caret.point(), |point, char| point.fwd(char))
505 } else {
506 text[..caret.point()]
507 .chars()
508 .rev()
509 .take(by.unsigned_abs())
510 .fold(caret.point(), |point, char| point.rev(char))
511 }
512 } else {
513 text.point_at_char(target_char)
514 };
515
516 let moved = point.char() as i32 - caret.point().char() as i32;
517 *caret = LazyVPoint::Unknown(point);
518 moved
519 }
520
521 pub fn move_ver(&mut self, by: i32, text: &Text, area: &Area, opts: PrintOpts) -> bool {
525 if by == 0 {
526 return false;
527 }
528 let caret = self.caret.get_mut().unwrap();
529 let point = caret.point();
530
531 let desired_col = match *caret {
532 LazyVPoint::Unknown(_) => None,
533 LazyVPoint::Known(vpoint) => Some(vpoint.desired_visual_col()),
534 LazyVPoint::Desired { dvcol, .. } => Some(dvcol as usize),
535 };
536
537 let vpoint = area.move_ver(by, text, point, desired_col, opts);
538 *caret = LazyVPoint::Known(vpoint);
539
540 vpoint.point != point
541 }
542
543 pub fn move_ver_wrapped(
547 &mut self,
548 by: i32,
549 text: &Text,
550 area: &Area,
551 opts: PrintOpts,
552 ) -> bool {
553 if by == 0 {
554 return false;
555 };
556
557 let caret = self.caret.get_mut().unwrap();
558 let point = caret.point();
559
560 let desired_col = match *caret {
561 LazyVPoint::Unknown(_) => None,
562 LazyVPoint::Known(vpoint) => Some(vpoint.desired_wrapped_col()),
563 LazyVPoint::Desired { dwcol, .. } => Some(dwcol as usize),
564 };
565
566 let vpoint = area.move_ver_wrapped(by, text, point, desired_col, opts);
567 *caret = LazyVPoint::Known(vpoint);
568
569 vpoint.point != point
570 }
571
572 pub(crate) fn shift_by_change(&self, change: Change<&str>) {
573 let mut caret = self.caret.lock().unwrap();
574
575 let (shift, taken) = (change.shift(), change.taken_end());
576 if caret.point() >= change.start() {
577 let shifted_caret = caret.point().max(taken).shift_by(shift);
578 *caret = LazyVPoint::Unknown(shifted_caret);
579 }
580
581 let mut anchor = self.anchor.lock().unwrap();
582 if let Some(anchor) = &mut *anchor
583 && anchor.point() >= change.start()
584 {
585 let shifted_anchor = anchor.point().max(taken).shift_by(shift);
586 *anchor = LazyVPoint::Unknown(shifted_anchor);
587 }
588 }
589
590 pub(crate) fn shift_by(&self, shift: [i32; 3]) {
593 let mut caret = self.caret.lock().unwrap();
594 *caret = LazyVPoint::Unknown(caret.point().shift_by(shift));
595
596 let mut anchor = self.anchor.lock().unwrap();
597 if let Some(anchor) = &mut *anchor {
598 *anchor = LazyVPoint::Unknown(anchor.point().shift_by(shift));
599 }
600 }
601
602 pub(crate) fn correct(&mut self, strs: &Strs) {
605 let mut caret = self.caret.lock().unwrap();
606 *caret = LazyVPoint::Unknown(strs.point_at_byte(caret.point().byte()));
607
608 let mut anchor = self.anchor.lock().unwrap();
609 if let Some(anchor) = &mut *anchor {
610 *anchor = LazyVPoint::Unknown(strs.point_at_byte(anchor.point().byte()));
611 }
612 }
613
614 pub fn set_anchor(&mut self) {
622 *self.anchor.get_mut().unwrap() = Some(*self.caret.get_mut().unwrap())
623 }
624
625 pub fn unset_anchor(&mut self) -> Option<Point> {
630 self.anchor.get_mut().unwrap().take().map(|a| a.point())
631 }
632
633 pub fn swap_ends(&mut self) {
635 if let Some(anchor) = self.anchor.get_mut().unwrap() {
636 std::mem::swap(self.caret.get_mut().unwrap(), anchor);
637 }
638 }
639
640 pub fn caret(&self) -> Point {
642 self.caret.lock().unwrap().point()
643 }
644
645 pub fn anchor(&self) -> Option<Point> {
648 self.anchor.lock().unwrap().map(|lazy| lazy.point())
649 }
650
651 pub fn byte_range(&self, text: &Text) -> Range<usize> {
666 self.start_point().byte()..self.end_point(text).byte()
667 }
668
669 pub fn start_point(&self) -> Point {
671 if let Some(anchor) = *self.anchor.lock().unwrap() {
672 anchor.point().min(self.caret.lock().unwrap().point())
673 } else {
674 self.caret.lock().unwrap().point()
675 }
676 }
677
678 pub fn end_point(&self, text: &Text) -> Point {
680 self.end_point_excl()
681 .fwd(text.char_at(self.end_point_excl()).unwrap())
682 }
683
684 pub(super) fn end_point_excl(&self) -> Point {
685 if let Some(anchor) = *self.anchor.lock().unwrap() {
686 anchor.point().max(self.caret.lock().unwrap().point())
687 } else {
688 self.caret.lock().unwrap().point()
689 }
690 }
691
692 pub fn point_range(&self, text: &Text) -> Range<Point> {
697 self.start_point()..self.end_point(text)
698 }
699
700 pub fn point_range_excl(&self) -> Range<Point> {
704 self.start_point()..self.end_point_excl()
705 }
706
707 pub fn set_desired_cols(&mut self, v: usize, w: usize) {
712 let (v, w) = (v as u16, w as u16);
713 let caret = self.caret.get_mut().unwrap();
714 match caret {
715 LazyVPoint::Known(vp) => {
716 vp.dvcol = v;
717 vp.dwcol = w;
718 }
719 LazyVPoint::Unknown(point) => {
720 *caret = LazyVPoint::Desired { point: *point, dvcol: v, dwcol: w }
721 }
722 LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
723 }
724 }
725
726 pub fn v_caret(&self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
732 let mut caret = self.caret.lock().unwrap();
733 let vp = caret.calculate(text, area, opts);
734 *caret = LazyVPoint::Known(vp);
735 vp
736 }
737
738 pub fn v_anchor(&self, text: &Text, area: &Area, opts: PrintOpts) -> Option<VPoint> {
744 self.anchor.lock().unwrap().as_mut().map(|anchor| {
745 let vp = anchor.calculate(text, area, opts);
746 *anchor = LazyVPoint::Known(vp);
747 vp
748 })
749 }
750
751 pub fn v_range(&self, text: &Text, area: &Area, opts: PrintOpts) -> [VPoint; 2] {
758 let v_caret = self.v_caret(text, area, opts);
759 let v_anchor = self.v_anchor(text, area, opts).unwrap_or(v_caret);
760 [v_caret.min(v_anchor), v_caret.max(v_anchor)]
761 }
762
763 pub(super) fn lazy_v_start(&self) -> LazyVPoint {
765 match *self.anchor.lock().unwrap() {
766 Some(anchor) => self.caret.lock().unwrap().min(anchor),
767 None => *self.caret.lock().unwrap(),
768 }
769 }
770
771 pub(super) fn lazy_v_end(&self) -> LazyVPoint {
773 match *self.anchor.lock().unwrap() {
774 Some(anchor) => self.caret.lock().unwrap().max(anchor),
775 None => *self.caret.lock().unwrap(),
776 }
777 }
778 }
779
780 impl Clone for Selection {
781 fn clone(&self) -> Self {
782 Self {
783 caret: Mutex::new(*self.caret.lock().unwrap()),
784 anchor: Mutex::new(*self.anchor.lock().unwrap()),
785 change_i: self.change_i,
786 }
787 }
788 }
789
790 #[derive(Clone, Copy, Eq, Encode, Decode)]
793 pub(super) enum LazyVPoint {
794 Unknown(Point),
795 Known(VPoint),
796 Desired {
797 point: Point,
798 dvcol: u16,
799 dwcol: u16,
800 },
801 }
802
803 impl LazyVPoint {
804 fn point(&self) -> Point {
805 match *self {
806 LazyVPoint::Unknown(point) | LazyVPoint::Desired { point, .. } => point,
807 LazyVPoint::Known(vp) => vp.point,
808 }
809 }
810
811 fn calculate(self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
813 match self {
814 Self::Known(vp) => vp,
815 Self::Unknown(point) => area.move_ver(0, text, point, None, opts),
816 Self::Desired { point, dvcol, dwcol } => {
817 let mut vp = area.move_ver(0, text, point, Some(dvcol as usize), opts);
818 vp.dvcol = dvcol;
819 vp.dwcol = dwcol;
820 vp
821 }
822 }
823 }
824 }
825
826 impl Default for LazyVPoint {
827 fn default() -> Self {
828 Self::Desired {
829 point: Point::default(),
830 dvcol: 0,
831 dwcol: 0,
832 }
833 }
834 }
835
836 #[allow(clippy::non_canonical_partial_ord_impl)]
837 impl PartialOrd for LazyVPoint {
838 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
839 Some(self.point().cmp(&other.point()))
840 }
841 }
842
843 impl Ord for LazyVPoint {
844 fn cmp(&self, other: &Self) -> Ordering {
845 self.partial_cmp(other).unwrap()
846 }
847 }
848
849 impl PartialEq for LazyVPoint {
850 fn eq(&self, other: &Self) -> bool {
851 self.point() == other.point()
852 }
853 }
854
855 #[derive(Default, Clone, Copy, Debug, Eq, Encode, Decode)]
879 pub struct VPoint {
880 point: Point,
881 ccol: u16,
883 vcol: u16,
884 dvcol: u16,
885 wcol: u16,
886 dwcol: u16,
887 }
888
889 impl VPoint {
890 pub fn new(point: Point, ccol: u16, vcol: u16, dvcol: u16, wcol: u16, dwcol: u16) -> Self {
892 Self { point, ccol, vcol, dvcol, wcol, dwcol }
893 }
894
895 pub fn byte(&self) -> usize {
897 self.point.byte()
898 }
899
900 pub fn char(&self) -> usize {
902 self.point.char()
903 }
904
905 pub fn line(&self) -> usize {
907 self.point.line()
908 }
909
910 pub fn char_col(&self) -> usize {
912 self.ccol as usize
913 }
914
915 pub fn visual_col(&self) -> usize {
917 self.vcol as usize
918 }
919
920 pub fn desired_visual_col(&self) -> usize {
922 self.dvcol as usize
923 }
924
925 pub fn wrapped_col(&self) -> usize {
927 self.wcol as usize
928 }
929
930 pub fn desired_wrapped_col(&self) -> usize {
932 self.dwcol as usize
933 }
934 }
935
936 #[allow(clippy::non_canonical_partial_ord_impl)]
937 impl PartialOrd for VPoint {
938 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
939 Some(self.point.cmp(&other.point))
940 }
941 }
942
943 impl Ord for VPoint {
944 fn cmp(&self, other: &Self) -> Ordering {
945 self.partial_cmp(other).unwrap()
946 }
947 }
948
949 impl PartialEq for VPoint {
950 fn eq(&self, other: &Self) -> bool {
951 self.point == other.point
952 }
953 }
954
955 impl std::fmt::Debug for Selection {
956 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
957 f.debug_struct("Selection")
958 .field("caret", &*self.caret.lock().unwrap())
959 .field("anchor", &*self.anchor.lock().unwrap())
960 .field("change_i", &self.change_i)
961 .finish()
962 }
963 }
964
965 impl std::fmt::Debug for LazyVPoint {
966 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
967 match self {
968 Self::Known(vp) => write!(f, "Known({:?}, {})", vp.point, vp.dwcol),
969 Self::Unknown(p_or_b) => write!(f, "Unknown({p_or_b:?}"),
970 Self::Desired { point, dvcol, dwcol } => {
971 write!(f, "Desired({point:?}, {dvcol}, {dwcol})")
972 }
973 }
974 }
975 }
976}
977
978impl std::fmt::Debug for Selections {
979 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
980 struct DebugShiftState(Shift);
981 impl std::fmt::Debug for DebugShiftState {
982 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
983 write!(f, "{:?}", self.0)
984 }
985 }
986
987 f.debug_struct("Selections")
988 .field("buf", &self.buf)
989 .field("main_i", &self.main_i)
990 .field("shift_sate", &DebugShiftState(*self.shift.lock().unwrap()))
991 .finish()
992 }
993}
994
995#[derive(Default, Debug, Clone, Copy, bincode::Decode, bincode::Encode)]
996struct Shift {
997 from: usize,
998 by: [i32; 3],
999}