Color staged and unstaged hunks differently by opacity (#25108)

Release Notes:

- Make staged diff hunks appear as more opaque than unstaged hunks

---------

Co-authored-by: Nate Butler <iamnbutler@gmail.com>
This commit is contained in:
Cole Miller 2025-02-19 13:33:21 -05:00 committed by GitHub
parent c9bd44f983
commit 8e17b34eff
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 265 additions and 175 deletions

View file

@ -105,6 +105,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@ -490,6 +493,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@ -875,6 +881,9 @@
"terminal.ansi.bright_white": "#fbf1c7ff",
"terminal.ansi.dim_white": "#b0a189ff",
"link_text.hover": "#83a598ff",
"version_control_added": "#b7bb26ff",
"version_control_modified": "#f9bd2fff",
"version_control_deleted": "#fb4a35ff",
"conflict": "#f9bd2fff",
"conflict.background": "#572e10ff",
"conflict.border": "#754916ff",
@ -1260,6 +1269,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@ -1645,6 +1657,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",
@ -2030,6 +2045,9 @@
"terminal.ansi.bright_white": "#282828ff",
"terminal.ansi.dim_white": "#73675eff",
"link_text.hover": "#0b6678ff",
"version_control_added": "#797410ff",
"version_control_modified": "#b57615ff",
"version_control_deleted": "#9d0308ff",
"conflict": "#b57615ff",
"conflict.background": "#f5e2d0ff",
"conflict.border": "#ebccabff",

View file

@ -96,6 +96,9 @@
"terminal.ansi.bright_white": "#dce0e5ff",
"terminal.ansi.dim_white": "#575d65ff",
"link_text.hover": "#74ade8ff",
"version_control_added": "#a7c088ff",
"version_control_modified": "#dec184ff",
"version_control_deleted": "#d07277ff",
"conflict": "#dec184ff",
"conflict.background": "#dec1841a",
"conflict.border": "#5d4c2fff",
@ -472,6 +475,9 @@
"terminal.ansi.bright_white": "#242529ff",
"terminal.ansi.dim_white": "#97979aff",
"link_text.hover": "#5c78e2ff",
"version_control_added": "#669f59ff",
"version_control_modified": "#a48819ff",
"version_control_deleted": "#d36151ff",
"conflict": "#a48819ff",
"conflict.background": "#faf2e6ff",
"conflict.border": "#f4e7d1ff",

View file

@ -29,10 +29,16 @@ struct BufferDiffInner {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DiffHunkStatus {
Added(DiffHunkSecondaryStatus),
Modified(DiffHunkSecondaryStatus),
Removed(DiffHunkSecondaryStatus),
pub struct DiffHunkStatus {
pub kind: DiffHunkStatusKind,
pub secondary: DiffHunkSecondaryStatus,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DiffHunkStatusKind {
Added,
Modified,
Deleted,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@ -42,6 +48,16 @@ pub enum DiffHunkSecondaryStatus {
None,
}
impl DiffHunkSecondaryStatus {
pub fn is_secondary(&self) -> bool {
match self {
DiffHunkSecondaryStatus::HasSecondaryHunk => true,
DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk => true,
DiffHunkSecondaryStatus::None => false,
}
}
}
/// A diff hunk resolved to rows in the buffer.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct DiffHunk {
@ -927,34 +943,76 @@ impl BufferDiff {
impl DiffHunk {
pub fn status(&self) -> DiffHunkStatus {
if self.buffer_range.start == self.buffer_range.end {
DiffHunkStatus::Removed(self.secondary_status)
let kind = if self.buffer_range.start == self.buffer_range.end {
DiffHunkStatusKind::Deleted
} else if self.diff_base_byte_range.is_empty() {
DiffHunkStatus::Added(self.secondary_status)
DiffHunkStatusKind::Added
} else {
DiffHunkStatus::Modified(self.secondary_status)
DiffHunkStatusKind::Modified
};
DiffHunkStatus {
kind,
secondary: self.secondary_status,
}
}
}
impl DiffHunkStatus {
pub fn is_removed(&self) -> bool {
matches!(self, DiffHunkStatus::Removed(_))
pub fn is_deleted(&self) -> bool {
self.kind == DiffHunkStatusKind::Deleted
}
pub fn is_added(&self) -> bool {
self.kind == DiffHunkStatusKind::Added
}
pub fn is_modified(&self) -> bool {
self.kind == DiffHunkStatusKind::Modified
}
pub fn added(secondary: DiffHunkSecondaryStatus) -> Self {
Self {
kind: DiffHunkStatusKind::Added,
secondary,
}
}
pub fn modified(secondary: DiffHunkSecondaryStatus) -> Self {
Self {
kind: DiffHunkStatusKind::Modified,
secondary,
}
}
pub fn deleted(secondary: DiffHunkSecondaryStatus) -> Self {
Self {
kind: DiffHunkStatusKind::Deleted,
secondary,
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn removed() -> Self {
DiffHunkStatus::Removed(DiffHunkSecondaryStatus::None)
pub fn deleted_none() -> Self {
Self {
kind: DiffHunkStatusKind::Deleted,
secondary: DiffHunkSecondaryStatus::None,
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn added() -> Self {
DiffHunkStatus::Added(DiffHunkSecondaryStatus::None)
pub fn added_none() -> Self {
Self {
kind: DiffHunkStatusKind::Added,
secondary: DiffHunkSecondaryStatus::None,
}
}
#[cfg(any(test, feature = "test-support"))]
pub fn modified() -> Self {
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::None)
pub fn modified_none() -> Self {
Self {
kind: DiffHunkStatusKind::Modified,
secondary: DiffHunkSecondaryStatus::None,
}
}
}
@ -1031,7 +1089,7 @@ mod tests {
diff.hunks_intersecting_range(Anchor::MIN..Anchor::MAX, &buffer, None),
&buffer,
&diff_base,
&[(1..2, "two\n", "HELLO\n", DiffHunkStatus::modified())],
&[(1..2, "two\n", "HELLO\n", DiffHunkStatus::modified_none())],
);
buffer.edit([(0..0, "point five\n")]);
@ -1041,8 +1099,8 @@ mod tests {
&buffer,
&diff_base,
&[
(0..1, "", "point five\n", DiffHunkStatus::added()),
(2..3, "two\n", "HELLO\n", DiffHunkStatus::modified()),
(0..1, "", "point five\n", DiffHunkStatus::added_none()),
(2..3, "two\n", "HELLO\n", DiffHunkStatus::modified_none()),
],
);
@ -1105,23 +1163,18 @@ mod tests {
let uncommitted_diff = BufferDiff::build_sync(buffer.clone(), head_text.clone(), cx);
let expected_hunks = vec![
(
2..3,
"two\n",
"TWO\n",
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::None),
),
(2..3, "two\n", "TWO\n", DiffHunkStatus::modified_none()),
(
4..6,
"four\nfive\n",
"FOUR\nFIVE\n",
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk),
DiffHunkStatus::modified(DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk),
),
(
7..8,
"seven\n",
"SEVEN\n",
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::HasSecondaryHunk),
DiffHunkStatus::modified(DiffHunkSecondaryStatus::HasSecondaryHunk),
),
];
@ -1197,9 +1250,9 @@ mod tests {
&buffer,
&diff_base,
&[
(6..7, "", "HELLO\n", DiffHunkStatus::added()),
(9..10, "six\n", "SIXTEEN\n", DiffHunkStatus::modified()),
(12..13, "", "WORLD\n", DiffHunkStatus::added()),
(6..7, "", "HELLO\n", DiffHunkStatus::added_none()),
(9..10, "six\n", "SIXTEEN\n", DiffHunkStatus::modified_none()),
(12..13, "", "WORLD\n", DiffHunkStatus::added_none()),
],
);
}

View file

@ -2618,7 +2618,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&diff.base_text_string().unwrap(),
&[(1..2, "", "two\n", DiffHunkStatus::added())],
&[(1..2, "", "two\n", DiffHunkStatus::added_none())],
);
});
@ -2646,7 +2646,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&diff.base_text_string().unwrap(),
&[(1..2, "", "two\n", DiffHunkStatus::added())],
&[(1..2, "", "two\n", DiffHunkStatus::added_none())],
);
});
@ -2672,7 +2672,7 @@ async fn test_git_diff_base_change(
1..2,
"TWO\n",
"two\n",
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::HasSecondaryHunk),
DiffHunkStatus::modified(DiffHunkSecondaryStatus::HasSecondaryHunk),
)],
);
});
@ -2699,7 +2699,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&diff.base_text_string().unwrap(),
&[(2..3, "", "three\n", DiffHunkStatus::added())],
&[(2..3, "", "three\n", DiffHunkStatus::added_none())],
);
});
@ -2713,7 +2713,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&diff.base_text_string().unwrap(),
&[(2..3, "", "three\n", DiffHunkStatus::added())],
&[(2..3, "", "three\n", DiffHunkStatus::added_none())],
);
});
@ -2731,7 +2731,7 @@ async fn test_git_diff_base_change(
1..2,
"TWO_HUNDRED\n",
"two\n",
DiffHunkStatus::Modified(DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk),
DiffHunkStatus::modified(DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk),
)],
);
});
@ -2778,7 +2778,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&diff.base_text_string().unwrap(),
&[(1..2, "", "two\n", DiffHunkStatus::added())],
&[(1..2, "", "two\n", DiffHunkStatus::added_none())],
);
});
@ -2805,7 +2805,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&staged_text,
&[(1..2, "", "two\n", DiffHunkStatus::added())],
&[(1..2, "", "two\n", DiffHunkStatus::added_none())],
);
});
@ -2827,7 +2827,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&new_staged_text,
&[(2..3, "", "three\n", DiffHunkStatus::added())],
&[(2..3, "", "three\n", DiffHunkStatus::added_none())],
);
});
@ -2841,7 +2841,7 @@ async fn test_git_diff_base_change(
diff.hunks_in_row_range(0..4, buffer, cx),
buffer,
&new_staged_text,
&[(2..3, "", "three\n", DiffHunkStatus::added())],
&[(2..3, "", "three\n", DiffHunkStatus::added_none())],
);
});
}

