diff --git a/crates/editor/src/hunk_diff.rs b/crates/editor/src/hunk_diff.rs index ef84833a4d..dbc0fbaf9e 100644 --- a/crates/editor/src/hunk_diff.rs +++ b/crates/editor/src/hunk_diff.rs @@ -1,4 +1,4 @@ -use std::ops::Range; +use std::{ops::Range, sync::Arc}; use collections::{hash_map, HashMap, HashSet}; use git::diff::{DiffHunk, DiffHunkStatus}; @@ -14,7 +14,8 @@ use util::{debug_panic, RangeExt}; use crate::{ git::{diff_hunk_to_display, DisplayDiffHunk}, hunks_for_selections, BlockDisposition, BlockId, BlockProperties, BlockStyle, DiffRowHighlight, - Editor, ExpandAllHunkDiffs, RangeToAnchorExt, ToDisplayPoint, ToggleHunkDiff, + Editor, ExpandAllHunkDiffs, RangeToAnchorExt, RevertSelectedHunks, ToDisplayPoint, + ToggleHunkDiff, }; #[derive(Debug, Clone)] @@ -215,35 +216,29 @@ impl Editor { let hunk_end = hunk.multi_buffer_range.end; let buffer = self.buffer().clone(); - let (diff_base_buffer, deleted_text_range, deleted_text_lines) = - buffer.update(cx, |buffer, cx| { - let snapshot = buffer.snapshot(cx); - let hunk = buffer_diff_hunk(&snapshot, multi_buffer_row_range.clone())?; - let mut buffer_ranges = buffer.range_to_buffer_ranges(multi_buffer_row_range, cx); - if buffer_ranges.len() == 1 { - let (buffer, _, _) = buffer_ranges.pop()?; - let diff_base_buffer = diff_base_buffer - .or_else(|| self.current_diff_base_buffer(&buffer, cx)) - .or_else(|| create_diff_base_buffer(&buffer, cx)); - let buffer = buffer.read(cx); - let deleted_text_lines = buffer.diff_base().map(|diff_base| { - let diff_start_row = diff_base - .offset_to_point(hunk.diff_base_byte_range.start) - .row; - let diff_end_row = - diff_base.offset_to_point(hunk.diff_base_byte_range.end).row; - let line_count = diff_end_row - diff_start_row; - line_count as usize - }); - Some(( - diff_base_buffer?, - hunk.diff_base_byte_range, - deleted_text_lines, - )) - } else { - None - } - })?; + let (diff_base_buffer, deleted_text_lines) = buffer.update(cx, |buffer, cx| { + let snapshot = buffer.snapshot(cx); + let hunk = buffer_diff_hunk(&snapshot, multi_buffer_row_range.clone())?; + let mut buffer_ranges = buffer.range_to_buffer_ranges(multi_buffer_row_range, cx); + if buffer_ranges.len() == 1 { + let (buffer, _, _) = buffer_ranges.pop()?; + let diff_base_buffer = diff_base_buffer + .or_else(|| self.current_diff_base_buffer(&buffer, cx)) + .or_else(|| create_diff_base_buffer(&buffer, cx))?; + let buffer = buffer.read(cx); + let deleted_text_lines = buffer.diff_base().map(|diff_base| { + let diff_start_row = diff_base + .offset_to_point(hunk.diff_base_byte_range.start) + .row; + let diff_end_row = diff_base.offset_to_point(hunk.diff_base_byte_range.end).row; + let line_count = diff_end_row - diff_start_row; + line_count as u8 + })?; + Some((diff_base_buffer, deleted_text_lines)) + } else { + None + } + })?; let block_insert_index = match self.expanded_hunks.hunks.binary_search_by(|probe| { probe @@ -256,13 +251,9 @@ impl Editor { }; let block = match hunk.status { - DiffHunkStatus::Removed => self.add_deleted_lines( - deleted_text_lines, - hunk_start, - diff_base_buffer, - deleted_text_range, - cx, - ), + DiffHunkStatus::Removed => { + self.insert_deleted_text_block(diff_base_buffer, deleted_text_lines, &hunk, cx) + } DiffHunkStatus::Added => { self.highlight_rows::( hunk_start..hunk_end, @@ -277,13 +268,7 @@ impl Editor { Some(added_hunk_color(cx)), cx, ); - self.add_deleted_lines( - deleted_text_lines, - hunk_start, - diff_base_buffer, - deleted_text_range, - cx, - ) + self.insert_deleted_text_block(diff_base_buffer, deleted_text_lines, &hunk, cx) } }; self.expanded_hunks.hunks.insert( @@ -300,43 +285,20 @@ impl Editor { Some(()) } - fn add_deleted_lines( - &mut self, - deleted_text_lines: Option, - hunk_start: Anchor, - diff_base_buffer: Model, - deleted_text_range: Range, - cx: &mut ViewContext<'_, Self>, - ) -> Option { - if let Some(deleted_text_lines) = deleted_text_lines { - self.insert_deleted_text_block( - hunk_start, - diff_base_buffer, - deleted_text_range, - deleted_text_lines as u8, - cx, - ) - } else { - debug_panic!("Found no deleted text for removed hunk on position {hunk_start:?}"); - None - } - } - fn insert_deleted_text_block( &mut self, - position: Anchor, diff_base_buffer: Model, - deleted_text_range: Range, deleted_text_height: u8, + hunk: &HunkToExpand, cx: &mut ViewContext<'_, Self>, ) -> Option { let deleted_hunk_color = deleted_hunk_color(cx); let (editor_height, editor_with_deleted_text) = - editor_with_deleted_text(diff_base_buffer, deleted_text_range, deleted_hunk_color, cx); + editor_with_deleted_text(diff_base_buffer, deleted_hunk_color, hunk, cx); let parent_gutter_offset = self.gutter_dimensions.width + self.gutter_dimensions.margin; let mut new_block_ids = self.insert_blocks( Some(BlockProperties { - position, + position: hunk.multi_buffer_range.start, height: editor_height.max(deleted_text_height), style: BlockStyle::Flex, render: Box::new(move |_| { @@ -571,10 +533,11 @@ fn deleted_hunk_color(cx: &AppContext) -> Hsla { fn editor_with_deleted_text( diff_base_buffer: Model, - deleted_text_range: Range, deleted_color: Hsla, + hunk: &HunkToExpand, cx: &mut ViewContext<'_, Editor>, ) -> (u8, View) { + let parent_editor = cx.view().downgrade(); let editor = cx.new_view(|cx| { let multi_buffer = cx.new_model(|_| MultiBuffer::without_headers(0, language::Capability::ReadOnly)); @@ -582,7 +545,7 @@ fn editor_with_deleted_text( multi_buffer.push_excerpts( diff_base_buffer, Some(ExcerptRange { - context: deleted_text_range, + context: hunk.diff_base_byte_range.clone(), primary: None, }), cx, @@ -603,6 +566,40 @@ fn editor_with_deleted_text( .anchor_after(editor.buffer.read(cx).len(cx)); editor.highlight_rows::(start..end, Some(deleted_color), cx); + let hunk_related_subscription = cx.on_blur(&editor.focus_handle, |editor, cx| { + editor.change_selections(None, cx, |s| { + s.try_cancel(); + }); + }); + editor._subscriptions.push(hunk_related_subscription); + let original_multi_buffer_range = hunk.multi_buffer_range.clone(); + let diff_base_range = hunk.diff_base_byte_range.clone(); + editor.register_action::(move |_, cx| { + parent_editor + .update(cx, |editor, cx| { + let Some((buffer, original_text)) = editor.buffer().update(cx, |buffer, cx| { + let (_, buffer, _) = + buffer.excerpt_containing(original_multi_buffer_range.start, cx)?; + let original_text = + buffer.read(cx).diff_base()?.slice(diff_base_range.clone()); + Some((buffer, Arc::from(original_text.to_string()))) + }) else { + return; + }; + buffer.update(cx, |buffer, cx| { + buffer.edit( + Some(( + original_multi_buffer_range.start.text_anchor + ..original_multi_buffer_range.end.text_anchor, + original_text, + )), + None, + cx, + ) + }); + }) + .ok(); + }); editor });