1use lapce_xi_rope::{RopeDelta, Transformer};
2#[cfg(feature = "serde")]
3use serde::{Deserialize, Serialize};
4
5use crate::{
6 buffer::{rope_text::RopeText, Buffer},
7 mode::{Mode, MotionMode, VisualMode},
8 register::RegisterData,
9 selection::{InsertDrift, SelRegion, Selection},
10};
11
12#[derive(Clone, Copy, PartialEq, Debug)]
13#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
14pub enum ColPosition {
15 FirstNonBlank,
16 Start,
17 End,
18 Col(f64),
19}
20
21#[derive(Clone, Debug, PartialEq)]
22#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
23pub struct Cursor {
24 pub mode: CursorMode,
25 pub horiz: Option<ColPosition>,
26 pub motion_mode: Option<MotionMode>,
27 pub history_selections: Vec<Selection>,
28}
29
30#[derive(Clone, Debug, PartialEq)]
31#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
32pub enum CursorMode {
33 Normal {
34 offset: usize,
35 affinity: CursorAffinity,
36 },
37 Visual {
38 start: usize,
39 end: usize,
40 mode: VisualMode,
41 affinity: CursorAffinity,
42 },
43 Insert(Selection),
44}
45
46struct RegionsIter<'c> {
47 cursor_mode: &'c CursorMode,
48 idx: usize,
49}
50
51impl Iterator for RegionsIter<'_> {
52 type Item = (usize, usize, CursorAffinity);
53
54 fn next(&mut self) -> Option<Self::Item> {
55 match self.cursor_mode {
56 &CursorMode::Normal { offset, affinity } => (self.idx == 0).then(|| {
57 self.idx = 1;
58 (offset, offset, affinity)
59 }),
60 &CursorMode::Visual {
61 start,
62 end,
63 affinity,
64 ..
65 } => (self.idx == 0).then(|| {
66 self.idx = 1;
67 (start, end, affinity)
68 }),
69 CursorMode::Insert(selection) => {
70 let next = selection.regions().get(self.idx).map(
71 |&SelRegion {
72 start,
73 end,
74 affinity,
75 ..
76 }| (start, end, affinity),
77 );
78
79 if next.is_some() {
80 self.idx += 1;
81 }
82
83 next
84 }
85 }
86 }
87
88 fn size_hint(&self) -> (usize, Option<usize>) {
89 let total_len = match self.cursor_mode {
90 CursorMode::Normal { .. } | CursorMode::Visual { .. } => 1,
91 CursorMode::Insert(selection) => selection.len(),
92 };
93 let len = total_len - self.idx;
94
95 (len, Some(len))
96 }
97}
98
99impl ExactSizeIterator for RegionsIter<'_> {}
100
101impl CursorMode {
102 pub fn offset(&self) -> usize {
103 match &self {
104 CursorMode::Normal { offset, .. } => *offset,
105 CursorMode::Visual { end, .. } => *end,
106 CursorMode::Insert(selection) => selection.get_cursor_offset(),
107 }
108 }
109
110 pub fn start_offset(&self) -> usize {
111 match &self {
112 CursorMode::Normal { offset, .. } => *offset,
113 CursorMode::Visual { start, .. } => *start,
114 CursorMode::Insert(selection) => selection.first().map(|s| s.start).unwrap_or(0),
115 }
116 }
117
118 pub fn affinity(&self) -> CursorAffinity {
119 match &self {
120 CursorMode::Normal { affinity, .. } => *affinity,
121 CursorMode::Visual { affinity, .. } => *affinity,
122 CursorMode::Insert(selection) => selection.get_cursor_affinity(),
123 }
124 }
125
126 pub fn regions_iter(
127 &self,
128 ) -> impl ExactSizeIterator<Item = (usize, usize, CursorAffinity)> + '_ {
129 RegionsIter {
130 cursor_mode: self,
131 idx: 0,
132 }
133 }
134}
135
136#[derive(Debug, Clone, Copy, PartialEq, Eq)]
167#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
168pub enum CursorAffinity {
169 Forward,
171 Backward,
173}
174impl CursorAffinity {
175 pub fn invert(&self) -> Self {
176 match self {
177 CursorAffinity::Forward => CursorAffinity::Backward,
178 CursorAffinity::Backward => CursorAffinity::Forward,
179 }
180 }
181}
182
183impl Cursor {
184 pub fn new(
185 mode: CursorMode,
186 horiz: Option<ColPosition>,
187 motion_mode: Option<MotionMode>,
188 ) -> Self {
189 Self {
190 mode,
191 horiz,
192 motion_mode,
193 history_selections: Vec::new(),
194 }
195 }
196
197 pub fn origin(modal: bool) -> Self {
198 Self::new(
199 if modal {
200 CursorMode::Normal {
201 offset: 0,
202 affinity: CursorAffinity::Backward,
203 }
204 } else {
205 CursorMode::Insert(Selection::caret(0, CursorAffinity::Backward))
206 },
207 None,
208 None,
209 )
210 }
211
212 pub fn offset(&self) -> usize {
213 self.mode.offset()
214 }
215
216 pub fn start_offset(&self) -> usize {
217 self.mode.start_offset()
218 }
219
220 pub fn affinity(&self) -> CursorAffinity {
221 self.mode.affinity()
222 }
223
224 pub fn set_latest_affinity(&mut self, affinity: CursorAffinity) {
225 match &mut self.mode {
226 CursorMode::Normal { affinity: aff, .. } => {
227 *aff = affinity;
228 }
229 CursorMode::Visual { affinity: aff, .. } => {
230 *aff = affinity;
231 }
232 CursorMode::Insert(selection) => {
233 if let Some(region) = selection.last_inserted_mut() {
234 region.affinity = affinity;
235 }
236 }
237 }
238 }
239
240 pub fn regions_iter(
241 &self,
242 ) -> impl ExactSizeIterator<Item = (usize, usize, CursorAffinity)> + '_ {
243 self.mode.regions_iter()
244 }
245
246 pub fn is_normal(&self) -> bool {
247 matches!(&self.mode, CursorMode::Normal { .. })
248 }
249
250 pub fn is_insert(&self) -> bool {
251 matches!(&self.mode, CursorMode::Insert(_))
252 }
253
254 pub fn is_visual(&self) -> bool {
255 matches!(&self.mode, CursorMode::Visual { .. })
256 }
257
258 pub fn get_mode(&self) -> Mode {
259 match &self.mode {
260 CursorMode::Normal { .. } => Mode::Normal,
261 CursorMode::Visual { mode, .. } => Mode::Visual(*mode),
262 CursorMode::Insert(_) => Mode::Insert,
263 }
264 }
265
266 pub fn set_mode(&mut self, mode: CursorMode) {
267 if let CursorMode::Insert(selection) = &self.mode {
268 self.history_selections.push(selection.clone());
269 }
270 self.mode = mode;
271 }
272
273 pub fn set_insert(&mut self, selection: Selection) {
274 self.set_mode(CursorMode::Insert(selection));
275 }
276
277 pub fn update_selection(&mut self, buffer: &Buffer, selection: Selection) {
278 match self.mode {
279 CursorMode::Normal { .. } | CursorMode::Visual { .. } => {
280 let offset = selection.min_offset();
281 let offset = buffer.offset_line_end(offset, false).min(offset);
282 self.mode = CursorMode::Normal {
283 offset,
284 affinity: CursorAffinity::Forward,
285 };
286 }
287 CursorMode::Insert(_) => {
288 self.mode = CursorMode::Insert(selection);
289 }
290 }
291 }
292
293 pub fn edit_selection(&self, text: &impl RopeText) -> Selection {
294 match &self.mode {
295 CursorMode::Insert(selection) => selection.clone(),
296 CursorMode::Normal { offset, .. } => Selection::region(
297 *offset,
298 text.next_grapheme_offset(*offset, 1, text.len()),
299 CursorAffinity::Backward,
300 ),
301 CursorMode::Visual {
302 start, end, mode, ..
303 } => match mode {
304 VisualMode::Normal => Selection::region(
305 *start.min(end),
306 text.next_grapheme_offset(*start.max(end), 1, text.len()),
307 CursorAffinity::Backward,
308 ),
309 VisualMode::Linewise => {
310 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
311 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
312 Selection::region(start_offset, end_offset, CursorAffinity::Backward)
313 }
314 VisualMode::Blockwise => {
315 let mut selection = Selection::new();
316 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
317 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
318 let left = start_col.min(end_col);
319 let right = start_col.max(end_col) + 1;
320 for line in start_line..end_line + 1 {
321 let max_col = text.line_end_col(line, true);
322 if left > max_col {
323 continue;
324 }
325 let right = match &self.horiz {
326 Some(ColPosition::End) => max_col,
327 _ => {
328 if right > max_col {
329 max_col
330 } else {
331 right
332 }
333 }
334 };
335 let left = text.offset_of_line_col(line, left);
336 let right = text.offset_of_line_col(line, right);
337 selection.add_region(SelRegion::new(
338 left,
339 right,
340 CursorAffinity::Backward,
341 None,
342 ));
343 }
344 selection
345 }
346 },
347 }
348 }
349
350 pub fn apply_delta(&mut self, delta: &RopeDelta) {
351 match &self.mode {
352 CursorMode::Normal { offset, affinity } => {
353 let mut transformer = Transformer::new(delta);
354 let new_offset = transformer.transform(*offset, true);
355 self.mode = CursorMode::Normal {
356 offset: new_offset,
357 affinity: *affinity,
358 };
359 }
360 CursorMode::Visual {
361 start,
362 end,
363 mode,
364 affinity,
365 } => {
366 let mut transformer = Transformer::new(delta);
367 let start = transformer.transform(*start, false);
368 let end = transformer.transform(*end, true);
369 self.mode = CursorMode::Visual {
370 start,
371 end,
372 mode: *mode,
373 affinity: *affinity,
374 };
375 }
376 CursorMode::Insert(selection) => {
377 let selection = selection.apply_delta(delta, true, InsertDrift::Default);
378 self.mode = CursorMode::Insert(selection);
379 }
380 }
381 self.horiz = None;
382 }
383
384 pub fn yank(&self, text: &impl RopeText) -> RegisterData {
385 let (content, mode) = match &self.mode {
386 CursorMode::Insert(selection) => {
387 let mut mode = VisualMode::Normal;
388 let mut content = "".to_string();
389 for region in selection.regions() {
390 let region_content = if region.is_caret() {
391 mode = VisualMode::Linewise;
392 let line = text.line_of_offset(region.start);
393 text.line_content(line)
394 } else {
395 text.slice_to_cow(region.min()..region.max())
396 };
397 if content.is_empty() {
398 content = region_content.to_string();
399 } else if content.ends_with('\n') {
400 content += ®ion_content;
401 } else {
402 content += "\n";
403 content += ®ion_content;
404 }
405 }
406 (content, mode)
407 }
408 CursorMode::Normal { offset, .. } => {
409 let new_offset = text.next_grapheme_offset(*offset, 1, text.len());
410 (
411 text.slice_to_cow(*offset..new_offset).to_string(),
412 VisualMode::Normal,
413 )
414 }
415 CursorMode::Visual {
416 start, end, mode, ..
417 } => match mode {
418 VisualMode::Normal => (
419 text.slice_to_cow(
420 *start.min(end)..text.next_grapheme_offset(*start.max(end), 1, text.len()),
421 )
422 .to_string(),
423 VisualMode::Normal,
424 ),
425 VisualMode::Linewise => {
426 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
427 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
428 (
429 text.slice_to_cow(start_offset..end_offset).to_string(),
430 VisualMode::Linewise,
431 )
432 }
433 VisualMode::Blockwise => {
434 let mut lines = Vec::new();
435 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
436 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
437 let left = start_col.min(end_col);
438 let right = start_col.max(end_col) + 1;
439 for line in start_line..end_line + 1 {
440 let max_col = text.line_end_col(line, true);
441 if left > max_col {
442 lines.push("".to_string());
443 } else {
444 let right = match &self.horiz {
445 Some(ColPosition::End) => max_col,
446 _ => {
447 if right > max_col {
448 max_col
449 } else {
450 right
451 }
452 }
453 };
454 let left = text.offset_of_line_col(line, left);
455 let right = text.offset_of_line_col(line, right);
456 lines.push(text.slice_to_cow(left..right).to_string());
457 }
458 }
459 (lines.join("\n") + "\n", VisualMode::Blockwise)
460 }
461 },
462 };
463 RegisterData { content, mode }
464 }
465
466 pub fn get_selection(&self) -> Option<(usize, usize)> {
469 match &self.mode {
470 CursorMode::Visual { start, end, .. } => Some((*start, *end)),
471 CursorMode::Insert(selection) => selection
472 .regions()
473 .first()
474 .map(|region| (region.start, region.end)),
475 _ => None,
476 }
477 }
478
479 pub fn get_line_col_char(&self, buffer: &Buffer) -> Option<(usize, usize, usize)> {
480 match &self.mode {
481 CursorMode::Normal { offset, .. } => {
482 let ln_col = buffer.offset_to_line_col(*offset);
483 Some((ln_col.0, ln_col.1, *offset))
484 }
485 CursorMode::Visual { start, end, .. } => {
486 let v = buffer.offset_to_line_col(*start.min(end));
487 Some((v.0, v.1, *start))
488 }
489 CursorMode::Insert(selection) => {
490 if selection.regions().len() > 1 {
491 return None;
492 }
493
494 let x = selection.regions().first().unwrap();
495 let v = buffer.offset_to_line_col(x.start);
496
497 Some((v.0, v.1, x.start))
498 }
499 }
500 }
501
502 pub fn get_selection_count(&self) -> usize {
503 match &self.mode {
504 CursorMode::Insert(selection) => selection.regions().len(),
505 _ => 0,
506 }
507 }
508
509 pub fn set_offset(
510 &mut self,
511 offset: usize,
512 affinity: CursorAffinity,
513 modify: bool,
514 new_cursor: bool,
515 ) {
516 match &self.mode {
517 CursorMode::Normal {
518 offset: old_offset, ..
519 } => {
520 if modify && *old_offset != offset {
521 self.mode = CursorMode::Visual {
522 start: *old_offset,
523 end: offset,
524 mode: VisualMode::Normal,
525 affinity,
526 };
527 } else {
528 self.mode = CursorMode::Normal { offset, affinity };
529 }
530 }
531 CursorMode::Visual { start, .. } => {
532 if modify {
533 self.mode = CursorMode::Visual {
534 start: *start,
535 end: offset,
536 mode: VisualMode::Normal,
537 affinity,
538 };
539 } else {
540 self.mode = CursorMode::Normal { offset, affinity };
541 }
542 }
543 CursorMode::Insert(selection) => {
544 if new_cursor {
545 let mut new_selection = selection.clone();
546
547 let delete_overlapping_carets =
548 |selection: &mut Selection, region: &SelRegion| {
549 let left = region.min().saturating_sub(1);
550 let right = region.max() + 1;
551 let neighbors = selection.regions_in_range(left, right);
552 let left_has_caret = neighbors.first().is_some_and(|r| r.is_caret());
553 let right_has_caret = neighbors.last().is_some_and(|r| r.is_caret());
554
555 if region.is_caret() || left_has_caret {
556 selection.delete_range(left, left + 2);
557 }
558
559 if region.is_caret() || right_has_caret {
560 selection.delete_range(left + 1, right);
561 }
562 };
563
564 if let (Some(mut region), true) =
565 (new_selection.last_inserted().cloned(), modify)
566 {
567 region.end = offset;
568 region.affinity = affinity;
569
570 new_selection.delete_range(region.min(), region.max());
572
573 delete_overlapping_carets(&mut new_selection, ®ion);
575
576 new_selection.add_region(region);
577 } else {
578 let region = SelRegion::caret(offset, affinity);
580
581 delete_overlapping_carets(&mut new_selection, ®ion);
582
583 let prev_len = selection.regions().len();
585 let new_len = new_selection.regions().len();
586
587 if new_len == prev_len || new_len == 0 {
588 new_selection.add_region(region);
589 }
590 }
591
592 self.set_insert(new_selection);
593 } else if modify {
594 let mut new_selection = Selection::new();
595 if let Some(region) = selection.first() {
596 let new_region = SelRegion::new(region.start, offset, affinity, None);
597 new_selection.add_region(new_region);
598 } else {
599 new_selection.add_region(SelRegion::new(offset, offset, affinity, None));
600 }
601 self.set_insert(new_selection);
602 } else {
603 self.set_insert(Selection::caret(offset, affinity));
604 }
605 }
606 }
607 }
608
609 pub fn add_region(
610 &mut self,
611 start: usize,
612 end: usize,
613 affinity: CursorAffinity,
614 modify: bool,
615 new_cursor: bool,
616 ) {
617 match &self.mode {
618 CursorMode::Normal { .. } => {
619 self.mode = CursorMode::Visual {
620 start,
621 end: end - 1,
622 mode: VisualMode::Normal,
623 affinity,
624 };
625 }
626 CursorMode::Visual {
627 start: old_start,
628 end: old_end,
629 ..
630 } => {
631 let forward = old_end >= old_start;
632 let new_start = (*old_start).min(*old_end).min(start).min(end - 1);
633 let new_end = (*old_start).max(*old_end).max(start).max(end - 1);
634 let (new_start, new_end) = if forward {
635 (new_start, new_end)
636 } else {
637 (new_end, new_start)
638 };
639 self.mode = CursorMode::Visual {
640 start: new_start,
641 end: new_end,
642 mode: VisualMode::Normal,
643 affinity,
644 };
645 }
646 CursorMode::Insert(selection) => {
647 let new_selection = if new_cursor {
648 let mut new_selection = selection.clone();
649 if modify {
650 let new_region = if let Some(last_inserted) = selection.last_inserted() {
651 last_inserted.merge_with(SelRegion::new(start, end, affinity, None))
652 } else {
653 SelRegion::new(start, end, affinity, None)
654 };
655 new_selection.replace_last_inserted_region(new_region);
656 } else {
657 new_selection.add_region(SelRegion::new(start, end, affinity, None));
658 }
659 new_selection
660 } else if modify {
661 let mut new_selection = selection.clone();
662 new_selection.add_region(SelRegion::new(start, end, affinity, None));
663 new_selection
664 } else {
665 Selection::region(start, end, affinity)
666 };
667 self.mode = CursorMode::Insert(new_selection);
668 }
669 }
670 }
671}
672
673pub fn get_first_selection_after(
674 cursor: &Cursor,
675 buffer: &Buffer,
676 delta: &RopeDelta,
677) -> Option<Cursor> {
678 let mut transformer = Transformer::new(delta);
679
680 let offset = cursor.offset();
681 let offset = transformer.transform(offset, false);
682 let (ins, del) = delta.clone().factor();
683 let ins = ins.transform_shrink(&del);
684 for el in ins.els.iter() {
685 match el {
686 lapce_xi_rope::DeltaElement::Copy(b, e) => {
687 if b == e {
689 return None;
690 }
691 }
692 lapce_xi_rope::DeltaElement::Insert(_) => {}
693 }
694 }
695
696 let mut positions = ins
698 .inserted_subset()
699 .complement_iter()
700 .map(|s| s.1)
701 .collect::<Vec<usize>>();
702 positions.append(
703 &mut del
704 .complement_iter()
705 .map(|s| transformer.transform(s.1, false))
706 .collect::<Vec<usize>>(),
707 );
708 positions.sort_by_key(|p| {
709 let p = *p as i32 - offset as i32;
710 if p > 0 {
711 p as usize
712 } else {
713 -p as usize
714 }
715 });
716
717 positions
718 .first()
719 .cloned()
720 .map(|offset| Selection::caret(offset, CursorAffinity::Forward))
721 .map(|selection| {
722 let cursor_mode = match cursor.mode {
723 CursorMode::Normal { .. } | CursorMode::Visual { .. } => {
724 let offset = selection.min_offset();
725 let offset = buffer.offset_line_end(offset, false).min(offset);
726 CursorMode::Normal {
727 offset,
728 affinity: CursorAffinity::Backward,
729 }
730 }
731 CursorMode::Insert(_) => CursorMode::Insert(selection),
732 };
733
734 Cursor::new(cursor_mode, None, None)
735 })
736}