use escriba_search::Direction as SearchDirection;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::edit::Edit;
use crate::mode::Mode;
use crate::motion::TextObject;
use crate::motion::{Motion, Operator};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub enum InsertAt {
Caret,
FirstNonBlank,
AfterCaret,
LineEnd,
OpenBelow,
OpenAbove,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub enum ViewAlign {
Top,
Center,
Bottom,
}
impl ViewAlign {
#[must_use]
pub const fn label(self) -> &'static str {
match self {
Self::Top => "scroll-top",
Self::Center => "scroll-center",
Self::Bottom => "scroll-bottom",
}
}
}
impl InsertAt {
#[must_use]
pub const fn opens_a_line(self) -> bool {
matches!(self, Self::OpenBelow | Self::OpenAbove)
}
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Caret => "caret",
Self::FirstNonBlank => "first-non-blank",
Self::AfterCaret => "after-caret",
Self::LineEnd => "line-end",
Self::OpenBelow => "open-below",
Self::OpenAbove => "open-above",
}
}
pub const ALL: [Self; 6] = [
Self::Caret,
Self::FirstNonBlank,
Self::AfterCaret,
Self::LineEnd,
Self::OpenBelow,
Self::OpenAbove,
];
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub enum Action {
Move(Motion),
Operator(Operator),
ApplyOperator {
op: Operator,
motion: Motion,
},
Edit(Edit),
ChangeMode(Mode),
EnterInsert(InsertAt),
Command {
name: String,
args: Vec<String>,
},
InsertChar(char),
SubmitCommand,
Undo,
Redo,
Save,
Quit,
SearchOpen(SearchDirection),
SearchRepeat {
reverse: bool,
},
SearchWord {
reverse: bool,
},
ClearSearchHighlight,
SearchSubmitOperated {
op: Operator,
},
TextObject(TextObject),
ApplyOperatorObject {
op: Operator,
object: TextObject,
},
Put {
before: bool,
},
ReplaceChar(char),
JoinLines {
space: bool,
},
RepeatLastChange,
JumpBack,
JumpForward,
SetMark(char),
ScrollView(ViewAlign),
Backspace,
PromptCaret {
to: escriba_search::CaretMove,
},
SearchPreviewStep {
forward: bool,
},
DeleteForward,
DeleteWordBefore,
DeleteToLineStart,
PromptHistory {
back: bool,
},
Pending,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CountedAction {
pub count: u32,
pub action: Action,
}
impl CountedAction {
#[must_use]
pub fn once(action: Action) -> Self {
Self { count: 1, action }
}
#[must_use]
pub fn repeated(count: u32, action: Action) -> Self {
Self {
count: count.max(1),
action,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum TextEffect {
Mutates,
Preserves,
}
impl Action {
#[must_use]
pub const fn text_effect(&self) -> TextEffect {
match self {
Self::Edit(_)
| Self::InsertChar(_)
| Self::ApplyOperator { .. }
| Self::ApplyOperatorObject { .. }
| Self::Undo
| Self::Redo
| Self::Backspace
| Self::DeleteForward
| Self::DeleteWordBefore
| Self::DeleteToLineStart
| Self::TextObject(_)
| Self::Command { .. }
| Self::SearchSubmitOperated { .. }
| Self::RepeatLastChange
| Self::Put { .. }
| Self::ReplaceChar(_)
| Self::JoinLines { .. }
| Self::SubmitCommand => TextEffect::Mutates,
Self::EnterInsert(at) => {
if at.opens_a_line() {
TextEffect::Mutates
} else {
TextEffect::Preserves
}
}
Self::Move(_)
| Self::Operator(_)
| Self::ChangeMode(_)
| Self::Save
| Self::Quit
| Self::SearchOpen(_)
| Self::SearchRepeat { .. }
| Self::SearchWord { .. }
| Self::ClearSearchHighlight
| Self::JumpBack
| Self::JumpForward
| Self::PromptCaret { .. }
| Self::PromptHistory { .. }
| Self::SearchPreviewStep { .. }
| Self::SetMark(_)
| Self::ScrollView(_)
| Self::Pending => TextEffect::Preserves,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum HighlightEffect {
Keep,
Clear,
}
impl Action {
#[must_use]
pub const fn highlight_effect(&self) -> HighlightEffect {
match self {
Self::SearchOpen(_)
| Self::SearchRepeat { .. }
| Self::SearchWord { .. }
| Self::SearchSubmitOperated { .. }
| Self::ClearSearchHighlight
| Self::TextObject(_)
| Self::SearchPreviewStep { .. }
| Self::PromptHistory { .. }
| Self::Backspace
| Self::PromptCaret { .. }
| Self::DeleteForward
| Self::DeleteWordBefore
| Self::DeleteToLineStart
| Self::InsertChar(_)
| Self::SubmitCommand
| Self::Pending
| Self::JumpBack
| Self::JumpForward
| Self::Operator(_)
| Self::SetMark(_)
| Self::ScrollView(_)
| Self::Save
| Self::Quit => HighlightEffect::Keep,
Self::ChangeMode(m) => match m {
Mode::Insert => HighlightEffect::Clear,
Mode::Normal | Mode::Visual | Mode::VisualLine | Mode::Command => {
HighlightEffect::Keep
}
},
Self::EnterInsert(_) => HighlightEffect::Clear,
Self::Move(m) => match m {
Motion::SearchNext | Motion::SearchPrev => HighlightEffect::Keep,
_ => HighlightEffect::Clear,
},
Self::ApplyOperator { .. }
| Self::ApplyOperatorObject { .. }
| Self::RepeatLastChange
| Self::Edit(_)
| Self::Command { .. }
| Self::Put { .. }
| Self::ReplaceChar(_)
| Self::JoinLines { .. }
| Self::Undo
| Self::Redo => HighlightEffect::Clear,
}
}
}
impl Action {
#[must_use]
pub const fn edits_prompt(&self) -> bool {
match self {
Self::InsertChar(_)
| Self::Backspace
| Self::PromptHistory { .. }
| Self::PromptCaret { .. }
| Self::DeleteForward
| Self::DeleteWordBefore
| Self::DeleteToLineStart
| Self::SearchPreviewStep { .. } => true,
Self::Move(_)
| Self::Operator(_)
| Self::ApplyOperator { .. }
| Self::ApplyOperatorObject { .. }
| Self::TextObject(_)
| Self::Edit(_)
| Self::ChangeMode(_)
| Self::EnterInsert(_)
| Self::Command { .. }
| Self::SubmitCommand
| Self::Put { .. }
| Self::ReplaceChar(_)
| Self::JoinLines { .. }
| Self::Undo
| Self::Redo
| Self::Save
| Self::Quit
| Self::SearchOpen(_)
| Self::SearchRepeat { .. }
| Self::SearchWord { .. }
| Self::SearchSubmitOperated { .. }
| Self::ClearSearchHighlight
| Self::RepeatLastChange
| Self::JumpBack
| Self::JumpForward
| Self::SetMark(_)
| Self::ScrollView(_)
| Self::Pending => false,
}
}
}