1use std::cell::Cell;
16
17use gapbuf::{GapBuffer, gap_buffer};
18
19pub use self::cursor::{Selection, VPoint};
20use crate::{
21 text::{Bytes, Change, Point, TextRange},
22 utils::{add_shifts, merging_range_by_guess_and_lazy_shift},
23};
24
25#[derive(Clone)]
49pub struct Selections {
50 buf: GapBuffer<Selection>,
51 main_i: usize,
52 shift_state: Cell<(usize, [i32; 3])>,
53}
54
55impl Selections {
56 pub(crate) fn new(main: Selection) -> Self {
58 Self {
59 buf: gap_buffer![main],
60 main_i: 0,
61 shift_state: Cell::new((0, [0; 3])),
62 }
63 }
64
65 pub(crate) fn new_empty() -> Self {
67 Self {
68 buf: GapBuffer::new(),
69 main_i: 0,
70 shift_state: Cell::default(),
71 }
72 }
73
74 pub fn set_main(&mut self, new: usize) {
78 self.main_i = new.min(self.buf.len().saturating_sub(1));
79 }
80
81 pub fn rotate_main(&mut self, amount: i32) {
83 self.main_i = (self.main_i as i32 + amount).rem_euclid(self.buf.len() as i32) as usize
84 }
85
86 pub fn clear(&mut self) {
88 self.buf = GapBuffer::new();
89 self.shift_state.take();
90 }
91
92 pub fn reset(&mut self) {
97 self.remove_extras();
98 self.buf[self.main_i] = Selection::default();
99 }
100
101 pub fn remove_extras(&mut self) {
103 if !self.is_empty() {
104 let cursor = self.buf.remove(self.main_i);
105 let (shift_from, shift) = self.shift_state.take();
106 if shift_from <= self.main_i && shift != [0; 3] {
107 cursor.shift_by(shift);
108 }
109 self.buf = gap_buffer![cursor];
110 }
111 self.main_i = 0;
112 }
113
114 pub(crate) fn correct_all(&mut self, bytes: &Bytes) {
117 for selection in &mut self.buf {
118 selection.correct(bytes)
119 }
120 }
121
122 pub fn get_main(&self) -> Option<&Selection> {
126 self.get(self.main_i)
127 }
128
129 pub fn get(&self, n: usize) -> Option<&Selection> {
131 if n >= self.len() {
132 return None;
133 }
134 let (shift_from, shift) = self.shift_state.get();
135 if n >= shift_from && shift != [0; 3] {
136 for cursor in self.buf.range(shift_from..n + 1).iter() {
137 cursor.shift_by(shift);
138 }
139 if n + 1 < self.buf.len() {
140 self.shift_state.set((n + 1, shift));
141 } else {
142 self.shift_state.take();
143 }
144 }
145
146 self.buf.get(n)
147 }
148
149 pub fn iter(&self) -> impl Iterator<Item = (&Selection, bool)> {
154 let (mut shift_from, shift) = self.shift_state.get();
155
156 self.buf.iter().enumerate().map(move |(i, selection)| {
157 if i >= shift_from && shift != [0; 3] {
158 selection.shift_by(shift);
159 if i + 1 < self.buf.len() {
160 self.shift_state.set((i + 1, shift));
161 shift_from = i + 1;
162 } else {
163 self.shift_state.set((0, [0; 3]));
164 }
165 }
166
167 (selection, i == self.main_i)
168 })
169 }
170
171 pub fn iter_within(
179 &self,
180 range: impl TextRange,
181 ) -> impl Iterator<Item = (usize, &Selection, bool)> {
182 let (shift_from, shift) = self.shift_state.get();
183
184 let range = if let Some(last) = self.buf.len().checked_sub(1) {
185 range.to_range(self.buf[last].end_excl().byte())
186 } else {
187 0..0
189 };
190
191 let m_range = merging_range_by_guess_and_lazy_shift(
192 (&self.buf, self.buf.len()),
193 (0, [range.start, range.end]),
194 (shift_from, shift[0], 0, |byte, shift| {
195 (byte as i32 + shift) as usize
196 }),
197 (
198 |sel: &Selection| sel.start().byte(),
199 |sel: &Selection| sel.end_excl().byte(),
200 ),
201 );
202
203 let (s0, s1) = self.buf.range(m_range.clone()).as_slices();
204 let iter = [s0, s1].into_iter().flatten().enumerate();
205 iter.map(move |(i, selection)| {
206 let i = i + m_range.start;
207 if i >= shift_from && shift != [0; 3] {
208 selection.shift_by(shift);
209 if i + 1 < self.buf.len() {
210 self.shift_state.set((i + 1, shift));
211 } else {
212 self.shift_state.set((0, [0; 3]));
213 }
214 }
215
216 (i, selection, i == self.main_i)
217 })
218 }
219
220 pub fn main_index(&self) -> usize {
222 self.main_i
223 }
224
225 pub fn len(&self) -> usize {
227 self.buf.len()
228 }
229
230 #[must_use]
232 pub fn is_empty(&self) -> bool {
233 self.len() == 0
234 }
235
236 pub(crate) fn insert(
240 &mut self,
241 guess_i: usize,
242 sel: Selection,
243 main: bool,
244 ) -> ([usize; 2], bool) {
245 let (shift_from, shift) = self.shift_state.take();
246 let shift_from = shift_from.min(self.len());
247
248 let m_range = merging_range_by_guess_and_lazy_shift(
250 (&self.buf, self.buf.len()),
251 (guess_i, [sel.start(), sel.end_excl()]),
252 (shift_from, shift, [0; 3], Point::shift_by),
253 (Selection::start, Selection::end_excl),
254 );
255
256 if shift_from < m_range.end && shift != [0; 3] {
258 for cursor in self.buf.range(shift_from..m_range.end).into_iter() {
259 cursor.shift_by(shift);
260 }
261 }
262
263 let (caret, anchor, last_cursor_overhangs) = {
266 let mut c_range = m_range.clone();
267 let first = c_range.next().and_then(|i| self.get(i));
268 let last = c_range.last().and_then(|i| self.get(i)).or(first);
269 let start = first
270 .map(|first| first.lazy_v_start().min(sel.lazy_v_start()))
271 .unwrap_or(sel.lazy_v_start());
272 let (end, last_sel_overhangs) = if let Some(last) = last
273 && last.lazy_v_end() >= sel.lazy_v_end()
274 {
275 (last.lazy_v_end(), true)
276 } else {
277 (sel.lazy_v_end(), false)
278 };
279
280 if let Some(anchor) = sel.anchor() {
281 match sel.caret() < anchor {
282 true => (start, Some(end), last_sel_overhangs),
283 false => (end, Some(start), last_sel_overhangs),
284 }
285 } else {
286 (end, (start != end).then_some(start), last_sel_overhangs)
287 }
288 };
289
290 let selection = Selection::from_v(caret, anchor, sel.change_i);
291 self.buf.splice(m_range.clone(), [selection]);
292
293 if main {
294 self.main_i = m_range.start;
295 } else if self.main_i >= m_range.start {
296 self.main_i = (self.main_i + 1 - m_range.clone().count()).max(m_range.start)
297 }
298
299 let cursors_taken = m_range.clone().count();
302 let new_shift_from = shift_from.saturating_sub(cursors_taken).max(m_range.start) + 1;
303 if new_shift_from < self.buf.len() {
304 self.shift_state.set((new_shift_from, shift));
305 }
306
307 ([m_range.start, cursors_taken], last_cursor_overhangs)
308 }
309
310 pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
314 let (shift_from, shift) = self.shift_state.take();
315 let shift_from = shift_from.min(self.len());
316
317 let c_range = merging_range_by_guess_and_lazy_shift(
319 (&self.buf, self.buf.len()),
320 (guess_i, [change.start(), change.taken_end()]),
321 (shift_from, shift, [0; 3], Point::shift_by),
322 (Selection::start, Selection::end_excl),
323 );
324
325 if c_range.end > shift_from && shift != [0; 3] {
330 for cursor in self.buf.range(shift_from..c_range.end).into_iter() {
331 cursor.shift_by(shift);
332 }
333 }
334 let range = c_range.start..c_range.end.max(shift_from);
335 for cursor in self.buf.range(range).into_iter() {
336 cursor.shift_by_change(change);
337 }
338
339 let (cursors_taken, cursors_added) = {
340 let mut cursors_taken = self.buf.splice(c_range.clone(), []);
341 if let Some(first) = cursors_taken.next() {
342 let last = cursors_taken.next_back().unwrap_or(first.clone());
343 let (start, end) = (first.start(), last.end_excl());
344 let merged = Selection::new(start, (start < end).then_some(end));
345 drop(cursors_taken);
346 self.buf.insert(c_range.start, merged);
347
348 (c_range.len(), 1)
349 } else {
350 (0, 0)
351 }
352 };
353
354 let new_shift_from =
355 shift_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
356 if new_shift_from < self.buf.len() {
357 self.shift_state
358 .set((new_shift_from, add_shifts(shift, change.shift())));
359 }
360
361 cursors_taken - cursors_added
362 }
363
364 pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
366 if i >= self.buf.len() {
367 return None;
368 }
369 let (shift_from, shift) = self.shift_state.get();
370
371 if i >= shift_from && shift != [0; 3] {
372 for cursor in self.buf.range(shift_from..i + 1).iter() {
373 cursor.shift_by(shift);
374 }
375 if i + 1 < self.buf.len() {
376 self.shift_state.set((i, shift));
379 } else {
380 self.shift_state.take();
381 }
382 } else if i < shift_from {
383 self.shift_state.set((shift_from - 1, shift));
386 }
387
388 let was_main = self.main_i == i;
389 if self.main_i >= i {
390 self.main_i = self.main_i.saturating_sub(1);
391 }
392 Some((self.buf.remove(i), was_main))
393 }
394
395 pub(crate) fn populate(&mut self) {
397 if self.buf.is_empty() {
398 self.main_i = 0;
399 self.buf = gap_buffer![Selection::default()];
400 }
401 }
402}
403
404mod cursor {
405 use std::{cell::Cell, cmp::Ordering, ops::Range};
406
407 use bincode::{Decode, Encode};
408
409 use crate::{
410 opts::PrintOpts,
411 text::{Bytes, Change, Point, Text},
412 ui::{Area, Caret},
413 };
414
415 #[derive(Default, Clone, Encode, Decode)]
418 pub struct Selection {
419 caret: Cell<LazyVPoint>,
420 anchor: Cell<Option<LazyVPoint>>,
421 pub(in crate::mode::cursor) change_i: Option<u32>,
422 }
423
424 impl Selection {
425 pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
427 Self {
428 caret: Cell::new(LazyVPoint::Unknown(caret)),
429 anchor: Cell::new(anchor.map(LazyVPoint::Unknown)),
430 change_i: None,
431 }
432 }
433
434 pub(super) fn from_v(
435 caret: LazyVPoint,
436 anchor: Option<LazyVPoint>,
437 change_i: Option<u32>,
438 ) -> Self {
439 Self {
440 caret: Cell::new(caret),
441 anchor: Cell::new(anchor),
442 change_i,
443 }
444 }
445
446 #[track_caller]
448 pub fn move_to(&mut self, p: Point, text: &Text) {
449 if p == self.caret() {
450 return;
451 }
452 let p = text.point_at_byte(p.byte().min(text.last_point().byte()));
453 *self.caret.get_mut() = LazyVPoint::Unknown(p);
454 }
455
456 pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
460 let by = by as isize;
461 if by == 0 {
462 return 0;
463 };
464 let target = self.caret.get().point().char().saturating_add_signed(by);
465
466 let p = if target == 0 {
467 Point::default()
468 } else if target >= text.last_point().char() {
469 text.last_point()
470 } else if by.abs() < 500 {
471 if by > 0 {
472 let (point, _) = text
473 .chars_fwd(self.caret()..)
474 .unwrap()
475 .take(by as usize + 1)
476 .last()
477 .unwrap();
478 point
479 } else {
480 let (point, _) = text
481 .chars_rev(..self.caret())
482 .unwrap()
483 .take(by.unsigned_abs())
484 .last()
485 .unwrap();
486 point
487 }
488 } else {
489 text.point_at_char(target)
490 };
491
492 let moved = p.char() as i32 - self.caret.get().point().char() as i32;
493 *self.caret.get_mut() = LazyVPoint::Unknown(p);
494 moved
495 }
496
497 pub fn move_ver(&mut self, by: i32, text: &Text, area: &Area, opts: PrintOpts) -> i32 {
501 let by = by as isize;
502 if by == 0 {
503 return 0;
504 };
505
506 let (vp, moved) = {
507 let vp = self.caret.get().calculate(text, area, opts);
508 let line_start = {
509 let target = self.caret.get().point().line().saturating_add_signed(by);
510 text.point_at_line(target.min(text.last_point().line()))
511 };
512
513 let mut wraps = 0;
514 let mut vcol = 0;
515
516 let (wcol, p) = area
517 .print_iter(text, line_start.to_two_points_before(), opts)
518 .find_map(|(Caret { len, x, wrap }, item)| {
519 wraps += wrap as usize;
520
521 if let Some((p, char)) = item.as_real_char()
522 && (vcol + len as u16 > vp.dvcol || char == '\n')
523 {
524 return Some((x as u16, p));
525 }
526
527 vcol += len as u16;
528 None
529 })
530 .unwrap_or((0, text.last_point()));
531
532 let moved = p.line() as i32 - vp.p.line() as i32;
533 let vp = vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol);
534 (vp, moved)
535 };
536
537 *self.caret.get_mut() = LazyVPoint::Known(vp);
538 moved
539 }
540
541 pub fn move_ver_wrapped(
545 &mut self,
546 by: i32,
547 text: &Text,
548 area: &Area,
549 opts: PrintOpts,
550 ) -> i32 {
551 if by == 0 {
552 return 0;
553 };
554 let vp = self.caret.get().calculate(text, area, opts);
555
556 let mut wraps = 0;
557
558 *self.caret.get_mut() = LazyVPoint::Known(if by > 0 {
559 let line_start = text.point_at_line(vp.p.line());
560 let mut vcol = vp.vcol;
561 let mut last = (vp.vcol, vp.wcol, vp.p);
562 let mut last_valid = (vp.vcol, vp.wcol, vp.p);
563
564 let (vcol, wcol, p) = area
565 .print_iter(text, line_start.to_two_points_after(), opts)
566 .skip_while(|(_, item)| item.char() <= self.char())
567 .find_map(|(Caret { x, len, wrap }, item)| {
568 wraps += wrap as i32;
569 if let Some((p, char)) = item.as_real_char() {
570 if (x..x + len).contains(&(vp.dwcol as u32))
571 || (char == '\n' && x <= vp.dwcol as u32)
572 {
573 last_valid = (vcol, x as u16, p);
574 if wraps == by {
575 return Some((vcol, x as u16, p));
576 }
577 } else if wraps > by {
578 return Some(last);
579 }
580 last = (vcol, x as u16, p);
581 }
582 vcol += len as u16;
583 None
584 })
585 .unwrap_or(last_valid);
586 vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol)
587 } else {
588 let end_points = text.points_after(vp.p.to_two_points_after()).unwrap();
589 let mut just_wrapped = false;
590 let mut last_valid = (vp.wcol, vp.p);
591
592 let mut iter = area.rev_print_iter(text, end_points, opts);
593 let wcol_and_p = iter.find_map(|(Caret { x, len, wrap }, item)| {
594 if let Some((p, _)) = item.as_real_char() {
595 if (x..x + len.max(1)).contains(&(vp.dwcol as u32))
597 || (just_wrapped && x + len < vp.dwcol as u32)
598 {
599 last_valid = (x as u16, p);
600 if wraps == by {
601 return Some((x as u16, p));
602 }
603 }
604 just_wrapped = false;
605 }
606 wraps -= wrap as i32;
607 just_wrapped |= wrap;
608 None
609 });
610
611 if let Some((wcol, p)) = wcol_and_p {
612 let (ccol, vcol) = iter
613 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
614 .fold((0, 0), |(ccol, vcol), (caret, item)| {
615 (ccol + item.is_real() as u16, vcol + caret.len as u16)
616 });
617
618 vp.known(p, ccol, vcol, wcol)
619 } else {
620 let (wcol, p) = last_valid;
621 let (ccol, vcol) = area
622 .rev_print_iter(text, p.to_two_points_before(), opts)
623 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
624 .fold((0, 0), |(ccol, vcol), (caret, item)| {
625 (ccol + item.is_real() as u16, vcol + caret.len as u16)
626 });
627
628 vp.known(p, ccol, vcol, wcol)
629 }
630 });
631
632 wraps
633 }
634
635 pub(crate) fn shift_by_change(&self, change: Change<&str>) {
636 let (shift, taken) = (change.shift(), change.taken_end());
637 if self.caret() >= change.start() {
638 let shifted_caret = self.caret().max(taken).shift_by(shift);
639 self.caret.set(LazyVPoint::Unknown(shifted_caret));
640 }
641 if let Some(anchor) = self.anchor.get()
642 && anchor.point() >= change.start()
643 {
644 let shifted_anchor = anchor.point().max(taken).shift_by(shift);
645 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
646 }
647 }
648
649 pub(crate) fn shift_by(&self, shift: [i32; 3]) {
652 let shifted_caret = self.caret().shift_by(shift);
653 self.caret.set(LazyVPoint::Unknown(shifted_caret));
654 if let Some(anchor) = self.anchor.get() {
655 let shifted_anchor = anchor.point().shift_by(shift);
656 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
657 }
658 }
659
660 pub(crate) fn correct(&mut self, bytes: &Bytes) {
663 self.caret.set(LazyVPoint::Unknown(
664 bytes.point_at_byte(self.caret.get().point().byte()),
665 ));
666
667 if let Some(anchor) = self.anchor.get() {
668 self.anchor.set(Some(LazyVPoint::Unknown(
669 bytes.point_at_byte(anchor.point().byte()),
670 )))
671 }
672 }
673
674 pub fn set_anchor(&mut self) {
682 *self.anchor.get_mut() = Some(self.caret.get())
683 }
684
685 pub fn unset_anchor(&mut self) -> Option<Point> {
690 self.anchor.take().map(|a| a.point())
691 }
692
693 pub fn swap_ends(&mut self) {
695 if let Some(anchor) = self.anchor.get_mut() {
696 std::mem::swap(self.caret.get_mut(), anchor);
697 }
698 }
699
700 pub fn caret(&self) -> Point {
702 self.caret.get().point()
703 }
704
705 pub fn anchor(&self) -> Option<Point> {
707 self.anchor.get().map(|a| a.point())
708 }
709
710 pub fn byte(&self) -> usize {
713 self.caret.get().point().byte()
714 }
715
716 pub fn char(&self) -> usize {
719 self.caret.get().point().char()
720 }
721
722 pub fn line(&self) -> usize {
724 self.caret.get().point().line()
725 }
726
727 pub fn byte_range(&self, bytes: &Bytes) -> Range<usize> {
742 let range = self.point_range(bytes);
743 range.start.byte()..range.end.byte()
744 }
745
746 pub fn start(&self) -> Point {
748 if let Some(anchor) = self.anchor.get() {
749 anchor.point().min(self.caret.get().point())
750 } else {
751 self.caret.get().point()
752 }
753 }
754
755 pub fn end(&self, bytes: &Bytes) -> Point {
757 let raw = self.end_excl();
758 assert_ne!(raw, bytes.len(), "Exclusive end is len");
759 raw.fwd(bytes.char_at(raw).unwrap())
760 }
761
762 pub(super) fn end_excl(&self) -> Point {
763 if let Some(anchor) = self.anchor.get() {
764 anchor.point().max(self.caret.get().point())
765 } else {
766 self.caret.get().point()
767 }
768 }
769
770 pub fn point_range(&self, bytes: &Bytes) -> Range<Point> {
775 self.start()..self.end(bytes)
776 }
777
778 pub fn point_range_excl(&self) -> Range<Point> {
782 self.start()..self.end_excl()
783 }
784
785 pub(crate) fn tag_points(&self, bytes: &Bytes) -> (Point, Option<Range<Point>>) {
786 let caret = self.caret();
787 if let Some(anchor) = self.anchor() {
788 match anchor.cmp(&caret) {
789 Ordering::Less => (caret, Some(anchor..caret)),
790 Ordering::Equal => (caret, None),
791 Ordering::Greater => {
792 let end = anchor.fwd(bytes.char_at(anchor).unwrap());
793 (caret, Some(caret..end))
794 }
795 }
796 } else {
797 (caret, None)
798 }
799 }
800
801 pub fn set_desired_cols(&mut self, v: usize, w: usize) {
806 let (v, w) = (v as u16, w as u16);
807 match self.caret.get_mut() {
808 LazyVPoint::Known(vp) => {
809 vp.dvcol = v;
810 vp.dwcol = w;
811 }
812 LazyVPoint::Unknown(p) => {
813 *self.caret.get_mut() = LazyVPoint::Desired { p: *p, dvcol: v, dwcol: w }
814 }
815 LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
816 }
817 }
818
819 pub fn v_caret(&self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
825 let vp = self.caret.get().calculate(text, area, opts);
826 self.caret.set(LazyVPoint::Known(vp));
827 vp
828 }
829
830 pub fn v_anchor(&self, text: &Text, area: &Area, opts: PrintOpts) -> Option<VPoint> {
836 self.anchor.get().map(|anchor| {
837 let vp = anchor.calculate(text, area, opts);
838 self.anchor.set(Some(LazyVPoint::Known(vp)));
839 vp
840 })
841 }
842
843 pub fn v_range(&self, text: &Text, area: &Area, opts: PrintOpts) -> [VPoint; 2] {
850 let v_caret = self.v_caret(text, area, opts);
851 let v_anchor = self.v_anchor(text, area, opts).unwrap_or(v_caret);
852 [v_caret.min(v_anchor), v_caret.max(v_anchor)]
853 }
854
855 pub(super) fn lazy_v_start(&self) -> LazyVPoint {
857 match self.anchor.get() {
858 Some(anchor) => self.caret.get().min(anchor),
859 None => self.caret.get(),
860 }
861 }
862
863 pub(super) fn lazy_v_end(&self) -> LazyVPoint {
865 match self.anchor.get() {
866 Some(anchor) => self.caret.get().max(anchor),
867 None => self.caret.get(),
868 }
869 }
870 }
871
872 #[derive(Clone, Copy, Eq, Encode, Decode)]
875 pub(super) enum LazyVPoint {
876 Known(VPoint),
877 Unknown(Point),
878 Desired { p: Point, dvcol: u16, dwcol: u16 },
879 }
880
881 impl LazyVPoint {
882 fn point(self) -> Point {
884 match self {
885 LazyVPoint::Known(vp) => vp.p,
886 LazyVPoint::Unknown(p) => p,
887 LazyVPoint::Desired { p, .. } => p,
888 }
889 }
890
891 fn calculate(self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
893 match self {
894 Self::Known(vp) => vp,
895 Self::Unknown(p) => VPoint::new(p, text, area, opts),
896 Self::Desired { p, dvcol, dwcol } => {
897 let mut vp = VPoint::new(p, text, area, opts);
898 vp.dvcol = dvcol;
899 vp.dwcol = dwcol;
900 vp
901 }
902 }
903 }
904 }
905
906 impl Default for LazyVPoint {
907 fn default() -> Self {
908 Self::Desired { p: Point::default(), dvcol: 0, dwcol: 0 }
909 }
910 }
911
912 #[allow(clippy::non_canonical_partial_ord_impl)]
913 impl PartialOrd for LazyVPoint {
914 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
915 Some(self.point().cmp(&other.point()))
916 }
917 }
918
919 impl Ord for LazyVPoint {
920 fn cmp(&self, other: &Self) -> Ordering {
921 self.partial_cmp(other).unwrap()
922 }
923 }
924
925 impl PartialEq for LazyVPoint {
926 fn eq(&self, other: &Self) -> bool {
927 self.point() == other.point()
928 }
929 }
930
931 #[derive(Clone, Copy, Debug, Eq, Encode, Decode)]
955 pub struct VPoint {
956 p: Point,
957 ccol: u16,
959 vcol: u16,
960 dvcol: u16,
961 wcol: u16,
962 dwcol: u16,
963 }
964
965 impl VPoint {
966 fn new(p: Point, text: &Text, area: &Area, opts: PrintOpts) -> Self {
968 let range = text.line_range(p.line());
969
970 let mut vcol = 0;
971
972 let wcol = area
973 .print_iter(text, range.start.to_two_points_before(), opts)
974 .find_map(|(caret, item)| {
975 if let Some((lhs, _)) = item.as_real_char()
976 && lhs == p
977 {
978 return Some(caret.x as u16);
979 }
980 vcol += caret.len as u16;
981 None
982 })
983 .unwrap_or(0);
984
985 Self {
986 p,
987 ccol: (p.char() - range.start.char()) as u16,
988 vcol,
989 dvcol: vcol,
990 wcol,
991 dwcol: wcol,
992 }
993 }
994
995 fn known(self, p: Point, ccol: u16, vcol: u16, wcol: u16) -> Self {
997 Self { p, ccol, vcol, wcol, ..self }
998 }
999
1000 pub fn byte(&self) -> usize {
1002 self.p.byte()
1003 }
1004
1005 pub fn char(&self) -> usize {
1007 self.p.char()
1008 }
1009
1010 pub fn line(&self) -> usize {
1012 self.p.line()
1013 }
1014
1015 pub fn char_col(&self) -> usize {
1017 self.ccol as usize
1018 }
1019
1020 pub fn visual_col(&self) -> usize {
1022 self.vcol as usize
1023 }
1024
1025 pub fn desired_visual_col(&self) -> usize {
1027 self.dvcol as usize
1028 }
1029
1030 pub fn wrapped_col(&self) -> usize {
1032 self.wcol as usize
1033 }
1034
1035 pub fn desired_wrapped_col(&self) -> usize {
1037 self.dwcol as usize
1038 }
1039 }
1040
1041 #[allow(clippy::non_canonical_partial_ord_impl)]
1042 impl PartialOrd for VPoint {
1043 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1044 Some(self.p.cmp(&other.p))
1045 }
1046 }
1047
1048 impl Ord for VPoint {
1049 fn cmp(&self, other: &Self) -> Ordering {
1050 self.partial_cmp(other).unwrap()
1051 }
1052 }
1053
1054 impl PartialEq for VPoint {
1055 fn eq(&self, other: &Self) -> bool {
1056 self.p == other.p
1057 }
1058 }
1059
1060 impl std::fmt::Debug for Selection {
1061 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1062 f.debug_struct("Selection")
1063 .field("caret", &self.caret.get())
1064 .field("anchor", &self.anchor.get())
1065 .field("change_i", &self.change_i)
1066 .finish()
1067 }
1068 }
1069
1070 impl std::fmt::Debug for LazyVPoint {
1071 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1072 match self {
1073 Self::Known(vp) => write!(f, "Known({:?}, {})", vp.p, vp.dwcol),
1074 Self::Unknown(p) => write!(f, "Unknown({p:?}"),
1075 Self::Desired { p, dvcol, dwcol } => write!(f, "Desired({p:?}, {dvcol}, {dwcol})"),
1076 }
1077 }
1078 }
1079}
1080
1081impl std::fmt::Debug for Selections {
1082 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1083 struct DebugShiftState((usize, [i32; 3]));
1084 impl std::fmt::Debug for DebugShiftState {
1085 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1086 write!(f, "{:?}", self.0)
1087 }
1088 }
1089
1090 f.debug_struct("Selections")
1091 .field("buf", &self.buf)
1092 .field("main_i", &self.main_i)
1093 .field("shift_sate", &DebugShiftState(self.shift_state.get()))
1094 .finish()
1095 }
1096}