use crate::{
ByteOffset, DocumentVersion, Motion, ResolvedRange, Selection, Shape, TextObjectKind,
TextObjectScope, TextRange,
};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub enum Mode {
#[default]
Normal,
Insert,
Replace,
Visual,
VisualLine,
VisualBlock,
}
impl Mode {
pub fn is_visual(self) -> bool {
matches!(self, Self::Visual | Self::VisualLine | Self::VisualBlock)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Capabilities {
pub replace: bool,
pub visual: bool,
pub visual_block: bool,
}
impl Default for Capabilities {
fn default() -> Self {
Self {
replace: true,
visual: true,
visual_block: true,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Key {
Char(char),
Ctrl(char),
Escape,
Enter,
Backspace,
Delete,
Tab,
Left,
Right,
Up,
Down,
Home,
End,
Named(String),
Text(String),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputOrigin {
Typed,
Macro,
Injected,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Binding {
Default,
Command(Command),
Host(HostCommand),
Unhandled,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Input {
pub key: Key,
pub origin: InputOrigin,
pub binding: Binding,
}
impl Input {
pub fn key(key: Key) -> Self {
Self {
key,
origin: InputOrigin::Typed,
binding: Binding::Default,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BindingContext {
Normal,
Insert,
Replace,
Visual,
Literal,
OperatorPending,
AwaitingHost,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Operator {
Delete,
Change,
Yank,
Lowercase,
Uppercase,
ToggleCase,
Indent,
Outdent,
Comment,
Format,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InsertStyle {
Before,
After,
FirstNonBlank,
LineEnd,
OpenAbove,
OpenBelow,
Replace,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HistoryCommand {
Undo,
Redo,
UndoLine,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct HostCommand {
pub id: u64,
pub repeatable: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TargetRequest {
Search {
backward: bool,
repeat: bool,
},
Mark {
name: char,
linewise: bool,
},
Geometry {
id: u64,
},
Syntax {
id: u64,
},
Block {
selection: Selection,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EditTarget {
Motion(Motion),
Object(TextObjectScope, TextObjectKind),
Lines,
Selection,
Host(TargetRequest),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Action {
Repeat,
SelectTarget(TargetRequest),
SelectObject {
scope: TextObjectScope,
kind: TextObjectKind,
},
Move(Motion),
Operate {
operator: Operator,
target: EditTarget,
},
Insert(InsertStyle),
ReplaceChar(char),
DeleteChars {
backward: bool,
},
Paste {
before: bool,
},
ToggleCase,
Join {
spaces: bool,
},
Visual(Shape),
SwapVisual,
SwapVisualHorizontal,
Reselect,
History(HistoryCommand),
Target(TargetRequest),
Host(HostCommand),
BlockInsert {
append: bool,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Command {
pub action: Action,
pub count: usize,
}
impl Command {
pub fn new(action: Action, count: usize) -> Self {
Self { action, count }
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Replacement {
pub range: TextRange,
pub text: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Transaction {
Atomic,
Begin,
Continue,
BreakInsert,
End,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum OperationKind {
Edit {
replacements: Vec<Replacement>,
cursor: ByteOffset,
selection: Option<Selection>,
transaction: Transaction,
},
Move {
cursor: ByteOffset,
selection: Option<Selection>,
},
Resolve {
request: TargetRequest,
count: usize,
},
History {
command: HistoryCommand,
count: usize,
},
Transform {
operator: Operator,
range: ResolvedRange,
count: usize,
},
Host {
command: HostCommand,
count: usize,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HostOperation {
pub id: u64,
pub expected: DocumentVersion,
pub kind: OperationKind,
}
impl HostOperation {
pub fn is_current(&self, version: DocumentVersion) -> bool {
self.expected == version
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AppliedEdit {
pub range: TextRange,
pub removed: String,
pub inserted: String,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HostOutcome {
Applied {
edits: Vec<AppliedEdit>,
changed: bool,
},
Target(ResolvedRange),
RememberedTarget {
range: ResolvedRange,
replay: TargetRequest,
},
Rejected,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HostResult {
pub operation: u64,
pub before: DocumentVersion,
pub after: DocumentVersion,
pub cursor: ByteOffset,
pub selection: Option<Selection>,
pub outcome: HostOutcome,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Step {
Consumed,
AwaitingInput,
Unhandled,
HostOperation(HostOperation),
Replay(Input),
Error(EngineError),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EngineError {
InvalidDocument,
AwaitingHost,
UnexpectedResult,
StaleResult,
UnsupportedMode,
PlaybackLimit,
RecordingLimit,
InvalidRegister,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Lifecycle {
CancelPending,
LeaveMode,
SwitchDocument,
RestoreHistory,
ReplaceDraft,
NewDraft,
}
impl std::fmt::Display for EngineError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::InvalidDocument => "invalid document coordinates or ranges",
Self::AwaitingHost => "an operation is waiting for the host",
Self::UnexpectedResult => "host result does not match the outstanding operation",
Self::StaleResult => "document changed before the operation completed",
Self::UnsupportedMode => "editing surface does not support the requested mode",
Self::PlaybackLimit => "macro playback exceeded its step or nesting limit",
Self::RecordingLimit => "macro recording exceeded its key limit",
Self::InvalidRegister => "invalid macro register name",
})
}
}
impl std::error::Error for EngineError {}