escriba_core/action.rs
1use schemars::JsonSchema;
2use serde::{Deserialize, Serialize};
3
4use crate::edit::Edit;
5use crate::mode::Mode;
6use crate::motion::{Motion, Operator};
7
8/// A fully-resolved editor action — what the keymap emits, what the buffer
9/// consumes.
10#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
11pub enum Action {
12 /// Move every cursor by `motion`.
13 Move(Motion),
14 /// Begin an operator (the `d`/`c`/`y` key). The editor enters
15 /// operator-pending: the next motion composes into an [`Action::ApplyOperator`].
16 /// Resolved by the operator-pending FSM, never executed directly.
17 Operator(Operator),
18 /// Apply a pending operator over a motion (delete-word, yank-line, etc.).
19 ApplyOperator {
20 op: Operator,
21 motion: Motion,
22 },
23 /// Apply a primitive edit at each cursor.
24 Edit(Edit),
25 /// Enter the given mode.
26 ChangeMode(Mode),
27 /// Run a named command (via the command registry).
28 Command {
29 name: String,
30 args: Vec<String>,
31 },
32 /// Insert a character at each caret. Separate from Edit so the keymap
33 /// can stay ignorant of rope details.
34 InsertChar(char),
35 /// Submit a minibuffer / command-mode line (e.g. `:w`, `:q`).
36 SubmitCommand,
37 /// Undo / redo one change.
38 Undo,
39 Redo,
40 /// Save the current buffer.
41 Save,
42 /// Quit the editor.
43 Quit,
44 /// No-op — used when a key sequence is pending but not yet complete.
45 Pending,
46}
47
48/// An [`Action`] with an optional repetition count (vim's `5dd`, `10k`).
49#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
50pub struct CountedAction {
51 pub count: u32,
52 pub action: Action,
53}
54
55impl CountedAction {
56 #[must_use]
57 pub fn once(action: Action) -> Self {
58 Self { count: 1, action }
59 }
60
61 #[must_use]
62 pub fn repeated(count: u32, action: Action) -> Self {
63 Self {
64 count: count.max(1),
65 action,
66 }
67 }
68}