use crate::{
Mode,
buffer::Buffer,
motion::Motion,
register::RegisterHandler,
undo::{Action, UndoTree},
};
pub struct Operator<'a> {
pub name: &'a str,
command: fn(
end: usize,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
),
}
impl<'a> Operator<'a> {
pub fn new(
name: &'a str,
command: fn(
end: usize,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
),
) -> Self {
Self { name, command }
}
pub fn execute(
&self,
motion: &Motion,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
) {
let mut end = motion.evaluate(buffer);
if !motion.inclusive && end != buffer.get_end_of_line() {
end = usize::max(end, 1) - 1;
}
(self.command)(end, buffer, register_handler, mode, undo_tree);
}
pub fn entire_line(
&self,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
) {
buffer.start_of_line();
let end_of_line = buffer.get_end_of_line();
let reg_before = register_handler.get_reg().to_string();
(self.command)(end_of_line, buffer, register_handler, mode, undo_tree);
if reg_before != register_handler.get_reg()
&& register_handler.get_reg().chars().last().unwrap_or('\n') != '\n'
{
register_handler.push_reg(&'\n');
}
}
}
pub fn iterate_range(
mode: &mut Mode,
register_handler: &mut RegisterHandler,
buffer: &mut Buffer,
end: usize,
initial_callback: fn(
register_handler: &mut RegisterHandler,
buffer: &mut Buffer,
mode: &mut Mode,
),
iter_callback: fn(register_handler: &mut RegisterHandler, buffer: &mut Buffer),
after_callback: fn(
start: usize,
register_handler: &mut RegisterHandler,
buffer: &mut Buffer,
mode: &mut Mode,
),
) {
let anchor = buffer.cursor;
let count = (i32::try_from(end).unwrap() - i32::try_from(anchor).unwrap()).abs();
initial_callback(register_handler, buffer, mode);
(0..=count).for_each(|_| iter_callback(register_handler, buffer));
after_callback(anchor, register_handler, buffer, mode);
}
const fn noop(
_start: usize,
_register_handler: &mut RegisterHandler,
_buffer: &mut Buffer,
_mode: &mut Mode,
) {
}
const fn reset_position(
start: usize,
_register_handler: &mut RegisterHandler,
buffer: &mut Buffer,
_mode: &mut Mode,
) {
buffer.cursor = start;
}
fn insert(
_start: usize,
_register_handler: &mut RegisterHandler,
_buffer: &mut Buffer,
mode: &mut Mode,
) {
mode.insert();
}
fn clear_reg(register_handler: &mut RegisterHandler, _buffer: &mut Buffer, _mode: &mut Mode) {
register_handler.empty_reg();
}
fn delete_char(register_handler: &mut RegisterHandler, buffer: &mut Buffer) {
if buffer.rope.len_chars() <= buffer.cursor {
return;
}
register_handler.push_reg(&buffer.get_curr_char());
buffer.delete_curr_char();
}
pub fn delete(
end: usize,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
) {
let end_of_file = buffer.rope.len_chars();
if end == end_of_file && end != 0 {
buffer.cursor -= 1;
}
iterate_range(
mode,
register_handler,
buffer,
end,
clear_reg,
delete_char,
noop,
);
buffer.update_list_use_current_line();
let text = register_handler.get_reg();
let action = Action::delete(buffer.cursor, &text);
undo_tree.new_action(action);
}
fn yank_char(register_handler: &mut RegisterHandler, buffer: &mut Buffer) {
register_handler.push_reg(&buffer.get_curr_char());
if buffer.cursor + 1 < buffer.rope.len_chars() {
buffer.next_char();
}
}
pub fn yank(
end: usize,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
_undo_tree: &mut UndoTree,
) {
if end == buffer.rope.len_chars() && end == buffer.cursor {
return;
}
let end_of_file = buffer.rope.len_chars();
if end == end_of_file && end != 0 {
buffer.cursor -= 1;
}
iterate_range(
mode,
register_handler,
buffer,
end,
clear_reg,
yank_char,
reset_position,
);
}
pub fn change(
end: usize,
buffer: &mut Buffer,
register_handler: &mut RegisterHandler,
mode: &mut Mode,
undo_tree: &mut UndoTree,
) {
let end_of_file = buffer.rope.len_chars();
if end == end_of_file && end != 0 {
buffer.cursor -= 1;
}
iterate_range(
mode,
register_handler,
buffer,
end,
clear_reg,
delete_char,
insert,
);
buffer.update_list_use_current_line();
let text = register_handler.get_reg();
let action = Action::delete(buffer.cursor, &text);
undo_tree.new_action(action);
}