tm/t0/tf
This commit is contained in:
+116
-2
@@ -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
@@ -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",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user