editor: Save base buffers when applying changes from their branches (#19562)

This PR makes it so that when we apply changes within a branch
buffer—currently just the edits buffer—we save the underlying buffer.

This also fixes an issue where new files created via edits were not
properly flushed to disk.

Release Notes:

- N/A

---------

Co-authored-by: Max <max@zed.dev>
This commit is contained in:
Marshall Bowers 2024-10-22 14:10:11 -04:00 committed by GitHub
parent d8d84bf5d4
commit 5dbf68ddc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 67 additions and 30 deletions

View file

@ -6260,28 +6260,6 @@ impl Editor {
} }
} }
fn apply_selected_diff_hunks(&mut self, _: &ApplyDiffHunk, cx: &mut ViewContext<Self>) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let hunks = hunks_for_selections(&snapshot, &self.selections.disjoint_anchors());
let mut ranges_by_buffer = HashMap::default();
self.transact(cx, |editor, cx| {
for hunk in hunks {
if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
ranges_by_buffer
.entry(buffer.clone())
.or_insert_with(Vec::new)
.push(hunk.buffer_range.to_offset(buffer.read(cx)));
}
}
for (buffer, ranges) in ranges_by_buffer {
buffer.update(cx, |buffer, cx| {
buffer.merge_into_base(ranges, cx);
});
}
});
}
pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) { pub fn open_active_item_in_terminal(&mut self, _: &OpenInTerminal, cx: &mut ViewContext<Self>) {
if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| { if let Some(working_directory) = self.active_excerpt(cx).and_then(|(_, buffer, _)| {
let project_path = buffer.read(cx).project_path(cx)?; let project_path = buffer.read(cx).project_path(cx)?;

View file

@ -7,11 +7,13 @@ use multi_buffer::{
MultiBufferSnapshot, ToPoint, MultiBufferSnapshot, ToPoint,
}; };
use std::{ops::Range, sync::Arc}; use std::{ops::Range, sync::Arc};
use text::OffsetRangeExt;
use ui::{ use ui::{
prelude::*, ActiveTheme, ContextMenu, IconButtonShape, InteractiveElement, IntoElement, prelude::*, ActiveTheme, ContextMenu, IconButtonShape, InteractiveElement, IntoElement,
ParentElement, PopoverMenu, Styled, Tooltip, ViewContext, VisualContext, ParentElement, PopoverMenu, Styled, Tooltip, ViewContext, VisualContext,
}; };
use util::RangeExt; use util::RangeExt;
use workspace::Item;
use crate::{ use crate::{
editor_settings::CurrentLineHighlight, hunk_status, hunks_for_selections, ApplyDiffHunk, editor_settings::CurrentLineHighlight, hunk_status, hunks_for_selections, ApplyDiffHunk,
@ -327,7 +329,7 @@ impl Editor {
Some(()) Some(())
} }
fn apply_changes_in_range( fn apply_diff_hunks_in_range(
&mut self, &mut self,
range: Range<Anchor>, range: Range<Anchor>,
cx: &mut ViewContext<'_, Editor>, cx: &mut ViewContext<'_, Editor>,
@ -343,16 +345,54 @@ impl Editor {
branch_buffer.merge_into_base(vec![range], cx); branch_buffer.merge_into_base(vec![range], cx);
}); });
if let Some(project) = self.project.clone() {
self.save(true, project, cx).detach_and_log_err(cx);
}
None None
} }
pub(crate) fn apply_all_changes(&self, cx: &mut ViewContext<Self>) { pub(crate) fn apply_all_diff_hunks(&mut self, cx: &mut ViewContext<Self>) {
let buffers = self.buffer.read(cx).all_buffers(); let buffers = self.buffer.read(cx).all_buffers();
for branch_buffer in buffers { for branch_buffer in buffers {
branch_buffer.update(cx, |branch_buffer, cx| { branch_buffer.update(cx, |branch_buffer, cx| {
branch_buffer.merge_into_base(Vec::new(), cx); branch_buffer.merge_into_base(Vec::new(), cx);
}); });
} }
if let Some(project) = self.project.clone() {
self.save(true, project, cx).detach_and_log_err(cx);
}
}
pub(crate) fn apply_selected_diff_hunks(
&mut self,
_: &ApplyDiffHunk,
cx: &mut ViewContext<Self>,
) {
let snapshot = self.buffer.read(cx).snapshot(cx);
let hunks = hunks_for_selections(&snapshot, &self.selections.disjoint_anchors());
let mut ranges_by_buffer = HashMap::default();
self.transact(cx, |editor, cx| {
for hunk in hunks {
if let Some(buffer) = editor.buffer.read(cx).buffer(hunk.buffer_id) {
ranges_by_buffer
.entry(buffer.clone())
.or_insert_with(Vec::new)
.push(hunk.buffer_range.to_offset(buffer.read(cx)));
}
}
for (buffer, ranges) in ranges_by_buffer {
buffer.update(cx, |buffer, cx| {
buffer.merge_into_base(ranges, cx);
});
}
});
if let Some(project) = self.project.clone() {
self.save(true, project, cx).detach_and_log_err(cx);
}
} }
fn hunk_header_block( fn hunk_header_block(
@ -548,11 +588,12 @@ impl Editor {
let hunk = hunk.clone(); let hunk = hunk.clone();
move |_event, cx| { move |_event, cx| {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.apply_changes_in_range( editor
hunk.multi_buffer_range .apply_diff_hunks_in_range(
.clone(), hunk.multi_buffer_range
cx, .clone(),
); cx,
);
}); });
} }
}), }),

View file

@ -720,6 +720,10 @@ impl Item for Editor {
) -> Task<Result<()>> { ) -> Task<Result<()>> {
self.report_editor_event("save", None, cx); self.report_editor_event("save", None, cx);
let buffers = self.buffer().clone().read(cx).all_buffers(); let buffers = self.buffer().clone().read(cx).all_buffers();
let buffers = buffers
.into_iter()
.map(|handle| handle.read(cx).diff_base_buffer().unwrap_or(handle.clone()))
.collect::<HashSet<_>>();
cx.spawn(|this, mut cx| async move { cx.spawn(|this, mut cx| async move {
if format { if format {
this.update(&mut cx, |editor, cx| { this.update(&mut cx, |editor, cx| {

View file

@ -298,6 +298,20 @@ impl Item for ProposedChangesEditor {
Item::set_nav_history(editor, nav_history, cx) Item::set_nav_history(editor, nav_history, cx)
}); });
} }
fn can_save(&self, cx: &AppContext) -> bool {
self.editor.read(cx).can_save(cx)
}
fn save(
&mut self,
format: bool,
project: Model<Project>,
cx: &mut ViewContext<Self>,
) -> Task<gpui::Result<()>> {
self.editor
.update(cx, |editor, cx| Item::save(editor, format, project, cx))
}
} }
impl ProposedChangesEditorToolbar { impl ProposedChangesEditorToolbar {
@ -323,7 +337,7 @@ impl Render for ProposedChangesEditorToolbar {
if let Some(editor) = &editor { if let Some(editor) = &editor {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.editor.update(cx, |editor, cx| { editor.editor.update(cx, |editor, cx| {
editor.apply_all_changes(cx); editor.apply_all_diff_hunks(cx);
}) })
}); });
} }