use std::{convert::Infallible, fmt, str::FromStr};
use crate::canvas::actions::CanvasAction;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum CanvasKeyAction {
MoveLeft,
MoveRight,
MoveUp,
MoveDown,
NextField,
PrevField,
MoveLineStart,
MoveLineEnd,
MoveHalfPageUp,
MoveHalfPageDown,
MoveFirstLine,
MoveLastLine,
MoveWordNext,
MoveWordPrev,
MoveWordEnd,
MoveWordEndPrev,
MoveBigWordNext,
MoveBigWordPrev,
MoveBigWordEnd,
MoveBigWordEndPrev,
DeleteCharBackward,
DeleteCharForward,
Undo,
Redo,
OpenLineBelow,
OpenLineAbove,
EnterEditModeLineStart,
EnterEditModeLineEnd,
DeleteLine,
DeleteToLineEnd,
ChangeLine,
ChangeToLineEnd,
OperatorDelete,
OperatorChange,
OperatorYank,
JoinLineBelow,
YankLine,
PasteAfter,
PasteBefore,
OpenSuggestions,
ApplySuggestion,
ExitSuggestions,
EnterDecider,
SuggestionDown,
SuggestionUp,
EnterEditModeBefore,
EnterEditModeAfter,
Exit,
ExitEditMode,
EnterHighlightMode,
EnterHighlightModeLinewise,
ExitHighlightMode,
DeleteSelection,
DeleteSelectionNoYank,
ChangeSelection,
ChangeSelectionNoYank,
YankSelection,
CollapseSelection,
ExtendLineBelow,
ExtendToLineBounds,
SearchNext,
SearchPrev,
SelectAll,
FlipSelections,
SwitchCase,
SwitchToLowercase,
SwitchToUppercase,
TrimSelections,
GotoFirstNonWhitespace,
MovePageUp,
MovePageDown,
SearchSelection,
EnsureSelectionForward,
MatchBrackets,
IndentSelection,
UnindentSelection,
IncrementNumber,
DecrementNumber,
FindNextChar,
FindPrevChar,
TillNextChar,
TillPrevChar,
ReplaceChar,
RepeatLastFind,
RepeatLastFindReverse,
SurroundAdd,
SurroundDelete,
SurroundReplace,
DeleteWordBackward,
DeleteToLineStart,
DeleteWordForward,
ClearSearch,
MoveLineUp,
MoveLineDown,
DuplicateLineUp,
DuplicateLineDown,
CopyLine,
CutLine,
SelectLeft,
SelectRight,
SelectUp,
SelectDown,
SelectWordPrev,
SelectWordNext,
SelectLineStart,
SelectLineEnd,
SelectDocStart,
SelectDocEnd,
Unknown(String),
}
impl CanvasKeyAction {
pub fn from_name(name: &str) -> Self {
match name {
"move_left" => Self::MoveLeft,
"move_right" => Self::MoveRight,
"move_up" => Self::MoveUp,
"move_down" => Self::MoveDown,
"next_field" => Self::NextField,
"prev_field" => Self::PrevField,
"move_line_start" => Self::MoveLineStart,
"move_line_end" => Self::MoveLineEnd,
"move_half_page_up" => Self::MoveHalfPageUp,
"move_half_page_down" => Self::MoveHalfPageDown,
"move_first_line" => Self::MoveFirstLine,
"move_last_line" => Self::MoveLastLine,
"move_word_next" => Self::MoveWordNext,
"move_word_prev" => Self::MoveWordPrev,
"move_word_end" => Self::MoveWordEnd,
"move_word_end_prev" => Self::MoveWordEndPrev,
"move_big_word_next" => Self::MoveBigWordNext,
"move_big_word_prev" => Self::MoveBigWordPrev,
"move_big_word_end" => Self::MoveBigWordEnd,
"move_big_word_end_prev" => Self::MoveBigWordEndPrev,
"delete_char_backward" => Self::DeleteCharBackward,
"delete_char_forward" => Self::DeleteCharForward,
"undo" => Self::Undo,
"redo" => Self::Redo,
"open_line_below" => Self::OpenLineBelow,
"open_line_above" => Self::OpenLineAbove,
"enter_edit_mode_line_start" => Self::EnterEditModeLineStart,
"enter_edit_mode_line_end" => Self::EnterEditModeLineEnd,
"delete_line" => Self::DeleteLine,
"delete_to_line_end" => Self::DeleteToLineEnd,
"change_line" => Self::ChangeLine,
"change_to_line_end" => Self::ChangeToLineEnd,
"operator_delete" => Self::OperatorDelete,
"operator_change" => Self::OperatorChange,
"operator_yank" => Self::OperatorYank,
"join_line_below" => Self::JoinLineBelow,
"yank_line" => Self::YankLine,
"paste_after" => Self::PasteAfter,
"paste_before" => Self::PasteBefore,
"open_suggestions" => Self::OpenSuggestions,
"apply_suggestion" => Self::ApplySuggestion,
"exit_suggestions" => Self::ExitSuggestions,
"enter_decider" => Self::EnterDecider,
"suggestion_down" => Self::SuggestionDown,
"suggestion_up" => Self::SuggestionUp,
"enter_edit_mode_before" => Self::EnterEditModeBefore,
"enter_edit_mode_after" => Self::EnterEditModeAfter,
"exit" => Self::Exit,
"exit_edit_mode" => Self::ExitEditMode,
"enter_highlight_mode" => Self::EnterHighlightMode,
"enter_highlight_mode_linewise" => Self::EnterHighlightModeLinewise,
"exit_highlight_mode" => Self::ExitHighlightMode,
"delete_selection" => Self::DeleteSelection,
"delete_selection_noyank" => Self::DeleteSelectionNoYank,
"change_selection" => Self::ChangeSelection,
"change_selection_noyank" => Self::ChangeSelectionNoYank,
"yank_selection" => Self::YankSelection,
"collapse_selection" => Self::CollapseSelection,
"extend_line_below" => Self::ExtendLineBelow,
"extend_to_line_bounds" => Self::ExtendToLineBounds,
"search_next" => Self::SearchNext,
"search_prev" => Self::SearchPrev,
"select_all" => Self::SelectAll,
"flip_selections" => Self::FlipSelections,
"switch_case" => Self::SwitchCase,
"switch_to_lowercase" => Self::SwitchToLowercase,
"switch_to_uppercase" => Self::SwitchToUppercase,
"trim_selections" => Self::TrimSelections,
"goto_first_nonwhitespace" => Self::GotoFirstNonWhitespace,
"move_page_up" => Self::MovePageUp,
"move_page_down" => Self::MovePageDown,
"search_selection" => Self::SearchSelection,
"ensure_selection_forward" => Self::EnsureSelectionForward,
"match_brackets" => Self::MatchBrackets,
"indent_selection" => Self::IndentSelection,
"unindent_selection" => Self::UnindentSelection,
"increment_number" => Self::IncrementNumber,
"decrement_number" => Self::DecrementNumber,
"find_next_char" => Self::FindNextChar,
"find_prev_char" => Self::FindPrevChar,
"till_next_char" => Self::TillNextChar,
"till_prev_char" => Self::TillPrevChar,
"replace_char" => Self::ReplaceChar,
"repeat_last_find" => Self::RepeatLastFind,
"repeat_last_find_reverse" => Self::RepeatLastFindReverse,
"surround_add" => Self::SurroundAdd,
"surround_delete" => Self::SurroundDelete,
"surround_replace" => Self::SurroundReplace,
"delete_word_backward" => Self::DeleteWordBackward,
"delete_to_line_start" => Self::DeleteToLineStart,
"delete_word_forward" => Self::DeleteWordForward,
"clear_search" => Self::ClearSearch,
"move_line_up" => Self::MoveLineUp,
"move_line_down" => Self::MoveLineDown,
"duplicate_line_up" => Self::DuplicateLineUp,
"duplicate_line_down" => Self::DuplicateLineDown,
"copy_line" => Self::CopyLine,
"cut_line" => Self::CutLine,
"select_left" => Self::SelectLeft,
"select_right" => Self::SelectRight,
"select_up" => Self::SelectUp,
"select_down" => Self::SelectDown,
"select_word_prev" => Self::SelectWordPrev,
"select_word_next" => Self::SelectWordNext,
"select_line_start" => Self::SelectLineStart,
"select_line_end" => Self::SelectLineEnd,
"select_doc_start" => Self::SelectDocStart,
"select_doc_end" => Self::SelectDocEnd,
other => Self::Unknown(other.to_string()),
}
}
pub fn as_str(&self) -> &str {
match self {
Self::MoveLeft => "move_left",
Self::MoveRight => "move_right",
Self::MoveUp => "move_up",
Self::MoveDown => "move_down",
Self::NextField => "next_field",
Self::PrevField => "prev_field",
Self::MoveLineStart => "move_line_start",
Self::MoveLineEnd => "move_line_end",
Self::MoveHalfPageUp => "move_half_page_up",
Self::MoveHalfPageDown => "move_half_page_down",
Self::MoveFirstLine => "move_first_line",
Self::MoveLastLine => "move_last_line",
Self::MoveWordNext => "move_word_next",
Self::MoveWordPrev => "move_word_prev",
Self::MoveWordEnd => "move_word_end",
Self::MoveWordEndPrev => "move_word_end_prev",
Self::MoveBigWordNext => "move_big_word_next",
Self::MoveBigWordPrev => "move_big_word_prev",
Self::MoveBigWordEnd => "move_big_word_end",
Self::MoveBigWordEndPrev => "move_big_word_end_prev",
Self::DeleteCharBackward => "delete_char_backward",
Self::DeleteCharForward => "delete_char_forward",
Self::Undo => "undo",
Self::Redo => "redo",
Self::OpenLineBelow => "open_line_below",
Self::OpenLineAbove => "open_line_above",
Self::EnterEditModeLineStart => "enter_edit_mode_line_start",
Self::EnterEditModeLineEnd => "enter_edit_mode_line_end",
Self::DeleteLine => "delete_line",
Self::DeleteToLineEnd => "delete_to_line_end",
Self::ChangeLine => "change_line",
Self::ChangeToLineEnd => "change_to_line_end",
Self::OperatorDelete => "operator_delete",
Self::OperatorChange => "operator_change",
Self::OperatorYank => "operator_yank",
Self::JoinLineBelow => "join_line_below",
Self::YankLine => "yank_line",
Self::PasteAfter => "paste_after",
Self::PasteBefore => "paste_before",
Self::OpenSuggestions => "open_suggestions",
Self::ApplySuggestion => "apply_suggestion",
Self::ExitSuggestions => "exit_suggestions",
Self::EnterDecider => "enter_decider",
Self::SuggestionDown => "suggestion_down",
Self::SuggestionUp => "suggestion_up",
Self::EnterEditModeBefore => "enter_edit_mode_before",
Self::EnterEditModeAfter => "enter_edit_mode_after",
Self::Exit => "exit",
Self::ExitEditMode => "exit_edit_mode",
Self::EnterHighlightMode => "enter_highlight_mode",
Self::EnterHighlightModeLinewise => "enter_highlight_mode_linewise",
Self::ExitHighlightMode => "exit_highlight_mode",
Self::DeleteSelection => "delete_selection",
Self::DeleteSelectionNoYank => "delete_selection_noyank",
Self::ChangeSelection => "change_selection",
Self::ChangeSelectionNoYank => "change_selection_noyank",
Self::YankSelection => "yank_selection",
Self::CollapseSelection => "collapse_selection",
Self::SearchNext => "search_next",
Self::SearchPrev => "search_prev",
Self::SelectAll => "select_all",
Self::FlipSelections => "flip_selections",
Self::SwitchCase => "switch_case",
Self::SwitchToLowercase => "switch_to_lowercase",
Self::SwitchToUppercase => "switch_to_uppercase",
Self::TrimSelections => "trim_selections",
Self::GotoFirstNonWhitespace => "goto_first_nonwhitespace",
Self::MovePageUp => "move_page_up",
Self::MovePageDown => "move_page_down",
Self::SearchSelection => "search_selection",
Self::EnsureSelectionForward => "ensure_selection_forward",
Self::MatchBrackets => "match_brackets",
Self::IndentSelection => "indent_selection",
Self::UnindentSelection => "unindent_selection",
Self::IncrementNumber => "increment_number",
Self::DecrementNumber => "decrement_number",
Self::FindNextChar => "find_next_char",
Self::FindPrevChar => "find_prev_char",
Self::TillNextChar => "till_next_char",
Self::TillPrevChar => "till_prev_char",
Self::ReplaceChar => "replace_char",
Self::RepeatLastFind => "repeat_last_find",
Self::RepeatLastFindReverse => "repeat_last_find_reverse",
Self::SurroundAdd => "surround_add",
Self::SurroundDelete => "surround_delete",
Self::SurroundReplace => "surround_replace",
Self::DeleteWordBackward => "delete_word_backward",
Self::DeleteToLineStart => "delete_to_line_start",
Self::DeleteWordForward => "delete_word_forward",
Self::ClearSearch => "clear_search",
Self::MoveLineUp => "move_line_up",
Self::MoveLineDown => "move_line_down",
Self::DuplicateLineUp => "duplicate_line_up",
Self::DuplicateLineDown => "duplicate_line_down",
Self::CopyLine => "copy_line",
Self::CutLine => "cut_line",
Self::SelectLeft => "select_left",
Self::SelectRight => "select_right",
Self::SelectUp => "select_up",
Self::SelectDown => "select_down",
Self::SelectWordPrev => "select_word_prev",
Self::SelectWordNext => "select_word_next",
Self::SelectLineStart => "select_line_start",
Self::SelectLineEnd => "select_line_end",
Self::SelectDocStart => "select_doc_start",
Self::SelectDocEnd => "select_doc_end",
Self::ExtendLineBelow => "extend_line_below",
Self::ExtendToLineBounds => "extend_to_line_bounds",
Self::Unknown(other) => other.as_str(),
}
}
pub fn to_canvas_action(&self) -> Option<CanvasAction> {
Some(match self {
Self::MoveLeft => CanvasAction::MoveLeft,
Self::MoveRight => CanvasAction::MoveRight,
Self::MoveUp => CanvasAction::MoveUp,
Self::MoveDown => CanvasAction::MoveDown,
Self::MoveWordNext => CanvasAction::MoveWordNext,
Self::MoveWordPrev => CanvasAction::MoveWordPrev,
Self::MoveWordEnd => CanvasAction::MoveWordEnd,
Self::MoveWordEndPrev => CanvasAction::MoveWordEndPrev,
Self::MoveBigWordNext => CanvasAction::MoveBigWordNext,
Self::MoveBigWordPrev => CanvasAction::MoveBigWordPrev,
Self::MoveBigWordEnd => CanvasAction::MoveBigWordEnd,
Self::MoveBigWordEndPrev => CanvasAction::MoveBigWordEndPrev,
Self::MoveLineStart => CanvasAction::MoveLineStart,
Self::MoveLineEnd => CanvasAction::MoveLineEnd,
Self::MoveHalfPageUp | Self::MoveHalfPageDown => return None,
Self::NextField => CanvasAction::NextField,
Self::PrevField => CanvasAction::PrevField,
Self::MoveFirstLine => CanvasAction::MoveFirstLine,
Self::MoveLastLine => CanvasAction::MoveLastLine,
Self::DeleteCharBackward => CanvasAction::DeleteBackward,
Self::DeleteCharForward => CanvasAction::DeleteForward,
Self::Undo => CanvasAction::Undo,
Self::Redo => CanvasAction::Redo,
Self::OpenSuggestions => CanvasAction::TriggerSuggestions,
Self::SuggestionUp => CanvasAction::SuggestionUp,
Self::SuggestionDown => CanvasAction::SuggestionDown,
Self::ApplySuggestion => CanvasAction::SelectSuggestion,
Self::ExitSuggestions => CanvasAction::ExitSuggestions,
Self::EnterEditModeBefore => CanvasAction::EnterEditMode,
Self::EnterEditModeAfter => CanvasAction::EnterEditModeAfter,
Self::ExitEditMode => CanvasAction::ExitEditMode,
Self::EnterHighlightMode => CanvasAction::EnterHighlightMode,
Self::EnterHighlightModeLinewise => CanvasAction::EnterHighlightModeLinewise,
Self::ExitHighlightMode => CanvasAction::ExitHighlightMode,
Self::OpenLineBelow => CanvasAction::OpenLineBelow,
Self::OpenLineAbove => CanvasAction::OpenLineAbove,
Self::EnterEditModeLineStart
| Self::EnterEditModeLineEnd
| Self::DeleteLine
| Self::DeleteToLineEnd
| Self::ChangeLine
| Self::ChangeToLineEnd
| Self::OperatorDelete
| Self::OperatorChange
| Self::OperatorYank
| Self::JoinLineBelow
| Self::YankLine
| Self::PasteAfter
| Self::PasteBefore
| Self::DeleteSelection
| Self::DeleteSelectionNoYank
| Self::ChangeSelection
| Self::ChangeSelectionNoYank
| Self::YankSelection
| Self::CollapseSelection
| Self::ExtendLineBelow
| Self::ExtendToLineBounds
| Self::SearchNext
| Self::SearchPrev
| Self::SelectAll
| Self::FlipSelections
| Self::SwitchCase
| Self::SwitchToLowercase
| Self::SwitchToUppercase
| Self::TrimSelections
| Self::GotoFirstNonWhitespace
| Self::MovePageUp
| Self::MovePageDown
| Self::SearchSelection
| Self::EnsureSelectionForward
| Self::MatchBrackets
| Self::IndentSelection
| Self::UnindentSelection
| Self::IncrementNumber
| Self::DecrementNumber
| Self::FindNextChar
| Self::FindPrevChar
| Self::TillNextChar
| Self::TillPrevChar
| Self::ReplaceChar
| Self::RepeatLastFind
| Self::RepeatLastFindReverse
| Self::SurroundAdd
| Self::SurroundDelete
| Self::SurroundReplace
| Self::DeleteWordBackward
| Self::DeleteToLineStart
| Self::DeleteWordForward
| Self::ClearSearch
| Self::MoveLineUp
| Self::MoveLineDown
| Self::DuplicateLineUp
| Self::DuplicateLineDown
| Self::CopyLine
| Self::CutLine
| Self::SelectLeft
| Self::SelectRight
| Self::SelectUp
| Self::SelectDown
| Self::SelectWordPrev
| Self::SelectWordNext
| Self::SelectLineStart
| Self::SelectLineEnd
| Self::SelectDocStart
| Self::SelectDocEnd => return None,
Self::EnterDecider | Self::Exit | Self::Unknown(_) => return None,
})
}
}
impl FromStr for CanvasKeyAction {
type Err = Infallible;
fn from_str(name: &str) -> Result<Self, Self::Err> {
Ok(Self::from_name(name))
}
}
impl fmt::Display for CanvasKeyAction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
impl serde::Serialize for CanvasKeyAction {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(self.as_str())
}
}
impl<'de> serde::Deserialize<'de> for CanvasKeyAction {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let name = <String as serde::Deserialize>::deserialize(deserializer)?;
Ok(Self::from_name(&name))
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn action_names_round_trip_through_traits_and_serde() {
assert_eq!("undo".parse::<CanvasKeyAction>(), Ok(CanvasKeyAction::Undo));
assert_eq!(CanvasKeyAction::Redo.to_string(), "redo");
assert_eq!(
toml::from_str::<ActionConfig>("action = \"custom_action\"")
.unwrap()
.action,
CanvasKeyAction::Unknown("custom_action".to_string())
);
assert_eq!(
toml::to_string(&ActionConfig {
action: CanvasKeyAction::MoveLeft,
})
.unwrap(),
"action = \"move_left\"\n"
);
}
#[derive(Debug, serde::Deserialize, serde::Serialize)]
struct ActionConfig {
action: CanvasKeyAction,
}
}