diff --git a/Cargo.lock b/Cargo.lock index 15d22a6..718d378 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -70,6 +70,9 @@ name = "bitflags" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +dependencies = [ + "serde_core", +] [[package]] name = "block-buffer" @@ -158,6 +161,7 @@ dependencies = [ "mio", "parking_lot", "rustix", + "serde", "signal-hook", "signal-hook-mio", "winapi", @@ -438,6 +442,8 @@ dependencies = [ "crossterm", "itertools", "ratatui", + "serde", + "toml", ] [[package]] @@ -1101,6 +1107,15 @@ dependencies = [ "zmij", ] +[[package]] +name = "serde_spanned" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" +dependencies = [ + "serde_core", +] + [[package]] name = "sha2" version = "0.10.9" @@ -1333,6 +1348,45 @@ version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +[[package]] +name = "toml" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.1.2+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.1.1+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" + [[package]] name = "typenum" version = "1.19.0" @@ -1625,6 +1679,12 @@ dependencies = [ "windows-link", ] +[[package]] +name = "winnow" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" + [[package]] name = "wit-bindgen" version = "0.51.0" diff --git a/Cargo.toml b/Cargo.toml index da062b7..2fa7191 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,8 @@ version = "0.1.0" edition = "2024" [dependencies] -crossterm = "0.29.0" +crossterm = { version = "0.29.0", features = ["serde"] } itertools = "0.14.0" ratatui = "0.30.0" +serde = { version = "1.0.228", features = ["derive"] } +toml = "1.1.2" diff --git a/src/action.rs b/src/action.rs index 4bcefbf..d35c832 100644 --- a/src/action.rs +++ b/src/action.rs @@ -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 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(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 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) } } -#[derive(Clone, Copy)] +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, @@ -93,13 +155,161 @@ pub enum BufferAction { InspectSelectionColor, } +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_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 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 { + 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 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 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), + + "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 { diff --git a/src/buffer/mod.rs b/src/buffer/mod.rs index 46d2fa2..36f9a03 100644 --- a/src/buffer/mod.rs +++ b/src/buffer/mod.rs @@ -2,6 +2,7 @@ use core::slice::GetDisjointMutIndex; use std::{collections::HashSet, fs::File, io::Read, path::PathBuf}; use crossterm::event::KeyEvent; use ratatui::{layout::{Constraint, Rect}, style::{Color, Stylize}, text::Span, widgets::{Block, Clear, Widget}}; +use serde::{Deserialize, Serialize}; use crate::{BYTES_PER_LINE, action::{Action, AppAction, bytes_to_nat}, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction}; mod widget; @@ -36,12 +37,16 @@ pub struct Buffer { pub logs: Vec, } -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug)] +#[serde(rename_all = "snake_case")] pub enum Mode { Normal, Select, Insert } -#[derive(Clone, Copy, Hash, PartialEq, Eq)] +#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug)] +#[serde(rename_all = "snake_case")] pub enum PartialAction { Goto, View, Replace, Space, Repeat, To } @@ -73,13 +78,33 @@ impl Mode { impl PartialAction { pub const fn label(self) -> &'static str { + use PartialAction::*; + match self { - Self::Goto => "g", - Self::View => "z", - Self::Replace => "r", - Self::Space => "␠", - Self::Repeat => "×", - Self::To => "t", + Goto => "g", + View => "z", + Replace => "r", + Space => "␠", + Repeat => "×", + To => "t", + } + } +} + +impl TryFrom<&str> for PartialAction { + type Error = (); + + fn try_from(value: &str) -> Result { + use PartialAction::*; + + match value { + "goto" => Ok(Goto), + "view" => Ok(View), + "replace" => Ok(Replace), + "space" => Ok(Space), + "repeat" => Ok(Repeat), + "to" => Ok(To), + _ => Err(()), } } } diff --git a/src/config.rs b/src/config.rs index a68cc3d..ae67c49 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,25 +1,114 @@ -use std::collections::HashMap; +use std::{collections::{HashMap, hash_map::Entry}, fmt::{self, Formatter}}; use crossterm::event::{KeyCode, KeyEvent, KeyModifiers}; use crate::{action::{Action, AppAction, BufferAction, CursorAction}, buffer::{Mode, PartialAction}}; +use serde::{Deserialize, Deserializer, Serialize, Serializer, de::{Error, MapAccess, Unexpected, Visitor}, ser::SerializeMap}; +#[derive(Serialize, Deserialize)] +#[serde(transparent)] pub struct Config( pub HashMap ); +#[derive(Debug)] pub struct ModeConfig( pub HashMap, Keybinds> ); +#[derive(Serialize, Deserialize)] +#[derive(Debug)] +#[serde(transparent)] pub struct Keybinds( pub HashMap ); -#[derive(PartialEq, Eq, Hash)] +#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)] +#[derive(Debug)] +#[serde(into = "String")] +#[serde(try_from = "&str")] pub struct Keypress { code: KeyCode, modifiers: KeyModifiers } +impl Serialize for ModeConfig { + fn serialize(&self, serializer: S) -> Result { + let mut map = serializer.serialize_map(None)?; + + if let Some(keybinds) = self.0.get(&None) { + for (keypress, action) in &keybinds.0 { + map.serialize_entry( + &String::from(keypress), + &action + )?; + } + } + + for (partial_action, keybinds) in &self.0 { + let Some(partial_action) = partial_action else { continue }; + + map.serialize_entry( + partial_action.into(), + keybinds + )?; + } + + map.end() + } +} + +struct ModeConfigVisitor; + +impl<'de> Visitor<'de> for ModeConfigVisitor { + type Value = ModeConfig; + + fn expecting(&self, formatter: &mut Formatter) -> fmt::Result { + formatter.write_str("a config for keypresses in various partial action states") + } + + fn visit_map>( + self, + mut map: Map + ) -> Result { + let mut result = ModeConfig(HashMap::new()); + + while let Some(key) = map.next_key::<&str>()? { + if let Ok(partial_action) = PartialAction::try_from(key) { + let keybinds: Keybinds = map.next_value()?; + + match result.0.entry(Some(partial_action)) { + Entry::Occupied(mut occupied_entry) => { + occupied_entry.get_mut().0.extend(keybinds.0); + }, + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(keybinds); + } + } + } else { + let Ok(keypress) = key.try_into() else { + return Err(Error::invalid_value( + Unexpected::Str(key), + &"a valid keypress, with an optional modifier" + )); + }; + + result.0.entry(None) + .or_insert_with(|| Keybinds(HashMap::new())) + .0.insert(keypress, map.next_value()?); + } + } + + Ok(result) + } +} + +impl<'de> Deserialize<'de> for ModeConfig { + fn deserialize>( + deserializer: D + ) -> Result { + deserializer.deserialize_map(ModeConfigVisitor) + } +} + impl From<[(Mode, ModeConfig); N]> for Config { fn from(array: [(Mode, ModeConfig); N]) -> Self { Self(array.into()) @@ -55,11 +144,30 @@ const fn modifier_from_character(character: char) -> Option { } } +const fn str_from_modifiers(modifier: KeyModifiers) -> &'static str { + match modifier { + KeyModifiers::ALT => "A-", + KeyModifiers::CONTROL => "C-", + _ => "" + } +} + +fn string_from_code(code: KeyCode) -> String { + match code { + KeyCode::Char(character) => character.to_string(), + KeyCode::Up => "Up".to_string(), + KeyCode::Down => "Down".to_string(), + KeyCode::Left => "Left".to_string(), + KeyCode::Right => "Right".to_string(), + _ => todo!() + } +} + impl TryFrom<&str> for Keypress { - type Error = (); + type Error = String; - fn try_from(string: &str) -> Result { - match string.len() { + fn try_from(string: &str) -> Result { + match string.chars().count() { 3 => { Ok(Self { code: KeyCode::Char( @@ -67,7 +175,7 @@ impl TryFrom<&str> for Keypress { ), modifiers: modifier_from_character( string.chars().nth(0).unwrap() - ).ok_or(())?, + ).ok_or(format!("unknown modifier: {}", string.chars().nth(0).unwrap()))?, }) } 1 => { @@ -77,11 +185,27 @@ impl TryFrom<&str> for Keypress { ).into() ) } - _ => Err(()) + _ => Err(format!("invalid keypress: {}. only one modifier is allowed", string)) } } } +impl From<&Keypress> for String { + fn from(value: &Keypress) -> Self { + format!( + "{}{}", + str_from_modifiers(value.modifiers), + string_from_code(value.code) + ) + } +} + +impl From for String { + fn from(value: Keypress) -> Self { + String::from(&value) + } +} + impl From for Keypress { fn from(event: KeyEvent) -> Self { Self { @@ -94,238 +218,242 @@ impl From for Keypress { impl Default for Config { #[allow(clippy::too_many_lines)] fn default() -> Self { + use AppAction::*; + use BufferAction::*; + use CursorAction::*; + [ (Mode::Normal, [ (None, [ - ("q".try_into().unwrap(), AppAction::QuitIfSaved.into()), - ("Q".try_into().unwrap(), AppAction::Quit.into()), + ("q".try_into().unwrap(), QuitIfSaved.into()), + ("Q".try_into().unwrap(), Quit.into()), - ("v".try_into().unwrap(), BufferAction::SelectMode.into()), + ("v".try_into().unwrap(), SelectMode.into()), - ("g".try_into().unwrap(), BufferAction::Goto.into()), - ("z".try_into().unwrap(), BufferAction::View.into()), - ("r".try_into().unwrap(), BufferAction::Replace.into()), - (" ".try_into().unwrap(), BufferAction::Space.into()), - ("*".try_into().unwrap(), BufferAction::Repeat.into()), - ("t".try_into().unwrap(), BufferAction::To.into()), + ("g".try_into().unwrap(), Goto.into()), + ("z".try_into().unwrap(), View.into()), + ("r".try_into().unwrap(), Replace.into()), + (" ".try_into().unwrap(), Space.into()), + ("*".try_into().unwrap(), Repeat.into()), + ("t".try_into().unwrap(), To.into()), - ("i".try_into().unwrap(), CursorAction::MoveByteUp.into()), - ("k".try_into().unwrap(), CursorAction::MoveByteDown.into()), - ("j".try_into().unwrap(), CursorAction::MoveByteLeft.into()), - ("l".try_into().unwrap(), CursorAction::MoveByteRight.into()), + ("i".try_into().unwrap(), MoveByteUp.into()), + ("k".try_into().unwrap(), MoveByteDown.into()), + ("j".try_into().unwrap(), MoveByteLeft.into()), + ("l".try_into().unwrap(), MoveByteRight.into()), - ("G".try_into().unwrap(), CursorAction::GotoFileEnd.into()), + ("G".try_into().unwrap(), GotoFileEnd.into()), - ("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()), - ("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()), + ("C-e".try_into().unwrap(), ScrollDown.into()), + ("C-y".try_into().unwrap(), ScrollUp.into()), - ("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()), - ("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()), + ("C-d".try_into().unwrap(), PageCursorHalfDown.into()), + ("C-u".try_into().unwrap(), PageCursorHalfUp.into()), - ("C-f".try_into().unwrap(), BufferAction::PageDown.into()), - ("C-b".try_into().unwrap(), BufferAction::PageUp.into()), + ("C-f".try_into().unwrap(), PageDown.into()), + ("C-b".try_into().unwrap(), PageUp.into()), - ("w".try_into().unwrap(), CursorAction::MoveNextWordStart.into()), - ("e".try_into().unwrap(), CursorAction::MoveNextWordEnd.into()), - ("b".try_into().unwrap(), CursorAction::MovePreviousWordStart.into()), + ("w".try_into().unwrap(), MoveNextWordStart.into()), + ("e".try_into().unwrap(), MoveNextWordEnd.into()), + ("b".try_into().unwrap(), MovePreviousWordStart.into()), - (";".try_into().unwrap(), BufferAction::CollapseSelection.into()), - ("A-;".try_into().unwrap(), BufferAction::FlipSelections.into()), + (";".try_into().unwrap(), CollapseSelection.into()), + ("A-;".try_into().unwrap(), FlipSelections.into()), - ("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()), - ("X".try_into().unwrap(), CursorAction::ExtendLineAbove.into()), + ("x".try_into().unwrap(), ExtendLineBelow.into()), + ("X".try_into().unwrap(), ExtendLineAbove.into()), - ("d".try_into().unwrap(), BufferAction::Delete.into()), + ("d".try_into().unwrap(), Delete.into()), - ("u".try_into().unwrap(), BufferAction::Undo.into()), - ("U".try_into().unwrap(), BufferAction::Redo.into()), + ("u".try_into().unwrap(), Undo.into()), + ("U".try_into().unwrap(), Redo.into()), - ("C-j".try_into().unwrap(), AppAction::PreviousBuffer.into()), - ("C-l".try_into().unwrap(), AppAction::NextBuffer.into()), + ("C-j".try_into().unwrap(), PreviousBuffer.into()), + ("C-l".try_into().unwrap(), NextBuffer.into()), - ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), + ("C".try_into().unwrap(), CopySelectionOnNextLine.into()), - ("(".try_into().unwrap(), BufferAction::RotateSelectionsBackward.into()), - (")".try_into().unwrap(), BufferAction::RotateSelectionsForward.into()), + ("(".try_into().unwrap(), RotateSelectionsBackward.into()), + (")".try_into().unwrap(), RotateSelectionsForward.into()), - (",".try_into().unwrap(), BufferAction::KeepPrimarySelection.into()), - ("A-,".try_into().unwrap(), BufferAction::RemovePrimarySelection.into()), + (",".try_into().unwrap(), KeepPrimarySelection.into()), + ("A-,".try_into().unwrap(), RemovePrimarySelection.into()), - ("1".try_into().unwrap(), BufferAction::SplitSelectionsInto1s.into()), - ("2".try_into().unwrap(), BufferAction::SplitSelectionsInto2s.into()), - ("3".try_into().unwrap(), BufferAction::SplitSelectionsInto3s.into()), - ("4".try_into().unwrap(), BufferAction::SplitSelectionsInto4s.into()), - ("5".try_into().unwrap(), BufferAction::SplitSelectionsInto5s.into()), - ("6".try_into().unwrap(), BufferAction::SplitSelectionsInto6s.into()), - ("7".try_into().unwrap(), BufferAction::SplitSelectionsInto7s.into()), - ("8".try_into().unwrap(), BufferAction::SplitSelectionsInto8s.into()), - ("9".try_into().unwrap(), BufferAction::SplitSelectionsInto9s.into()), + ("1".try_into().unwrap(), SplitSelectionsInto1s.into()), + ("2".try_into().unwrap(), SplitSelectionsInto2s.into()), + ("3".try_into().unwrap(), SplitSelectionsInto3s.into()), + ("4".try_into().unwrap(), SplitSelectionsInto4s.into()), + ("5".try_into().unwrap(), SplitSelectionsInto5s.into()), + ("6".try_into().unwrap(), SplitSelectionsInto6s.into()), + ("7".try_into().unwrap(), SplitSelectionsInto7s.into()), + ("8".try_into().unwrap(), SplitSelectionsInto8s.into()), + ("9".try_into().unwrap(), SplitSelectionsInto9s.into()), - ("J".try_into().unwrap(), BufferAction::JumpToSelectedOffsetRelativeToMark.into()), - ("A-J".try_into().unwrap(), BufferAction::JumpToSelectedOffset.into()), + ("J".try_into().unwrap(), JumpToSelectedOffsetRelativeToMark.into()), + ("A-J".try_into().unwrap(), JumpToSelectedOffset.into()), - ("m".try_into().unwrap(), BufferAction::ToggleMark.into()), + ("m".try_into().unwrap(), ToggleMark.into()), - ("y".try_into().unwrap(), AppAction::Yank.into()), + ("y".try_into().unwrap(), Yank.into()), - ("C- ".try_into().unwrap(), BufferAction::InspectSelection.into()), - ("A- ".try_into().unwrap(), BufferAction::InspectSelectionColor.into()), + ("C- ".try_into().unwrap(), InspectSelection.into()), + ("A- ".try_into().unwrap(), InspectSelectionColor.into()), ].into()), (Some(PartialAction::Goto), [ - ("j".try_into().unwrap(), CursorAction::GotoLineStart.into()), - ("l".try_into().unwrap(), CursorAction::GotoLineEnd.into()), + ("j".try_into().unwrap(), GotoLineStart.into()), + ("l".try_into().unwrap(), GotoLineEnd.into()), - ("g".try_into().unwrap(), CursorAction::GotoFileStart.into()), + ("g".try_into().unwrap(), GotoFileStart.into()), ].into()), (Some(PartialAction::View), [ - ("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()), - ("b".try_into().unwrap(), BufferAction::AlignViewBottom.into()), - ("t".try_into().unwrap(), BufferAction::AlignViewTop.into()), + ("z".try_into().unwrap(), AlignViewCenter.into()), + ("b".try_into().unwrap(), AlignViewBottom.into()), + ("t".try_into().unwrap(), AlignViewTop.into()), ].into()), (Some(PartialAction::Space), [ - ("w".try_into().unwrap(), BufferAction::Save.into()), + ("w".try_into().unwrap(), Save.into()), ].into()), (Some(PartialAction::Repeat), [ - ("i".try_into().unwrap(), CursorAction::MoveByteUp.into()), - ("k".try_into().unwrap(), CursorAction::MoveByteDown.into()), - ("j".try_into().unwrap(), CursorAction::MoveByteLeft.into()), - ("l".try_into().unwrap(), CursorAction::MoveByteRight.into()), + ("i".try_into().unwrap(), MoveByteUp.into()), + ("k".try_into().unwrap(), MoveByteDown.into()), + ("j".try_into().unwrap(), MoveByteLeft.into()), + ("l".try_into().unwrap(), MoveByteRight.into()), - ("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()), - ("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()), + ("C-e".try_into().unwrap(), ScrollDown.into()), + ("C-y".try_into().unwrap(), ScrollUp.into()), - ("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()), - ("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()), + ("C-d".try_into().unwrap(), PageCursorHalfDown.into()), + ("C-u".try_into().unwrap(), PageCursorHalfUp.into()), - ("C-f".try_into().unwrap(), BufferAction::PageDown.into()), - ("C-b".try_into().unwrap(), BufferAction::PageUp.into()), + ("C-f".try_into().unwrap(), PageDown.into()), + ("C-b".try_into().unwrap(), PageUp.into()), - ("w".try_into().unwrap(), CursorAction::MoveNextWordStart.into()), - ("e".try_into().unwrap(), CursorAction::MoveNextWordEnd.into()), - ("b".try_into().unwrap(), CursorAction::MovePreviousWordStart.into()), + ("w".try_into().unwrap(), MoveNextWordStart.into()), + ("e".try_into().unwrap(), MoveNextWordEnd.into()), + ("b".try_into().unwrap(), MovePreviousWordStart.into()), - ("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()), - ("X".try_into().unwrap(), CursorAction::ExtendLineAbove.into()), + ("x".try_into().unwrap(), ExtendLineBelow.into()), + ("X".try_into().unwrap(), ExtendLineAbove.into()), - ("d".try_into().unwrap(), BufferAction::Delete.into()), + ("d".try_into().unwrap(), Delete.into()), - ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), + ("C".try_into().unwrap(), CopySelectionOnNextLine.into()), ].into()), (Some(PartialAction::To), [ - ("m".try_into().unwrap(), BufferAction::ExtendToMark.into()), - ("0".try_into().unwrap(), BufferAction::ExtendToNull.into()), - ("f".try_into().unwrap(), BufferAction::ExtendToFF.into()), + ("m".try_into().unwrap(), ExtendToMark.into()), + ("0".try_into().unwrap(), ExtendToNull.into()), + ("f".try_into().unwrap(), ExtendToFF.into()), ].into()), ].into()), (Mode::Select, [ (None, [ - ("q".try_into().unwrap(), AppAction::QuitIfSaved.into()), - ("Q".try_into().unwrap(), AppAction::Quit.into()), + ("q".try_into().unwrap(), QuitIfSaved.into()), + ("Q".try_into().unwrap(), Quit.into()), - ("v".try_into().unwrap(), BufferAction::NormalMode.into()), + ("v".try_into().unwrap(), NormalMode.into()), - ("g".try_into().unwrap(), BufferAction::Goto.into()), - ("z".try_into().unwrap(), BufferAction::View.into()), - ("r".try_into().unwrap(), BufferAction::Replace.into()), - (" ".try_into().unwrap(), BufferAction::Space.into()), - ("*".try_into().unwrap(), BufferAction::Repeat.into()), - ("t".try_into().unwrap(), BufferAction::To.into()), + ("g".try_into().unwrap(), Goto.into()), + ("z".try_into().unwrap(), View.into()), + ("r".try_into().unwrap(), Replace.into()), + (" ".try_into().unwrap(), Space.into()), + ("*".try_into().unwrap(), Repeat.into()), + ("t".try_into().unwrap(), To.into()), - ("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()), - ("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()), - ("j".try_into().unwrap(), CursorAction::ExtendByteLeft.into()), - ("l".try_into().unwrap(), CursorAction::ExtendByteRight.into()), + ("i".try_into().unwrap(), ExtendByteUp.into()), + ("k".try_into().unwrap(), ExtendByteDown.into()), + ("j".try_into().unwrap(), ExtendByteLeft.into()), + ("l".try_into().unwrap(), ExtendByteRight.into()), - ("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()), - ("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()), + ("C-e".try_into().unwrap(), ScrollDown.into()), + ("C-y".try_into().unwrap(), ScrollUp.into()), - ("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()), - ("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()), + ("C-d".try_into().unwrap(), PageCursorHalfDown.into()), + ("C-u".try_into().unwrap(), PageCursorHalfUp.into()), - ("C-f".try_into().unwrap(), BufferAction::PageDown.into()), - ("C-b".try_into().unwrap(), BufferAction::PageUp.into()), + ("C-f".try_into().unwrap(), PageDown.into()), + ("C-b".try_into().unwrap(), PageUp.into()), - ("w".try_into().unwrap(), CursorAction::ExtendNextWordStart.into()), - ("e".try_into().unwrap(), CursorAction::ExtendNextWordEnd.into()), - ("b".try_into().unwrap(), CursorAction::ExtendPreviousWordStart.into()), + ("w".try_into().unwrap(), ExtendNextWordStart.into()), + ("e".try_into().unwrap(), ExtendNextWordEnd.into()), + ("b".try_into().unwrap(), ExtendPreviousWordStart.into()), - (";".try_into().unwrap(), BufferAction::CollapseSelection.into()), - ("A-;".try_into().unwrap(), BufferAction::FlipSelections.into()), + (";".try_into().unwrap(), CollapseSelection.into()), + ("A-;".try_into().unwrap(), FlipSelections.into()), - ("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()), - ("X".try_into().unwrap(), CursorAction::ExtendLineAbove.into()), + ("x".try_into().unwrap(), ExtendLineBelow.into()), + ("X".try_into().unwrap(), ExtendLineAbove.into()), - ("d".try_into().unwrap(), BufferAction::Delete.into()), + ("d".try_into().unwrap(), Delete.into()), - ("u".try_into().unwrap(), BufferAction::Undo.into()), - ("U".try_into().unwrap(), BufferAction::Redo.into()), + ("u".try_into().unwrap(), Undo.into()), + ("U".try_into().unwrap(), Redo.into()), - ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), + ("C".try_into().unwrap(), CopySelectionOnNextLine.into()), - ("(".try_into().unwrap(), BufferAction::RotateSelectionsBackward.into()), - (")".try_into().unwrap(), BufferAction::RotateSelectionsForward.into()), + ("(".try_into().unwrap(), RotateSelectionsBackward.into()), + (")".try_into().unwrap(), RotateSelectionsForward.into()), - (",".try_into().unwrap(), BufferAction::KeepPrimarySelection.into()), - ("A-,".try_into().unwrap(), BufferAction::RemovePrimarySelection.into()), + (",".try_into().unwrap(), KeepPrimarySelection.into()), + ("A-,".try_into().unwrap(), RemovePrimarySelection.into()), - ("1".try_into().unwrap(), BufferAction::SplitSelectionsInto1s.into()), - ("2".try_into().unwrap(), BufferAction::SplitSelectionsInto2s.into()), - ("3".try_into().unwrap(), BufferAction::SplitSelectionsInto3s.into()), - ("4".try_into().unwrap(), BufferAction::SplitSelectionsInto4s.into()), - ("5".try_into().unwrap(), BufferAction::SplitSelectionsInto5s.into()), - ("6".try_into().unwrap(), BufferAction::SplitSelectionsInto6s.into()), - ("7".try_into().unwrap(), BufferAction::SplitSelectionsInto7s.into()), - ("8".try_into().unwrap(), BufferAction::SplitSelectionsInto8s.into()), - ("9".try_into().unwrap(), BufferAction::SplitSelectionsInto9s.into()), + ("1".try_into().unwrap(), SplitSelectionsInto1s.into()), + ("2".try_into().unwrap(), SplitSelectionsInto2s.into()), + ("3".try_into().unwrap(), SplitSelectionsInto3s.into()), + ("4".try_into().unwrap(), SplitSelectionsInto4s.into()), + ("5".try_into().unwrap(), SplitSelectionsInto5s.into()), + ("6".try_into().unwrap(), SplitSelectionsInto6s.into()), + ("7".try_into().unwrap(), SplitSelectionsInto7s.into()), + ("8".try_into().unwrap(), SplitSelectionsInto8s.into()), + ("9".try_into().unwrap(), SplitSelectionsInto9s.into()), - ("J".try_into().unwrap(), BufferAction::JumpToSelectedOffsetRelativeToMark.into()), - ("A-J".try_into().unwrap(), BufferAction::JumpToSelectedOffset.into()), + ("J".try_into().unwrap(), JumpToSelectedOffsetRelativeToMark.into()), + ("A-J".try_into().unwrap(), JumpToSelectedOffset.into()), - ("m".try_into().unwrap(), BufferAction::ToggleMark.into()), + ("m".try_into().unwrap(), ToggleMark.into()), - ("y".try_into().unwrap(), AppAction::Yank.into()), + ("y".try_into().unwrap(), Yank.into()), - ("C- ".try_into().unwrap(), BufferAction::InspectSelection.into()), - ("A- ".try_into().unwrap(), BufferAction::InspectSelectionColor.into()), + ("C- ".try_into().unwrap(), InspectSelection.into()), + ("A- ".try_into().unwrap(), InspectSelectionColor.into()), ].into()), (Some(PartialAction::View), [ - ("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()), - ("b".try_into().unwrap(), BufferAction::AlignViewBottom.into()), - ("t".try_into().unwrap(), BufferAction::AlignViewTop.into()), + ("z".try_into().unwrap(), AlignViewCenter.into()), + ("b".try_into().unwrap(), AlignViewBottom.into()), + ("t".try_into().unwrap(), AlignViewTop.into()), ].into()), (Some(PartialAction::Space), [ - ("w".try_into().unwrap(), BufferAction::Save.into()), + ("w".try_into().unwrap(), Save.into()), ].into()), (Some(PartialAction::Repeat), [ - ("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()), - ("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()), - ("j".try_into().unwrap(), CursorAction::ExtendByteLeft.into()), - ("l".try_into().unwrap(), CursorAction::ExtendByteRight.into()), + ("i".try_into().unwrap(), ExtendByteUp.into()), + ("k".try_into().unwrap(), ExtendByteDown.into()), + ("j".try_into().unwrap(), ExtendByteLeft.into()), + ("l".try_into().unwrap(), ExtendByteRight.into()), - ("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()), - ("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()), + ("C-e".try_into().unwrap(), ScrollDown.into()), + ("C-y".try_into().unwrap(), ScrollUp.into()), - ("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()), - ("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()), + ("C-d".try_into().unwrap(), PageCursorHalfDown.into()), + ("C-u".try_into().unwrap(), PageCursorHalfUp.into()), - ("C-f".try_into().unwrap(), BufferAction::PageDown.into()), - ("C-b".try_into().unwrap(), BufferAction::PageUp.into()), + ("C-f".try_into().unwrap(), PageDown.into()), + ("C-b".try_into().unwrap(), PageUp.into()), - ("w".try_into().unwrap(), CursorAction::ExtendNextWordStart.into()), - ("e".try_into().unwrap(), CursorAction::ExtendNextWordEnd.into()), - ("b".try_into().unwrap(), CursorAction::ExtendPreviousWordStart.into()), + ("w".try_into().unwrap(), ExtendNextWordStart.into()), + ("e".try_into().unwrap(), ExtendNextWordEnd.into()), + ("b".try_into().unwrap(), ExtendPreviousWordStart.into()), - ("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()), - ("X".try_into().unwrap(), CursorAction::ExtendLineAbove.into()), + ("x".try_into().unwrap(), ExtendLineBelow.into()), + ("X".try_into().unwrap(), ExtendLineAbove.into()), - ("d".try_into().unwrap(), BufferAction::Delete.into()), + ("d".try_into().unwrap(), Delete.into()), - ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), + ("C".try_into().unwrap(), CopySelectionOnNextLine.into()), ].into()), (Some(PartialAction::To), [ - ("m".try_into().unwrap(), BufferAction::ExtendToMark.into()), - ("0".try_into().unwrap(), BufferAction::ExtendToNull.into()), - ("f".try_into().unwrap(), BufferAction::ExtendToFF.into()), + ("m".try_into().unwrap(), ExtendToMark.into()), + ("0".try_into().unwrap(), ExtendToNull.into()), + ("f".try_into().unwrap(), ExtendToFF.into()), ].into()), ].into()) ].into() diff --git a/src/main.rs b/src/main.rs index 8f6f7b1..e1de11c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,9 +5,13 @@ #![feature(hash_set_entry)] #![feature(trim_prefix_suffix)] +use std::fs::read_to_string; + use app::App; use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}}; +use crate::config::Config; + mod app; mod buffer; mod config; @@ -55,6 +59,16 @@ const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE; // - how to fit??! `-128` longer than `80` fn main() { + // let config = Config::default(); + // let toml_string = toml::to_string_pretty(&config); + // println!("{}", toml_string.unwrap()); + + // let string = read_to_string("/Users/simonomi/Desktop/hexapoda_config.toml").unwrap(); + // let config: Config = toml::from_str(&string).unwrap(); + // dbg!(config.0); + + // return; + let mut app = App::new(); let mut terminal = ratatui::init(); crossterm::terminal::enable_raw_mode().unwrap();