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