use crate::buffer::operation::Operation;
use crate::buffer::{Buffer, Position, Range};
use std::clone::Clone;
#[derive(Clone)]
pub struct Delete {
content: Option<String>,
range: Range,
}
impl Operation for Delete {
fn run(&mut self, buffer: &mut Buffer) {
self.content = buffer.data.borrow().read(&self.range);
buffer.data.borrow_mut().delete(&self.range);
if let Some(ref callback) = buffer.change_callback {
callback(self.range.start())
}
}
fn reverse(&mut self, buffer: &mut Buffer) {
if let Some(ref content) = self.content {
buffer
.data
.borrow_mut()
.insert(content, &self.range.start());
if let Some(ref callback) = buffer.change_callback {
callback(self.range.start())
}
}
}
fn clone_operation(&self) -> Box<dyn Operation> {
Box::new(self.clone())
}
}
impl Delete {
pub fn new(range: Range) -> Delete {
Delete {
content: None,
range,
}
}
}
impl Buffer {
pub fn delete(&mut self) {
let mut end = Position {
line: self.cursor.line,
offset: self.cursor.offset + 1,
};
if !self.data.borrow().in_bounds(&end) {
end.line += 1;
end.offset = 0;
}
let start = self.cursor.position;
self.delete_range(Range::new(start, end));
}
pub fn delete_range(&mut self, range: Range) {
let mut op = Delete::new(range);
op.run(self);
match self.operation_group {
Some(ref mut group) => group.add(Box::new(op)),
None => self.history.add(Box::new(op)),
};
}
}
#[cfg(test)]
mod tests {
use super::Delete;
use crate::buffer::operation::Operation;
use crate::buffer::{Buffer, Position, Range};
use std::cell::RefCell;
use std::rc::Rc;
#[test]
fn run_and_reverse_remove_and_add_content_without_newlines_at_cursor_position() {
let mut buffer = Buffer::new();
buffer.insert("something else");
let start = Position { line: 0, offset: 9 };
let end = Position {
line: 0,
offset: 14,
};
let delete_range = Range::new(start, end);
let mut delete_operation = Delete::new(delete_range);
delete_operation.run(&mut buffer);
assert_eq!(buffer.data(), "something");
delete_operation.reverse(&mut buffer);
assert_eq!(buffer.data(), "something else");
}
#[test]
fn run_and_reverse_remove_and_add_content_with_newlines_at_cursor_position() {
let mut buffer = Buffer::new();
buffer.insert("\n something\n else\n entirely");
let start = Position {
line: 1,
offset: 10,
};
let end = Position { line: 3, offset: 9 };
let delete_range = Range::new(start, end);
let mut delete_operation = Delete::new(delete_range);
delete_operation.run(&mut buffer);
assert_eq!(buffer.data(), "\n something");
delete_operation.reverse(&mut buffer);
assert_eq!(buffer.data(), "\n something\n else\n entirely");
}
#[test]
fn run_calls_change_callback_with_position() {
let mut buffer = Buffer::new();
buffer.insert("something else");
let start = Position { line: 0, offset: 9 };
let end = Position {
line: 0,
offset: 14,
};
let delete_range = Range::new(start, end);
let tracked_position = Rc::new(RefCell::new(Position::new()));
let callback_position = tracked_position.clone();
buffer.change_callback = Some(Box::new(move |change_position| {
*callback_position.borrow_mut() = change_position
}));
let mut delete_operation = Delete::new(delete_range);
delete_operation.run(&mut buffer);
assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 });
}
#[test]
fn reverse_calls_change_callback_with_position() {
let mut buffer = Buffer::new();
buffer.insert("something else");
let start = Position { line: 0, offset: 9 };
let end = Position {
line: 0,
offset: 14,
};
let delete_range = Range::new(start, end);
let mut delete_operation = Delete::new(delete_range);
delete_operation.run(&mut buffer);
let tracked_position = Rc::new(RefCell::new(Position::new()));
let callback_position = tracked_position.clone();
buffer.change_callback = Some(Box::new(move |change_position| {
*callback_position.borrow_mut() = change_position
}));
delete_operation.reverse(&mut buffer);
assert_eq!(*tracked_position.borrow(), Position { line: 0, offset: 9 });
}
}