1use std::cmp::{max, min};
22
23pub trait TextBuffer {
25 fn line_count(&self) -> usize;
27
28 fn get_line(&self, line_idx: usize) -> Option<String>;
30
31 fn line_len(&self, line_idx: usize) -> usize {
33 self.get_line(line_idx).map(|s| s.len()).unwrap_or(0)
34 }
35
36 fn all_lines(&self) -> Vec<String>;
38
39 fn insert_at(&mut self, row: usize, col: usize, text: &str);
41
42 fn delete_at(&mut self, row: usize, col: usize);
44
45 fn backspace_at(&mut self, row: usize, col: usize);
47}
48
49#[derive(Clone)]
64pub struct GapBuffer {
65 buffer: Vec<char>,
67 gap_start: usize,
69 gap_end: usize,
71}
72
73impl GapBuffer {
74 pub fn new() -> Self {
76 let initial_capacity = 1024;
77 let buffer = vec!['\0'; initial_capacity];
78 Self {
79 buffer,
80 gap_start: 0,
81 gap_end: initial_capacity,
82 }
83 }
84
85 pub fn from_text(text: &str) -> Self {
87 let chars: Vec<char> = text.chars().collect();
88 let text_len = chars.len();
89
90 let capacity = max(1024, text_len * 2);
92 let mut buffer = vec!['\0'; capacity];
93
94 for (i, &ch) in chars.iter().enumerate() {
96 buffer[i] = ch;
97 }
98
99 Self {
100 buffer,
101 gap_start: text_len,
102 gap_end: capacity,
103 }
104 }
105
106 pub fn from_lines(lines: Vec<String>) -> Self {
108 Self::from_text(&lines.join("\n"))
109 }
110
111 pub fn len(&self) -> usize {
113 self.buffer.len() - self.gap_size()
114 }
115
116 fn gap_size(&self) -> usize {
118 self.gap_end - self.gap_start
119 }
120
121 pub fn move_gap_to(&mut self, position: usize) {
129 let position = min(position, self.len());
130
131 if position < self.gap_start {
132 let move_count = self.gap_start - position;
134
135 for i in (0..move_count).rev() {
137 self.buffer[self.gap_end - 1 - i] = self.buffer[self.gap_start - 1 - i];
138 }
139
140 self.gap_end -= move_count;
141 self.gap_start -= move_count;
142 } else if position > self.gap_start {
143 let move_count = position - self.gap_start;
145
146 for i in 0..move_count {
148 if self.gap_end + i < self.buffer.len() {
149 self.buffer[self.gap_start + i] = self.buffer[self.gap_end + i];
150 }
151 }
152
153 self.gap_start += move_count;
154 self.gap_end += move_count;
155 }
156 }
157
158 pub fn insert_char(&mut self, position: usize, ch: char) {
163 self.move_gap_to(position);
164 if self.gap_start >= self.gap_end {
165 self.grow_gap();
166 }
167 self.buffer[self.gap_start] = ch;
168 self.gap_start += 1;
169 }
170
171 pub fn insert(&mut self, position: usize, text: &str) {
173 self.move_gap_to(position);
174 for ch in text.chars() {
175 if self.gap_start >= self.gap_end {
176 self.grow_gap();
177 }
178 self.buffer[self.gap_start] = ch;
179 self.gap_start += 1;
180 }
181 }
182
183 pub fn delete_backward(&mut self, position: usize) {
185 if position > 0 {
186 self.move_gap_to(position);
187 self.gap_start -= 1;
188 }
189 }
190
191 pub fn delete_forward(&mut self, position: usize) {
193 self.move_gap_to(position);
194 if self.gap_end < self.buffer.len() {
195 self.gap_end += 1;
196 }
197 }
198
199 pub fn delete_range(&mut self, start: usize, end: usize) {
201 if start >= end {
202 return;
203 }
204
205 let start = min(start, self.len());
206 let end = min(end, self.len());
207
208 self.move_gap_to(start);
209 let delete_count = end - start;
210 self.gap_end = min(self.gap_end + delete_count, self.buffer.len());
211 }
212
213 fn grow_gap(&mut self) {
215 let old_capacity = self.buffer.len();
216 let new_capacity = old_capacity * 2;
217 let additional_capacity = new_capacity - old_capacity;
218
219 let mut new_buffer = vec!['\0'; new_capacity];
220
221 for i in 0..self.gap_start {
223 new_buffer[i] = self.buffer[i];
224 }
225
226 let after_gap_start = self.gap_end;
228 let after_gap_count = old_capacity - self.gap_end;
229 let new_gap_end = self.gap_start + self.gap_size() + additional_capacity;
230
231 for i in 0..after_gap_count {
232 new_buffer[new_gap_end + i] = self.buffer[after_gap_start + i];
233 }
234
235 self.buffer = new_buffer;
236 self.gap_end = new_gap_end;
237 }
238
239 pub fn to_string(&self) -> String {
247 let mut result = String::with_capacity(self.len());
248
249 for i in 0..self.gap_start {
251 result.push(self.buffer[i]);
252 }
253
254 for i in self.gap_end..self.buffer.len() {
256 let ch = self.buffer[i];
257 if ch != '\0' {
258 result.push(ch);
259 }
260 }
261
262 result
263 }
264
265 pub fn to_lines(&self) -> Vec<String> {
267 let text = self.to_string();
268 if text.is_empty() {
269 vec![String::new()]
270 } else {
271 let lines: Vec<String> = text.split('\n').map(|s| s.to_string()).collect();
272 if lines.is_empty() {
273 vec![String::new()]
274 } else {
275 lines
276 }
277 }
278 }
279
280 pub fn cursor_to_position(&self, row: usize, col: usize) -> usize {
289 let text = self.to_string();
290 let mut current_row = 0;
291 let mut current_col = 0;
292
293 for (i, ch) in text.char_indices() {
294 if current_row == row && current_col == col {
295 return i;
296 }
297
298 if ch == '\n' {
299 if current_row == row {
300 return i; }
302 current_row += 1;
303 current_col = 0;
304 } else {
305 current_col += 1;
306 }
307 }
308
309 text.len()
311 }
312
313 pub fn position_to_cursor(&self, position: usize) -> (usize, usize) {
321 let text = self.to_string();
322 let position = min(position, text.len());
323
324 let mut row = 0;
325 let mut col = 0;
326
327 for (i, ch) in text.char_indices() {
328 if i >= position {
329 break;
330 }
331 if ch == '\n' {
332 row += 1;
333 col = 0;
334 } else {
335 col += 1;
336 }
337 }
338
339 (row, col)
340 }
341}
342
343impl Default for GapBuffer {
344 fn default() -> Self {
345 Self::new()
346 }
347}
348
349impl TextBuffer for GapBuffer {
350 fn line_count(&self) -> usize {
351 let text = self.to_string();
352 if text.is_empty() {
353 1
354 } else {
355 text.chars().filter(|&c| c == '\n').count() + 1
356 }
357 }
358
359 fn get_line(&self, line_idx: usize) -> Option<String> {
360 let lines = self.to_lines();
361 lines.get(line_idx).cloned()
362 }
363
364 fn all_lines(&self) -> Vec<String> {
365 self.to_lines()
366 }
367
368 fn line_len(&self, line_idx: usize) -> usize {
369 let lines = self.to_lines();
370 lines.get(line_idx).map(|s| s.len()).unwrap_or(0)
371 }
372
373 fn insert_at(&mut self, row: usize, col: usize, text: &str) {
374 let position = self.cursor_to_position(row, col);
375 self.insert(position, text);
376 }
377
378 fn delete_at(&mut self, row: usize, col: usize) {
379 let position = self.cursor_to_position(row, col);
380 self.delete_forward(position);
381 }
382
383 fn backspace_at(&mut self, row: usize, col: usize) {
384 let position = self.cursor_to_position(row, col);
385 if position > 0 {
386 self.delete_backward(position);
387 }
388 }
389}
390
391#[cfg(test)]
392mod tests {
393 use super::*;
394
395 #[test]
396 fn test_line_splitting_with_newlines() {
397 let buffer = GapBuffer::from_text("Hello\nWorld\nTest");
398 let lines = buffer.to_lines();
399
400 assert_eq!(lines.len(), 3);
401 assert_eq!(lines[0], "Hello");
402 assert_eq!(lines[1], "World");
403 assert_eq!(lines[2], "Test");
404 }
405
406 #[test]
407 fn test_cursor_position_conversion() {
408 let buffer = GapBuffer::from_text("Hello\nWorld");
409
410 assert_eq!(buffer.cursor_to_position(0, 0), 0);
412 assert_eq!(buffer.cursor_to_position(0, 5), 5);
413 assert_eq!(buffer.cursor_to_position(1, 0), 6);
414 assert_eq!(buffer.cursor_to_position(1, 5), 11);
415
416 assert_eq!(buffer.position_to_cursor(0), (0, 0));
418 assert_eq!(buffer.position_to_cursor(5), (0, 5));
419 assert_eq!(buffer.position_to_cursor(6), (1, 0));
420 }
421
422 #[test]
423 fn test_newline_insertion() {
424 let mut buffer = GapBuffer::from_text("HelloWorld");
425 buffer.insert(5, "\n");
426
427 let lines = buffer.to_lines();
428 assert_eq!(lines.len(), 2);
429 assert_eq!(lines[0], "Hello");
430 assert_eq!(lines[1], "World");
431
432 assert_eq!(buffer.to_string(), "Hello\nWorld");
433 }
434
435 #[test]
436 fn test_new_empty_buffer() {
437 let buffer = GapBuffer::new();
438 assert_eq!(buffer.len(), 0);
439 assert_eq!(buffer.to_string(), "");
440 }
441
442 #[test]
443 fn test_from_text() {
444 let buffer = GapBuffer::from_text("Hello, World!");
445 assert_eq!(buffer.len(), 13);
446 assert_eq!(buffer.to_string(), "Hello, World!");
447 }
448
449 #[test]
450 fn test_from_lines() {
451 let lines = vec!["Hello".to_string(), "World".to_string()];
452 let buffer = GapBuffer::from_lines(lines);
453 assert_eq!(buffer.to_string(), "Hello\nWorld");
454 }
455
456 #[test]
457 fn test_insert_char() {
458 let mut buffer = GapBuffer::from_text("Hello");
459 buffer.insert_char(5, '!');
460 assert_eq!(buffer.to_string(), "Hello!");
461
462 buffer.insert_char(0, '>');
463 assert_eq!(buffer.to_string(), ">Hello!");
464
465 buffer.insert_char(3, '<');
466 assert_eq!(buffer.to_string(), ">He<llo!");
467 }
468
469 #[test]
470 fn test_insert_text_various_positions() {
471 let mut buffer = GapBuffer::from_text("Hello");
472
473 buffer.insert(5, " World");
475 assert_eq!(buffer.to_string(), "Hello World");
476
477 buffer.insert(0, "Say ");
479 assert_eq!(buffer.to_string(), "Say Hello World");
480
481 buffer.insert(9, " Beautiful");
483 assert_eq!(buffer.to_string(), "Say Hello Beautiful World");
484 }
485
486 #[test]
487 fn test_insert_multiline() {
488 let mut buffer = GapBuffer::from_text("Line1");
489 buffer.insert(5, "\nLine2\nLine3");
490 assert_eq!(buffer.to_string(), "Line1\nLine2\nLine3");
491
492 let lines = buffer.to_lines();
493 assert_eq!(lines.len(), 3);
494 assert_eq!(lines[0], "Line1");
495 assert_eq!(lines[1], "Line2");
496 assert_eq!(lines[2], "Line3");
497 }
498
499 #[test]
500 fn test_delete_backward() {
501 let mut buffer = GapBuffer::from_text("Hello World");
502
503 buffer.delete_backward(11);
504 assert_eq!(buffer.to_string(), "Hello Worl");
505
506 buffer.delete_backward(6);
507 assert_eq!(buffer.to_string(), "HelloWorl");
508
509 buffer.delete_backward(1);
510 assert_eq!(buffer.to_string(), "elloWorl");
511 }
512
513 #[test]
514 fn test_delete_forward() {
515 let mut buffer = GapBuffer::from_text("Hello World");
516
517 buffer.delete_forward(0);
518 assert_eq!(buffer.to_string(), "ello World");
519
520 buffer.delete_forward(4);
521 assert_eq!(buffer.to_string(), "elloWorld");
522
523 buffer.delete_forward(8);
524 assert_eq!(buffer.to_string(), "elloWorl");
525 }
526
527 #[test]
528 fn test_delete_range() {
529 let mut buffer = GapBuffer::from_text("Hello World");
530
531 buffer.delete_range(5, 11);
532 assert_eq!(buffer.to_string(), "Hello");
533
534 let mut buffer = GapBuffer::from_text("Hello World");
535 buffer.delete_range(0, 6);
536 assert_eq!(buffer.to_string(), "World");
537
538 let mut buffer = GapBuffer::from_text("Hello World");
539 buffer.delete_range(2, 8);
540 assert_eq!(buffer.to_string(), "Herld");
541 }
542
543 #[test]
544 fn test_delete_range_edge_cases() {
545 let mut buffer = GapBuffer::from_text("Hello");
546
547 buffer.delete_range(0, 5);
549 assert_eq!(buffer.to_string(), "");
550
551 let mut buffer = GapBuffer::from_text("Hello");
553 buffer.delete_range(3, 2);
554 assert_eq!(buffer.to_string(), "Hello");
555 }
556
557 #[test]
558 fn test_move_gap_to() {
559 let mut buffer = GapBuffer::from_text("Hello World");
560 let initial_text = buffer.to_string();
561
562 buffer.move_gap_to(5);
564 assert_eq!(buffer.to_string(), initial_text);
565
566 buffer.move_gap_to(0);
567 assert_eq!(buffer.to_string(), initial_text);
568
569 buffer.move_gap_to(11);
570 assert_eq!(buffer.to_string(), initial_text);
571 }
572
573 #[test]
574 fn test_gap_movement_with_operations() {
575 let mut buffer = GapBuffer::from_text("ABC");
576
577 buffer.insert(0, "1");
579 assert_eq!(buffer.to_string(), "1ABC");
580
581 buffer.insert(4, "2");
583 assert_eq!(buffer.to_string(), "1ABC2");
584
585 buffer.insert(2, "X");
587 assert_eq!(buffer.to_string(), "1AXBC2");
588 }
589
590 #[test]
591 fn test_cursor_to_position() {
592 let buffer = GapBuffer::from_text("Line1\nLine2\nLine3");
593
594 assert_eq!(buffer.cursor_to_position(0, 0), 0);
595 assert_eq!(buffer.cursor_to_position(0, 5), 5);
596 assert_eq!(buffer.cursor_to_position(1, 0), 6);
597 assert_eq!(buffer.cursor_to_position(1, 5), 11);
598 assert_eq!(buffer.cursor_to_position(2, 0), 12);
599
600 assert_eq!(buffer.cursor_to_position(0, 100), 5);
602 }
603
604 #[test]
605 fn test_position_to_cursor() {
606 let buffer = GapBuffer::from_text("Line1\nLine2\nLine3");
607
608 assert_eq!(buffer.position_to_cursor(0), (0, 0));
609 assert_eq!(buffer.position_to_cursor(5), (0, 5));
610 assert_eq!(buffer.position_to_cursor(6), (1, 0));
611 assert_eq!(buffer.position_to_cursor(11), (1, 5));
612 assert_eq!(buffer.position_to_cursor(12), (2, 0));
613
614 assert_eq!(buffer.position_to_cursor(100), (2, 5));
616 }
617
618 #[test]
619 fn test_cursor_position_roundtrip() {
620 let buffer = GapBuffer::from_text("Hello\nWorld\n!");
621
622 for row in 0..3 {
623 for col in 0..6 {
624 let pos = buffer.cursor_to_position(row, col);
625 let (r, c) = buffer.position_to_cursor(pos);
626 if col <= buffer.line_len(row) {
627 assert_eq!((r, c), (row, col.min(buffer.line_len(row))));
628 }
629 }
630 }
631 }
632
633 #[test]
634 fn test_to_lines() {
635 let buffer = GapBuffer::from_text("Line1\nLine2\nLine3");
636 let lines = buffer.to_lines();
637 assert_eq!(lines, vec!["Line1", "Line2", "Line3"]);
638
639 let empty_buffer = GapBuffer::new();
640 let empty_lines = empty_buffer.to_lines();
641 assert_eq!(empty_lines, vec![""]);
642 }
643
644 #[test]
645 fn test_line_count() {
646 let buffer = GapBuffer::from_text("");
647 assert_eq!(buffer.line_count(), 1);
648
649 let buffer = GapBuffer::from_text("Hello");
650 assert_eq!(buffer.line_count(), 1);
651
652 let buffer = GapBuffer::from_text("Hello\nWorld");
653 assert_eq!(buffer.line_count(), 2);
654
655 let buffer = GapBuffer::from_text("Line1\nLine2\nLine3");
656 assert_eq!(buffer.line_count(), 3);
657
658 let buffer = GapBuffer::from_text("Line1\nLine2\n");
659 assert_eq!(buffer.line_count(), 3);
660 }
661
662 #[test]
663 fn test_line_len() {
664 let buffer = GapBuffer::from_text("Hello\nWorld!\n");
665 assert_eq!(buffer.line_len(0), 5);
666 assert_eq!(buffer.line_len(1), 6);
667 assert_eq!(buffer.line_len(2), 0);
668 }
669
670 #[test]
671 fn test_insert_at() {
672 let mut buffer = GapBuffer::from_text("Hello\nWorld");
673
674 buffer.insert_at(0, 5, "!");
675 assert_eq!(buffer.to_string(), "Hello!\nWorld");
676
677 buffer.insert_at(1, 5, "!");
678 assert_eq!(buffer.to_string(), "Hello!\nWorld!");
679
680 buffer.insert_at(1, 0, "> ");
681 assert_eq!(buffer.to_string(), "Hello!\n> World!");
682 }
683
684 #[test]
685 fn test_delete_at() {
686 let mut buffer = GapBuffer::from_text("Hello\nWorld");
687
688 buffer.delete_at(0, 4);
689 assert_eq!(buffer.to_string(), "Hell\nWorld");
690
691 buffer.delete_at(1, 0);
692 assert_eq!(buffer.to_string(), "Hell\norld");
693 }
694
695 #[test]
696 fn test_backspace_at() {
697 let mut buffer = GapBuffer::from_text("Hello\nWorld");
698
699 buffer.backspace_at(0, 5);
700 assert_eq!(buffer.to_string(), "Hell\nWorld");
701
702 buffer.backspace_at(1, 1);
703 assert_eq!(buffer.to_string(), "Hell\norld");
704
705 buffer.backspace_at(1, 0);
707 assert_eq!(buffer.to_string(), "Hellorld");
708 }
709
710 #[test]
711 fn test_grow_gap() {
712 let mut buffer = GapBuffer::from_text("Hi");
713 let mut long_text = String::new();
714 for _ in 0..1000 {
715 long_text.push('x');
716 }
717 buffer.insert(2, &long_text);
718 assert_eq!(buffer.to_string(), format!("Hi{}", long_text));
719 }
720
721 #[test]
722 fn test_gap_movement_preserves_text() {
723 let mut buffer = GapBuffer::from_text("The quick brown fox jumps over the lazy dog");
724 let original = buffer.to_string();
725
726 for i in 0..original.len() {
728 buffer.move_gap_to(i);
729 assert_eq!(buffer.to_string(), original);
730 }
731
732 buffer.insert(10, "[INSERT]");
734 assert_eq!(
735 buffer.to_string(),
736 "The quick [INSERT]brown fox jumps over the lazy dog"
737 );
738
739 buffer.delete_range(10, 18);
740 assert_eq!(buffer.to_string(), original);
741 }
742
743 #[test]
744 fn test_large_buffer_with_gap_movement() {
745 let mut text = String::new();
746 for i in 0..100 {
747 text.push_str(&format!("Line {}\n", i));
748 }
749
750 let mut buffer = GapBuffer::from_text(&text);
751
752 buffer.insert(0, "START\n");
754 buffer.insert(buffer.len(), "\nEND");
755 buffer.insert(buffer.len() / 2, "\nMIDDLE\n");
756
757 let result = buffer.to_string();
758 assert!(result.starts_with("START\n"));
759 assert!(result.ends_with("\nEND"));
760 assert!(result.contains("\nMIDDLE\n"));
761 }
762
763 #[test]
764 fn test_empty_buffer_operations() {
765 let mut buffer = GapBuffer::new();
766
767 buffer.insert(0, "Hello");
768 assert_eq!(buffer.to_string(), "Hello");
769
770 buffer.delete_range(0, 5);
771 assert_eq!(buffer.to_string(), "");
772
773 buffer.insert(0, "World");
774 assert_eq!(buffer.to_string(), "World");
775
776 buffer.delete_backward(5);
777 assert_eq!(buffer.to_string(), "Worl");
778 }
779
780 #[test]
781 fn test_newline_handling() {
782 let mut buffer = GapBuffer::new();
783
784 buffer.insert(0, "Line1");
785 buffer.insert(5, "\n");
786 buffer.insert(6, "Line2");
787 buffer.insert(11, "\n");
788 buffer.insert(12, "Line3");
789
790 let lines = buffer.to_lines();
791 assert_eq!(lines.len(), 3);
792 assert_eq!(lines[0], "Line1");
793 assert_eq!(lines[1], "Line2");
794 assert_eq!(lines[2], "Line3");
795
796 buffer.delete_at(0, 5); assert_eq!(buffer.to_string(), "Line1Line2\nLine3");
799
800 buffer.delete_forward(10); assert_eq!(buffer.to_string(), "Line1Line2Line3");
802 }
803
804 #[test]
805 fn test_stress_random_operations() {
806 let mut buffer = GapBuffer::from_text("Initial");
807
808 for i in 0..50 {
810 let pos = i % (buffer.len() + 1);
811 buffer.insert(pos, &format!("{}", i % 10));
812
813 if buffer.len() > 10 && i % 3 == 0 {
814 let del_pos = (i * 7) % buffer.len();
815 buffer.delete_forward(del_pos);
816 }
817
818 if buffer.len() > 5 && i % 5 == 0 {
819 let del_pos = (i * 3) % buffer.len();
820 buffer.delete_backward(del_pos);
821 }
822 }
823
824 let text = buffer.to_string();
826 let reconstructed = GapBuffer::from_text(&text);
827 assert_eq!(reconstructed.to_string(), text);
828 }
829
830 #[test]
831 fn test_large_text() {
832 let mut large_text = String::new();
833 for i in 0..1000 {
834 large_text.push_str(&format!(
835 "Line {}: This is a test line with some content.\n",
836 i
837 ));
838 }
839
840 let buffer = GapBuffer::from_text(&large_text);
841 assert_eq!(buffer.to_string(), large_text);
842
843 let lines = buffer.to_lines();
844 assert_eq!(lines.len(), 1001); assert_eq!(buffer.line_count(), 1001);
848 assert!(buffer.get_line(500).is_some());
849 }
850
851 #[test]
852 fn test_unicode_characters() {
853 let mut buffer = GapBuffer::from_text("Hello δΈη");
854 assert_eq!(buffer.to_string(), "Hello δΈη");
855
856 buffer.insert(6, "π ");
857 assert_eq!(buffer.to_string(), "Hello π δΈη");
858
859 buffer.insert_char(0, 'π');
860 assert_eq!(buffer.to_string(), "πHello π δΈη");
861
862 let mut buffer = GapBuffer::from_text("π¨ππͺ");
864 buffer.delete_forward(0);
865 assert_eq!(buffer.to_string(), "ππͺ");
866 }
867
868 #[test]
869 fn test_sequential_edits() {
870 let mut buffer = GapBuffer::new();
871
872 let text = "The quick brown fox";
874 for ch in text.chars() {
875 buffer.insert_char(buffer.len(), ch);
876 }
877 assert_eq!(buffer.to_string(), text);
878
879 buffer.delete_backward(19); buffer.delete_backward(18); buffer.delete_backward(17); buffer.insert(16, "cat");
884 assert_eq!(buffer.to_string(), "The quick brown cat");
885
886 buffer.insert(buffer.len(), " jumped over the lazy dog");
888 assert_eq!(
889 buffer.to_string(),
890 "The quick brown cat jumped over the lazy dog"
891 );
892 }
893}