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