1use std::ops::RangeBounds;
2
3use gapbuf::{GapBuffer, gap_buffer};
4use serde::{Deserialize, Serialize, de::Visitor, ser::SerializeSeq};
5
6pub use self::cursor::Cursor;
7use crate::{
8 cfg::PrintCfg,
9 text::{Point, Text},
10 ui::Area,
11};
12
13#[derive(Clone, Debug, Serialize, Deserialize)]
14pub struct Cursors {
15 buf: CursorGapBuffer,
16 main_i: usize,
17 is_incl: bool,
18}
19
20impl Cursors {
21 pub fn new_excl() -> Self {
23 Self {
24 buf: CursorGapBuffer(gap_buffer![Cursor::default()]),
25 main_i: 0,
26 is_incl: false,
27 }
28 }
29
30 pub fn new_incl() -> Self {
31 Self {
32 buf: CursorGapBuffer(gap_buffer![Cursor::default()]),
33 main_i: 0,
34 is_incl: true,
35 }
36 }
37
38 pub fn reset_on_byte(&mut self, b: usize, text: &Text, area: &impl Area, cfg: PrintCfg) {
39 let point = text.point_at(b.min(text.len().byte()));
40 let cursor = Cursor::new(point, text, area, cfg);
41 self.buf = CursorGapBuffer(gap_buffer![cursor]);
42 self.main_i = 0;
43 }
44
45 pub fn make_excl(&mut self) {
46 self.is_incl = false;
47 }
48
49 pub fn make_incl(&mut self) {
50 self.is_incl = true;
51 }
52
53 pub fn insert_from_parts(
55 &mut self,
56 guess_i: usize,
57 point: Point,
58 range: usize,
59 text: &Text,
60 area: &impl Area,
61 cfg: PrintCfg,
62 ) -> usize {
63 let mut cursor = Cursor::new(point, text, area, cfg);
64 let range = match self.is_incl {
65 true => range.saturating_sub(1),
66 false => range,
67 };
68 if range > 0 {
69 cursor.set_anchor();
70 cursor.move_hor(range as i32, text, area, cfg);
71 }
72 self.insert(guess_i, false, cursor)
73 }
74
75 pub(super) fn insert(&mut self, guess_i: usize, was_main: bool, cursor: Cursor) -> usize {
76 let c_range = if let Some(prev_i) = guess_i.checked_sub(1)
78 && let Some(prev) = self.get(prev_i)
79 && prev.start() <= cursor.start()
80 && cursor.start_v() <= prev.end_v()
81 {
82 prev_i..guess_i
83 } else {
84 let buf = self.buf.range(..);
85 match binary_search_by_key(buf, cursor.start_v(), |c| c.start_v()) {
86 Ok(i) => i..i + 1,
87 Err(i) => {
88 if let Some(prev_i) = i.checked_sub(1)
89 && let Some(prev) = self.buf.get(prev_i)
90 && cursor.start_v() <= prev.end_v()
91 {
92 prev_i..i
93 } else {
94 i..i
95 }
96 }
97 }
98 };
99
100 let c_range = if self
102 .get(c_range.end)
103 .is_none_or(|c| cursor.end_v() < c.start_v())
104 {
105 c_range
106 } else {
107 let buf = self.buf.range(..);
108 match binary_search_by_key(buf, cursor.end_v(), |c| c.start_v()) {
109 Ok(i) => c_range.start..i + 1,
110 Err(i) => {
111 if let Some(prev) = self.buf.get(i)
112 && prev.start_v() < cursor.end_v()
113 {
114 c_range.start..i + 1
115 } else {
116 c_range.start..i
117 }
118 }
119 }
120 };
121
122 let mut c_range_iter = c_range.clone();
123 let first = c_range_iter.next().and_then(|i| self.get(i));
124 let last = c_range_iter.last().and_then(|i| self.get(i));
125 let start = first
126 .map(|c| c.start_v().min(cursor.start_v()))
127 .unwrap_or(cursor.start_v());
128 let end = last
129 .map(|c| c.end_v().max(cursor.end_v()))
130 .unwrap_or(cursor.end_v());
131
132 let (caret, anchor) = if let Some(anchor) = cursor.anchor() {
133 match cursor.caret() < anchor {
134 true => (start, Some(end)),
135 false => (end, Some(start)),
136 }
137 } else {
138 (end, (start != end).then_some(start))
139 };
140
141 let cursor = Cursor::from_v(caret, anchor, cursor.change_i);
142 self.buf.drain(c_range.clone());
143 self.buf.insert(c_range.start, cursor);
144
145 if was_main {
146 self.main_i = c_range.start;
147 } else if self.main_i > c_range.start {
148 self.main_i = (self.main_i - c_range.clone().count()).max(c_range.start)
149 }
150
151 c_range.start
152 }
153
154 pub fn rotate_main(&mut self, amount: i32) {
155 self.main_i = (self.main_i as i32 + amount).rem_euclid(self.buf.len() as i32) as usize
156 }
157
158 pub fn remove_extras(&mut self) {
159 if !self.is_empty() {
160 let cursor = self.buf[self.main_i];
161 self.buf = CursorGapBuffer(gap_buffer![cursor]);
162 }
163 self.main_i = 0;
164 }
165
166 pub fn main(&self) -> &Cursor {
172 &self.buf[self.main_i]
173 }
174
175 pub fn get_main(&self) -> Option<Cursor> {
176 self.get(self.main_i)
177 }
178
179 pub fn get(&self, i: usize) -> Option<Cursor> {
180 self.buf.get(i).cloned()
181 }
182
183 pub fn iter(&self) -> impl Iterator<Item = (&Cursor, bool)> {
184 self.buf
185 .iter()
186 .enumerate()
187 .map(move |(index, cursor)| (cursor, index == self.main_i))
188 }
189
190 pub fn main_index(&self) -> usize {
191 self.main_i
192 }
193
194 pub fn len(&self) -> usize {
195 self.buf.len()
196 }
197
198 #[must_use]
199 pub fn is_empty(&self) -> bool {
200 self.len() == 0
201 }
202
203 pub fn is_incl(&self) -> bool {
204 self.is_incl
205 }
206
207 pub fn clear(&mut self) {
208 self.buf = CursorGapBuffer(GapBuffer::new())
209 }
210
211 pub fn reset(&mut self) {
212 self.remove_extras();
213 self.buf[self.main_i] = Cursor::default();
214 }
215
216 pub(super) fn remove(&mut self, i: usize) -> Option<(Cursor, bool)> {
217 (i < self.buf.len()).then(|| {
218 let was_main = self.main_i == i;
219 if self.main_i >= i {
220 self.main_i = self.main_i.saturating_sub(1);
221 }
222 (self.buf.remove(i), was_main)
223 })
224 }
225
226 pub(crate) fn shift_by(
227 &mut self,
228 from: usize,
229 shift: (i32, i32, i32),
230 text: &Text,
231 area: &impl Area,
232 cfg: PrintCfg,
233 ) {
234 for cursor in self.buf.iter_mut().skip(from) {
235 cursor.shift_by(shift, text, area, cfg);
236 }
237 }
238
239 pub(super) fn drain(
240 &mut self,
241 range: impl RangeBounds<usize>,
242 ) -> impl Iterator<Item = (Cursor, bool)> + '_ {
243 let orig_main = self.main_i;
244 self.main_i = 0;
245 self.buf
246 .drain(range)
247 .enumerate()
248 .map(move |(i, c)| match i == orig_main {
249 true => (c, true),
250 false => (c, false),
251 })
252 }
253
254 pub(super) fn populate(&mut self) {
255 if self.buf.0.is_empty() {
256 self.main_i = 0;
257 self.buf.0 = gap_buffer![Cursor::default()];
258 }
259 }
260}
261
262impl Default for Cursors {
263 fn default() -> Self {
264 Self::new_excl()
265 }
266}
267
268mod cursor {
269 use std::ops::Range;
270
271 use serde::{Deserialize, Serialize};
272
273 use crate::{
274 cfg::{IterCfg, PrintCfg},
275 text::{Point, Text},
276 ui::{Area, Caret},
277 };
278
279 #[derive(Default, Clone, Copy, Debug, Serialize, Deserialize)]
282 pub struct Cursor {
283 caret: VPoint,
284 anchor: Option<VPoint>,
285 pub(in crate::mode::helper) change_i: Option<usize>,
286 }
287
288 impl Cursor {
289 pub(super) fn new(point: Point, text: &Text, area: &impl Area, cfg: PrintCfg) -> Self {
291 Self {
292 caret: VPoint::new(point, text, area, cfg),
293 anchor: None,
295 change_i: None,
296 }
297 }
298
299 pub(super) fn from_v(
300 caret: VPoint,
301 anchor: Option<VPoint>,
302 change_i: Option<usize>,
303 ) -> Self {
304 Self { caret, anchor, change_i }
305 }
306
307 pub fn move_to(&mut self, point: Point, text: &Text, area: &impl Area, cfg: PrintCfg) {
309 if point == self.caret() {
310 return;
311 }
312 let Some(last) = text.last_point() else {
313 self.anchor = None;
314 self.caret = VPoint::default();
315 return;
316 };
317 self.caret = VPoint::new(point.min(last), text, area, cfg);
318 }
319
320 pub fn move_hor(&mut self, by: i32, text: &Text, area: &impl Area, cfg: PrintCfg) {
322 let by = by as isize;
323 let (Some(last), false) = (text.last_point(), by == 0) else {
324 return;
325 };
326 let target = self.caret.point.char().saturating_add_signed(by);
327
328 let point = if target == 0 {
329 Point::default()
330 } else if target >= last.char() {
331 last
332 } else if by.abs() < 500 {
333 if by > 0 {
334 let (point, _) = text
335 .chars_fwd(self.caret())
336 .take(by as usize + 1)
337 .last()
338 .unwrap();
339 point
340 } else {
341 let (point, _) = text
342 .chars_rev(self.caret())
343 .take(by.unsigned_abs())
344 .last()
345 .unwrap();
346 point
347 }
348 } else {
349 text.point_at_char(target)
350 };
351
352 self.caret = VPoint::new(point, text, area, cfg);
353 }
354
355 pub fn move_ver(&mut self, by: i32, text: &Text, area: &impl Area, cfg: PrintCfg) {
357 let by = by as isize;
358 let (Some(last), false) = (text.last_point(), by == 0) else {
359 return;
360 };
361 let cfg = IterCfg::new(cfg).dont_wrap();
362 let dcol = self.caret.dcol;
363
364 let point = {
365 let target = self.caret.line().saturating_add_signed(by).min(last.line());
366 let point = text.point_at_line(target);
367
368 area.print_iter(text.iter_fwd(point), cfg)
369 .filter_map(|(caret, item)| Some(caret).zip(item.as_real_char()))
370 .find_map(|(Caret { x, len, .. }, (p, char))| {
371 (p.line() == target && (x + len > dcol || char == '\n')).then_some(p)
372 })
373 .unwrap_or(last)
374 };
375
376 self.caret.point = point;
377 self.caret.vcol = vcol(point, text, area, cfg)
378 }
379
380 pub fn move_ver_wrapped(&mut self, by: i32, text: &Text, area: &impl Area, cfg: PrintCfg) {
382 if text.last_point().is_none() || by == 0 {
383 return;
384 };
385 let cfg = IterCfg::new(cfg);
386 let dwcol = self.caret.dwcol;
387
388 let mut wraps = 0;
389 let mut last_valid = self.caret();
390 let mut new_wrap = false;
391
392 let point = if by > 0 {
393 let line_start = text.visual_line_start(self.caret.point);
394
395 area.print_iter(text.iter_fwd(line_start), cfg)
396 .skip_while(|(_, item)| item.byte() <= self.byte())
397 .filter_map(|(caret, item)| {
398 wraps += caret.wrap as i32;
399 Some((caret, wraps)).zip(item.as_real_char())
400 })
401 .find_map(|((Caret { x, len, wrap }, wraps), (p, char))| {
402 new_wrap |= wrap;
403 if x + len > dwcol || char == '\n' {
404 if new_wrap {
405 new_wrap = false;
406 last_valid = p;
407 }
408 (wraps == by).then_some(p)
409 } else {
410 None
411 }
412 })
413 } else {
414 let end = text.points_after(self.caret.point).unwrap();
415
416 area.rev_print_iter(text.iter_rev(end), cfg)
417 .filter_map(|(Caret { x, wrap, .. }, item)| {
418 let old_wraps = wraps;
419 wraps -= wrap as i32;
420 Some((x, old_wraps, wrap)).zip(item.as_real_char())
421 })
422 .find_map(|((x, wraps, wrap), (p, _))| {
423 if dwcol >= x || wrap {
424 if new_wrap {
425 new_wrap = false;
426 last_valid = p;
427 }
428 (wraps == by).then_some(p)
429 } else {
430 None
431 }
432 })
433 };
434
435 self.caret.point = point.unwrap_or(last_valid);
436 self.caret.vcol = vcol(self.caret.point, text, area, cfg.dont_wrap())
437 }
438
439 pub(crate) fn shift_by(
440 &mut self,
441 shift: (i32, i32, i32),
442 text: &Text,
443 area: &impl Area,
444 cfg: PrintCfg,
445 ) {
446 let shifted_caret = self.caret().shift_by(shift);
447 self.move_to(shifted_caret, text, area, cfg);
448 if let Some(anchor) = self.anchor() {
449 let shifted_anchor = anchor.shift_by(shift);
450 self.swap_ends();
451 self.move_to(shifted_anchor, text, area, cfg);
452 self.swap_ends();
453 }
454 }
455
456 pub fn set_anchor(&mut self) {
462 self.anchor = Some(self.caret)
463 }
464
465 pub fn unset_anchor(&mut self) -> Option<Point> {
470 self.anchor.take().map(|a| a.point)
471 }
472
473 pub fn swap_ends(&mut self) {
475 if let Some(anchor) = self.anchor.as_mut() {
476 std::mem::swap(&mut self.caret, anchor);
477 }
478 }
479
480 pub fn caret(&self) -> Point {
482 self.caret.point
483 }
484
485 pub fn anchor(&self) -> Option<Point> {
486 self.anchor.map(|a| a.point)
487 }
488
489 pub fn byte(&self) -> usize {
492 self.caret.byte()
493 }
494
495 pub fn char(&self) -> usize {
498 self.caret.char()
499 }
500
501 pub fn line(&self) -> usize {
503 self.caret.line()
504 }
505
506 pub fn vcol(&self) -> usize {
508 self.caret.vcol()
509 }
510
511 pub fn anchor_vcol(&self) -> Option<usize> {
512 self.anchor.map(|a| a.vcol())
513 }
514
515 pub fn desired_vcol(&self) -> usize {
516 self.caret.dcol as usize
517 }
518
519 pub fn desired_anchor_vcol(&self) -> Option<usize> {
520 self.anchor.map(|a| a.dcol as usize)
521 }
522
523 pub fn range(&self, is_inclusive: bool, text: &Text) -> Range<usize> {
536 let anchor = self.anchor.unwrap_or(self.caret);
537 let (start, end) = if anchor < self.caret {
538 (anchor.byte(), self.caret.byte())
539 } else {
540 (self.caret.byte(), anchor.byte())
541 };
542
543 let last = text.last_point();
544 if let Some(last) = last {
545 let go_further = is_inclusive && last.byte() > end;
546 start..if go_further { end + 1 } else { end }
547 } else {
548 0..0
549 }
550 }
551
552 pub fn start(&self) -> Point {
554 if let Some(anchor) = self.anchor {
555 anchor.point.min(self.caret.point)
556 } else {
557 self.caret.point
558 }
559 }
560
561 pub fn point_range(&self, is_incl: bool, text: &Text) -> (Point, Point) {
568 let anchor = self.anchor.unwrap_or(self.caret);
569 let mut end = self.caret.point.max(anchor.point);
570 if is_incl
571 && end.byte() + 1 != text.len().byte()
572 && let Some(char) = text.char_at(end)
573 {
574 end = end.fwd(char)
575 }
576 (self.caret.point.min(anchor.point), end)
577 }
578
579 pub fn set_desired_v_col(&mut self, x: usize) {
585 self.caret.dcol = x as u32;
586 }
587
588 pub fn set_desired_wrapped_v_col(&mut self, x: usize) {
594 self.caret.dwcol = x as u32;
595 }
596
597 pub(super) fn start_v(&self) -> VPoint {
598 match self.anchor {
599 Some(anchor) => self.caret.min(anchor),
600 None => self.caret,
601 }
602 }
603
604 pub(super) fn end_v(&self) -> VPoint {
605 match self.anchor {
606 Some(anchor) => self.caret.max(anchor),
607 None => self.caret,
608 }
609 }
610 }
611
612 impl std::fmt::Display for Cursor {
613 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
614 write!(
615 f,
616 "{}:{}, {}",
617 self.caret.line() + 1,
618 self.caret.vcol() + 1,
619 self.caret.dcol
620 )
621 }
622 }
623
624 #[derive(Default, Clone, Copy, Eq, Debug, Serialize, Deserialize)]
625 pub struct VPoint {
626 point: Point,
627 vcol: u32,
628 dcol: u32,
629 dwcol: u32,
630 }
631
632 impl PartialOrd for VPoint {
633 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
634 Some(self.point.cmp(&other.point))
635 }
636 }
637
638 impl Ord for VPoint {
639 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
640 self.partial_cmp(other).unwrap()
641 }
642 }
643
644 impl PartialEq for VPoint {
645 fn eq(&self, other: &Self) -> bool {
646 self.point == other.point
647 }
648 }
649
650 impl VPoint {
651 fn new(point: Point, text: &Text, area: &impl Area, cfg: PrintCfg) -> Self {
652 let cfg = IterCfg::new(cfg);
653 let dwcol = vcol(point, text, area, cfg);
654 let vcol = vcol(point, text, area, cfg.dont_wrap());
655 Self { point, vcol, dcol: vcol, dwcol }
656 }
657
658 pub fn byte(&self) -> usize {
659 self.point.byte()
660 }
661
662 pub fn char(&self) -> usize {
663 self.point.char()
664 }
665
666 pub fn line(&self) -> usize {
667 self.point.line()
668 }
669
670 pub fn vcol(&self) -> usize {
671 self.vcol as usize
672 }
673 }
674
675 fn vcol(point: Point, text: &Text, area: &impl Area, cfg: IterCfg) -> u32 {
676 if let Some(after) = text.points_after(point) {
677 area.rev_print_iter(text.iter_rev(after), cfg)
678 .find_map(|(caret, item)| item.part.is_char().then_some(caret.x))
679 .unwrap_or(0)
680 } else {
681 area.rev_print_iter(text.iter_rev(text.len()), cfg)
682 .find_map(|(caret, item)| item.part.is_char().then_some(caret.x + caret.len))
683 .unwrap_or(0)
684 }
685 }
686}
687
688fn binary_search_by_key<K>(
690 buf: gapbuf::Range<Cursor>,
691 key: K,
692 f: impl Fn(&Cursor) -> K,
693) -> Result<usize, usize>
694where
695 K: PartialEq + Eq + PartialOrd + Ord,
696{
697 let mut size = buf.len();
698 let mut left = 0;
699 let mut right = size;
700
701 while left < right {
702 let mid = left + size / 2;
703
704 let k = f(&buf[mid]);
705
706 match k.cmp(&key) {
707 std::cmp::Ordering::Less => left = mid + 1,
708 std::cmp::Ordering::Equal => return Ok(mid),
709 std::cmp::Ordering::Greater => right = mid,
710 }
711
712 size = right - left;
713 }
714
715 Err(left)
716}
717
718#[derive(Clone)]
719struct CursorGapBuffer(GapBuffer<Cursor>);
720
721impl std::ops::Deref for CursorGapBuffer {
722 type Target = GapBuffer<Cursor>;
723
724 fn deref(&self) -> &Self::Target {
725 &self.0
726 }
727}
728
729impl std::ops::DerefMut for CursorGapBuffer {
730 fn deref_mut(&mut self) -> &mut Self::Target {
731 &mut self.0
732 }
733}
734
735impl std::fmt::Debug for CursorGapBuffer {
736 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
737 std::fmt::Debug::fmt(&self.0, f)
738 }
739}
740
741impl Serialize for CursorGapBuffer {
742 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
743 where
744 S: serde::Serializer,
745 {
746 let mut ser_gapbuf = serializer.serialize_seq(Some(self.0.len()))?;
747
748 for cursor in self.0.iter() {
749 ser_gapbuf.serialize_element(cursor)?;
750 }
751 ser_gapbuf.end()
752 }
753}
754
755impl<'de> Deserialize<'de> for CursorGapBuffer {
756 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
757 where
758 D: serde::Deserializer<'de>,
759 {
760 struct GapBufferVisitor;
761
762 impl<'v> Visitor<'v> for GapBufferVisitor {
763 type Value = CursorGapBuffer;
764
765 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
766 write!(formatter, "This visitor expected a sequence of Cursors")
767 }
768
769 fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error>
770 where
771 A: serde::de::SeqAccess<'v>,
772 {
773 let mut buf = if let Some(len) = seq.size_hint() {
774 GapBuffer::with_capacity(len)
775 } else {
776 GapBuffer::new()
777 };
778
779 while let Some(cursor) = seq.next_element()? {
780 buf.push_back(cursor);
781 }
782
783 Ok(CursorGapBuffer(buf))
784 }
785 }
786
787 deserializer.deserialize_seq(GapBufferVisitor)
788 }
789}