1use std::cell::Cell;
2
3use gapbuf::{GapBuffer, gap_buffer};
4
5pub use self::cursor::{Selection, VPoint};
6use crate::{
7 add_shifts, merging_range_by_guess_and_lazy_shift,
8 text::{Change, Point},
9};
10
11#[derive(Clone)]
35pub struct Selections {
36 buf: GapBuffer<Selection>,
37 main_i: usize,
38 shift_state: Cell<(usize, [i32; 3])>,
39}
40
41impl Selections {
42 pub fn new() -> Self {
44 Self {
45 buf: gap_buffer![Selection::default()],
46 main_i: 0,
47 shift_state: Cell::new((0, [0; 3])),
48 }
49 }
50
51 pub(crate) fn new_with_main(main: Selection) -> Self {
53 Self {
54 buf: gap_buffer![main],
55 main_i: 0,
56 shift_state: Cell::new((0, [0; 3])),
57 }
58 }
59
60 pub fn set_main(&mut self, new: usize) {
64 self.main_i = new.min(self.buf.len().saturating_sub(1));
65 }
66
67 pub fn rotate_main(&mut self, amount: i32) {
69 self.main_i = (self.main_i as i32 + amount).rem_euclid(self.buf.len() as i32) as usize
70 }
71
72 pub fn clear(&mut self) {
74 self.buf = GapBuffer::new();
75 self.shift_state.take();
76 }
77
78 pub fn reset(&mut self) {
83 self.remove_extras();
84 self.buf[self.main_i] = Selection::default();
85 }
86
87 pub fn remove_extras(&mut self) {
89 if !self.is_empty() {
90 let cursor = self.buf.remove(self.main_i);
91 let (sh_from, shift) = self.shift_state.take();
92 if sh_from <= self.main_i {
93 cursor.shift_by(shift);
94 }
95 self.buf = gap_buffer![cursor];
96 }
97 self.main_i = 0;
98 }
99
100 pub fn get_main(&self) -> Option<&Selection> {
104 self.get(self.main_i)
105 }
106
107 pub fn get(&self, n: usize) -> Option<&Selection> {
109 if n >= self.len() {
110 return None;
111 }
112 let (sh_from, shift) = self.shift_state.get();
113 if n >= sh_from && shift != [0; 3] {
114 for cursor in self.buf.range(sh_from..n + 1).iter() {
115 cursor.shift_by(shift);
116 }
117 if n + 1 < self.buf.len() {
118 self.shift_state.set((n + 1, shift));
119 } else {
120 self.shift_state.take();
121 }
122 }
123
124 self.buf.get(n)
125 }
126
127 pub fn iter(&self) -> impl Iterator<Item = (&Selection, bool)> {
129 let (sh_from, shift) = self.shift_state.take();
132 if shift != [0; 3] {
133 for cursor in self.buf.range(sh_from..).iter() {
134 cursor.shift_by(shift);
135 }
136 }
137 self.buf
138 .iter()
139 .enumerate()
140 .map(move |(i, cursor)| (cursor, i == self.main_i))
141 }
142
143 pub fn main_index(&self) -> usize {
145 self.main_i
146 }
147
148 pub fn len(&self) -> usize {
150 self.buf.len()
151 }
152
153 #[must_use]
155 pub fn is_empty(&self) -> bool {
156 self.len() == 0
157 }
158
159 pub(crate) fn insert(
163 &mut self,
164 guess_i: usize,
165 cursor: Selection,
166 main: bool,
167 ) -> ([usize; 2], bool) {
168 let (sh_from, shift) = self.shift_state.take();
169 let sh_from = sh_from.min(self.len());
170
171 let c_range = merging_range_by_guess_and_lazy_shift(
173 (&self.buf, self.buf.len()),
174 (guess_i, [cursor.start(), cursor.end_excl()]),
175 (sh_from, shift, [0; 3], Point::shift_by),
176 (Selection::start, Selection::end_excl),
177 );
178
179 if sh_from < c_range.end && shift != [0; 3] {
181 for cursor in self.buf.range(sh_from..c_range.end).into_iter() {
182 cursor.shift_by(shift);
183 }
184 }
185
186 let (caret, anchor, last_cursor_overhangs) = {
189 let mut c_range = c_range.clone();
190 let first = c_range.next().and_then(|i| self.get(i));
191 let last = c_range.last().and_then(|i| self.get(i)).or(first);
192 let start = first
193 .map(|first| first.lazy_v_start().min(cursor.lazy_v_start()))
194 .unwrap_or(cursor.lazy_v_start());
195 let (end, last_cursor_overhangs) = if let Some(last) = last
196 && last.lazy_v_end() >= cursor.lazy_v_end()
197 {
198 (last.lazy_v_end(), true)
199 } else {
200 (cursor.lazy_v_end(), false)
201 };
202
203 if let Some(anchor) = cursor.anchor() {
204 match cursor.caret() < anchor {
205 true => (start, Some(end), last_cursor_overhangs),
206 false => (end, Some(start), last_cursor_overhangs),
207 }
208 } else {
209 (end, (start != end).then_some(start), last_cursor_overhangs)
210 }
211 };
212
213 let cursor = Selection::from_v(caret, anchor, cursor.change_i);
214 self.buf.splice(c_range.clone(), [cursor]);
215
216 if main {
217 self.main_i = c_range.start;
218 } else if self.main_i >= c_range.start {
219 self.main_i = (self.main_i + 1 - c_range.clone().count()).max(c_range.start)
220 }
221
222 let cursors_taken = c_range.clone().count();
225 let new_sh_from = sh_from.saturating_sub(cursors_taken).max(c_range.start) + 1;
226 if new_sh_from < self.buf.len() {
227 self.shift_state.set((new_sh_from, shift));
228 }
229
230 ([c_range.start, cursors_taken], last_cursor_overhangs)
231 }
232
233 pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
235 let (sh_from, shift) = self.shift_state.take();
236 let sh_from = sh_from.min(self.len());
237
238 let c_range = merging_range_by_guess_and_lazy_shift(
240 (&self.buf, self.buf.len()),
241 (guess_i, [change.start(), change.taken_end()]),
242 (sh_from, shift, [0; 3], Point::shift_by),
243 (Selection::start, Selection::end_excl),
244 );
245
246 if c_range.end > sh_from && shift != [0; 3] {
251 for cursor in self.buf.range(sh_from..c_range.end).into_iter() {
252 cursor.shift_by(shift);
253 }
254 }
255 let range = c_range.start..c_range.end.max(sh_from);
256 for cursor in self.buf.range(range).into_iter() {
257 cursor.shift_by_change(change);
258 }
259
260 let (cursors_taken, cursors_added) = {
261 let mut cursors_taken = self.buf.splice(c_range.clone(), []);
262 if let Some(first) = cursors_taken.next() {
263 let last = cursors_taken.next_back().unwrap_or(first.clone());
264 let (start, end) = (first.start(), last.end_excl());
265 let merged = Selection::new(start, (start < end).then_some(end));
266 drop(cursors_taken);
267 self.buf.insert(c_range.start, merged);
268
269 (c_range.len(), 1)
270 } else {
271 (0, 0)
272 }
273 };
274
275 let new_sh_from = sh_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
276 if new_sh_from < self.buf.len() {
277 self.shift_state
278 .set((new_sh_from, add_shifts(shift, change.shift())));
279 }
280
281 cursors_taken - cursors_added
282 }
283
284 pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
286 if i >= self.buf.len() {
287 return None;
288 }
289 let (sh_from, shift) = self.shift_state.get();
290
291 if i >= sh_from && shift != [0; 3] {
292 for cursor in self.buf.range(sh_from..i + 1).iter() {
293 cursor.shift_by(shift);
294 }
295 if i + 1 < self.buf.len() {
296 self.shift_state.set((i, shift));
299 } else {
300 self.shift_state.take();
301 }
302 } else if i < sh_from {
303 self.shift_state.set((sh_from - 1, shift));
306 }
307
308 let was_main = self.main_i == i;
309 if self.main_i >= i {
310 self.main_i = self.main_i.saturating_sub(1);
311 }
312 Some((self.buf.remove(i), was_main))
313 }
314
315 pub(crate) fn populate(&mut self) {
317 if self.buf.is_empty() {
318 self.main_i = 0;
319 self.buf = gap_buffer![Selection::default()];
320 }
321 }
322}
323
324impl Default for Selections {
325 fn default() -> Self {
326 Self::new()
327 }
328}
329
330mod cursor {
331 use std::{cell::Cell, cmp::Ordering, ops::Range};
332
333 use bincode::{Decode, Encode};
334
335 use crate::{
336 cfg::PrintCfg,
337 text::{Change, Point, Text},
338 ui::{Caret, RawArea},
339 };
340
341 #[derive(Default, Clone, Encode, Decode)]
344 pub struct Selection {
345 caret: Cell<LazyVPoint>,
346 anchor: Cell<Option<LazyVPoint>>,
347 pub(in crate::mode::cursor) change_i: Option<u32>,
348 }
349
350 impl Selection {
351 pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
353 Self {
354 caret: Cell::new(LazyVPoint::Unknown(caret)),
355 anchor: Cell::new(anchor.map(LazyVPoint::Unknown)),
356 change_i: None,
357 }
358 }
359
360 pub(super) fn from_v(
361 caret: LazyVPoint,
362 anchor: Option<LazyVPoint>,
363 change_i: Option<u32>,
364 ) -> Self {
365 Self {
366 caret: Cell::new(caret),
367 anchor: Cell::new(anchor),
368 change_i,
369 }
370 }
371
372 pub fn move_to(&mut self, p: Point, text: &Text) {
374 if p == self.caret() {
375 return;
376 }
377 let p = text.point_at(p.byte().min(text.last_point().unwrap().byte()));
378 *self.caret.get_mut() = LazyVPoint::Unknown(p);
379 }
380
381 pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
385 let by = by as isize;
386 let (Some(last), false) = (text.last_point(), by == 0) else {
387 return 0;
388 };
389 let target = self.caret.get().point().char().saturating_add_signed(by);
390
391 let p = if target == 0 {
392 Point::default()
393 } else if target >= last.char() {
394 last
395 } else if by.abs() < 500 {
396 if by > 0 {
397 let (point, _) = text
398 .chars_fwd(self.caret())
399 .take(by as usize + 1)
400 .last()
401 .unwrap();
402 point
403 } else {
404 let (point, _) = text
405 .chars_rev(self.caret())
406 .take(by.unsigned_abs())
407 .last()
408 .unwrap();
409 point
410 }
411 } else {
412 text.point_at_char(target)
413 };
414
415 let moved = p.char() as i32 - self.caret.get().point().char() as i32;
416 *self.caret.get_mut() = LazyVPoint::Unknown(p);
417 moved
418 }
419
420 pub fn move_ver(
424 &mut self,
425 by: i32,
426 text: &Text,
427 area: &impl RawArea,
428 cfg: PrintCfg,
429 ) -> i32 {
430 let by = by as isize;
431 let (Some(last), false) = (text.last_point(), by == 0) else {
432 return 0;
433 };
434
435 let (vp, moved) = {
436 let vp = self.caret.get().calculate(text, area, cfg);
437 let line_start = {
438 let target = self.caret.get().point().line().saturating_add_signed(by);
439 text.point_at_line(target.min(last.line()))
440 };
441
442 let mut wraps = 0;
443 let mut vcol = 0;
444
445 let (wcol, p) = area
446 .print_iter(text.iter_fwd(line_start), cfg.new_line_as('\n'))
447 .find_map(|(Caret { len, x, wrap }, item)| {
448 wraps += wrap as usize;
449 if let Some((p, char)) = item.as_real_char()
450 && (vcol + len as u16 > vp.dvcol || char == '\n')
451 {
452 return Some((x as u16, p));
453 }
454
455 vcol += len as u16;
456 None
457 })
458 .unwrap_or((0, last));
459
460 let moved = p.line() as i32 - vp.p.line() as i32;
461 let vp = vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol);
462 (vp, moved)
463 };
464
465 *self.caret.get_mut() = LazyVPoint::Known(vp);
466 moved
467 }
468
469 pub fn move_ver_wrapped(
473 &mut self,
474 by: i32,
475 text: &Text,
476 area: &impl RawArea,
477 cfg: PrintCfg,
478 ) -> i32 {
479 if text.last_point().is_none() || by == 0 {
480 return 0;
481 };
482 let vp = self.caret.get().calculate(text, area, cfg);
483
484 let mut wraps = 0;
485
486 *self.caret.get_mut() = LazyVPoint::Known(if by > 0 {
487 let line_start = text.point_at_line(vp.p.line());
488 let mut vcol = vp.vcol;
489 let mut last = (vp.vcol, vp.wcol, vp.p);
490 let mut last_valid = (vp.vcol, vp.wcol, vp.p);
491
492 let (vcol, wcol, p) = area
493 .print_iter(text.iter_fwd(line_start), cfg.new_line_as('\n'))
494 .skip_while(|(_, item)| item.byte() <= self.byte())
495 .find_map(|(Caret { x, len, wrap }, item)| {
496 wraps += wrap as i32;
497 if let Some((p, char)) = item.as_real_char() {
498 if (x..x + len).contains(&(vp.dwcol as u32)) || char == '\n' {
499 last_valid = (vcol, x as u16, p);
500 if wraps == by {
501 return Some((vcol, x as u16, p));
502 }
503 } else if wraps > by {
504 return Some(last);
505 }
506 last = (vcol, x as u16, p);
507 }
508 vcol += len as u16;
509 None
510 })
511 .unwrap_or(last_valid);
512 vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol)
513 } else {
514 let end_points = text.points_after(vp.p).unwrap();
515 let mut just_wrapped = false;
516 let mut last_valid = (vp.wcol, vp.p);
517
518 let mut iter =
519 area.rev_print_iter(text.iter_rev(end_points), cfg.new_line_as('\n'));
520 let wcol_and_p = iter.find_map(|(Caret { x, len, wrap }, item)| {
521 if let Some((p, _)) = item.as_real_char() {
522 if (x..x + len).contains(&(vp.dwcol as u32))
523 || (just_wrapped && x + len < vp.dwcol as u32)
524 {
525 last_valid = (x as u16, p);
526 if wraps == by {
527 return Some((x as u16, p));
528 }
529 }
530 just_wrapped = false;
531 }
532 wraps -= wrap as i32;
533 just_wrapped |= wrap;
534 None
535 });
536
537 if let Some((wcol, p)) = wcol_and_p {
538 let (ccol, vcol) = iter
539 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
540 .fold((0, 0), |(ccol, vcol), (caret, item)| {
541 (ccol + item.is_real() as u16, vcol + caret.len as u16)
542 });
543 vp.known(p, ccol, vcol, wcol)
544 } else {
545 let (wcol, p) = last_valid;
546 let (ccol, vcol) = area
547 .rev_print_iter(text.iter_rev(p), cfg.new_line_as('\n'))
548 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
549 .fold((0, 0), |(ccol, vcol), (caret, item)| {
550 (ccol + item.is_real() as u16, vcol + caret.len as u16)
551 });
552 vp.known(p, ccol, vcol, wcol)
553 }
554 });
555
556 wraps
557 }
558
559 pub(crate) fn shift_by_change(&self, change: Change<&str>) {
560 let (shift, taken) = (change.shift(), change.taken_end());
561 if self.caret() >= change.start() {
562 let shifted_caret = self.caret().max(taken).shift_by(shift);
563 self.caret.set(LazyVPoint::Unknown(shifted_caret));
564 }
565 if let Some(anchor) = self.anchor.get()
566 && anchor.point() >= change.start()
567 {
568 let shifted_anchor = anchor.point().max(taken).shift_by(shift);
569 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
570 }
571 }
572
573 pub(crate) fn shift_by(&self, shift: [i32; 3]) {
576 let shifted_caret = self.caret().shift_by(shift);
577 self.caret.set(LazyVPoint::Unknown(shifted_caret));
578 if let Some(anchor) = self.anchor.get() {
579 let shifted_anchor = anchor.point().shift_by(shift);
580 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
581 }
582 }
583
584 pub fn set_anchor(&mut self) {
590 *self.anchor.get_mut() = Some(self.caret.get())
591 }
592
593 pub fn unset_anchor(&mut self) -> Option<Point> {
598 self.anchor.take().map(|a| a.point())
599 }
600
601 pub fn swap_ends(&mut self) {
603 if let Some(anchor) = self.anchor.get_mut() {
604 std::mem::swap(self.caret.get_mut(), anchor);
605 }
606 }
607
608 pub fn caret(&self) -> Point {
610 self.caret.get().point()
611 }
612
613 pub fn anchor(&self) -> Option<Point> {
615 self.anchor.get().map(|a| a.point())
616 }
617
618 pub fn byte(&self) -> usize {
621 self.caret.get().point().byte()
622 }
623
624 pub fn char(&self) -> usize {
627 self.caret.get().point().char()
628 }
629
630 pub fn line(&self) -> usize {
632 self.caret.get().point().line()
633 }
634
635 pub fn range(&self, text: &Text) -> Range<usize> {
648 let [start, end] = self.point_range(text);
649 start.byte()..end.byte()
650 }
651
652 pub fn start(&self) -> Point {
654 if let Some(anchor) = self.anchor.get() {
655 anchor.point().min(self.caret.get().point())
656 } else {
657 self.caret.get().point()
658 }
659 }
660
661 pub fn end(&self, text: &Text) -> Point {
663 let raw = self.end_excl();
664 raw.fwd(text.char_at(raw).unwrap())
665 }
666
667 pub(crate) fn end_excl(&self) -> Point {
668 if let Some(anchor) = self.anchor.get() {
669 anchor.point().max(self.caret.get().point())
670 } else {
671 self.caret.get().point()
672 }
673 }
674
675 pub(crate) fn tag_points(&self, text: &Text) -> (Point, Option<[Point; 2]>) {
676 let caret = self.caret();
677 if let Some(anchor) = self.anchor() {
678 match anchor.cmp(&caret) {
679 Ordering::Less => (caret, Some([anchor, caret])),
680 Ordering::Equal => (caret, None),
681 Ordering::Greater => {
682 let end = anchor.fwd(text.char_at(anchor).unwrap());
683 (caret, Some([caret, end]))
684 }
685 }
686 } else {
687 (caret, None)
688 }
689 }
690
691 pub fn point_range(&self, text: &Text) -> [Point; 2] {
698 [self.start(), self.end(text)]
699 }
700
701 pub fn set_desired_cols(&mut self, v: usize, w: usize) {
704 let (v, w) = (v as u16, w as u16);
705 match self.caret.get_mut() {
706 LazyVPoint::Known(vp) => {
707 vp.dvcol = v;
708 vp.dwcol = w;
709 }
710 LazyVPoint::Unknown(p) => {
711 *self.caret.get_mut() = LazyVPoint::Desired { p: *p, dvcol: v, dwcol: w }
712 }
713 LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
714 }
715 }
716
717 pub fn v_caret(&self, text: &Text, area: &impl RawArea, cfg: PrintCfg) -> VPoint {
723 let vp = self.caret.get().calculate(text, area, cfg);
724 self.caret.set(LazyVPoint::Known(vp));
725 vp
726 }
727
728 pub fn v_anchor(&self, text: &Text, area: &impl RawArea, cfg: PrintCfg) -> Option<VPoint> {
734 self.anchor.get().map(|anchor| {
735 let vp = anchor.calculate(text, area, cfg);
736 self.anchor.set(Some(LazyVPoint::Known(vp)));
737 vp
738 })
739 }
740
741 pub fn v_range(&self, text: &Text, area: &impl RawArea, cfg: PrintCfg) -> [VPoint; 2] {
748 let v_caret = self.v_caret(text, area, cfg);
749 let v_anchor = self.v_anchor(text, area, cfg).unwrap_or(v_caret);
750 [v_caret.min(v_anchor), v_caret.max(v_anchor)]
751 }
752
753 pub(super) fn lazy_v_start(&self) -> LazyVPoint {
755 match self.anchor.get() {
756 Some(anchor) => self.caret.get().min(anchor),
757 None => self.caret.get(),
758 }
759 }
760
761 pub(super) fn lazy_v_end(&self) -> LazyVPoint {
763 match self.anchor.get() {
764 Some(anchor) => self.caret.get().max(anchor),
765 None => self.caret.get(),
766 }
767 }
768 }
769
770 #[derive(Clone, Copy, Eq, Encode, Decode)]
773 pub(super) enum LazyVPoint {
774 Known(VPoint),
775 Unknown(Point),
776 Desired { p: Point, dvcol: u16, dwcol: u16 },
777 }
778
779 impl LazyVPoint {
780 fn point(self) -> Point {
782 match self {
783 LazyVPoint::Known(vp) => vp.p,
784 LazyVPoint::Unknown(p) => p,
785 LazyVPoint::Desired { p, .. } => p,
786 }
787 }
788
789 fn calculate(self, text: &Text, area: &impl RawArea, cfg: PrintCfg) -> VPoint {
791 match self {
792 Self::Known(vp) => vp,
793 Self::Unknown(p) => VPoint::new(p, text, area, cfg),
794 Self::Desired { p, dvcol, dwcol } => {
795 let mut vp = VPoint::new(p, text, area, cfg);
796 vp.dvcol = dvcol;
797 vp.dwcol = dwcol;
798 vp
799 }
800 }
801 }
802 }
803
804 impl Default for LazyVPoint {
805 fn default() -> Self {
806 Self::Desired { p: Point::default(), dvcol: 0, dwcol: 0 }
807 }
808 }
809
810 #[allow(clippy::non_canonical_partial_ord_impl)]
811 impl PartialOrd for LazyVPoint {
812 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
813 Some(self.point().cmp(&other.point()))
814 }
815 }
816
817 impl Ord for LazyVPoint {
818 fn cmp(&self, other: &Self) -> Ordering {
819 self.partial_cmp(other).unwrap()
820 }
821 }
822
823 impl PartialEq for LazyVPoint {
824 fn eq(&self, other: &Self) -> bool {
825 self.point() == other.point()
826 }
827 }
828
829 #[derive(Clone, Copy, Debug, Eq, Encode, Decode)]
853 pub struct VPoint {
854 p: Point,
855 ccol: u16,
857 vcol: u16,
858 dvcol: u16,
859 wcol: u16,
860 dwcol: u16,
861 }
862
863 impl VPoint {
864 fn new(p: Point, text: &Text, area: &impl RawArea, cfg: PrintCfg) -> Self {
866 let [start, _] = text.points_of_line(p.line());
867
868 let mut vcol = 0;
869
870 let wcol = area
871 .print_iter(text.iter_fwd(text.visual_line_start(start)), cfg)
872 .find_map(|(caret, item)| {
873 if let Some((lhs, _)) = item.as_real_char()
874 && lhs == p
875 {
876 return Some(caret.x as u16);
877 }
878 vcol += caret.len as u16;
879 None
880 })
881 .unwrap_or(0);
882
883 Self {
884 p,
885 ccol: (p.char() - start.char()) as u16,
886 vcol,
887 dvcol: vcol,
888 wcol,
889 dwcol: wcol,
890 }
891 }
892
893 fn known(self, p: Point, ccol: u16, vcol: u16, wcol: u16) -> Self {
895 Self { p, ccol, vcol, wcol, ..self }
896 }
897
898 pub fn byte(&self) -> usize {
900 self.p.byte()
901 }
902
903 pub fn char(&self) -> usize {
905 self.p.char()
906 }
907
908 pub fn line(&self) -> usize {
910 self.p.line()
911 }
912
913 pub fn char_col(&self) -> usize {
915 self.ccol as usize
916 }
917
918 pub fn visual_col(&self) -> usize {
920 self.vcol as usize
921 }
922
923 pub fn desired_visual_col(&self) -> usize {
925 self.dvcol as usize
926 }
927
928 pub fn wrapped_col(&self) -> usize {
930 self.wcol as usize
931 }
932
933 pub fn desired_wrapped_col(&self) -> usize {
935 self.dwcol as usize
936 }
937 }
938
939 #[allow(clippy::non_canonical_partial_ord_impl)]
940 impl PartialOrd for VPoint {
941 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
942 Some(self.p.cmp(&other.p))
943 }
944 }
945
946 impl Ord for VPoint {
947 fn cmp(&self, other: &Self) -> Ordering {
948 self.partial_cmp(other).unwrap()
949 }
950 }
951
952 impl PartialEq for VPoint {
953 fn eq(&self, other: &Self) -> bool {
954 self.p == other.p
955 }
956 }
957
958 impl std::fmt::Debug for Selection {
959 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
960 f.debug_struct("Selection")
961 .field("caret", &self.caret.get())
962 .field("anchor", &self.anchor.get())
963 .field("change_i", &self.change_i)
964 .finish()
965 }
966 }
967
968 impl std::fmt::Debug for LazyVPoint {
969 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
970 match self {
971 Self::Known(vp) => write!(f, "Known({:?})", vp.p),
972 Self::Unknown(p) => write!(f, "Unknown({p:?}"),
973 Self::Desired { p, .. } => write!(f, "Desired({p:?})"),
974 }
975 }
976 }
977}
978
979impl std::fmt::Debug for Selections {
980 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
981 struct DebugShiftState((usize, [i32; 3]));
982 impl std::fmt::Debug for DebugShiftState {
983 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
984 write!(f, "{:?}", self.0)
985 }
986 }
987
988 f.debug_struct("Selections")
989 .field("buf", &self.buf)
990 .field("main_i", &self.main_i)
991 .field("shift_sate", &DebugShiftState(self.shift_state.get()))
992 .finish()
993 }
994}