From d1e2bff16b603c49a0216fd3630444301389b2dc Mon Sep 17 00:00:00 2001 From: Sam Vente Date: Sun, 9 Jun 2024 16:46:36 +0200 Subject: [PATCH] implement selection update mechanism --- helix-term/src/commands.rs | 4 +- helix-term/src/commands/typed.rs | 121 ++++++++++++++++++------------- helix-view/src/lib.rs | 8 ++ 3 files changed, 82 insertions(+), 51 deletions(-) diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 788037c34..ba9403802 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -6125,8 +6125,8 @@ fn extend_to_word(cx: &mut Context) { jump_to_word(cx, Movement::Extend) } -fn read_from_register(editor: &Editor, reg: char) -> Option { - editor.registers.read(reg, &editor) +fn read_from_register(editor: &mut Editor, reg: char) -> Option { + editor.registers.read(reg, &*editor) } fn jump_to_label(cx: &mut Context, labels: Vec, behaviour: Movement) { diff --git a/helix-term/src/commands/typed.rs b/helix-term/src/commands/typed.rs index 333732953..667d6979e 100644 --- a/helix-term/src/commands/typed.rs +++ b/helix-term/src/commands/typed.rs @@ -467,14 +467,21 @@ fn register_mark( let ranges_str = ranges .iter() .map(|r| r.to_string()) - .collect::>() - .join(","); + .collect::>(); + + // we have to take because of cell + let history = doc.history.take(); + let current_history_point = history.current_revision(); + doc.history.replace(history); + let mut register_val = vec![ + format!("{}", doc.id()), + format!("{}", current_history_point), + ]; + register_val.extend(ranges_str); + cx.editor .registers - .write( - register_name, - vec![format!("{}:{}", doc.id(), ranges_str.to_string())], - ) + .write(register_name, register_val) .unwrap(); cx.editor @@ -482,6 +489,54 @@ fn register_mark( Ok(()) } +fn parse_mark_register_contents( + registers_vals: Option, +) -> Result<(DocumentId, usize, Selection), String> { + match registers_vals { + Some(rv) => { + let mut rv_iter = rv.into_iter(); + let doc_id_str = rv_iter.next().unwrap().into_owned(); + let doc_id: DocumentId = doc_id_str.try_into().unwrap(); + let history_rev_str = rv_iter.next().unwrap().into_owned(); + let history_rev: usize = history_rev_str.parse().unwrap(); + let mut ranges = rv_iter + .map(|tup| { + let s = tup.into_owned(); + let range_parser = seq!( + "(", + take_until(|c| c == ','), + ",", + take_until(|c| c == ')'), + ")" + ); + let (_, (_, anchor_str, _, head_str, _)) = range_parser.parse(&s).unwrap(); + let anchor: usize = ::from_str(anchor_str).unwrap().clone(); + let head: usize = ::from_str(head_str).unwrap(); + Range { + anchor, + head, + old_visual_position: None, + } + }) + // reverse the iterators so the first range will end up as the primary when we push them + .rev(); + 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); + } + Ok((doc_id, history_rev, selection)) + } + None => Err("Could not parse registry content".to_string()), // I can't figure out how to set status line here because of borrow issues :( + } +} + +fn get_revisions_to_apply(doc: &mut Document, history_rev: usize) -> Option { + let history = doc.history.take(); + let revisions_to_apply = history.changes_since(history_rev); + doc.history.replace(history); + revisions_to_apply +} fn goto_mark( cx: &mut compositor::Context, args: &[Cow], @@ -498,51 +553,19 @@ fn goto_mark( ) .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, history_rev, mut selection) = + parse_mark_register_contents(registers_vals).unwrap(); + cx.editor.switch(doc_id, Action::Replace); - 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 => (), + let (view, doc) = current!(cx.editor); + let revisions_to_apply = get_revisions_to_apply(doc, history_rev); + + selection = match revisions_to_apply { + Some(t) => selection.map(t.changes()), + None => selection, }; + + doc.set_selection(view.id, selection); Ok(()) } diff --git a/helix-view/src/lib.rs b/helix-view/src/lib.rs index a18da2517..cf5d000e3 100644 --- a/helix-view/src/lib.rs +++ b/helix-view/src/lib.rs @@ -38,6 +38,14 @@ impl TryFrom<&str> for DocumentId { Ok(Self(value.parse::()?)) } } + +impl TryFrom for DocumentId { + type Error = ParseIntError; + + fn try_from(value: String) -> Result { + Ok(Self(value.parse::()?)) + } +} impl std::fmt::Display for DocumentId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("{}", self.0))