rustyline/
line_buffer.rs

1//! Line buffer with current cursor position
2use keymap::{At, CharSearch, Movement, RepeatCount, Word};
3use std::cell::RefCell;
4use std::fmt;
5use std::iter;
6use std::ops::{Deref, Index, Range};
7use std::rc::Rc;
8use std::string::Drain;
9use std::sync::{Arc, Mutex};
10use unicode_segmentation::UnicodeSegmentation;
11
12/// Maximum buffer size for the line read
13pub(crate) static MAX_LINE: usize = 4096;
14
15/// Word's case change
16#[derive(Clone, Copy)]
17pub enum WordAction {
18    CAPITALIZE,
19    LOWERCASE,
20    UPPERCASE,
21}
22
23/// Delete (kill) direction
24#[derive(Debug, Clone, Copy, PartialEq, Eq)]
25pub(crate) enum Direction {
26    Forward,
27    Backward,
28}
29
30impl Default for Direction {
31    fn default() -> Direction {
32        Direction::Forward
33    }
34}
35
36/// Listener to be notified when some text is deleted.
37pub(crate) trait DeleteListener {
38    fn start_killing(&mut self);
39    fn delete(&mut self, idx: usize, string: &str, dir: Direction);
40    fn stop_killing(&mut self);
41}
42
43/// Listener to be notified when the line is modified.
44pub(crate) trait ChangeListener: DeleteListener {
45    fn insert_char(&mut self, idx: usize, c: char);
46    fn insert_str(&mut self, idx: usize, string: &str);
47    fn replace(&mut self, idx: usize, old: &str, new: &str);
48}
49
50/// Represent the current input (text and cursor position).
51///
52/// The methods do text manipulations or/and cursor movements.
53pub struct LineBuffer {
54    buf: String, // Edited line buffer (rl_line_buffer)
55    pos: usize,  // Current cursor position (byte position) (rl_point)
56    dl: Option<Arc<Mutex<dyn DeleteListener>>>,
57    cl: Option<Rc<RefCell<dyn ChangeListener>>>,
58}
59
60impl fmt::Debug for LineBuffer {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        f.debug_struct("LineBuffer")
63            .field("buf", &self.buf)
64            .field("pos", &self.pos)
65            .finish()
66    }
67}
68
69impl LineBuffer {
70    /// Create a new line buffer with the given maximum `capacity`.
71    pub fn with_capacity(capacity: usize) -> LineBuffer {
72        LineBuffer {
73            buf: String::with_capacity(capacity),
74            pos: 0,
75            dl: None,
76            cl: None,
77        }
78    }
79
80    #[cfg(test)]
81    pub(crate) fn init(
82        line: &str,
83        pos: usize,
84        cl: Option<Rc<RefCell<ChangeListener>>>,
85    ) -> LineBuffer {
86        let mut lb = Self::with_capacity(MAX_LINE);
87        assert!(lb.insert_str(0, line));
88        lb.set_pos(pos);
89        lb.cl = cl;
90        lb
91    }
92
93    pub(crate) fn set_delete_listener(&mut self, dl: Arc<Mutex<dyn DeleteListener>>) {
94        self.dl = Some(dl);
95    }
96
97    pub(crate) fn set_change_listener(&mut self, dl: Rc<RefCell<dyn ChangeListener>>) {
98        self.cl = Some(dl);
99    }
100
101    pub(crate) fn remove_change_listener(&mut self) {
102        self.cl = None;
103    }
104
105    /// Extracts a string slice containing the entire buffer.
106    pub fn as_str(&self) -> &str {
107        &self.buf
108    }
109
110    /// Converts a buffer into a `String` without copying or allocating.
111    pub fn into_string(self) -> String {
112        self.buf
113    }
114
115    /// Current cursor position (byte position)
116    pub fn pos(&self) -> usize {
117        self.pos
118    }
119
120    /// Set cursor position (byte position)
121    pub fn set_pos(&mut self, pos: usize) {
122        assert!(pos <= self.buf.len());
123        self.pos = pos;
124    }
125
126    /// Returns the length of this buffer, in bytes.
127    pub fn len(&self) -> usize {
128        self.buf.len()
129    }
130
131    /// Returns `true` if this buffer has a length of zero.
132    pub fn is_empty(&self) -> bool {
133        self.buf.is_empty()
134    }
135
136    /// Set line content (`buf`) and cursor position (`pos`).
137    pub fn update(&mut self, buf: &str, pos: usize) {
138        assert!(pos <= buf.len());
139        let end = self.len();
140        self.drain(0..end, Direction::default());
141        let max = self.buf.capacity();
142        if buf.len() > max {
143            self.insert_str(0, &buf[..max]);
144            if pos > max {
145                self.pos = max;
146            } else {
147                self.pos = pos;
148            }
149        } else {
150            self.insert_str(0, buf);
151            self.pos = pos;
152        }
153    }
154
155    /// Returns the character at current cursor position.
156    pub(crate) fn grapheme_at_cursor(&self) -> Option<&str> {
157        if self.pos == self.buf.len() {
158            None
159        } else {
160            self.buf[self.pos..].graphemes(true).next()
161        }
162    }
163
164    /// Returns the position of the character just after the current cursor
165    /// position.
166    pub fn next_pos(&self, n: RepeatCount) -> Option<usize> {
167        if self.pos == self.buf.len() {
168            return None;
169        }
170        self.buf[self.pos..]
171            .grapheme_indices(true)
172            .take(n)
173            .last()
174            .map(|(i, s)| i + self.pos + s.len())
175    }
176
177    /// Returns the position of the character just before the current cursor
178    /// position.
179    fn prev_pos(&self, n: RepeatCount) -> Option<usize> {
180        if self.pos == 0 {
181            return None;
182        }
183        self.buf[..self.pos]
184            .grapheme_indices(true)
185            .rev()
186            .take(n)
187            .last()
188            .map(|(i, _)| i)
189    }
190
191    /// Insert the character `ch` at current cursor position
192    /// and advance cursor position accordingly.
193    /// Return `None` when maximum buffer size has been reached,
194    /// `true` when the character has been appended to the end of the line.
195    pub fn insert(&mut self, ch: char, n: RepeatCount) -> Option<bool> {
196        let shift = ch.len_utf8() * n;
197        if self.buf.len() + shift > self.buf.capacity() {
198            return None;
199        }
200        let push = self.pos == self.buf.len();
201        if n == 1 {
202            self.buf.insert(self.pos, ch);
203            for cl in &self.cl {
204                cl.borrow_mut().insert_char(self.pos, ch);
205            }
206        } else {
207            let text = iter::repeat(ch).take(n).collect::<String>();
208            let pos = self.pos;
209            self.insert_str(pos, &text);
210        }
211        self.pos += shift;
212        Some(push)
213    }
214
215    /// Yank/paste `text` at current position.
216    /// Return `None` when maximum buffer size has been reached,
217    /// `true` when the character has been appended to the end of the line.
218    pub fn yank(&mut self, text: &str, n: RepeatCount) -> Option<bool> {
219        let shift = text.len() * n;
220        if text.is_empty() || (self.buf.len() + shift) > self.buf.capacity() {
221            return None;
222        }
223        let push = self.pos == self.buf.len();
224        let pos = self.pos;
225        if n == 1 {
226            self.insert_str(pos, text);
227        } else {
228            let text = iter::repeat(text).take(n).collect::<String>();
229            self.insert_str(pos, &text);
230        }
231        self.pos += shift;
232        Some(push)
233    }
234
235    /// Delete previously yanked text and yank/paste `text` at current position.
236    pub fn yank_pop(&mut self, yank_size: usize, text: &str) -> Option<bool> {
237        let end = self.pos;
238        let start = end - yank_size;
239        self.drain(start..end, Direction::default());
240        self.pos -= yank_size;
241        self.yank(text, 1)
242    }
243
244    /// Move cursor on the left.
245    pub fn move_backward(&mut self, n: RepeatCount) -> bool {
246        match self.prev_pos(n) {
247            Some(pos) => {
248                self.pos = pos;
249                true
250            }
251            None => false,
252        }
253    }
254
255    /// Move cursor on the right.
256    pub fn move_forward(&mut self, n: RepeatCount) -> bool {
257        match self.next_pos(n) {
258            Some(pos) => {
259                self.pos = pos;
260                true
261            }
262            None => false,
263        }
264    }
265
266    /// Move cursor to the start of the line.
267    pub fn move_home(&mut self) -> bool {
268        if self.pos > 0 {
269            self.pos = 0;
270            true
271        } else {
272            false
273        }
274    }
275
276    /// Move cursor to the end of the line.
277    pub fn move_end(&mut self) -> bool {
278        if self.pos == self.buf.len() {
279            false
280        } else {
281            self.pos = self.buf.len();
282            true
283        }
284    }
285
286    /// Delete the character at the right of the cursor without altering the
287    /// cursor position. Basically this is what happens with the "Delete"
288    /// keyboard key.
289    /// Return the number of characters deleted.
290    pub fn delete(&mut self, n: RepeatCount) -> Option<String> {
291        match self.next_pos(n) {
292            Some(pos) => {
293                let start = self.pos;
294                let chars = self
295                    .drain(start..pos, Direction::Forward)
296                    .collect::<String>();
297                Some(chars)
298            }
299            None => None,
300        }
301    }
302
303    /// Delete the character at the left of the cursor.
304    /// Basically that is what happens with the "Backspace" keyboard key.
305    pub fn backspace(&mut self, n: RepeatCount) -> bool {
306        match self.prev_pos(n) {
307            Some(pos) => {
308                let end = self.pos;
309                self.drain(pos..end, Direction::Backward);
310                self.pos = pos;
311                true
312            }
313            None => false,
314        }
315    }
316
317    /// Kill the text from point to the end of the line.
318    pub fn kill_line(&mut self) -> bool {
319        if !self.buf.is_empty() && self.pos < self.buf.len() {
320            let start = self.pos;
321            let end = self.buf.len();
322            self.drain(start..end, Direction::Forward);
323            true
324        } else {
325            false
326        }
327    }
328
329    /// Kill backward from point to the beginning of the line.
330    pub fn discard_line(&mut self) -> bool {
331        if self.pos > 0 && !self.buf.is_empty() {
332            let end = self.pos;
333            self.drain(0..end, Direction::Backward);
334            self.pos = 0;
335            true
336        } else {
337            false
338        }
339    }
340
341    /// Exchange the char before cursor with the character at cursor.
342    pub fn transpose_chars(&mut self) -> bool {
343        if self.pos == 0 || self.buf.graphemes(true).count() < 2 {
344            return false;
345        }
346        if self.pos == self.buf.len() {
347            self.move_backward(1);
348        }
349        let chars = self.delete(1).unwrap();
350        self.move_backward(1);
351        self.yank(&chars, 1);
352        self.move_forward(1);
353        true
354    }
355
356    /// Go left until start of word
357    fn prev_word_pos(&self, pos: usize, word_def: Word, n: RepeatCount) -> Option<usize> {
358        if pos == 0 {
359            return None;
360        }
361        let mut sow = 0;
362        let mut gis = self.buf[..pos].grapheme_indices(true).rev();
363        'outer: for _ in 0..n {
364            sow = 0;
365            let mut gj = gis.next();
366            'inner: loop {
367                if let Some((j, y)) = gj {
368                    let gi = gis.next();
369                    if let Some((_, x)) = gi {
370                        if is_start_of_word(word_def, x, y) {
371                            sow = j;
372                            break 'inner;
373                        }
374                        gj = gi;
375                    } else {
376                        break 'outer;
377                    }
378                } else {
379                    break 'outer;
380                }
381            }
382        }
383        Some(sow)
384    }
385
386    /// Moves the cursor to the beginning of previous word.
387    pub fn move_to_prev_word(&mut self, word_def: Word, n: RepeatCount) -> bool {
388        if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
389            self.pos = pos;
390            true
391        } else {
392            false
393        }
394    }
395
396    /// Delete the previous word, maintaining the cursor at the start of the
397    /// current word.
398    pub fn delete_prev_word(&mut self, word_def: Word, n: RepeatCount) -> bool {
399        if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
400            let end = self.pos;
401            self.drain(pos..end, Direction::Backward);
402            self.pos = pos;
403            true
404        } else {
405            false
406        }
407    }
408
409    fn next_word_pos(&self, pos: usize, at: At, word_def: Word, n: RepeatCount) -> Option<usize> {
410        if pos == self.buf.len() {
411            return None;
412        }
413        let mut wp = 0;
414        let mut gis = self.buf[pos..].grapheme_indices(true);
415        let mut gi = if at == At::BeforeEnd {
416            // TODO Validate
417            gis.next()
418        } else {
419            None
420        };
421        'outer: for _ in 0..n {
422            wp = 0;
423            gi = gis.next();
424            'inner: loop {
425                if let Some((i, x)) = gi {
426                    let gj = gis.next();
427                    if let Some((j, y)) = gj {
428                        if at == At::Start && is_start_of_word(word_def, x, y) {
429                            wp = j;
430                            break 'inner;
431                        } else if at != At::Start && is_end_of_word(word_def, x, y) {
432                            if word_def == Word::Emacs || at == At::AfterEnd {
433                                wp = j;
434                            } else {
435                                wp = i;
436                            }
437                            break 'inner;
438                        }
439                        gi = gj;
440                    } else {
441                        break 'outer;
442                    }
443                } else {
444                    break 'outer;
445                }
446            }
447        }
448        if wp == 0 {
449            if word_def == Word::Emacs || at == At::AfterEnd {
450                Some(self.buf.len())
451            } else {
452                match gi {
453                    Some((i, _)) if i != 0 => Some(i + pos),
454                    _ => None,
455                }
456            }
457        } else {
458            Some(wp + pos)
459        }
460    }
461
462    /// Moves the cursor to the end of next word.
463    pub fn move_to_next_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> bool {
464        if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
465            self.pos = pos;
466            true
467        } else {
468            false
469        }
470    }
471
472    fn search_char_pos(&self, cs: CharSearch, n: RepeatCount) -> Option<usize> {
473        let mut shift = 0;
474        let search_result = match cs {
475            CharSearch::Backward(c) | CharSearch::BackwardAfter(c) => self.buf[..self.pos]
476                .char_indices()
477                .rev()
478                .filter(|&(_, ch)| ch == c)
479                .take(n)
480                .last()
481                .map(|(i, _)| i),
482            CharSearch::Forward(c) | CharSearch::ForwardBefore(c) => {
483                if let Some(cc) = self.grapheme_at_cursor() {
484                    shift = self.pos + cc.len();
485                    if shift < self.buf.len() {
486                        self.buf[shift..]
487                            .char_indices()
488                            .filter(|&(_, ch)| ch == c)
489                            .take(n)
490                            .last()
491                            .map(|(i, _)| i)
492                    } else {
493                        None
494                    }
495                } else {
496                    None
497                }
498            }
499        };
500        if let Some(pos) = search_result {
501            Some(match cs {
502                CharSearch::Backward(_) => pos,
503                CharSearch::BackwardAfter(c) => pos + c.len_utf8(),
504                CharSearch::Forward(_) => shift + pos,
505                CharSearch::ForwardBefore(_) => {
506                    shift + pos - self.buf[..shift + pos]
507                        .chars()
508                        .next_back()
509                        .unwrap()
510                        .len_utf8()
511                }
512            })
513        } else {
514            None
515        }
516    }
517
518    /// Move cursor to the matching character position.
519    /// Return `true` when the search succeeds.
520    pub fn move_to(&mut self, cs: CharSearch, n: RepeatCount) -> bool {
521        if let Some(pos) = self.search_char_pos(cs, n) {
522            self.pos = pos;
523            true
524        } else {
525            false
526        }
527    }
528
529    /// Kill from the cursor to the end of the current word,
530    /// or, if between words, to the end of the next word.
531    pub fn delete_word(&mut self, at: At, word_def: Word, n: RepeatCount) -> bool {
532        if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
533            let start = self.pos;
534            self.drain(start..pos, Direction::Forward);
535            true
536        } else {
537            false
538        }
539    }
540
541    pub fn delete_to(&mut self, cs: CharSearch, n: RepeatCount) -> bool {
542        let search_result = match cs {
543            CharSearch::ForwardBefore(c) => self.search_char_pos(CharSearch::Forward(c), n),
544            _ => self.search_char_pos(cs, n),
545        };
546        if let Some(pos) = search_result {
547            match cs {
548                CharSearch::Backward(_) | CharSearch::BackwardAfter(_) => {
549                    let end = self.pos;
550                    self.pos = pos;
551                    self.drain(pos..end, Direction::Backward);
552                }
553                CharSearch::ForwardBefore(_) => {
554                    let start = self.pos;
555                    self.drain(start..pos, Direction::Forward);
556                }
557                CharSearch::Forward(c) => {
558                    let start = self.pos;
559                    self.drain(start..pos + c.len_utf8(), Direction::Forward);
560                }
561            };
562            true
563        } else {
564            false
565        }
566    }
567
568    fn skip_whitespace(&self) -> Option<usize> {
569        if self.pos == self.buf.len() {
570            return None;
571        }
572        self.buf[self.pos..]
573            .grapheme_indices(true)
574            .filter(|&(_, ch)| ch.chars().all(|c| c.is_alphanumeric()))
575            .map(|(i, _)| i)
576            .next()
577            .map(|i| i + self.pos)
578    }
579
580    /// Alter the next word.
581    pub fn edit_word(&mut self, a: WordAction) -> bool {
582        if let Some(start) = self.skip_whitespace() {
583            if let Some(end) = self.next_word_pos(start, At::AfterEnd, Word::Emacs, 1) {
584                if start == end {
585                    return false;
586                }
587                let word = self
588                    .drain(start..end, Direction::default())
589                    .collect::<String>();
590                let result = match a {
591                    WordAction::CAPITALIZE => {
592                        let ch = (&word).graphemes(true).next().unwrap();
593                        let cap = ch.to_uppercase();
594                        cap + &word[ch.len()..].to_lowercase()
595                    }
596                    WordAction::LOWERCASE => word.to_lowercase(),
597                    WordAction::UPPERCASE => word.to_uppercase(),
598                };
599                self.insert_str(start, &result);
600                self.pos = start + result.len();
601                return true;
602            }
603        }
604        false
605    }
606
607    /// Transpose two words
608    pub fn transpose_words(&mut self, n: RepeatCount) -> bool {
609        let word_def = Word::Emacs;
610        self.move_to_next_word(At::AfterEnd, word_def, n);
611        let w2_end = self.pos;
612        self.move_to_prev_word(word_def, 1);
613        let w2_beg = self.pos;
614        self.move_to_prev_word(word_def, n);
615        let w1_beg = self.pos;
616        self.move_to_next_word(At::AfterEnd, word_def, 1);
617        let w1_end = self.pos;
618        if w1_beg == w2_beg || w2_beg < w1_end {
619            return false;
620        }
621
622        let w1 = self.buf[w1_beg..w1_end].to_owned();
623
624        let w2 = self
625            .drain(w2_beg..w2_end, Direction::default())
626            .collect::<String>();
627        self.insert_str(w2_beg, &w1);
628
629        self.drain(w1_beg..w1_end, Direction::default());
630        self.insert_str(w1_beg, &w2);
631
632        self.pos = w2_end;
633        true
634    }
635
636    /// Replaces the content between [`start`..`end`] with `text`
637    /// and positions the cursor to the end of text.
638    pub fn replace(&mut self, range: Range<usize>, text: &str) {
639        let start = range.start;
640        for cl in &self.cl {
641            cl.borrow_mut()
642                .replace(start, self.buf.index(range.clone()), text);
643        }
644        self.buf.drain(range);
645        if start == self.buf.len() {
646            self.buf.push_str(text);
647        } else {
648            self.buf.insert_str(start, text);
649        }
650        self.pos = start + text.len();
651    }
652
653    /// Insert the `s`tring at the specified position.
654    /// Return `true` if the text has been inserted at the end of the line.
655    pub fn insert_str(&mut self, idx: usize, s: &str) -> bool {
656        for cl in &self.cl {
657            cl.borrow_mut().insert_str(idx, s);
658        }
659        if idx == self.buf.len() {
660            self.buf.push_str(s);
661            true
662        } else {
663            self.buf.insert_str(idx, s);
664            false
665        }
666    }
667
668    /// Remove the specified `range` in the line.
669    pub fn delete_range(&mut self, range: Range<usize>) {
670        self.set_pos(range.start);
671        self.drain(range, Direction::default());
672    }
673
674    fn drain(&mut self, range: Range<usize>, dir: Direction) -> Drain {
675        for dl in &self.dl {
676            let lock = dl.try_lock();
677            if let Ok(mut dl) = lock {
678                dl.delete(range.start, &self.buf[range.start..range.end], dir);
679            }
680        }
681        for cl in &self.cl {
682            cl.borrow_mut()
683                .delete(range.start, &self.buf[range.start..range.end], dir);
684        }
685        self.buf.drain(range)
686    }
687
688    /// Return the content between current cursor position and `mvt` position.
689    /// Return `None` when the buffer is empty or when the movement fails.
690    pub fn copy(&self, mvt: &Movement) -> Option<String> {
691        if self.is_empty() {
692            return None;
693        }
694        match *mvt {
695            Movement::WholeLine => Some(self.buf.clone()),
696            Movement::BeginningOfLine => {
697                if self.pos == 0 {
698                    None
699                } else {
700                    Some(self.buf[..self.pos].to_owned())
701                }
702            }
703            Movement::ViFirstPrint => {
704                if self.pos == 0 {
705                    None
706                } else if let Some(pos) = self.next_word_pos(0, At::Start, Word::Big, 1) {
707                    Some(self.buf[pos..self.pos].to_owned())
708                } else {
709                    None
710                }
711            }
712            Movement::EndOfLine => {
713                if self.pos == self.buf.len() {
714                    None
715                } else {
716                    Some(self.buf[self.pos..].to_owned())
717                }
718            }
719            Movement::BackwardWord(n, word_def) => {
720                if let Some(pos) = self.prev_word_pos(self.pos, word_def, n) {
721                    Some(self.buf[pos..self.pos].to_owned())
722                } else {
723                    None
724                }
725            }
726            Movement::ForwardWord(n, at, word_def) => {
727                if let Some(pos) = self.next_word_pos(self.pos, at, word_def, n) {
728                    Some(self.buf[self.pos..pos].to_owned())
729                } else {
730                    None
731                }
732            }
733            Movement::ViCharSearch(n, cs) => {
734                let search_result = match cs {
735                    CharSearch::ForwardBefore(c) => self.search_char_pos(CharSearch::Forward(c), n),
736                    _ => self.search_char_pos(cs, n),
737                };
738                if let Some(pos) = search_result {
739                    Some(match cs {
740                        CharSearch::Backward(_) | CharSearch::BackwardAfter(_) => {
741                            self.buf[pos..self.pos].to_owned()
742                        }
743                        CharSearch::ForwardBefore(_) => self.buf[self.pos..pos].to_owned(),
744                        CharSearch::Forward(c) => self.buf[self.pos..pos + c.len_utf8()].to_owned(),
745                    })
746                } else {
747                    None
748                }
749            }
750            Movement::BackwardChar(n) => {
751                if let Some(pos) = self.prev_pos(n) {
752                    Some(self.buf[pos..self.pos].to_owned())
753                } else {
754                    None
755                }
756            }
757            Movement::ForwardChar(n) => {
758                if let Some(pos) = self.next_pos(n) {
759                    Some(self.buf[self.pos..pos].to_owned())
760                } else {
761                    None
762                }
763            }
764        }
765    }
766
767    pub fn kill(&mut self, mvt: &Movement) -> bool {
768        let notify = match *mvt {
769            Movement::ForwardChar(_) => false,
770            Movement::BackwardChar(_) => false,
771            _ => true,
772        };
773        if notify {
774            if let Some(dl) = self.dl.as_ref() {
775                let mut dl = dl.lock().unwrap();
776                dl.start_killing()
777            }
778        }
779        let killed = match *mvt {
780            Movement::ForwardChar(n) => {
781                // Delete (forward) `n` characters at point.
782                self.delete(n).is_some()
783            }
784            Movement::BackwardChar(n) => {
785                // Delete `n` characters backward.
786                self.backspace(n)
787            }
788            Movement::EndOfLine => {
789                // Kill the text from point to the end of the line.
790                self.kill_line()
791            }
792            Movement::WholeLine => {
793                self.move_home();
794                self.kill_line()
795            }
796            Movement::BeginningOfLine => {
797                // Kill backward from point to the beginning of the line.
798                self.discard_line()
799            }
800            Movement::BackwardWord(n, word_def) => {
801                // kill `n` words backward (until start of word)
802                self.delete_prev_word(word_def, n)
803            }
804            Movement::ForwardWord(n, at, word_def) => {
805                // kill `n` words forward (until start/end of word)
806                self.delete_word(at, word_def, n)
807            }
808            Movement::ViCharSearch(n, cs) => self.delete_to(cs, n),
809            Movement::ViFirstPrint => {
810                false // TODO
811            }
812        };
813        if notify {
814            if let Some(dl) = self.dl.as_ref() {
815                let mut dl = dl.lock().unwrap();
816                dl.stop_killing()
817            }
818        }
819        killed
820    }
821}
822
823impl Deref for LineBuffer {
824    type Target = str;
825
826    fn deref(&self) -> &str {
827        self.as_str()
828    }
829}
830
831fn is_start_of_word(word_def: Word, previous: &str, grapheme: &str) -> bool {
832    (!is_word_char(word_def, previous) && is_word_char(word_def, grapheme))
833        || (word_def == Word::Vi && !is_other_char(previous) && is_other_char(grapheme))
834}
835fn is_end_of_word(word_def: Word, grapheme: &str, next: &str) -> bool {
836    (!is_word_char(word_def, next) && is_word_char(word_def, grapheme))
837        || (word_def == Word::Vi && !is_other_char(next) && is_other_char(grapheme))
838}
839
840fn is_word_char(word_def: Word, grapheme: &str) -> bool {
841    match word_def {
842        Word::Emacs => grapheme.chars().all(|c| c.is_alphanumeric()),
843        Word::Vi => is_vi_word_char(grapheme),
844        Word::Big => !grapheme.chars().any(|c| c.is_whitespace()),
845    }
846}
847fn is_vi_word_char(grapheme: &str) -> bool {
848    grapheme.chars().all(|c| c.is_alphanumeric()) || grapheme == "_"
849}
850fn is_other_char(grapheme: &str) -> bool {
851    !(grapheme.chars().any(|c| c.is_whitespace()) || is_vi_word_char(grapheme))
852}
853
854#[cfg(test)]
855mod test {
856    use super::{ChangeListener, DeleteListener, Direction, LineBuffer, WordAction, MAX_LINE};
857    use keymap::{At, CharSearch, Word};
858    use std::cell::RefCell;
859    use std::rc::Rc;
860
861    struct Listener {
862        deleted_str: Option<String>,
863    }
864
865    impl Listener {
866        fn new() -> Rc<RefCell<Listener>> {
867            let l = Listener { deleted_str: None };
868            Rc::new(RefCell::new(l))
869        }
870
871        fn assert_deleted_str_eq(&self, expected: &str) {
872            let actual = self.deleted_str.as_ref().expect("no deleted string");
873            assert_eq!(expected, actual)
874        }
875    }
876
877    impl DeleteListener for Listener {
878        fn start_killing(&mut self) {}
879
880        fn delete(&mut self, _: usize, string: &str, _: Direction) {
881            self.deleted_str = Some(string.to_owned());
882        }
883
884        fn stop_killing(&mut self) {}
885    }
886    impl ChangeListener for Listener {
887        fn insert_char(&mut self, _: usize, _: char) {}
888
889        fn insert_str(&mut self, _: usize, _: &str) {}
890
891        fn replace(&mut self, _: usize, _: &str, _: &str) {}
892    }
893
894    #[test]
895    fn next_pos() {
896        let s = LineBuffer::init("ö̲g̈", 0, None);
897        assert_eq!(7, s.len());
898        let pos = s.next_pos(1);
899        assert_eq!(Some(4), pos);
900
901        let s = LineBuffer::init("ö̲g̈", 4, None);
902        let pos = s.next_pos(1);
903        assert_eq!(Some(7), pos);
904    }
905
906    #[test]
907    fn prev_pos() {
908        let s = LineBuffer::init("ö̲g̈", 4, None);
909        assert_eq!(7, s.len());
910        let pos = s.prev_pos(1);
911        assert_eq!(Some(0), pos);
912
913        let s = LineBuffer::init("ö̲g̈", 7, None);
914        let pos = s.prev_pos(1);
915        assert_eq!(Some(4), pos);
916    }
917
918    #[test]
919    fn insert() {
920        let mut s = LineBuffer::with_capacity(MAX_LINE);
921        let push = s.insert('α', 1).unwrap();
922        assert_eq!("α", s.buf);
923        assert_eq!(2, s.pos);
924        assert_eq!(true, push);
925
926        let push = s.insert('ß', 1).unwrap();
927        assert_eq!("αß", s.buf);
928        assert_eq!(4, s.pos);
929        assert_eq!(true, push);
930
931        s.pos = 0;
932        let push = s.insert('γ', 1).unwrap();
933        assert_eq!("γαß", s.buf);
934        assert_eq!(2, s.pos);
935        assert_eq!(false, push);
936    }
937
938    #[test]
939    fn yank_after() {
940        let mut s = LineBuffer::init("αß", 2, None);
941        s.move_forward(1);
942        let ok = s.yank("γδε", 1);
943        assert_eq!(Some(true), ok);
944        assert_eq!("αßγδε", s.buf);
945        assert_eq!(10, s.pos);
946    }
947
948    #[test]
949    fn yank_before() {
950        let mut s = LineBuffer::init("αε", 2, None);
951        let ok = s.yank("ßγδ", 1);
952        assert_eq!(Some(false), ok);
953        assert_eq!("αßγδε", s.buf);
954        assert_eq!(8, s.pos);
955    }
956
957    #[test]
958    fn moves() {
959        let mut s = LineBuffer::init("αß", 4, None);
960        let ok = s.move_backward(1);
961        assert_eq!("αß", s.buf);
962        assert_eq!(2, s.pos);
963        assert_eq!(true, ok);
964
965        let ok = s.move_forward(1);
966        assert_eq!("αß", s.buf);
967        assert_eq!(4, s.pos);
968        assert_eq!(true, ok);
969
970        let ok = s.move_home();
971        assert_eq!("αß", s.buf);
972        assert_eq!(0, s.pos);
973        assert_eq!(true, ok);
974
975        let ok = s.move_end();
976        assert_eq!("αß", s.buf);
977        assert_eq!(4, s.pos);
978        assert_eq!(true, ok);
979    }
980
981    #[test]
982    fn move_grapheme() {
983        let mut s = LineBuffer::init("ag̈", 4, None);
984        assert_eq!(4, s.len());
985        let ok = s.move_backward(1);
986        assert_eq!(true, ok);
987        assert_eq!(1, s.pos);
988
989        let ok = s.move_forward(1);
990        assert_eq!(true, ok);
991        assert_eq!(4, s.pos);
992    }
993
994    #[test]
995    fn delete() {
996        let cl = Listener::new();
997        let mut s = LineBuffer::init("αß", 2, Some(cl.clone()));
998        let chars = s.delete(1);
999        assert_eq!("α", s.buf);
1000        assert_eq!(2, s.pos);
1001        assert_eq!(Some("ß".to_owned()), chars);
1002
1003        let ok = s.backspace(1);
1004        assert_eq!("", s.buf);
1005        assert_eq!(0, s.pos);
1006        assert_eq!(true, ok);
1007        cl.borrow().assert_deleted_str_eq("α");
1008    }
1009
1010    #[test]
1011    fn kill() {
1012        let cl = Listener::new();
1013        let mut s = LineBuffer::init("αßγδε", 6, Some(cl.clone()));
1014        let ok = s.kill_line();
1015        assert_eq!("αßγ", s.buf);
1016        assert_eq!(6, s.pos);
1017        assert_eq!(true, ok);
1018        cl.borrow().assert_deleted_str_eq("δε");
1019
1020        s.pos = 4;
1021        let ok = s.discard_line();
1022        assert_eq!("γ", s.buf);
1023        assert_eq!(0, s.pos);
1024        assert_eq!(true, ok);
1025        cl.borrow().assert_deleted_str_eq("αß");
1026    }
1027
1028    #[test]
1029    fn transpose() {
1030        let mut s = LineBuffer::init("aßc", 1, None);
1031        let ok = s.transpose_chars();
1032        assert_eq!("ßac", s.buf);
1033        assert_eq!(3, s.pos);
1034        assert_eq!(true, ok);
1035
1036        s.buf = String::from("aßc");
1037        s.pos = 3;
1038        let ok = s.transpose_chars();
1039        assert_eq!("acß", s.buf);
1040        assert_eq!(4, s.pos);
1041        assert_eq!(true, ok);
1042
1043        s.buf = String::from("aßc");
1044        s.pos = 4;
1045        let ok = s.transpose_chars();
1046        assert_eq!("acß", s.buf);
1047        assert_eq!(4, s.pos);
1048        assert_eq!(true, ok);
1049    }
1050
1051    #[test]
1052    fn move_to_prev_word() {
1053        let mut s = LineBuffer::init("a ß  c", 6, None); // before 'c'
1054        let ok = s.move_to_prev_word(Word::Emacs, 1);
1055        assert_eq!("a ß  c", s.buf);
1056        assert_eq!(2, s.pos); // before 'ß'
1057        assert!(true, ok);
1058
1059        assert!(s.move_end()); // after 'c'
1060        assert_eq!(7, s.pos);
1061        let ok = s.move_to_prev_word(Word::Emacs, 1);
1062        assert!(true, ok);
1063        assert_eq!(6, s.pos); // before 'c'
1064
1065        let ok = s.move_to_prev_word(Word::Emacs, 2);
1066        assert!(true, ok);
1067        assert_eq!(0, s.pos);
1068    }
1069
1070    #[test]
1071    fn move_to_prev_vi_word() {
1072        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19, None);
1073        let ok = s.move_to_prev_word(Word::Vi, 1);
1074        assert!(ok);
1075        assert_eq!(17, s.pos);
1076        let ok = s.move_to_prev_word(Word::Vi, 1);
1077        assert!(ok);
1078        assert_eq!(15, s.pos);
1079        let ok = s.move_to_prev_word(Word::Vi, 1);
1080        assert!(ok);
1081        assert_eq!(12, s.pos);
1082        let ok = s.move_to_prev_word(Word::Vi, 1);
1083        assert!(ok);
1084        assert_eq!(11, s.pos);
1085        let ok = s.move_to_prev_word(Word::Vi, 1);
1086        assert!(ok);
1087        assert_eq!(7, s.pos);
1088        let ok = s.move_to_prev_word(Word::Vi, 1);
1089        assert!(ok);
1090        assert_eq!(6, s.pos);
1091        let ok = s.move_to_prev_word(Word::Vi, 1);
1092        assert!(ok);
1093        assert_eq!(0, s.pos);
1094        let ok = s.move_to_prev_word(Word::Vi, 1);
1095        assert!(!ok);
1096    }
1097
1098    #[test]
1099    fn move_to_prev_big_word() {
1100        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 19, None);
1101        let ok = s.move_to_prev_word(Word::Big, 1);
1102        assert!(ok);
1103        assert_eq!(17, s.pos);
1104        let ok = s.move_to_prev_word(Word::Big, 1);
1105        assert!(ok);
1106        assert_eq!(6, s.pos);
1107        let ok = s.move_to_prev_word(Word::Big, 1);
1108        assert!(ok);
1109        assert_eq!(0, s.pos);
1110        let ok = s.move_to_prev_word(Word::Big, 1);
1111        assert!(!ok);
1112    }
1113
1114    #[test]
1115    fn move_to_forward() {
1116        let mut s = LineBuffer::init("αßγδε", 2, None);
1117        let ok = s.move_to(CharSearch::ForwardBefore('ε'), 1);
1118        assert_eq!(true, ok);
1119        assert_eq!(6, s.pos);
1120
1121        let mut s = LineBuffer::init("αßγδε", 2, None);
1122        let ok = s.move_to(CharSearch::Forward('ε'), 1);
1123        assert_eq!(true, ok);
1124        assert_eq!(8, s.pos);
1125
1126        let mut s = LineBuffer::init("αßγδε", 2, None);
1127        let ok = s.move_to(CharSearch::Forward('ε'), 10);
1128        assert_eq!(true, ok);
1129        assert_eq!(8, s.pos);
1130    }
1131
1132    #[test]
1133    fn move_to_backward() {
1134        let mut s = LineBuffer::init("αßγδε", 8, None);
1135        let ok = s.move_to(CharSearch::BackwardAfter('ß'), 1);
1136        assert_eq!(true, ok);
1137        assert_eq!(4, s.pos);
1138
1139        let mut s = LineBuffer::init("αßγδε", 8, None);
1140        let ok = s.move_to(CharSearch::Backward('ß'), 1);
1141        assert_eq!(true, ok);
1142        assert_eq!(2, s.pos);
1143    }
1144
1145    #[test]
1146    fn delete_prev_word() {
1147        let cl = Listener::new();
1148        let mut s = LineBuffer::init("a ß  c", 6, Some(cl.clone()));
1149        let ok = s.delete_prev_word(Word::Big, 1);
1150        assert_eq!("a c", s.buf);
1151        assert_eq!(2, s.pos);
1152        assert_eq!(true, ok);
1153        cl.borrow().assert_deleted_str_eq("ß  ");
1154    }
1155
1156    #[test]
1157    fn move_to_next_word() {
1158        let mut s = LineBuffer::init("a ß  c", 1, None); // after 'a'
1159        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1160        assert_eq!("a ß  c", s.buf);
1161        assert_eq!(true, ok);
1162        assert_eq!(4, s.pos); // after 'ß'
1163
1164        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1165        assert_eq!(true, ok);
1166        assert_eq!(7, s.pos); // after 'c'
1167
1168        s.move_home();
1169        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 1);
1170        assert_eq!(true, ok);
1171        assert_eq!(1, s.pos); // after 'a'
1172
1173        let ok = s.move_to_next_word(At::AfterEnd, Word::Emacs, 2);
1174        assert_eq!(true, ok);
1175        assert_eq!(7, s.pos); // after 'c'
1176    }
1177
1178    #[test]
1179    fn move_to_end_of_word() {
1180        let mut s = LineBuffer::init("a ßeta  c", 1, None);
1181        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1182        assert_eq!("a ßeta  c", s.buf);
1183        assert_eq!(6, s.pos);
1184        assert_eq!(true, ok);
1185    }
1186
1187    #[test]
1188    fn move_to_end_of_vi_word() {
1189        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
1190        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1191        assert!(ok);
1192        assert_eq!(4, s.pos);
1193        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1194        assert!(ok);
1195        assert_eq!(6, s.pos);
1196        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1197        assert!(ok);
1198        assert_eq!(10, s.pos);
1199        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1200        assert!(ok);
1201        assert_eq!(11, s.pos);
1202        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1203        assert!(ok);
1204        assert_eq!(14, s.pos);
1205        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1206        assert!(ok);
1207        assert_eq!(15, s.pos);
1208        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1209        assert!(ok);
1210        assert_eq!(18, s.pos);
1211        let ok = s.move_to_next_word(At::BeforeEnd, Word::Vi, 1);
1212        assert!(!ok);
1213    }
1214
1215    #[test]
1216    fn move_to_end_of_big_word() {
1217        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
1218        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1219        assert!(ok);
1220        assert_eq!(4, s.pos);
1221        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1222        assert!(ok);
1223        assert_eq!(15, s.pos);
1224        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1225        assert!(ok);
1226        assert_eq!(18, s.pos);
1227        let ok = s.move_to_next_word(At::BeforeEnd, Word::Big, 1);
1228        assert!(!ok);
1229    }
1230
1231    #[test]
1232    fn move_to_start_of_word() {
1233        let mut s = LineBuffer::init("a ß  c", 2, None);
1234        let ok = s.move_to_next_word(At::Start, Word::Emacs, 1);
1235        assert_eq!("a ß  c", s.buf);
1236        assert_eq!(6, s.pos);
1237        assert_eq!(true, ok);
1238    }
1239
1240    #[test]
1241    fn move_to_start_of_vi_word() {
1242        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
1243        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1244        assert!(ok);
1245        assert_eq!(6, s.pos);
1246        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1247        assert!(ok);
1248        assert_eq!(7, s.pos);
1249        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1250        assert!(ok);
1251        assert_eq!(11, s.pos);
1252        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1253        assert!(ok);
1254        assert_eq!(12, s.pos);
1255        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1256        assert!(ok);
1257        assert_eq!(15, s.pos);
1258        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1259        assert!(ok);
1260        assert_eq!(17, s.pos);
1261        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1262        assert!(ok);
1263        assert_eq!(18, s.pos);
1264        let ok = s.move_to_next_word(At::Start, Word::Vi, 1);
1265        assert!(!ok);
1266    }
1267
1268    #[test]
1269    fn move_to_start_of_big_word() {
1270        let mut s = LineBuffer::init("alpha ,beta/rho; mu", 0, None);
1271        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1272        assert!(ok);
1273        assert_eq!(6, s.pos);
1274        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1275        assert!(ok);
1276        assert_eq!(17, s.pos);
1277        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1278        assert!(ok);
1279        assert_eq!(18, s.pos);
1280        let ok = s.move_to_next_word(At::Start, Word::Big, 1);
1281        assert!(!ok);
1282    }
1283
1284    #[test]
1285    fn delete_word() {
1286        let cl = Listener::new();
1287        let mut s = LineBuffer::init("a ß  c", 1, Some(cl.clone()));
1288        let ok = s.delete_word(At::AfterEnd, Word::Emacs, 1);
1289        assert_eq!("a  c", s.buf);
1290        assert_eq!(1, s.pos);
1291        assert_eq!(true, ok);
1292        cl.borrow().assert_deleted_str_eq(" ß");
1293
1294        let mut s = LineBuffer::init("test", 0, Some(cl.clone()));
1295        let ok = s.delete_word(At::AfterEnd, Word::Vi, 1);
1296        assert_eq!("", s.buf);
1297        assert_eq!(0, s.pos);
1298        assert_eq!(true, ok);
1299        cl.borrow().assert_deleted_str_eq("test");
1300    }
1301
1302    #[test]
1303    fn delete_til_start_of_word() {
1304        let cl = Listener::new();
1305        let mut s = LineBuffer::init("a ß  c", 2, Some(cl.clone()));
1306        let ok = s.delete_word(At::Start, Word::Emacs, 1);
1307        assert_eq!("a c", s.buf);
1308        assert_eq!(2, s.pos);
1309        assert_eq!(true, ok);
1310        cl.borrow().assert_deleted_str_eq("ß  ");
1311    }
1312
1313    #[test]
1314    fn delete_to_forward() {
1315        let cl = Listener::new();
1316        let mut s = LineBuffer::init("αßγδε", 2, Some(cl.clone()));
1317        let ok = s.delete_to(CharSearch::ForwardBefore('ε'), 1);
1318        assert_eq!(true, ok);
1319        cl.borrow().assert_deleted_str_eq("ßγδ");
1320        assert_eq!("αε", s.buf);
1321        assert_eq!(2, s.pos);
1322
1323        let mut s = LineBuffer::init("αßγδε", 2, Some(cl.clone()));
1324        let ok = s.delete_to(CharSearch::Forward('ε'), 1);
1325        assert_eq!(true, ok);
1326        cl.borrow().assert_deleted_str_eq("ßγδε");
1327        assert_eq!("α", s.buf);
1328        assert_eq!(2, s.pos);
1329    }
1330
1331    #[test]
1332    fn delete_to_backward() {
1333        let cl = Listener::new();
1334        let mut s = LineBuffer::init("αßγδε", 8, Some(cl.clone()));
1335        let ok = s.delete_to(CharSearch::BackwardAfter('α'), 1);
1336        assert_eq!(true, ok);
1337        cl.borrow().assert_deleted_str_eq("ßγδ");
1338        assert_eq!("αε", s.buf);
1339        assert_eq!(2, s.pos);
1340
1341        let mut s = LineBuffer::init("αßγδε", 8, Some(cl.clone()));
1342        let ok = s.delete_to(CharSearch::Backward('ß'), 1);
1343        assert_eq!(true, ok);
1344        cl.borrow().assert_deleted_str_eq("ßγδ");
1345        assert_eq!("αε", s.buf);
1346        assert_eq!(2, s.pos);
1347    }
1348
1349    #[test]
1350    fn edit_word() {
1351        let mut s = LineBuffer::init("a ßeta  c", 1, None);
1352        assert!(s.edit_word(WordAction::UPPERCASE));
1353        assert_eq!("a SSETA  c", s.buf);
1354        assert_eq!(7, s.pos);
1355
1356        let mut s = LineBuffer::init("a ßetA  c", 1, None);
1357        assert!(s.edit_word(WordAction::LOWERCASE));
1358        assert_eq!("a ßeta  c", s.buf);
1359        assert_eq!(7, s.pos);
1360
1361        let mut s = LineBuffer::init("a ßETA  c", 1, None);
1362        assert!(s.edit_word(WordAction::CAPITALIZE));
1363        assert_eq!("a SSeta  c", s.buf);
1364        assert_eq!(7, s.pos);
1365
1366        let mut s = LineBuffer::init("test", 1, None);
1367        assert!(s.edit_word(WordAction::CAPITALIZE));
1368        assert_eq!("tEst", s.buf);
1369        assert_eq!(4, s.pos);
1370    }
1371
1372    #[test]
1373    fn transpose_words() {
1374        let mut s = LineBuffer::init("ßeta / δelta__", 15, None);
1375        assert!(s.transpose_words(1));
1376        assert_eq!("δelta__ / ßeta", s.buf);
1377        assert_eq!(16, s.pos);
1378
1379        let mut s = LineBuffer::init("ßeta / δelta", 14, None);
1380        assert!(s.transpose_words(1));
1381        assert_eq!("δelta / ßeta", s.buf);
1382        assert_eq!(14, s.pos);
1383
1384        let mut s = LineBuffer::init(" / δelta", 8, None);
1385        assert!(!s.transpose_words(1));
1386
1387        let mut s = LineBuffer::init("ßeta / __", 9, None);
1388        assert!(!s.transpose_words(1));
1389    }
1390}