diff --git a/src/command/cmd.rs b/src/command/cmd.rs index 61d3818..41d7c89 100644 --- a/src/command/cmd.rs +++ b/src/command/cmd.rs @@ -313,75 +313,32 @@ impl Cmd for MoveSelection { } } +/// Unified jump-to-edge: jump to first/last row or column. +/// `is_row` selects the axis; `end` selects first (false) or last (true). #[derive(Debug)] -pub struct JumpToFirstRow { - pub col: usize, +pub struct JumpToEdge { + pub cursor: CursorState, + pub is_row: bool, + pub end: bool, + pub cmd_name: &'static str, } -impl Cmd for JumpToFirstRow { +impl Cmd for JumpToEdge { fn name(&self) -> &'static str { - "jump-first-row" + self.cmd_name } fn execute(&self, _ctx: &CmdContext) -> Vec> { - vec![ - Box::new(effect::SetSelected(0, self.col)), - Box::new(effect::SetRowOffset(0)), - ] - } -} - -#[derive(Debug)] -pub struct JumpToLastRow { - pub col: usize, - pub row_count: usize, - pub row_offset: usize, -} -impl Cmd for JumpToLastRow { - fn name(&self) -> &'static str { - "jump-last-row" - } - fn execute(&self, _ctx: &CmdContext) -> Vec> { - let last = self.row_count.saturating_sub(1); - let mut effects: Vec> = vec![Box::new(effect::SetSelected(last, self.col))]; - if last >= self.row_offset + 20 { - effects.push(Box::new(effect::SetRowOffset(last.saturating_sub(19)))); - } - effects - } -} - -#[derive(Debug)] -pub struct JumpToFirstCol { - pub row: usize, -} -impl Cmd for JumpToFirstCol { - fn name(&self) -> &'static str { - "jump-first-col" - } - fn execute(&self, _ctx: &CmdContext) -> Vec> { - vec![ - Box::new(effect::SetSelected(self.row, 0)), - Box::new(effect::SetColOffset(0)), - ] - } -} - -#[derive(Debug)] -pub struct JumpToLastCol { - pub row: usize, - pub col_count: usize, - pub col_offset: usize, -} -impl Cmd for JumpToLastCol { - fn name(&self) -> &'static str { - "jump-last-col" - } - fn execute(&self, _ctx: &CmdContext) -> Vec> { - let last = self.col_count.saturating_sub(1); - let mut effects: Vec> = vec![Box::new(effect::SetSelected(self.row, last))]; - if last >= self.col_offset + 8 { - effects.push(Box::new(effect::SetColOffset(last.saturating_sub(7)))); - } - effects + let (nr, nc) = if self.is_row { + let r = if self.end { self.cursor.row_count.saturating_sub(1) } else { 0 }; + (r, self.cursor.col) + } else { + let c = if self.end { self.cursor.col_count.saturating_sub(1) } else { 0 }; + (self.cursor.row, c) + }; + viewport_effects( + nr, nc, + self.cursor.row_offset, self.cursor.col_offset, + self.cursor.visible_rows, self.cursor.visible_cols, + ) } } @@ -397,19 +354,14 @@ impl Cmd for ScrollRows { fn execute(&self, _ctx: &CmdContext) -> Vec> { let row_max = self.cursor.row_count.saturating_sub(1) as i32; let nr = (self.cursor.row as i32 + self.delta).clamp(0, row_max) as usize; - let mut effects: Vec> = - vec![Box::new(effect::SetSelected(nr, self.cursor.col))]; - let mut row_offset = self.cursor.row_offset; - if nr < row_offset { - row_offset = nr; - } - if nr >= row_offset + 20 { - row_offset = nr.saturating_sub(19); - } - if row_offset != self.cursor.row_offset { - effects.push(Box::new(effect::SetRowOffset(row_offset))); - } - effects + viewport_effects( + nr, + self.cursor.col, + self.cursor.row_offset, + self.cursor.col_offset, + self.cursor.visible_rows, + self.cursor.visible_cols, + ) } } @@ -2549,58 +2501,20 @@ pub fn default_registry() -> CmdRegistry { })) }, ); - r.register( - &JumpToFirstRow { col: 0 }, - |_| Ok(Box::new(JumpToFirstRow { col: 0 })), - |_, ctx| { - Ok(Box::new(JumpToFirstRow { - col: ctx.selected.1, - })) - }, - ); - r.register( - &JumpToLastRow { col: 0, row_count: 0, row_offset: 0 }, - |_| { - Ok(Box::new(JumpToLastRow { - col: 0, - row_count: 0, - row_offset: 0, - })) - }, - |_, ctx| { - Ok(Box::new(JumpToLastRow { - col: ctx.selected.1, - row_count: ctx.row_count, - row_offset: ctx.row_offset, - })) - }, - ); - r.register( - &JumpToFirstCol { row: 0 }, - |_| Ok(Box::new(JumpToFirstCol { row: 0 })), - |_, ctx| { - Ok(Box::new(JumpToFirstCol { - row: ctx.selected.0, - })) - }, - ); - r.register( - &JumpToLastCol { row: 0, col_count: 0, col_offset: 0 }, - |_| { - Ok(Box::new(JumpToLastCol { - row: 0, - col_count: 0, - col_offset: 0, - })) - }, - |_, ctx| { - Ok(Box::new(JumpToLastCol { - row: ctx.selected.0, - col_count: ctx.col_count, - col_offset: ctx.col_offset, - })) - }, - ); + // Jump-to-edge commands: first/last row/col + macro_rules! reg_jump { + ($r:expr, $is_row:expr, $end:expr, $name:expr) => { + $r.register( + &JumpToEdge { cursor: CursorState::default(), is_row: $is_row, end: $end, cmd_name: $name }, + |_| Ok(Box::new(JumpToEdge { cursor: CursorState::default(), is_row: $is_row, end: $end, cmd_name: $name })), + |_, ctx| Ok(Box::new(JumpToEdge { cursor: CursorState::from_ctx(ctx), is_row: $is_row, end: $end, cmd_name: $name })), + ); + }; + } + reg_jump!(r, true, false, "jump-first-row"); + reg_jump!(r, true, true, "jump-last-row"); + reg_jump!(r, false, false, "jump-first-col"); + reg_jump!(r, false, true, "jump-last-col"); r.register( &ScrollRows { delta: 0, cursor: CursorState::default() }, |args| {