make config (de)serializable
This commit is contained in:
Generated
+60
@@ -70,6 +70,9 @@ name = "bitflags"
|
|||||||
version = "2.10.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "block-buffer"
|
name = "block-buffer"
|
||||||
@@ -158,6 +161,7 @@ dependencies = [
|
|||||||
"mio",
|
"mio",
|
||||||
"parking_lot",
|
"parking_lot",
|
||||||
"rustix",
|
"rustix",
|
||||||
|
"serde",
|
||||||
"signal-hook",
|
"signal-hook",
|
||||||
"signal-hook-mio",
|
"signal-hook-mio",
|
||||||
"winapi",
|
"winapi",
|
||||||
@@ -438,6 +442,8 @@ dependencies = [
|
|||||||
"crossterm",
|
"crossterm",
|
||||||
"itertools",
|
"itertools",
|
||||||
"ratatui",
|
"ratatui",
|
||||||
|
"serde",
|
||||||
|
"toml",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1101,6 +1107,15 @@ dependencies = [
|
|||||||
"zmij",
|
"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]]
|
[[package]]
|
||||||
name = "sha2"
|
name = "sha2"
|
||||||
version = "0.10.9"
|
version = "0.10.9"
|
||||||
@@ -1333,6 +1348,45 @@ version = "0.1.8"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca"
|
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]]
|
[[package]]
|
||||||
name = "typenum"
|
name = "typenum"
|
||||||
version = "1.19.0"
|
version = "1.19.0"
|
||||||
@@ -1625,6 +1679,12 @@ dependencies = [
|
|||||||
"windows-link",
|
"windows-link",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winnow"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wit-bindgen"
|
name = "wit-bindgen"
|
||||||
version = "0.51.0"
|
version = "0.51.0"
|
||||||
|
|||||||
+3
-1
@@ -4,6 +4,8 @@ version = "0.1.0"
|
|||||||
edition = "2024"
|
edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
crossterm = "0.29.0"
|
crossterm = { version = "0.29.0", features = ["serde"] }
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
ratatui = "0.30.0"
|
ratatui = "0.30.0"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
|
toml = "1.1.2"
|
||||||
|
|||||||
+286
-4
@@ -1,16 +1,41 @@
|
|||||||
use std::{cmp::min, collections::hash_set::Entry, convert::identity, fs::File, io::Write, iter, mem::{replace, swap}};
|
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 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};
|
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 {
|
pub enum Action {
|
||||||
App(AppAction),
|
App(AppAction),
|
||||||
Buffer(BufferAction),
|
Buffer(BufferAction),
|
||||||
Cursor(CursorAction),
|
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
|
// 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 {
|
pub enum AppAction {
|
||||||
QuitIfSaved,
|
QuitIfSaved,
|
||||||
Quit,
|
Quit,
|
||||||
@@ -21,13 +46,50 @@ pub enum AppAction {
|
|||||||
Yank,
|
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 {
|
impl From<AppAction> for Action {
|
||||||
fn from(app_action: AppAction) -> Self {
|
fn from(app_action: AppAction) -> Self {
|
||||||
Self::App(app_action)
|
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 {
|
pub enum BufferAction {
|
||||||
NormalMode,
|
NormalMode,
|
||||||
SelectMode,
|
SelectMode,
|
||||||
@@ -93,13 +155,161 @@ pub enum BufferAction {
|
|||||||
InspectSelectionColor,
|
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 {
|
impl From<BufferAction> for Action {
|
||||||
fn from(buffer_action: BufferAction) -> Self {
|
fn from(buffer_action: BufferAction) -> Self {
|
||||||
Self::Buffer(buffer_action)
|
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 {
|
pub enum CursorAction {
|
||||||
MoveByteUp,
|
MoveByteUp,
|
||||||
MoveByteDown,
|
MoveByteDown,
|
||||||
@@ -128,12 +338,84 @@ pub enum CursorAction {
|
|||||||
ExtendLineAbove,
|
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 {
|
impl From<CursorAction> for Action {
|
||||||
fn from(cursor_action: CursorAction) -> Self {
|
fn from(cursor_action: CursorAction) -> Self {
|
||||||
Self::Cursor(cursor_action)
|
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 {
|
impl Buffer {
|
||||||
pub fn execute(&mut self, action: BufferAction, window_size: WindowSize) {
|
pub fn execute(&mut self, action: BufferAction, window_size: WindowSize) {
|
||||||
match action {
|
match action {
|
||||||
|
|||||||
+33
-8
@@ -2,6 +2,7 @@ use core::slice::GetDisjointMutIndex;
|
|||||||
use std::{collections::HashSet, fs::File, io::Read, path::PathBuf};
|
use std::{collections::HashSet, fs::File, io::Read, path::PathBuf};
|
||||||
use crossterm::event::KeyEvent;
|
use crossterm::event::KeyEvent;
|
||||||
use ratatui::{layout::{Constraint, Rect}, style::{Color, Stylize}, text::Span, widgets::{Block, Clear, Widget}};
|
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};
|
use crate::{BYTES_PER_LINE, action::{Action, AppAction, bytes_to_nat}, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
|
||||||
|
|
||||||
mod widget;
|
mod widget;
|
||||||
@@ -36,12 +37,16 @@ pub struct Buffer {
|
|||||||
pub logs: Vec<String>,
|
pub logs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[serde(rename_all = "snake_case")]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Normal, Select, Insert
|
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 {
|
pub enum PartialAction {
|
||||||
Goto, View, Replace, Space, Repeat, To
|
Goto, View, Replace, Space, Repeat, To
|
||||||
}
|
}
|
||||||
@@ -73,13 +78,33 @@ impl Mode {
|
|||||||
|
|
||||||
impl PartialAction {
|
impl PartialAction {
|
||||||
pub const fn label(self) -> &'static str {
|
pub const fn label(self) -> &'static str {
|
||||||
|
use PartialAction::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Goto => "g",
|
Goto => "g",
|
||||||
Self::View => "z",
|
View => "z",
|
||||||
Self::Replace => "r",
|
Replace => "r",
|
||||||
Self::Space => "␠",
|
Space => "␠",
|
||||||
Self::Repeat => "×",
|
Repeat => "×",
|
||||||
Self::To => "t",
|
To => "t",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&str> for PartialAction {
|
||||||
|
type Error = ();
|
||||||
|
|
||||||
|
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||||
|
use PartialAction::*;
|
||||||
|
|
||||||
|
match value {
|
||||||
|
"goto" => Ok(Goto),
|
||||||
|
"view" => Ok(View),
|
||||||
|
"replace" => Ok(Replace),
|
||||||
|
"space" => Ok(Space),
|
||||||
|
"repeat" => Ok(Repeat),
|
||||||
|
"to" => Ok(To),
|
||||||
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+288
-160
@@ -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 crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
|
||||||
use crate::{action::{Action, AppAction, BufferAction, CursorAction}, buffer::{Mode, PartialAction}};
|
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 struct Config(
|
||||||
pub HashMap<Mode, ModeConfig>
|
pub HashMap<Mode, ModeConfig>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct ModeConfig(
|
pub struct ModeConfig(
|
||||||
pub HashMap<Option<PartialAction>, Keybinds>
|
pub HashMap<Option<PartialAction>, Keybinds>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct Keybinds(
|
pub struct Keybinds(
|
||||||
pub HashMap<Keypress, Action>
|
pub HashMap<Keypress, Action>
|
||||||
);
|
);
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash)]
|
#[derive(PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[serde(into = "String")]
|
||||||
|
#[serde(try_from = "&str")]
|
||||||
pub struct Keypress {
|
pub struct Keypress {
|
||||||
code: KeyCode,
|
code: KeyCode,
|
||||||
modifiers: KeyModifiers
|
modifiers: KeyModifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Serialize for ModeConfig {
|
||||||
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
|
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<Map: MapAccess<'de>>(
|
||||||
|
self,
|
||||||
|
mut map: Map
|
||||||
|
) -> Result<Self::Value, Map::Error> {
|
||||||
|
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<D: Deserializer<'de>>(
|
||||||
|
deserializer: D
|
||||||
|
) -> Result<Self, D::Error> {
|
||||||
|
deserializer.deserialize_map(ModeConfigVisitor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<const N: usize> From<[(Mode, ModeConfig); N]> for Config {
|
impl<const N: usize> From<[(Mode, ModeConfig); N]> for Config {
|
||||||
fn from(array: [(Mode, ModeConfig); N]) -> Self {
|
fn from(array: [(Mode, ModeConfig); N]) -> Self {
|
||||||
Self(array.into())
|
Self(array.into())
|
||||||
@@ -55,11 +144,30 @@ const fn modifier_from_character(character: char) -> Option<KeyModifiers> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&str> for Keypress {
|
const fn str_from_modifiers(modifier: KeyModifiers) -> &'static str {
|
||||||
type Error = ();
|
match modifier {
|
||||||
|
KeyModifiers::ALT => "A-",
|
||||||
|
KeyModifiers::CONTROL => "C-",
|
||||||
|
_ => ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn try_from(string: &str) -> Result<Self, ()> {
|
fn string_from_code(code: KeyCode) -> String {
|
||||||
match string.len() {
|
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 = String;
|
||||||
|
|
||||||
|
fn try_from(string: &str) -> Result<Self, Self::Error> {
|
||||||
|
match string.chars().count() {
|
||||||
3 => {
|
3 => {
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
code: KeyCode::Char(
|
code: KeyCode::Char(
|
||||||
@@ -67,7 +175,7 @@ impl TryFrom<&str> for Keypress {
|
|||||||
),
|
),
|
||||||
modifiers: modifier_from_character(
|
modifiers: modifier_from_character(
|
||||||
string.chars().nth(0).unwrap()
|
string.chars().nth(0).unwrap()
|
||||||
).ok_or(())?,
|
).ok_or(format!("unknown modifier: {}", string.chars().nth(0).unwrap()))?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
1 => {
|
1 => {
|
||||||
@@ -77,11 +185,27 @@ impl TryFrom<&str> for Keypress {
|
|||||||
).into()
|
).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<Keypress> for String {
|
||||||
|
fn from(value: Keypress) -> Self {
|
||||||
|
String::from(&value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<KeyEvent> for Keypress {
|
impl From<KeyEvent> for Keypress {
|
||||||
fn from(event: KeyEvent) -> Self {
|
fn from(event: KeyEvent) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@@ -94,238 +218,242 @@ impl From<KeyEvent> for Keypress {
|
|||||||
impl Default for Config {
|
impl Default for Config {
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
use AppAction::*;
|
||||||
|
use BufferAction::*;
|
||||||
|
use CursorAction::*;
|
||||||
|
|
||||||
[
|
[
|
||||||
(Mode::Normal, [
|
(Mode::Normal, [
|
||||||
(None, [
|
(None, [
|
||||||
("q".try_into().unwrap(), AppAction::QuitIfSaved.into()),
|
("q".try_into().unwrap(), QuitIfSaved.into()),
|
||||||
("Q".try_into().unwrap(), AppAction::Quit.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()),
|
("g".try_into().unwrap(), Goto.into()),
|
||||||
("z".try_into().unwrap(), BufferAction::View.into()),
|
("z".try_into().unwrap(), View.into()),
|
||||||
("r".try_into().unwrap(), BufferAction::Replace.into()),
|
("r".try_into().unwrap(), Replace.into()),
|
||||||
(" ".try_into().unwrap(), BufferAction::Space.into()),
|
(" ".try_into().unwrap(), Space.into()),
|
||||||
("*".try_into().unwrap(), BufferAction::Repeat.into()),
|
("*".try_into().unwrap(), Repeat.into()),
|
||||||
("t".try_into().unwrap(), BufferAction::To.into()),
|
("t".try_into().unwrap(), To.into()),
|
||||||
|
|
||||||
("i".try_into().unwrap(), CursorAction::MoveByteUp.into()),
|
("i".try_into().unwrap(), MoveByteUp.into()),
|
||||||
("k".try_into().unwrap(), CursorAction::MoveByteDown.into()),
|
("k".try_into().unwrap(), MoveByteDown.into()),
|
||||||
("j".try_into().unwrap(), CursorAction::MoveByteLeft.into()),
|
("j".try_into().unwrap(), MoveByteLeft.into()),
|
||||||
("l".try_into().unwrap(), CursorAction::MoveByteRight.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-e".try_into().unwrap(), ScrollDown.into()),
|
||||||
("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()),
|
("C-y".try_into().unwrap(), ScrollUp.into()),
|
||||||
|
|
||||||
("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()),
|
("C-d".try_into().unwrap(), PageCursorHalfDown.into()),
|
||||||
("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()),
|
("C-u".try_into().unwrap(), PageCursorHalfUp.into()),
|
||||||
|
|
||||||
("C-f".try_into().unwrap(), BufferAction::PageDown.into()),
|
("C-f".try_into().unwrap(), PageDown.into()),
|
||||||
("C-b".try_into().unwrap(), BufferAction::PageUp.into()),
|
("C-b".try_into().unwrap(), PageUp.into()),
|
||||||
|
|
||||||
("w".try_into().unwrap(), CursorAction::MoveNextWordStart.into()),
|
("w".try_into().unwrap(), MoveNextWordStart.into()),
|
||||||
("e".try_into().unwrap(), CursorAction::MoveNextWordEnd.into()),
|
("e".try_into().unwrap(), MoveNextWordEnd.into()),
|
||||||
("b".try_into().unwrap(), CursorAction::MovePreviousWordStart.into()),
|
("b".try_into().unwrap(), MovePreviousWordStart.into()),
|
||||||
|
|
||||||
(";".try_into().unwrap(), BufferAction::CollapseSelection.into()),
|
(";".try_into().unwrap(), CollapseSelection.into()),
|
||||||
("A-;".try_into().unwrap(), BufferAction::FlipSelections.into()),
|
("A-;".try_into().unwrap(), FlipSelections.into()),
|
||||||
|
|
||||||
("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()),
|
("x".try_into().unwrap(), ExtendLineBelow.into()),
|
||||||
("X".try_into().unwrap(), CursorAction::ExtendLineAbove.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(), Undo.into()),
|
||||||
("U".try_into().unwrap(), BufferAction::Redo.into()),
|
("U".try_into().unwrap(), Redo.into()),
|
||||||
|
|
||||||
("C-j".try_into().unwrap(), AppAction::PreviousBuffer.into()),
|
("C-j".try_into().unwrap(), PreviousBuffer.into()),
|
||||||
("C-l".try_into().unwrap(), AppAction::NextBuffer.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(), RotateSelectionsBackward.into()),
|
||||||
(")".try_into().unwrap(), BufferAction::RotateSelectionsForward.into()),
|
(")".try_into().unwrap(), RotateSelectionsForward.into()),
|
||||||
|
|
||||||
(",".try_into().unwrap(), BufferAction::KeepPrimarySelection.into()),
|
(",".try_into().unwrap(), KeepPrimarySelection.into()),
|
||||||
("A-,".try_into().unwrap(), BufferAction::RemovePrimarySelection.into()),
|
("A-,".try_into().unwrap(), RemovePrimarySelection.into()),
|
||||||
|
|
||||||
("1".try_into().unwrap(), BufferAction::SplitSelectionsInto1s.into()),
|
("1".try_into().unwrap(), SplitSelectionsInto1s.into()),
|
||||||
("2".try_into().unwrap(), BufferAction::SplitSelectionsInto2s.into()),
|
("2".try_into().unwrap(), SplitSelectionsInto2s.into()),
|
||||||
("3".try_into().unwrap(), BufferAction::SplitSelectionsInto3s.into()),
|
("3".try_into().unwrap(), SplitSelectionsInto3s.into()),
|
||||||
("4".try_into().unwrap(), BufferAction::SplitSelectionsInto4s.into()),
|
("4".try_into().unwrap(), SplitSelectionsInto4s.into()),
|
||||||
("5".try_into().unwrap(), BufferAction::SplitSelectionsInto5s.into()),
|
("5".try_into().unwrap(), SplitSelectionsInto5s.into()),
|
||||||
("6".try_into().unwrap(), BufferAction::SplitSelectionsInto6s.into()),
|
("6".try_into().unwrap(), SplitSelectionsInto6s.into()),
|
||||||
("7".try_into().unwrap(), BufferAction::SplitSelectionsInto7s.into()),
|
("7".try_into().unwrap(), SplitSelectionsInto7s.into()),
|
||||||
("8".try_into().unwrap(), BufferAction::SplitSelectionsInto8s.into()),
|
("8".try_into().unwrap(), SplitSelectionsInto8s.into()),
|
||||||
("9".try_into().unwrap(), BufferAction::SplitSelectionsInto9s.into()),
|
("9".try_into().unwrap(), SplitSelectionsInto9s.into()),
|
||||||
|
|
||||||
("J".try_into().unwrap(), BufferAction::JumpToSelectedOffsetRelativeToMark.into()),
|
("J".try_into().unwrap(), JumpToSelectedOffsetRelativeToMark.into()),
|
||||||
("A-J".try_into().unwrap(), BufferAction::JumpToSelectedOffset.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()),
|
("C- ".try_into().unwrap(), InspectSelection.into()),
|
||||||
("A- ".try_into().unwrap(), BufferAction::InspectSelectionColor.into()),
|
("A- ".try_into().unwrap(), InspectSelectionColor.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Goto), [
|
(Some(PartialAction::Goto), [
|
||||||
("j".try_into().unwrap(), CursorAction::GotoLineStart.into()),
|
("j".try_into().unwrap(), GotoLineStart.into()),
|
||||||
("l".try_into().unwrap(), CursorAction::GotoLineEnd.into()),
|
("l".try_into().unwrap(), GotoLineEnd.into()),
|
||||||
|
|
||||||
("g".try_into().unwrap(), CursorAction::GotoFileStart.into()),
|
("g".try_into().unwrap(), GotoFileStart.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::View), [
|
(Some(PartialAction::View), [
|
||||||
("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()),
|
("z".try_into().unwrap(), AlignViewCenter.into()),
|
||||||
("b".try_into().unwrap(), BufferAction::AlignViewBottom.into()),
|
("b".try_into().unwrap(), AlignViewBottom.into()),
|
||||||
("t".try_into().unwrap(), BufferAction::AlignViewTop.into()),
|
("t".try_into().unwrap(), AlignViewTop.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Space), [
|
(Some(PartialAction::Space), [
|
||||||
("w".try_into().unwrap(), BufferAction::Save.into()),
|
("w".try_into().unwrap(), Save.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Repeat), [
|
(Some(PartialAction::Repeat), [
|
||||||
("i".try_into().unwrap(), CursorAction::MoveByteUp.into()),
|
("i".try_into().unwrap(), MoveByteUp.into()),
|
||||||
("k".try_into().unwrap(), CursorAction::MoveByteDown.into()),
|
("k".try_into().unwrap(), MoveByteDown.into()),
|
||||||
("j".try_into().unwrap(), CursorAction::MoveByteLeft.into()),
|
("j".try_into().unwrap(), MoveByteLeft.into()),
|
||||||
("l".try_into().unwrap(), CursorAction::MoveByteRight.into()),
|
("l".try_into().unwrap(), MoveByteRight.into()),
|
||||||
|
|
||||||
("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()),
|
("C-e".try_into().unwrap(), ScrollDown.into()),
|
||||||
("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()),
|
("C-y".try_into().unwrap(), ScrollUp.into()),
|
||||||
|
|
||||||
("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()),
|
("C-d".try_into().unwrap(), PageCursorHalfDown.into()),
|
||||||
("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()),
|
("C-u".try_into().unwrap(), PageCursorHalfUp.into()),
|
||||||
|
|
||||||
("C-f".try_into().unwrap(), BufferAction::PageDown.into()),
|
("C-f".try_into().unwrap(), PageDown.into()),
|
||||||
("C-b".try_into().unwrap(), BufferAction::PageUp.into()),
|
("C-b".try_into().unwrap(), PageUp.into()),
|
||||||
|
|
||||||
("w".try_into().unwrap(), CursorAction::MoveNextWordStart.into()),
|
("w".try_into().unwrap(), MoveNextWordStart.into()),
|
||||||
("e".try_into().unwrap(), CursorAction::MoveNextWordEnd.into()),
|
("e".try_into().unwrap(), MoveNextWordEnd.into()),
|
||||||
("b".try_into().unwrap(), CursorAction::MovePreviousWordStart.into()),
|
("b".try_into().unwrap(), MovePreviousWordStart.into()),
|
||||||
|
|
||||||
("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()),
|
("x".try_into().unwrap(), ExtendLineBelow.into()),
|
||||||
("X".try_into().unwrap(), CursorAction::ExtendLineAbove.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()),
|
].into()),
|
||||||
(Some(PartialAction::To), [
|
(Some(PartialAction::To), [
|
||||||
("m".try_into().unwrap(), BufferAction::ExtendToMark.into()),
|
("m".try_into().unwrap(), ExtendToMark.into()),
|
||||||
("0".try_into().unwrap(), BufferAction::ExtendToNull.into()),
|
("0".try_into().unwrap(), ExtendToNull.into()),
|
||||||
("f".try_into().unwrap(), BufferAction::ExtendToFF.into()),
|
("f".try_into().unwrap(), ExtendToFF.into()),
|
||||||
].into()),
|
].into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Mode::Select, [
|
(Mode::Select, [
|
||||||
(None, [
|
(None, [
|
||||||
("q".try_into().unwrap(), AppAction::QuitIfSaved.into()),
|
("q".try_into().unwrap(), QuitIfSaved.into()),
|
||||||
("Q".try_into().unwrap(), AppAction::Quit.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()),
|
("g".try_into().unwrap(), Goto.into()),
|
||||||
("z".try_into().unwrap(), BufferAction::View.into()),
|
("z".try_into().unwrap(), View.into()),
|
||||||
("r".try_into().unwrap(), BufferAction::Replace.into()),
|
("r".try_into().unwrap(), Replace.into()),
|
||||||
(" ".try_into().unwrap(), BufferAction::Space.into()),
|
(" ".try_into().unwrap(), Space.into()),
|
||||||
("*".try_into().unwrap(), BufferAction::Repeat.into()),
|
("*".try_into().unwrap(), Repeat.into()),
|
||||||
("t".try_into().unwrap(), BufferAction::To.into()),
|
("t".try_into().unwrap(), To.into()),
|
||||||
|
|
||||||
("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()),
|
("i".try_into().unwrap(), ExtendByteUp.into()),
|
||||||
("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()),
|
("k".try_into().unwrap(), ExtendByteDown.into()),
|
||||||
("j".try_into().unwrap(), CursorAction::ExtendByteLeft.into()),
|
("j".try_into().unwrap(), ExtendByteLeft.into()),
|
||||||
("l".try_into().unwrap(), CursorAction::ExtendByteRight.into()),
|
("l".try_into().unwrap(), ExtendByteRight.into()),
|
||||||
|
|
||||||
("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()),
|
("C-e".try_into().unwrap(), ScrollDown.into()),
|
||||||
("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()),
|
("C-y".try_into().unwrap(), ScrollUp.into()),
|
||||||
|
|
||||||
("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()),
|
("C-d".try_into().unwrap(), PageCursorHalfDown.into()),
|
||||||
("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()),
|
("C-u".try_into().unwrap(), PageCursorHalfUp.into()),
|
||||||
|
|
||||||
("C-f".try_into().unwrap(), BufferAction::PageDown.into()),
|
("C-f".try_into().unwrap(), PageDown.into()),
|
||||||
("C-b".try_into().unwrap(), BufferAction::PageUp.into()),
|
("C-b".try_into().unwrap(), PageUp.into()),
|
||||||
|
|
||||||
("w".try_into().unwrap(), CursorAction::ExtendNextWordStart.into()),
|
("w".try_into().unwrap(), ExtendNextWordStart.into()),
|
||||||
("e".try_into().unwrap(), CursorAction::ExtendNextWordEnd.into()),
|
("e".try_into().unwrap(), ExtendNextWordEnd.into()),
|
||||||
("b".try_into().unwrap(), CursorAction::ExtendPreviousWordStart.into()),
|
("b".try_into().unwrap(), ExtendPreviousWordStart.into()),
|
||||||
|
|
||||||
(";".try_into().unwrap(), BufferAction::CollapseSelection.into()),
|
(";".try_into().unwrap(), CollapseSelection.into()),
|
||||||
("A-;".try_into().unwrap(), BufferAction::FlipSelections.into()),
|
("A-;".try_into().unwrap(), FlipSelections.into()),
|
||||||
|
|
||||||
("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()),
|
("x".try_into().unwrap(), ExtendLineBelow.into()),
|
||||||
("X".try_into().unwrap(), CursorAction::ExtendLineAbove.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(), Undo.into()),
|
||||||
("U".try_into().unwrap(), BufferAction::Redo.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(), RotateSelectionsBackward.into()),
|
||||||
(")".try_into().unwrap(), BufferAction::RotateSelectionsForward.into()),
|
(")".try_into().unwrap(), RotateSelectionsForward.into()),
|
||||||
|
|
||||||
(",".try_into().unwrap(), BufferAction::KeepPrimarySelection.into()),
|
(",".try_into().unwrap(), KeepPrimarySelection.into()),
|
||||||
("A-,".try_into().unwrap(), BufferAction::RemovePrimarySelection.into()),
|
("A-,".try_into().unwrap(), RemovePrimarySelection.into()),
|
||||||
|
|
||||||
("1".try_into().unwrap(), BufferAction::SplitSelectionsInto1s.into()),
|
("1".try_into().unwrap(), SplitSelectionsInto1s.into()),
|
||||||
("2".try_into().unwrap(), BufferAction::SplitSelectionsInto2s.into()),
|
("2".try_into().unwrap(), SplitSelectionsInto2s.into()),
|
||||||
("3".try_into().unwrap(), BufferAction::SplitSelectionsInto3s.into()),
|
("3".try_into().unwrap(), SplitSelectionsInto3s.into()),
|
||||||
("4".try_into().unwrap(), BufferAction::SplitSelectionsInto4s.into()),
|
("4".try_into().unwrap(), SplitSelectionsInto4s.into()),
|
||||||
("5".try_into().unwrap(), BufferAction::SplitSelectionsInto5s.into()),
|
("5".try_into().unwrap(), SplitSelectionsInto5s.into()),
|
||||||
("6".try_into().unwrap(), BufferAction::SplitSelectionsInto6s.into()),
|
("6".try_into().unwrap(), SplitSelectionsInto6s.into()),
|
||||||
("7".try_into().unwrap(), BufferAction::SplitSelectionsInto7s.into()),
|
("7".try_into().unwrap(), SplitSelectionsInto7s.into()),
|
||||||
("8".try_into().unwrap(), BufferAction::SplitSelectionsInto8s.into()),
|
("8".try_into().unwrap(), SplitSelectionsInto8s.into()),
|
||||||
("9".try_into().unwrap(), BufferAction::SplitSelectionsInto9s.into()),
|
("9".try_into().unwrap(), SplitSelectionsInto9s.into()),
|
||||||
|
|
||||||
("J".try_into().unwrap(), BufferAction::JumpToSelectedOffsetRelativeToMark.into()),
|
("J".try_into().unwrap(), JumpToSelectedOffsetRelativeToMark.into()),
|
||||||
("A-J".try_into().unwrap(), BufferAction::JumpToSelectedOffset.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()),
|
("C- ".try_into().unwrap(), InspectSelection.into()),
|
||||||
("A- ".try_into().unwrap(), BufferAction::InspectSelectionColor.into()),
|
("A- ".try_into().unwrap(), InspectSelectionColor.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::View), [
|
(Some(PartialAction::View), [
|
||||||
("z".try_into().unwrap(), BufferAction::AlignViewCenter.into()),
|
("z".try_into().unwrap(), AlignViewCenter.into()),
|
||||||
("b".try_into().unwrap(), BufferAction::AlignViewBottom.into()),
|
("b".try_into().unwrap(), AlignViewBottom.into()),
|
||||||
("t".try_into().unwrap(), BufferAction::AlignViewTop.into()),
|
("t".try_into().unwrap(), AlignViewTop.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Space), [
|
(Some(PartialAction::Space), [
|
||||||
("w".try_into().unwrap(), BufferAction::Save.into()),
|
("w".try_into().unwrap(), Save.into()),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Repeat), [
|
(Some(PartialAction::Repeat), [
|
||||||
("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()),
|
("i".try_into().unwrap(), ExtendByteUp.into()),
|
||||||
("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()),
|
("k".try_into().unwrap(), ExtendByteDown.into()),
|
||||||
("j".try_into().unwrap(), CursorAction::ExtendByteLeft.into()),
|
("j".try_into().unwrap(), ExtendByteLeft.into()),
|
||||||
("l".try_into().unwrap(), CursorAction::ExtendByteRight.into()),
|
("l".try_into().unwrap(), ExtendByteRight.into()),
|
||||||
|
|
||||||
("C-e".try_into().unwrap(), BufferAction::ScrollDown.into()),
|
("C-e".try_into().unwrap(), ScrollDown.into()),
|
||||||
("C-y".try_into().unwrap(), BufferAction::ScrollUp.into()),
|
("C-y".try_into().unwrap(), ScrollUp.into()),
|
||||||
|
|
||||||
("C-d".try_into().unwrap(), BufferAction::PageCursorHalfDown.into()),
|
("C-d".try_into().unwrap(), PageCursorHalfDown.into()),
|
||||||
("C-u".try_into().unwrap(), BufferAction::PageCursorHalfUp.into()),
|
("C-u".try_into().unwrap(), PageCursorHalfUp.into()),
|
||||||
|
|
||||||
("C-f".try_into().unwrap(), BufferAction::PageDown.into()),
|
("C-f".try_into().unwrap(), PageDown.into()),
|
||||||
("C-b".try_into().unwrap(), BufferAction::PageUp.into()),
|
("C-b".try_into().unwrap(), PageUp.into()),
|
||||||
|
|
||||||
("w".try_into().unwrap(), CursorAction::ExtendNextWordStart.into()),
|
("w".try_into().unwrap(), ExtendNextWordStart.into()),
|
||||||
("e".try_into().unwrap(), CursorAction::ExtendNextWordEnd.into()),
|
("e".try_into().unwrap(), ExtendNextWordEnd.into()),
|
||||||
("b".try_into().unwrap(), CursorAction::ExtendPreviousWordStart.into()),
|
("b".try_into().unwrap(), ExtendPreviousWordStart.into()),
|
||||||
|
|
||||||
("x".try_into().unwrap(), CursorAction::ExtendLineBelow.into()),
|
("x".try_into().unwrap(), ExtendLineBelow.into()),
|
||||||
("X".try_into().unwrap(), CursorAction::ExtendLineAbove.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()),
|
].into()),
|
||||||
(Some(PartialAction::To), [
|
(Some(PartialAction::To), [
|
||||||
("m".try_into().unwrap(), BufferAction::ExtendToMark.into()),
|
("m".try_into().unwrap(), ExtendToMark.into()),
|
||||||
("0".try_into().unwrap(), BufferAction::ExtendToNull.into()),
|
("0".try_into().unwrap(), ExtendToNull.into()),
|
||||||
("f".try_into().unwrap(), BufferAction::ExtendToFF.into()),
|
("f".try_into().unwrap(), ExtendToFF.into()),
|
||||||
].into()),
|
].into()),
|
||||||
].into())
|
].into())
|
||||||
].into()
|
].into()
|
||||||
|
|||||||
+14
@@ -5,9 +5,13 @@
|
|||||||
#![feature(hash_set_entry)]
|
#![feature(hash_set_entry)]
|
||||||
#![feature(trim_prefix_suffix)]
|
#![feature(trim_prefix_suffix)]
|
||||||
|
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
use app::App;
|
use app::App;
|
||||||
use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}};
|
use crossterm::{QueueableCommand, event::{DisableMouseCapture, EnableMouseCapture}};
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
|
||||||
mod app;
|
mod app;
|
||||||
mod buffer;
|
mod buffer;
|
||||||
mod config;
|
mod config;
|
||||||
@@ -55,6 +59,16 @@ const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
|
|||||||
// - how to fit??! `-128` longer than `80`
|
// - how to fit??! `-128` longer than `80`
|
||||||
|
|
||||||
fn main() {
|
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 app = App::new();
|
||||||
let mut terminal = ratatui::init();
|
let mut terminal = ratatui::init();
|
||||||
crossterm::terminal::enable_raw_mode().unwrap();
|
crossterm::terminal::enable_raw_mode().unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user