mathtex_editor_core/command.rs
1//! Commands the host sends to `Editor::exec` and the outcome it gets back.
2
3use crate::doc::Document;
4use crate::model::{FracStyle, Mark, MatrixEnv, ScriptSlot, Symbol, UnderOverSpec, Variant};
5use crate::path::CaretPath;
6
7/// A movement direction.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
9pub enum Dir {
10 /// Left.
11 Left,
12 /// Right.
13 Right,
14 /// Up.
15 Up,
16 /// Down.
17 Down,
18}
19
20/// A side relative to a matrix row or column, or the side a host box is approached from.
21#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22pub enum Side {
23 /// Before the target.
24 Before,
25 /// After the target.
26 After,
27}
28
29/// A direction in which the caret leaves the formula.
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
31pub enum ExitDir {
32 /// Left.
33 Left,
34 /// Right.
35 Right,
36 /// Up.
37 Up,
38 /// Down.
39 Down,
40}
41
42/// An edge of the whole formula.
43#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
44pub enum Edge {
45 /// Before the first item.
46 Start,
47 /// After the last item.
48 End,
49}
50
51/// How horizontal motion treats host boxes.
52#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
53pub enum HostBoxPolicy {
54 /// Step over a host box like any atom.
55 #[default]
56 Skip,
57 /// Stop in front of a host box and report it in [`Outcome::entered_host_box`].
58 Enter,
59}
60
61/// A host box the caret would have crossed under [`HostBoxPolicy::Enter`].
62#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
63pub struct HostBoxEntry {
64 /// The box's token.
65 pub token: u32,
66 /// `Before` when approached moving right, `After` when approached moving left.
67 pub side: Side,
68}
69
70/// An editor command.
71#[derive(Debug, Clone, PartialEq, Eq)]
72pub enum Command {
73 /// Move the caret.
74 Move(Dir),
75 /// Move to the start of the caret's sequence.
76 MoveLineStart,
77 /// Move to the end of the caret's sequence.
78 MoveLineEnd,
79 /// Move to the next empty slot.
80 Tab,
81 /// Move to the previous empty slot.
82 ShiftTab,
83 /// Place the caret, usually at a `Editor::hit_test` result.
84 MoveTo(CaretPath),
85 /// Extend the selection by one step.
86 Extend(Dir),
87 /// Extend the selection to a caret, promoting across structures.
88 ExtendTo(CaretPath),
89 /// Select the whole formula.
90 SelectAll,
91 /// Collapse the selection, or close the menu.
92 Collapse,
93 /// Insert a symbol atom, replacing the selection.
94 InsertAtom(Symbol),
95 /// Insert an opaque host box carrying a host minted token, refused above [`crate::MAX_HOST_TOKEN`].
96 InsertHostBox(u32),
97 /// Insert each character as an atom, spaces are kept only in text slots.
98 InsertText(String),
99 /// Insert a fraction, wrapping the selection into the numerator.
100 InsertFraction(FracStyle),
101 /// Attach a script to the item left of the caret, or wrap the selection as the base.
102 InsertScript(ScriptSlot),
103 /// Insert a big operator with empty limits, replacing the selection.
104 InsertBigOp(Symbol),
105 /// Insert a radical, wrapping the selection into the radicand.
106 InsertSqrt,
107 /// Insert stretchy delimiters, wrapping the selection into the body.
108 InsertDelimiters {
109 /// Opening delimiter.
110 open: char,
111 /// Closing delimiter.
112 close: char,
113 },
114 /// Insert an accent, wrapping the selection into its base.
115 InsertAccent(Mark),
116 /// Insert an under or over construct, wrapping the selection into its base.
117 InsertUnderOver(UnderOverSpec),
118 /// Insert a styled run, wrapping the selection into it.
119 InsertStyled(Variant),
120 /// Insert a matrix, replacing the selection.
121 InsertMatrix {
122 /// Environment.
123 env: MatrixEnv,
124 /// Row count, at least one.
125 rows: usize,
126 /// Column count, at least one.
127 cols: usize,
128 },
129 /// Paste a document at the caret, replacing the selection, refused when it fails validation.
130 InsertDocument(Document),
131 /// Delete backward, selecting or opening the menu next to a structure first.
132 DeleteBackward,
133 /// Delete forward, selecting or opening the menu next to a structure first.
134 DeleteForward,
135 /// Insert a matrix row next to the caret's row.
136 MatrixInsertRow(Side),
137 /// Delete the caret's matrix row.
138 MatrixDeleteRow,
139 /// Insert a matrix column next to the caret's column.
140 MatrixInsertCol(Side),
141 /// Delete the caret's matrix column.
142 MatrixDeleteCol,
143 /// Commit the highlighted menu row, or collapse when no menu is open.
144 Confirm,
145 /// Commit a visible menu row by index.
146 MenuSelect(usize),
147 /// When the atoms left of the caret spell `typed`, delete them and run `with`.
148 ReplaceTyped {
149 /// Characters to match, compared through [`Symbol::from_char`].
150 typed: String,
151 /// Commands to run after deleting the match.
152 with: Vec<Command>,
153 },
154 /// Leave the innermost matching delimiters when at their end, else insert the character.
155 CloseDelimiter(char),
156}
157
158/// What a command did.
159#[must_use]
160#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
161pub struct Outcome {
162 /// The document changed and the revision advanced.
163 pub changed: bool,
164 /// The caret or selection moved.
165 pub moved: bool,
166 /// The caret tried to leave the formula in this direction.
167 pub exit: Option<ExitDir>,
168 /// Deleting in an empty formula asks the host to end math mode.
169 pub close: bool,
170 /// Motion stopped in front of a host box under [`HostBoxPolicy::Enter`].
171 pub entered_host_box: Option<HostBoxEntry>,
172 /// The revision after the command.
173 pub revision: u64,
174}