1use crate::keymap::{At, CharSearch, Movement, RepeatCount, Word};
3use std::cmp::min;
4use std::fmt;
5use std::iter;
6use std::ops::{Deref, Index, Range};
7use std::string::Drain;
8use unicode_segmentation::UnicodeSegmentation;
9
10pub(crate) const MAX_LINE: usize = 4096;
12pub(crate) const INDENT: &str = " ";
13
14#[derive(Clone, Copy)]
16pub enum WordAction {
17 Capitalize,
19 Lowercase,
21 Uppercase,
23}
24
25#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
27pub enum Direction {
28 #[default]
30 Forward,
31 Backward,
33}
34
35pub trait DeleteListener {
37 fn start_killing(&mut self) {}
40 fn delete(&mut self, idx: usize, string: &str, dir: Direction);
42 fn stop_killing(&mut self) {}
45}
46
47pub trait ChangeListener: DeleteListener {
49 fn insert_char(&mut self, idx: usize, c: char);
51 fn insert_str(&mut self, idx: usize, string: &str);
53 fn replace(&mut self, idx: usize, old: &str, new: &str);
55}
56
57pub(crate) struct NoListener;
58
59impl DeleteListener for NoListener {
60 fn delete(&mut self, _idx: usize, _string: &str, _dir: Direction) {}
61}
62impl ChangeListener for NoListener {
63 fn insert_char(&mut self, _idx: usize, _c: char) {}
64
65 fn insert_str(&mut self, _idx: usize, _string: &str) {}
66
67 fn replace(&mut self, _idx: usize, _old: &str, _new: &str) {}
68}
69
70pub struct LineBuffer {
76 buf: String, pos: usize, can_growth: bool, }
80
81impl fmt::Debug for LineBuffer {
82 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
83 f.debug_struct("LineBuffer")
84 .field("buf", &self.buf)
85 .field("pos", &self.pos)
86 .finish()
87 }
88}
89
90impl LineBuffer {
91 #[must_use]
93 pub fn with_capacity(capacity: usize) -> Self {
94 Self {
95 buf: String::with_capacity(capacity),
96 pos: 0,
97 can_growth: false,
98 }
99 }
100
101 pub(crate) fn can_growth(mut self, can_growth: bool) -> Self {
103 self.can_growth = can_growth;
104 self
105 }
106
107 fn must_truncate(&self, new_len: usize) -> bool {
108 !self.can_growth && new_len > self.buf.capacity()
109 }
110
111 #[cfg(test)]
112 pub(crate) fn init(line: &str, pos: usize) -> Self {
113 let mut lb = Self::with_capacity(MAX_LINE);
114 assert!(lb.insert_str(0, line, &mut NoListener));
115 lb.set_pos(pos);
116 lb
117 }
118
119 #[must_use]
121 pub fn as_str(&self) -> &str {
122 &self.buf
123 }
124
125 #[must_use]
127 pub fn into_string(self) -> String {
128 self.buf
129 }
130
131 #[must_use]
133 pub fn pos(&self) -> usize {
134 self.pos
135 }
136
137 pub fn set_pos(&mut self, pos: usize) {
139 assert!(pos <= self.buf.len());
140 self.pos = pos;
141 }
142
143 #[must_use]
145 pub fn len(&self) -> usize {
146 self.buf.len()
147 }
148
149 #[must_use]
151 pub fn is_empty(&self) -> bool {
152 self.buf.is_empty()
153 }
154
155 pub fn update<C: ChangeListener>(&mut self, buf: &str, pos: usize, cl: &mut C) {
157 assert!(pos <= buf.len());
158 let end = self.len();
159 self.drain(0..end, Direction::default(), cl);
160 let max = self.buf.capacity();
161 if self.must_truncate(buf.len()) {
162 self.insert_str(0, &buf[..max], cl);
163 self.pos = max.min(pos);
164 } else {
165 self.insert_str(0, buf, cl);
166 self.pos = pos;
167 }
168 }
169
170 fn end_of_line(&self) -> usize {
171 if let Some(n) = self.buf[self.pos..].find('\n') {
172 n + self.pos
173 } else {
174 self.buf.len()
175 }
176 }
177
178 fn start_of_line(&self) -> usize {
179 if let Some(i) = self.buf[..self.pos].rfind('\n') {
180 i + 1
182 } else {
183 0
184 }
185 }
186
187 pub(crate) fn grapheme_at_cursor(&self) -> Option<&str> {
189 if self.pos == self.buf.len() {
190 None
191 } else {
192 self.buf[self.pos..].graphemes(true).next()
193 }
194 }
195
196 #[must_use]
199 pub fn next_pos(&self, n: RepeatCount) -> Option<usize> {
200 if self.pos == self.buf.len() {
201 return None;
202 }
203 self.buf[self.pos..]
204 .grapheme_indices(true)
205 .take(n)
206 .last()
207 .map(|(i, s)| i + self.pos + s.len())
208 }
209
210 fn prev_pos(&self, n: RepeatCount) -> Option<usize> {
213 if self.pos == 0 {
214 return None;
215 }
216 self.buf[..self.pos]
217 .grapheme_indices(true)
218 .rev()
219 .take(n)
220 .last()
221 .map(|(i, _)| i)
222 }
223
224 pub fn insert<C: ChangeListener>(
229 &mut self,
230 ch: char,
231 n: RepeatCount,
232 cl: &mut C,
233 ) -> Option<bool> {
234 let shift = ch.len_utf8() * n;
235 if self.must_truncate(self.buf.len() + shift) {
236 return None;
237 }
238 let push = self.pos == self.buf.len();
239 if n == 1 {
240 self.buf.insert(self.pos, ch);
241 cl.insert_char(self.pos, ch);
242 } else {
243 let text = iter::repeat(ch).take(n).collect::<String>();
244 let pos = self.pos;
245 self.insert_str(pos, &text, cl);
246 }
247 self.pos += shift;
248 Some(push)
249 }
250
251 pub fn yank<C: ChangeListener>(
255 &mut self,
256 text: &str,
257 n: RepeatCount,
258 cl: &mut C,
259 ) -> Option<bool> {
260 let shift = text.len() * n;
261 if text.is_empty() || self.must_truncate(self.buf.len() + shift) {
262 return None;
263 }
264 let push = self.pos == self.buf.len();
265 let pos = self.pos;
266 if n == 1 {
267 self.insert_str(pos, text, cl);
268 } else {
269 let text = text.repeat(n);
270 self.insert_str(pos, &text, cl);
271 }
272 self.pos += shift;
273 Some(push)
274 }
275
276 pub fn yank_pop<C: ChangeListener>(
278 &mut self,
279 yank_size: usize,
280 text: &str,
281 cl: &mut C,
282 ) -> Option<bool> {
283 let end = self.pos;
284 let start = end - yank_size;
285 self.drain(start..end, Direction::default(), cl);
286 self.pos -= yank_size;
287 self.yank(text, 1, cl)
288 }
289
290 pub fn move_backward(&mut self, n: RepeatCount) -> bool {
292 match self.prev_pos(n) {
293 Some(pos) => {
294 self.pos = pos;
295 true
296 }
297 None => false,
298 }
299 }
300
301 pub fn move_forward(&mut self, n: RepeatCount) -> bool {
303 match self.next_pos(n) {
304 Some(pos) => {
305 self.pos = pos;
306 true
307 }
308 None => false,
309 }
310 }
311
312 pub fn move_buffer_start(&mut self) -> bool {
314 if self.pos > 0 {
315 self.pos = 0;
316 true
317 } else {
318 false
319 }
320 }
321
322 pub fn move_buffer_end(&mut self) -> bool {
324 if self.pos == self.buf.len() {
325 false
326 } else {
327 self.pos = self.buf.len();
328 true
329 }
330 }
331
332 pub fn move_home(&mut self) -> bool {
334 let start = self.start_of_line();
335 if self.pos > start {
336 self.pos = start;
337 true
338 } else {
339 false
340 }
341 }
342
343 pub fn move_end(&mut self) -> bool {
345 let end = self.end_of_line();
346 if self.pos == end {
347 false
348 } else {
349 self.pos = end;
350 true
351 }
352 }
353
354 #[must_use]
356 pub fn is_end_of_input(&self) -> bool {
357 self.pos >= self.buf.trim_end().len()
358 }
359
360 pub fn delete<D: DeleteListener>(&mut self, n: RepeatCount, dl: &mut D) -> Option<String> {
365 match self.next_pos(n) {
366 Some(pos) => {
367 let start = self.pos;
368 let chars = self
369 .drain(start..pos, Direction::Forward, dl)
370 .collect::<String>();
371 Some(chars)
372 }
373 None => None,
374 }
375 }
376
377 pub fn backspace<D: DeleteListener>(&mut self, n: RepeatCount, dl: &mut D) -> bool {
380 match self.prev_pos(n) {
381 Some(pos) => {
382 let end = self.pos;
383 self.drain(pos..end, Direction::Backward, dl);
384 self.pos = pos;
385 true
386 }
387 None => false,
388 }
389 }
390
391 pub fn kill_line<D: DeleteListener>(&mut self, dl: &mut D) -> bool {
393 if !self.buf.is_empty() && self.pos < self.buf.len() {
394 let start = self.pos;
395 let end = self.end_of_line();
396 if start == end {
397 self.delete(1, dl);
398 } else {
399 self.drain(start..end, Direction::Forward, dl);
400 }
401 true
402 } else {
403 false
404 }
405 }
406
407 pub fn kill_buffer<D: DeleteListener>(&mut self, dl: &mut D) -> bool {
409 if !self.buf.is_empty() && self.pos < self.buf.len() {
410 let start = self.pos;
411 let end = self.buf.len();
412 self.drain(start..end, Direction::Forward, dl);
413 true
414 } else {
415 false
416 }
417 }
418
419 pub fn discard_line<D: DeleteListener>(&mut self, dl: &mut D) -> bool {
421 if self.pos > 0 && !self.buf.is_empty() {
422 let start = self.start_of_line();
423 let end = self.pos;
424 if end == start {
425 self.backspace(1, dl)
426 } else {
427 self.drain(start..end, Direction::Backward, dl);
428 self.pos = start;
429 true
430 }
431 } else {
432 false
433 }
434 }
435
436 pub fn discard_buffer<D: DeleteListener>(&mut self, dl: &mut D) -> bool {
438 if self.pos > 0 && !self.buf.is_empty() {
439 let end = self.pos;
440 self.drain(0..end, Direction::Backward, dl);
441 self.pos = 0;
442 true
443 } else {
444 false
445 }
446 }
447
448 pub fn transpose_chars<C: ChangeListener>(&mut self, cl: &mut C) -> bool {
450 if self.pos == 0 || self.buf.graphemes(true).count() < 2 {
451 return false;
452 }
453 if self.pos == self.buf.len() {
454 self.move_backward(1);
455 }
456 let chars = self.delete(1, cl).unwrap();
457 self.move_backward(1);
458 self.yank(&chars, 1, cl);
459 self.move_forward(1);
460 true
461 }
462
463 fn prev_word_pos(&self, pos: usize, word_def: Word, n: RepeatCount) -> Option<usize> {
465 if pos == 0 {
466 return None;
467 }
468 let mut sow = 0;
469 let mut gis = self.buf[..pos].grapheme_indices(true).rev();
470 'outer: for _ in 0..n {
471 sow = 0;
472 let mut gj = gis.next();
473 'inner: loop {
474 if let Some((j, y)) = gj {
475 let gi = gis.next();
476 if let Some((_, x)) = gi {
477 if is_start_of_word(word_def, x, y) {
478 sow = j;
479 break 'inner;
480 }
481 gj = gi;
482 } else {
483 break 'outer;
484 }
485 } else {
486 break 'outer;
487 }
488 }
489 }
490 Some(sow)
491 }
492
493 pub fn move_to_prev_word(&mut self, word_def: Word, n: RepeatCount) -> bool {
495 if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
496 self.pos = pos;
497 true
498 } else {
499 false
500 }
501 }
502
503 pub fn delete_prev_word<D: DeleteListener>(
506 &mut self,
507 word_def: Word,
508 n: RepeatCount,
509 dl: &mut D,
510 ) -> bool {
511 if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
512 let end = self.pos;
513 self.drain(pos..end, Direction::Backward, dl);
514 self.pos = pos;
515 true
516 } else {
517 false
518 }
519 }
520
521 fn next_word_pos(&self, pos: usize, at: At, word_def: Word, n: RepeatCount) -> Option<usize> {
522 if pos == self.buf.len() {
523 return None;
524 }
525 let mut wp = 0;
526 let mut gis = self.buf[pos..].grapheme_indices(true);
527 let mut gi = if at == At::BeforeEnd {
528 gis.next()
530 } else {
531 None
532 };
533 'outer: for _ in 0..n {
534 wp = 0;
535 gi = gis.next();
536 'inner: loop {
537 if let Some((i, x)) = gi {
538 let gj = gis.next();
539 if let Some((j, y)) = gj {
540 if at == At::Start && is_start_of_word(word_def, x, y) {
541 wp = j;
542 break 'inner;
543 } else if at != At::Start && is_end_of_word(word_def, x, y) {
544 if word_def == Word::Emacs || at == At::AfterEnd {
545 wp = j;
546 } else {
547 wp = i;
548 }
549 break 'inner;
550 }
551 gi = gj;
552 } else {
553 break 'outer;
554 }
555 } else {
556 break 'outer;
557 }
558 }
559 }
560 if wp == 0 {
561 if word_def == Word::Emacs || at == At::AfterEnd {
562 Some(self.buf.len())
563 } else {
564 match gi {
565 Some((i, _)) if i != 0 => Some(i + pos),
566 _ => None,
567 }
568 }
569 } else {
570 Some(wp + pos)
571 }
572 }
573
574 pub fn move_to_next_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> bool {
576 if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
577 self.pos = pos;
578 true
579 } else {
580 false
581 }
582 }
583
584 pub fn move_to_line_up(&mut self, n: RepeatCount) -> bool {
586 match self.buf[..self.pos].rfind('\n') {
587 Some(off) => {
588 let column = self.buf[off + 1..self.pos].graphemes(true).count();
589
590 let mut dest_start = self.buf[..off].rfind('\n').map_or(0, |n| n + 1);
591 let mut dest_end = off;
592 for _ in 1..n {
593 if dest_start == 0 {
594 break;
595 }
596 dest_end = dest_start - 1;
597 dest_start = self.buf[..dest_end].rfind('\n').map_or(0, |n| n + 1);
598 }
599 let gidx = self.buf[dest_start..dest_end]
600 .grapheme_indices(true)
601 .nth(column);
602
603 self.pos = gidx.map_or(off, |(idx, _)| dest_start + idx); true
605 }
606 None => false,
607 }
608 }
609
610 fn n_lines_up(&self, n: RepeatCount) -> Option<(usize, usize)> {
614 let mut start = if let Some(off) = self.buf[..self.pos].rfind('\n') {
615 off + 1
616 } else {
617 return None;
618 };
619 let end = self.buf[self.pos..]
620 .find('\n')
621 .map_or_else(|| self.buf.len(), |x| self.pos + x + 1);
622 for _ in 0..n {
623 if let Some(off) = self.buf[..start - 1].rfind('\n') {
624 start = off + 1;
625 } else {
626 start = 0;
627 break;
628 }
629 }
630 Some((start, end))
631 }
632
633 fn n_lines_down(&self, n: RepeatCount) -> Option<(usize, usize)> {
637 let mut end = if let Some(off) = self.buf[self.pos..].find('\n') {
638 self.pos + off + 1
639 } else {
640 return None;
641 };
642 let start = self.buf[..self.pos].rfind('\n').unwrap_or(0);
643 for _ in 0..n {
644 if let Some(off) = self.buf[end..].find('\n') {
645 end = end + off + 1;
646 } else {
647 end = self.buf.len();
648 break;
649 };
650 }
651 Some((start, end))
652 }
653
654 pub fn move_to_line_down(&mut self, n: RepeatCount) -> bool {
656 match self.buf[self.pos..].find('\n') {
657 Some(off) => {
658 let line_start = self.buf[..self.pos].rfind('\n').map_or(0, |n| n + 1);
659 let column = self.buf[line_start..self.pos].graphemes(true).count();
660 let mut dest_start = self.pos + off + 1;
661 let mut dest_end = self.buf[dest_start..]
662 .find('\n')
663 .map_or_else(|| self.buf.len(), |v| dest_start + v);
664 for _ in 1..n {
665 if dest_end == self.buf.len() {
666 break;
667 }
668 dest_start = dest_end + 1;
669 dest_end = self.buf[dest_start..]
670 .find('\n')
671 .map_or_else(|| self.buf.len(), |v| dest_start + v);
672 }
673 self.pos = self.buf[dest_start..dest_end]
674 .grapheme_indices(true)
675 .nth(column)
676 .map_or(dest_end, |(idx, _)| dest_start + idx); debug_assert!(self.pos <= self.buf.len());
678 true
679 }
680 None => false,
681 }
682 }
683
684 fn search_char_pos(&self, cs: CharSearch, n: RepeatCount) -> Option<usize> {
685 let mut shift = 0;
686 let search_result = match cs {
687 CharSearch::Backward(c) | CharSearch::BackwardAfter(c) => self.buf[..self.pos]
688 .char_indices()
689 .rev()
690 .filter(|&(_, ch)| ch == c)
691 .take(n)
692 .last()
693 .map(|(i, _)| i),
694 CharSearch::Forward(c) | CharSearch::ForwardBefore(c) => {
695 if let Some(cc) = self.grapheme_at_cursor() {
696 shift = self.pos + cc.len();
697 if shift < self.buf.len() {
698 self.buf[shift..]
699 .char_indices()
700 .filter(|&(_, ch)| ch == c)
701 .take(n)
702 .last()
703 .map(|(i, _)| i)
704 } else {
705 None
706 }
707 } else {
708 None
709 }
710 }
711 };
712 search_result.map(|pos| match cs {
713 CharSearch::Backward(_) => pos,
714 CharSearch::BackwardAfter(c) => pos + c.len_utf8(),
715 CharSearch::Forward(_) => shift + pos,
716 CharSearch::ForwardBefore(_) => {
717 shift + pos
718 - self.buf[..shift + pos]
719 .chars()
720 .next_back()
721 .unwrap()
722 .len_utf8()
723 }
724 })
725 }
726
727 pub fn move_to(&mut self, cs: CharSearch, n: RepeatCount) -> bool {
730 if let Some(pos) = self.search_char_pos(cs, n) {
731 self.pos = pos;
732 true
733 } else {
734 false
735 }
736 }
737
738 pub fn delete_word<D: DeleteListener>(
741 &mut self,
742 at: At,
743 word_def: Word,
744 n: RepeatCount,
745 dl: &mut D,
746 ) -> bool {
747 if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
748 let start = self.pos;
749 self.drain(start..pos, Direction::Forward, dl);
750 true
751 } else {
752 false
753 }
754 }
755
756 pub fn delete_to<D: DeleteListener>(
758 &mut self,
759 cs: CharSearch,
760 n: RepeatCount,
761 dl: &mut D,
762 ) -> bool {
763 let search_result = match cs {
764 CharSearch::ForwardBefore(c) => self.search_char_pos(CharSearch::Forward(c), n),
765 _ => self.search_char_pos(cs, n),
766 };
767 if let Some(pos) = search_result {
768 match cs {
769 CharSearch::Backward(_) | CharSearch::BackwardAfter(_) => {
770 let end = self.pos;
771 self.pos = pos;
772 self.drain(pos..end, Direction::Backward, dl);
773 }
774 CharSearch::ForwardBefore(_) => {
775 let start = self.pos;
776 self.drain(start..pos, Direction::Forward, dl);
777 }
778 CharSearch::Forward(c) => {
779 let start = self.pos;
780 self.drain(start..pos + c.len_utf8(), Direction::Forward, dl);
781 }
782 };
783 true
784 } else {
785 false
786 }
787 }
788
789 fn skip_whitespace(&self) -> Option<usize> {
790 if self.pos == self.buf.len() {
791 return None;
792 }
793 self.buf[self.pos..]
794 .grapheme_indices(true)
795 .find_map(|(i, ch)| {
796 if ch.chars().all(char::is_alphanumeric) {
797 Some(i)
798 } else {
799 None
800 }
801 })
802 .map(|i| i + self.pos)
803 }
804
805 pub fn edit_word<C: ChangeListener>(&mut self, a: WordAction, cl: &mut C) -> bool {
807 if let Some(start) = self.skip_whitespace() {
808 if let Some(end) = self.next_word_pos(start, At::AfterEnd, Word::Emacs, 1) {
809 if start == end {
810 return false;
811 }
812 let word = self
813 .drain(start..end, Direction::default(), cl)
814 .collect::<String>();
815 let result = match a {
816 WordAction::Capitalize => {
817 let ch = word.graphemes(true).next().unwrap();
818 let cap = ch.to_uppercase();
819 cap + &word[ch.len()..].to_lowercase()
820 }
821 WordAction::Lowercase => word.to_lowercase(),
822 WordAction::Uppercase => word.to_uppercase(),
823 };
824 self.insert_str(start, &result, cl);
825 self.pos = start + result.len();
826 return true;
827 }
828 }
829 false
830 }
831
832 pub fn transpose_words<C: ChangeListener>(&mut self, n: RepeatCount, cl: &mut C) -> bool {
834 let word_def = Word::Emacs;
835 self.move_to_next_word(At::AfterEnd, word_def, n);
836 let w2_end = self.pos;
837 self.move_to_prev_word(word_def, 1);
838 let w2_beg = self.pos;
839 self.move_to_prev_word(word_def, n);
840 let w1_beg = self.pos;
841 self.move_to_next_word(At::AfterEnd, word_def, 1);
842 let w1_end = self.pos;
843 if w1_beg == w2_beg || w2_beg < w1_end {
844 return false;
845 }
846
847 let w1 = self.buf[w1_beg..w1_end].to_owned();
848
849 let w2 = self
850 .drain(w2_beg..w2_end, Direction::default(), cl)
851 .collect::<String>();
852 self.insert_str(w2_beg, &w1, cl);
853
854 self.drain(w1_beg..w1_end, Direction::default(), cl);
855 self.insert_str(w1_beg, &w2, cl);
856
857 self.pos = w2_end;
858 true
859 }
860
861 pub fn replace<C: ChangeListener>(&mut self, range: Range<usize>, text: &str, cl: &mut C) {
864 let start = range.start;
865 cl.replace(start, self.buf.index(range.clone()), text);
866 self.buf.drain(range);
867 if start == self.buf.len() {
868 self.buf.push_str(text);
869 } else {
870 self.buf.insert_str(start, text);
871 }
872 self.pos = start + text.len();
873 }
874
875 pub fn insert_str<C: ChangeListener>(&mut self, idx: usize, s: &str, cl: &mut C) -> bool {
878 cl.insert_str(idx, s);
879 if idx == self.buf.len() {
880 self.buf.push_str(s);
881 true
882 } else {
883 self.buf.insert_str(idx, s);
884 false
885 }
886 }
887
888 pub fn delete_range<D: DeleteListener>(&mut self, range: Range<usize>, dl: &mut D) {
890 self.set_pos(range.start);
891 self.drain(range, Direction::default(), dl);
892 }
893
894 fn drain<D: DeleteListener>(
895 &mut self,
896 range: Range<usize>,
897 dir: Direction,
898 dl: &mut D,
899 ) -> Drain<'_> {
900 dl.delete(range.start, &self.buf[range.start..range.end], dir);
901 self.buf.drain(range)
902 }
903
904 #[must_use]
907 pub fn copy(&self, mvt: &Movement) -> Option<String> {
908 if self.is_empty() {
909 return None;
910 }
911 match *mvt {
912 Movement::WholeLine => {
913 let start = self.start_of_line();
914 let end = self.end_of_line();
915 if start == end {
916 None
917 } else {
918 Some(self.buf[start..self.pos].to_owned())
919 }
920 }
921 Movement::BeginningOfLine => {
922 let start = self.start_of_line();
923 if self.pos == start {
924 None
925 } else {
926 Some(self.buf[start..self.pos].to_owned())
927 }
928 }
929 Movement::ViFirstPrint => {
930 if self.pos == 0 {
931 None
932 } else {
933 self.next_word_pos(0, At::Start, Word::Big, 1)
934 .map(|pos| self.buf[pos..self.pos].to_owned())
935 }
936 }
937 Movement::EndOfLine => {
938 let end = self.end_of_line();
939 if self.pos == end {
940 None
941 } else {
942 Some(self.buf[self.pos..end].to_owned())
943 }
944 }
945 Movement::EndOfBuffer => {
946 if self.pos == self.buf.len() {
947 None
948 } else {
949 Some(self.buf[self.pos..].to_owned())
950 }
951 }
952 Movement::WholeBuffer => {
953 if self.buf.is_empty() {
954 None
955 } else {
956 Some(self.buf.clone())
957 }
958 }
959 Movement::BeginningOfBuffer => {
960 if self.pos == 0 {
961 None
962 } else {
963 Some(self.buf[..self.pos].to_owned())
964 }
965 }
966 Movement::BackwardWord(n, word_def) => self
967 .prev_word_pos(self.pos, word_def, n)
968 .map(|pos| self.buf[pos..self.pos].to_owned()),
969 Movement::ForwardWord(n, at, word_def) => self
970 .next_word_pos(self.pos, at, word_def, n)
971 .map(|pos| self.buf[self.pos..pos].to_owned()),
972 Movement::ViCharSearch(n, cs) => {
973 let search_result = match cs {
974 CharSearch::ForwardBefore(c) => self.search_char_pos(CharSearch::Forward(c), n),
975 _ => self.search_char_pos(cs, n),
976 };
977 search_result.map(|pos| match cs {
978 CharSearch::Backward(_) | CharSearch::BackwardAfter(_) => {
979 self.buf[pos..self.pos].to_owned()
980 }
981 CharSearch::ForwardBefore(_) => self.buf[self.pos..pos].to_owned(),
982 CharSearch::Forward(c) => self.buf[self.pos..pos + c.len_utf8()].to_owned(),
983 })
984 }
985 Movement::BackwardChar(n) => self
986 .prev_pos(n)
987 .map(|pos| self.buf[pos..self.pos].to_owned()),
988 Movement::ForwardChar(n) => self
989 .next_pos(n)
990 .map(|pos| self.buf[self.pos..pos].to_owned()),
991 Movement::LineUp(n) => {
992 if let Some((start, end)) = self.n_lines_up(n) {
993 Some(self.buf[start..end].to_owned())
994 } else {
995 None
996 }
997 }
998 Movement::LineDown(n) => {
999 if let Some((start, end)) = self.n_lines_down(n) {
1000 Some(self.buf[start..end].to_owned())
1001 } else {
1002 None
1003 }
1004 }
1005 }
1006 }
1007
1008 pub fn kill<D: DeleteListener>(&mut self, mvt: &Movement, dl: &mut D) -> bool {
1010 let notify = !matches!(*mvt, Movement::ForwardChar(_) | Movement::BackwardChar(_));
1011 if notify {
1012 dl.start_killing();
1013 }
1014 let killed = match *mvt {
1015 Movement::ForwardChar(n) => {
1016 self.delete(n, dl).is_some()
1018 }
1019 Movement::BackwardChar(n) => {
1020 self.backspace(n, dl)
1022 }
1023 Movement::EndOfLine => {
1024 self.kill_line(dl)
1026 }
1027 Movement::WholeLine => {
1028 self.move_home();
1029 self.kill_line(dl)
1030 }
1031 Movement::BeginningOfLine => {
1032 self.discard_line(dl)
1034 }
1035 Movement::BackwardWord(n, word_def) => {
1036 self.delete_prev_word(word_def, n, dl)
1038 }
1039 Movement::ForwardWord(n, at, word_def) => {
1040 self.delete_word(at, word_def, n, dl)
1042 }
1043 Movement::ViCharSearch(n, cs) => self.delete_to(cs, n, dl),
1044 Movement::LineUp(n) => {
1045 if let Some((start, end)) = self.n_lines_up(n) {
1046 self.delete_range(start..end, dl);
1047 true
1048 } else {
1049 false
1050 }
1051 }
1052 Movement::LineDown(n) => {
1053 if let Some((start, end)) = self.n_lines_down(n) {
1054 self.delete_range(start..end, dl);
1055 true
1056 } else {
1057 false
1058 }
1059 }
1060 Movement::ViFirstPrint => {
1061 false }
1063 Movement::EndOfBuffer => {
1064 self.kill_buffer(dl)
1066 }
1067 Movement::BeginningOfBuffer => {
1068 self.discard_buffer(dl)
1070 }
1071 Movement::WholeBuffer => {
1072 self.move_buffer_start();
1073 self.kill_buffer(dl)
1074 }
1075 };
1076 if notify {
1077 dl.stop_killing();
1078 }
1079 killed
1080 }
1081
1082 pub fn indent<C: ChangeListener>(
1084 &mut self,
1085 mvt: &Movement,
1086 amount: usize,
1087 dedent: bool,
1088 cl: &mut C,
1089 ) -> bool {
1090 let pair = match *mvt {
1091 Movement::WholeLine
1093 | Movement::BeginningOfLine
1094 | Movement::ViFirstPrint
1095 | Movement::EndOfLine
1096 | Movement::BackwardChar(..)
1097 | Movement::ForwardChar(..)
1098 | Movement::ViCharSearch(..) => Some((self.pos, self.pos)),
1099 Movement::EndOfBuffer => Some((self.pos, self.buf.len())),
1100 Movement::WholeBuffer => Some((0, self.buf.len())),
1101 Movement::BeginningOfBuffer => Some((0, self.pos)),
1102 Movement::BackwardWord(n, word_def) => self
1103 .prev_word_pos(self.pos, word_def, n)
1104 .map(|pos| (pos, self.pos)),
1105 Movement::ForwardWord(n, at, word_def) => self
1106 .next_word_pos(self.pos, at, word_def, n)
1107 .map(|pos| (self.pos, pos)),
1108 Movement::LineUp(n) => self.n_lines_up(n),
1109 Movement::LineDown(n) => self.n_lines_down(n),
1110 };
1111 let (start, end) = pair.unwrap_or((self.pos, self.pos));
1112 let start = self.buf[..start].rfind('\n').map_or(0, |pos| pos + 1);
1113 let end = self.buf[end..]
1114 .rfind('\n')
1115 .map_or_else(|| self.buf.len(), |pos| end + pos);
1116 let mut index = start;
1117 if dedent {
1118 #[expect(clippy::unnecessary_to_owned)]
1119 for line in self.buf[start..end].to_string().split('\n') {
1120 let max = line.len() - line.trim_start().len();
1121 let deleting = min(max, amount);
1122 self.drain(index..index + deleting, Direction::default(), cl);
1123 if self.pos >= index {
1124 if self.pos.saturating_sub(index) < deleting {
1125 self.pos = index;
1127 } else {
1128 self.pos -= deleting;
1129 }
1130 }
1131 index += line.len() + 1 - deleting;
1132 }
1133 } else {
1134 #[expect(clippy::unnecessary_to_owned)]
1135 for line in self.buf[start..end].to_string().split('\n') {
1136 for off in (0..amount).step_by(INDENT.len()) {
1137 self.insert_str(index, &INDENT[..min(amount - off, INDENT.len())], cl);
1138 }
1139 if self.pos >= index {
1140 self.pos += amount;
1141 }
1142 index += amount + line.len() + 1;
1143 }
1144 }
1145 true
1146 }
1147}
1148
1149impl Deref for LineBuffer {
1150 type Target = str;
1151
1152 fn deref(&self) -> &str {
1153 self.as_str()
1154 }
1155}
1156
1157fn is_start_of_word(word_def: Word, previous: &str, grapheme: &str) -> bool {
1158 (!is_word_char(word_def, previous) && is_word_char(word_def, grapheme))
1159 || (word_def == Word::Vi && !is_other_char(previous) && is_other_char(grapheme))
1160}
1161fn is_end_of_word(word_def: Word, grapheme: &str, next: &str) -> bool {
1162 (!is_word_char(word_def, next) && is_word_char(word_def, grapheme))
1163 || (word_def == Word::Vi && !is_other_char(next) && is_other_char(grapheme))
1164}
1165
1166fn is_word_char(word_def: Word, grapheme: &str) -> bool {
1167 match word_def {
1168 Word::Emacs => grapheme.chars().all(char::is_alphanumeric),
1169 Word::Vi => is_vi_word_char(grapheme),
1170 Word::Big => !grapheme.chars().any(char::is_whitespace),
1171 }
1172}
1173fn is_vi_word_char(grapheme: &str) -> bool {
1174 grapheme.chars().all(char::is_alphanumeric) || grapheme == "_"
1175}
1176fn is_other_char(grapheme: &str) -> bool {
1177 !(grapheme.chars().any(char::is_whitespace) || is_vi_word_char(grapheme))
1178}
1179
1180#[cfg(test)]
1181mod test {
1182 use super::{
1183 ChangeListener, DeleteListener, Direction, LineBuffer, NoListener, WordAction, MAX_LINE,
1184 };
1185 use crate::keymap::{At, CharSearch, Word};
1186
1187 struct Listener {
1188 deleted_str: Option<String>,
1189 }
1190
1191 impl Listener {
1192 fn new() -> Self {
1193 Self { deleted_str: None }
1194 }
1195
1196 fn assert_deleted_str_eq(&self, expected: &str) {
1197 let actual = self.deleted_str.as_ref().expect("no deleted string");
1198 assert_eq!(expected, actual)
1199 }
1200 }
1201
1202 impl DeleteListener for Listener {
1203 fn delete(&mut self, _: usize, string: &str, _: Direction) {
1204 self.deleted_str = Some(string.to_owned());
1205 }
1206 }
1207 impl ChangeListener for Listener {
1208 fn insert_char(&mut self, _: usize, _: char) {}
1209
1210 fn insert_str(&mut self, _: usize, _: &str) {}
1211
1212 fn replace(&mut self, _: usize, _: &str, _: &str) {}
1213 }
1214
1215 #[test]
1216 fn next_pos() {
1217 let s = LineBuffer::init("ö̲g̈", 0);
1218 assert_eq!(7, s.len());
1219 let pos = s.next_pos(1);
1220 assert_eq!(Some(4), pos);
1221
1222 let s = LineBuffer::init("ö̲g̈", 4);
1223 let pos = s.next_pos(1);
1224 assert_eq!(Some(7), pos);
1225 }
1226
1227 #[test]
1228 fn prev_pos() {
1229 let s = LineBuffer::init("ö̲g̈", 4);
1230 assert_eq!(7, s.len());
1231 let pos = s.prev_pos(1);
1232 assert_eq!(Some(0), pos);
1233
1234 let s = LineBuffer::init("ö̲g̈", 7);
1235 let pos = s.prev_pos(1);
1236 assert_eq!(Some(4), pos);
1237 }
1238
1239 #[test]
1240 fn insert() {
1241 let mut s = LineBuffer::with_capacity(MAX_LINE);
1242 let push = s.insert('α', 1, &mut NoListener).unwrap();
1243 assert_eq!("α", s.buf);
1244 assert_eq!(2, s.pos);
1245 assert!(push);
1246
1247 let push = s.insert('ß', 1, &mut NoListener).unwrap();
1248 assert_eq!("αß", s.buf);
1249 assert_eq!(4, s.pos);
1250 assert!(push);
1251
1252 s.pos = 0;
1253 let push = s.insert('γ', 1, &mut NoListener).unwrap();
1254 assert_eq!("γαß", s.buf);
1255 assert_eq!(2, s.pos);
1256 assert!(!push);
1257 }
1258
1259 #[test]
1260 fn yank_after() {
1261 let mut s = LineBuffer::init("αß", 2);
1262 s.move_forward(1);
1263 let ok = s.yank("γδε", 1, &mut NoListener);
1264 assert_eq!(Some(true), ok);
1265 assert_eq!("αßγδε", s.buf);
1266 assert_eq!(10, s.pos);
1267 }
1268
1269 #[test]
1270 fn yank_before() {
1271 let mut s = LineBuffer::init("αε", 2);
1272 let ok = s.yank("ßγδ", 1, &mut NoListener);
1273 assert_eq!(Some(false), ok);
1274 assert_eq!("αßγδε", s.buf);
1275 assert_eq!(8, s.pos);
1276 }
1277
1278 #[test]
1279 fn moves() {
1280 let mut s = LineBuffer::init("αß", 4);
1281 let ok = s.move_backward(1);
1282 assert_eq!("αß", s.buf);
1283 assert_eq!(2, s.pos);
1284 assert!(ok);
1285
1286 let ok = s.move_forward(1);
1287 assert_eq!("αß", s.buf);
1288 assert_eq!(4, s.pos);
1289 assert!(ok);
1290
1291 let ok = s.move_home();
1292 assert_eq!("αß", s.buf);
1293 assert_eq!(0, s.pos);
1294 assert!(ok);
1295
1296 let ok = s.move_end();
1297 assert_eq!("αß", s.buf);
1298 assert_eq!(4, s.pos);
1299 assert!(ok);
1300 }
1301
1302 #[test]
1303 fn move_home_end_multiline() {
1304 let text = "αa\nsdf ßc\nasdf";
1305 let mut s = LineBuffer::init(text, 7);
1306 let ok = s.move_home();
1307 assert_eq!(text, s.buf);
1308 assert_eq!(4, s.pos);
1309 assert!(ok);
1310
1311 let ok = s.move_home();
1312 assert_eq!(text, s.buf);
1313 assert_eq!(4, s.pos);
1314 assert!(!ok);
1315
1316 let ok = s.move_end();
1317 assert_eq!(text, s.buf);
1318 assert_eq!(11, s.pos);
1319 assert!(ok);
1320
1321 let ok = s.move_end();
1322 assert_eq!(text, s.buf);
1323 assert_eq!(11, s.pos);
1324 assert!(!ok);
1325 }
1326
1327 #[test]
1328 fn move_buffer_multiline() {
1329 let text = "αa\nsdf ßc\nasdf";
1330 let mut s = LineBuffer::init(text, 7);
1331 let ok = s.move_buffer_start();
1332 assert_eq!(text, s.buf);
1333 assert_eq!(0, s.pos);
1334 assert!(ok);
1335
1336 let ok = s.move_buffer_start();
1337 assert_eq!(text, s.buf);
1338 assert_eq!(0, s.pos);
1339 assert!(!ok);
1340
1341 let ok = s.move_buffer_end();
1342 assert_eq!(text, s.buf);
1343 assert_eq!(text.len(), s.pos);
1344 assert!(ok);
1345
1346 let ok = s.move_buffer_end();
1347 assert_eq!(text, s.buf);
1348 assert_eq!(text.len(), s.pos);
1349 assert!(!ok);
1350 }
1351
1352 #[test]
1353 fn move_grapheme() {
1354 let mut s = LineBuffer::init("ag̈", 4);
1355 assert_eq!(4, s.len());
1356 let ok = s.move_backward(1);
1357 assert!(ok);
1358 assert_eq!(1, s.pos);
1359
1360 let ok = s.move_forward(1);
1361 assert!(ok);
1362 assert_eq!(4, s.pos);
1363 }
1364
1365 #[test]
1366 fn delete() {
1367 let mut cl = Listener::new();
1368 let mut s = LineBuffer::init("αß", 2);
1369 let chars = s.delete(1, &mut cl);
1370 assert_eq!("α", s.buf);
1371 assert_eq!(2, s.pos);
1372 assert_eq!(Some("ß".to_owned()), chars);
1373
1374 let ok = s.backspace(1, &mut cl);
1375 assert_eq!("", s.buf);
1376 assert_eq!(0, s.pos);
1377 assert!(ok);
1378 cl.assert_deleted_str_eq("α");
1379 }
1380
1381 #[test]
1382 fn kill() {
1383 let mut cl = Listener::new();
1384 let mut s = LineBuffer::init("αßγδε", 6);
1385 let ok = s.kill_line(&mut cl);
1386 assert_eq!("αßγ", s.buf);
1387 assert_eq!(6, s.pos);
1388 assert!(ok);
1389 cl.assert_deleted_str_eq("δε");
1390
1391 s.pos = 4;
1392 let ok = s.discard_line(&mut cl);
1393 assert_eq!("γ", s.buf);
1394 assert_eq!(0, s.pos);
1395 assert!(ok);
1396 cl.assert_deleted_str_eq("αß");
1397 }
1398
1399 #[test]
1400 fn kill_multiline() {
1401 let mut cl = Listener::new();
1402 let mut s = LineBuffer::init("αß\nγδ 12\nε f4", 7);
1403
1404 let ok = s.kill_line(&mut cl);
1405 assert_eq!("αß\nγ\nε f4", s.buf);
1406 assert_eq!(7, s.pos);
1407 assert!(ok);
1408 cl.assert_deleted_str_eq("δ 12");
1409
1410 let ok = s.kill_line(&mut cl);
1411 assert_eq!("αß\nγε f4", s.buf);
1412 assert_eq!(7, s.pos);
1413 assert!(ok);
1414 cl.assert_deleted_str_eq("\n");
1415
1416 let ok = s.kill_line(&mut cl);
1417 assert_eq!("αß\nγ", s.buf);
1418 assert_eq!(7, s.pos);
1419 assert!(ok);
1420 cl.assert_deleted_str_eq("ε f4");
1421
1422 let ok = s.kill_line(&mut cl);
1423 assert_eq!(7, s.pos);
1424 assert!(!ok);
1425 }
1426
1427 #[test]
1428 fn discard_multiline() {
1429 let mut cl = Listener::new();
1430 let mut s = LineBuffer::init("αß\nc γδε", 9);
1431
1432 let ok = s.discard_line(&mut cl);
1433 assert_eq!("αß\nδε", s.buf);
1434 assert_eq!(5, s.pos);
1435 assert!(ok);
1436 cl.assert_deleted_str_eq("c γ");
1437
1438 let ok = s.discard_line(&mut cl);
1439 assert_eq!("αßδε", s.buf);
1440 assert_eq!(4, s.pos);
1441 assert!(ok);
1442 cl.assert_deleted_str_eq("\n");
1443
1444 let ok = s.discard_line(&mut cl);
1445 assert_eq!("δε", s.buf);
1446 assert_eq!(0, s.pos);
1447 assert!(ok);
1448 cl.assert_deleted_str_eq("αß");
1449
1450 let ok = s.discard_line(&mut cl);
1451 assert_eq!(0, s.pos);
1452 assert!(!ok);
1453 }
1454
1455 #[test]
1456 fn transpose() {
1457 let mut s = LineBuffer::init("aßc", 1);
1458 let ok = s.transpose_chars(&mut NoListener);
1459 assert_eq!("ßac", s.buf);
1460 assert_eq!(3, s.pos);
1461 assert!(ok);
1462
1463 s.buf = String::from("aßc");
1464 s.pos = 3;
1465 let ok = s.transpose_chars(&mut NoListener);
1466 assert_eq!("acß", s.buf);
1467 assert_eq!(4, s.pos);
1468 assert!(ok);
1469
1470 s.buf = String::from("aßc");
1471 s.pos = 4;
1472 let ok = s.transpose_chars(&mut NoListener);
1473 assert_eq!("acß", s.buf);
1474 assert_eq!(4, s.pos);
1475 assert!(ok);
1476 }
1477
1478 #[test]
1479 fn move_to_prev_word() {
1480 let mut s = LineBuffer::init("a ß c", 6); let ok = s.move_to_prev_word(Word::Emacs, 1);
1482 assert_eq!("a ß c", s.buf);
1483 assert_eq!(2, s.pos); assert!(ok);
1485
1486 assert!(s.move_end()); assert_eq!(7, s.pos);
1488 let ok = s.move_to_prev_word(Word::Emacs, 1);
1489 assert!(ok);
1490 assert_eq!(6, s.pos); let ok = s.move_to_prev_word(Word::Emacs, 2);
1493 assert!(ok);
1494 assert_eq!(0, s.pos);
1495 }
1496
1497 #[test]
1498 fn move_to_prev_vi_word() {
1499 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
1500 let ok = s.move_to_prev_word(Word::Vi, 1);
1501 assert!(ok);
1502 assert_eq!(17, s.pos);
1503 let ok = s.move_to_prev_word(Word::Vi, 1);
1504 assert!(ok);
1505 assert_eq!(15, s.pos);
1506 let ok = s.move_to_prev_word(Word::Vi, 1);
1507 assert!(ok);
1508 assert_eq!(12, s.pos);
1509 let ok = s.move_to_prev_word(Word::Vi, 1);
1510 assert!(ok);
1511 assert_eq!(11, s.pos);
1512 let ok = s.move_to_prev_word(Word::Vi, 1);
1513 assert!(ok);
1514 assert_eq!(7, s.pos);
1515 let ok = s.move_to_prev_word(Word::Vi, 1);
1516 assert!(ok);
1517 assert_eq!(6, s.pos);
1518 let ok = s.move_to_prev_word(Word::Vi, 1);
1519 assert!(ok);
1520 assert_eq!(0, s.pos);
1521 let ok = s.move_to_prev_word(Word::Vi, 1);
1522 assert!(!ok);
1523 }
1524
1525 #[test]
1526 fn move_to_prev_big_word() {
1527 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
1528 let ok = s.move_to_prev_word(Word::Big, 1);
1529 assert!(ok);
1530 assert_eq!(17, s.pos);
1531 let ok = s.move_to_prev_word(Word::Big, 1);
1532 assert!(ok);
1533 assert_eq!(6, s.pos);
1534 let ok = s.move_to_prev_word(Word::Big, 1);
1535 assert!(ok);
1536 assert_eq!(0, s.pos);
1537 let ok = s.move_to_prev_word(Word::Big, 1);
1538 assert!(!ok);
1539 }
1540
1541 #[test]
1542 fn move_to_forward() {
1543 let mut s = LineBuffer::init("αßγδε", 2);
1544 let ok = s.move_to(CharSearch::ForwardBefore('ε'), 1);
1545 assert!(ok);
1546 assert_eq!(6, s.pos);
1547
1548 let mut s = LineBuffer::init("αßγδε", 2);
1549 let ok = s.move_to(CharSearch::Forward('ε'), 1);
1550 assert!(ok);
1551 assert_eq!(8, s.pos);
1552
1553 let mut s = LineBuffer::init("αßγδε", 2);
1554 let ok = s.move_to(CharSearch::Forward('ε'), 10);
1555 assert!(ok);
1556 assert_eq!(8, s.pos);
1557 }
1558
1559 #[test]
1560 fn move_to_backward() {
1561 let mut s = LineBuffer::init("αßγδε", 8);
1562 let ok = s.move_to(CharSearch::BackwardAfter('ß'), 1);
1563 assert!(ok);
1564 assert_eq!(4, s.pos);
1565
1566 let mut s = LineBuffer::init("αßγδε", 8);
1567 let ok = s.move_to(CharSearch::Backward('ß'), 1);
1568 assert!(ok);
1569 assert_eq!(2, s.pos);
1570 }
1571
1572 #[test]
1573 fn delete_prev_word() {
1574 let mut cl = Listener::new();
1575 let mut s = LineBuffer::init("a ß c", 6);
1576 let ok = s.delete_prev_word(Word::Big, 1, &mut cl);
1577 assert_eq!("a c", s.buf);
1578 assert_eq!(2, s.pos);
1579 assert!(ok);
1580 cl.assert_deleted_str_eq("ß ");
1581 }
1582
1583 #[test]
1584 fn move_to_next_word() {
1585 let mut s = LineBuffer::init("a ß c", 1); let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1587 assert_eq!("a ß c", s.buf);
1588 assert!(ok);
1589 assert_eq!(4, s.pos); let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1592 assert!(ok);
1593 assert_eq!(7, s.pos); s.move_home();
1596 let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1597 assert!(ok);
1598 assert_eq!(1, s.pos); let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 2);
1601 assert!(ok);
1602 assert_eq!(7, s.pos); }
1604
1605 #[test]
1606 fn move_to_end_of_word() {
1607 let mut s = LineBuffer::init("a ßeta c", 1);
1608 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1609 assert_eq!("a ßeta c", s.buf);
1610 assert_eq!(6, s.pos);
1611 assert!(ok);
1612 }
1613
1614 #[test]
1615 fn move_to_end_of_vi_word() {
1616 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1617 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1618 assert!(ok);
1619 assert_eq!(4, s.pos);
1620 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1621 assert!(ok);
1622 assert_eq!(6, s.pos);
1623 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1624 assert!(ok);
1625 assert_eq!(10, s.pos);
1626 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1627 assert!(ok);
1628 assert_eq!(11, s.pos);
1629 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1630 assert!(ok);
1631 assert_eq!(14, s.pos);
1632 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1633 assert!(ok);
1634 assert_eq!(15, s.pos);
1635 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1636 assert!(ok);
1637 assert_eq!(18, s.pos);
1638 let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1639 assert!(!ok);
1640 }
1641
1642 #[test]
1643 fn move_to_end_of_big_word() {
1644 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1645 let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1646 assert!(ok);
1647 assert_eq!(4, s.pos);
1648 let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1649 assert!(ok);
1650 assert_eq!(15, s.pos);
1651 let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1652 assert!(ok);
1653 assert_eq!(18, s.pos);
1654 let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1655 assert!(!ok);
1656 }
1657
1658 #[test]
1659 fn move_to_start_of_word() {
1660 let mut s = LineBuffer::init("a ß c", 2);
1661 let ok = s.move_to_next_word(At::Start, Word::Emacs, 1);
1662 assert_eq!("a ß c", s.buf);
1663 assert_eq!(6, s.pos);
1664 assert!(ok);
1665 }
1666
1667 #[test]
1668 fn move_to_start_of_vi_word() {
1669 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1670 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1671 assert!(ok);
1672 assert_eq!(6, s.pos);
1673 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1674 assert!(ok);
1675 assert_eq!(7, s.pos);
1676 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1677 assert!(ok);
1678 assert_eq!(11, s.pos);
1679 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1680 assert!(ok);
1681 assert_eq!(12, s.pos);
1682 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1683 assert!(ok);
1684 assert_eq!(15, s.pos);
1685 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1686 assert!(ok);
1687 assert_eq!(17, s.pos);
1688 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1689 assert!(ok);
1690 assert_eq!(18, s.pos);
1691 let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1692 assert!(!ok);
1693 }
1694
1695 #[test]
1696 fn move_to_start_of_big_word() {
1697 let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1698 let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1699 assert!(ok);
1700 assert_eq!(6, s.pos);
1701 let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1702 assert!(ok);
1703 assert_eq!(17, s.pos);
1704 let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1705 assert!(ok);
1706 assert_eq!(18, s.pos);
1707 let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1708 assert!(!ok);
1709 }
1710
1711 #[test]
1712 fn delete_word() {
1713 let mut cl = Listener::new();
1714 let mut s = LineBuffer::init("a ß c", 1);
1715 let ok = s.delete_word(At::AfterEnd, Word::Emacs, 1, &mut cl);
1716 assert_eq!("a c", s.buf);
1717 assert_eq!(1, s.pos);
1718 assert!(ok);
1719 cl.assert_deleted_str_eq(" ß");
1720
1721 let mut s = LineBuffer::init("test", 0);
1722 let ok = s.delete_word(At::AfterEnd, Word::Vi, 1, &mut cl);
1723 assert_eq!("", s.buf);
1724 assert_eq!(0, s.pos);
1725 assert!(ok);
1726 cl.assert_deleted_str_eq("test");
1727 }
1728
1729 #[test]
1730 fn delete_til_start_of_word() {
1731 let mut cl = Listener::new();
1732 let mut s = LineBuffer::init("a ß c", 2);
1733 let ok = s.delete_word(At::Start, Word::Emacs, 1, &mut cl);
1734 assert_eq!("a c", s.buf);
1735 assert_eq!(2, s.pos);
1736 assert!(ok);
1737 cl.assert_deleted_str_eq("ß ");
1738 }
1739
1740 #[test]
1741 fn delete_to_forward() {
1742 let mut cl = Listener::new();
1743 let mut s = LineBuffer::init("αßγδε", 2);
1744 let ok = s.delete_to(CharSearch::ForwardBefore('ε'), 1, &mut cl);
1745 assert!(ok);
1746 cl.assert_deleted_str_eq("ßγδ");
1747 assert_eq!("αε", s.buf);
1748 assert_eq!(2, s.pos);
1749
1750 let mut s = LineBuffer::init("αßγδε", 2);
1751 let ok = s.delete_to(CharSearch::Forward('ε'), 1, &mut cl);
1752 assert!(ok);
1753 cl.assert_deleted_str_eq("ßγδε");
1754 assert_eq!("α", s.buf);
1755 assert_eq!(2, s.pos);
1756 }
1757
1758 #[test]
1759 fn delete_to_backward() {
1760 let mut cl = Listener::new();
1761 let mut s = LineBuffer::init("αßγδε", 8);
1762 let ok = s.delete_to(CharSearch::BackwardAfter('α'), 1, &mut cl);
1763 assert!(ok);
1764 cl.assert_deleted_str_eq("ßγδ");
1765 assert_eq!("αε", s.buf);
1766 assert_eq!(2, s.pos);
1767
1768 let mut s = LineBuffer::init("αßγδε", 8);
1769 let ok = s.delete_to(CharSearch::Backward('ß'), 1, &mut cl);
1770 assert!(ok);
1771 cl.assert_deleted_str_eq("ßγδ");
1772 assert_eq!("αε", s.buf);
1773 assert_eq!(2, s.pos);
1774 }
1775
1776 #[test]
1777 fn edit_word() {
1778 let mut s = LineBuffer::init("a ßeta c", 1);
1779 assert!(s.edit_word(WordAction::Uppercase, &mut NoListener));
1780 assert_eq!("a SSETA c", s.buf);
1781 assert_eq!(7, s.pos);
1782
1783 let mut s = LineBuffer::init("a ßetA c", 1);
1784 assert!(s.edit_word(WordAction::Lowercase, &mut NoListener));
1785 assert_eq!("a ßeta c", s.buf);
1786 assert_eq!(7, s.pos);
1787
1788 let mut s = LineBuffer::init("a ßETA c", 1);
1789 assert!(s.edit_word(WordAction::Capitalize, &mut NoListener));
1790 assert_eq!("a SSeta c", s.buf);
1791 assert_eq!(7, s.pos);
1792
1793 let mut s = LineBuffer::init("test", 1);
1794 assert!(s.edit_word(WordAction::Capitalize, &mut NoListener));
1795 assert_eq!("tEst", s.buf);
1796 assert_eq!(4, s.pos);
1797 }
1798
1799 #[test]
1800 fn transpose_words() {
1801 let mut s = LineBuffer::init("ßeta / δelta__", 15);
1802 assert!(s.transpose_words(1, &mut NoListener));
1803 assert_eq!("δelta__ / ßeta", s.buf);
1804 assert_eq!(16, s.pos);
1805
1806 let mut s = LineBuffer::init("ßeta / δelta", 14);
1807 assert!(s.transpose_words(1, &mut NoListener));
1808 assert_eq!("δelta / ßeta", s.buf);
1809 assert_eq!(14, s.pos);
1810
1811 let mut s = LineBuffer::init(" / δelta", 8);
1812 assert!(!s.transpose_words(1, &mut NoListener));
1813
1814 let mut s = LineBuffer::init("ßeta / __", 9);
1815 assert!(!s.transpose_words(1, &mut NoListener));
1816 }
1817
1818 #[test]
1819 fn move_by_line() {
1820 let text = "aa123\nsdf bc\nasdf";
1821 let mut s = LineBuffer::init(text, 14);
1822 let ok = s.move_to_line_up(1);
1824 assert_eq!(7, s.pos);
1825 assert!(ok);
1826
1827 let ok = s.move_to_line_up(1);
1828 assert_eq!(1, s.pos);
1829 assert!(ok);
1830
1831 let ok = s.move_to_line_up(1);
1832 assert_eq!(1, s.pos);
1833 assert!(!ok);
1834
1835 let ok = s.move_to_line_down(1);
1837 assert_eq!(7, s.pos);
1838 assert!(ok);
1839
1840 let ok = s.move_to_line_down(1);
1841 assert_eq!(14, s.pos);
1842 assert!(ok);
1843
1844 let ok = s.move_to_line_down(1);
1845 assert_eq!(14, s.pos);
1846 assert!(!ok);
1847
1848 let ok = s.move_to_line_up(2);
1850 assert_eq!(1, s.pos);
1851 assert!(ok);
1852
1853 let ok = s.move_to_line_down(2);
1854 assert_eq!(14, s.pos);
1855 assert!(ok);
1856 }
1857
1858 #[test]
1859 fn test_send() {
1860 fn assert_send<T: Send>() {}
1861 assert_send::<LineBuffer>();
1862 }
1863
1864 #[test]
1865 fn test_sync() {
1866 fn assert_sync<T: Sync>() {}
1867 assert_sync::<LineBuffer>();
1868 }
1869}