diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index a6993315c7fde6803d5b3110134c437cc53c9a45..91cab249bd5aa3db957488b5df7a124b154f324f 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -79,17 +79,18 @@ use workspace::{item::Item, notifications::NotifyTaskExt, Workspace}; const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.; +/// Note that for a "modified" MultiBufferDiffHunk, there are two DisplayDiffHunks, +/// one for the deleted portion and one for the added portion. #[derive(Debug, Clone, PartialEq, Eq)] enum DisplayDiffHunk { Folded { display_row: DisplayRow, }, Unfolded { - diff_base_byte_range: Range, display_row_range: Range, multi_buffer_range: Range, status: DiffHunkStatus, - contains_expanded: bool, + expanded: bool, }, } @@ -104,7 +105,7 @@ struct SelectionLayout { } impl SelectionLayout { - fn new( + fn new( selection: Selection, line_mode: bool, cursor_shape: CursorShape, @@ -1557,36 +1558,97 @@ impl EditorElement { let hunk_end_point = Point::new(hunk.row_range.end.0, 0); let hunk_display_start = snapshot.point_to_display_point(hunk_start_point, Bias::Left); + let hunk_added_start_at = + Anchor::in_buffer(hunk.excerpt_id, hunk.buffer_id, hunk.buffer_range.start); + let hunk_deleted_to_added_break = snapshot.point_to_display_point( + hunk_added_start_at.to_point(&snapshot.buffer_snapshot), + Bias::Right, + ); + let hunk_display_end = snapshot.point_to_display_point(hunk_end_point, Bias::Right); - let display_hunk = if hunk_display_start.column() != 0 { - DisplayDiffHunk::Folded { - display_row: hunk_display_start.row(), - } + if hunk_display_start.column() != 0 { + display_hunks.push(( + DisplayDiffHunk::Folded { + display_row: hunk_display_start.row(), + }, + None, + )); } else { let mut end_row = hunk_display_end.row(); if hunk_display_end.column() > 0 { end_row.0 += 1; } - let start_row = hunk_display_start.row(); - let contains_expanded = snapshot - .row_infos(start_row) - .take(end_row.0 as usize - start_row.0 as usize) - .any(|row_info| row_info.diff_status.is_some()); - DisplayDiffHunk::Unfolded { - status: hunk.status(), - diff_base_byte_range: hunk.diff_base_byte_range, - display_row_range: hunk_display_start.row()..end_row, - multi_buffer_range: Anchor::range_in_buffer( - hunk.excerpt_id, - hunk.buffer_id, - hunk.buffer_range, - ), - contains_expanded, + let deleted_count = snapshot + .buffer_snapshot + .row_infos(hunk.row_range.start) + .take(hunk.row_range.end.0 as usize - hunk.row_range.start.0 as usize) + .take_while(|row_info| { + matches!(row_info.diff_status, Some(DiffHunkStatus::Removed(_))) + }) + .count(); + let has_added = snapshot + .buffer_snapshot + .row_infos(hunk.row_range.start) + .take(hunk.row_range.end.0 as usize - hunk.row_range.start.0 as usize) + .any(|row_info| matches!(row_info.diff_status, Some(DiffHunkStatus::Added(_)))); + let expanded = deleted_count > 0 || has_added; + if deleted_count > 0 && has_added { + display_hunks.push(( + DisplayDiffHunk::Unfolded { + status: DiffHunkStatus::Removed(hunk.secondary_status), + display_row_range: hunk_display_start.row() + ..hunk_display_start.row() + DisplayRow(deleted_count as u32), + multi_buffer_range: Anchor::range_in_buffer( + hunk.excerpt_id, + hunk.buffer_id, + hunk.buffer_range.clone(), + ), + expanded, + }, + None, + )); + display_hunks.push(( + DisplayDiffHunk::Unfolded { + status: DiffHunkStatus::Added(hunk.secondary_status), + display_row_range: hunk_display_start.row() + + DisplayRow(deleted_count as u32) + ..end_row, + multi_buffer_range: Anchor::range_in_buffer( + hunk.excerpt_id, + hunk.buffer_id, + hunk.buffer_range, + ), + expanded, + }, + None, + )); + } else { + let status = if expanded && matches!(hunk.status(), DiffHunkStatus::Modified(_)) + { + if hunk_display_start.row() < hunk_deleted_to_added_break.row() { + DiffHunkStatus::Removed(hunk.secondary_status) + } else { + DiffHunkStatus::Added(hunk.secondary_status) + } + } else { + hunk.status() + }; + display_hunks.push(( + DisplayDiffHunk::Unfolded { + status, + display_row_range: hunk_display_start.row()..end_row, + multi_buffer_range: Anchor::range_in_buffer( + hunk.excerpt_id, + hunk.buffer_id, + hunk.buffer_range, + ), + expanded, + }, + None, + )); } }; - - display_hunks.push((display_hunk, None)); } let git_gutter_setting = ProjectSettings::get_global(cx) @@ -1924,7 +1986,8 @@ impl EditorElement { if tasks.offset.0 < offset_range_start || tasks.offset.0 >= offset_range_end { return None; } - let multibuffer_point = tasks.offset.0.to_point(&snapshot.buffer_snapshot); + let multibuffer_point = + multi_buffer::ToPoint::to_point(&tasks.offset.0, &snapshot.buffer_snapshot); let multibuffer_row = MultiBufferRow(multibuffer_point.row); let buffer_folded = snapshot .buffer_snapshot @@ -4579,7 +4642,7 @@ impl EditorElement { DisplayDiffHunk::Unfolded { status, display_row_range, - contains_expanded, + expanded, .. } => hitbox.as_ref().map(|hunk_hitbox| match status { DiffHunkStatus::Added(secondary_status) => ( @@ -4587,14 +4650,14 @@ impl EditorElement { cx.theme().colors().version_control_added.opacity(0.7), corners, secondary_status, - *contains_expanded, + *expanded, ), DiffHunkStatus::Modified(secondary_status) => ( hunk_hitbox.bounds, cx.theme().colors().version_control_modified.opacity(0.7), corners, secondary_status, - *contains_expanded, + *expanded, ), DiffHunkStatus::Removed(secondary_status) if !display_row_range.is_empty() => @@ -4604,7 +4667,7 @@ impl EditorElement { cx.theme().colors().version_control_deleted.opacity(0.7), corners, secondary_status, - *contains_expanded, + *expanded, ) } DiffHunkStatus::Removed(secondary_status) => ( @@ -4618,7 +4681,7 @@ impl EditorElement { cx.theme().colors().version_control_deleted.opacity(0.7), Corners::all(1. * line_height), secondary_status, - *contains_expanded, + *expanded, ), }), }; @@ -4628,16 +4691,15 @@ impl EditorElement { background_color, corner_radii, secondary_status, - contains_expanded, + expanded, )) = hunk_to_paint { - let background = if *secondary_status != DiffHunkSecondaryStatus::None - && contains_expanded - { - pattern_slash(background_color, line_height.0 / 2.5) - } else { - solid_color(background_color) - }; + let background = + if *secondary_status != DiffHunkSecondaryStatus::None && expanded { + pattern_slash(background_color, line_height.0 / 2.5) + } else { + solid_color(background_color) + }; window.paint_quad(quad( hunk_bounds,