Skip to content

Commit

Permalink
Apply transactions to all views on history changes
Browse files Browse the repository at this point in the history
This ensures that jumplist selections follow changes in documents, even
when there are multiple views (for example a split where both windows
edit the same document).
  • Loading branch information
the-mikedavis committed Nov 23, 2022
1 parent 6e423bb commit f650ce0
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 4 deletions.
18 changes: 18 additions & 0 deletions helix-core/src/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,24 @@ impl History {
self.current == 0
}

/// Returns the changes since the given revision composed into a transaction.
/// Returns None if there are no changes between the current and given revisions.
pub fn changes_since(&self, revision: usize) -> Option<Transaction> {
if self.at_root() || self.current >= revision {
return None;
}

let mut transaction = self.revisions[revision].transaction.clone();

// The bounds are checked in the if condition above:
// `revision + 1` is known to be `<= self.current`.
for revision in &self.revisions[revision + 1..self.current] {
transaction = transaction.compose(revision.transaction.clone());
}

Some(transaction)
}

/// Undo the last edit.
pub fn undo(&mut self) -> Option<&Transaction> {
if self.at_root() {
Expand Down
26 changes: 23 additions & 3 deletions helix-term/src/ui/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1337,7 +1337,9 @@ impl Component for EditorView {
cx.editor.status_msg = None;

let mode = cx.editor.mode();
let (view, _) = current!(cx.editor);
let (view, doc) = current!(cx.editor);
let original_doc_id = doc.id();
let original_doc_revision = doc.get_current_revision();
let focus = view.id;

if let Some(on_next_key) = self.on_next_key.take() {
Expand Down Expand Up @@ -1413,13 +1415,31 @@ impl Component for EditorView {
let view = view_mut!(cx.editor, focus);
let doc = doc_mut!(cx.editor, &view.doc);

view.ensure_cursor_in_view(doc, config.scrolloff);

// Store a history state if not in insert mode. This also takes care of
// committing changes when leaving insert mode.
if mode != Mode::Insert {
doc.append_changes_to_history(view.id);
}

// If the current document has been changed, apply the changes to all views.
// This ensures that selections in jumplists follow changes.
if doc.id() == original_doc_id
&& doc.get_current_revision() > original_doc_revision
{
if let Some(transaction) =
doc.history.get_mut().changes_since(original_doc_revision)
{
let doc = doc!(cx.editor, &original_doc_id);
for (view, _focused) in cx.editor.tree.views_mut() {
view.apply(&transaction, doc);
}
}
}

let view = view_mut!(cx.editor, focus);
let doc = doc_mut!(cx.editor, &view.doc);

view.ensure_cursor_in_view(doc, config.scrolloff);
}

EventResult::Consumed(callback)
Expand Down
2 changes: 1 addition & 1 deletion helix-view/src/macros.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ macro_rules! view {
#[macro_export]
macro_rules! doc {
($editor:expr, $id:expr) => {{
$editor.documents[$id]
&$editor.documents[$id]
}};
($editor:expr) => {{
$crate::current_ref!($editor).1
Expand Down

0 comments on commit f650ce0

Please sign in to comment.