use reovim_kernel::api::v1::{
BufferId, HistoryRing, KernelContext, Position, Register, RegisterBank,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Range {
pub start: Position,
pub end: Position,
pub is_linewise: bool,
}
impl Range {
#[must_use]
pub const fn new(start: Position, end: Position) -> Self {
Self {
start,
end,
is_linewise: false,
}
}
#[must_use]
pub const fn linewise(start: Position, end: Position) -> Self {
Self {
start,
end,
is_linewise: true,
}
}
#[must_use]
pub const fn from_position(pos: Position) -> Self {
Self {
start: pos,
end: pos,
is_linewise: false,
}
}
#[must_use]
pub const fn to_linewise(self) -> Self {
Self {
start: self.start,
end: self.end,
is_linewise: true,
}
}
#[must_use]
pub const fn is_empty(&self) -> bool {
self.start.line == self.end.line && self.start.column == self.end.column
}
#[must_use]
pub const fn is_single_line(&self) -> bool {
self.start.line == self.end.line
}
#[must_use]
pub const fn line_count(&self) -> usize {
if self.end.line >= self.start.line {
self.end.line - self.start.line + 1
} else {
0
}
}
#[must_use]
#[allow(clippy::missing_const_for_fn)]
pub fn normalized(self) -> Self {
if self.start.line > self.end.line
|| (self.start.line == self.end.line && self.start.column > self.end.column)
{
Self {
start: self.end,
end: self.start,
is_linewise: self.is_linewise,
}
} else {
self
}
}
}
pub trait Operator: Send + Sync {
fn id(&self) -> &'static str;
fn execute(&self, ctx: &mut OperatorContext<'_>, range: Range) -> Result<(), OperatorError>;
#[cfg_attr(coverage_nightly, coverage(off))]
fn is_linewise(&self) -> bool {
false
}
#[cfg_attr(coverage_nightly, coverage(off))]
fn is_text_modifying(&self) -> bool {
true
}
}
pub struct OperatorContext<'a> {
pub kernel: &'a KernelContext,
pub registers: &'a mut RegisterBank,
pub clipboard_history: &'a mut HistoryRing,
pub buffer_id: BufferId,
pub register: Register,
pub count: usize,
pub cursor_position: Position,
pub cursor_after: Option<Position>,
}
#[derive(Debug, Clone)]
pub enum OperatorError {
BufferNotFound(BufferId),
InvalidRange(Range),
OperationFailed(String),
}
impl std::fmt::Display for OperatorError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::BufferNotFound(id) => write!(f, "buffer not found: {id:?}"),
Self::InvalidRange(r) => write!(f, "invalid range: {r:?}"),
Self::OperationFailed(msg) => write!(f, "operation failed: {msg}"),
}
}
}
impl std::error::Error for OperatorError {}