rustyline/
line_buffer.rs

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