use {
reovim_driver_command::{Command, CommandContext, CommandHandler, CommandResult},
reovim_driver_session::{BufferApi, SessionRuntime, api::ExtensionApi},
reovim_kernel::api::v1::{CommandId, Position},
};
use crate::{
ids,
session_state::{ChangeType, VimSessionState},
};
#[derive(Debug, Clone, Copy, Default)]
pub struct DotRepeat;
impl Command for DotRepeat {
fn id(&self) -> CommandId {
ids::DOT_REPEAT
}
fn description(&self) -> &'static str {
"Repeat last change (.)"
}
}
impl CommandHandler for DotRepeat {
fn execute(&self, runtime: &mut SessionRuntime<'_>, args: &CommandContext) -> CommandResult {
let Some(vim) = runtime.ext::<VimSessionState>() else {
return CommandResult::Success; };
let Some(last_change) = vim.last_change.as_ref() else {
return CommandResult::Success; };
let last_change = last_change.clone();
let effective_count = args.count().or(last_change.count);
let _ = last_change.register;
match &last_change.change_type {
ChangeType::Insert { text } => {
Self::repeat_insert(runtime, args, text, effective_count)
}
ChangeType::OperatorMotion { operator, linewise }
| ChangeType::OperatorTextObject { operator, linewise } => {
tracing::debug!(
?operator,
linewise,
count = ?effective_count,
"dot repeat: operator (stub - requires key re-dispatch)"
);
CommandResult::Success
}
}
}
}
impl DotRepeat {
fn repeat_insert(
runtime: &mut SessionRuntime<'_>,
args: &CommandContext,
text: &str,
count: Option<usize>,
) -> CommandResult {
let buffer_id = args.buffer_id().or_else(|| runtime.active_buffer());
let Some(buffer_id) = buffer_id else {
return CommandResult::error("No active buffer");
};
let Some(window) = runtime.windows().active() else {
return CommandResult::error("No active window");
};
let pos = Position::new(window.cursor.line, window.cursor.column);
let effective_count = count.unwrap_or(1);
let repeated_text = text.repeat(effective_count);
runtime.insert_text(buffer_id, pos, &repeated_text);
CommandResult::Success
}
}