brush_rustyline_fork/
line_buffer.rs

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