use crate::buffer::Buffer;
use crate::{DEBUG, io::log};
#[derive(Debug, Clone)]
pub enum Action {
Insert {
position: usize,
text: String,
},
Delete {
position: usize,
text: String,
},
Replace {
positions: Vec<usize>,
original: String,
new: String,
},
}
impl Action {
pub fn delete(final_position: usize, text: &impl ToString) -> Self {
Self::Delete {
position: final_position,
text: text.to_string(),
}
}
pub fn insert(initial_position: usize, text: &impl ToString) -> Self {
Self::Insert {
position: initial_position,
text: text.to_string(),
}
}
pub fn replace(
initial_positions: Vec<usize>,
original: &impl ToString,
new: &impl ToString,
) -> Self {
Self::Replace {
positions: initial_positions,
original: original.to_string(),
new: new.to_string(),
}
}
}
#[derive(Debug, Clone)]
pub struct UndoTree {
actions: Vec<Action>,
}
impl Default for UndoTree {
fn default() -> Self {
Self::new()
}
}
impl UndoTree {
pub const fn new() -> Self {
Self {
actions: Vec::new(),
}
}
pub fn undo(&mut self, buffer: &mut Buffer) {
let Some(action) = self.actions.pop() else {
return;
};
log!("Undoing Action: {:?}", action);
match action {
Action::Insert { text, position } => {
buffer.cursor = position;
(0..text.len()).for_each(|_| buffer.delete_curr_char());
}
Action::Delete { text, position } => {
buffer.cursor = position;
text.chars().rev().for_each(|c| buffer.insert_char(c));
}
Action::Replace {
positions,
original,
new,
} => {
buffer.replace_text(&original, &new, &positions, self, true);
}
}
buffer.update_list_set(.., true);
buffer.has_changed = true;
}
pub fn new_action_merge(&mut self, mut action: Action) {
match &action {
Action::Insert { text, position: _ } => {
let mut text = text.clone();
if let Some(last) = self.actions.clone().last()
&& let Action::Insert {
text: last_text,
position: last_position,
} = &last
{
text.push_str(last_text);
self.actions.pop();
action = Action::insert(*last_position, &text);
}
}
Action::Delete { text, position } => {
let mut text = text.clone();
if let Some(last) = self.actions.clone().last()
&& let Action::Delete {
text: last_text,
position: _,
} = &last
{
text.push_str(last_text);
self.actions.pop();
action = Action::delete(*position, &text);
}
}
Action::Replace {
positions,
original,
new,
} => {
if let Some(last) = self.actions.clone().last()
&& let Action::Replace {
new: last_new,
original: last_original,
positions: last_positions,
} = &last
&& new == last_new
&& original == last_original
{
let mut positions: Vec<usize> =
positions.iter().chain(last_positions).copied().collect();
positions.sort_unstable();
self.actions.pop();
action = Action::replace(positions, original, new);
}
}
}
self.actions.push(action);
}
pub fn new_action(&mut self, action: Action) {
self.actions.push(action);
}
}