1use std::ops::Range;
2
3use ropey::{LineType, Rope, RopeSlice};
4use sum_tree::Bias;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8pub struct Point {
9 pub row: usize,
10 pub column: usize,
11}
12
13impl Point {
14 pub fn new(row: usize, column: usize) -> Self {
15 Self { row, column }
16 }
17}
18
19#[derive(Debug, Clone, Copy)]
21pub struct InputEdit {
22 pub start_byte: usize,
23 pub old_end_byte: usize,
24 pub new_end_byte: usize,
25 pub start_position: Point,
26 pub old_end_position: Point,
27 pub new_end_position: Point,
28}
29
30use lsp_types::Position;
31
32pub struct RopeLines<'a> {
34 rope: &'a Rope,
35 row: usize,
36 end_row: usize,
37}
38
39impl<'a> RopeLines<'a> {
40 pub fn new(rope: &'a Rope) -> Self {
42 let end_row = rope.lines_len();
43 Self {
44 row: 0,
45 end_row,
46 rope,
47 }
48 }
49}
50impl<'a> Iterator for RopeLines<'a> {
51 type Item = RopeSlice<'a>;
52
53 #[inline]
54 fn next(&mut self) -> Option<Self::Item> {
55 if self.row >= self.end_row {
56 return None;
57 }
58
59 let line = self.rope.slice_line(self.row);
60 self.row += 1;
61 Some(line)
62 }
63
64 #[inline]
65 fn nth(&mut self, n: usize) -> Option<Self::Item> {
66 self.row = self.row.saturating_add(n);
67 self.next()
68 }
69
70 #[inline]
71 fn size_hint(&self) -> (usize, Option<usize>) {
72 let len = self.end_row - self.row;
73 (len, Some(len))
74 }
75}
76
77impl std::iter::ExactSizeIterator for RopeLines<'_> {}
78impl std::iter::FusedIterator for RopeLines<'_> {}
79
80pub trait RopeExt {
82 fn line_start_offset(&self, row: usize) -> usize;
94
95 fn line_end_offset(&self, row: usize) -> usize;
106
107 fn slice_line(&self, row: usize) -> RopeSlice<'_>;
118
119 fn slice_lines(&self, rows_range: Range<usize>) -> RopeSlice<'_>;
133
134 fn iter_lines(&self) -> RopeLines<'_>;
145
146 fn lines_len(&self) -> usize;
154
155 fn line_len(&self, row: usize) -> usize;
168
169 fn replace(&mut self, range: Range<usize>, new_text: &str);
183
184 fn char_at(&self, offset: usize) -> Option<char>;
189
190 fn position_to_offset(&self, line_col: &Position) -> usize;
194
195 fn offset_to_position(&self, offset: usize) -> Position;
199
200 fn offset_to_point(&self, offset: usize) -> Point;
204
205 fn point_to_offset(&self, point: Point) -> usize;
209
210 fn word_range(&self, offset: usize) -> Option<Range<usize>>;
212
213 fn word_at(&self, offset: usize) -> String;
215
216 fn offset_utf16_to_offset(&self, offset_utf16: usize) -> usize;
220
221 fn offset_to_offset_utf16(&self, offset: usize) -> usize;
225
226 fn clip_offset(&self, offset: usize, bias: Bias) -> usize;
243
244 fn char_index_to_offset(&self, char_index: usize) -> usize;
259
260 fn offset_to_char_index(&self, offset: usize) -> usize;
275}
276
277impl RopeExt for Rope {
278 fn slice_line(&self, row: usize) -> RopeSlice<'_> {
279 let total_lines = self.lines_len();
280 if row >= total_lines {
281 return self.slice(0..0);
282 }
283
284 let line = self.line(row, LineType::LF);
285 if line.len() > 0 {
286 let line_end = line.len() - 1;
287 if line.is_char_boundary(line_end) && line.char(line_end) == '\n' {
288 return line.slice(..line_end);
289 }
290 }
291
292 line
293 }
294
295 fn slice_lines(&self, rows_range: Range<usize>) -> RopeSlice<'_> {
296 let start = self.line_start_offset(rows_range.start);
297 let end = self.line_end_offset(rows_range.end.saturating_sub(1));
298 self.slice(start..end)
299 }
300
301 fn iter_lines(&self) -> RopeLines<'_> {
302 RopeLines::new(&self)
303 }
304
305 fn line_len(&self, row: usize) -> usize {
306 self.slice_line(row).len()
307 }
308
309 fn line_start_offset(&self, row: usize) -> usize {
310 self.point_to_offset(Point::new(row, 0))
311 }
312
313 fn offset_to_point(&self, offset: usize) -> Point {
314 let offset = self.clip_offset(offset, Bias::Left);
315 let row = self.byte_to_line_idx(offset, LineType::LF);
316 let line_start = self.line_to_byte_idx(row, LineType::LF);
317 let column = offset.saturating_sub(line_start);
318 Point::new(row, column)
319 }
320
321 fn point_to_offset(&self, point: Point) -> usize {
322 if point.row >= self.lines_len() {
323 return self.len();
324 }
325
326 let line_start = self.line_to_byte_idx(point.row, LineType::LF);
327 line_start + point.column
328 }
329
330 fn position_to_offset(&self, pos: &Position) -> usize {
331 let line = self.slice_line(pos.line as usize);
332 self.line_start_offset(pos.line as usize)
334 + line.char_to_byte_idx((pos.character as usize).min(line.len_chars()))
335 }
336
337 fn offset_to_position(&self, offset: usize) -> Position {
338 let point = self.offset_to_point(offset);
339 let line = self.slice_line(point.row);
340 let offset = line.utf16_to_byte_idx(line.byte_to_utf16_idx(point.column));
341 let character = line.slice(..offset).chars().count();
342 Position::new(point.row as u32, character as u32)
343 }
344
345 fn line_end_offset(&self, row: usize) -> usize {
346 if row > self.lines_len() {
347 return self.len();
348 }
349
350 self.line_start_offset(row) + self.line_len(row)
351 }
352
353 fn lines_len(&self) -> usize {
354 self.len_lines(LineType::LF)
355 }
356
357 fn char_at(&self, offset: usize) -> Option<char> {
358 if offset > self.len() {
359 return None;
360 }
361
362 self.get_char(offset).ok()
363 }
364
365 fn word_range(&self, offset: usize) -> Option<Range<usize>> {
366 if offset >= self.len() {
367 return None;
368 }
369
370 let mut left = String::new();
371 let offset = self.clip_offset(offset, Bias::Left);
372 for c in self.chars_at(offset).reversed() {
373 if c.is_alphanumeric() || c == '_' {
374 left.insert(0, c);
375 } else {
376 break;
377 }
378 }
379 let start = offset.saturating_sub(left.len());
380
381 let right = self
382 .chars_at(offset)
383 .take_while(|c| c.is_alphanumeric() || *c == '_')
384 .collect::<String>();
385
386 let end = offset + right.len();
387
388 if start == end { None } else { Some(start..end) }
389 }
390
391 fn word_at(&self, offset: usize) -> String {
392 if let Some(range) = self.word_range(offset) {
393 self.slice(range).to_string()
394 } else {
395 String::new()
396 }
397 }
398
399 #[inline]
400 fn offset_utf16_to_offset(&self, offset_utf16: usize) -> usize {
401 if offset_utf16 > self.len_utf16() {
402 return self.len();
403 }
404
405 self.utf16_to_byte_idx(offset_utf16)
406 }
407
408 #[inline]
409 fn offset_to_offset_utf16(&self, offset: usize) -> usize {
410 if offset > self.len() {
411 return self.len_utf16();
412 }
413
414 self.byte_to_utf16_idx(offset)
415 }
416
417 fn replace(&mut self, range: Range<usize>, new_text: &str) {
418 let range =
419 self.clip_offset(range.start, Bias::Left)..self.clip_offset(range.end, Bias::Right);
420 self.remove(range.clone());
421 self.insert(range.start, new_text);
422 }
423
424 fn clip_offset(&self, offset: usize, bias: Bias) -> usize {
425 if offset > self.len() {
426 return self.len();
427 }
428
429 if self.is_char_boundary(offset) {
430 return offset;
431 }
432
433 if bias == Bias::Left {
434 self.floor_char_boundary(offset)
435 } else {
436 self.ceil_char_boundary(offset)
437 }
438 }
439
440 fn char_index_to_offset(&self, char_offset: usize) -> usize {
441 self.chars().take(char_offset).map(|c| c.len_utf8()).sum()
442 }
443
444 fn offset_to_char_index(&self, offset: usize) -> usize {
445 let offset = self.clip_offset(offset, Bias::Right);
446 self.slice(..offset).chars().count()
447 }
448}
449
450#[cfg(test)]
451mod tests {
452 use super::Point;
453 use ropey::Rope;
454 use sum_tree::Bias;
455
456 use crate::input::{Position, RopeExt};
457
458 #[test]
459 fn test_slice_line() {
460 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
461 assert_eq!(rope.slice_line(0).to_string(), "Hello");
462 assert_eq!(rope.slice_line(1).to_string(), "World\r");
463 assert_eq!(rope.slice_line(2).to_string(), "This is a test 中文");
464 assert_eq!(rope.slice_line(3).to_string(), "Rope");
465
466 assert_eq!(rope.slice_line(6).to_string(), "");
468
469 let rope = Rope::from("Hello\r");
471 assert_eq!(rope.slice_line(0).to_string(), "Hello\r");
472 assert_eq!(rope.slice_line(1).to_string(), "");
473 }
474
475 #[test]
476 fn test_lines_len() {
477 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
478 assert_eq!(rope.lines_len(), 4);
479 let rope = Rope::from("");
480 assert_eq!(rope.lines_len(), 1);
481 let rope = Rope::from("Single line");
482 assert_eq!(rope.lines_len(), 1);
483
484 let rope = Rope::from("Hello\r");
486 assert_eq!(rope.lines_len(), 1);
487 }
488
489 #[test]
490 fn test_lines() {
491 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope\r");
492 let lines: Vec<_> = rope.iter_lines().map(|r| r.to_string()).collect();
493 assert_eq!(
494 lines,
495 vec!["Hello", "World\r", "This is a test 中文", "Rope\r"]
496 );
497 }
498
499 #[test]
500 fn test_eq() {
501 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
502 assert!(rope.eq(&Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope")));
503 assert!(!rope.eq(&Rope::from("Hello\nWorld")));
504
505 let rope1 = rope.clone();
506 assert!(rope.eq(&rope1));
507 }
508
509 #[test]
510 fn test_iter_lines() {
511 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
512 let lines: Vec<_> = rope
513 .iter_lines()
514 .skip(1)
515 .take(2)
516 .map(|r| r.to_string())
517 .collect();
518 assert_eq!(lines, vec!["World\r", "This is a test 中文"]);
519 }
520
521 #[test]
522 fn test_line_start_end_offset() {
523 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
524 assert_eq!(rope.line_start_offset(0), 0);
525 assert_eq!(rope.line_end_offset(0), 5);
526
527 assert_eq!(rope.line_start_offset(1), 6);
528 assert_eq!(rope.line_end_offset(1), 12);
529
530 assert_eq!(rope.line_start_offset(2), 13);
531 assert_eq!(rope.line_end_offset(2), 34);
532
533 assert_eq!(rope.line_start_offset(3), 35);
534 assert_eq!(rope.line_end_offset(3), 39);
535
536 assert_eq!(rope.line_start_offset(4), 39);
537 assert_eq!(rope.line_end_offset(4), 39);
538 }
539
540 #[test]
541 fn test_line_column() {
542 let rope = Rope::from("a 中文🎉 test\nRope");
543 assert_eq!(rope.position_to_offset(&Position::new(0, 3)), "a 中".len());
544 assert_eq!(
545 rope.position_to_offset(&Position::new(0, 5)),
546 "a 中文🎉".len()
547 );
548 assert_eq!(
549 rope.position_to_offset(&Position::new(1, 1)),
550 "a 中文🎉 test\nR".len()
551 );
552 assert_eq!(
553 rope.position_to_offset(&Position::new(0, u32::MAX)),
554 "a 中文🎉 test".len()
555 );
556
557 assert_eq!(
558 rope.offset_to_position("a 中文🎉 test\nR".len()),
559 Position::new(1, 1)
560 );
561 assert_eq!(
562 rope.offset_to_position("a 中文🎉".len()),
563 Position::new(0, 5)
564 );
565 }
566
567 #[test]
568 fn test_offset_to_point() {
569 let rope = Rope::from("a 中文🎉 test\nRope");
570 assert_eq!(rope.offset_to_point(0), Point::new(0, 0));
571 assert_eq!(rope.offset_to_point(1), Point::new(0, 1));
572 assert_eq!(rope.offset_to_point("a 中".len()), Point::new(0, 5));
573 assert_eq!(rope.offset_to_point("a 中文🎉".len()), Point::new(0, 12));
574 assert_eq!(
575 rope.offset_to_point("a 中文🎉 test\nR".len()),
576 Point::new(1, 1)
577 );
578 }
579
580 #[test]
581 fn test_point_to_offset() {
582 let rope = Rope::from("a 中文🎉 test\nRope");
583 assert_eq!(rope.point_to_offset(Point::new(0, 0)), 0);
584 assert_eq!(rope.point_to_offset(Point::new(0, 1)), 1);
585 assert_eq!(rope.point_to_offset(Point::new(0, 5)), "a 中".len());
586 assert_eq!(rope.point_to_offset(Point::new(0, 12)), "a 中文🎉".len());
587 assert_eq!(
588 rope.point_to_offset(Point::new(1, 1)),
589 "a 中文🎉 test\nR".len()
590 );
591 }
592
593 #[test]
594 fn test_char_at() {
595 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文🎉\nRope");
596 assert_eq!(rope.char_at(0), Some('H'));
597 assert_eq!(rope.char_at(5), Some('\n'));
598 assert_eq!(rope.char_at(13), Some('T'));
599 assert_eq!(rope.char_at(28), Some('中'));
600 assert_eq!(rope.char_at(34), Some('🎉'));
601 assert_eq!(rope.char_at(38), Some('\n'));
602 assert_eq!(rope.char_at(50), None);
603 }
604
605 #[test]
606 fn test_word_at() {
607 let rope = Rope::from("Hello\nWorld\r\nThis is a test 中文 世界\nRope");
608 assert_eq!(rope.word_at(0), "Hello");
609 assert_eq!(rope.word_range(0), Some(0..5));
610 assert_eq!(rope.word_at(8), "World");
611 assert_eq!(rope.word_range(8), Some(6..11));
612 assert_eq!(rope.word_at(12), "");
613 assert_eq!(rope.word_range(12), None);
614 assert_eq!(rope.word_at(13), "This");
615 assert_eq!(rope.word_range(13), Some(13..17));
616 assert_eq!(rope.word_at(31), "中文");
617 assert_eq!(rope.word_range(31), Some(28..34));
618 assert_eq!(rope.word_at(38), "世界");
619 assert_eq!(rope.word_range(38), Some(35..41));
620 assert_eq!(rope.word_at(44), "Rope");
621 assert_eq!(rope.word_range(44), Some(42..46));
622 assert_eq!(rope.word_at(45), "Rope");
623 }
624
625 #[test]
626 fn test_offset_utf16_conversion() {
627 let rope = Rope::from("hello 中文🎉 test\nRope");
628 assert_eq!(rope.offset_to_offset_utf16("hello".len()), 5);
629 assert_eq!(rope.offset_to_offset_utf16("hello 中".len()), 7);
630 assert_eq!(rope.offset_to_offset_utf16("hello 中文".len()), 8);
631 assert_eq!(rope.offset_to_offset_utf16("hello 中文🎉".len()), 10);
632 assert_eq!(rope.offset_to_offset_utf16(100), 20);
633
634 assert_eq!(rope.offset_utf16_to_offset(5), "hello".len());
635 assert_eq!(rope.offset_utf16_to_offset(7), "hello 中".len());
636 assert_eq!(rope.offset_utf16_to_offset(8), "hello 中文".len());
637 assert_eq!(rope.offset_utf16_to_offset(10), "hello 中文🎉".len());
638 assert_eq!(rope.offset_utf16_to_offset(100), rope.len());
639 }
640
641 #[test]
642 fn test_replace() {
643 let mut rope = Rope::from("Hello\nWorld\r\nThis is a test 中文\nRope");
644 rope.replace(6..11, "Universe");
645 assert_eq!(
646 rope.to_string(),
647 "Hello\nUniverse\r\nThis is a test 中文\nRope"
648 );
649
650 rope.replace(0..5, "Hi");
651 assert_eq!(
652 rope.to_string(),
653 "Hi\nUniverse\r\nThis is a test 中文\nRope"
654 );
655
656 rope.replace(rope.len() - 4..rope.len(), "String");
657 assert_eq!(
658 rope.to_string(),
659 "Hi\nUniverse\r\nThis is a test 中文\nString"
660 );
661
662 let mut rope = Rope::from("中文");
664 rope.replace(0..1, "New");
665 assert_eq!(rope.to_string(), "New文");
667 let mut rope = Rope::from("中文");
668 rope.replace(0..2, "New");
669 assert_eq!(rope.to_string(), "New文");
670 let mut rope = Rope::from("中文");
671 rope.replace(0..3, "New");
672 assert_eq!(rope.to_string(), "New文");
673 let mut rope = Rope::from("中文");
675 rope.replace(1..4, "New");
676 assert_eq!(rope.to_string(), "New");
677 }
678
679 #[test]
680 fn test_clip_offset() {
681 let rope = Rope::from("Hello 中文🎉 test\nRope");
682 assert_eq!(rope.clip_offset(5, Bias::Left), 5);
684 assert_eq!(rope.clip_offset(7, Bias::Left), 6);
685 assert_eq!(rope.clip_offset(7, Bias::Right), 9);
686 assert_eq!(rope.clip_offset(9, Bias::Left), 9);
687
688 assert_eq!(rope.clip_offset(13, Bias::Left), 12);
690 assert_eq!(rope.clip_offset(13, Bias::Right), 16);
691 assert_eq!(rope.clip_offset(16, Bias::Left), 16);
692
693 assert_eq!(rope.clip_offset(5, Bias::Left), 5);
695 assert_eq!(rope.clip_offset(5, Bias::Right), 5);
696
697 assert_eq!(rope.clip_offset(26, Bias::Left), 26);
699 assert_eq!(rope.clip_offset(100, Bias::Left), 26);
700 }
701
702 #[test]
703 fn test_char_index_to_offset() {
704 let rope = Rope::from("a 中文🎉 test\nRope");
705 assert_eq!(rope.char_index_to_offset(0), 0);
706 assert_eq!(rope.char_index_to_offset(1), 1);
707 assert_eq!(rope.char_index_to_offset(3), "a 中".len());
708 assert_eq!(rope.char_index_to_offset(5), "a 中文🎉".len());
709 assert_eq!(rope.char_index_to_offset(6), "a 中文🎉 ".len());
710
711 assert_eq!(rope.offset_to_char_index(0), 0);
712 assert_eq!(rope.offset_to_char_index(1), 1);
713 assert_eq!(rope.offset_to_char_index(3), 3);
714 assert_eq!(rope.offset_to_char_index(4), 3);
715 assert_eq!(rope.offset_to_char_index(5), 3);
716 assert_eq!(rope.offset_to_char_index(6), 4);
717 assert_eq!(rope.offset_to_char_index(10), 5);
718 }
719}