Add staged status information to diff hunks (#24475)

Release Notes:

- Render unstaged hunks in the project diff editor with a slashed
background

---------

Co-authored-by: maxbrunsfeld <max@zed.dev>
Co-authored-by: Max Brunsfeld <maxbrunsfeld@gmail.com>
This commit is contained in:
Cole Miller 2025-02-10 21:43:25 -05:00 committed by GitHub
parent a9de9e3cb4
commit 8f75fe25e5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
28 changed files with 1132 additions and 753 deletions

View file

@ -73,17 +73,16 @@ use code_context_menus::{
AvailableCodeAction, CodeActionContents, CodeActionsItem, CodeActionsMenu, CodeContextMenu,
CompletionsMenu, ContextMenuOrigin,
};
use diff::DiffHunkStatus;
use git::blame::GitBlame;
use gpui::{
div, impl_actions, linear_color_stop, linear_gradient, point, prelude::*, pulsating_between,
px, relative, size, Action, Animation, AnimationExt, AnyElement, App, AsyncWindowContext,
AvailableSpace, Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase, ElementId,
Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable, FontId,
FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers, MouseButton,
MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, SharedString, Size, Styled,
StyledText, Subscription, Task, TextRun, TextStyle, TextStyleRefinement, UTF16Selection,
UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
AvailableSpace, Background, Bounds, ClipboardEntry, ClipboardItem, Context, DispatchPhase,
ElementId, Entity, EntityInputHandler, EventEmitter, FocusHandle, FocusOutEvent, Focusable,
FontId, FontWeight, Global, HighlightStyle, Hsla, InteractiveText, KeyContext, Modifiers,
MouseButton, MouseDownEvent, PaintQuad, ParentElement, Pixels, Render, SharedString, Size,
Styled, StyledText, Subscription, Task, TextRun, TextStyle, TextStyleRefinement,
UTF16Selection, UnderlineStyle, UniformListScrollHandle, WeakEntity, WeakFocusHandle, Window,
};
use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState};
@ -722,6 +721,7 @@ pub struct Editor {
show_git_blame_gutter: bool,
show_git_blame_inline: bool,
show_git_blame_inline_delay_task: Option<Task<()>>,
distinguish_unstaged_diff_hunks: bool,
git_blame_inline_enabled: bool,
serialize_dirty_buffers: bool,
show_selection_menu: Option<bool>,
@ -1418,6 +1418,7 @@ impl Editor {
custom_context_menu: None,
show_git_blame_gutter: false,
show_git_blame_inline: false,
distinguish_unstaged_diff_hunks: false,
show_selection_menu: None,
show_git_blame_inline_delay_task: None,
git_blame_inline_enabled: ProjectSettings::get_global(cx).git.inline_blame_enabled(),
@ -6878,8 +6879,7 @@ impl Editor {
let buffer = buffer.read(cx);
let original_text = diff
.read(cx)
.snapshot
.base_text
.base_text()
.as_ref()?
.as_rope()
.slice(hunk.diff_base_byte_range.clone());
@ -12290,6 +12290,10 @@ impl Editor {
});
}
pub fn set_distinguish_unstaged_diff_hunks(&mut self) {
self.distinguish_unstaged_diff_hunks = true;
}
pub fn expand_all_diff_hunks(
&mut self,
_: &ExpandAllHunkDiffs,
@ -13332,14 +13336,14 @@ impl Editor {
&self,
window: &mut Window,
cx: &mut App,
) -> BTreeMap<DisplayRow, Hsla> {
) -> BTreeMap<DisplayRow, Background> {
let snapshot = self.snapshot(window, cx);
let mut used_highlight_orders = HashMap::default();
self.highlighted_rows
.iter()
.flat_map(|(_, highlighted_rows)| highlighted_rows.iter())
.fold(
BTreeMap::<DisplayRow, Hsla>::new(),
BTreeMap::<DisplayRow, Background>::new(),
|mut unique_rows, highlight| {
let start = highlight.range.start.to_display_point(&snapshot);
let end = highlight.range.end.to_display_point(&snapshot);
@ -13356,7 +13360,7 @@ impl Editor {
used_highlight_orders.entry(row).or_insert(highlight.index);
if highlight.index >= *used_index {
*used_index = highlight.index;
unique_rows.insert(DisplayRow(row), highlight.color);
unique_rows.insert(DisplayRow(row), highlight.color.into());
}
}
unique_rows
@ -15518,7 +15522,7 @@ impl EditorSnapshot {
) {
// Deleted hunk is an empty row range, no caret can be placed there and Zed allows to revert it
// when the caret is just above or just below the deleted hunk.
let allow_adjacent = hunk.status() == DiffHunkStatus::Removed;
let allow_adjacent = hunk.status().is_removed();
let related_to_selection = if allow_adjacent {
hunk.row_range.overlaps(&query_rows)
|| hunk.row_range.start == query_rows.end