diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 5ff0183..61aa38a 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -70,14 +70,29 @@ impl Buffer { } - /// Remove the text between grapheme positions 'pos_a' and 'pos_b'. - pub fn remove_text(&mut self, pos_a: usize, pos_b: usize) { - let removed_text = self.string_from_range(pos_a, pos_b); + /// Remove the text before grapheme position 'pos' of length 'len'. + pub fn remove_text_before(&mut self, pos: usize, len: usize) { + if pos >= len { + let removed_text = self.string_from_range(pos - len, pos); + + self._remove_text(pos - len, pos); + + // Push operation to the undo stack + self.undo_stack.push(RemoveTextBefore(removed_text, pos - len)); + } + else { + panic!("Buffer::remove_text_before(): attempt to remove text before beginning of buffer."); + } + } - self._remove_text(pos_a, pos_b); + /// Remove the text after grapheme position 'pos' of length 'len'. + pub fn remove_text_after(&mut self, pos: usize, len: usize) { + let removed_text = self.string_from_range(pos, pos + len); + + self._remove_text(pos, pos + len); // Push operation to the undo stack - self.undo_stack.push(RemoveText(removed_text, pos_a)); + self.undo_stack.push(RemoveTextAfter(removed_text, pos)); } fn _remove_text(&mut self, pos_a: usize, pos_b: usize) { @@ -146,8 +161,8 @@ impl Buffer { // TODO: a more efficient implementation that directly // manipulates the node tree. let s = self.string_from_range(pos_a, pos_b); - self.remove_text(pos_a, pos_b); - self.insert_text(s.as_slice(), pos_to); + self._remove_text(pos_a, pos_b); + self._insert_text(s.as_slice(), pos_to); } } @@ -203,12 +218,18 @@ impl Buffer { return Some(p); }, - RemoveText(ref s, p) => { + RemoveTextBefore(ref s, p) => { let size = grapheme_count(s.as_slice()); self._insert_text(s.as_slice(), p); return Some(p+size); }, + RemoveTextAfter(ref s, p) => { + let size = grapheme_count(s.as_slice()); + self._insert_text(s.as_slice(), p); + return Some(p); + }, + MoveText(pa, pb, pto) => { let size = pb - pa; self._move_text(pto, pto + size, pa); @@ -236,7 +257,7 @@ impl Buffer { return Some(p+size); }, - RemoveText(ref s, p) => { + RemoveTextBefore(ref s, p) | RemoveTextAfter(ref s, p) => { let size = grapheme_count(s.as_slice()); self._remove_text(p, p+size); return Some(p); @@ -782,7 +803,7 @@ mod tests { assert!(buf.grapheme_count() == 29); assert!(buf.text.line_count == 6); - buf.remove_text(0, 3); + buf._remove_text(0, 3); let mut iter = buf.grapheme_iter(); @@ -826,7 +847,7 @@ mod tests { assert!(buf.grapheme_count() == 29); assert!(buf.text.line_count == 6); - buf.remove_text(0, 12); + buf._remove_text(0, 12); let mut iter = buf.grapheme_iter(); @@ -861,7 +882,7 @@ mod tests { assert!(buf.grapheme_count() == 29); assert!(buf.text.line_count == 6); - buf.remove_text(5, 17); + buf._remove_text(5, 17); let mut iter = buf.grapheme_iter(); @@ -896,7 +917,7 @@ mod tests { assert!(buf.grapheme_count() == 29); assert!(buf.text.line_count == 6); - buf.remove_text(23, 29); + buf._remove_text(23, 29); let mut iter = buf.grapheme_iter(); @@ -937,7 +958,7 @@ mod tests { assert!(buf.grapheme_count() == 29); assert!(buf.text.line_count == 6); - buf.remove_text(17, 29); + buf._remove_text(17, 29); let mut iter = buf.grapheme_iter(); @@ -972,7 +993,7 @@ mod tests { assert!(buf.grapheme_count() == 12); assert!(buf.text.line_count == 2); - buf.remove_text(3, 12); + buf._remove_text(3, 12); let mut iter = buf.grapheme_iter(); @@ -993,7 +1014,7 @@ mod tests { assert!(buf.grapheme_count() == 15); assert!(buf.text.line_count == 3); - buf.remove_text(5, 15); + buf._remove_text(5, 15); let mut iter = buf.grapheme_iter(); @@ -1016,7 +1037,7 @@ mod tests { assert!(buf.grapheme_count() == 12); assert!(buf.text.line_count == 2); - buf.remove_text(3, 11); + buf._remove_text(3, 11); let mut iter = buf.grapheme_iter(); @@ -1038,7 +1059,7 @@ mod tests { assert!(buf.grapheme_count() == 12); assert!(buf.text.line_count == 2); - buf.remove_text(8, 12); + buf._remove_text(8, 12); let mut iter = buf.grapheme_iter(); @@ -1064,7 +1085,7 @@ mod tests { assert!(buf.grapheme_count() == 11); assert!(buf.text.line_count == 4); - buf.remove_text(4, 11); + buf._remove_text(4, 11); let mut iter = buf.grapheme_iter(); @@ -1086,7 +1107,7 @@ mod tests { assert!(buf.grapheme_count() == 10); assert!(buf.text.line_count == 1); - buf.remove_text(9, 10); + buf._remove_text(9, 10); let mut iter = buf.grapheme_iter(); diff --git a/src/buffer/undo_stack.rs b/src/buffer/undo_stack.rs index 9d63652..7a8c91a 100644 --- a/src/buffer/undo_stack.rs +++ b/src/buffer/undo_stack.rs @@ -5,7 +5,8 @@ use std::collections::DList; #[derive(Clone)] pub enum Operation { InsertText(String, usize), - RemoveText(String, usize), + RemoveTextBefore(String, usize), + RemoveTextAfter(String, usize), MoveText(usize, usize, usize), CompositeOp(Vec), } diff --git a/src/editor.rs b/src/editor.rs index 6446b03..a597b2c 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -287,17 +287,15 @@ impl Editor { return; } - let pos_b = self.cursor.range.0; - let pos_a = if pos_b >= grapheme_count {pos_b - grapheme_count} else {0}; - let tot_g = pos_b - pos_a; + let len = min(self.cursor.range.0, grapheme_count); // Remove text - self.buffer.remove_text(pos_a, pos_b); + self.buffer.remove_text_before(self.cursor.range.0, len); self.dirty = true; // Move cursor - self.cursor.range.0 -= tot_g; - self.cursor.range.1 -= tot_g; + self.cursor.range.0 -= len; + self.cursor.range.1 -= len; self.cursor.update_vis_start(&(self.buffer)); // Adjust view @@ -310,11 +308,11 @@ impl Editor { return; } - let pos_a = self.cursor.range.1; - let pos_b = if (pos_a + grapheme_count) <= self.buffer.grapheme_count() {pos_a + grapheme_count} else {self.buffer.grapheme_count()}; + let max_len = if self.buffer.grapheme_count() > self.cursor.range.1 {self.buffer.grapheme_count() - self.cursor.range.1} else {0}; + let len = min(max_len, grapheme_count); // Remove text - self.buffer.remove_text(pos_a, pos_b); + self.buffer.remove_text_after(self.cursor.range.1, len); self.dirty = true; // Move cursor @@ -327,7 +325,7 @@ impl Editor { pub fn remove_text_inside_cursor(&mut self) { // If selection, remove text if self.cursor.range.0 < self.cursor.range.1 { - self.buffer.remove_text(self.cursor.range.0, self.cursor.range.1); + self.buffer.remove_text_before(self.cursor.range.0, self.cursor.range.1 - self.cursor.range.0); self.dirty = true; } diff --git a/todo.md b/todo.md index 9b4f7e4..ff680d6 100644 --- a/todo.md +++ b/todo.md @@ -9,7 +9,8 @@ - Clean up text buffer interface: - Editing (these are undoable): //- insert_text - //- remove_text + //- remove_text_before + //- remove_text_after //- move_text - Undo functionality: //- Undo