editor: Restore selections to positions after last edit (#28527)

Closes #22692

Makes it so when undoing a format operation, the selections are set to
where they were at the last edit.

Release Notes:

- Made it so the cursor position is reset to where it was after the last
edit when undoing a format operation. This will only result in different
behavior when you make an edit, scroll away, initiate formatting (either
by saving or manually) and then undo the format.

---------

Co-authored-by: Zed AI <ai@zed.dev>
This commit is contained in:
Ben Kunkle 2025-04-10 14:33:49 -04:00 committed by GitHub
parent 26f4705198
commit fbbc23bec3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 117 additions and 4 deletions

View file

@ -14175,12 +14175,28 @@ impl Editor {
}
};
let transaction_id_prev = buffer.read_with(cx, |b, cx| b.last_transaction_id(cx));
let selections_prev = transaction_id_prev
.and_then(|transaction_id_prev| {
// default to selections as they were after the last edit, if we have them,
// instead of how they are now.
// This will make it so that editing, moving somewhere else, formatting, then undoing the format
// will take you back to where you made the last edit, instead of staying where you scrolled
self.selection_history
.transaction(transaction_id_prev)
.map(|t| t.0.clone())
})
.unwrap_or_else(|| {
log::info!("Failed to determine selections from before format. Falling back to selections when format was initiated");
self.selections.disjoint_anchors()
});
let mut timeout = cx.background_executor().timer(FORMAT_TIMEOUT).fuse();
let format = project.update(cx, |project, cx| {
project.format(buffers, target, true, trigger, cx)
});
cx.spawn_in(window, async move |_, cx| {
cx.spawn_in(window, async move |editor, cx| {
let transaction = futures::select_biased! {
transaction = format.log_err().fuse() => transaction,
() = timeout => {
@ -14200,6 +14216,19 @@ impl Editor {
})
.ok();
if let Some(transaction_id_now) =
buffer.read_with(cx, |b, cx| b.last_transaction_id(cx))?
{
let has_new_transaction = transaction_id_prev != Some(transaction_id_now);
if has_new_transaction {
_ = editor.update(cx, |editor, _| {
editor
.selection_history
.insert_transaction(transaction_id_now, selections_prev);
});
}
}
Ok(())
})
}