rustyline_with_hint_fix/
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            for line in self.buf[start..end].to_string().split('\n') {
1123                let max = line.len() - line.trim_start().len();
1124                let deleting = min(max, amount);
1125                self.drain(index..index + deleting, Direction::default(), cl);
1126                if self.pos >= index {
1127                    if self.pos.saturating_sub(index) < deleting {
1128                        // don't wrap into the previous line
1129                        self.pos = index;
1130                    } else {
1131                        self.pos -= deleting;
1132                    }
1133                }
1134                index += line.len() + 1 - deleting;
1135            }
1136        } else {
1137            for line in self.buf[start..end].to_string().split('\n') {
1138                for off in (0..amount).step_by(INDENT.len()) {
1139                    self.insert_str(index, &INDENT[..min(amount - off, INDENT.len())], cl);
1140                }
1141                if self.pos >= index {
1142                    self.pos += amount;
1143                }
1144                index += amount + line.len() + 1;
1145            }
1146        }
1147        true
1148    }
1149}
1150
1151impl Deref for LineBuffer {
1152    type Target = str;
1153
1154    fn deref(&self) -> &str {
1155        self.as_str()
1156    }
1157}
1158
1159fn is_start_of_word(word_def: Word, previous: &str, grapheme: &str) -> bool {
1160    (!is_word_char(word_def, previous) && is_word_char(word_def, grapheme))
1161        || (word_def == Word::Vi && !is_other_char(previous) && is_other_char(grapheme))
1162}
1163fn is_end_of_word(word_def: Word, grapheme: &str, next: &str) -> bool {
1164    (!is_word_char(word_def, next) && is_word_char(word_def, grapheme))
1165        || (word_def == Word::Vi && !is_other_char(next) && is_other_char(grapheme))
1166}
1167
1168fn is_word_char(word_def: Word, grapheme: &str) -> bool {
1169    match word_def {
1170        Word::Emacs => grapheme.chars().all(char::is_alphanumeric),
1171        Word::Vi => is_vi_word_char(grapheme),
1172        Word::Big => !grapheme.chars().any(char::is_whitespace),
1173    }
1174}
1175fn is_vi_word_char(grapheme: &str) -> bool {
1176    grapheme.chars().all(char::is_alphanumeric) || grapheme == "_"
1177}
1178fn is_other_char(grapheme: &str) -> bool {
1179    !(grapheme.chars().any(char::is_whitespace) || is_vi_word_char(grapheme))
1180}
1181
1182#[cfg(test)]
1183mod test {
1184    use super::{
1185        ChangeListener, DeleteListener, Direction, LineBuffer, NoListener, WordAction, MAX_LINE,
1186    };
1187    use crate::keymap::{At, CharSearch, Word};
1188
1189    struct Listener {
1190        deleted_str: Option<String>,
1191    }
1192
1193    impl Listener {
1194        fn new() -> Listener {
1195            Listener { deleted_str: None }
1196        }
1197
1198        fn assert_deleted_str_eq(&self, expected: &str) {
1199            let actual = self.deleted_str.as_ref().expect("no deleted string");
1200            assert_eq!(expected, actual)
1201        }
1202    }
1203
1204    impl DeleteListener for Listener {
1205        fn delete(&mut self, _: usize, string: &str, _: Direction) {
1206            self.deleted_str = Some(string.to_owned());
1207        }
1208    }
1209    impl ChangeListener for Listener {
1210        fn insert_char(&mut self, _: usize, _: char) {}
1211
1212        fn insert_str(&mut self, _: usize, _: &str) {}
1213
1214        fn replace(&mut self, _: usize, _: &str, _: &str) {}
1215    }
1216
1217    #[test]
1218    fn next_pos() {
1219        let s = LineBuffer::init("ö̲g̈", 0);
1220        assert_eq!(7, s.len());
1221        let pos = s.next_pos(1);
1222        assert_eq!(Some(4), pos);
1223
1224        let s = LineBuffer::init("ö̲g̈", 4);
1225        let pos = s.next_pos(1);
1226        assert_eq!(Some(7), pos);
1227    }
1228
1229    #[test]
1230    fn prev_pos() {
1231        let s = LineBuffer::init("ö̲g̈", 4);
1232        assert_eq!(7, s.len());
1233        let pos = s.prev_pos(1);
1234        assert_eq!(Some(0), pos);
1235
1236        let s = LineBuffer::init("ö̲g̈", 7);
1237        let pos = s.prev_pos(1);
1238        assert_eq!(Some(4), pos);
1239    }
1240
1241    #[test]
1242    fn insert() {
1243        let mut s = LineBuffer::with_capacity(MAX_LINE);
1244        let push = s.insert('α', 1, &mut NoListener).unwrap();
1245        assert_eq!("α", s.buf);
1246        assert_eq!(2, s.pos);
1247        assert!(push);
1248
1249        let push = s.insert('ß', 1, &mut NoListener).unwrap();
1250        assert_eq!("αß", s.buf);
1251        assert_eq!(4, s.pos);
1252        assert!(push);
1253
1254        s.pos = 0;
1255        let push = s.insert('γ', 1, &mut NoListener).unwrap();
1256        assert_eq!("γαß", s.buf);
1257        assert_eq!(2, s.pos);
1258        assert!(!push);
1259    }
1260
1261    #[test]
1262    fn yank_after() {
1263        let mut s = LineBuffer::init("αß", 2);
1264        s.move_forward(1);
1265        let ok = s.yank("γδε", 1, &mut NoListener);
1266        assert_eq!(Some(true), ok);
1267        assert_eq!("αßγδε", s.buf);
1268        assert_eq!(10, s.pos);
1269    }
1270
1271    #[test]
1272    fn yank_before() {
1273        let mut s = LineBuffer::init("αε", 2);
1274        let ok = s.yank("ßγδ", 1, &mut NoListener);
1275        assert_eq!(Some(false), ok);
1276        assert_eq!("αßγδε", s.buf);
1277        assert_eq!(8, s.pos);
1278    }
1279
1280    #[test]
1281    fn moves() {
1282        let mut s = LineBuffer::init("αß", 4);
1283        let ok = s.move_backward(1);
1284        assert_eq!("αß", s.buf);
1285        assert_eq!(2, s.pos);
1286        assert!(ok);
1287
1288        let ok = s.move_forward(1);
1289        assert_eq!("αß", s.buf);
1290        assert_eq!(4, s.pos);
1291        assert!(ok);
1292
1293        let ok = s.move_home();
1294        assert_eq!("αß", s.buf);
1295        assert_eq!(0, s.pos);
1296        assert!(ok);
1297
1298        let ok = s.move_end();
1299        assert_eq!("αß", s.buf);
1300        assert_eq!(4, s.pos);
1301        assert!(ok);
1302    }
1303
1304    #[test]
1305    fn move_home_end_multiline() {
1306        let text = "αa\nsdf ßc\nasdf";
1307        let mut s = LineBuffer::init(text, 7);
1308        let ok = s.move_home();
1309        assert_eq!(text, s.buf);
1310        assert_eq!(4, s.pos);
1311        assert!(ok);
1312
1313        let ok = s.move_home();
1314        assert_eq!(text, s.buf);
1315        assert_eq!(4, s.pos);
1316        assert!(!ok);
1317
1318        let ok = s.move_end();
1319        assert_eq!(text, s.buf);
1320        assert_eq!(11, s.pos);
1321        assert!(ok);
1322
1323        let ok = s.move_end();
1324        assert_eq!(text, s.buf);
1325        assert_eq!(11, s.pos);
1326        assert!(!ok);
1327    }
1328
1329    #[test]
1330    fn move_buffer_multiline() {
1331        let text = "αa\nsdf ßc\nasdf";
1332        let mut s = LineBuffer::init(text, 7);
1333        let ok = s.move_buffer_start();
1334        assert_eq!(text, s.buf);
1335        assert_eq!(0, s.pos);
1336        assert!(ok);
1337
1338        let ok = s.move_buffer_start();
1339        assert_eq!(text, s.buf);
1340        assert_eq!(0, s.pos);
1341        assert!(!ok);
1342
1343        let ok = s.move_buffer_end();
1344        assert_eq!(text, s.buf);
1345        assert_eq!(text.len(), s.pos);
1346        assert!(ok);
1347
1348        let ok = s.move_buffer_end();
1349        assert_eq!(text, s.buf);
1350        assert_eq!(text.len(), s.pos);
1351        assert!(!ok);
1352    }
1353
1354    #[test]
1355    fn move_grapheme() {
1356        let mut s = LineBuffer::init("ag̈", 4);
1357        assert_eq!(4, s.len());
1358        let ok = s.move_backward(1);
1359        assert!(ok);
1360        assert_eq!(1, s.pos);
1361
1362        let ok = s.move_forward(1);
1363        assert!(ok);
1364        assert_eq!(4, s.pos);
1365    }
1366
1367    #[test]
1368    fn delete() {
1369        let mut cl = Listener::new();
1370        let mut s = LineBuffer::init("αß", 2);
1371        let chars = s.delete(1, &mut cl);
1372        assert_eq!("α", s.buf);
1373        assert_eq!(2, s.pos);
1374        assert_eq!(Some("ß".to_owned()), chars);
1375
1376        let ok = s.backspace(1, &mut cl);
1377        assert_eq!("", s.buf);
1378        assert_eq!(0, s.pos);
1379        assert!(ok);
1380        cl.assert_deleted_str_eq("α");
1381    }
1382
1383    #[test]
1384    fn kill() {
1385        let mut cl = Listener::new();
1386        let mut s = LineBuffer::init("αßγδε", 6);
1387        let ok = s.kill_line(&mut cl);
1388        assert_eq!("αßγ", s.buf);
1389        assert_eq!(6, s.pos);
1390        assert!(ok);
1391        cl.assert_deleted_str_eq("δε");
1392
1393        s.pos = 4;
1394        let ok = s.discard_line(&mut cl);
1395        assert_eq!("γ", s.buf);
1396        assert_eq!(0, s.pos);
1397        assert!(ok);
1398        cl.assert_deleted_str_eq("αß");
1399    }
1400
1401    #[test]
1402    fn kill_multiline() {
1403        let mut cl = Listener::new();
1404        let mut s = LineBuffer::init("αß\nγδ 12\nε f4", 7);
1405
1406        let ok = s.kill_line(&mut cl);
1407        assert_eq!("αß\nγ\nε f4", s.buf);
1408        assert_eq!(7, s.pos);
1409        assert!(ok);
1410        cl.assert_deleted_str_eq("δ 12");
1411
1412        let ok = s.kill_line(&mut cl);
1413        assert_eq!("αß\nγε f4", s.buf);
1414        assert_eq!(7, s.pos);
1415        assert!(ok);
1416        cl.assert_deleted_str_eq("\n");
1417
1418        let ok = s.kill_line(&mut cl);
1419        assert_eq!("αß\nγ", s.buf);
1420        assert_eq!(7, s.pos);
1421        assert!(ok);
1422        cl.assert_deleted_str_eq("ε f4");
1423
1424        let ok = s.kill_line(&mut cl);
1425        assert_eq!(7, s.pos);
1426        assert!(!ok);
1427    }
1428
1429    #[test]
1430    fn discard_multiline() {
1431        let mut cl = Listener::new();
1432        let mut s = LineBuffer::init("αß\nc γδε", 9);
1433
1434        let ok = s.discard_line(&mut cl);
1435        assert_eq!("αß\nδε", s.buf);
1436        assert_eq!(5, s.pos);
1437        assert!(ok);
1438        cl.assert_deleted_str_eq("c γ");
1439
1440        let ok = s.discard_line(&mut cl);
1441        assert_eq!("αßδε", s.buf);
1442        assert_eq!(4, s.pos);
1443        assert!(ok);
1444        cl.assert_deleted_str_eq("\n");
1445
1446        let ok = s.discard_line(&mut cl);
1447        assert_eq!("δε", s.buf);
1448        assert_eq!(0, s.pos);
1449        assert!(ok);
1450        cl.assert_deleted_str_eq("αß");
1451
1452        let ok = s.discard_line(&mut cl);
1453        assert_eq!(0, s.pos);
1454        assert!(!ok);
1455    }
1456
1457    #[test]
1458    fn transpose() {
1459        let mut s = LineBuffer::init("aßc", 1);
1460        let ok = s.transpose_chars(&mut NoListener);
1461        assert_eq!("ßac", s.buf);
1462        assert_eq!(3, s.pos);
1463        assert!(ok);
1464
1465        s.buf = String::from("aßc");
1466        s.pos = 3;
1467        let ok = s.transpose_chars(&mut NoListener);
1468        assert_eq!("acß", s.buf);
1469        assert_eq!(4, s.pos);
1470        assert!(ok);
1471
1472        s.buf = String::from("aßc");
1473        s.pos = 4;
1474        let ok = s.transpose_chars(&mut NoListener);
1475        assert_eq!("acß", s.buf);
1476        assert_eq!(4, s.pos);
1477        assert!(ok);
1478    }
1479
1480    #[test]
1481    fn move_to_prev_word() {
1482        let mut s = LineBuffer::init("a ß  c", 6); // before 'c'
1483        let ok = s.move_to_prev_word(Word::Emacs, 1);
1484        assert_eq!("a ß  c", s.buf);
1485        assert_eq!(2, s.pos); // before 'ß'
1486        assert!(ok);
1487
1488        assert!(s.move_end()); // after 'c'
1489        assert_eq!(7, s.pos);
1490        let ok = s.move_to_prev_word(Word::Emacs, 1);
1491        assert!(ok);
1492        assert_eq!(6, s.pos); // before 'c'
1493
1494        let ok = s.move_to_prev_word(Word::Emacs, 2);
1495        assert!(ok);
1496        assert_eq!(0, s.pos);
1497    }
1498
1499    #[test]
1500    fn move_to_prev_vi_word() {
1501        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
1502        let ok = s.move_to_prev_word(Word::Vi, 1);
1503        assert!(ok);
1504        assert_eq!(17, s.pos);
1505        let ok = s.move_to_prev_word(Word::Vi, 1);
1506        assert!(ok);
1507        assert_eq!(15, s.pos);
1508        let ok = s.move_to_prev_word(Word::Vi, 1);
1509        assert!(ok);
1510        assert_eq!(12, s.pos);
1511        let ok = s.move_to_prev_word(Word::Vi, 1);
1512        assert!(ok);
1513        assert_eq!(11, s.pos);
1514        let ok = s.move_to_prev_word(Word::Vi, 1);
1515        assert!(ok);
1516        assert_eq!(7, s.pos);
1517        let ok = s.move_to_prev_word(Word::Vi, 1);
1518        assert!(ok);
1519        assert_eq!(6, s.pos);
1520        let ok = s.move_to_prev_word(Word::Vi, 1);
1521        assert!(ok);
1522        assert_eq!(0, s.pos);
1523        let ok = s.move_to_prev_word(Word::Vi, 1);
1524        assert!(!ok);
1525    }
1526
1527    #[test]
1528    fn move_to_prev_big_word() {
1529        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19);
1530        let ok = s.move_to_prev_word(Word::Big, 1);
1531        assert!(ok);
1532        assert_eq!(17, s.pos);
1533        let ok = s.move_to_prev_word(Word::Big, 1);
1534        assert!(ok);
1535        assert_eq!(6, s.pos);
1536        let ok = s.move_to_prev_word(Word::Big, 1);
1537        assert!(ok);
1538        assert_eq!(0, s.pos);
1539        let ok = s.move_to_prev_word(Word::Big, 1);
1540        assert!(!ok);
1541    }
1542
1543    #[test]
1544    fn move_to_forward() {
1545        let mut s = LineBuffer::init("αßγδε", 2);
1546        let ok = s.move_to(CharSearch::ForwardBefore('ε'), 1);
1547        assert!(ok);
1548        assert_eq!(6, s.pos);
1549
1550        let mut s = LineBuffer::init("αßγδε", 2);
1551        let ok = s.move_to(CharSearch::Forward('ε'), 1);
1552        assert!(ok);
1553        assert_eq!(8, s.pos);
1554
1555        let mut s = LineBuffer::init("αßγδε", 2);
1556        let ok = s.move_to(CharSearch::Forward('ε'), 10);
1557        assert!(ok);
1558        assert_eq!(8, s.pos);
1559    }
1560
1561    #[test]
1562    fn move_to_backward() {
1563        let mut s = LineBuffer::init("αßγδε", 8);
1564        let ok = s.move_to(CharSearch::BackwardAfter('ß'), 1);
1565        assert!(ok);
1566        assert_eq!(4, s.pos);
1567
1568        let mut s = LineBuffer::init("αßγδε", 8);
1569        let ok = s.move_to(CharSearch::Backward('ß'), 1);
1570        assert!(ok);
1571        assert_eq!(2, s.pos);
1572    }
1573
1574    #[test]
1575    fn delete_prev_word() {
1576        let mut cl = Listener::new();
1577        let mut s = LineBuffer::init("a ß  c", 6);
1578        let ok = s.delete_prev_word(Word::Big, 1, &mut cl);
1579        assert_eq!("a c", s.buf);
1580        assert_eq!(2, s.pos);
1581        assert!(ok);
1582        cl.assert_deleted_str_eq("ß  ");
1583    }
1584
1585    #[test]
1586    fn move_to_next_word() {
1587        let mut s = LineBuffer::init("a ß  c", 1); // after 'a'
1588        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1589        assert_eq!("a ß  c", s.buf);
1590        assert!(ok);
1591        assert_eq!(4, s.pos); // after 'ß'
1592
1593        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1594        assert!(ok);
1595        assert_eq!(7, s.pos); // after 'c'
1596
1597        s.move_home();
1598        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1599        assert!(ok);
1600        assert_eq!(1, s.pos); // after 'a'
1601
1602        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 2);
1603        assert!(ok);
1604        assert_eq!(7, s.pos); // after 'c'
1605    }
1606
1607    #[test]
1608    fn move_to_end_of_word() {
1609        let mut s = LineBuffer::init("a ßeta  c", 1);
1610        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1611        assert_eq!("a ßeta  c", s.buf);
1612        assert_eq!(6, s.pos);
1613        assert!(ok);
1614    }
1615
1616    #[test]
1617    fn move_to_end_of_vi_word() {
1618        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1619        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1620        assert!(ok);
1621        assert_eq!(4, s.pos);
1622        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1623        assert!(ok);
1624        assert_eq!(6, s.pos);
1625        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1626        assert!(ok);
1627        assert_eq!(10, s.pos);
1628        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1629        assert!(ok);
1630        assert_eq!(11, s.pos);
1631        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1632        assert!(ok);
1633        assert_eq!(14, s.pos);
1634        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1635        assert!(ok);
1636        assert_eq!(15, s.pos);
1637        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1638        assert!(ok);
1639        assert_eq!(18, s.pos);
1640        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1641        assert!(!ok);
1642    }
1643
1644    #[test]
1645    fn move_to_end_of_big_word() {
1646        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1647        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1648        assert!(ok);
1649        assert_eq!(4, s.pos);
1650        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1651        assert!(ok);
1652        assert_eq!(15, s.pos);
1653        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1654        assert!(ok);
1655        assert_eq!(18, s.pos);
1656        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1657        assert!(!ok);
1658    }
1659
1660    #[test]
1661    fn move_to_start_of_word() {
1662        let mut s = LineBuffer::init("a ß  c", 2);
1663        let ok = s.move_to_next_word(At::Start, Word::Emacs, 1);
1664        assert_eq!("a ß  c", s.buf);
1665        assert_eq!(6, s.pos);
1666        assert!(ok);
1667    }
1668
1669    #[test]
1670    fn move_to_start_of_vi_word() {
1671        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1672        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1673        assert!(ok);
1674        assert_eq!(6, s.pos);
1675        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1676        assert!(ok);
1677        assert_eq!(7, s.pos);
1678        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1679        assert!(ok);
1680        assert_eq!(11, s.pos);
1681        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1682        assert!(ok);
1683        assert_eq!(12, s.pos);
1684        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1685        assert!(ok);
1686        assert_eq!(15, s.pos);
1687        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1688        assert!(ok);
1689        assert_eq!(17, s.pos);
1690        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1691        assert!(ok);
1692        assert_eq!(18, s.pos);
1693        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1694        assert!(!ok);
1695    }
1696
1697    #[test]
1698    fn move_to_start_of_big_word() {
1699        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0);
1700        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1701        assert!(ok);
1702        assert_eq!(6, s.pos);
1703        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1704        assert!(ok);
1705        assert_eq!(17, s.pos);
1706        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1707        assert!(ok);
1708        assert_eq!(18, s.pos);
1709        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1710        assert!(!ok);
1711    }
1712
1713    #[test]
1714    fn delete_word() {
1715        let mut cl = Listener::new();
1716        let mut s = LineBuffer::init("a ß  c", 1);
1717        let ok = s.delete_word(At::AfterEnd, Word::Emacs, 1, &mut cl);
1718        assert_eq!("a  c", s.buf);
1719        assert_eq!(1, s.pos);
1720        assert!(ok);
1721        cl.assert_deleted_str_eq(" ß");
1722
1723        let mut s = LineBuffer::init("test", 0);
1724        let ok = s.delete_word(At::AfterEnd, Word::Vi, 1, &mut cl);
1725        assert_eq!("", s.buf);
1726        assert_eq!(0, s.pos);
1727        assert!(ok);
1728        cl.assert_deleted_str_eq("test");
1729    }
1730
1731    #[test]
1732    fn delete_til_start_of_word() {
1733        let mut cl = Listener::new();
1734        let mut s = LineBuffer::init("a ß  c", 2);
1735        let ok = s.delete_word(At::Start, Word::Emacs, 1, &mut cl);
1736        assert_eq!("a c", s.buf);
1737        assert_eq!(2, s.pos);
1738        assert!(ok);
1739        cl.assert_deleted_str_eq("ß  ");
1740    }
1741
1742    #[test]
1743    fn delete_to_forward() {
1744        let mut cl = Listener::new();
1745        let mut s = LineBuffer::init("αßγδε", 2);
1746        let ok = s.delete_to(CharSearch::ForwardBefore('ε'), 1, &mut cl);
1747        assert!(ok);
1748        cl.assert_deleted_str_eq("ßγδ");
1749        assert_eq!("αε", s.buf);
1750        assert_eq!(2, s.pos);
1751
1752        let mut s = LineBuffer::init("αßγδε", 2);
1753        let ok = s.delete_to(CharSearch::Forward('ε'), 1, &mut cl);
1754        assert!(ok);
1755        cl.assert_deleted_str_eq("ßγδε");
1756        assert_eq!("α", s.buf);
1757        assert_eq!(2, s.pos);
1758    }
1759
1760    #[test]
1761    fn delete_to_backward() {
1762        let mut cl = Listener::new();
1763        let mut s = LineBuffer::init("αßγδε", 8);
1764        let ok = s.delete_to(CharSearch::BackwardAfter('α'), 1, &mut cl);
1765        assert!(ok);
1766        cl.assert_deleted_str_eq("ßγδ");
1767        assert_eq!("αε", s.buf);
1768        assert_eq!(2, s.pos);
1769
1770        let mut s = LineBuffer::init("αßγδε", 8);
1771        let ok = s.delete_to(CharSearch::Backward('ß'), 1, &mut cl);
1772        assert!(ok);
1773        cl.assert_deleted_str_eq("ßγδ");
1774        assert_eq!("αε", s.buf);
1775        assert_eq!(2, s.pos);
1776    }
1777
1778    #[test]
1779    fn edit_word() {
1780        let mut s = LineBuffer::init("a ßeta  c", 1);
1781        assert!(s.edit_word(WordAction::Uppercase, &mut NoListener));
1782        assert_eq!("a SSETA  c", s.buf);
1783        assert_eq!(7, s.pos);
1784
1785        let mut s = LineBuffer::init("a ßetA  c", 1);
1786        assert!(s.edit_word(WordAction::Lowercase, &mut NoListener));
1787        assert_eq!("a ßeta  c", s.buf);
1788        assert_eq!(7, s.pos);
1789
1790        let mut s = LineBuffer::init("a ßETA  c", 1);
1791        assert!(s.edit_word(WordAction::Capitalize, &mut NoListener));
1792        assert_eq!("a SSeta  c", s.buf);
1793        assert_eq!(7, s.pos);
1794
1795        let mut s = LineBuffer::init("test", 1);
1796        assert!(s.edit_word(WordAction::Capitalize, &mut NoListener));
1797        assert_eq!("tEst", s.buf);
1798        assert_eq!(4, s.pos);
1799    }
1800
1801    #[test]
1802    fn transpose_words() {
1803        let mut s = LineBuffer::init("ßeta / δelta__", 15);
1804        assert!(s.transpose_words(1, &mut NoListener));
1805        assert_eq!("δelta__ / ßeta", s.buf);
1806        assert_eq!(16, s.pos);
1807
1808        let mut s = LineBuffer::init("ßeta / δelta", 14);
1809        assert!(s.transpose_words(1, &mut NoListener));
1810        assert_eq!("δelta / ßeta", s.buf);
1811        assert_eq!(14, s.pos);
1812
1813        let mut s = LineBuffer::init(" / δelta", 8);
1814        assert!(!s.transpose_words(1, &mut NoListener));
1815
1816        let mut s = LineBuffer::init("ßeta / __", 9);
1817        assert!(!s.transpose_words(1, &mut NoListener));
1818    }
1819
1820    #[test]
1821    fn move_by_line() {
1822        let text = "aa123\nsdf bc\nasdf";
1823        let mut s = LineBuffer::init(text, 14);
1824        // move up
1825        let ok = s.move_to_line_up(1);
1826        assert_eq!(7, s.pos);
1827        assert!(ok);
1828
1829        let ok = s.move_to_line_up(1);
1830        assert_eq!(1, s.pos);
1831        assert!(ok);
1832
1833        let ok = s.move_to_line_up(1);
1834        assert_eq!(1, s.pos);
1835        assert!(!ok);
1836
1837        // move down
1838        let ok = s.move_to_line_down(1);
1839        assert_eq!(7, s.pos);
1840        assert!(ok);
1841
1842        let ok = s.move_to_line_down(1);
1843        assert_eq!(14, s.pos);
1844        assert!(ok);
1845
1846        let ok = s.move_to_line_down(1);
1847        assert_eq!(14, s.pos);
1848        assert!(!ok);
1849
1850        // move by multiple steps
1851        let ok = s.move_to_line_up(2);
1852        assert_eq!(1, s.pos);
1853        assert!(ok);
1854
1855        let ok = s.move_to_line_down(2);
1856        assert_eq!(14, s.pos);
1857        assert!(ok);
1858    }
1859
1860    #[test]
1861    fn test_send() {
1862        fn assert_send<T: Send>() {}
1863        assert_send::<LineBuffer>();
1864    }
1865
1866    #[test]
1867    fn test_sync() {
1868        fn assert_sync<T: Sync>() {}
1869        assert_sync::<LineBuffer>();
1870    }
1871}