From 89b63a23cbc06f6052a88e7fcbfab2606ab790e2 Mon Sep 17 00:00:00 2001 From: Sam Vente Date: Sun, 9 Jun 2024 13:53:32 +0200 Subject: [PATCH] make mark commands typeable --- helix-term/src/commands.rs | 73 -------------------- helix-term/src/commands/typed.rs | 114 +++++++++++++++++++++++++++++++ helix-term/src/keymap/default.rs | 2 - 3 files changed, 114 insertions(+), 75 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 59162dc41..788037c34 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -570,8 +570,6 @@ impl MappableCommand { command_palette, "Open command palette", goto_word, "Jump to a two-character label", extend_to_word, "Extend to a two-character label", - register_mark, "Register a bookmark", - goto_mark, "Goto a bookmark", ); } @@ -6131,77 +6129,6 @@ fn read_from_register(editor: &Editor, reg: char) -> Option { editor.registers.read(reg, &editor) } -pub fn goto_mark(cx: &mut Context) { - let register_name = cx.register.unwrap_or('^').clone(); - let registers_vals = read_from_register(cx.editor, register_name); - let blurb = registers_vals - .unwrap() - .into_iter() - .next() - .map(|c| c.into_owned()); - match blurb { - Some(s) => { - let doc_id_parser = seq!(take_until(|c| c == ':'), ":"); - let range_parser = seq!( - "(", - take_until(|c| c == ','), - ",", - take_until(|c| c == ')'), - ")" - ); - let multiple_ranges_parser = sep(range_parser, ","); - let (tail, (doc_id_str, _)) = doc_id_parser.parse(&s).unwrap(); - let (tail, v) = multiple_ranges_parser.parse(tail).unwrap(); - let mut ranges = v - .iter() - .map(|tup| { - let (_, anchor_str, _, head_str, _) = tup; - let anchor: usize = ::from_str(anchor_str).unwrap(); - let head: usize = ::from_str(head_str).unwrap(); - Range { - anchor, - head, - old_visual_position: None, - } - }) - .rev(); - // reverse the iterators so the first range will end up as the primary when we push them - - let doc_id: DocumentId = doc_id_str.try_into().unwrap(); - cx.editor.switch(doc_id, Action::Replace); - let (view, doc) = current!(cx.editor); - let last_range = ranges.next().unwrap(); // there is always at least one range - let mut selection = Selection::from(last_range); - for r in ranges { - selection = selection.push(r); - } - doc.set_selection(view.id, selection); - } - None => (), - } -} - -fn register_mark(cx: &mut Context) { - let register_name = cx.register.unwrap_or('^').clone(); - let (view, doc) = current!(cx.editor); - let ranges = doc.selection(view.id).ranges(); - let ranges_str = ranges - .iter() - .map(|r| r.to_string()) - .collect::>() - .join(","); - cx.editor - .registers - .write( - register_name, - vec![format!("{}:{}", doc.id(), ranges_str.to_string())], - ) - .unwrap(); - - cx.editor - .set_status(format!("Saved selection bookmark to [{}]", register_name)); -} - fn jump_to_label(cx: &mut Context, labels: Vec, behaviour: Movement) { let doc = doc!(cx.editor); let alphabet = &cx.editor.config().jump_label_alphabet; diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 7ad0369fc..333732953 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -1,3 +1,4 @@ +use std::borrow::Borrow; use std::fmt::Write; use std::io::BufReader; use std::ops::Deref; @@ -446,6 +447,105 @@ fn new_file( Ok(()) } +fn register_mark( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + }; + let register_name: char = args + .first() + .map_or_else( + || cx.editor.selected_register, + |s| s.as_ref().chars().next(), + ) + .unwrap_or('^'); + let (view, doc) = current!(cx.editor); + let ranges = doc.selection(view.id).ranges(); + let ranges_str = ranges + .iter() + .map(|r| r.to_string()) + .collect::>() + .join(","); + cx.editor + .registers + .write( + register_name, + vec![format!("{}:{}", doc.id(), ranges_str.to_string())], + ) + .unwrap(); + + cx.editor + .set_status(format!("Saved selection bookmark to [{}]", register_name)); + Ok(()) +} + +fn goto_mark( + cx: &mut compositor::Context, + args: &[Cow], + event: PromptEvent, +) -> anyhow::Result<()> { + if event != PromptEvent::Validate { + return Ok(()); + }; + let register_name: char = args + .first() + .map_or_else( + || cx.editor.selected_register, + |s| s.as_ref().chars().next(), + ) + .unwrap_or('^'); + let registers_vals = read_from_register(cx.editor, register_name); + let blurb = registers_vals + .unwrap() + .into_iter() + .next() + .map(|c| c.into_owned()); + match blurb { + Some(s) => { + let doc_id_parser = seq!(take_until(|c| c == ':'), ":"); + let range_parser = seq!( + "(", + take_until(|c| c == ','), + ",", + take_until(|c| c == ')'), + ")" + ); + let multiple_ranges_parser = sep(range_parser, ","); + let (tail, (doc_id_str, _)) = doc_id_parser.parse(&s).unwrap(); + let (_tail, v) = multiple_ranges_parser.parse(tail).unwrap(); + let mut ranges = v + .iter() + .map(|tup| { + let (_, anchor_str, _, head_str, _) = tup; + let anchor: usize = ::from_str(anchor_str).unwrap(); + let head: usize = ::from_str(head_str).unwrap(); + Range { + anchor, + head, + old_visual_position: None, + } + }) + .rev(); + // reverse the iterators so the first range will end up as the primary when we push them + + let doc_id: DocumentId = doc_id_str.try_into().unwrap(); + cx.editor.switch(doc_id, Action::Replace); + let (view, doc) = current!(cx.editor); + let last_range = ranges.next().unwrap(); // there is always at least one range + let mut selection = Selection::from(last_range); + for r in ranges { + selection = selection.push(r); + } + doc.set_selection(view.id, selection); + } + None => (), + }; + Ok(()) +} + fn format( cx: &mut compositor::Context, _args: &[Cow], @@ -2633,6 +2733,20 @@ pub const TYPABLE_COMMAND_LIST: &[TypableCommand] = &[ fun: new_file, signature: CommandSignature::none(), }, + TypableCommand { + name: "goto_mark", + aliases: &[], + doc: "Go to the selection saved in a register. Register can be provided as argument or selected register else ^ will be used", + fun: goto_mark, + signature: CommandSignature::positional(&[completers::register]), + }, + TypableCommand { + name: "register_mark", + aliases: &[], + doc: "Save current selection into a register. Register can be provided as argument or selected register else ^ will be used", + fun: register_mark, + signature: CommandSignature::positional(&[completers::register]), + }, TypableCommand { name: "format", aliases: &["fmt"], diff --git a/helix-term/src/keymap/default.rs b/helix-term/src/keymap/default.rs index 615731d08..b14375224 100644 --- a/helix-term/src/keymap/default.rs +++ b/helix-term/src/keymap/default.rs @@ -333,8 +333,6 @@ pub fn default() -> HashMap { "C-a" => increment, "C-x" => decrement, // just for debugging I'll find something better later - "1" => register_mark, - "2" => goto_mark, }); let mut select = normal.clone();