diff --git a/src/lib.rs b/src/lib.rs index c90b146b459aa48f25ca3357faee1dfc822a3205..d6d7da63173f2cc1d198d46b82788173bcc8ae34 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,7 @@ //! } //! ``` #![feature(io)] -#![feature(str_char)] +#![feature(iter_arith)] #![feature(unicode)] #![cfg_attr(feature="clippy", feature(plugin))] #![cfg_attr(feature="clippy", plugin(clippy))] @@ -169,6 +169,21 @@ impl<'out, 'prompt> State<'out, 'prompt> { write_and_flush(self.out, ab.as_bytes()) } + + fn char_at_cursor(&self) -> Option<char> { + if self.pos == self.buf.len() { + None + } else { + self.buf[self.pos..].chars().next() + } + } + fn char_before_cursor(&self) -> Option<char> { + if self.pos == 0 { + None + } else { + self.buf[..self.pos].chars().next_back() + } + } } impl<'out, 'prompt> fmt::Debug for State<'out, 'prompt> { @@ -413,8 +428,7 @@ fn edit_yank_pop(s: &mut State, yank_size: usize, text: &str) -> Result<()> { /// Move cursor on the left. fn edit_move_left(s: &mut State) -> Result<()> { - if s.pos > 0 { - let ch = s.buf.char_at_reverse(s.pos); + if let Some(ch) = s.char_before_cursor() { s.pos -= ch.len_utf8(); s.refresh_line() } else { @@ -424,12 +438,12 @@ fn edit_move_left(s: &mut State) -> Result<()> { /// Move cursor on the right. fn edit_move_right(s: &mut State) -> Result<()> { - if s.pos == s.buf.len() { - return Ok(()); + if let Some(ch) = s.char_at_cursor() { + s.pos += ch.len_utf8(); + s.refresh_line() + } else { + Ok(()) } - let ch = s.buf.char_at(s.pos); - s.pos += ch.len_utf8(); - s.refresh_line() } /// Move cursor to the start of the line. @@ -464,8 +478,7 @@ fn edit_delete(s: &mut State) -> Result<()> { /// Backspace implementation. fn edit_backspace(s: &mut State) -> Result<()> { - if s.pos > 0 && !s.buf.is_empty() { - let ch = s.buf.char_at_reverse(s.pos); + if let Some(ch) = s.char_before_cursor() { s.pos -= ch.len_utf8(); s.buf.remove(s.pos); s.refresh_line() @@ -503,7 +516,7 @@ fn edit_transpose_chars(s: &mut State) -> Result<()> { // TODO should work even if s.pos == s.buf.len() let ch = s.buf.remove(s.pos); let size = ch.len_utf8(); - let other_ch = s.buf.char_at_reverse(s.pos); + let other_ch = s.char_before_cursor().unwrap(); let other_size = other_ch.len_utf8(); s.buf.insert(s.pos - other_size, ch); if s.pos != s.buf.len() - size { @@ -526,16 +539,21 @@ fn edit_delete_prev_word<F>(s: &mut State, test: F) -> Result<Option<String>> { if s.pos > 0 { let old_pos = s.pos; - let mut ch = s.buf.char_at_reverse(s.pos); // eat any spaces on the left - while s.pos > 0 && test(ch) { - s.pos -= ch.len_utf8(); - ch = s.buf.char_at_reverse(s.pos); - } - // eat any non-spaces on the left - while s.pos > 0 && !test(ch) { - s.pos -= ch.len_utf8(); - ch = s.buf.char_at_reverse(s.pos); + s.pos -= s.buf[..s.pos] + .chars() + .rev() + .take_while(|ch| test(*ch)) + .map(char::len_utf8) + .sum(); + if s.pos > 0 { + // eat any non-spaces on the left + s.pos -= s.buf[..s.pos] + .chars() + .rev() + .take_while(|ch| !test(*ch)) + .map(char::len_utf8) + .sum(); } let text = s.buf.drain(s.pos..old_pos).collect(); try!(s.refresh_line()); @@ -549,15 +567,21 @@ fn edit_delete_prev_word<F>(s: &mut State, test: F) -> Result<Option<String>> fn edit_delete_word(s: &mut State) -> Result<Option<String>> { if s.pos < s.buf.len() { let mut pos = s.pos; - let mut ch = s.buf.char_at(pos); - while pos < s.buf.len() && !ch.is_alphanumeric() { - pos += ch.len_utf8(); - ch = s.buf.char_at(pos); - } - while pos < s.buf.len() && ch.is_alphanumeric() { - pos += ch.len_utf8(); - ch = s.buf.char_at(pos); + // eat any spaces + pos += s.buf[pos..] + .chars() + .take_while(|ch| !ch.is_alphanumeric()) + .map(char::len_utf8) + .sum(); + if pos < s.buf.len() { + // eat any non-spaces + pos += s.buf[pos..] + .chars() + .take_while(|ch| ch.is_alphanumeric()) + .map(char::len_utf8) + .sum(); } + let text = s.buf.drain(s.pos..pos).collect(); try!(s.refresh_line()); Ok(Some(text))