From 5ce55232f73b1bea75810137edf036e8fb4665c6 Mon Sep 17 00:00:00 2001 From: darcy Date: Thu, 2 Jan 2025 19:04:08 +1100 Subject: [PATCH] feat: better api to move input cursor to bol/eol --- yazi-config/preset/keymap-default.toml | 44 +++++++------- yazi-core/src/input/commands/move_.rs | 79 ++++++++++++++++++++++---- 2 files changed, 91 insertions(+), 32 deletions(-) diff --git a/yazi-config/preset/keymap-default.toml b/yazi-config/preset/keymap-default.toml index 5f3a885c..906698ce 100644 --- a/yazi-config/preset/keymap-default.toml +++ b/yazi-config/preset/keymap-default.toml @@ -232,13 +232,13 @@ keymap = [ { on = "", run = "escape", desc = "Go back the normal mode, or cancel input" }, # Mode - { on = "i", run = "insert", desc = "Enter insert mode" }, - { on = "a", run = "insert --append", desc = "Enter append mode" }, - { on = "I", run = [ "move -999", "insert" ], desc = "Move to the BOL, and enter insert mode" }, - { on = "A", run = [ "move 999", "insert --append" ], desc = "Move to the EOL, and enter append mode" }, - { on = "v", run = "visual", desc = "Enter visual mode" }, - { on = "V", run = [ "move -999", "visual", "move 999" ], desc = "Enter visual mode and select all" }, - { on = "r", run = "replace", desc = "Replace a single character" }, + { on = "i", run = "insert", desc = "Enter insert mode" }, + { on = "a", run = "insert --append", desc = "Enter append mode" }, + { on = "I", run = [ "move first-char", "insert" ], desc = "Move to the BOL, and enter insert mode" }, + { on = "A", run = [ "move eol", "insert --append" ], desc = "Move to the EOL, and enter append mode" }, + { on = "v", run = "visual", desc = "Enter visual mode" }, + { on = "V", run = [ "move first-char", "visual", "move eol" ], desc = "Enter visual mode and select all" }, + { on = "r", run = "replace", desc = "Replace a single character" }, # Character-wise movement { on = "h", run = "move -1", desc = "Move back a character" }, @@ -256,12 +256,14 @@ keymap = [ { on = "", run = "forward --end-of-word", desc = "Move forward to the end of the current or next word" }, # Line-wise movement - { on = "0", run = "move -999", desc = "Move to the BOL" }, - { on = "$", run = "move 999", desc = "Move to the EOL" }, - { on = "", run = "move -999", desc = "Move to the BOL" }, - { on = "", run = "move 999", desc = "Move to the EOL" }, - { on = "", run = "move -999", desc = "Move to the BOL" }, - { on = "", run = "move 999", desc = "Move to the EOL" }, + { on = "0", run = "move bol", desc = "Move to the BOL" }, + { on = "_", run = "move first-char", desc = "Move to the first non-whitespace character" }, + { on = "^", run = "move first-char", desc = "Move to the first non-whitespace character" }, + { on = "$", run = "move eol", desc = "Move to the EOL" }, + { on = "", run = "move first-char", desc = "Move to the BOL" }, + { on = "", run = "move eol", desc = "Move to the EOL" }, + { on = "", run = "move first-char", desc = "Move to the BOL" }, + { on = "", run = "move eol", desc = "Move to the EOL" }, # Delete { on = "", run = "backspace", desc = "Delete the character before the cursor" }, @@ -276,14 +278,14 @@ keymap = [ { on = "", run = "kill forward", desc = "Kill forwards to the end of the current word" }, # Cut/Yank/Paste - { on = "d", run = "delete --cut", desc = "Cut the selected characters" }, - { on = "D", run = [ "delete --cut", "move 999" ], desc = "Cut until the EOL" }, - { on = "c", run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" }, - { on = "C", run = [ "delete --cut --insert", "move 999" ], desc = "Cut until the EOL, and enter insert mode" }, - { on = "x", run = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut the current character" }, - { on = "y", run = "yank", desc = "Copy the selected characters" }, - { on = "p", run = "paste", desc = "Paste the copied characters after the cursor" }, - { on = "P", run = "paste --before", desc = "Paste the copied characters before the cursor" }, + { on = "d", run = "delete --cut", desc = "Cut the selected characters" }, + { on = "D", run = [ "delete --cut", "move eol" ], desc = "Cut until the EOL" }, + { on = "c", run = "delete --cut --insert", desc = "Cut the selected characters, and enter insert mode" }, + { on = "C", run = [ "delete --cut --insert", "move eol" ], desc = "Cut until the EOL, and enter insert mode" }, + { on = "x", run = [ "delete --cut", "move 1 --in-operating" ], desc = "Cut the current character" }, + { on = "y", run = "yank", desc = "Copy the selected characters" }, + { on = "p", run = "paste", desc = "Paste the copied characters after the cursor" }, + { on = "P", run = "paste --before", desc = "Paste the copied characters before the cursor" }, # Undo/Redo { on = "u", run = "undo", desc = "Undo the last operation" }, diff --git a/yazi-core/src/input/commands/move_.rs b/yazi-core/src/input/commands/move_.rs index 66331936..6a6d883a 100644 --- a/yazi-core/src/input/commands/move_.rs +++ b/yazi-core/src/input/commands/move_.rs @@ -5,20 +5,56 @@ use yazi_shared::event::{CmdCow, Data}; use crate::input::{Input, op::InputOp, snap::InputSnap}; struct Opt { - step: isize, + step: Step, in_operating: bool, } +enum Step { + Offset(isize), + Bol, + Eol, + FirstChar, + LastChar, +} + +impl TryFrom<&Data> for Step { + type Error = (); + + fn try_from(d: &Data) -> Result { + if let Some(offset) = d.as_isize() { + return Ok(Step::Offset(offset)); + }; + if let Some(s) = d.as_str() { + if let Ok(offset) = s.parse() { + return Ok(Step::Offset(offset)); + }; + match s.as_ref() { + "bol" => return Ok(Step::Bol), + "eol" => return Ok(Step::Eol), + "first-char" => return Ok(Step::FirstChar), + "last-char" => return Ok(Step::LastChar), + _ => (), + } + } + Err(()) + } +} + impl From for Opt { fn from(c: CmdCow) -> Self { Self { - step: c.first().and_then(Data::as_isize).unwrap_or(0), + step: c.get(0).unwrap().try_into().unwrap(), in_operating: c.bool("in-operating"), } } } impl From for Opt { - fn from(step: isize) -> Self { Self { step, in_operating: false } } + fn from(step: isize) -> Self { + Self { + step: Step::Offset(step), + in_operating: false, + } + } } impl Input { @@ -29,14 +65,35 @@ impl Input { return; } - render!(self.handle_op( - if opt.step <= 0 { - snap.cursor.saturating_sub(opt.step.unsigned_abs()) - } else { - snap.count().min(snap.cursor + opt.step as usize) - }, - false, - )); + let position = match opt.step { + Step::Offset(offset) => + if offset <= 0 { + snap.cursor.saturating_sub(offset.unsigned_abs()) + } else { + snap.count().min(snap.cursor + offset as usize) + }, + Step::Bol => 0, + Step::Eol => snap.count(), + Step::FirstChar => snap + .value + .chars() + .enumerate() + .filter(|(_, ch)| !ch.is_whitespace()) + .map(|(i, _)| i) + .next() + .unwrap_or(0), + Step::LastChar => snap + .value + .chars() + .rev() + .enumerate() + .filter(|(_, ch)| !ch.is_whitespace()) + .map(|(i, _)| i) + .next() + .unwrap_or(0), + }; + + render!(self.handle_op(position, false)); let (limit, snap) = (self.limit(), self.snap_mut()); if snap.offset > snap.cursor {