Add the ability to propose changes to a set of buffers (#18170)
This PR introduces functionality for creating *branches* of buffers that can be used to preview and edit change sets that haven't yet been applied to the buffers themselves. Release Notes: - N/A --------- Co-authored-by: Marshall Bowers <elliott.codes@gmail.com> Co-authored-by: Marshall <marshall@zed.dev>
This commit is contained in:
co-authored by
Marshall Bowers
Marshall
parent
e309fbda2a
commit
743feb98bc
@@ -273,6 +273,7 @@ gpui::actions!(
|
||||
NextScreen,
|
||||
OpenExcerpts,
|
||||
OpenExcerptsSplit,
|
||||
OpenProposedChangesEditor,
|
||||
OpenFile,
|
||||
OpenPermalinkToLine,
|
||||
OpenUrl,
|
||||
|
||||
+64
-14
@@ -35,6 +35,7 @@ mod lsp_ext;
|
||||
mod mouse_context_menu;
|
||||
pub mod movement;
|
||||
mod persistence;
|
||||
mod proposed_changes_editor;
|
||||
mod rust_analyzer_ext;
|
||||
pub mod scroll;
|
||||
mod selections_collection;
|
||||
@@ -46,7 +47,7 @@ mod signature_help;
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test;
|
||||
|
||||
use ::git::diff::{DiffHunk, DiffHunkStatus};
|
||||
use ::git::diff::DiffHunkStatus;
|
||||
use ::git::{parse_git_remote_url, BuildPermalinkParams, GitHostingProviderRegistry};
|
||||
pub(crate) use actions::*;
|
||||
use aho_corasick::AhoCorasick;
|
||||
@@ -98,6 +99,7 @@ use language::{
|
||||
};
|
||||
use language::{point_to_lsp, BufferRow, CharClassifier, Runnable, RunnableRange};
|
||||
use linked_editing_ranges::refresh_linked_ranges;
|
||||
use proposed_changes_editor::{ProposedChangesBuffer, ProposedChangesEditor};
|
||||
use similar::{ChangeTag, TextDiff};
|
||||
use task::{ResolvedTask, TaskTemplate, TaskVariables};
|
||||
|
||||
@@ -113,7 +115,9 @@ pub use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, ExcerptId, ExcerptRange, MultiBuffer, MultiBufferSnapshot, ToOffset,
|
||||
ToPoint,
|
||||
};
|
||||
use multi_buffer::{ExpandExcerptDirection, MultiBufferPoint, MultiBufferRow, ToOffsetUtf16};
|
||||
use multi_buffer::{
|
||||
ExpandExcerptDirection, MultiBufferDiffHunk, MultiBufferPoint, MultiBufferRow, ToOffsetUtf16,
|
||||
};
|
||||
use ordered_float::OrderedFloat;
|
||||
use parking_lot::{Mutex, RwLock};
|
||||
use project::project_settings::{GitGutterSetting, ProjectSettings};
|
||||
@@ -6152,7 +6156,7 @@ impl Editor {
|
||||
pub fn prepare_revert_change(
|
||||
revert_changes: &mut HashMap<BufferId, Vec<(Range<text::Anchor>, Rope)>>,
|
||||
multi_buffer: &Model<MultiBuffer>,
|
||||
hunk: &DiffHunk<MultiBufferRow>,
|
||||
hunk: &MultiBufferDiffHunk,
|
||||
cx: &AppContext,
|
||||
) -> Option<()> {
|
||||
let buffer = multi_buffer.read(cx).buffer(hunk.buffer_id)?;
|
||||
@@ -9338,7 +9342,7 @@ impl Editor {
|
||||
snapshot: &DisplaySnapshot,
|
||||
initial_point: Point,
|
||||
is_wrapped: bool,
|
||||
hunks: impl Iterator<Item = DiffHunk<MultiBufferRow>>,
|
||||
hunks: impl Iterator<Item = MultiBufferDiffHunk>,
|
||||
cx: &mut ViewContext<Editor>,
|
||||
) -> bool {
|
||||
let display_point = initial_point.to_display_point(snapshot);
|
||||
@@ -11885,6 +11889,52 @@ impl Editor {
|
||||
self.searchable
|
||||
}
|
||||
|
||||
fn open_proposed_changes_editor(
|
||||
&mut self,
|
||||
_: &OpenProposedChangesEditor,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let Some(workspace) = self.workspace() else {
|
||||
cx.propagate();
|
||||
return;
|
||||
};
|
||||
|
||||
let buffer = self.buffer.read(cx);
|
||||
let mut new_selections_by_buffer = HashMap::default();
|
||||
for selection in self.selections.all::<usize>(cx) {
|
||||
for (buffer, mut range, _) in
|
||||
buffer.range_to_buffer_ranges(selection.start..selection.end, cx)
|
||||
{
|
||||
if selection.reversed {
|
||||
mem::swap(&mut range.start, &mut range.end);
|
||||
}
|
||||
let mut range = range.to_point(buffer.read(cx));
|
||||
range.start.column = 0;
|
||||
range.end.column = buffer.read(cx).line_len(range.end.row);
|
||||
new_selections_by_buffer
|
||||
.entry(buffer)
|
||||
.or_insert(Vec::new())
|
||||
.push(range)
|
||||
}
|
||||
}
|
||||
|
||||
let proposed_changes_buffers = new_selections_by_buffer
|
||||
.into_iter()
|
||||
.map(|(buffer, ranges)| ProposedChangesBuffer { buffer, ranges })
|
||||
.collect::<Vec<_>>();
|
||||
let proposed_changes_editor = cx.new_view(|cx| {
|
||||
ProposedChangesEditor::new(proposed_changes_buffers, self.project.clone(), cx)
|
||||
});
|
||||
|
||||
cx.window_context().defer(move |cx| {
|
||||
workspace.update(cx, |workspace, cx| {
|
||||
workspace.active_pane().update(cx, |pane, cx| {
|
||||
pane.add_item(Box::new(proposed_changes_editor), true, true, None, cx);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
fn open_excerpts_in_split(&mut self, _: &OpenExcerptsSplit, cx: &mut ViewContext<Self>) {
|
||||
self.open_excerpts_common(true, cx)
|
||||
}
|
||||
@@ -12399,7 +12449,7 @@ impl Editor {
|
||||
fn hunks_for_selections(
|
||||
multi_buffer_snapshot: &MultiBufferSnapshot,
|
||||
selections: &[Selection<Anchor>],
|
||||
) -> Vec<DiffHunk<MultiBufferRow>> {
|
||||
) -> Vec<MultiBufferDiffHunk> {
|
||||
let buffer_rows_for_selections = selections.iter().map(|selection| {
|
||||
let head = selection.head();
|
||||
let tail = selection.tail();
|
||||
@@ -12418,7 +12468,7 @@ fn hunks_for_selections(
|
||||
pub fn hunks_for_rows(
|
||||
rows: impl Iterator<Item = Range<MultiBufferRow>>,
|
||||
multi_buffer_snapshot: &MultiBufferSnapshot,
|
||||
) -> Vec<DiffHunk<MultiBufferRow>> {
|
||||
) -> Vec<MultiBufferDiffHunk> {
|
||||
let mut hunks = Vec::new();
|
||||
let mut processed_buffer_rows: HashMap<BufferId, HashSet<Range<text::Anchor>>> =
|
||||
HashMap::default();
|
||||
@@ -12430,14 +12480,14 @@ pub fn hunks_for_rows(
|
||||
// when the caret is just above or just below the deleted hunk.
|
||||
let allow_adjacent = hunk_status(&hunk) == DiffHunkStatus::Removed;
|
||||
let related_to_selection = if allow_adjacent {
|
||||
hunk.associated_range.overlaps(&query_rows)
|
||||
|| hunk.associated_range.start == query_rows.end
|
||||
|| hunk.associated_range.end == query_rows.start
|
||||
hunk.row_range.overlaps(&query_rows)
|
||||
|| hunk.row_range.start == query_rows.end
|
||||
|| hunk.row_range.end == query_rows.start
|
||||
} else {
|
||||
// `selected_multi_buffer_rows` are inclusive (e.g. [2..2] means 2nd row is selected)
|
||||
// `hunk.associated_range` is exclusive (e.g. [2..3] means 2nd row is selected)
|
||||
hunk.associated_range.overlaps(&selected_multi_buffer_rows)
|
||||
|| selected_multi_buffer_rows.end == hunk.associated_range.start
|
||||
// `hunk.row_range` is exclusive (e.g. [2..3] means 2nd row is selected)
|
||||
hunk.row_range.overlaps(&selected_multi_buffer_rows)
|
||||
|| selected_multi_buffer_rows.end == hunk.row_range.start
|
||||
};
|
||||
if related_to_selection {
|
||||
if !processed_buffer_rows
|
||||
@@ -13738,10 +13788,10 @@ impl RowRangeExt for Range<DisplayRow> {
|
||||
}
|
||||
}
|
||||
|
||||
fn hunk_status(hunk: &DiffHunk<MultiBufferRow>) -> DiffHunkStatus {
|
||||
fn hunk_status(hunk: &MultiBufferDiffHunk) -> DiffHunkStatus {
|
||||
if hunk.diff_base_byte_range.is_empty() {
|
||||
DiffHunkStatus::Added
|
||||
} else if hunk.associated_range.is_empty() {
|
||||
} else if hunk.row_range.is_empty() {
|
||||
DiffHunkStatus::Removed
|
||||
} else {
|
||||
DiffHunkStatus::Modified
|
||||
|
||||
@@ -346,6 +346,7 @@ impl EditorElement {
|
||||
register_action(view, cx, Editor::toggle_code_actions);
|
||||
register_action(view, cx, Editor::open_excerpts);
|
||||
register_action(view, cx, Editor::open_excerpts_in_split);
|
||||
register_action(view, cx, Editor::open_proposed_changes_editor);
|
||||
register_action(view, cx, Editor::toggle_soft_wrap);
|
||||
register_action(view, cx, Editor::toggle_tab_bar);
|
||||
register_action(view, cx, Editor::toggle_line_numbers);
|
||||
@@ -3710,11 +3711,11 @@ impl EditorElement {
|
||||
)
|
||||
.map(|hunk| {
|
||||
let start_display_row =
|
||||
MultiBufferPoint::new(hunk.associated_range.start.0, 0)
|
||||
MultiBufferPoint::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
let mut end_display_row =
|
||||
MultiBufferPoint::new(hunk.associated_range.end.0, 0)
|
||||
MultiBufferPoint::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
.row();
|
||||
if end_display_row != start_display_row {
|
||||
|
||||
+12
-12
@@ -2,9 +2,9 @@ pub mod blame;
|
||||
|
||||
use std::ops::Range;
|
||||
|
||||
use git::diff::{DiffHunk, DiffHunkStatus};
|
||||
use git::diff::DiffHunkStatus;
|
||||
use language::Point;
|
||||
use multi_buffer::{Anchor, MultiBufferRow};
|
||||
use multi_buffer::{Anchor, MultiBufferDiffHunk};
|
||||
|
||||
use crate::{
|
||||
display_map::{DisplaySnapshot, ToDisplayPoint},
|
||||
@@ -49,25 +49,25 @@ impl DisplayDiffHunk {
|
||||
}
|
||||
|
||||
pub fn diff_hunk_to_display(
|
||||
hunk: &DiffHunk<MultiBufferRow>,
|
||||
hunk: &MultiBufferDiffHunk,
|
||||
snapshot: &DisplaySnapshot,
|
||||
) -> DisplayDiffHunk {
|
||||
let hunk_start_point = Point::new(hunk.associated_range.start.0, 0);
|
||||
let hunk_start_point_sub = Point::new(hunk.associated_range.start.0.saturating_sub(1), 0);
|
||||
let hunk_start_point = Point::new(hunk.row_range.start.0, 0);
|
||||
let hunk_start_point_sub = Point::new(hunk.row_range.start.0.saturating_sub(1), 0);
|
||||
let hunk_end_point_sub = Point::new(
|
||||
hunk.associated_range
|
||||
hunk.row_range
|
||||
.end
|
||||
.0
|
||||
.saturating_sub(1)
|
||||
.max(hunk.associated_range.start.0),
|
||||
.max(hunk.row_range.start.0),
|
||||
0,
|
||||
);
|
||||
|
||||
let status = hunk_status(hunk);
|
||||
let is_removal = status == DiffHunkStatus::Removed;
|
||||
|
||||
let folds_start = Point::new(hunk.associated_range.start.0.saturating_sub(2), 0);
|
||||
let folds_end = Point::new(hunk.associated_range.end.0 + 2, 0);
|
||||
let folds_start = Point::new(hunk.row_range.start.0.saturating_sub(2), 0);
|
||||
let folds_end = Point::new(hunk.row_range.end.0 + 2, 0);
|
||||
let folds_range = folds_start..folds_end;
|
||||
|
||||
let containing_fold = snapshot.folds_in_range(folds_range).find(|fold| {
|
||||
@@ -87,7 +87,7 @@ pub fn diff_hunk_to_display(
|
||||
} else {
|
||||
let start = hunk_start_point.to_display_point(snapshot).row();
|
||||
|
||||
let hunk_end_row = hunk.associated_range.end.max(hunk.associated_range.start);
|
||||
let hunk_end_row = hunk.row_range.end.max(hunk.row_range.start);
|
||||
let hunk_end_point = Point::new(hunk_end_row.0, 0);
|
||||
|
||||
let multi_buffer_start = snapshot.buffer_snapshot.anchor_after(hunk_start_point);
|
||||
@@ -288,7 +288,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.git_diff_hunks_in_range(MultiBufferRow(0)..MultiBufferRow(12))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.associated_range))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.row_range))
|
||||
.collect::<Vec<_>>(),
|
||||
&expected,
|
||||
);
|
||||
@@ -296,7 +296,7 @@ mod tests {
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.git_diff_hunks_in_range_rev(MultiBufferRow(0)..MultiBufferRow(12))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.associated_range))
|
||||
.map(|hunk| (hunk_status(&hunk), hunk.row_range))
|
||||
.collect::<Vec<_>>(),
|
||||
expected
|
||||
.iter()
|
||||
|
||||
@@ -4,11 +4,12 @@ use std::{
|
||||
};
|
||||
|
||||
use collections::{hash_map, HashMap, HashSet};
|
||||
use git::diff::{DiffHunk, DiffHunkStatus};
|
||||
use git::diff::DiffHunkStatus;
|
||||
use gpui::{Action, AppContext, CursorStyle, Hsla, Model, MouseButton, Subscription, Task, View};
|
||||
use language::Buffer;
|
||||
use multi_buffer::{
|
||||
Anchor, AnchorRangeExt, ExcerptRange, MultiBuffer, MultiBufferRow, MultiBufferSnapshot, ToPoint,
|
||||
Anchor, AnchorRangeExt, ExcerptRange, MultiBuffer, MultiBufferDiffHunk, MultiBufferRow,
|
||||
MultiBufferSnapshot, ToPoint,
|
||||
};
|
||||
use settings::SettingsStore;
|
||||
use text::{BufferId, Point};
|
||||
@@ -190,9 +191,9 @@ impl Editor {
|
||||
.buffer_snapshot
|
||||
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
|
||||
.filter(|hunk| {
|
||||
let hunk_display_row_range = Point::new(hunk.associated_range.start.0, 0)
|
||||
let hunk_display_row_range = Point::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot)
|
||||
..Point::new(hunk.associated_range.end.0, 0)
|
||||
..Point::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(&snapshot.display_snapshot);
|
||||
let row_range_end =
|
||||
display_rows_with_expanded_hunks.get(&hunk_display_row_range.start.row());
|
||||
@@ -203,7 +204,7 @@ impl Editor {
|
||||
|
||||
fn toggle_hunks_expanded(
|
||||
&mut self,
|
||||
hunks_to_toggle: Vec<DiffHunk<MultiBufferRow>>,
|
||||
hunks_to_toggle: Vec<MultiBufferDiffHunk>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let previous_toggle_task = self.expanded_hunks.hunk_update_tasks.remove(&None);
|
||||
@@ -274,8 +275,8 @@ impl Editor {
|
||||
});
|
||||
for remaining_hunk in hunks_to_toggle {
|
||||
let remaining_hunk_point_range =
|
||||
Point::new(remaining_hunk.associated_range.start.0, 0)
|
||||
..Point::new(remaining_hunk.associated_range.end.0, 0);
|
||||
Point::new(remaining_hunk.row_range.start.0, 0)
|
||||
..Point::new(remaining_hunk.row_range.end.0, 0);
|
||||
hunks_to_expand.push(HoveredHunk {
|
||||
status: hunk_status(&remaining_hunk),
|
||||
multi_buffer_range: remaining_hunk_point_range
|
||||
@@ -705,7 +706,7 @@ impl Editor {
|
||||
fn to_diff_hunk(
|
||||
hovered_hunk: &HoveredHunk,
|
||||
multi_buffer_snapshot: &MultiBufferSnapshot,
|
||||
) -> Option<DiffHunk<MultiBufferRow>> {
|
||||
) -> Option<MultiBufferDiffHunk> {
|
||||
let buffer_id = hovered_hunk
|
||||
.multi_buffer_range
|
||||
.start
|
||||
@@ -716,9 +717,8 @@ fn to_diff_hunk(
|
||||
let point_range = hovered_hunk
|
||||
.multi_buffer_range
|
||||
.to_point(multi_buffer_snapshot);
|
||||
Some(DiffHunk {
|
||||
associated_range: MultiBufferRow(point_range.start.row)
|
||||
..MultiBufferRow(point_range.end.row),
|
||||
Some(MultiBufferDiffHunk {
|
||||
row_range: MultiBufferRow(point_range.start.row)..MultiBufferRow(point_range.end.row),
|
||||
buffer_id,
|
||||
buffer_range,
|
||||
diff_base_byte_range: hovered_hunk.diff_base_byte_range.clone(),
|
||||
@@ -868,7 +868,7 @@ fn editor_with_deleted_text(
|
||||
fn buffer_diff_hunk(
|
||||
buffer_snapshot: &MultiBufferSnapshot,
|
||||
row_range: Range<Point>,
|
||||
) -> Option<DiffHunk<MultiBufferRow>> {
|
||||
) -> Option<MultiBufferDiffHunk> {
|
||||
let mut hunks = buffer_snapshot.git_diff_hunks_in_range(
|
||||
MultiBufferRow(row_range.start.row)..MultiBufferRow(row_range.end.row),
|
||||
);
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
use crate::{Editor, EditorEvent};
|
||||
use collections::HashSet;
|
||||
use futures::{channel::mpsc, future::join_all};
|
||||
use gpui::{AppContext, EventEmitter, FocusableView, Model, Render, Subscription, Task, View};
|
||||
use language::{Buffer, BufferEvent, Capability};
|
||||
use multi_buffer::{ExcerptRange, MultiBuffer};
|
||||
use project::Project;
|
||||
use smol::stream::StreamExt;
|
||||
use std::{ops::Range, time::Duration};
|
||||
use text::ToOffset;
|
||||
use ui::prelude::*;
|
||||
use workspace::Item;
|
||||
|
||||
pub struct ProposedChangesEditor {
|
||||
editor: View<Editor>,
|
||||
_subscriptions: Vec<Subscription>,
|
||||
_recalculate_diffs_task: Task<Option<()>>,
|
||||
recalculate_diffs_tx: mpsc::UnboundedSender<Model<Buffer>>,
|
||||
}
|
||||
|
||||
pub struct ProposedChangesBuffer<T> {
|
||||
pub buffer: Model<Buffer>,
|
||||
pub ranges: Vec<Range<T>>,
|
||||
}
|
||||
|
||||
impl ProposedChangesEditor {
|
||||
pub fn new<T: ToOffset>(
|
||||
buffers: Vec<ProposedChangesBuffer<T>>,
|
||||
project: Option<Model<Project>>,
|
||||
cx: &mut ViewContext<Self>,
|
||||
) -> Self {
|
||||
let mut subscriptions = Vec::new();
|
||||
let multibuffer = cx.new_model(|_| MultiBuffer::new(Capability::ReadWrite));
|
||||
|
||||
for buffer in buffers {
|
||||
let branch_buffer = buffer.buffer.update(cx, |buffer, cx| buffer.branch(cx));
|
||||
subscriptions.push(cx.subscribe(&branch_buffer, Self::on_buffer_event));
|
||||
|
||||
multibuffer.update(cx, |multibuffer, cx| {
|
||||
multibuffer.push_excerpts(
|
||||
branch_buffer,
|
||||
buffer.ranges.into_iter().map(|range| ExcerptRange {
|
||||
context: range,
|
||||
primary: None,
|
||||
}),
|
||||
cx,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
let (recalculate_diffs_tx, mut recalculate_diffs_rx) = mpsc::unbounded();
|
||||
|
||||
Self {
|
||||
editor: cx
|
||||
.new_view(|cx| Editor::for_multibuffer(multibuffer.clone(), project, true, cx)),
|
||||
recalculate_diffs_tx,
|
||||
_recalculate_diffs_task: cx.spawn(|_, mut cx| async move {
|
||||
let mut buffers_to_diff = HashSet::default();
|
||||
while let Some(buffer) = recalculate_diffs_rx.next().await {
|
||||
buffers_to_diff.insert(buffer);
|
||||
|
||||
loop {
|
||||
cx.background_executor()
|
||||
.timer(Duration::from_millis(250))
|
||||
.await;
|
||||
let mut had_further_changes = false;
|
||||
while let Ok(next_buffer) = recalculate_diffs_rx.try_next() {
|
||||
buffers_to_diff.insert(next_buffer?);
|
||||
had_further_changes = true;
|
||||
}
|
||||
if !had_further_changes {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
join_all(buffers_to_diff.drain().filter_map(|buffer| {
|
||||
buffer
|
||||
.update(&mut cx, |buffer, cx| buffer.recalculate_diff(cx))
|
||||
.ok()?
|
||||
}))
|
||||
.await;
|
||||
}
|
||||
None
|
||||
}),
|
||||
_subscriptions: subscriptions,
|
||||
}
|
||||
}
|
||||
|
||||
fn on_buffer_event(
|
||||
&mut self,
|
||||
buffer: Model<Buffer>,
|
||||
event: &BufferEvent,
|
||||
_cx: &mut ViewContext<Self>,
|
||||
) {
|
||||
if let BufferEvent::Edited = event {
|
||||
self.recalculate_diffs_tx.unbounded_send(buffer).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Render for ProposedChangesEditor {
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
|
||||
self.editor.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl FocusableView for ProposedChangesEditor {
|
||||
fn focus_handle(&self, cx: &AppContext) -> gpui::FocusHandle {
|
||||
self.editor.focus_handle(cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl EventEmitter<EditorEvent> for ProposedChangesEditor {}
|
||||
|
||||
impl Item for ProposedChangesEditor {
|
||||
type Event = EditorEvent;
|
||||
|
||||
fn tab_icon(&self, _cx: &ui::WindowContext) -> Option<Icon> {
|
||||
Some(Icon::new(IconName::Pencil))
|
||||
}
|
||||
|
||||
fn tab_content_text(&self, _cx: &WindowContext) -> Option<SharedString> {
|
||||
Some("Proposed changes".into())
|
||||
}
|
||||
}
|
||||
@@ -108,16 +108,16 @@ pub fn editor_hunks(
|
||||
.buffer_snapshot
|
||||
.git_diff_hunks_in_range(MultiBufferRow::MIN..MultiBufferRow::MAX)
|
||||
.map(|hunk| {
|
||||
let display_range = Point::new(hunk.associated_range.start.0, 0)
|
||||
let display_range = Point::new(hunk.row_range.start.0, 0)
|
||||
.to_display_point(snapshot)
|
||||
.row()
|
||||
..Point::new(hunk.associated_range.end.0, 0)
|
||||
..Point::new(hunk.row_range.end.0, 0)
|
||||
.to_display_point(snapshot)
|
||||
.row();
|
||||
let (_, buffer, _) = editor
|
||||
.buffer()
|
||||
.read(cx)
|
||||
.excerpt_containing(Point::new(hunk.associated_range.start.0, 0), cx)
|
||||
.excerpt_containing(Point::new(hunk.row_range.start.0, 0), cx)
|
||||
.expect("no excerpt for expanded buffer's hunk start");
|
||||
let diff_base = buffer
|
||||
.read(cx)
|
||||
|
||||
Reference in New Issue
Block a user