Restructure git diff state management to allow viewing buffers with different diff bases (#21258)

This is a pure refactor of our Git diff state management. Buffers are no
longer are associated with one single diff (the unstaged changes).
Instead, there is an explicit project API for retrieving a buffer's
unstaged changes, and the `Editor` view layer is responsible for
choosing what diff to associate with a buffer.

The reason for this change is that we'll soon want to add multiple "git
diff views" to Zed, one of which will show the *uncommitted* changes for
a buffer. But that view will need to co-exist with other views of the
same buffer, which may want to show the unstaged changes.

### Todo

* [x] Get git gutter and git hunks working with new structure
* [x] Update editor tests to use new APIs
* [x] Update buffer tests
* [x] Restructure remoting/collab protocol
* [x] Update assertions about staged text in
`random_project_collaboration_tests`
* [x] Move buffer tests for git diff management to a new spot, using the
new APIs

Release Notes:

- N/A

---------

Co-authored-by: Richard <richard@zed.dev>
Co-authored-by: Cole <cole@zed.dev>
Co-authored-by: Conrad <conrad@zed.dev>
This commit is contained in:
Max Brunsfeld
2024-12-04 15:02:33 -08:00
committed by GitHub
co-authored by Richard Cole Conrad
parent 31796171de
commit a2115e7242
29 changed files with 1832 additions and 1651 deletions
+27 -38
View File
@@ -1169,7 +1169,7 @@ impl EditorElement {
let editor = self.editor.read(cx);
let is_singleton = editor.is_singleton(cx);
// Git
(is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs())
(is_singleton && scrollbar_settings.git_diff && !snapshot.diff_map.is_empty())
||
// Buffer Search Results
(is_singleton && scrollbar_settings.search_results && editor.has_background_highlights::<BufferSearchHighlights>())
@@ -1320,17 +1320,8 @@ impl EditorElement {
cx: &mut WindowContext,
) -> Vec<(DisplayDiffHunk, Option<Hitbox>)> {
let buffer_snapshot = &snapshot.buffer_snapshot;
let buffer_start_row = MultiBufferRow(
DisplayPoint::new(display_rows.start, 0)
.to_point(snapshot)
.row,
);
let buffer_end_row = MultiBufferRow(
DisplayPoint::new(display_rows.end, 0)
.to_point(snapshot)
.row,
);
let buffer_start = DisplayPoint::new(display_rows.start, 0).to_point(snapshot);
let buffer_end = DisplayPoint::new(display_rows.end, 0).to_point(snapshot);
let git_gutter_setting = ProjectSettings::get_global(cx)
.git
@@ -1338,7 +1329,7 @@ impl EditorElement {
.unwrap_or_default();
self.editor.update(cx, |editor, cx| {
let expanded_hunks = &editor.expanded_hunks.hunks;
let expanded_hunks = &editor.diff_map.hunks;
let expanded_hunks_start_ix = expanded_hunks
.binary_search_by(|hunk| {
hunk.hunk_range
@@ -1349,8 +1340,10 @@ impl EditorElement {
.unwrap_err();
let mut expanded_hunks = expanded_hunks[expanded_hunks_start_ix..].iter().peekable();
let display_hunks = buffer_snapshot
.git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
let mut display_hunks: Vec<(DisplayDiffHunk, Option<Hitbox>)> = editor
.diff_map
.snapshot
.diff_hunks_in_range(buffer_start..buffer_end, &buffer_snapshot)
.filter_map(|hunk| {
let display_hunk = diff_hunk_to_display(&hunk, snapshot);
@@ -1393,25 +1386,23 @@ impl EditorElement {
Some(display_hunk)
})
.dedup()
.map(|hunk| match git_gutter_setting {
GitGutterSetting::TrackedFiles => {
let hitbox = match hunk {
DisplayDiffHunk::Unfolded { .. } => {
let hunk_bounds = Self::diff_hunk_bounds(
snapshot,
line_height,
gutter_hitbox.bounds,
&hunk,
);
Some(cx.insert_hitbox(hunk_bounds, true))
}
DisplayDiffHunk::Folded { .. } => None,
};
(hunk, hitbox)
}
GitGutterSetting::Hide => (hunk, None),
})
.map(|hunk| (hunk, None))
.collect();
if let GitGutterSetting::TrackedFiles = git_gutter_setting {
for (hunk, hitbox) in &mut display_hunks {
if let DisplayDiffHunk::Unfolded { .. } = hunk {
let hunk_bounds = Self::diff_hunk_bounds(
snapshot,
line_height,
gutter_hitbox.bounds,
&hunk,
);
*hitbox = Some(cx.insert_hitbox(hunk_bounds, true));
};
}
}
display_hunks
})
}
@@ -3755,10 +3746,8 @@ impl EditorElement {
let mut marker_quads = Vec::new();
if scrollbar_settings.git_diff {
let marker_row_ranges = snapshot
.buffer_snapshot
.git_diff_hunks_in_range(
MultiBufferRow::MIN..MultiBufferRow::MAX,
)
.diff_map
.diff_hunks(&snapshot.buffer_snapshot)
.map(|hunk| {
let start_display_row =
MultiBufferPoint::new(hunk.row_range.start.0, 0)
@@ -5440,7 +5429,7 @@ impl Element for EditorElement {
let expanded_add_hunks_by_rows = self.editor.update(cx, |editor, _| {
editor
.expanded_hunks
.diff_map
.hunks(false)
.filter(|hunk| hunk.status == DiffHunkStatus::Added)
.map(|expanded_hunk| {