From: Simon Tatham Date: Tue, 2 Jan 2024 11:05:17 +0000 (+0000) Subject: Fix movement by words in the editor buffer. X-Git-Url: https://www.chiark.greenend.org.uk/ucgi/~ian/git?a=commitdiff_plain;h=687c8b56d707bc79a8c3aca9eb8c021cc76ab9cb;p=mastodonochrome.git Fix movement by words in the editor buffer. I apparently only half-finished writing is_word_boundary: it tested that the _next_ character wasn't a space, but not that the previous one was. --- diff --git a/src/editor.rs b/src/editor.rs index bef31c6..343db26 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -46,41 +46,62 @@ impl EditorCore { } } + fn is_word_sep(c: char) -> bool { + c == ' ' + } + fn is_word_boundary(&self, pos: usize) -> bool { if !self.is_char_boundary(pos) { false - } else { - match self.text[pos..].chars().next() { - None => true, // end of string - - // not just before a space - Some(c) => c != ' ' + } else if let Some(prevpos) = self.prev_position(pos) { + let mut chars = self.text[prevpos..].chars(); + let prevchar = chars.next().expect("We're not at end of string"); + if let Some(thischar) = chars.next() { + Self::is_word_sep(prevchar) && !Self::is_word_sep(thischar) + } else { + true // end of string } + } else { + true // start of string } } - fn forward(&mut self) -> bool { + fn next_position(&self, pos: usize) -> Option { let len = self.text.len(); - if self.point >= len { - false + if pos >= len { + None } else { - self.point += 1; - while !self.is_char_boundary(self.point) { - self.point += 1; + let mut pos = pos + 1; + while !self.is_char_boundary(pos) { + pos += 1; } - true + Some(pos) } } - fn backward(&mut self) -> bool { - if self.point == 0 { - false + fn prev_position(&self, pos: usize) -> Option { + if pos == 0 { + None } else { - self.point -= 1; - while !self.is_char_boundary(self.point) { - self.point -= 1; + let mut pos = pos - 1; + while !self.is_char_boundary(pos) { + pos -= 1; } - true + Some(pos) + } + } + + fn forward(&mut self) -> bool { + match self.next_position(self.point) { + Some(pos) => { self.point = pos; true } + None => false + } + } + + fn backward(&mut self) -> bool { + match self.prev_position(self.point) { + Some(pos) => { self.point = pos; true } + None => false } } @@ -224,6 +245,39 @@ fn test_forward_backward() { assert_eq!(ec.backward(), true); } +#[test] +fn test_forward_backward_word() { + let mut ec = EditorCore { + text: "lorem ipsum dolor sit amet".to_owned(), + point: 0, + paste_buffer: "".to_owned(), + }; + + assert_eq!(ec.forward_word(), true); + assert_eq!(ec.point, 6); // ipsum + assert_eq!(ec.forward_word(), true); + assert_eq!(ec.point, 12); // dolor + assert_eq!(ec.forward_word(), true); + assert_eq!(ec.point, 18); // sit + assert_eq!(ec.forward_word(), true); + assert_eq!(ec.point, 22); // amet + assert_eq!(ec.forward_word(), true); + assert_eq!(ec.point, 26); // end of string + assert_eq!(ec.forward_word(), false); + + assert_eq!(ec.backward_word(), true); + assert_eq!(ec.point, 22); // amet + assert_eq!(ec.backward_word(), true); + assert_eq!(ec.point, 18); // sit + assert_eq!(ec.backward_word(), true); + assert_eq!(ec.point, 12); // dolor + assert_eq!(ec.backward_word(), true); + assert_eq!(ec.point, 6); // ipsum + assert_eq!(ec.backward_word(), true); + assert_eq!(ec.point, 0); // lorem + assert_eq!(ec.backward_word(), false); +} + #[test] fn test_delete() { let mut ec = EditorCore { @@ -864,7 +918,7 @@ impl Composer { // buffer text. let start_cell_index = self.layout .partition_point(|cell| cell.y < y); - if dbg!(start_cell_index) == self.layout.len() { + if start_cell_index == self.layout.len() { return None; // y is after the end of the buffer } let start_pos = self.layout[start_cell_index].pos;