brush_core/interfaces/
keybindings.rs

1use std::{
2    collections::HashMap,
3    fmt::{self, Display, Formatter},
4};
5
6/// Represents an action that can be taken in response to a key sequence.
7#[derive(Debug)]
8pub enum KeyAction {
9    /// Execute a shell command.
10    ShellCommand(String),
11    /// Execute an input "function".
12    DoInputFunction(InputFunction),
13}
14
15impl Display for KeyAction {
16    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
17        match self {
18            Self::ShellCommand(command) => write!(f, "shell command: {command}"),
19            Self::DoInputFunction(function) => function.fmt(f),
20        }
21    }
22}
23
24/// Defines all input functions.
25#[derive(Debug, strum_macros::EnumString, strum_macros::Display, strum_macros::EnumIter)]
26#[strum(serialize_all = "kebab-case")]
27#[expect(missing_docs)]
28pub enum InputFunction {
29    Abort,
30    AcceptLine,
31    AliasExpandLine,
32    ArrowKeyPrefix,
33    BackwardByte,
34    BackwardChar,
35    BackwardDeleteChar,
36    BackwardKillLine,
37    BackwardKillWord,
38    BackwardWord,
39    BeginningOfHistory,
40    BeginningOfLine,
41    BracketedPasteBegin,
42    CallLastKbdMacro,
43    CapitalizeWord,
44    CharacterSearch,
45    CharacterSearchBackward,
46    ClearDisplay,
47    ClearScreen,
48    Complete,
49    CompleteCommand,
50    CompleteFilename,
51    CompleteHostname,
52    CompleteIntoBraces,
53    CompleteUsername,
54    CompleteVariable,
55    CopyBackwardWord,
56    CopyForwardWord,
57    CopyRegionAsKill,
58    DabbrevExpand,
59    DeleteChar,
60    DeleteCharOrList,
61    DeleteHorizontalSpace,
62    DigitArgument,
63    DisplayShellVersion,
64    DoLowercaseVersion,
65    DowncaseWord,
66    DumpFunctions,
67    DumpMacros,
68    DumpVariables,
69    DynamicCompleteHistory,
70    EditAndExecuteCommand,
71    EmacsEditingMode,
72    EndKbdMacro,
73    EndOfHistory,
74    EndOfLine,
75    ExchangePointAndMark,
76    ForwardBackwardDeleteChar,
77    ForwardByte,
78    ForwardChar,
79    ForwardSearchHistory,
80    ForwardWord,
81    GlobCompleteWord,
82    GlobExpandWord,
83    GlobListExpansions,
84    HistoryAndAliasExpandLine,
85    HistoryExpandLine,
86    HistorySearchBackward,
87    HistorySearchForward,
88    HistorySubstringSearchBackward,
89    HistorySubstringSearchForward,
90    InsertComment,
91    InsertCompletions,
92    InsertLastArgument,
93    KillLine,
94    KillRegion,
95    KillWholeLine,
96    KillWord,
97    MagicSpace,
98    MenuComplete,
99    MenuCompleteBackward,
100    NextHistory,
101    NextScreenLine,
102    NonIncrementalForwardSearchHistory,
103    NonIncrementalForwardSearchHistoryAgain,
104    NonIncrementalReverseSearchHistory,
105    NonIncrementalReverseSearchHistoryAgain,
106    OldMenuComplete,
107    OperateAndGetNext,
108    OverwriteMode,
109    PossibleCommandCompletions,
110    PossibleCompletions,
111    PossibleFilenameCompletions,
112    PossibleHostnameCompletions,
113    PossibleUsernameCompletions,
114    PossibleVariableCompletions,
115    PreviousHistory,
116    PreviousScreenLine,
117    PrintLastKbdMacro,
118    QuotedInsert,
119    ReReadInitFile,
120    RedrawCurrentLine,
121    ReverseSearchHistory,
122    RevertLine,
123    SelfInsert,
124    SetMark,
125    ShellBackwardKillWord,
126    ShellBackwardWord,
127    ShellExpandLine,
128    ShellForwardWord,
129    ShellKillWord,
130    ShellTransposeWords,
131    SkipCsiSequence,
132    StartKbdMacro,
133    TabInsert,
134    TildeExpand,
135    TransposeChars,
136    TransposeWords,
137    TtyStatus,
138    Undo,
139    UniversalArgument,
140    UnixFilenameRubout,
141    UnixLineDiscard,
142    UnixWordRubout,
143    UpcaseWord,
144    ViAppendEol,
145    ViAppendMode,
146    ViArgDigit,
147    ViBWord,
148    ViBackToIndent,
149    ViBackwardBigword,
150    ViBackwardWord,
151    ViBword,
152    ViChangeCase,
153    ViChangeChar,
154    ViChangeTo,
155    ViCharSearch,
156    ViColumn,
157    ViComplete,
158    ViDelete,
159    ViDeleteTo,
160    ViEWord,
161    ViEditingMode,
162    ViEndBigword,
163    ViEndWord,
164    ViEofMaybe,
165    ViEword,
166    ViFWord,
167    ViFetchHistory,
168    ViFirstPrint,
169    ViForwardBigword,
170    ViForwardWord,
171    ViFword,
172    ViGotoMark,
173    ViInsertBeg,
174    ViInsertionMode,
175    ViMatch,
176    ViMovementMode,
177    ViNextWord,
178    ViOverstrike,
179    ViOverstrikeDelete,
180    ViPrevWord,
181    ViPut,
182    ViRedo,
183    ViReplace,
184    ViRubout,
185    ViSearch,
186    ViSearchAgain,
187    ViSetMark,
188    ViSubst,
189    ViTildeExpand,
190    ViUnixWordRubout,
191    ViYankArg,
192    ViYankPop,
193    ViYankTo,
194    Yank,
195    YankLastArg,
196    YankNthArg,
197    YankPop,
198}
199
200/// Represents a sequence of keys.
201#[derive(Debug, Eq, Hash, PartialEq)]
202pub struct KeySequence {
203    /// The strokes in the sequence.
204    pub strokes: Vec<KeyStroke>,
205}
206
207impl Display for KeySequence {
208    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
209        for stroke in &self.strokes {
210            stroke.fmt(f)?;
211        }
212        Ok(())
213    }
214}
215
216impl From<KeyStroke> for KeySequence {
217    /// Creates a new key sequence with a single stroke.
218    fn from(value: KeyStroke) -> Self {
219        Self {
220            strokes: vec![value],
221        }
222    }
223}
224
225#[derive(Debug, Eq, Hash, PartialEq)]
226/// Represents a single key press.
227pub struct KeyStroke {
228    /// Alt key was pressed.
229    pub alt: bool,
230    /// Control key was pressed.
231    pub control: bool,
232    /// Shift key was pressed.
233    pub shift: bool,
234    /// Primary key pressed.
235    pub key: Key,
236}
237
238impl Display for KeyStroke {
239    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
240        if self.alt {
241            write!(f, "\\e")?;
242        }
243        if self.control {
244            write!(f, "\\C-")?;
245        }
246        if self.shift {
247            // TODO: Figure out what to do here or if the key encodes the shift in it.
248        }
249        self.key.fmt(f)
250    }
251}
252
253impl From<Key> for KeyStroke {
254    /// Creates a new key stroke with a single key.
255    fn from(value: Key) -> Self {
256        Self {
257            alt: false,
258            control: false,
259            shift: false,
260            key: value,
261        }
262    }
263}
264
265#[derive(Clone, Debug, Eq, Hash, PartialEq)]
266/// Represents a single key.
267pub enum Key {
268    /// A simple character key.
269    Character(char),
270    /// Backspace key.
271    Backspace,
272    /// Enter key.
273    Enter,
274    /// Left arrow key.
275    Left,
276    /// Right arrow key.
277    Right,
278    /// Up arrow key.
279    Up,
280    /// Down arrow key.
281    Down,
282    /// Home key.
283    Home,
284    /// End key.
285    End,
286    /// Page up key.
287    PageUp,
288    /// Page down key.
289    PageDown,
290    /// Tab key.
291    Tab,
292    /// Shift + Tab key.
293    BackTab,
294    /// Delete key.
295    Delete,
296    /// Insert key.
297    Insert,
298    /// F key.
299    F(u8),
300    /// Escape key.
301    Escape,
302}
303
304impl Display for Key {
305    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
306        match self {
307            Self::Character(c @ ('\\' | '\"' | '\'')) => write!(f, "\\{c}")?,
308            Self::Character(c) => write!(f, "{c}")?,
309            Self::Backspace => write!(f, "Backspace")?,
310            Self::Enter => write!(f, "Enter")?,
311            Self::Left => write!(f, "Left")?,
312            Self::Right => write!(f, "Right")?,
313            Self::Up => write!(f, "Up")?,
314            Self::Down => write!(f, "Down")?,
315            Self::Home => write!(f, "Home")?,
316            Self::End => write!(f, "End")?,
317            Self::PageUp => write!(f, "PageUp")?,
318            Self::PageDown => write!(f, "PageDown")?,
319            Self::Tab => write!(f, "Tab")?,
320            Self::BackTab => write!(f, "BackTab")?,
321            Self::Delete => write!(f, "Delete")?,
322            Self::Insert => write!(f, "Insert")?,
323            Self::F(n) => write!(f, "F{n}")?,
324            Self::Escape => write!(f, "Esc")?,
325        }
326
327        Ok(())
328    }
329}
330
331/// Encapsulates the shell's interaction with key bindings for input.
332pub trait KeyBindings: Send {
333    /// Retrieves current bindings.
334    fn get_current(&self) -> HashMap<KeySequence, KeyAction>;
335    /// Updates a binding.
336    fn bind(&mut self, seq: KeySequence, action: KeyAction) -> Result<(), std::io::Error>;
337}