1use std::sync::Mutex;
16
17use gapbuf::{GapBuffer, gap_buffer};
18
19pub use self::cursor::{Selection, VPoint};
20use crate::{
21 buffer::Change,
22 text::{Bytes, Point, TextRange},
23 utils::{add_shifts, merging_range_by_guess_and_lazy_shift},
24};
25
26pub struct Selections {
50 buf: GapBuffer<Selection>,
51 main_i: usize,
52 shift: Mutex<Shift>,
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: Mutex::default(),
62 }
63 }
64
65 pub(crate) fn new_empty() -> Self {
67 Self {
68 buf: GapBuffer::new(),
69 main_i: 0,
70 shift: Mutex::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.get_mut().unwrap() = Shift::default();
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 = std::mem::take(self.shift.get_mut().unwrap());
106 if shift.from <= self.main_i && shift.by != [0; 3] {
107 cursor.shift_by(shift.by);
108 }
109 self.buf = gap_buffer![cursor];
110 }
111 self.main_i = 0;
112 }
113
114 pub(crate) fn correct_all(&mut self, bytes: &mut Bytes) {
117 for selection in &mut self.buf {
118 selection.correct(bytes)
119 }
120 }
121
122 #[track_caller]
131 pub fn main(&self) -> &Selection {
132 match self.get(self.main_i) {
133 Some(main) => main,
134 None => panic!("No main selection"),
135 }
136 }
137
138 pub fn get_main(&self) -> Option<&Selection> {
143 self.get(self.main_i)
144 }
145
146 pub fn get(&self, n: usize) -> Option<&Selection> {
148 if n >= self.len() {
149 return None;
150 }
151 let mut shift = self.shift.lock().unwrap();
152 if n >= shift.from && shift.by != [0; 3] {
153 for cursor in self.buf.range(shift.from..n + 1).iter() {
154 cursor.shift_by(shift.by);
155 }
156 if n + 1 < self.buf.len() {
157 shift.from = n + 1;
158 } else {
159 *shift = Shift::default();
160 }
161 }
162
163 self.buf.get(n)
164 }
165
166 pub fn iter(&self) -> impl Iterator<Item = (&Selection, bool)> {
171 let mut shift = *self.shift.lock().unwrap();
172
173 self.buf.iter().enumerate().map(move |(i, selection)| {
174 if i >= shift.from && shift.by != [0; 3] {
175 selection.shift_by(shift.by);
176 if i + 1 < self.buf.len() {
177 self.shift.lock().unwrap().from = i + 1;
178 shift.from = i + 1;
179 } else {
180 *self.shift.lock().unwrap() = Shift::default();
181 }
182 }
183
184 (selection, i == self.main_i)
185 })
186 }
187
188 pub fn iter_within(
196 &self,
197 range: impl TextRange,
198 ) -> impl Iterator<Item = (usize, &Selection, bool)> {
199 let shift = *self.shift.lock().unwrap();
200
201 let range = if let Some(last) = self.buf.len().checked_sub(1) {
202 range.to_range(self.buf[last].end_point_excl().byte())
203 } else {
204 0..0
206 };
207
208 let m_range = merging_range_by_guess_and_lazy_shift(
209 (&self.buf, self.buf.len()),
210 (0, [range.start, range.end]),
211 (shift.from, shift.by[0], 0, |byte, shift| {
212 (byte as i32 + shift) as usize
213 }),
214 (
215 |sel| sel.start_point().byte(),
216 |sel| sel.end_point_excl().byte(),
217 ),
218 );
219
220 let (s0, s1) = self.buf.range(m_range.clone()).as_slices();
221 let iter = [s0, s1].into_iter().flatten().enumerate();
222 iter.map(move |(i, selection)| {
223 let i = i + m_range.start;
224 if i >= shift.from && shift.by != [0; 3] {
225 selection.shift_by(shift.by);
226 if i + 1 < self.buf.len() {
227 self.shift.lock().unwrap().from = i + 1;
228 } else {
229 *self.shift.lock().unwrap() = Shift::default();
230 }
231 }
232
233 (i, selection, i == self.main_i)
234 })
235 }
236
237 pub fn main_index(&self) -> usize {
239 self.main_i
240 }
241
242 pub fn len(&self) -> usize {
244 self.buf.len()
245 }
246
247 #[must_use]
249 pub fn is_empty(&self) -> bool {
250 self.len() == 0
251 }
252
253 pub(crate) fn insert(
257 &mut self,
258 guess_i: usize,
259 sel: Selection,
260 main: bool,
261 ) -> ([usize; 2], bool) {
262 let mut shift = self.shift.lock().unwrap();
263 let shift_from = shift.from.min(self.len());
264
265 let m_range = merging_range_by_guess_and_lazy_shift(
267 (&self.buf, self.buf.len()),
268 (guess_i, [sel.start_point(), sel.end_point_excl()]),
269 (shift_from, shift.by, [0; 3], Point::shift_by),
270 (Selection::start_point, Selection::end_point_excl),
271 );
272
273 if shift_from < m_range.end && shift.by != [0; 3] {
275 for cursor in self.buf.range(shift_from..m_range.end).into_iter() {
276 cursor.shift_by(shift.by);
277 }
278 }
279
280 let (caret, anchor, last_cursor_overhangs) = {
283 let mut c_range = m_range.clone();
284 let first = c_range.next().and_then(|i| self.buf.get(i));
285 let last = c_range.last().and_then(|i| self.buf.get(i)).or(first);
286 let start = first
287 .map(|first| first.lazy_v_start().min(sel.lazy_v_start()))
288 .unwrap_or(sel.lazy_v_start());
289 let (end, last_sel_overhangs) = if let Some(last) = last
290 && last.lazy_v_end() >= sel.lazy_v_end()
291 {
292 (last.lazy_v_end(), true)
293 } else {
294 (sel.lazy_v_end(), false)
295 };
296
297 if let Some(anchor) = sel.anchor() {
298 match sel.caret() < anchor {
299 true => (start, Some(end), last_sel_overhangs),
300 false => (end, Some(start), last_sel_overhangs),
301 }
302 } else {
303 (end, (start != end).then_some(start), last_sel_overhangs)
304 }
305 };
306
307 let selection = Selection::from_v(caret, anchor, sel.change_i);
308 self.buf.splice(m_range.clone(), [selection]);
309
310 if main {
311 self.main_i = m_range.start;
312 } else if self.main_i >= m_range.start {
313 self.main_i = (self.main_i + 1 - m_range.clone().count()).max(m_range.start)
314 }
315
316 let cursors_taken = m_range.clone().count();
319 let new_shift_from = shift_from.saturating_sub(cursors_taken).max(m_range.start) + 1;
320 if new_shift_from < self.buf.len() {
321 shift.from = new_shift_from;
322 } else {
323 *shift = Shift::default()
324 }
325
326 ([m_range.start, cursors_taken], last_cursor_overhangs)
327 }
328
329 pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
333 let mut shift = self.shift.lock().unwrap();
334 let shift_from = shift.from.min(self.len());
335
336 let c_range = merging_range_by_guess_and_lazy_shift(
338 (&self.buf, self.buf.len()),
339 (guess_i, [change.start(), change.taken_end()]),
340 (shift_from, shift.by, [0; 3], Point::shift_by),
341 (Selection::start_point, Selection::end_point_excl),
342 );
343
344 if c_range.end > shift_from && shift.by != [0; 3] {
349 for cursor in self.buf.range(shift_from..c_range.end).into_iter() {
350 cursor.shift_by(shift.by);
351 }
352 }
353 let range = c_range.start..c_range.end.max(shift_from);
354 for cursor in self.buf.range(range).into_iter() {
355 cursor.shift_by_change(change);
356 }
357
358 let (cursors_taken, cursors_added) = {
359 let mut cursors_taken = self.buf.splice(c_range.clone(), []);
360 if let Some(first) = cursors_taken.next() {
361 let last = cursors_taken.next_back().unwrap_or(first.clone());
362 let (start, end) = (first.start_point(), last.end_point_excl());
363 let merged = Selection::new(start, (start < end).then_some(end));
364 drop(cursors_taken);
365 self.buf.insert(c_range.start, merged);
366
367 (c_range.len(), 1)
368 } else {
369 (0, 0)
370 }
371 };
372
373 let from = shift_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
374 if from < self.buf.len() {
375 *shift = Shift {
376 from,
377 by: add_shifts(shift.by, change.shift()),
378 };
379 } else {
380 *shift = Shift::default()
381 }
382
383 cursors_taken - cursors_added
384 }
385
386 pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
388 if i >= self.buf.len() {
389 return None;
390 }
391 let shift = self.shift.get_mut().unwrap();
392
393 if i >= shift.from && shift.by != [0; 3] {
394 for cursor in self.buf.range(shift.from..i + 1).iter() {
395 cursor.shift_by(shift.by);
396 }
397 if i + 1 < self.buf.len() {
398 shift.from = i;
401 } else {
402 *shift = Shift::default()
403 }
404 } else if i < shift.from {
405 shift.from -= 1;
408 }
409
410 let was_main = self.main_i == i;
411 if self.main_i >= i {
412 self.main_i = self.main_i.saturating_sub(1);
413 }
414 Some((self.buf.remove(i), was_main))
415 }
416
417 pub(crate) fn populate(&mut self) {
419 if self.buf.is_empty() {
420 self.main_i = 0;
421 self.buf = gap_buffer![Selection::default()];
422 }
423 }
424}
425
426impl Clone for Selections {
427 fn clone(&self) -> Self {
428 Self {
429 buf: self.buf.clone(),
430 main_i: self.main_i,
431 shift: Mutex::new(*self.shift.lock().unwrap()),
432 }
433 }
434}
435
436mod cursor {
437 use std::{cmp::Ordering, ops::Range, sync::Mutex};
438
439 use bincode::{Decode, Encode};
440
441 use crate::{
442 buffer::Change,
443 opts::PrintOpts,
444 text::{Bytes, Point, Text, TextIndex},
445 ui::{Area, Caret},
446 };
447
448 #[derive(Default, Encode, Decode)]
451 pub struct Selection {
452 caret: Mutex<LazyVPoint>,
453 anchor: Mutex<Option<LazyVPoint>>,
454 pub(in crate::mode::cursor) change_i: Option<u32>,
455 }
456
457 impl Selection {
458 pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
460 Self {
461 caret: Mutex::new(LazyVPoint::Unknown(caret)),
462 anchor: Mutex::new(anchor.map(LazyVPoint::Unknown)),
463 change_i: None,
464 }
465 }
466
467 pub(super) fn from_v(
468 caret: LazyVPoint,
469 anchor: Option<LazyVPoint>,
470 change_i: Option<u32>,
471 ) -> Self {
472 Self {
473 caret: Mutex::new(caret),
474 anchor: Mutex::new(anchor),
475 change_i,
476 }
477 }
478
479 #[track_caller]
481 pub fn move_to(&mut self, idx: impl TextIndex, text: &Text) {
482 let byte = idx.to_byte_index();
483 if byte == self.caret().byte() {
484 return;
485 }
486 *self.caret.get_mut().unwrap() =
487 LazyVPoint::Unknown(text.point_at_byte(byte.min(text.len().byte() - 1)));
488 }
489
490 pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
494 let by = by as isize;
495 if by == 0 {
496 return 0;
497 };
498
499 let caret = self.caret.get_mut().unwrap();
500
501 let target_char = caret.point().char().saturating_add_signed(by);
505
506 let point = if target_char == 0 {
507 Point::default()
508 } else if target_char >= text.last_point().char() {
509 text.last_point()
510 } else if by.abs() < 500 {
511 if by > 0 {
512 text.chars_fwd(caret.point()..)
513 .unwrap()
514 .take(by as usize)
515 .fold(caret.point(), |point, (_, char)| point.fwd(char))
516 } else {
517 text.chars_rev(..caret.point())
518 .unwrap()
519 .take(by.unsigned_abs())
520 .fold(caret.point(), |point, (_, char)| point.rev(char))
521 }
522 } else {
523 text.point_at_char(target_char)
524 };
525
526 let moved = point.char() as i32 - caret.point().char() as i32;
527 *caret = LazyVPoint::Unknown(point);
528 moved
529 }
530
531 pub fn move_ver(&mut self, by: i32, text: &Text, area: &Area, opts: PrintOpts) -> i32 {
535 let by = by as isize;
536 if by == 0 {
537 return 0;
538 };
539
540 let caret = self.caret.get_mut().unwrap();
541
542 let (vp, moved) = {
543 let vp = caret.calculate(text, area, opts);
544 let line_start = {
545 let target = vp.point.line().saturating_add_signed(by);
546 text.point_at_line(target.min(text.last_point().line()))
547 };
548
549 let mut wraps = 0;
550 let mut vcol = 0;
551
552 let (wcol, p) = area
553 .print_iter(text, line_start.to_two_points_before(), opts)
554 .find_map(|(Caret { len, x, wrap }, item)| {
555 wraps += wrap as usize;
556
557 if let Some((p, char)) = item.as_real_char()
558 && (vcol + len as u16 > vp.dvcol || char == '\n')
559 {
560 return Some((x as u16, p));
561 }
562
563 vcol += len as u16;
564 None
565 })
566 .unwrap_or((0, text.last_point()));
567
568 let moved = p.line() as i32 - vp.point.line() as i32;
569 let vp = vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol);
570 (vp, moved)
571 };
572
573 *caret = LazyVPoint::Known(vp);
574 moved
575 }
576
577 pub fn move_ver_wrapped(
581 &mut self,
582 by: i32,
583 text: &Text,
584 area: &Area,
585 opts: PrintOpts,
586 ) -> i32 {
587 if by == 0 {
588 return 0;
589 };
590 let caret = self.caret.get_mut().unwrap();
591 let vp = caret.calculate(text, area, opts);
592
593 let mut wraps = 0;
594
595 *caret = LazyVPoint::Known(if by > 0 {
596 let line_start = text.point_at_line(vp.point.line());
597 let mut vcol = vp.vcol;
598 let mut last = (vp.vcol, vp.wcol, vp.point);
599 let mut last_valid = (vp.vcol, vp.wcol, vp.point);
600
601 let (vcol, wcol, p) = area
602 .print_iter(text, line_start.to_two_points_after(), opts)
603 .skip_while(|(_, item)| item.char() <= vp.char())
604 .find_map(|(Caret { x, len, wrap }, item)| {
605 wraps += wrap as i32;
606 if let Some((p, char)) = item.as_real_char() {
607 if (x..x + len).contains(&(vp.dwcol as u32))
608 || (char == '\n' && x <= vp.dwcol as u32)
609 {
610 last_valid = (vcol, x as u16, p);
611 if wraps == by {
612 return Some((vcol, x as u16, p));
613 }
614 } else if wraps > by {
615 return Some(last);
616 }
617 last = (vcol, x as u16, p);
618 }
619 vcol += len as u16;
620 None
621 })
622 .unwrap_or(last_valid);
623 vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol)
624 } else {
625 let end_points = text.points_after(vp.point.to_two_points_after()).unwrap();
626 let mut just_wrapped = false;
627 let mut last_valid = (vp.wcol, vp.point);
628
629 let mut iter = area.rev_print_iter(text, end_points, opts);
630 let wcol_and_p = iter.find_map(|(Caret { x, len, wrap }, item)| {
631 if let Some((p, _)) = item.as_real_char() {
632 if (x..x + len.max(1)).contains(&(vp.dwcol as u32))
634 || (just_wrapped && x + len < vp.dwcol as u32)
635 {
636 last_valid = (x as u16, p);
637 if wraps == by {
638 return Some((x as u16, p));
639 }
640 }
641 just_wrapped = false;
642 }
643 wraps -= wrap as i32;
644 just_wrapped |= wrap;
645 None
646 });
647
648 if let Some((wcol, p)) = wcol_and_p {
649 let (ccol, vcol) = iter
650 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
651 .fold((0, 0), |(ccol, vcol), (caret, item)| {
652 (ccol + item.is_real() as u16, vcol + caret.len as u16)
653 });
654
655 vp.known(p, ccol, vcol, wcol)
656 } else {
657 let (wcol, p) = last_valid;
658 let (ccol, vcol) = area
659 .rev_print_iter(text, p.to_two_points_before(), opts)
660 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
661 .fold((0, 0), |(ccol, vcol), (caret, item)| {
662 (ccol + item.is_real() as u16, vcol + caret.len as u16)
663 });
664
665 vp.known(p, ccol, vcol, wcol)
666 }
667 });
668
669 wraps
670 }
671
672 pub(crate) fn shift_by_change(&self, change: Change<&str>) {
673 let mut caret = self.caret.lock().unwrap();
674
675 let (shift, taken) = (change.shift(), change.taken_end());
676 if caret.point() >= change.start() {
677 let shifted_caret = caret.point().max(taken).shift_by(shift);
678 *caret = LazyVPoint::Unknown(shifted_caret);
679 }
680
681 let mut anchor = self.anchor.lock().unwrap();
682 if let Some(anchor) = &mut *anchor
683 && anchor.point() >= change.start()
684 {
685 let shifted_anchor = anchor.point().max(taken).shift_by(shift);
686 *anchor = LazyVPoint::Unknown(shifted_anchor);
687 }
688 }
689
690 pub(crate) fn shift_by(&self, shift: [i32; 3]) {
693 let mut caret = self.caret.lock().unwrap();
694 *caret = LazyVPoint::Unknown(caret.point().shift_by(shift));
695
696 let mut anchor = self.anchor.lock().unwrap();
697 if let Some(anchor) = &mut *anchor {
698 *anchor = LazyVPoint::Unknown(anchor.point().shift_by(shift));
699 }
700 }
701
702 pub(crate) fn correct(&mut self, bytes: &mut Bytes) {
705 let mut caret = self.caret.lock().unwrap();
706 *caret = LazyVPoint::Unknown(bytes.point_at_byte(caret.point().byte()));
707 let point = caret.point();
708 bytes.add_record([point.byte(), point.char(), point.line()]);
709
710 let mut anchor = self.anchor.lock().unwrap();
711 if let Some(anchor) = &mut *anchor {
712 *anchor = LazyVPoint::Unknown(bytes.point_at_byte(anchor.point().byte()));
713 let point = anchor.point();
714 bytes.add_record([point.byte(), point.char(), point.line()]);
715 }
716 }
717
718 pub fn set_anchor(&mut self) {
726 *self.anchor.get_mut().unwrap() = Some(*self.caret.get_mut().unwrap())
727 }
728
729 pub fn unset_anchor(&mut self) -> Option<Point> {
734 self.anchor.get_mut().unwrap().take().map(|a| a.point())
735 }
736
737 pub fn swap_ends(&mut self) {
739 if let Some(anchor) = self.anchor.get_mut().unwrap() {
740 std::mem::swap(self.caret.get_mut().unwrap(), anchor);
741 }
742 }
743
744 pub fn caret(&self) -> Point {
746 self.caret.lock().unwrap().point()
747 }
748
749 pub fn anchor(&self) -> Option<Point> {
752 self.anchor.lock().unwrap().map(|lazy| lazy.point())
753 }
754
755 pub fn byte_range(&self, bytes: &Bytes) -> Range<usize> {
770 self.start_point().byte()..self.end_point(bytes).byte()
771 }
772
773 pub fn start_point(&self) -> Point {
775 if let Some(anchor) = *self.anchor.lock().unwrap() {
776 anchor.point().min(self.caret.lock().unwrap().point())
777 } else {
778 self.caret.lock().unwrap().point()
779 }
780 }
781
782 pub fn end_point(&self, bytes: &Bytes) -> Point {
784 self.end_point_excl()
785 .fwd(bytes.char_at(self.end_point_excl()).unwrap())
786 }
787
788 pub(super) fn end_point_excl(&self) -> Point {
789 if let Some(anchor) = *self.anchor.lock().unwrap() {
790 anchor.point().max(self.caret.lock().unwrap().point())
791 } else {
792 self.caret.lock().unwrap().point()
793 }
794 }
795
796 pub fn point_range(&self, bytes: &Bytes) -> Range<Point> {
801 self.start_point()..self.end_point(bytes)
802 }
803
804 pub fn point_range_excl(&self) -> Range<Point> {
808 self.start_point()..self.end_point_excl()
809 }
810
811 pub(crate) fn tag_bytes(&self, bytes: &Bytes) -> (usize, Option<Range<usize>>) {
812 let caret = self.caret().byte();
813 if let Some(anchor) = self.anchor() {
814 match anchor.byte().cmp(&caret) {
815 Ordering::Less => (caret, Some(anchor.byte()..caret)),
816 Ordering::Equal => (caret, None),
817 Ordering::Greater => {
818 let end = anchor.byte() + bytes.char_at(anchor).unwrap().len_utf8();
819 (caret, Some(caret..end))
820 }
821 }
822 } else {
823 (caret, None)
824 }
825 }
826
827 pub fn set_desired_cols(&mut self, v: usize, w: usize) {
832 let (v, w) = (v as u16, w as u16);
833 let caret = self.caret.get_mut().unwrap();
834 match caret {
835 LazyVPoint::Known(vp) => {
836 vp.dvcol = v;
837 vp.dwcol = w;
838 }
839 LazyVPoint::Unknown(point) => {
840 *caret = LazyVPoint::Desired { point: *point, dvcol: v, dwcol: w }
841 }
842 LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
843 }
844 }
845
846 pub fn v_caret(&self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
852 let mut caret = self.caret.lock().unwrap();
853 let vp = caret.calculate(text, area, opts);
854 *caret = LazyVPoint::Known(vp);
855 vp
856 }
857
858 pub fn v_anchor(&self, text: &Text, area: &Area, opts: PrintOpts) -> Option<VPoint> {
864 self.anchor.lock().unwrap().as_mut().map(|anchor| {
865 let vp = anchor.calculate(text, area, opts);
866 *anchor = LazyVPoint::Known(vp);
867 vp
868 })
869 }
870
871 pub fn v_range(&self, text: &Text, area: &Area, opts: PrintOpts) -> [VPoint; 2] {
878 let v_caret = self.v_caret(text, area, opts);
879 let v_anchor = self.v_anchor(text, area, opts).unwrap_or(v_caret);
880 [v_caret.min(v_anchor), v_caret.max(v_anchor)]
881 }
882
883 pub(super) fn lazy_v_start(&self) -> LazyVPoint {
885 match *self.anchor.lock().unwrap() {
886 Some(anchor) => self.caret.lock().unwrap().min(anchor),
887 None => *self.caret.lock().unwrap(),
888 }
889 }
890
891 pub(super) fn lazy_v_end(&self) -> LazyVPoint {
893 match *self.anchor.lock().unwrap() {
894 Some(anchor) => self.caret.lock().unwrap().max(anchor),
895 None => *self.caret.lock().unwrap(),
896 }
897 }
898 }
899
900 impl Clone for Selection {
901 fn clone(&self) -> Self {
902 Self {
903 caret: Mutex::new(*self.caret.lock().unwrap()),
904 anchor: Mutex::new(*self.anchor.lock().unwrap()),
905 change_i: self.change_i,
906 }
907 }
908 }
909
910 #[derive(Clone, Copy, Eq, Encode, Decode)]
913 pub(super) enum LazyVPoint {
914 Unknown(Point),
915 Known(VPoint),
916 Desired {
917 point: Point,
918 dvcol: u16,
919 dwcol: u16,
920 },
921 }
922
923 impl LazyVPoint {
924 fn point(&self) -> Point {
925 match *self {
926 LazyVPoint::Unknown(point) | LazyVPoint::Desired { point, .. } => point,
927 LazyVPoint::Known(vp) => vp.point,
928 }
929 }
930
931 fn calculate(self, text: &Text, area: &Area, opts: PrintOpts) -> VPoint {
933 match self {
934 Self::Known(vp) => vp,
935 Self::Unknown(point) => VPoint::new(point, text, area, opts),
936 Self::Desired { point, dvcol, dwcol } => {
937 let mut vp = VPoint::new(point, text, area, opts);
938 vp.dvcol = dvcol;
939 vp.dwcol = dwcol;
940 vp
941 }
942 }
943 }
944 }
945
946 impl Default for LazyVPoint {
947 fn default() -> Self {
948 Self::Desired {
949 point: Point::default(),
950 dvcol: 0,
951 dwcol: 0,
952 }
953 }
954 }
955
956 #[allow(clippy::non_canonical_partial_ord_impl)]
957 impl PartialOrd for LazyVPoint {
958 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
959 Some(self.point().cmp(&other.point()))
960 }
961 }
962
963 impl Ord for LazyVPoint {
964 fn cmp(&self, other: &Self) -> Ordering {
965 self.partial_cmp(other).unwrap()
966 }
967 }
968
969 impl PartialEq for LazyVPoint {
970 fn eq(&self, other: &Self) -> bool {
971 self.point() == other.point()
972 }
973 }
974
975 #[derive(Clone, Copy, Debug, Eq, Encode, Decode)]
999 pub struct VPoint {
1000 point: Point,
1001 ccol: u16,
1003 vcol: u16,
1004 dvcol: u16,
1005 wcol: u16,
1006 dwcol: u16,
1007 }
1008
1009 impl VPoint {
1010 fn new(point: Point, text: &Text, area: &Area, opts: PrintOpts) -> Self {
1012 let range = text.line_range(point.line());
1013
1014 let mut vcol = 0;
1015
1016 let wcol = area
1017 .print_iter(text, range.start.to_two_points_before(), opts)
1018 .find_map(|(caret, item)| {
1019 if let Some((lhs, _)) = item.as_real_char()
1020 && lhs == point
1021 {
1022 return Some(caret.x as u16);
1023 }
1024 vcol += caret.len as u16;
1025 None
1026 })
1027 .unwrap_or(0);
1028
1029 Self {
1030 point,
1031 ccol: (point.char() - range.start.char()) as u16,
1032 vcol,
1033 dvcol: vcol,
1034 wcol,
1035 dwcol: wcol,
1036 }
1037 }
1038
1039 fn known(self, p: Point, ccol: u16, vcol: u16, wcol: u16) -> Self {
1041 Self { point: p, ccol, vcol, wcol, ..self }
1042 }
1043
1044 pub fn byte(&self) -> usize {
1046 self.point.byte()
1047 }
1048
1049 pub fn char(&self) -> usize {
1051 self.point.char()
1052 }
1053
1054 pub fn line(&self) -> usize {
1056 self.point.line()
1057 }
1058
1059 pub fn char_col(&self) -> usize {
1061 self.ccol as usize
1062 }
1063
1064 pub fn visual_col(&self) -> usize {
1066 self.vcol as usize
1067 }
1068
1069 pub fn desired_visual_col(&self) -> usize {
1071 self.dvcol as usize
1072 }
1073
1074 pub fn wrapped_col(&self) -> usize {
1076 self.wcol as usize
1077 }
1078
1079 pub fn desired_wrapped_col(&self) -> usize {
1081 self.dwcol as usize
1082 }
1083 }
1084
1085 #[allow(clippy::non_canonical_partial_ord_impl)]
1086 impl PartialOrd for VPoint {
1087 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1088 Some(self.point.cmp(&other.point))
1089 }
1090 }
1091
1092 impl Ord for VPoint {
1093 fn cmp(&self, other: &Self) -> Ordering {
1094 self.partial_cmp(other).unwrap()
1095 }
1096 }
1097
1098 impl PartialEq for VPoint {
1099 fn eq(&self, other: &Self) -> bool {
1100 self.point == other.point
1101 }
1102 }
1103
1104 impl std::fmt::Debug for Selection {
1105 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1106 f.debug_struct("Selection")
1107 .field("caret", &*self.caret.lock().unwrap())
1108 .field("anchor", &*self.anchor.lock().unwrap())
1109 .field("change_i", &self.change_i)
1110 .finish()
1111 }
1112 }
1113
1114 impl std::fmt::Debug for LazyVPoint {
1115 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1116 match self {
1117 Self::Known(vp) => write!(f, "Known({:?}, {})", vp.point, vp.dwcol),
1118 Self::Unknown(p_or_b) => write!(f, "Unknown({p_or_b:?}"),
1119 Self::Desired { point, dvcol, dwcol } => {
1120 write!(f, "Desired({point:?}, {dvcol}, {dwcol})")
1121 }
1122 }
1123 }
1124 }
1125}
1126
1127impl std::fmt::Debug for Selections {
1128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1129 struct DebugShiftState(Shift);
1130 impl std::fmt::Debug for DebugShiftState {
1131 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1132 write!(f, "{:?}", self.0)
1133 }
1134 }
1135
1136 f.debug_struct("Selections")
1137 .field("buf", &self.buf)
1138 .field("main_i", &self.main_i)
1139 .field("shift_sate", &DebugShiftState(*self.shift.lock().unwrap()))
1140 .finish()
1141 }
1142}
1143
1144#[derive(Default, Debug, Clone, Copy)]
1145struct Shift {
1146 from: usize,
1147 by: [i32; 3],
1148}