Improve deleted hunk blocks' behavior (#11340)

* clear their selections on focus lost
* allow reverting diff hunks when the caret is inside of the deleted
hunk diff editor block

Release Notes:

- N/A
This commit is contained in:
Kirill Bulatov 2024-05-03 12:18:50 +03:00 committed by GitHub
parent e69e25c171
commit cd03e473c8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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::<DiffRowHighlight>(
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<usize>,
hunk_start: Anchor,
diff_base_buffer: Model<Buffer>,
deleted_text_range: Range<usize>,
cx: &mut ViewContext<'_, Self>,
) -> Option<BlockId> {
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<Buffer>,
deleted_text_range: Range<usize>,
deleted_text_height: u8,
hunk: &HunkToExpand,
cx: &mut ViewContext<'_, Self>,
) -> Option<BlockId> {
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<Buffer>,
deleted_text_range: Range<usize>,
deleted_color: Hsla,
hunk: &HunkToExpand,
cx: &mut ViewContext<'_, Editor>,
) -> (u8, View<Editor>) {
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::<DiffRowHighlight>(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::<RevertSelectedHunks>(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
});