use super::motion::{Kind, Motion, Pos, TextObject};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Operator {
Delete,
Change,
Yank,
Indent,
Unindent,
Lowercase,
Uppercase,
ToggleCase,
}
impl Operator {
pub fn from_key(c: char) -> Option<Self> {
Some(match c {
'd' => Operator::Delete,
'c' => Operator::Change,
'y' => Operator::Yank,
'>' => Operator::Indent,
'<' => Operator::Unindent,
_ => return None,
})
}
pub fn enters_insert(self) -> bool {
self == Operator::Change
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Range {
Motion(Motion),
Object(TextObject),
Line,
Visual {
rows: usize,
cols: usize,
kind: Kind,
},
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Simple {
DeleteChar { before: bool },
Replace(char),
JoinLines,
ToggleCaseChar,
Put { before: bool },
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InsertAt {
Cursor,
After,
LineStart,
LineEnd,
OpenBelow,
OpenAbove,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Change {
Operator {
count: usize,
operator: Operator,
range: Range,
},
Simple {
count: usize,
edit: Simple,
},
Insert {
at: InsertAt,
text: String,
count: usize,
},
OperatorInsert {
count: usize,
operator: Operator,
range: Range,
text: String,
},
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Register {
pub text: String,
pub linewise: bool,
}
pub fn ordered(a: Pos, b: Pos) -> (Pos, Pos) {
if a <= b {
(a, b)
} else {
(b, a)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn operators_come_from_their_keys() {
assert_eq!(Operator::from_key('d'), Some(Operator::Delete));
assert_eq!(Operator::from_key('>'), Some(Operator::Indent));
assert_eq!(Operator::from_key('q'), None);
}
#[test]
fn only_change_enters_insert() {
assert!(Operator::Change.enters_insert());
assert!(!Operator::Delete.enters_insert());
}
#[test]
fn a_change_is_a_value_so_it_can_be_stored_and_compared() {
let a = Change::Simple {
count: 1,
edit: Simple::DeleteChar { before: false },
};
assert_eq!(a.clone(), a);
}
}