use serde::{Deserialize, Serialize}; #[derive(Clone, Copy, Serialize, Deserialize)] #[derive(Debug)] #[serde(into = "&str")] #[serde(try_from = "&str")] pub enum Action { App(AppAction), Buffer(BufferAction), Cursor(CursorAction), } impl Action { pub const fn clears_popups(self) -> bool { use Action::*; match self { App(app_action) => app_action.clears_popups(), Buffer(buffer_action) => buffer_action.clears_popups(), Cursor(cursor_action) => cursor_action.clears_popups(), } } pub const fn is_inspection(self) -> bool { use Action::*; use BufferAction::*; matches!(self, Buffer(InspectSelection | InspectSelectionColor)) } } impl From for &str { fn from(action: Action) -> Self { match action { Action::App(app_action) => app_action.into(), Action::Buffer(buffer_action) => buffer_action.into(), Action::Cursor(cursor_action) => cursor_action.into(), } } } impl TryFrom<&str> for Action { type Error = String; fn try_from(string: &str) -> Result { AppAction::try_from(string).map(Self::from) .or_else(|()| BufferAction::try_from(string).map(Self::from)) .or_else(|()| CursorAction::try_from(string).map(Self::from)) .map_err(|()| format!("invalid action: {string}")) } } // actions that act on the app as a whole, not just one buffer #[derive(Debug, Clone, Copy, Deserialize)] pub enum AppAction { QuitIfSaved, Quit, PreviousBuffer, NextBuffer, Yank, } impl AppAction { const fn clears_popups(self) -> bool { use AppAction::*; #[allow(clippy::match_same_arms)] match self { QuitIfSaved => true, Quit => true, PreviousBuffer => false, NextBuffer => false, Yank => false, } } } impl From for &str { fn from(app_action: AppAction) -> Self { use AppAction::*; match app_action { QuitIfSaved => "quit_if_saved", Quit => "quit", PreviousBuffer => "previous_buffer", NextBuffer => "next_buffer", Yank => "yank", } } } impl From for Action { fn from(app_action: AppAction) -> Self { Self::App(app_action) } } impl TryFrom<&str> for AppAction { type Error = (); fn try_from(string: &str) -> Result { use AppAction::*; match string { "quit_if_saved" => Ok(QuitIfSaved), "quit" => Ok(Quit), "previous_buffer" => Ok(PreviousBuffer), "next_buffer" => Ok(NextBuffer), "yank" => Ok(Yank), _ => Err(()), } } } #[derive(Clone, Copy, Deserialize)] #[derive(Debug)] pub enum BufferAction { NormalMode, SelectMode, Goto, View, Replace, Space, Repeat, To, ScrollDown, ScrollUp, PageCursorHalfDown, PageCursorHalfUp, PageDown, PageUp, CollapseSelection, FlipSelections, Delete, Undo, Redo, Save, CopySelectionOnNextLine, RotateSelectionsBackward, RotateSelectionsForward, KeepPrimarySelection, RemovePrimarySelection, SplitSelectionsInto1s, SplitSelectionsInto2s, SplitSelectionsInto3s, SplitSelectionsInto4s, SplitSelectionsInto5s, SplitSelectionsInto6s, SplitSelectionsInto7s, SplitSelectionsInto8s, SplitSelectionsInto9s, JumpToSelectedOffset, JumpToSelectedOffsetRelativeToMark, ToggleMark, AlignViewCenter, AlignViewBottom, AlignViewTop, FindTillMark, FindTillNull, FindTillFF, ExtendTillMark, ExtendTillNull, ExtendTillFF, InspectSelection, InspectSelectionColor, } impl BufferAction { const fn clears_popups(self) -> bool { use BufferAction::*; #[allow(clippy::match_same_arms)] match self { NormalMode => false, SelectMode => false, Goto => false, View => false, Replace => true, Space => false, Repeat => true, To => false, ScrollDown => true, ScrollUp => true, PageCursorHalfDown => true, PageCursorHalfUp => true, PageDown => true, PageUp => true, CollapseSelection => true, FlipSelections => false, Delete => true, Undo => true, Redo => true, Save => false, CopySelectionOnNextLine => true, RotateSelectionsBackward => false, RotateSelectionsForward => false, KeepPrimarySelection => true, RemovePrimarySelection => true, SplitSelectionsInto1s => true, SplitSelectionsInto2s => true, SplitSelectionsInto3s => true, SplitSelectionsInto4s => true, SplitSelectionsInto5s => true, SplitSelectionsInto6s => true, SplitSelectionsInto7s => true, SplitSelectionsInto8s => true, SplitSelectionsInto9s => true, JumpToSelectedOffset => true, JumpToSelectedOffsetRelativeToMark => true, ToggleMark => false, AlignViewCenter => false, AlignViewBottom => false, AlignViewTop => false, FindTillMark => true, FindTillNull => true, FindTillFF => true, ExtendTillMark => true, ExtendTillNull => true, ExtendTillFF => true, InspectSelection => true, InspectSelectionColor => true, } } } impl From for &str { fn from(buffer_action: BufferAction) -> Self { use BufferAction::*; match buffer_action { NormalMode => "normal_mode", SelectMode => "select_mode", Goto => "goto", View => "view", Replace => "replace", Space => "space", Repeat => "repeat", To => "to", ScrollDown => "scroll_down", ScrollUp => "scroll_up", PageCursorHalfDown => "page_cursor_half_down", PageCursorHalfUp => "page_cursor_half_up", PageDown => "page_down", PageUp => "page_up", CollapseSelection => "collapse_selection", FlipSelections => "flip_selections", Delete => "delete", Undo => "undo", Redo => "redo", Save => "save", CopySelectionOnNextLine => "copy_selection_on_next_line", RotateSelectionsBackward => "rotate_selections_backward", RotateSelectionsForward => "rotate_selections_forward", KeepPrimarySelection => "keep_primary_selection", RemovePrimarySelection => "remove_primary_selection", SplitSelectionsInto1s => "split_selections_into_1s", SplitSelectionsInto2s => "split_selections_into_2s", SplitSelectionsInto3s => "split_selections_into_3s", SplitSelectionsInto4s => "split_selections_into_4s", SplitSelectionsInto5s => "split_selections_into_5s", SplitSelectionsInto6s => "split_selections_into_6s", SplitSelectionsInto7s => "split_selections_into_7s", SplitSelectionsInto8s => "split_selections_into_8s", SplitSelectionsInto9s => "split_selections_into_9s", JumpToSelectedOffset => "jump_to_selected_offset", JumpToSelectedOffsetRelativeToMark => "jump_to_selected_offset_relative_to_mark", ToggleMark => "toggle_mark", AlignViewCenter => "align_view_center", AlignViewBottom => "align_view_bottom", AlignViewTop => "align_view_top", FindTillMark => "find_till_mark", FindTillNull => "find_till_null", FindTillFF => "find_till_ff", ExtendTillMark => "extend_till_mark", ExtendTillNull => "extend_till_null", ExtendTillFF => "extend_till_ff", InspectSelection => "inspect_selection", InspectSelectionColor => "inspect_selection_color", } } } impl From for Action { fn from(buffer_action: BufferAction) -> Self { Self::Buffer(buffer_action) } } impl TryFrom<&str> for BufferAction { type Error = (); fn try_from(string: &str) -> Result { use BufferAction::*; match string { "normal_mode" => Ok(NormalMode), "select_mode" => Ok(SelectMode), "goto" => Ok(Goto), "view" => Ok(View), "replace" => Ok(Replace), "space" => Ok(Space), "repeat" => Ok(Repeat), "to" => Ok(To), "scroll_down" => Ok(ScrollDown), "scroll_up" => Ok(ScrollUp), "page_cursor_half_down" => Ok(PageCursorHalfDown), "page_cursor_half_up" => Ok(PageCursorHalfUp), "page_down" => Ok(PageDown), "page_up" => Ok(PageUp), "collapse_selection" => Ok(CollapseSelection), "flip_selections" => Ok(FlipSelections), "delete" => Ok(Delete), "undo" => Ok(Undo), "redo" => Ok(Redo), "save" => Ok(Save), "copy_selection_on_next_line" => Ok(CopySelectionOnNextLine), "rotate_selections_backward" => Ok(RotateSelectionsBackward), "rotate_selections_forward" => Ok(RotateSelectionsForward), "keep_primary_selection" => Ok(KeepPrimarySelection), "remove_primary_selection" => Ok(RemovePrimarySelection), "split_selections_into_1s" => Ok(SplitSelectionsInto1s), "split_selections_into_2s" => Ok(SplitSelectionsInto2s), "split_selections_into_3s" => Ok(SplitSelectionsInto3s), "split_selections_into_4s" => Ok(SplitSelectionsInto4s), "split_selections_into_5s" => Ok(SplitSelectionsInto5s), "split_selections_into_6s" => Ok(SplitSelectionsInto6s), "split_selections_into_7s" => Ok(SplitSelectionsInto7s), "split_selections_into_8s" => Ok(SplitSelectionsInto8s), "split_selections_into_9s" => Ok(SplitSelectionsInto9s), "jump_to_selected_offset" => Ok(JumpToSelectedOffset), "jump_to_selected_offset_relative_to_mark" => Ok(JumpToSelectedOffsetRelativeToMark), "toggle_mark" => Ok(ToggleMark), "align_view_center" => Ok(AlignViewCenter), "align_view_bottom" => Ok(AlignViewBottom), "align_view_top" => Ok(AlignViewTop), "find_till_mark" => Ok(FindTillMark), "find_till_null" => Ok(FindTillNull), "find_till_ff" => Ok(FindTillFF), "extend_till_mark" => Ok(ExtendTillMark), "extend_till_null" => Ok(ExtendTillNull), "extend_till_ff" => Ok(ExtendTillFF), "inspect_selection" => Ok(InspectSelection), "inspect_selection_color" => Ok(InspectSelectionColor), _ => Err(()), } } } #[derive(Clone, Copy, Serialize, Deserialize)] #[derive(Debug)] #[serde(rename_all = "snake_case")] pub enum CursorAction { MoveByteUp, MoveByteDown, MoveByteLeft, MoveByteRight, ExtendByteUp, ExtendByteDown, ExtendByteLeft, ExtendByteRight, GotoLineStart, GotoLineEnd, GotoFileStart, GotoFileEnd, ExtendLineStart, ExtendLineEnd, ExtendFileStart, ExtendFileEnd, MoveNextWordStart, MoveNextWordEnd, MovePreviousWordStart, ExtendNextWordStart, ExtendNextWordEnd, ExtendPreviousWordStart, ExtendLineBelow, ExtendLineAbove, } impl CursorAction { const fn clears_popups(self) -> bool { use CursorAction::*; #[allow(clippy::match_same_arms)] match self { MoveByteUp => true, MoveByteDown => true, MoveByteLeft => true, MoveByteRight => true, ExtendByteUp => true, ExtendByteDown => true, ExtendByteLeft => true, ExtendByteRight => true, GotoLineStart => true, GotoLineEnd => true, GotoFileStart => true, GotoFileEnd => true, ExtendLineStart => true, ExtendLineEnd => true, ExtendFileStart => true, ExtendFileEnd => true, MoveNextWordStart => true, MoveNextWordEnd => true, MovePreviousWordStart => true, ExtendNextWordStart => true, ExtendNextWordEnd => true, ExtendPreviousWordStart => true, ExtendLineBelow => true, ExtendLineAbove => true, } } } impl From for &str { fn from(cursor_action: CursorAction) -> Self { use CursorAction::*; match cursor_action { MoveByteUp => "move_byte_up", MoveByteDown => "move_byte_down", MoveByteLeft => "move_byte_left", MoveByteRight => "move_byte_right", ExtendByteUp => "extend_byte_up", ExtendByteDown => "extend_byte_down", ExtendByteLeft => "extend_byte_left", ExtendByteRight => "extend_byte_right", GotoLineStart => "goto_line_start", GotoLineEnd => "goto_line_end", GotoFileStart => "goto_file_start", GotoFileEnd => "goto_file_end", ExtendLineStart => "extend_line_start", ExtendLineEnd => "extend_line_end", ExtendFileStart => "extend_file_start", ExtendFileEnd => "extend_file_end", MoveNextWordStart => "move_next_word_start", MoveNextWordEnd => "move_next_word_end", MovePreviousWordStart => "move_previous_word_start", ExtendNextWordStart => "extend_next_word_start", ExtendNextWordEnd => "extend_next_word_end", ExtendPreviousWordStart => "extend_previous_word_start", ExtendLineBelow => "extend_line_below", ExtendLineAbove => "extend_line_above", } } } impl From for Action { fn from(cursor_action: CursorAction) -> Self { Self::Cursor(cursor_action) } } impl TryFrom<&str> for CursorAction { type Error = (); fn try_from(string: &str) -> Result { use CursorAction::*; match string { "move_byte_up" => Ok(MoveByteUp), "move_byte_down" => Ok(MoveByteDown), "move_byte_left" => Ok(MoveByteLeft), "move_byte_right" => Ok(MoveByteRight), "extend_byte_up" => Ok(ExtendByteUp), "extend_byte_down" => Ok(ExtendByteDown), "extend_byte_left" => Ok(ExtendByteLeft), "extend_byte_right" => Ok(ExtendByteRight), "goto_line_start" => Ok(GotoLineStart), "goto_line_end" => Ok(GotoLineEnd), "goto_file_start" => Ok(GotoFileStart), "goto_file_end" => Ok(GotoFileEnd), "extend_line_start" => Ok(ExtendLineStart), "extend_line_end" => Ok(ExtendLineEnd), "extend_file_start" => Ok(ExtendFileStart), "extend_file_end" => Ok(ExtendFileEnd), "move_next_word_start" => Ok(MoveNextWordStart), "move_next_word_end" => Ok(MoveNextWordEnd), "move_previous_word_start" => Ok(MovePreviousWordStart), "extend_next_word_start" => Ok(ExtendNextWordStart), "extend_next_word_end" => Ok(ExtendNextWordEnd), "extend_previous_word_start" => Ok(ExtendPreviousWordStart), "extend_line_below" => Ok(ExtendLineBelow), "extend_line_above" => Ok(ExtendLineAbove), _ => Err(()), } } }