ochrepad_core/action.rs
1//! `Action`: what the user intends, independent of where the carets are
2//! (PLAN 3.5). Key bindings map to actions and macros record them.
3
4use std::fmt;
5
6use serde::{Deserialize, Serialize};
7
8use crate::buffer::BufferId;
9use crate::position::VisualCol;
10use crate::search::SearchQuery;
11use crate::selection::SelectionSet;
12use crate::transform::{CaseMode, SortOptions};
13use crate::view::ViewId;
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
16pub enum Motion {
17 /// One grapheme cluster.
18 Left,
19 Right,
20 WordLeft,
21 WordRight,
22 /// Smart home: first non-blank of the line, or column 0 if already there.
23 Home,
24 LineStart,
25 LineEnd,
26 DocStart,
27 DocEnd,
28 /// Vertical moves keep a remembered visual column.
29 Up,
30 Down,
31 /// Page moves by the given number of lines (the view's page height).
32 PageUp(usize),
33 PageDown(usize),
34}
35
36#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
37pub enum Direction {
38 Up,
39 Down,
40 Left,
41 Right,
42}
43
44#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
45pub enum Action {
46 InsertText(String),
47 /// Like `InsertText`, but when there are several selections and the text
48 /// has exactly that many lines, each selection gets one line.
49 Paste(String),
50 /// Tab key: a tab character, or spaces to the next tab stop when the
51 /// editor is set to indent with spaces.
52 InsertTab,
53 /// Newline plus the current line's leading whitespace (auto-indent).
54 InsertNewline,
55 DeleteBackward,
56 DeleteForward,
57 DeleteWordBackward,
58 DeleteWordForward,
59 MoveCursor {
60 motion: Motion,
61 extend: bool,
62 },
63 SelectAll,
64 SelectWord,
65 SelectLine,
66 AddCursorAbove,
67 AddCursorBelow,
68 /// Collapse to a caret at the primary selection's head.
69 CollapseSelections,
70 /// Replace the selections (mouse clicks and drags). Positions are clamped
71 /// into the document and onto char boundaries.
72 SetSelections(SelectionSet),
73 /// Rectangular selection in visual columns: one selection per line from
74 /// the anchor corner to the head corner. Lines shorter than the rectangle
75 /// get an empty selection at their end (no virtual space).
76 ColumnSelect {
77 anchor_line: usize,
78 anchor_col: VisualCol,
79 head_line: usize,
80 head_col: VisualCol,
81 },
82 /// Grow or shrink the rectangle by moving its head corner (Alt+Shift+
83 /// arrows); starts a rectangle at the primary caret if there is none.
84 ColumnExtend(Direction),
85 /// Paste a rectangular clip: line `i` goes to the caret's visual column
86 /// on the `i`-th line below it, padding short lines with spaces and
87 /// adding lines at the end of the document as needed. With several
88 /// selections or a non-empty one it behaves like `Paste`.
89 PasteBlock(String),
90 /// Select the next (or previous) match after the primary selection.
91 /// Fails with `NotFound` when there is none (macros stop there).
92 Find {
93 query: SearchQuery,
94 backward: bool,
95 },
96 /// Replace the primary selection if it is exactly a match, then find
97 /// the next match.
98 Replace {
99 query: SearchQuery,
100 replacement: String,
101 },
102 /// Replace every match (inside the selections with "in selection") as
103 /// one undo step.
104 ReplaceAll {
105 query: SearchQuery,
106 replacement: String,
107 },
108 /// One selection per match.
109 SelectAllMatches(SearchQuery),
110 /// Convert each selection (or the caret's line) to a case.
111 ConvertCase(CaseMode),
112 /// Sort the selected lines, the rectangle's lines keyed by the text in
113 /// the rectangle, or the whole document when nothing is selected.
114 SortLines(SortOptions),
115 /// Remove trailing spaces and tabs from the selected lines (all lines
116 /// when nothing is selected).
117 TrimTrailingWhitespace,
118 /// Duplicate the caret's line, or each selection.
119 DuplicateLine,
120 MoveLinesUp,
121 MoveLinesDown,
122 /// Join the selected lines (or the caret's line and the next).
123 JoinLines,
124 Undo,
125 Redo,
126}
127
128#[derive(Clone, Debug, PartialEq, Eq)]
129pub enum ActionError {
130 UnknownView(ViewId),
131 UnknownBuffer(BufferId),
132 InvalidPattern(String),
133 NotFound,
134}
135
136impl fmt::Display for ActionError {
137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
138 match self {
139 ActionError::UnknownView(v) => write!(f, "no view with id {}", v.0),
140 ActionError::UnknownBuffer(b) => write!(f, "no buffer with id {}", b.0),
141 ActionError::InvalidPattern(e) => write!(f, "invalid search pattern: {e}"),
142 ActionError::NotFound => f.write_str("no match found"),
143 }
144 }
145}
146
147impl std::error::Error for ActionError {}