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, Replace,
Space, Space,
Repeat, Repeat,
To,
ScrollDown, ScrollDown,
ScrollUp, ScrollUp,
@@ -83,6 +84,10 @@ pub enum BufferAction {
AlignViewCenter, AlignViewCenter,
AlignViewBottom, AlignViewBottom,
AlignViewTop, AlignViewTop,
ExtendToMark,
ExtendToNull,
ExtendToFF,
} }
impl From<BufferAction> for Action { impl From<BufferAction> for Action {
@@ -137,6 +142,7 @@ impl Buffer {
BufferAction::Replace => self.replace(), BufferAction::Replace => self.replace(),
BufferAction::Space => self.space(), BufferAction::Space => self.space(),
BufferAction::Repeat => self.repeat(), BufferAction::Repeat => self.repeat(),
BufferAction::To => self.to(),
BufferAction::ScrollDown => self.scroll_down(window_size), BufferAction::ScrollDown => self.scroll_down(window_size),
BufferAction::ScrollUp => self.scroll_up(window_size), BufferAction::ScrollUp => self.scroll_up(window_size),
@@ -148,7 +154,7 @@ impl Buffer {
BufferAction::PageUp => self.page_up(window_size), BufferAction::PageUp => self.page_up(window_size),
BufferAction::CollapseSelection => self.collapse_selection(), BufferAction::CollapseSelection => self.collapse_selection(),
BufferAction::FlipSelections => self.flip_selection(), BufferAction::FlipSelections => self.flip_selection(window_size),
BufferAction::Delete => self.delete(window_size), BufferAction::Delete => self.delete(window_size),
@@ -183,6 +189,10 @@ impl Buffer {
BufferAction::AlignViewCenter => self.align_view_center(window_size), BufferAction::AlignViewCenter => self.align_view_center(window_size),
BufferAction::AlignViewBottom => self.align_view_bottom(window_size), BufferAction::AlignViewBottom => self.align_view_bottom(window_size),
BufferAction::AlignViewTop => self.align_view_top(), 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); 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) { pub fn scroll_down(&mut self, window_size: WindowSize) {
if self.contents.len() <= BYTES_OF_PADDING { return; } 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(); self.primary_cursor.flip();
for cursor in &mut self.cursors { for cursor in &mut self.cursors {
cursor.flip(); cursor.flip();
} }
self.clamp_screen_to_primary_cursor(window_size);
} }
fn delete(&mut self, window_size: WindowSize) { fn delete(&mut self, window_size: WindowSize) {
@@ -651,6 +667,84 @@ impl Buffer {
.saturating_sub(self.primary_cursor.head % BYTES_PER_LINE) .saturating_sub(self.primary_cursor.head % BYTES_PER_LINE)
.saturating_sub(BYTES_OF_PADDING); .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 // helpers
@@ -682,3 +776,23 @@ fn mark_before(offset: usize, sorted_marks: &[usize]) -> usize {
Err(mark_after_index) => sorted_marks[mark_after_index - 1], 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)] #[derive(Clone, Copy, Hash, PartialEq, Eq)]
pub enum PartialAction { pub enum PartialAction {
Goto, View, Replace, Space, Repeat Goto, View, Replace, Space, Repeat, To
} }
impl Mode { impl Mode {
@@ -69,6 +69,7 @@ impl PartialAction {
Self::Replace => "r", Self::Replace => "r",
Self::Space => "", Self::Space => "",
Self::Repeat => "×", Self::Repeat => "×",
Self::To => "t",
} }
} }
} }
+12
View File
@@ -107,6 +107,7 @@ impl Default for Config {
("r".try_into().unwrap(), BufferAction::Replace.into()), ("r".try_into().unwrap(), BufferAction::Replace.into()),
(" ".try_into().unwrap(), BufferAction::Space.into()), (" ".try_into().unwrap(), BufferAction::Space.into()),
("*".try_into().unwrap(), BufferAction::Repeat.into()), ("*".try_into().unwrap(), BufferAction::Repeat.into()),
("t".try_into().unwrap(), BufferAction::To.into()),
("i".try_into().unwrap(), CursorAction::MoveByteUp.into()), ("i".try_into().unwrap(), CursorAction::MoveByteUp.into()),
("k".try_into().unwrap(), CursorAction::MoveByteDown.into()), ("k".try_into().unwrap(), CursorAction::MoveByteDown.into()),
@@ -207,6 +208,11 @@ impl Default for Config {
("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()),
].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()),
(Mode::Select, [ (Mode::Select, [
(None, [ (None, [
@@ -220,6 +226,7 @@ impl Default for Config {
("r".try_into().unwrap(), BufferAction::Replace.into()), ("r".try_into().unwrap(), BufferAction::Replace.into()),
(" ".try_into().unwrap(), BufferAction::Space.into()), (" ".try_into().unwrap(), BufferAction::Space.into()),
("*".try_into().unwrap(), BufferAction::Repeat.into()), ("*".try_into().unwrap(), BufferAction::Repeat.into()),
("t".try_into().unwrap(), BufferAction::To.into()),
("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()), ("i".try_into().unwrap(), CursorAction::ExtendByteUp.into()),
("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()), ("k".try_into().unwrap(), CursorAction::ExtendByteDown.into()),
@@ -309,6 +316,11 @@ impl Default for Config {
("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()), ("C".try_into().unwrap(), BufferAction::CopySelectionOnNextLine.into()),
].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())
].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; const BYTES_OF_PADDING: usize = LINES_OF_PADDING * BYTES_PER_LINE;
// TODO: // TODO:
// - extend to mark (tm?)
// - t0 can be to next null
// - tf can be to next FF
// - inspect selection // - inspect selection
// - resizing can move the cursor off the screen // - resizing can move the cursor off the screen
// - tab bar overflow // - tab bar overflow