replacing
This commit is contained in:
+10
-10
@@ -9,9 +9,9 @@ pub enum Action {
|
|||||||
NormalMode,
|
NormalMode,
|
||||||
SelectMode,
|
SelectMode,
|
||||||
|
|
||||||
GPartial,
|
Goto,
|
||||||
ZPartial,
|
Zview,
|
||||||
RPartial,
|
Replace,
|
||||||
|
|
||||||
MoveByteUp,
|
MoveByteUp,
|
||||||
MoveByteDown,
|
MoveByteDown,
|
||||||
@@ -61,9 +61,9 @@ impl App {
|
|||||||
Action::NormalMode => self.normal_mode(),
|
Action::NormalMode => self.normal_mode(),
|
||||||
Action::SelectMode => self.select_mode(),
|
Action::SelectMode => self.select_mode(),
|
||||||
|
|
||||||
Action::GPartial => self.g_partial(),
|
Action::Goto => self.goto(),
|
||||||
Action::ZPartial => self.z_partial(),
|
Action::Zview => self.zview(),
|
||||||
Action::RPartial => self.r_partial(),
|
Action::Replace => self.replace(),
|
||||||
|
|
||||||
Action::MoveByteUp => self.move_byte_up(),
|
Action::MoveByteUp => self.move_byte_up(),
|
||||||
Action::MoveByteDown => self.move_byte_down(),
|
Action::MoveByteDown => self.move_byte_down(),
|
||||||
@@ -118,15 +118,15 @@ impl App {
|
|||||||
self.mode = Mode::Select;
|
self.mode = Mode::Select;
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn g_partial(&mut self) {
|
const fn goto(&mut self) {
|
||||||
self.partial_action = Some(PartialAction::Goto);
|
self.partial_action = Some(PartialAction::Goto);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn z_partial(&mut self) {
|
const fn zview(&mut self) {
|
||||||
self.partial_action = Some(PartialAction::Zview);
|
self.partial_action = Some(PartialAction::Zview);
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn r_partial(&mut self) {
|
const fn replace(&mut self) {
|
||||||
self.partial_action = Some(PartialAction::Replace);
|
self.partial_action = Some(PartialAction::Replace);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ impl App {
|
|||||||
self.execute_and_add(
|
self.execute_and_add(
|
||||||
EditAction::Delete {
|
EditAction::Delete {
|
||||||
cursor: self.cursor,
|
cursor: self.cursor,
|
||||||
data: self.contents[self.cursor.range()].into()
|
old_data: self.contents[self.cursor.range()].into()
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+70
-16
@@ -20,6 +20,7 @@ pub struct App {
|
|||||||
|
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
pub partial_action: Option<PartialAction>,
|
pub partial_action: Option<PartialAction>,
|
||||||
|
pub partial_replace: Option<u8>,
|
||||||
|
|
||||||
pub edit_history: Vec<EditAction>,
|
pub edit_history: Vec<EditAction>,
|
||||||
// some index to keep track of where we are? edit_prophecy?
|
// some index to keep track of where we are? edit_prophecy?
|
||||||
@@ -27,18 +28,18 @@ pub struct App {
|
|||||||
pub logs: Vec<String>,
|
pub logs: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum Mode {
|
pub enum Mode {
|
||||||
Normal, Select, Insert
|
Normal, Select, Insert
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
|
||||||
pub enum PartialAction {
|
pub enum PartialAction {
|
||||||
Goto, Zview, Replace
|
Goto, Zview, Replace
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Mode {
|
impl Mode {
|
||||||
pub const fn label(&self) -> &'static str {
|
pub const fn label(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Normal => " NORMAL ",
|
Self::Normal => " NORMAL ",
|
||||||
Self::Select => " SELECT ",
|
Self::Select => " SELECT ",
|
||||||
@@ -46,7 +47,7 @@ impl Mode {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn color(&self) -> Color {
|
pub const fn color(self) -> Color {
|
||||||
match self {
|
match self {
|
||||||
Self::Normal => Color::Blue,
|
Self::Normal => Color::Blue,
|
||||||
Self::Select => Color::Yellow,
|
Self::Select => Color::Yellow,
|
||||||
@@ -56,7 +57,7 @@ impl Mode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl PartialAction {
|
impl PartialAction {
|
||||||
pub const fn label(&self) -> &'static str {
|
pub const fn label(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
Self::Goto => "g",
|
Self::Goto => "g",
|
||||||
Self::Zview => "z",
|
Self::Zview => "z",
|
||||||
@@ -98,6 +99,7 @@ impl App {
|
|||||||
|
|
||||||
mode: Mode::Normal,
|
mode: Mode::Normal,
|
||||||
partial_action: None,
|
partial_action: None,
|
||||||
|
partial_replace: None,
|
||||||
|
|
||||||
edit_history: Vec::new(),
|
edit_history: Vec::new(),
|
||||||
|
|
||||||
@@ -122,17 +124,69 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_key(&mut self, event: KeyEvent) {
|
fn handle_key(&mut self, event: KeyEvent) {
|
||||||
let should_reset_partial = self.partial_action.is_some();
|
if self.partial_action == Some(PartialAction::Replace) {
|
||||||
|
if let Some(hex_character) = event.code.as_char() &&
|
||||||
if let Some(mode_config) = self.config.0.get(&self.mode) &&
|
let Some(nybble) = nybble_from_hex(hex_character)
|
||||||
let Some(keybinds) = mode_config.0.get(&self.partial_action) &&
|
{
|
||||||
let Some(action) = keybinds.0.get(&event.into())
|
if let Some(partial_replace) = self.partial_replace.take() {
|
||||||
{
|
self.execute_and_add(
|
||||||
self.execute(*action);
|
EditAction::Replace {
|
||||||
}
|
cursor: self.cursor,
|
||||||
|
old_data: self.contents[self.cursor.range()].into(),
|
||||||
if should_reset_partial {
|
new_byte: partial_replace << 4 | nybble
|
||||||
self.partial_action = None;
|
}
|
||||||
|
);
|
||||||
|
self.partial_action = None;
|
||||||
|
} else {
|
||||||
|
self.partial_replace = Some(nybble);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.partial_action = None;
|
||||||
|
self.partial_replace = None;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let should_reset_partial = self.partial_action.is_some();
|
||||||
|
|
||||||
|
if let Some(mode_config) = self.config.0.get(&self.mode) &&
|
||||||
|
let Some(keybinds) = mode_config.0.get(&self.partial_action) &&
|
||||||
|
let Some(action) = keybinds.0.get(&event.into())
|
||||||
|
{
|
||||||
|
self.execute(*action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if should_reset_partial {
|
||||||
|
self.partial_action = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nybble_from_hex(hex: char) -> Option<u8> {
|
||||||
|
if !hex.is_ascii() { return None }
|
||||||
|
|
||||||
|
match hex {
|
||||||
|
'0'..='9' => Some(u8::try_from(hex).unwrap() - u8::try_from('0').unwrap()),
|
||||||
|
'a'..='f' => Some(u8::try_from(hex).unwrap() - u8::try_from('a').unwrap() + 10),
|
||||||
|
'A'..='F' => Some(u8::try_from(hex).unwrap() - u8::try_from('A').unwrap() + 10),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mod tests {
|
||||||
|
#[allow(unused_imports)]
|
||||||
|
use crate::app::nybble_from_hex;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nybble_from_hex_case_doesnt_matter() {
|
||||||
|
for character in 'a'..='f' {
|
||||||
|
assert_eq!(nybble_from_hex(character), nybble_from_hex(character.to_ascii_uppercase()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn nybble_from_hex_digits_are_correct() {
|
||||||
|
for (index, character) in ('0'..='9').enumerate() {
|
||||||
|
assert_eq!(nybble_from_hex(character), Some(index as u8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -394,7 +394,7 @@ mod status_line {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mod extra_statuses {
|
mod extra_statuses {
|
||||||
use crate::app::{App, PartialAction};
|
use crate::app::App;
|
||||||
use ratatui::text::Line;
|
use ratatui::text::Line;
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
@@ -404,7 +404,7 @@ mod extra_statuses {
|
|||||||
|
|
||||||
let partial_action = self.partial_action
|
let partial_action = self.partial_action
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map_or("", PartialAction::label);
|
.map_or("", |partial_action| partial_action.label());
|
||||||
|
|
||||||
format!("{partial_action} {percentage:.0}% ").into()
|
format!("{partial_action} {percentage:.0}% ").into()
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -103,9 +103,9 @@ impl Default for Config {
|
|||||||
|
|
||||||
("v".try_into().unwrap(), Action::SelectMode),
|
("v".try_into().unwrap(), Action::SelectMode),
|
||||||
|
|
||||||
("g".try_into().unwrap(), Action::GPartial),
|
("g".try_into().unwrap(), Action::Goto),
|
||||||
("z".try_into().unwrap(), Action::ZPartial),
|
("z".try_into().unwrap(), Action::Zview),
|
||||||
("r".try_into().unwrap(), Action::RPartial),
|
("r".try_into().unwrap(), Action::Replace),
|
||||||
|
|
||||||
("i".try_into().unwrap(), Action::MoveByteUp),
|
("i".try_into().unwrap(), Action::MoveByteUp),
|
||||||
("k".try_into().unwrap(), Action::MoveByteDown),
|
("k".try_into().unwrap(), Action::MoveByteDown),
|
||||||
@@ -147,9 +147,9 @@ impl Default for Config {
|
|||||||
|
|
||||||
("v".try_into().unwrap(), Action::NormalMode),
|
("v".try_into().unwrap(), Action::NormalMode),
|
||||||
|
|
||||||
("g".try_into().unwrap(), Action::GPartial),
|
("g".try_into().unwrap(), Action::Goto),
|
||||||
("z".try_into().unwrap(), Action::ZPartial),
|
("z".try_into().unwrap(), Action::Zview),
|
||||||
("r".try_into().unwrap(), Action::RPartial),
|
("r".try_into().unwrap(), Action::Replace),
|
||||||
|
|
||||||
("i".try_into().unwrap(), Action::ExtendByteUp),
|
("i".try_into().unwrap(), Action::ExtendByteUp),
|
||||||
("k".try_into().unwrap(), Action::ExtendByteDown),
|
("k".try_into().unwrap(), Action::ExtendByteDown),
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
use std::ops::RangeInclusive;
|
use std::ops::RangeInclusive;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||||
pub struct Cursor {
|
pub struct Cursor {
|
||||||
pub head: usize,
|
pub head: usize,
|
||||||
pub tail: usize
|
pub tail: usize
|
||||||
|
|||||||
+15
-1
@@ -4,7 +4,12 @@ use crate::{app::App, cursor::Cursor};
|
|||||||
pub enum EditAction {
|
pub enum EditAction {
|
||||||
Delete {
|
Delete {
|
||||||
cursor: Cursor,
|
cursor: Cursor,
|
||||||
data: Vec<u8>
|
old_data: Vec<u8>
|
||||||
|
},
|
||||||
|
Replace {
|
||||||
|
cursor: Cursor,
|
||||||
|
old_data: Vec<u8>,
|
||||||
|
new_byte: u8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -17,6 +22,9 @@ impl App {
|
|||||||
fn execute_edit(&mut self, edit_action: &EditAction) {
|
fn execute_edit(&mut self, edit_action: &EditAction) {
|
||||||
match edit_action {
|
match edit_action {
|
||||||
EditAction::Delete { cursor, .. } => self.delete_at(*cursor),
|
EditAction::Delete { cursor, .. } => self.delete_at(*cursor),
|
||||||
|
EditAction::Replace {
|
||||||
|
cursor, old_data: _, new_byte
|
||||||
|
} => self.replace_at_with(*cursor, *new_byte),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,4 +34,10 @@ impl App {
|
|||||||
self.cursor.head = min(cursor.head, cursor.tail);
|
self.cursor.head = min(cursor.head, cursor.tail);
|
||||||
self.cursor.collapse();
|
self.cursor.collapse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn replace_at_with(&mut self, cursor: Cursor, new_byte: u8) {
|
||||||
|
self.contents[self.cursor.range()].fill(new_byte);
|
||||||
|
|
||||||
|
self.cursor = cursor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-8
@@ -18,23 +18,23 @@ const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
|
|||||||
|
|
||||||
// TODO:
|
// TODO:
|
||||||
// - undo/redo
|
// - undo/redo
|
||||||
// - modes
|
|
||||||
// - select
|
|
||||||
// - insert
|
|
||||||
// - zz/zt/zb
|
|
||||||
// - modifications
|
// - modifications
|
||||||
|
// - replace
|
||||||
|
// - partial action(s)
|
||||||
// - insert/append
|
// - insert/append
|
||||||
// - mode
|
// - mode
|
||||||
// - replace
|
// - how this works with edit history is strange :/
|
||||||
// - partial action
|
// - add to edit history when *leaving* insert mode
|
||||||
// - replace-and-keep-going
|
// - replace-and-keep-going
|
||||||
// - mode
|
// - mode
|
||||||
// - delete
|
|
||||||
// - change
|
// - change
|
||||||
|
// - saving
|
||||||
|
// - search
|
||||||
// - edit character panel
|
// - edit character panel
|
||||||
// - modifier on existing keys like teehee? or jump to panel?
|
// - modifier on existing keys like teehee? or jump to panel?
|
||||||
// - if jump to panel, space?
|
// - if jump to panel, space?
|
||||||
// - search
|
// - zz/zt/zb
|
||||||
|
// - visual gg/G
|
||||||
// - jumplist
|
// - jumplist
|
||||||
// - f/t
|
// - f/t
|
||||||
// - ascii?
|
// - ascii?
|
||||||
@@ -53,6 +53,8 @@ const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
|
|||||||
// - utf8?
|
// - utf8?
|
||||||
// - diffing
|
// - diffing
|
||||||
|
|
||||||
|
// when AsciiChar is stabilized, use it instead of char everywhere
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = App::init();
|
let mut app = App::init();
|
||||||
let mut terminal = ratatui::init();
|
let mut terminal = ratatui::init();
|
||||||
|
|||||||
Reference in New Issue
Block a user