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)]
161#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
162pub enum CursorAffinity {
163 Forward,
165 Backward,
167}
168impl CursorAffinity {
169 pub fn invert(&self) -> Self {
170 match self {
171 CursorAffinity::Forward => CursorAffinity::Backward,
172 CursorAffinity::Backward => CursorAffinity::Forward,
173 }
174 }
175}
176
177impl Cursor {
178 pub fn new(
179 mode: CursorMode,
180 horiz: Option<ColPosition>,
181 motion_mode: Option<MotionMode>,
182 ) -> Self {
183 Self {
184 mode,
185 horiz,
186 motion_mode,
187 history_selections: Vec::new(),
188 }
189 }
190
191 pub fn origin(modal: bool) -> Self {
192 Self::new(
193 if modal {
194 CursorMode::Normal {
195 offset: 0,
196 affinity: CursorAffinity::Backward,
197 }
198 } else {
199 CursorMode::Insert(Selection::caret(0, CursorAffinity::Backward))
200 },
201 None,
202 None,
203 )
204 }
205
206 pub fn offset(&self) -> usize {
207 self.mode.offset()
208 }
209
210 pub fn start_offset(&self) -> usize {
211 self.mode.start_offset()
212 }
213
214 pub fn affinity(&self) -> CursorAffinity {
215 self.mode.affinity()
216 }
217
218 pub fn set_latest_affinity(&mut self, affinity: CursorAffinity) {
219 match &mut self.mode {
220 CursorMode::Normal { affinity: aff, .. } => {
221 *aff = affinity;
222 }
223 CursorMode::Visual { affinity: aff, .. } => {
224 *aff = affinity;
225 }
226 CursorMode::Insert(selection) => {
227 if let Some(region) = selection.last_inserted_mut() {
228 region.affinity = affinity;
229 }
230 }
231 }
232 }
233
234 pub fn regions_iter(
235 &self,
236 ) -> impl ExactSizeIterator<Item = (usize, usize, CursorAffinity)> + '_ {
237 self.mode.regions_iter()
238 }
239
240 pub fn is_normal(&self) -> bool {
241 matches!(&self.mode, CursorMode::Normal { .. })
242 }
243
244 pub fn is_insert(&self) -> bool {
245 matches!(&self.mode, CursorMode::Insert(_))
246 }
247
248 pub fn is_visual(&self) -> bool {
249 matches!(&self.mode, CursorMode::Visual { .. })
250 }
251
252 pub fn get_mode(&self) -> Mode {
253 match &self.mode {
254 CursorMode::Normal { .. } => Mode::Normal,
255 CursorMode::Visual { mode, .. } => Mode::Visual(*mode),
256 CursorMode::Insert(_) => Mode::Insert,
257 }
258 }
259
260 pub fn set_mode(&mut self, mode: CursorMode) {
261 if let CursorMode::Insert(selection) = &self.mode {
262 self.history_selections.push(selection.clone());
263 }
264 self.mode = mode;
265 }
266
267 pub fn set_insert(&mut self, selection: Selection) {
268 self.set_mode(CursorMode::Insert(selection));
269 }
270
271 pub fn update_selection(&mut self, buffer: &Buffer, selection: Selection) {
272 match self.mode {
273 CursorMode::Normal { .. } | CursorMode::Visual { .. } => {
274 let offset = selection.min_offset();
275 let offset = buffer.offset_line_end(offset, false).min(offset);
276 self.mode = CursorMode::Normal {
277 offset,
278 affinity: CursorAffinity::Forward,
279 };
280 }
281 CursorMode::Insert(_) => {
282 self.mode = CursorMode::Insert(selection);
283 }
284 }
285 }
286
287 pub fn edit_selection(&self, text: &impl RopeText) -> Selection {
288 match &self.mode {
289 CursorMode::Insert(selection) => selection.clone(),
290 CursorMode::Normal { offset, .. } => Selection::region(
291 *offset,
292 text.next_grapheme_offset(*offset, 1, text.len()),
293 CursorAffinity::Backward,
294 ),
295 CursorMode::Visual {
296 start, end, mode, ..
297 } => match mode {
298 VisualMode::Normal => Selection::region(
299 *start.min(end),
300 text.next_grapheme_offset(*start.max(end), 1, text.len()),
301 CursorAffinity::Backward,
302 ),
303 VisualMode::Linewise => {
304 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
305 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
306 Selection::region(start_offset, end_offset, CursorAffinity::Backward)
307 }
308 VisualMode::Blockwise => {
309 let mut selection = Selection::new();
310 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
311 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
312 let left = start_col.min(end_col);
313 let right = start_col.max(end_col) + 1;
314 for line in start_line..end_line + 1 {
315 let max_col = text.line_end_col(line, true);
316 if left > max_col {
317 continue;
318 }
319 let right = match &self.horiz {
320 Some(ColPosition::End) => max_col,
321 _ => {
322 if right > max_col {
323 max_col
324 } else {
325 right
326 }
327 }
328 };
329 let left = text.offset_of_line_col(line, left);
330 let right = text.offset_of_line_col(line, right);
331 selection.add_region(SelRegion::new(
332 left,
333 right,
334 CursorAffinity::Backward,
335 None,
336 ));
337 }
338 selection
339 }
340 },
341 }
342 }
343
344 pub fn apply_delta(&mut self, delta: &RopeDelta) {
345 match &self.mode {
346 CursorMode::Normal { offset, affinity } => {
347 let mut transformer = Transformer::new(delta);
348 let new_offset = transformer.transform(*offset, true);
349 self.mode = CursorMode::Normal {
350 offset: new_offset,
351 affinity: *affinity,
352 };
353 }
354 CursorMode::Visual {
355 start,
356 end,
357 mode,
358 affinity,
359 } => {
360 let mut transformer = Transformer::new(delta);
361 let start = transformer.transform(*start, false);
362 let end = transformer.transform(*end, true);
363 self.mode = CursorMode::Visual {
364 start,
365 end,
366 mode: *mode,
367 affinity: *affinity,
368 };
369 }
370 CursorMode::Insert(selection) => {
371 let selection = selection.apply_delta(delta, true, InsertDrift::Default);
372 self.mode = CursorMode::Insert(selection);
373 }
374 }
375 self.horiz = None;
376 }
377
378 pub fn yank(&self, text: &impl RopeText) -> RegisterData {
379 let (content, mode) = match &self.mode {
380 CursorMode::Insert(selection) => {
381 let mut mode = VisualMode::Normal;
382 let mut content = "".to_string();
383 for region in selection.regions() {
384 let region_content = if region.is_caret() {
385 mode = VisualMode::Linewise;
386 let line = text.line_of_offset(region.start);
387 text.line_content(line)
388 } else {
389 text.slice_to_cow(region.min()..region.max())
390 };
391 if content.is_empty() {
392 content = region_content.to_string();
393 } else if content.ends_with('\n') {
394 content += ®ion_content;
395 } else {
396 content += "\n";
397 content += ®ion_content;
398 }
399 }
400 (content, mode)
401 }
402 CursorMode::Normal { offset, .. } => {
403 let new_offset = text.next_grapheme_offset(*offset, 1, text.len());
404 (
405 text.slice_to_cow(*offset..new_offset).to_string(),
406 VisualMode::Normal,
407 )
408 }
409 CursorMode::Visual {
410 start, end, mode, ..
411 } => match mode {
412 VisualMode::Normal => (
413 text.slice_to_cow(
414 *start.min(end)..text.next_grapheme_offset(*start.max(end), 1, text.len()),
415 )
416 .to_string(),
417 VisualMode::Normal,
418 ),
419 VisualMode::Linewise => {
420 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
421 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
422 (
423 text.slice_to_cow(start_offset..end_offset).to_string(),
424 VisualMode::Linewise,
425 )
426 }
427 VisualMode::Blockwise => {
428 let mut lines = Vec::new();
429 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
430 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
431 let left = start_col.min(end_col);
432 let right = start_col.max(end_col) + 1;
433 for line in start_line..end_line + 1 {
434 let max_col = text.line_end_col(line, true);
435 if left > max_col {
436 lines.push("".to_string());
437 } else {
438 let right = match &self.horiz {
439 Some(ColPosition::End) => max_col,
440 _ => {
441 if right > max_col {
442 max_col
443 } else {
444 right
445 }
446 }
447 };
448 let left = text.offset_of_line_col(line, left);
449 let right = text.offset_of_line_col(line, right);
450 lines.push(text.slice_to_cow(left..right).to_string());
451 }
452 }
453 (lines.join("\n") + "\n", VisualMode::Blockwise)
454 }
455 },
456 };
457 RegisterData { content, mode }
458 }
459
460 pub fn get_selection(&self) -> Option<(usize, usize)> {
463 match &self.mode {
464 CursorMode::Visual { start, end, .. } => Some((*start, *end)),
465 CursorMode::Insert(selection) => selection
466 .regions()
467 .first()
468 .map(|region| (region.start, region.end)),
469 _ => None,
470 }
471 }
472
473 pub fn get_line_col_char(&self, buffer: &Buffer) -> Option<(usize, usize, usize)> {
474 match &self.mode {
475 CursorMode::Normal { offset, .. } => {
476 let ln_col = buffer.offset_to_line_col(*offset);
477 Some((ln_col.0, ln_col.1, *offset))
478 }
479 CursorMode::Visual { start, end, .. } => {
480 let v = buffer.offset_to_line_col(*start.min(end));
481 Some((v.0, v.1, *start))
482 }
483 CursorMode::Insert(selection) => {
484 if selection.regions().len() > 1 {
485 return None;
486 }
487
488 let x = selection.regions().first().unwrap();
489 let v = buffer.offset_to_line_col(x.start);
490
491 Some((v.0, v.1, x.start))
492 }
493 }
494 }
495
496 pub fn get_selection_count(&self) -> usize {
497 match &self.mode {
498 CursorMode::Insert(selection) => selection.regions().len(),
499 _ => 0,
500 }
501 }
502
503 pub fn set_offset(
504 &mut self,
505 offset: usize,
506 affinity: CursorAffinity,
507 modify: bool,
508 new_cursor: bool,
509 ) {
510 match &self.mode {
511 CursorMode::Normal {
512 offset: old_offset, ..
513 } => {
514 if modify && *old_offset != offset {
515 self.mode = CursorMode::Visual {
516 start: *old_offset,
517 end: offset,
518 mode: VisualMode::Normal,
519 affinity,
520 };
521 } else {
522 self.mode = CursorMode::Normal { offset, affinity };
523 }
524 }
525 CursorMode::Visual { start, .. } => {
526 if modify {
527 self.mode = CursorMode::Visual {
528 start: *start,
529 end: offset,
530 mode: VisualMode::Normal,
531 affinity,
532 };
533 } else {
534 self.mode = CursorMode::Normal { offset, affinity };
535 }
536 }
537 CursorMode::Insert(selection) => {
538 if new_cursor {
539 let mut new_selection = selection.clone();
540 if modify {
541 if let Some(mut region) = new_selection.last_inserted().cloned() {
542 region.end = offset;
543 region.affinity = affinity;
544
545 new_selection.delete_range(region.min(), region.max());
547
548 let left = region.min().saturating_sub(1);
550 let right = region.max() + 1;
551 let neighbors = new_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 new_selection.delete_range(left, left + 2);
557 }
558
559 if region.is_caret() || right_has_caret {
560 new_selection.delete_range(left + 1, right);
561 }
562
563 new_selection.add_region(region);
564 } else {
565 new_selection.add_region(SelRegion::caret(offset, affinity));
566 }
567 self.set_insert(new_selection);
568 } else {
569 let mut new_selection = selection.clone();
570 new_selection.add_region(SelRegion::caret(offset, affinity));
571 self.set_insert(new_selection);
572 }
573 } else if modify {
574 let mut new_selection = Selection::new();
575 if let Some(region) = selection.first() {
576 let new_region = SelRegion::new(region.start, offset, affinity, None);
577 new_selection.add_region(new_region);
578 } else {
579 new_selection.add_region(SelRegion::new(offset, offset, affinity, None));
580 }
581 self.set_insert(new_selection);
582 } else {
583 self.set_insert(Selection::caret(offset, affinity));
584 }
585 }
586 }
587 }
588
589 pub fn add_region(
590 &mut self,
591 start: usize,
592 end: usize,
593 affinity: CursorAffinity,
594 modify: bool,
595 new_cursor: bool,
596 ) {
597 match &self.mode {
598 CursorMode::Normal { .. } => {
599 self.mode = CursorMode::Visual {
600 start,
601 end: end - 1,
602 mode: VisualMode::Normal,
603 affinity,
604 };
605 }
606 CursorMode::Visual {
607 start: old_start,
608 end: old_end,
609 ..
610 } => {
611 let forward = old_end >= old_start;
612 let new_start = (*old_start).min(*old_end).min(start).min(end - 1);
613 let new_end = (*old_start).max(*old_end).max(start).max(end - 1);
614 let (new_start, new_end) = if forward {
615 (new_start, new_end)
616 } else {
617 (new_end, new_start)
618 };
619 self.mode = CursorMode::Visual {
620 start: new_start,
621 end: new_end,
622 mode: VisualMode::Normal,
623 affinity,
624 };
625 }
626 CursorMode::Insert(selection) => {
627 let new_selection = if new_cursor {
628 let mut new_selection = selection.clone();
629 if modify {
630 let new_region = if let Some(last_inserted) = selection.last_inserted() {
631 last_inserted.merge_with(SelRegion::new(start, end, affinity, None))
632 } else {
633 SelRegion::new(start, end, affinity, None)
634 };
635 new_selection.replace_last_inserted_region(new_region);
636 } else {
637 new_selection.add_region(SelRegion::new(start, end, affinity, None));
638 }
639 new_selection
640 } else if modify {
641 let mut new_selection = selection.clone();
642 new_selection.add_region(SelRegion::new(start, end, affinity, None));
643 new_selection
644 } else {
645 Selection::region(start, end, affinity)
646 };
647 self.mode = CursorMode::Insert(new_selection);
648 }
649 }
650 }
651}
652
653pub fn get_first_selection_after(
654 cursor: &Cursor,
655 buffer: &Buffer,
656 delta: &RopeDelta,
657) -> Option<Cursor> {
658 let mut transformer = Transformer::new(delta);
659
660 let offset = cursor.offset();
661 let offset = transformer.transform(offset, false);
662 let (ins, del) = delta.clone().factor();
663 let ins = ins.transform_shrink(&del);
664 for el in ins.els.iter() {
665 match el {
666 lapce_xi_rope::DeltaElement::Copy(b, e) => {
667 if b == e {
669 return None;
670 }
671 }
672 lapce_xi_rope::DeltaElement::Insert(_) => {}
673 }
674 }
675
676 let mut positions = ins
678 .inserted_subset()
679 .complement_iter()
680 .map(|s| s.1)
681 .collect::<Vec<usize>>();
682 positions.append(
683 &mut del
684 .complement_iter()
685 .map(|s| transformer.transform(s.1, false))
686 .collect::<Vec<usize>>(),
687 );
688 positions.sort_by_key(|p| {
689 let p = *p as i32 - offset as i32;
690 if p > 0 {
691 p as usize
692 } else {
693 -p as usize
694 }
695 });
696
697 positions
698 .first()
699 .cloned()
700 .map(|offset| Selection::caret(offset, CursorAffinity::Forward))
701 .map(|selection| {
702 let cursor_mode = match cursor.mode {
703 CursorMode::Normal { .. } | CursorMode::Visual { .. } => {
704 let offset = selection.min_offset();
705 let offset = buffer.offset_line_end(offset, false).min(offset);
706 CursorMode::Normal {
707 offset,
708 affinity: CursorAffinity::Backward,
709 }
710 }
711 CursorMode::Insert(_) => CursorMode::Insert(selection),
712 };
713
714 Cursor::new(cursor_mode, None, None)
715 })
716}