mark offset
This commit is contained in:
+19
-1
@@ -1,4 +1,4 @@
|
|||||||
use std::{cmp::min, 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::Stylize, text::Span};
|
use ratatui::{style::Stylize, text::Span};
|
||||||
|
|
||||||
use crate::{BYTES_PER_LINE, app::WindowSize, buffer::{Buffer, Mode, PartialAction}, cursor::Cursor, edit_action::EditAction};
|
use crate::{BYTES_PER_LINE, app::WindowSize, buffer::{Buffer, Mode, PartialAction}, cursor::Cursor, edit_action::EditAction};
|
||||||
@@ -83,6 +83,8 @@ pub enum Action {
|
|||||||
SplitSelectionsInto9s,
|
SplitSelectionsInto9s,
|
||||||
|
|
||||||
JumpToSelectedOffset,
|
JumpToSelectedOffset,
|
||||||
|
|
||||||
|
ToggleMark,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@@ -175,6 +177,8 @@ impl Buffer {
|
|||||||
Action::SplitSelectionsInto9s => self.split_selections_into_size(9),
|
Action::SplitSelectionsInto9s => self.split_selections_into_size(9),
|
||||||
|
|
||||||
Action::JumpToSelectedOffset => self.jump_to_selected_offset(window_size),
|
Action::JumpToSelectedOffset => self.jump_to_selected_offset(window_size),
|
||||||
|
|
||||||
|
Action::ToggleMark => self.toggle_mark(),
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
@@ -646,6 +650,20 @@ impl Buffer {
|
|||||||
self.combine_cursors_if_overlapping();
|
self.combine_cursors_if_overlapping();
|
||||||
self.clamp_screen_to_primary_cursor(window_size);
|
self.clamp_screen_to_primary_cursor(window_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn toggle_mark(&mut self) {
|
||||||
|
match self.marks.entry(self.primary_cursor.lower_bound()) {
|
||||||
|
Entry::Occupied(occupied_entry) => { occupied_entry.remove(); },
|
||||||
|
Entry::Vacant(vacant_entry) => vacant_entry.insert(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for cursor in &self.cursors {
|
||||||
|
match self.marks.entry(cursor.lower_bound()) {
|
||||||
|
Entry::Occupied(occupied_entry) => { occupied_entry.remove(); },
|
||||||
|
Entry::Vacant(vacant_entry) => vacant_entry.insert(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// helpers
|
// helpers
|
||||||
|
|||||||
+5
-1
@@ -1,5 +1,5 @@
|
|||||||
use core::slice::GetDisjointMutIndex;
|
use core::slice::GetDisjointMutIndex;
|
||||||
use std::{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::{style::Color, text::Span};
|
use ratatui::{style::Color, text::Span};
|
||||||
use crate::{action::AppAction, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
|
use crate::{action::AppAction, app::WindowSize, config::Config, cursor::Cursor, edit_action::EditAction};
|
||||||
@@ -16,6 +16,8 @@ pub struct Buffer {
|
|||||||
pub primary_cursor: Cursor,
|
pub primary_cursor: Cursor,
|
||||||
pub cursors: Vec<Cursor>,
|
pub cursors: Vec<Cursor>,
|
||||||
|
|
||||||
|
pub marks: HashSet<usize>,
|
||||||
|
|
||||||
pub mode: Mode,
|
pub mode: Mode,
|
||||||
pub partial_action: Option<PartialAction>,
|
pub partial_action: Option<PartialAction>,
|
||||||
pub partial_replace: Option<u8>,
|
pub partial_replace: Option<u8>,
|
||||||
@@ -86,6 +88,8 @@ impl Buffer {
|
|||||||
primary_cursor: Cursor::default(),
|
primary_cursor: Cursor::default(),
|
||||||
cursors: Vec::new(),
|
cursors: Vec::new(),
|
||||||
|
|
||||||
|
marks: HashSet::from([0, 4, 12, 15, 16, 17]),
|
||||||
|
|
||||||
mode: Mode::Normal,
|
mode: Mode::Normal,
|
||||||
partial_action: None,
|
partial_action: None,
|
||||||
partial_replace: None,
|
partial_replace: None,
|
||||||
|
|||||||
+22
-19
@@ -103,15 +103,9 @@ mod hex {
|
|||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
.zip((address..).step_by(BYTES_PER_CHUNK))
|
.zip((address..).step_by(BYTES_PER_CHUNK))
|
||||||
.map(|(chunk, address)| self.render_chunk(address, &chunk).collect())
|
.flat_map(|(chunk, address)| {
|
||||||
.interleave(
|
self.render_chunk(address, &chunk).collect::<Vec<_>>()
|
||||||
(address..)
|
})
|
||||||
.step_by(BYTES_PER_CHUNK)
|
|
||||||
.take(CHUNKS_PER_LINE)
|
|
||||||
.skip(1)
|
|
||||||
.map(|address| vec![self.render_large_space_before(address)])
|
|
||||||
)
|
|
||||||
.flatten()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_partial_chunks(
|
pub fn render_partial_chunks(
|
||||||
@@ -161,6 +155,8 @@ mod hex {
|
|||||||
bytes: &[u8; BYTES_PER_CHUNK]
|
bytes: &[u8; BYTES_PER_CHUNK]
|
||||||
) -> impl Iterator<Item=Span<'static>> {
|
) -> impl Iterator<Item=Span<'static>> {
|
||||||
#[allow(unstable_name_collisions)]
|
#[allow(unstable_name_collisions)]
|
||||||
|
iter::once(self.render_large_space_before(address))
|
||||||
|
.chain(
|
||||||
bytes
|
bytes
|
||||||
.iter()
|
.iter()
|
||||||
.copied()
|
.copied()
|
||||||
@@ -172,6 +168,7 @@ mod hex {
|
|||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|address| self.render_space_before(address))
|
.map(|address| self.render_space_before(address))
|
||||||
)
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_partial_chunk(
|
fn render_partial_chunk(
|
||||||
@@ -244,30 +241,36 @@ mod hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_large_space_before(&self, address: usize) -> Span<'static> {
|
fn render_large_space_before(&self, address: usize) -> Span<'static> {
|
||||||
|
let span: Span = if self.marks.contains(&address) {
|
||||||
|
" →".into()
|
||||||
|
} else {
|
||||||
|
" ".into()
|
||||||
|
};
|
||||||
|
|
||||||
if iter::once(&self.primary_cursor)
|
if iter::once(&self.primary_cursor)
|
||||||
.chain(&self.cursors)
|
.chain(&self.cursors)
|
||||||
.any(|cursor| cursor.contains_space_before(address))
|
.any(|cursor| cursor.contains_space_before(address))
|
||||||
{
|
{
|
||||||
Span {
|
span.bg(Color::select_grey())
|
||||||
style: Style::new().bg(Color::select_grey()),
|
|
||||||
content: " ".into()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
" ".into()
|
span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_space_before(&self, address: usize) -> Span<'static> {
|
fn render_space_before(&self, address: usize) -> Span<'static> {
|
||||||
|
let span: Span = if self.marks.contains(&address) {
|
||||||
|
"→".into()
|
||||||
|
} else {
|
||||||
|
" ".into()
|
||||||
|
};
|
||||||
|
|
||||||
if iter::once(&self.primary_cursor)
|
if iter::once(&self.primary_cursor)
|
||||||
.chain(&self.cursors)
|
.chain(&self.cursors)
|
||||||
.any(|cursor| cursor.contains_space_before(address))
|
.any(|cursor| cursor.contains_space_before(address))
|
||||||
{
|
{
|
||||||
Span {
|
span.bg(Color::select_grey())
|
||||||
style: Style::new().bg(Color::select_grey()),
|
|
||||||
content: " ".into()
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
" ".into()
|
span
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -163,6 +163,8 @@ impl Default for Config {
|
|||||||
("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
|
("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
|
||||||
|
|
||||||
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
|
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
|
||||||
|
|
||||||
|
("m".try_into().unwrap(), Action::ToggleMark),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Goto), [
|
(Some(PartialAction::Goto), [
|
||||||
("j".try_into().unwrap(), Action::GotoLineStart),
|
("j".try_into().unwrap(), Action::GotoLineStart),
|
||||||
@@ -234,6 +236,8 @@ impl Default for Config {
|
|||||||
("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
|
("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
|
||||||
|
|
||||||
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
|
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
|
||||||
|
|
||||||
|
("m".try_into().unwrap(), Action::ToggleMark),
|
||||||
].into()),
|
].into()),
|
||||||
(Some(PartialAction::Space), [
|
(Some(PartialAction::Space), [
|
||||||
("w".try_into().unwrap(), Action::Save),
|
("w".try_into().unwrap(), Action::Save),
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#![allow(clippy::cast_possible_truncation)]
|
#![allow(clippy::cast_possible_truncation)]
|
||||||
#![feature(get_disjoint_mut_helpers)]
|
#![feature(get_disjoint_mut_helpers)]
|
||||||
#![feature(exact_bitshifts)]
|
#![feature(exact_bitshifts)]
|
||||||
|
#![feature(hash_set_entry)]
|
||||||
|
|
||||||
use app::App;
|
use app::App;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user