jump to selected offset

This commit is contained in:
alice pellerin
2026-03-21 01:10:24 -05:00
parent 05d3a8a293
commit 5716ae804d
3 changed files with 58 additions and 2 deletions
+51 -1
View File
@@ -81,6 +81,8 @@ pub enum Action {
SplitSelectionsInto7s, SplitSelectionsInto7s,
SplitSelectionsInto8s, SplitSelectionsInto8s,
SplitSelectionsInto9s, SplitSelectionsInto9s,
JumpToSelectedOffset,
} }
// 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
@@ -171,6 +173,8 @@ impl Buffer {
Action::SplitSelectionsInto7s => self.split_selections_into_size(7), Action::SplitSelectionsInto7s => self.split_selections_into_size(7),
Action::SplitSelectionsInto8s => self.split_selections_into_size(8), Action::SplitSelectionsInto8s => self.split_selections_into_size(8),
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),
} }
None None
@@ -600,12 +604,48 @@ impl Buffer {
cursor cursor
.range() .range()
.step_by(size) .step_by(size)
.map(|head| Cursor { head, tail: head + size - 1 }) .map(|tail| Cursor { head: tail + size - 1, tail })
}); });
self.primary_cursor = new_cursors.next().unwrap(); self.primary_cursor = new_cursors.next().unwrap();
self.cursors = new_cursors.collect(); self.cursors = new_cursors.collect();
} }
fn jump_to_selected_offset(&mut self, window_size: WindowSize) {
if !iter::once(&self.primary_cursor)
.chain(&self.cursors)
.all(|cursor| {
bytes_as_nat(&self.contents[cursor.range()])
.is_some_and(|offset| offset < self.contents.len())
})
{
if self.cursors.is_empty() {
self.alert_message = Span::from(
"selection is not a valid offset"
).red();
} else {
self.alert_message = Span::from(
"not all selections are valid offsets"
).red();
}
return;
}
self.primary_cursor = Cursor::at(
bytes_as_nat(&self.contents[self.primary_cursor.range()]).unwrap()
);
for cursor in &mut self.cursors {
*cursor = Cursor::at(
bytes_as_nat(&self.contents[cursor.range()]).unwrap()
);
}
self.cursors.sort_by_key(|cursor| cursor.head);
self.combine_cursors_if_overlapping();
self.clamp_screen_to_primary_cursor(window_size);
}
} }
// helpers // helpers
@@ -622,3 +662,13 @@ impl Buffer {
} }
} }
} }
fn bytes_as_nat(bytes: &[u8]) -> Option<usize> {
bytes
.iter()
.rev() // little-endian
.skip_while(|&&byte| byte == 0)
.try_fold(usize::default(), |result, &byte| {
Some(result.shl_exact(8)? | (byte as usize))
})
}
+4
View File
@@ -161,6 +161,8 @@ impl Default for Config {
("7".try_into().unwrap(), Action::SplitSelectionsInto7s), ("7".try_into().unwrap(), Action::SplitSelectionsInto7s),
("8".try_into().unwrap(), Action::SplitSelectionsInto8s), ("8".try_into().unwrap(), Action::SplitSelectionsInto8s),
("9".try_into().unwrap(), Action::SplitSelectionsInto9s), ("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
].into()), ].into()),
(Some(PartialAction::Goto), [ (Some(PartialAction::Goto), [
("j".try_into().unwrap(), Action::GotoLineStart), ("j".try_into().unwrap(), Action::GotoLineStart),
@@ -230,6 +232,8 @@ impl Default for Config {
("7".try_into().unwrap(), Action::SplitSelectionsInto7s), ("7".try_into().unwrap(), Action::SplitSelectionsInto7s),
("8".try_into().unwrap(), Action::SplitSelectionsInto8s), ("8".try_into().unwrap(), Action::SplitSelectionsInto8s),
("9".try_into().unwrap(), Action::SplitSelectionsInto9s), ("9".try_into().unwrap(), Action::SplitSelectionsInto9s),
("J".try_into().unwrap(), Action::JumpToSelectedOffset),
].into()), ].into()),
(Some(PartialAction::Space), [ (Some(PartialAction::Space), [
("w".try_into().unwrap(), Action::Save), ("w".try_into().unwrap(), Action::Save),
+3 -1
View File
@@ -1,6 +1,7 @@
#![warn(clippy::pedantic, clippy::nursery)] #![warn(clippy::pedantic, clippy::nursery)]
#![allow(clippy::cast_possible_truncation)] #![allow(clippy::cast_possible_truncation)]
#![feature(get_disjoint_mut_helpers)] #![feature(get_disjoint_mut_helpers)]
#![feature(exact_bitshifts)]
use app::App; use app::App;
@@ -20,7 +21,6 @@ const BYTES_PER_CHUNK: usize = 4;
const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK; const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
// TODO: // TODO:
// - J jump to offset under cursor
// - m mark offset // - m mark offset
// - search // - search
// - s/A-k/A-K // - s/A-k/A-K
@@ -40,6 +40,8 @@ const CHUNKS_PER_LINE: usize = BYTES_PER_LINE / BYTES_PER_CHUNK;
// - y/p // - y/p
// - [/] to cycle view offset? // - [/] to cycle view offset?
// - gj jump to entered offset // - gj jump to entered offset
// - repeat X times (dec and hex)
// - jump relative to last marker?
// future directions // future directions
// - 'views' for bytes (i8/16/etc u8/16/etc 20.12/8.4/etc) // - 'views' for bytes (i8/16/etc u8/16/etc 20.12/8.4/etc)