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