View file

@ -15956,7 +15956,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().is_removed();
let allow_adjacent = hunk.status().is_deleted();
let related_to_selection = if allow_adjacent {
hunk.row_range.overlaps(&query_rows)
|| hunk.row_range.start == query_rows.end

View file

@ -12258,7 +12258,7 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
struct Row9.2;
struct Row9.3;
struct Row10;"#},
vec![DiffHunkStatus::added(), DiffHunkStatus::added()],
vec![DiffHunkStatus::added_none(), DiffHunkStatus::added_none()],
indoc! {r#"struct Row;
struct Row1;
struct Row1.1;
@ -12296,7 +12296,7 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
struct Row8;
struct Row9;
struct Row10;"#},
vec![DiffHunkStatus::added(), DiffHunkStatus::added()],
vec![DiffHunkStatus::added_none(), DiffHunkStatus::added_none()],
indoc! {r#"struct Row;
struct Row1;
struct Row2;
@ -12343,11 +12343,11 @@ async fn test_addition_reverts(cx: &mut gpui::TestAppContext) {
«ˇ// something on bottom»
struct Row10;"#},
vec![
DiffHunkStatus::added(),
DiffHunkStatus::added(),
DiffHunkStatus::added(),
DiffHunkStatus::added(),
DiffHunkStatus::added(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
DiffHunkStatus::added_none(),
],
indoc! {r#"struct Row;
ˇstruct Row1;
@ -12395,7 +12395,10 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
struct Row99;
struct Row9;
struct Row10;"#},
vec![DiffHunkStatus::modified(), DiffHunkStatus::modified()],
vec![
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
],
indoc! {r#"struct Row;
struct Row1;
struct Row33;
@ -12422,7 +12425,10 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
struct Row99;
struct Row9;
struct Row10;"#},
vec![DiffHunkStatus::modified(), DiffHunkStatus::modified()],
vec![
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
],
indoc! {r#"struct Row;
struct Row1;
struct Row33;
@ -12451,12 +12457,12 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
struct Row9;
struct Row1011;ˇ"#},
vec![
DiffHunkStatus::modified(),
DiffHunkStatus::modified(),
DiffHunkStatus::modified(),
DiffHunkStatus::modified(),
DiffHunkStatus::modified(),
DiffHunkStatus::modified(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
DiffHunkStatus::modified_none(),
],
indoc! {r#"struct Row;
ˇstruct Row1;
@ -12534,7 +12540,10 @@ struct Row10;"#};
ˇ
struct Row8;
struct Row10;"#},
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
indoc! {r#"struct Row;
struct Row2;
@ -12557,7 +12566,10 @@ struct Row10;"#};
ˇ»
struct Row8;
struct Row10;"#},
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
indoc! {r#"struct Row;
struct Row2;
@ -12582,7 +12594,10 @@ struct Row10;"#};
struct Row8;ˇ
struct Row10;"#},
vec![DiffHunkStatus::removed(), DiffHunkStatus::removed()],
vec![
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
indoc! {r#"struct Row;
struct Row1;
ˇstruct Row2;
@ -12607,9 +12622,9 @@ struct Row10;"#};
struct Row8;ˇ»
struct Row10;"#},
vec![
DiffHunkStatus::removed(),
DiffHunkStatus::removed(),
DiffHunkStatus::removed(),
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
DiffHunkStatus::deleted_none(),
],
indoc! {r#"struct Row;
struct Row1;

View file

@ -25,20 +25,20 @@ use crate::{
CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN,
MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,
};
use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus};
use buffer_diff::{DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind};
use client::ParticipantIndex;
use collections::{BTreeMap, HashMap, HashSet};
use file_icons::FileIcons;
use git::{blame::BlameEntry, Oid};
use gpui::{
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, pattern_slash,
point, px, quad, relative, size, svg, transparent_black, Action, AnyElement, App,
AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners,
CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable as _,
FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size,
StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement, Window,
anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, point, px, quad,
relative, size, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds,
ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase,
Edges, Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox,
Hsla, InteractiveElement, IntoElement, Keystroke, Length, ModifiersChangedEvent, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta,
ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
Subscription, TextRun, TextStyleRefinement, Window,
};
use itertools::Itertools;
use language::{
@ -74,7 +74,7 @@ use ui::{
POPOVER_Y_PADDING,
};
use unicode_segmentation::UnicodeSegmentation;
use util::{RangeExt, ResultExt};
use util::{debug_panic, RangeExt, ResultExt};
use workspace::{item::Item, notifications::NotifyTaskExt};
const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;
@ -2124,7 +2124,10 @@ impl EditorElement {
.get(&display_row)
.unwrap_or(&non_relative_number);
write!(&mut line_number, "{number}").unwrap();
if matches!(row_info.diff_status, Some(DiffHunkStatus::Removed(_))) {
if row_info
.diff_status
.is_some_and(|status| status.is_deleted())
{
return None;
}
@ -4174,10 +4177,10 @@ impl EditorElement {
if row_infos[row_ix].diff_status.is_none() {
continue;
}
if matches!(
row_infos[row_ix].diff_status,
Some(DiffHunkStatus::Added(_))
) && !matches!(*status, DiffHunkStatus::Added(_))
if row_infos[row_ix]
.diff_status
.is_some_and(|status| status.is_added())
&& !status.is_added()
{
continue;
}
@ -4571,39 +4574,35 @@ impl EditorElement {
);
Some((
hunk_bounds,
cx.theme().status().modified,
cx.theme().colors().version_control_modified,
Corners::all(px(0.)),
&DiffHunkSecondaryStatus::None,
DiffHunkSecondaryStatus::None,
))
}
DisplayDiffHunk::Unfolded {
status,
display_row_range,
..
} => hitbox.as_ref().map(|hunk_hitbox| match status {
DiffHunkStatus::Added(secondary_status) => (
} => hitbox.as_ref().map(|hunk_hitbox| match status.kind {
DiffHunkStatusKind::Added => (
hunk_hitbox.bounds,
cx.theme().status().created,
cx.theme().colors().version_control_added,
Corners::all(px(0.)),
secondary_status,
status.secondary,
),
DiffHunkStatus::Modified(secondary_status) => (
DiffHunkStatusKind::Modified => (
hunk_hitbox.bounds,
cx.theme().status().modified,
cx.theme().colors().version_control_modified,
Corners::all(px(0.)),
secondary_status,
status.secondary,
),
DiffHunkStatus::Removed(secondary_status)
if !display_row_range.is_empty() =>
{
(
hunk_hitbox.bounds,
cx.theme().status().deleted,
Corners::all(px(0.)),
secondary_status,
)
}
DiffHunkStatus::Removed(secondary_status) => (
DiffHunkStatusKind::Deleted if !display_row_range.is_empty() => (
hunk_hitbox.bounds,
cx.theme().colors().version_control_deleted,
Corners::all(px(0.)),
status.secondary,
),
DiffHunkStatusKind::Deleted => (
Bounds::new(
point(
hunk_hitbox.origin.x - hunk_hitbox.size.width,
@ -4611,19 +4610,21 @@ impl EditorElement {
),
size(hunk_hitbox.size.width * px(2.), hunk_hitbox.size.height),
),
cx.theme().status().deleted,
cx.theme().colors().version_control_deleted,
Corners::all(1. * line_height),
secondary_status,
status.secondary,
),
}),
};
if let Some((hunk_bounds, mut background_color, corner_radii, secondary_status)) =
if let Some((hunk_bounds, background_color, corner_radii, secondary_status)) =
hunk_to_paint
{
if *secondary_status != DiffHunkSecondaryStatus::None {
background_color.a *= 0.6;
}
let background_color = if secondary_status != DiffHunkSecondaryStatus::None {
background_color.opacity(0.3)
} else {
background_color.opacity(1.0)
};
window.paint_quad(quad(
hunk_bounds,
corner_radii,
@ -4659,7 +4660,7 @@ impl EditorElement {
status,
..
} => {
if status.is_removed() && display_row_range.is_empty() {
if status.is_deleted() && display_row_range.is_empty() {
let row = display_row_range.start;
let offset = line_height / 2.;
@ -5312,10 +5313,10 @@ impl EditorElement {
if end_display_row != start_display_row {
end_display_row.0 -= 1;
}
let color = match &hunk.status() {
DiffHunkStatus::Added(_) => theme.status().created,
DiffHunkStatus::Modified(_) => theme.status().modified,
DiffHunkStatus::Removed(_) => theme.status().deleted,
let color = match &hunk.status().kind {
DiffHunkStatusKind::Added => theme.status().created,
DiffHunkStatusKind::Modified => theme.status().modified,
DiffHunkStatusKind::Deleted => theme.status().deleted,
};
ColoredRange {
start: start_display_row,
@ -6896,46 +6897,38 @@ impl Element for EditorElement {
)
};
let (mut highlighted_rows, distinguish_unstaged_hunks) =
self.editor.update(cx, |editor, cx| {
(
editor.highlighted_display_rows(window, cx),
editor.distinguish_unstaged_diff_hunks,
)
});
let mut highlighted_rows = self
.editor
.update(cx, |editor, cx| editor.highlighted_display_rows(window, cx));
for (ix, row_info) in row_infos.iter().enumerate() {
let background = match row_info.diff_status {
Some(DiffHunkStatus::Added(secondary_status)) => {
let color = style.status.created_background;
match secondary_status {
DiffHunkSecondaryStatus::HasSecondaryHunk
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
if distinguish_unstaged_hunks =>
{
pattern_slash(color, line_height.0 / 4.0)
}
_ => color.into(),
}
}
Some(DiffHunkStatus::Removed(secondary_status)) => {
let color = style.status.deleted_background;
match secondary_status {
DiffHunkSecondaryStatus::HasSecondaryHunk
| DiffHunkSecondaryStatus::OverlapsWithSecondaryHunk
if distinguish_unstaged_hunks =>
{
pattern_slash(color, line_height.0 / 4.0)
}
_ => color.into(),
}
}
_ => continue,
let Some(diff_status) = row_info.diff_status else {
continue;
};
let staged_opacity = 0.10;
let unstaged_opacity = 0.04;
let background_color = match diff_status.kind {
DiffHunkStatusKind::Added => cx.theme().colors().version_control_added,
DiffHunkStatusKind::Deleted => {
cx.theme().colors().version_control_deleted
}
DiffHunkStatusKind::Modified => {
debug_panic!("modified diff status for row info");
continue;
}
};
let background_color =
if diff_status.secondary == DiffHunkSecondaryStatus::None {
background_color.opacity(staged_opacity)
} else {
background_color.opacity(unstaged_opacity)
};
highlighted_rows
.entry(start_row + DisplayRow(ix as u32))
.or_insert(background);
.or_insert(background_color.into());
}
let highlighted_ranges = self.editor.read(cx).background_highlights_in_range(

View file

@ -2,7 +2,7 @@ use crate::{
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
RowExt,
};
use buffer_diff::DiffHunkStatus;
use buffer_diff::DiffHunkStatusKind;
use collections::BTreeMap;
use futures::Future;
@ -470,10 +470,10 @@ pub fn assert_state_with_diff(
.split('\n')
.zip(line_infos)
.map(|(line, info)| {
let mut marker = match info.diff_status {
Some(DiffHunkStatus::Added(_)) => "+ ",
Some(DiffHunkStatus::Removed(_)) => "- ",
Some(DiffHunkStatus::Modified(_)) => unreachable!(),
let mut marker = match info.diff_status.map(|status| status.kind) {
Some(DiffHunkStatusKind::Added) => "+ ",
Some(DiffHunkStatusKind::Deleted) => "- ",
Some(DiffHunkStatusKind::Modified) => unreachable!(),
None => {
if has_diff {
" "

View file

@ -9,6 +9,7 @@ pub use position::{TypedOffset, TypedPoint, TypedRow};
use anyhow::{anyhow, Result};
use buffer_diff::{
BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffHunkSecondaryStatus, DiffHunkStatus,
DiffHunkStatusKind,
};
use clock::ReplicaId;
use collections::{BTreeMap, Bound, HashMap, HashSet};
@ -135,12 +136,16 @@ pub struct MultiBufferDiffHunk {
impl MultiBufferDiffHunk {
pub fn status(&self) -> DiffHunkStatus {
if self.buffer_range.start == self.buffer_range.end {
DiffHunkStatus::Removed(self.secondary_status)
let kind = if self.buffer_range.start == self.buffer_range.end {
DiffHunkStatusKind::Deleted
} else if self.diff_base_byte_range.is_empty() {
DiffHunkStatus::Added(self.secondary_status)
DiffHunkStatusKind::Added
} else {
DiffHunkStatus::Modified(self.secondary_status)
DiffHunkStatusKind::Modified
};
DiffHunkStatus {
kind,
secondary: self.secondary_status,
}
}
}
@ -6210,7 +6215,7 @@ where
excerpt,
has_trailing_newline: *has_trailing_newline,
is_main_buffer: false,
diff_hunk_status: Some(DiffHunkStatus::Removed(
diff_hunk_status: Some(DiffHunkStatus::deleted(
hunk_info.hunk_secondary_status,
)),
buffer_range: buffer_start..buffer_end,
@ -6256,7 +6261,7 @@ where
has_trailing_newline,
is_main_buffer: true,
diff_hunk_status: inserted_hunk_info
.map(|info| DiffHunkStatus::Added(info.hunk_secondary_status)),
.map(|info| DiffHunkStatus::added(info.hunk_secondary_status)),
buffer_range: buffer_start..buffer_end,
range: start..end,
})

View file

@ -1,5 +1,5 @@
use super::*;
use buffer_diff::DiffHunkStatus;
use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};
use gpui::{App, TestAppContext};
use indoc::indoc;
use language::{Buffer, Rope};
@ -1325,13 +1325,13 @@ fn test_basic_diff_hunks(cx: &mut TestAppContext) {
.map(|info| (info.buffer_row, info.diff_status))
.collect::<Vec<_>>(),
vec![
(Some(0), Some(DiffHunkStatus::added())),
(Some(0), Some(DiffHunkStatus::added_none())),
(Some(1), None),
(Some(1), Some(DiffHunkStatus::removed())),
(Some(2), Some(DiffHunkStatus::added())),
(Some(1), Some(DiffHunkStatus::deleted_none())),
(Some(2), Some(DiffHunkStatus::added_none())),
(Some(3), None),
(Some(3), Some(DiffHunkStatus::removed())),
(Some(4), Some(DiffHunkStatus::removed())),
(Some(3), Some(DiffHunkStatus::deleted_none())),
(Some(4), Some(DiffHunkStatus::deleted_none())),
(Some(4), None),
(Some(5), None)
]
@ -2279,7 +2279,7 @@ impl ReferenceMultibuffer {
buffer_start: Some(
base_buffer.offset_to_point(hunk.diff_base_byte_range.start),
),
status: Some(DiffHunkStatus::Removed(hunk.secondary_status)),
status: Some(DiffHunkStatus::deleted(hunk.secondary_status)),
});
}
@ -2294,7 +2294,7 @@ impl ReferenceMultibuffer {
buffer_id: Some(buffer.remote_id()),
range: len..text.len(),
buffer_start: Some(buffer.offset_to_point(offset)),
status: Some(DiffHunkStatus::Added(hunk.secondary_status)),
status: Some(DiffHunkStatus::added(hunk.secondary_status)),
});
offset = hunk_range.end;
}
@ -2664,13 +2664,13 @@ async fn test_random_multibuffer(cx: &mut TestAppContext, mut rng: StdRng) {
snapshot.widest_line_number(),
expected_row_infos
.into_iter()
.filter_map(
|info| if matches!(info.diff_status, Some(DiffHunkStatus::Removed(_))) {
.filter_map(|info| {
if info.diff_status.is_some_and(|status| status.is_deleted()) {
None
} else {
info.buffer_row
}
)
})
.max()
.unwrap()
+ 1
@ -3021,10 +3021,10 @@ fn format_diff(
.enumerate()
.zip(row_infos)
.map(|((ix, line), info)| {
let marker = match info.diff_status {
Some(DiffHunkStatus::Added(_)) => "+ ",
Some(DiffHunkStatus::Removed(_)) => "- ",
Some(DiffHunkStatus::Modified(_)) => unreachable!(),
let marker = match info.diff_status.map(|status| status.kind) {
Some(DiffHunkStatusKind::Added) => "+ ",
Some(DiffHunkStatusKind::Deleted) => "- ",
Some(DiffHunkStatusKind::Modified) => unreachable!(),
None => {
if has_diff && !line.is_empty() {
" "

View file

@ -5693,12 +5693,12 @@ async fn test_unstaged_diff_for_buffer(cx: &mut gpui::TestAppContext) {
&snapshot,
&unstaged_diff.base_text_string().unwrap(),
&[
(0..1, "", "// print goodbye\n", DiffHunkStatus::added()),
(0..1, "", "// print goodbye\n", DiffHunkStatus::added_none()),
(
2..3,
" println!(\"hello world\");\n",
" println!(\"goodbye world\");\n",
DiffHunkStatus::modified(),
DiffHunkStatus::modified_none(),
),
],
);
@ -5727,7 +5727,7 @@ async fn test_unstaged_diff_for_buffer(cx: &mut gpui::TestAppContext) {
2..3,
"",
" println!(\"goodbye world\");\n",
DiffHunkStatus::added(),
DiffHunkStatus::added_none(),
)],
);
});
@ -5815,13 +5815,13 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
0..1,
"",
"// print goodbye\n",
DiffHunkStatus::Added(DiffHunkSecondaryStatus::HasSecondaryHunk),
DiffHunkStatus::added(DiffHunkSecondaryStatus::HasSecondaryHunk),
),
(
2..3,
" println!(\"hello world\");\n",
" println!(\"goodbye world\");\n",
DiffHunkStatus::modified(),
DiffHunkStatus::modified_none(),
),
],
);
@ -5850,7 +5850,7 @@ async fn test_uncommitted_diff_for_buffer(cx: &mut gpui::TestAppContext) {
2..3,
"",
" println!(\"goodbye world\");\n",
DiffHunkStatus::added(),
DiffHunkStatus::added_none(),
)],
);
});
@ -5916,7 +5916,7 @@ async fn test_single_file_diffs(cx: &mut gpui::TestAppContext) {
1..2,
" println!(\"hello from HEAD\");\n",
" println!(\"hello from the working copy\");\n",
DiffHunkStatus::modified(),
DiffHunkStatus::modified_none(),
)],
);
});