make config (de)serializable

This commit is contained in:
alice pellerin
2026-04-05 18:55:23 -05:00
parent a042e6ae34
commit d45e0a5032
6 changed files with 683 additions and 172 deletions
+286 -4
View File
@@ -1,16 +1,41 @@
use std::{cmp::min, collections::hash_set::Entry, convert::identity, fs::File, io::Write, iter, mem::{replace, swap}};
use ratatui::{style::{Color, Stylize}, text::Span};
use serde::{Deserialize, Serialize};
use crate::{BYTES_OF_PADDING, BYTES_PER_LINE, LINES_OF_PADDING, app::WindowSize, buffer::{Buffer, Mode, PartialAction, Popup}, cursor::Cursor, edit_action::EditAction};
#[derive(Clone, Copy)]
#[derive(Clone, Copy, Serialize, Deserialize)]
#[derive(Debug)]
#[serde(into = "&str")]
#[serde(try_from = "&str")]
pub enum Action {
App(AppAction),
Buffer(BufferAction),
Cursor(CursorAction),
}
impl From<Action> 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<Self, String> {
AppAction::try_from(string).map(Action::from)
.or_else(|_| BufferAction::try_from(string).map(Action::from))
.or_else(|_| CursorAction::try_from(string).map(Action::from))
.map_err(|_| format!("invalid action: {}", string))
}
}
// actions that act on the app as a whole, not just one buffer
#[derive(Debug, Clone, Copy)]
#[derive(Debug, Clone, Copy, Deserialize)]
pub enum AppAction {
QuitIfSaved,
Quit,
@@ -21,13 +46,50 @@ pub enum AppAction {
Yank,
}
impl From<AppAction> 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<AppAction> for Action {
fn from(app_action: AppAction) -> Self {
Self::App(app_action)
}
}
#[derive(Clone, Copy)]
impl TryFrom<&str> for AppAction {
type Error = ();
fn try_from(string: &str) -> Result<Self, ()> {
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,
@@ -93,13 +155,161 @@ pub enum BufferAction {
InspectSelectionColor,
}
impl From<BufferAction> 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_1_s",
SplitSelectionsInto2s => "split_selections_into_2_s",
SplitSelectionsInto3s => "split_selections_into_3_s",
SplitSelectionsInto4s => "split_selections_into_4_s",
SplitSelectionsInto5s => "split_selections_into_5_s",
SplitSelectionsInto6s => "split_selections_into_6_s",
SplitSelectionsInto7s => "split_selections_into_7_s",
SplitSelectionsInto8s => "split_selections_into_8_s",
SplitSelectionsInto9s => "split_selections_into_9_s",
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",
ExtendToMark => "extend_to_mark",
ExtendToNull => "extend_to_null",
ExtendToFF => "extend_to_ff",
InspectSelection => "inspect_selection",
InspectSelectionColor => "inspect_selection_color",
}
}
}
impl From<BufferAction> for Action {
fn from(buffer_action: BufferAction) -> Self {
Self::Buffer(buffer_action)
}
}
#[derive(Clone, Copy)]
impl TryFrom<&str> for BufferAction {
type Error = ();
fn try_from(string: &str) -> Result<Self, ()> {
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_1_s" => Ok(SplitSelectionsInto1s),
"split_selections_into_2_s" => Ok(SplitSelectionsInto2s),
"split_selections_into_3_s" => Ok(SplitSelectionsInto3s),
"split_selections_into_4_s" => Ok(SplitSelectionsInto4s),
"split_selections_into_5_s" => Ok(SplitSelectionsInto5s),
"split_selections_into_6_s" => Ok(SplitSelectionsInto6s),
"split_selections_into_7_s" => Ok(SplitSelectionsInto7s),
"split_selections_into_8_s" => Ok(SplitSelectionsInto8s),
"split_selections_into_9_s" => 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),
"extend_to_mark" => Ok(ExtendToMark),
"extend_to_null" => Ok(ExtendToNull),
"extend_to_ff" => Ok(ExtendToFF),
"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,
@@ -128,12 +338,84 @@ pub enum CursorAction {
ExtendLineAbove,
}
impl From<CursorAction> 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",
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<CursorAction> 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<Self, ()> {
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),
"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(()),
}
}
}
impl Buffer {
pub fn execute(&mut self, action: BufferAction, window_size: WindowSize) {
match action {