diff --git a/helix-term/src/commands.rs b/helix-term/src/commands.rs index 16f7e601231fc..f224711473eb8 100644 --- a/helix-term/src/commands.rs +++ b/helix-term/src/commands.rs @@ -2346,7 +2346,7 @@ fn jumplist_picker(cx: &mut Context) { view.jumps .get() .iter() - .map(|(doc_id, selection)| new_meta(view, *doc_id, selection.clone())) + .map(|(doc_id, selection)| new_meta(view, *doc_id, selection.borrow().clone())) }) .collect(), (), @@ -2644,9 +2644,8 @@ fn try_restore_indent(doc: &mut Document, view_id: ViewId) { } // Store a jump on the jumplist. -fn push_jump(view: &mut View, doc: &Document) { - let jump = (doc.id(), doc.selection(view.id).clone()); - view.jumps.push(jump); +fn push_jump(view: &mut View, doc: &mut Document) { + view.jumps.push(doc, doc.selection(view.id).clone()); } fn goto_line(cx: &mut Context) { @@ -4048,7 +4047,7 @@ fn jump_forward(cx: &mut Context) { if let Some((id, selection)) = view.jumps.forward(count) { view.doc = *id; - let selection = selection.clone(); + let selection = selection.borrow().clone(); let (view, doc) = current!(cx.editor); // refetch doc doc.set_selection(view.id, selection); @@ -4062,7 +4061,7 @@ fn jump_backward(cx: &mut Context) { if let Some((id, selection)) = view.jumps.backward(view.id, doc, count) { view.doc = *id; - let selection = selection.clone(); + let selection = selection.borrow().clone(); let (view, doc) = current!(cx.editor); // refetch doc doc.set_selection(view.id, selection); diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 560e91558846f..64a32396dff5b 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -69,7 +69,6 @@ pub fn regex_prompt( fun: impl Fn(&mut View, &mut Document, Regex, PromptEvent) + 'static, ) { let (view, doc) = current!(cx.editor); - let doc_id = view.doc; let snapshot = doc.selection(view.id).clone(); let offset_snapshot = view.offset; let config = cx.editor.config(); @@ -109,8 +108,7 @@ pub fn regex_prompt( doc.set_selection(view.id, snapshot.clone()); if event == PromptEvent::Validate { - // Equivalent to push_jump to store selection just before jump - view.jumps.push((doc_id, snapshot.clone())); + view.jumps.push(doc, snapshot.clone()); } fun(view, doc, regex, event); diff --git a/helix-view/src/document.rs b/helix-view/src/document.rs index c96f222de8569..f2dc654ebc2bb 100644 --- a/helix-view/src/document.rs +++ b/helix-view/src/document.rs @@ -5,11 +5,12 @@ use helix_core::auto_pairs::AutoPairs; use helix_core::Range; use serde::de::{self, Deserialize, Deserializer}; use serde::Serialize; -use std::cell::Cell; +use std::cell::{Cell, RefCell}; use std::collections::HashMap; use std::fmt::Display; use std::future::Future; use std::path::{Path, PathBuf}; +use std::rc::Rc; use std::str::FromStr; use std::sync::Arc; @@ -86,6 +87,7 @@ pub struct Document { pub(crate) id: DocumentId, text: Rope, selections: HashMap, + jump_selections: Vec>>, path: Option, encoding: &'static encoding::Encoding, @@ -347,6 +349,7 @@ impl Document { encoding, text, selections: HashMap::default(), + jump_selections: vec![Rc::new(RefCell::new(Selection::point(0)))], indent_style: DEFAULT_INDENT, line_ending: DEFAULT_LINE_ENDING, mode: Mode::Normal, @@ -744,6 +747,14 @@ impl Document { } self.modified_since_accessed = true; + + for selection in &self.jump_selections { + let mut selection = selection.borrow_mut(); + *selection = selection + .clone() + .map(transaction.changes()) + .ensure_invariants(self.text.slice(..)); + } } if !transaction.changes().is_empty() { @@ -1075,6 +1086,10 @@ impl Document { None => global_config, } } + + pub fn push_jump_selection(&mut self, selection: Rc>) { + self.jump_selections.push(selection) + } } impl Default for Document { diff --git a/helix-view/src/editor.rs b/helix-view/src/editor.rs index 520a425c18ac7..70ac6336e5407 100644 --- a/helix-view/src/editor.rs +++ b/helix-view/src/editor.rs @@ -905,8 +905,7 @@ impl Editor { view.remove_document(&id); } } else { - let jump = (view.doc, doc.selection(view.id).clone()); - view.jumps.push(jump); + view.jumps.push(doc, doc.selection(view.id).clone()); // Set last accessed doc if it is a different document if doc.id != id { view.add_to_history(view.doc); diff --git a/helix-view/src/view.rs b/helix-view/src/view.rs index 3df533dfc6d9e..855e9a494c733 100644 --- a/helix-view/src/view.rs +++ b/helix-view/src/view.rs @@ -5,9 +5,9 @@ use crate::{ }; use helix_core::{pos_at_visual_coords, visual_coords_at_pos, Position, RopeSlice, Selection}; -use std::fmt; +use std::{cell::RefCell, fmt, rc::Rc}; -type Jump = (DocumentId, Selection); +type Jump = (DocumentId, Rc>); #[derive(Debug, Clone)] pub struct JumpList { @@ -23,7 +23,11 @@ impl JumpList { } } - pub fn push(&mut self, jump: Jump) { + pub fn push(&mut self, doc: &mut Document, selection: Selection) { + let selection = Rc::new(RefCell::new(selection)); + let jump = (doc.id, selection.clone()); + doc.push_jump_selection(selection); + self.jumps.truncate(self.current); // don't push duplicates if self.jumps.last() != Some(&jump) { @@ -45,8 +49,7 @@ impl JumpList { pub fn backward(&mut self, view_id: ViewId, doc: &mut Document, count: usize) -> Option<&Jump> { if let Some(current) = self.current.checked_sub(count) { if self.current == self.jumps.len() { - let jump = (doc.id(), doc.selection(view_id).clone()); - self.push(jump); + self.push(doc, doc.selection(view_id).clone()); } self.current = current; self.jumps.get(self.current) @@ -126,7 +129,7 @@ impl View { doc, offset: Position::new(0, 0), area: Rect::default(), // will get calculated upon inserting into tree - jumps: JumpList::new((doc, Selection::point(0))), // TODO: use actual sel + jumps: JumpList::new((doc, Rc::new(RefCell::new(Selection::point(0))))), docs_access_history: Vec::new(), last_modified_docs: [None, None], object_selections: Vec::new(),