This commit is contained in:
alice pellerin
2026-03-21 22:32:19 -05:00
parent 9ac66fc074
commit 1a6e7882ed
4 changed files with 130 additions and 6 deletions
+116 -2
View File
@@ -37,6 +37,7 @@ pub enum BufferAction {
Replace,
Space,
Repeat,
To,
ScrollDown,
ScrollUp,
@@ -83,6 +84,10 @@ pub enum BufferAction {
AlignViewCenter,
AlignViewBottom,
AlignViewTop,
ExtendToMark,
ExtendToNull,
ExtendToFF,
}
impl From<BufferAction> for Action {
@@ -137,6 +142,7 @@ impl Buffer {
BufferAction::Replace => self.replace(),
BufferAction::Space => self.space(),
BufferAction::Repeat => self.repeat(),
BufferAction::To => self.to(),
BufferAction::ScrollDown => self.scroll_down(window_size),
BufferAction::ScrollUp => self.scroll_up(window_size),
@@ -148,7 +154,7 @@ impl Buffer {
BufferAction::PageUp => self.page_up(window_size),
BufferAction::CollapseSelection => self.collapse_selection(),
BufferAction::FlipSelections => self.flip_selection(),
BufferAction::FlipSelections => self.flip_selection(window_size),
BufferAction::Delete => self.delete(window_size),
@@ -183,6 +189,10 @@ impl Buffer {
BufferAction::AlignViewCenter => self.align_view_center(window_size),
BufferAction::AlignViewBottom => self.align_view_bottom(window_size),
BufferAction::AlignViewTop => self.align_view_top(),
BufferAction::ExtendToMark => self.extend_to_mark(window_size),
BufferAction::ExtendToNull => self.extend_to_null(window_size),
BufferAction::ExtendToFF => self.extend_to_FF(window_size),
}
}
@@ -216,6 +226,10 @@ impl Buffer {
self.partial_action = Some(PartialAction::Repeat);
}
const fn to(&mut self) {
self.partial_action = Some(PartialAction::To);
}
pub fn scroll_down(&mut self, window_size: WindowSize) {
if self.contents.len() <= BYTES_OF_PADDING { return; }
@@ -348,12 +362,14 @@ impl Buffer {
}
}
fn flip_selection(&mut self) {
fn flip_selection(&mut self, window_size: WindowSize) {
self.primary_cursor.flip();
for cursor in &mut self.cursors {
cursor.flip();
}
self.clamp_screen_to_primary_cursor(window_size);
}
fn delete(&mut self, window_size: WindowSize) {
@@ -651,6 +667,84 @@ impl Buffer {
.saturating_sub(self.primary_cursor.head % BYTES_PER_LINE)
.saturating_sub(BYTES_OF_PADDING);
}
fn extend_to_mark(&mut self, window_size: WindowSize) {
let mut sorted_marks: Vec<_> = self.marks.iter().copied().collect();
sorted_marks.sort_unstable();
let max_contents_index = self.max_contents_index();
let mark_after_primary = mark_after(
self.primary_cursor.head + 1,
&sorted_marks,
max_contents_index
);
self.primary_cursor.tail = self.primary_cursor.head;
self.primary_cursor.head = mark_after_primary - 1;
for cursor in &mut self.cursors {
let mark_after_cursor = mark_after(
cursor.head + 1,
&sorted_marks,
max_contents_index
);
cursor.tail = cursor.head;
cursor.head = mark_after_cursor - 1;
}
self.clamp_screen_to_primary_cursor(window_size);
}
fn extend_to_null(&mut self, window_size: WindowSize) {
if let Some(null_offset_after_primary) = self.contents[self.primary_cursor.head..]
.iter()
.skip(2)
.position(|&byte| byte == 0)
{
self.primary_cursor.tail = self.primary_cursor.head;
self.primary_cursor.head += null_offset_after_primary + 1;
}
for cursor in &mut self.cursors {
if let Some(null_offset_after_primary) = self.contents[cursor.head..]
.iter()
.skip(2)
.position(|&byte| byte == 0)
{
cursor.tail = cursor.head;
cursor.head += null_offset_after_primary + 1;
}
}
self.clamp_screen_to_primary_cursor(window_size);
}
#[allow(non_snake_case)]
fn extend_to_FF(&mut self, window_size: WindowSize) {
if let Some(null_offset_after_primary) = self.contents[self.primary_cursor.head..]
.iter()
.skip(2)
.position(|&byte| byte == 0xFF)
{
self.primary_cursor.tail = self.primary_cursor.head;
self.primary_cursor.head += null_offset_after_primary + 1;
}
for cursor in &mut self.cursors {
if let Some(null_offset_after_primary) = self.contents[cursor.head..]
.iter()
.skip(2)
.position(|&byte| byte == 0xFF)
{
cursor.tail = cursor.head;
cursor.head += null_offset_after_primary + 1;
}
}
self.clamp_screen_to_primary_cursor(window_size);
}
}
// helpers
@@ -682,3 +776,23 @@ fn mark_before(offset: usize, sorted_marks: &[usize]) -> usize {
Err(mark_after_index) => sorted_marks[mark_after_index - 1],
}
}
// or end index if no mark is after
fn mark_after(offset: usize, sorted_marks: &[usize], max: usize) -> usize {
if sorted_marks.is_empty() { return max + 1; }
match sorted_marks.binary_search(&offset) {
Ok(mark_before_index) => if mark_before_index == sorted_marks.len() - 1 {
max + 1
} else {
sorted_marks[mark_before_index + 1]
},
Err(mark_after_index) => {
if mark_after_index == sorted_marks.len() {
max + 1
} else {
sorted_marks[mark_after_index]
}
},
}
}
+2 -1
View File
@@ -40,7 +40,7 @@ pub enum Mode {
#[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub enum PartialAction {
Goto, View, Replace, Space, Repeat
Goto, View, Replace, Space, Repeat, To
}
impl Mode {
@@ -69,6 +69,7 @@ impl PartialAction {
Self::Replace => "r",
Self::Space => "",
Self::Repeat => "×",
Self::To => "t",
}
}
}
+12
View File
@@ -107,6 +107,7 @@ impl Default for Config {
("r".try_into().unwrap(), BufferAction::Replace.into()),
(" ".try_into().unwrap(), BufferAction::Space.into()),
("*".try_into().unwrap(), BufferAction::Repeat.into()),
("t".try_into().unwrap(), BufferAction::To.into()),
("i".try_into().unwrap(), CursorAction::MoveByteUp.into()),
("k".try_into().unwrap(), CursorAction::MoveByteDown.into()),
@@ -207,6 +208,11 @@ impl Default for Config {
("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()),
].into()),
(Some(PartialAction::To), [
("m".try_into().unwrap(), BufferAction::ExtendToMark.into()),
("0".try_into().unwrap(), BufferAction::ExtendToNull.into()),
("f".try_into().unwrap(), BufferAction::ExtendToFF.into()),
].into()),
].into()),
(Mode::Select, [
(None, [
@@ -220,6 +226,7 @@ impl Default for Config {
("r".try_into().unwrap(), BufferAction::Replace.into()),
(" ".try_into().unwrap(), BufferAction::Space.into()),
("*".try_into().unwrap(), BufferAction::Repeat.into()),
("t".try_into().unwrap(), BufferAction::To.into()),
("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()),
("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()),
@@ -309,6 +316,11 @@ impl Default for Config {
("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()),
].into()),
(Some(PartialAction::To), [
("m".try_into().unwrap(), BufferAction::ExtendToMark.into()),
("0".try_into().unwrap(), BufferAction::ExtendToNull.into()),
("f".try_into().unwrap(), BufferAction::ExtendToFF.into()),
].into()),
].into())
].into()
}
-3
View File
@@ -26,9 +26,6 @@ const LINES_OF_PADDING: usize = 5;
const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
// TODO:
// - extend to mark (tm?)
// - t0 can be to next null
// - tf can be to next FF
// - inspect selection
// - resizing can move the cursor off the screen
// - tab bar overflow