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, TextRange},
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(crate) fn new(main: Selection) -> Self {
44 Self {
45 buf: gap_buffer![main],
46 main_i: 0,
47 shift_state: Cell::new((0, [0; 3])),
48 }
49 }
50
51 pub(crate) fn new_empty() -> Self {
53 Self {
54 buf: GapBuffer::new(),
55 main_i: 0,
56 shift_state: Cell::default(),
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 (shift_from, shift) = self.shift_state.take();
92 if shift_from <= self.main_i && shift != [0; 3] {
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 (shift_from, shift) = self.shift_state.get();
113 if n >= shift_from && shift != [0; 3] {
114 for cursor in self.buf.range(shift_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)> {
132 let (mut shift_from, shift) = self.shift_state.get();
133
134 self.buf.iter().enumerate().map(move |(i, selection)| {
135 if i >= shift_from && shift != [0; 3] {
136 selection.shift_by(shift);
137 if i + 1 < self.buf.len() {
138 self.shift_state.set((i + 1, shift));
139 shift_from = i + 1;
140 } else {
141 self.shift_state.set((0, [0; 3]));
142 }
143 }
144
145 (selection, i == self.main_i)
146 })
147 }
148
149 pub fn iter_within(
157 &self,
158 range: impl TextRange,
159 ) -> impl Iterator<Item = (usize, &Selection, bool)> {
160 let (shift_from, shift) = self.shift_state.get();
161
162 let range = if let Some(last) = self.buf.len().checked_sub(1) {
163 range.to_range(self.buf[last].end_excl().byte())
164 } else {
165 0..0
167 };
168
169 let m_range = merging_range_by_guess_and_lazy_shift(
170 (&self.buf, self.buf.len()),
171 (0, [range.start, range.end]),
172 (shift_from, shift[0], 0, |byte, shift| {
173 (byte as i32 + shift) as usize
174 }),
175 (
176 |sel: &Selection| sel.start().byte(),
177 |sel: &Selection| sel.end_excl().byte(),
178 ),
179 );
180
181 let (s0, s1) = self.buf.range(m_range.clone()).as_slices();
182 let iter = [s0, s1].into_iter().flatten().enumerate();
183 iter.map(move |(i, selection)| {
184 let i = i + m_range.start;
185 if i >= shift_from && shift != [0; 3] {
186 selection.shift_by(shift);
187 if i + 1 < self.buf.len() {
188 self.shift_state.set((i + 1, shift));
189 } else {
190 self.shift_state.set((0, [0; 3]));
191 }
192 }
193
194 (i, selection, i == self.main_i)
195 })
196 }
197
198 pub fn main_index(&self) -> usize {
200 self.main_i
201 }
202
203 pub fn len(&self) -> usize {
205 self.buf.len()
206 }
207
208 #[must_use]
210 pub fn is_empty(&self) -> bool {
211 self.len() == 0
212 }
213
214 pub(crate) fn insert(
218 &mut self,
219 guess_i: usize,
220 sel: Selection,
221 main: bool,
222 ) -> ([usize; 2], bool) {
223 let (shift_from, shift) = self.shift_state.take();
224 let shift_from = shift_from.min(self.len());
225
226 let m_range = merging_range_by_guess_and_lazy_shift(
228 (&self.buf, self.buf.len()),
229 (guess_i, [sel.start(), sel.end_excl()]),
230 (shift_from, shift, [0; 3], Point::shift_by),
231 (Selection::start, Selection::end_excl),
232 );
233
234 if shift_from < m_range.end && shift != [0; 3] {
236 for cursor in self.buf.range(shift_from..m_range.end).into_iter() {
237 cursor.shift_by(shift);
238 }
239 }
240
241 let (caret, anchor, last_cursor_overhangs) = {
244 let mut c_range = m_range.clone();
245 let first = c_range.next().and_then(|i| self.get(i));
246 let last = c_range.last().and_then(|i| self.get(i)).or(first);
247 let start = first
248 .map(|first| first.lazy_v_start().min(sel.lazy_v_start()))
249 .unwrap_or(sel.lazy_v_start());
250 let (end, last_sel_overhangs) = if let Some(last) = last
251 && last.lazy_v_end() >= sel.lazy_v_end()
252 {
253 (last.lazy_v_end(), true)
254 } else {
255 (sel.lazy_v_end(), false)
256 };
257
258 if let Some(anchor) = sel.anchor() {
259 match sel.caret() < anchor {
260 true => (start, Some(end), last_sel_overhangs),
261 false => (end, Some(start), last_sel_overhangs),
262 }
263 } else {
264 (end, (start != end).then_some(start), last_sel_overhangs)
265 }
266 };
267
268 let selection = Selection::from_v(caret, anchor, sel.change_i);
269 self.buf.splice(m_range.clone(), [selection]);
270
271 if main {
272 self.main_i = m_range.start;
273 } else if self.main_i >= m_range.start {
274 self.main_i = (self.main_i + 1 - m_range.clone().count()).max(m_range.start)
275 }
276
277 let cursors_taken = m_range.clone().count();
280 let new_shift_from = shift_from.saturating_sub(cursors_taken).max(m_range.start) + 1;
281 if new_shift_from < self.buf.len() {
282 self.shift_state.set((new_shift_from, shift));
283 }
284
285 ([m_range.start, cursors_taken], last_cursor_overhangs)
286 }
287
288 pub(crate) fn apply_change(&mut self, guess_i: usize, change: Change<&str>) -> usize {
292 let (shift_from, shift) = self.shift_state.take();
293 let shift_from = shift_from.min(self.len());
294
295 let c_range = merging_range_by_guess_and_lazy_shift(
297 (&self.buf, self.buf.len()),
298 (guess_i, [change.start(), change.taken_end()]),
299 (shift_from, shift, [0; 3], Point::shift_by),
300 (Selection::start, Selection::end_excl),
301 );
302
303 if c_range.end > shift_from && shift != [0; 3] {
308 for cursor in self.buf.range(shift_from..c_range.end).into_iter() {
309 cursor.shift_by(shift);
310 }
311 }
312 let range = c_range.start..c_range.end.max(shift_from);
313 for cursor in self.buf.range(range).into_iter() {
314 cursor.shift_by_change(change);
315 }
316
317 let (cursors_taken, cursors_added) = {
318 let mut cursors_taken = self.buf.splice(c_range.clone(), []);
319 if let Some(first) = cursors_taken.next() {
320 let last = cursors_taken.next_back().unwrap_or(first.clone());
321 let (start, end) = (first.start(), last.end_excl());
322 let merged = Selection::new(start, (start < end).then_some(end));
323 drop(cursors_taken);
324 self.buf.insert(c_range.start, merged);
325
326 (c_range.len(), 1)
327 } else {
328 (0, 0)
329 }
330 };
331
332 let new_shift_from =
333 shift_from.saturating_sub(cursors_taken).max(c_range.start) + cursors_added;
334 if new_shift_from < self.buf.len() {
335 self.shift_state
336 .set((new_shift_from, add_shifts(shift, change.shift())));
337 }
338
339 cursors_taken - cursors_added
340 }
341
342 pub(crate) fn remove(&mut self, i: usize) -> Option<(Selection, bool)> {
344 if i >= self.buf.len() {
345 return None;
346 }
347 let (shift_from, shift) = self.shift_state.get();
348
349 if i >= shift_from && shift != [0; 3] {
350 for cursor in self.buf.range(shift_from..i + 1).iter() {
351 cursor.shift_by(shift);
352 }
353 if i + 1 < self.buf.len() {
354 self.shift_state.set((i, shift));
357 } else {
358 self.shift_state.take();
359 }
360 } else if i < shift_from {
361 self.shift_state.set((shift_from - 1, shift));
364 }
365
366 let was_main = self.main_i == i;
367 if self.main_i >= i {
368 self.main_i = self.main_i.saturating_sub(1);
369 }
370 Some((self.buf.remove(i), was_main))
371 }
372
373 pub(crate) fn populate(&mut self) {
375 if self.buf.is_empty() {
376 self.main_i = 0;
377 self.buf = gap_buffer![Selection::default()];
378 }
379 }
380}
381
382mod cursor {
383 use std::{cell::Cell, cmp::Ordering, ops::Range};
384
385 use bincode::{Decode, Encode};
386
387 use crate::{
388 cfg::PrintCfg,
389 text::{Bytes, Change, Point, Text},
390 ui::{Caret, Area},
391 };
392
393 #[derive(Default, Clone, Encode, Decode)]
396 pub struct Selection {
397 caret: Cell<LazyVPoint>,
398 anchor: Cell<Option<LazyVPoint>>,
399 pub(in crate::mode::cursor) change_i: Option<u32>,
400 }
401
402 impl Selection {
403 pub(crate) fn new(caret: Point, anchor: Option<Point>) -> Self {
405 Self {
406 caret: Cell::new(LazyVPoint::Unknown(caret)),
407 anchor: Cell::new(anchor.map(LazyVPoint::Unknown)),
408 change_i: None,
409 }
410 }
411
412 pub(super) fn from_v(
413 caret: LazyVPoint,
414 anchor: Option<LazyVPoint>,
415 change_i: Option<u32>,
416 ) -> Self {
417 Self {
418 caret: Cell::new(caret),
419 anchor: Cell::new(anchor),
420 change_i,
421 }
422 }
423
424 pub fn move_to(&mut self, p: Point, text: &Text) {
426 if p == self.caret() {
427 return;
428 }
429 let p = text.point_at_byte(p.byte().min(text.last_point().byte()));
430 *self.caret.get_mut() = LazyVPoint::Unknown(p);
431 }
432
433 pub fn move_hor(&mut self, by: i32, text: &Text) -> i32 {
437 let by = by as isize;
438 if by == 0 {
439 return 0;
440 };
441 let target = self.caret.get().point().char().saturating_add_signed(by);
442
443 let p = if target == 0 {
444 Point::default()
445 } else if target >= text.last_point().char() {
446 text.last_point()
447 } else if by.abs() < 500 {
448 if by > 0 {
449 let (point, _) = text
450 .chars_fwd(self.caret()..)
451 .unwrap()
452 .take(by as usize + 1)
453 .last()
454 .unwrap();
455 point
456 } else {
457 let (point, _) = text
458 .chars_rev(..self.caret())
459 .unwrap()
460 .take(by.unsigned_abs())
461 .last()
462 .unwrap();
463 point
464 }
465 } else {
466 text.point_at_char(target)
467 };
468
469 let moved = p.char() as i32 - self.caret.get().point().char() as i32;
470 *self.caret.get_mut() = LazyVPoint::Unknown(p);
471 moved
472 }
473
474 pub fn move_ver(
478 &mut self,
479 by: i32,
480 text: &Text,
481 area: &impl Area,
482 mut cfg: PrintCfg,
483 ) -> i32 {
484 let by = by as isize;
485 if by == 0 {
486 return 0;
487 };
488
489 let (vp, moved) = {
490 let vp = self.caret.get().calculate(text, area, cfg);
491 let line_start = {
492 let target = self.caret.get().point().line().saturating_add_signed(by);
493 text.point_at_line(target.min(text.last_point().line()))
494 };
495
496 let mut wraps = 0;
497 let mut vcol = 0;
498
499 let (wcol, p) = area
500 .print_iter(text.iter_fwd(line_start), *cfg.new_line_as('\n'))
501 .find_map(|(Caret { len, x, wrap }, item)| {
502 wraps += wrap as usize;
503 if let Some((p, char)) = item.as_real_char()
504 && (vcol + len as u16 > vp.dvcol || char == '\n')
505 {
506 return Some((x as u16, p));
507 }
508
509 vcol += len as u16;
510 None
511 })
512 .unwrap_or((0, text.last_point()));
513
514 let moved = p.line() as i32 - vp.p.line() as i32;
515 let vp = vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol);
516 (vp, moved)
517 };
518
519 *self.caret.get_mut() = LazyVPoint::Known(vp);
520 moved
521 }
522
523 pub fn move_ver_wrapped(
527 &mut self,
528 by: i32,
529 text: &Text,
530 area: &impl Area,
531 mut cfg: PrintCfg,
532 ) -> i32 {
533 if by == 0 {
534 return 0;
535 };
536 let vp = self.caret.get().calculate(text, area, cfg);
537
538 let mut wraps = 0;
539
540 *self.caret.get_mut() = LazyVPoint::Known(if by > 0 {
541 let line_start = text.point_at_line(vp.p.line());
542 let mut vcol = vp.vcol;
543 let mut last = (vp.vcol, vp.wcol, vp.p);
544 let mut last_valid = (vp.vcol, vp.wcol, vp.p);
545
546 let (vcol, wcol, p) = area
547 .print_iter(text.iter_fwd(line_start), *cfg.new_line_as('\n'))
548 .skip_while(|(_, item)| item.char() <= self.char())
549 .find_map(|(Caret { x, len, wrap }, item)| {
550 wraps += wrap as i32;
551 if let Some((p, char)) = item.as_real_char() {
552 if (x..x + len).contains(&(vp.dwcol as u32))
553 || (char == '\n' && x <= vp.dwcol as u32)
554 {
555 last_valid = (vcol, x as u16, p);
556 if wraps == by {
557 return Some((vcol, x as u16, p));
558 }
559 } else if wraps > by {
560 return Some(last);
561 }
562 last = (vcol, x as u16, p);
563 }
564 vcol += len as u16;
565 None
566 })
567 .unwrap_or(last_valid);
568 vp.known(p, (p.char() - line_start.char()) as u16, vcol, wcol)
569 } else {
570 let end_points = text.points_after(vp.p).unwrap();
571 let mut just_wrapped = false;
572 let mut last_valid = (vp.wcol, vp.p);
573
574 let mut iter = area.rev_print_iter(text.iter_rev(end_points), cfg);
575 let wcol_and_p = iter.find_map(|(Caret { x, len, wrap }, item)| {
576 if let Some((p, _)) = item.as_real_char() {
577 if (x..x + len.max(1)).contains(&(vp.dwcol as u32))
579 || (just_wrapped && x + len < vp.dwcol as u32)
580 {
581 last_valid = (x as u16, p);
582 if wraps == by {
583 return Some((x as u16, p));
584 }
585 }
586 just_wrapped = false;
587 }
588 wraps -= wrap as i32;
589 just_wrapped |= wrap;
590 None
591 });
592
593 if let Some((wcol, p)) = wcol_and_p {
594 let (ccol, vcol) = iter
595 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
596 .fold((0, 0), |(ccol, vcol), (caret, item)| {
597 (ccol + item.is_real() as u16, vcol + caret.len as u16)
598 });
599
600 vp.known(p, ccol, vcol, wcol)
601 } else {
602 let (wcol, p) = last_valid;
603 let (ccol, vcol) = area
604 .rev_print_iter(text.iter_rev(p), *cfg.new_line_as('\n'))
605 .take_while(|(_, item)| item.as_real_char().is_none_or(|(_, c)| c != '\n'))
606 .fold((0, 0), |(ccol, vcol), (caret, item)| {
607 (ccol + item.is_real() as u16, vcol + caret.len as u16)
608 });
609
610 vp.known(p, ccol, vcol, wcol)
611 }
612 });
613
614 wraps
615 }
616
617 pub(crate) fn shift_by_change(&self, change: Change<&str>) {
618 let (shift, taken) = (change.shift(), change.taken_end());
619 if self.caret() >= change.start() {
620 let shifted_caret = self.caret().max(taken).shift_by(shift);
621 self.caret.set(LazyVPoint::Unknown(shifted_caret));
622 }
623 if let Some(anchor) = self.anchor.get()
624 && anchor.point() >= change.start()
625 {
626 let shifted_anchor = anchor.point().max(taken).shift_by(shift);
627 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
628 }
629 }
630
631 pub(crate) fn shift_by(&self, shift: [i32; 3]) {
634 let shifted_caret = self.caret().shift_by(shift);
635 self.caret.set(LazyVPoint::Unknown(shifted_caret));
636 if let Some(anchor) = self.anchor.get() {
637 let shifted_anchor = anchor.point().shift_by(shift);
638 self.anchor.set(Some(LazyVPoint::Unknown(shifted_anchor)));
639 }
640 }
641
642 pub fn set_anchor(&mut self) {
648 *self.anchor.get_mut() = Some(self.caret.get())
649 }
650
651 pub fn unset_anchor(&mut self) -> Option<Point> {
656 self.anchor.take().map(|a| a.point())
657 }
658
659 pub fn swap_ends(&mut self) {
661 if let Some(anchor) = self.anchor.get_mut() {
662 std::mem::swap(self.caret.get_mut(), anchor);
663 }
664 }
665
666 pub fn caret(&self) -> Point {
668 self.caret.get().point()
669 }
670
671 pub fn anchor(&self) -> Option<Point> {
673 self.anchor.get().map(|a| a.point())
674 }
675
676 pub fn byte(&self) -> usize {
679 self.caret.get().point().byte()
680 }
681
682 pub fn char(&self) -> usize {
685 self.caret.get().point().char()
686 }
687
688 pub fn line(&self) -> usize {
690 self.caret.get().point().line()
691 }
692
693 pub fn range(&self, bytes: &Bytes) -> Range<usize> {
706 let [start, end] = self.point_range(bytes);
707 start.byte()..end.byte()
708 }
709
710 pub fn start(&self) -> Point {
712 if let Some(anchor) = self.anchor.get() {
713 anchor.point().min(self.caret.get().point())
714 } else {
715 self.caret.get().point()
716 }
717 }
718
719 pub fn end(&self, bytes: &Bytes) -> Point {
721 let raw = self.end_excl();
722 if raw == bytes.len() {
723 panic!("equals len: {raw:?}, {bytes:#?}");
724 }
725 raw.fwd(bytes.char_at(raw).unwrap())
726 }
727
728 pub(super) fn end_excl(&self) -> Point {
729 if let Some(anchor) = self.anchor.get() {
730 anchor.point().max(self.caret.get().point())
731 } else {
732 self.caret.get().point()
733 }
734 }
735
736 pub(crate) fn tag_points(&self, bytes: &Bytes) -> (Point, Option<[Point; 2]>) {
737 let caret = self.caret();
738 if let Some(anchor) = self.anchor() {
739 match anchor.cmp(&caret) {
740 Ordering::Less => (caret, Some([anchor, caret])),
741 Ordering::Equal => (caret, None),
742 Ordering::Greater => {
743 let end = anchor.fwd(bytes.char_at(anchor).unwrap());
744 (caret, Some([caret, end]))
745 }
746 }
747 } else {
748 (caret, None)
749 }
750 }
751
752 pub fn point_range(&self, bytes: &Bytes) -> [Point; 2] {
757 [self.start(), self.end(bytes)]
758 }
759
760 pub fn point_range_excl(&self) -> [Point; 2] {
764 [self.start(), self.end_excl()]
765 }
766
767 pub fn set_desired_cols(&mut self, v: usize, w: usize) {
770 let (v, w) = (v as u16, w as u16);
771 match self.caret.get_mut() {
772 LazyVPoint::Known(vp) => {
773 vp.dvcol = v;
774 vp.dwcol = w;
775 }
776 LazyVPoint::Unknown(p) => {
777 *self.caret.get_mut() = LazyVPoint::Desired { p: *p, dvcol: v, dwcol: w }
778 }
779 LazyVPoint::Desired { dvcol, dwcol, .. } => (*dvcol, *dwcol) = (v, w),
780 }
781 }
782
783 pub fn v_caret(&self, text: &Text, area: &impl Area, cfg: PrintCfg) -> VPoint {
789 let vp = self.caret.get().calculate(text, area, cfg);
790 self.caret.set(LazyVPoint::Known(vp));
791 vp
792 }
793
794 pub fn v_anchor(&self, text: &Text, area: &impl Area, cfg: PrintCfg) -> Option<VPoint> {
800 self.anchor.get().map(|anchor| {
801 let vp = anchor.calculate(text, area, cfg);
802 self.anchor.set(Some(LazyVPoint::Known(vp)));
803 vp
804 })
805 }
806
807 pub fn v_range(&self, text: &Text, area: &impl Area, cfg: PrintCfg) -> [VPoint; 2] {
814 let v_caret = self.v_caret(text, area, cfg);
815 let v_anchor = self.v_anchor(text, area, cfg).unwrap_or(v_caret);
816 [v_caret.min(v_anchor), v_caret.max(v_anchor)]
817 }
818
819 pub(super) fn lazy_v_start(&self) -> LazyVPoint {
821 match self.anchor.get() {
822 Some(anchor) => self.caret.get().min(anchor),
823 None => self.caret.get(),
824 }
825 }
826
827 pub(super) fn lazy_v_end(&self) -> LazyVPoint {
829 match self.anchor.get() {
830 Some(anchor) => self.caret.get().max(anchor),
831 None => self.caret.get(),
832 }
833 }
834 }
835
836 #[derive(Clone, Copy, Eq, Encode, Decode)]
839 pub(super) enum LazyVPoint {
840 Known(VPoint),
841 Unknown(Point),
842 Desired { p: Point, dvcol: u16, dwcol: u16 },
843 }
844
845 impl LazyVPoint {
846 fn point(self) -> Point {
848 match self {
849 LazyVPoint::Known(vp) => vp.p,
850 LazyVPoint::Unknown(p) => p,
851 LazyVPoint::Desired { p, .. } => p,
852 }
853 }
854
855 fn calculate(self, text: &Text, area: &impl Area, cfg: PrintCfg) -> VPoint {
857 match self {
858 Self::Known(vp) => vp,
859 Self::Unknown(p) => VPoint::new(p, text, area, cfg),
860 Self::Desired { p, dvcol, dwcol } => {
861 let mut vp = VPoint::new(p, text, area, cfg);
862 vp.dvcol = dvcol;
863 vp.dwcol = dwcol;
864 vp
865 }
866 }
867 }
868 }
869
870 impl Default for LazyVPoint {
871 fn default() -> Self {
872 Self::Desired { p: Point::default(), dvcol: 0, dwcol: 0 }
873 }
874 }
875
876 #[allow(clippy::non_canonical_partial_ord_impl)]
877 impl PartialOrd for LazyVPoint {
878 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
879 Some(self.point().cmp(&other.point()))
880 }
881 }
882
883 impl Ord for LazyVPoint {
884 fn cmp(&self, other: &Self) -> Ordering {
885 self.partial_cmp(other).unwrap()
886 }
887 }
888
889 impl PartialEq for LazyVPoint {
890 fn eq(&self, other: &Self) -> bool {
891 self.point() == other.point()
892 }
893 }
894
895 #[derive(Clone, Copy, Debug, Eq, Encode, Decode)]
919 pub struct VPoint {
920 p: Point,
921 ccol: u16,
923 vcol: u16,
924 dvcol: u16,
925 wcol: u16,
926 dwcol: u16,
927 }
928
929 impl VPoint {
930 fn new(p: Point, text: &Text, area: &impl Area, cfg: PrintCfg) -> Self {
932 let [start, _] = text.points_of_line(p.line());
933
934 let mut vcol = 0;
935
936 let wcol = area
937 .print_iter(text.iter_fwd(text.visual_line_start(start)), cfg)
938 .find_map(|(caret, item)| {
939 if let Some((lhs, _)) = item.as_real_char()
940 && lhs == p
941 {
942 return Some(caret.x as u16);
943 }
944 vcol += caret.len as u16;
945 None
946 })
947 .unwrap_or(0);
948
949 Self {
950 p,
951 ccol: (p.char() - start.char()) as u16,
952 vcol,
953 dvcol: vcol,
954 wcol,
955 dwcol: wcol,
956 }
957 }
958
959 fn known(self, p: Point, ccol: u16, vcol: u16, wcol: u16) -> Self {
961 Self { p, ccol, vcol, wcol, ..self }
962 }
963
964 pub fn byte(&self) -> usize {
966 self.p.byte()
967 }
968
969 pub fn char(&self) -> usize {
971 self.p.char()
972 }
973
974 pub fn line(&self) -> usize {
976 self.p.line()
977 }
978
979 pub fn char_col(&self) -> usize {
981 self.ccol as usize
982 }
983
984 pub fn visual_col(&self) -> usize {
986 self.vcol as usize
987 }
988
989 pub fn desired_visual_col(&self) -> usize {
991 self.dvcol as usize
992 }
993
994 pub fn wrapped_col(&self) -> usize {
996 self.wcol as usize
997 }
998
999 pub fn desired_wrapped_col(&self) -> usize {
1001 self.dwcol as usize
1002 }
1003 }
1004
1005 #[allow(clippy::non_canonical_partial_ord_impl)]
1006 impl PartialOrd for VPoint {
1007 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
1008 Some(self.p.cmp(&other.p))
1009 }
1010 }
1011
1012 impl Ord for VPoint {
1013 fn cmp(&self, other: &Self) -> Ordering {
1014 self.partial_cmp(other).unwrap()
1015 }
1016 }
1017
1018 impl PartialEq for VPoint {
1019 fn eq(&self, other: &Self) -> bool {
1020 self.p == other.p
1021 }
1022 }
1023
1024 impl std::fmt::Debug for Selection {
1025 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1026 f.debug_struct("Selection")
1027 .field("caret", &self.caret.get())
1028 .field("anchor", &self.anchor.get())
1029 .field("change_i", &self.change_i)
1030 .finish()
1031 }
1032 }
1033
1034 impl std::fmt::Debug for LazyVPoint {
1035 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1036 match self {
1037 Self::Known(vp) => write!(f, "Known({:?})", vp.p),
1038 Self::Unknown(p) => write!(f, "Unknown({p:?}"),
1039 Self::Desired { p, dvcol, dwcol } => write!(f, "Desired({p:?}, {dvcol}, {dwcol})"),
1040 }
1041 }
1042 }
1043}
1044
1045impl std::fmt::Debug for Selections {
1046 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1047 struct DebugShiftState((usize, [i32; 3]));
1048 impl std::fmt::Debug for DebugShiftState {
1049 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1050 write!(f, "{:?}", self.0)
1051 }
1052 }
1053
1054 f.debug_struct("Selections")
1055 .field("buf", &self.buf)
1056 .field("main_i", &self.main_i)
1057 .field("shift_sate", &DebugShiftState(self.shift_state.get()))
1058 .finish()
1059 }
1060}