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 pub affinity: CursorAffinity,
29}
30
31#[derive(Clone, Debug, PartialEq)]
32#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
33pub enum CursorMode {
34 Normal(usize),
35 Visual {
36 start: usize,
37 end: usize,
38 mode: VisualMode,
39 },
40 Insert(Selection),
41}
42
43struct RegionsIter<'c> {
44 cursor_mode: &'c CursorMode,
45 idx: usize,
46}
47
48impl Iterator for RegionsIter<'_> {
49 type Item = (usize, usize);
50
51 fn next(&mut self) -> Option<Self::Item> {
52 match self.cursor_mode {
53 &CursorMode::Normal(offset) => (self.idx == 0).then(|| {
54 self.idx = 1;
55 (offset, offset)
56 }),
57 &CursorMode::Visual { start, end, .. } => (self.idx == 0).then(|| {
58 self.idx = 1;
59 (start, end)
60 }),
61 CursorMode::Insert(selection) => {
62 let next = selection
63 .regions()
64 .get(self.idx)
65 .map(|&SelRegion { start, end, .. }| (start, end));
66
67 if next.is_some() {
68 self.idx += 1;
69 }
70
71 next
72 }
73 }
74 }
75
76 fn size_hint(&self) -> (usize, Option<usize>) {
77 let total_len = match self.cursor_mode {
78 CursorMode::Normal(_) | CursorMode::Visual { .. } => 1,
79 CursorMode::Insert(selection) => selection.len(),
80 };
81 let len = total_len - self.idx;
82
83 (len, Some(len))
84 }
85}
86
87impl ExactSizeIterator for RegionsIter<'_> {}
88
89impl CursorMode {
90 pub fn offset(&self) -> usize {
91 match &self {
92 CursorMode::Normal(offset) => *offset,
93 CursorMode::Visual { end, .. } => *end,
94 CursorMode::Insert(selection) => selection.get_cursor_offset(),
95 }
96 }
97
98 pub fn start_offset(&self) -> usize {
99 match &self {
100 CursorMode::Normal(offset) => *offset,
101 CursorMode::Visual { start, .. } => *start,
102 CursorMode::Insert(selection) => selection.first().map(|s| s.start).unwrap_or(0),
103 }
104 }
105
106 pub fn regions_iter(&self) -> impl ExactSizeIterator<Item = (usize, usize)> + '_ {
107 RegionsIter {
108 cursor_mode: self,
109 idx: 0,
110 }
111 }
112}
113
114#[derive(Debug, Clone, Copy, PartialEq, Eq)]
139#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
140pub enum CursorAffinity {
141 Forward,
143 Backward,
145}
146impl CursorAffinity {
147 pub fn invert(&self) -> Self {
148 match self {
149 CursorAffinity::Forward => CursorAffinity::Backward,
150 CursorAffinity::Backward => CursorAffinity::Forward,
151 }
152 }
153}
154
155impl Cursor {
156 pub fn new(
157 mode: CursorMode,
158 horiz: Option<ColPosition>,
159 motion_mode: Option<MotionMode>,
160 ) -> Self {
161 Self {
162 mode,
163 horiz,
164 motion_mode,
165 history_selections: Vec::new(),
166 affinity: CursorAffinity::Backward,
168 }
169 }
170
171 pub fn origin(modal: bool) -> Self {
172 Self::new(
173 if modal {
174 CursorMode::Normal(0)
175 } else {
176 CursorMode::Insert(Selection::caret(0))
177 },
178 None,
179 None,
180 )
181 }
182
183 pub fn offset(&self) -> usize {
184 self.mode.offset()
185 }
186
187 pub fn start_offset(&self) -> usize {
188 self.mode.start_offset()
189 }
190
191 pub fn regions_iter(&self) -> impl ExactSizeIterator<Item = (usize, usize)> + '_ {
192 self.mode.regions_iter()
193 }
194
195 pub fn is_normal(&self) -> bool {
196 matches!(&self.mode, CursorMode::Normal(_))
197 }
198
199 pub fn is_insert(&self) -> bool {
200 matches!(&self.mode, CursorMode::Insert(_))
201 }
202
203 pub fn is_visual(&self) -> bool {
204 matches!(&self.mode, CursorMode::Visual { .. })
205 }
206
207 pub fn get_mode(&self) -> Mode {
208 match &self.mode {
209 CursorMode::Normal(_) => Mode::Normal,
210 CursorMode::Visual { mode, .. } => Mode::Visual(*mode),
211 CursorMode::Insert(_) => Mode::Insert,
212 }
213 }
214
215 pub fn set_mode(&mut self, mode: CursorMode) {
216 if let CursorMode::Insert(selection) = &self.mode {
217 self.history_selections.push(selection.clone());
218 }
219 self.mode = mode;
220 }
221
222 pub fn set_insert(&mut self, selection: Selection) {
223 self.set_mode(CursorMode::Insert(selection));
224 }
225
226 pub fn update_selection(&mut self, buffer: &Buffer, selection: Selection) {
227 match self.mode {
228 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
229 let offset = selection.min_offset();
230 let offset = buffer.offset_line_end(offset, false).min(offset);
231 self.mode = CursorMode::Normal(offset);
232 }
233 CursorMode::Insert(_) => {
234 self.mode = CursorMode::Insert(selection);
235 }
236 }
237 }
238
239 pub fn edit_selection(&self, text: &impl RopeText) -> Selection {
240 match &self.mode {
241 CursorMode::Insert(selection) => selection.clone(),
242 CursorMode::Normal(offset) => {
243 Selection::region(*offset, text.next_grapheme_offset(*offset, 1, text.len()))
244 }
245 CursorMode::Visual { start, end, mode } => match mode {
246 VisualMode::Normal => Selection::region(
247 *start.min(end),
248 text.next_grapheme_offset(*start.max(end), 1, text.len()),
249 ),
250 VisualMode::Linewise => {
251 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
252 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
253 Selection::region(start_offset, end_offset)
254 }
255 VisualMode::Blockwise => {
256 let mut selection = Selection::new();
257 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
258 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
259 let left = start_col.min(end_col);
260 let right = start_col.max(end_col) + 1;
261 for line in start_line..end_line + 1 {
262 let max_col = text.line_end_col(line, true);
263 if left > max_col {
264 continue;
265 }
266 let right = match &self.horiz {
267 Some(ColPosition::End) => max_col,
268 _ => {
269 if right > max_col {
270 max_col
271 } else {
272 right
273 }
274 }
275 };
276 let left = text.offset_of_line_col(line, left);
277 let right = text.offset_of_line_col(line, right);
278 selection.add_region(SelRegion::new(left, right, None));
279 }
280 selection
281 }
282 },
283 }
284 }
285
286 pub fn apply_delta(&mut self, delta: &RopeDelta) {
287 match &self.mode {
288 CursorMode::Normal(offset) => {
289 let mut transformer = Transformer::new(delta);
290 let new_offset = transformer.transform(*offset, true);
291 self.mode = CursorMode::Normal(new_offset);
292 }
293 CursorMode::Visual { start, end, mode } => {
294 let mut transformer = Transformer::new(delta);
295 let start = transformer.transform(*start, false);
296 let end = transformer.transform(*end, true);
297 self.mode = CursorMode::Visual {
298 start,
299 end,
300 mode: *mode,
301 };
302 }
303 CursorMode::Insert(selection) => {
304 let selection = selection.apply_delta(delta, true, InsertDrift::Default);
305 self.mode = CursorMode::Insert(selection);
306 }
307 }
308 self.horiz = None;
309 }
310
311 pub fn yank(&self, text: &impl RopeText) -> RegisterData {
312 let (content, mode) = match &self.mode {
313 CursorMode::Insert(selection) => {
314 let mut mode = VisualMode::Normal;
315 let mut content = "".to_string();
316 for region in selection.regions() {
317 let region_content = if region.is_caret() {
318 mode = VisualMode::Linewise;
319 let line = text.line_of_offset(region.start);
320 text.line_content(line)
321 } else {
322 text.slice_to_cow(region.min()..region.max())
323 };
324 if content.is_empty() {
325 content = region_content.to_string();
326 } else if content.ends_with('\n') {
327 content += ®ion_content;
328 } else {
329 content += "\n";
330 content += ®ion_content;
331 }
332 }
333 (content, mode)
334 }
335 CursorMode::Normal(offset) => {
336 let new_offset = text.next_grapheme_offset(*offset, 1, text.len());
337 (
338 text.slice_to_cow(*offset..new_offset).to_string(),
339 VisualMode::Normal,
340 )
341 }
342 CursorMode::Visual { start, end, mode } => match mode {
343 VisualMode::Normal => (
344 text.slice_to_cow(
345 *start.min(end)..text.next_grapheme_offset(*start.max(end), 1, text.len()),
346 )
347 .to_string(),
348 VisualMode::Normal,
349 ),
350 VisualMode::Linewise => {
351 let start_offset = text.offset_of_line(text.line_of_offset(*start.min(end)));
352 let end_offset = text.offset_of_line(text.line_of_offset(*start.max(end)) + 1);
353 (
354 text.slice_to_cow(start_offset..end_offset).to_string(),
355 VisualMode::Linewise,
356 )
357 }
358 VisualMode::Blockwise => {
359 let mut lines = Vec::new();
360 let (start_line, start_col) = text.offset_to_line_col(*start.min(end));
361 let (end_line, end_col) = text.offset_to_line_col(*start.max(end));
362 let left = start_col.min(end_col);
363 let right = start_col.max(end_col) + 1;
364 for line in start_line..end_line + 1 {
365 let max_col = text.line_end_col(line, true);
366 if left > max_col {
367 lines.push("".to_string());
368 } else {
369 let right = match &self.horiz {
370 Some(ColPosition::End) => max_col,
371 _ => {
372 if right > max_col {
373 max_col
374 } else {
375 right
376 }
377 }
378 };
379 let left = text.offset_of_line_col(line, left);
380 let right = text.offset_of_line_col(line, right);
381 lines.push(text.slice_to_cow(left..right).to_string());
382 }
383 }
384 (lines.join("\n") + "\n", VisualMode::Blockwise)
385 }
386 },
387 };
388 RegisterData { content, mode }
389 }
390
391 pub fn get_selection(&self) -> Option<(usize, usize)> {
394 match &self.mode {
395 CursorMode::Visual {
396 start,
397 end,
398 mode: _,
399 } => Some((*start, *end)),
400 CursorMode::Insert(selection) => selection
401 .regions()
402 .first()
403 .map(|region| (region.start, region.end)),
404 _ => None,
405 }
406 }
407
408 pub fn get_line_col_char(&self, buffer: &Buffer) -> Option<(usize, usize, usize)> {
409 match &self.mode {
410 CursorMode::Normal(offset) => {
411 let ln_col = buffer.offset_to_line_col(*offset);
412 Some((ln_col.0, ln_col.1, *offset))
413 }
414 CursorMode::Visual {
415 start,
416 end,
417 mode: _,
418 } => {
419 let v = buffer.offset_to_line_col(*start.min(end));
420 Some((v.0, v.1, *start))
421 }
422 CursorMode::Insert(selection) => {
423 if selection.regions().len() > 1 {
424 return None;
425 }
426
427 let x = selection.regions().first().unwrap();
428 let v = buffer.offset_to_line_col(x.start);
429
430 Some((v.0, v.1, x.start))
431 }
432 }
433 }
434
435 pub fn get_selection_count(&self) -> usize {
436 match &self.mode {
437 CursorMode::Insert(selection) => selection.regions().len(),
438 _ => 0,
439 }
440 }
441
442 pub fn set_offset(&mut self, offset: usize, modify: bool, new_cursor: bool) {
443 match &self.mode {
444 CursorMode::Normal(old_offset) => {
445 if modify && *old_offset != offset {
446 self.mode = CursorMode::Visual {
447 start: *old_offset,
448 end: offset,
449 mode: VisualMode::Normal,
450 };
451 } else {
452 self.mode = CursorMode::Normal(offset);
453 }
454 }
455 CursorMode::Visual {
456 start,
457 end: _,
458 mode: _,
459 } => {
460 if modify {
461 self.mode = CursorMode::Visual {
462 start: *start,
463 end: offset,
464 mode: VisualMode::Normal,
465 };
466 } else {
467 self.mode = CursorMode::Normal(offset);
468 }
469 }
470 CursorMode::Insert(selection) => {
471 if new_cursor {
472 let mut new_selection = selection.clone();
473 if modify {
474 if let Some(region) = new_selection.last_inserted_mut() {
475 region.end = offset;
476 } else {
477 new_selection.add_region(SelRegion::caret(offset));
478 }
479 self.set_insert(new_selection);
480 } else {
481 let mut new_selection = selection.clone();
482 new_selection.add_region(SelRegion::caret(offset));
483 self.set_insert(new_selection);
484 }
485 } else if modify {
486 let mut new_selection = Selection::new();
487 if let Some(region) = selection.first() {
488 let new_region = SelRegion::new(region.start, offset, None);
489 new_selection.add_region(new_region);
490 } else {
491 new_selection.add_region(SelRegion::new(offset, offset, None));
492 }
493 self.set_insert(new_selection);
494 } else {
495 self.set_insert(Selection::caret(offset));
496 }
497 }
498 }
499 }
500
501 pub fn add_region(&mut self, start: usize, end: usize, modify: bool, new_cursor: bool) {
502 match &self.mode {
503 CursorMode::Normal(_offset) => {
504 self.mode = CursorMode::Visual {
505 start,
506 end: end - 1,
507 mode: VisualMode::Normal,
508 };
509 }
510 CursorMode::Visual {
511 start: old_start,
512 end: old_end,
513 mode: _,
514 } => {
515 let forward = old_end >= old_start;
516 let new_start = (*old_start).min(*old_end).min(start).min(end - 1);
517 let new_end = (*old_start).max(*old_end).max(start).max(end - 1);
518 let (new_start, new_end) = if forward {
519 (new_start, new_end)
520 } else {
521 (new_end, new_start)
522 };
523 self.mode = CursorMode::Visual {
524 start: new_start,
525 end: new_end,
526 mode: VisualMode::Normal,
527 };
528 }
529 CursorMode::Insert(selection) => {
530 let new_selection = if new_cursor {
531 let mut new_selection = selection.clone();
532 if modify {
533 let new_region = if let Some(last_inserted) = selection.last_inserted() {
534 last_inserted.merge_with(SelRegion::new(start, end, None))
535 } else {
536 SelRegion::new(start, end, None)
537 };
538 new_selection.replace_last_inserted_region(new_region);
539 } else {
540 new_selection.add_region(SelRegion::new(start, end, None));
541 }
542 new_selection
543 } else if modify {
544 let mut new_selection = selection.clone();
545 new_selection.add_region(SelRegion::new(start, end, None));
546 new_selection
547 } else {
548 Selection::region(start, end)
549 };
550 self.mode = CursorMode::Insert(new_selection);
551 }
552 }
553 }
554}
555
556pub fn get_first_selection_after(
557 cursor: &Cursor,
558 buffer: &Buffer,
559 delta: &RopeDelta,
560) -> Option<Cursor> {
561 let mut transformer = Transformer::new(delta);
562
563 let offset = cursor.offset();
564 let offset = transformer.transform(offset, false);
565 let (ins, del) = delta.clone().factor();
566 let ins = ins.transform_shrink(&del);
567 for el in ins.els.iter() {
568 match el {
569 lapce_xi_rope::DeltaElement::Copy(b, e) => {
570 if b == e {
572 return None;
573 }
574 }
575 lapce_xi_rope::DeltaElement::Insert(_) => {}
576 }
577 }
578
579 let mut positions = ins
581 .inserted_subset()
582 .complement_iter()
583 .map(|s| s.1)
584 .collect::<Vec<usize>>();
585 positions.append(
586 &mut del
587 .complement_iter()
588 .map(|s| transformer.transform(s.1, false))
589 .collect::<Vec<usize>>(),
590 );
591 positions.sort_by_key(|p| {
592 let p = *p as i32 - offset as i32;
593 if p > 0 {
594 p as usize
595 } else {
596 -p as usize
597 }
598 });
599
600 positions
601 .first()
602 .cloned()
603 .map(Selection::caret)
604 .map(|selection| {
605 let cursor_mode = match cursor.mode {
606 CursorMode::Normal(_) | CursorMode::Visual { .. } => {
607 let offset = selection.min_offset();
608 let offset = buffer.offset_line_end(offset, false).min(offset);
609 CursorMode::Normal(offset)
610 }
611 CursorMode::Insert(_) => CursorMode::Insert(selection),
612 };
613
614 Cursor::new(cursor_mode, None, None)
615 })
616}