From 00b7c78e33da3d920f8534ab8d540fde82822ea5 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 9 Dec 2022 15:24:13 -0500 Subject: [PATCH 1/8] Initial hacky displaying of git gutter in multi-buffers --- crates/editor/src/multi_buffer.rs | 70 ++++++++++++++++++++++++++++--- crates/git/src/diff.rs | 10 ++--- crates/language/src/buffer.rs | 5 +-- crates/sum_tree/src/cursor.rs | 4 ++ 4 files changed, 76 insertions(+), 13 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index d758792e6c..736db68965 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2635,11 +2635,71 @@ impl MultiBufferSnapshot { row_range: Range, reversed: bool, ) -> impl 'a + Iterator> { - self.as_singleton() - .into_iter() - .flat_map(move |(_, _, buffer)| { - buffer.git_diff_hunks_in_range(row_range.clone(), reversed) - }) + // dbg!(&row_range); + let mut lines_advance = 0; + let mut cursor = self.excerpts.filter::<_, ExcerptSummary>(move |summary| { + let filter = summary.text.lines.row + lines_advance >= row_range.start + && lines_advance <= row_range.end; + lines_advance += summary.text.lines.row; + filter + }); + + let mut lines_advance = 0; + std::iter::from_fn(move || { + cursor.next(&()); + let excerpt = cursor.item()?; + let summary = cursor.item_summary()?; + + let range = excerpt.range.context.clone(); + let range_start_row = range.start.to_point(&excerpt.buffer).row; + let range_end_row = range.end.to_point(&excerpt.buffer).row; + // dbg!(range_start_row); + let a = Some(excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( + move |mut hunk| { + hunk.buffer_range.start = hunk.buffer_range.start.max(range_start_row) + - range_start_row + + lines_advance; + hunk.buffer_range.end = hunk.buffer_range.end.max(range_start_row) + - range_start_row + + lines_advance; + hunk + }, + )); + lines_advance += summary.text.lines.row; + a + }) + .flatten() + // let mut cursor = self.excerpts.cursor::(); + // cursor.seek(&Point::new(row_range.start, 0), Bias::Left, &()); + + // let mut is_first = true; + // let mut advance = 0; + // std::iter::from_fn(move || { + // if !is_first { + // cursor.next(&()); + // } + // is_first = false; + + // let (item, summary) = match (cursor.item(), cursor.item_summary()) { + // (Some(item), Some(summary)) => (item, summary), + // _ => return None, + // }; + + // // dbg!(&advance); + // // if advance > row_range.end { + // // println!("returning none"); + // // return None; + // // } + + // // let row_range = row_range.start - advance..row_range.end - advance; + // // println!("returning an iterator, {row_range:?}"); + // // // summary. + // // advance += summary.text.lines.row; + // Some(item.buffer.git_diff_hunks_in_range(row_range, reversed)) + + // item.range + // }) + // .flatten() } pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index e808eee24f..3a818e6505 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -73,16 +73,16 @@ impl BufferDiff { pub fn hunks_in_range<'a>( &'a self, - query_row_range: Range, + range: Range, buffer: &'a BufferSnapshot, reversed: bool, ) -> impl 'a + Iterator> { - let start = buffer.anchor_before(Point::new(query_row_range.start, 0)); - let end = buffer.anchor_after(Point::new(query_row_range.end, 0)); + // let start = buffer.anchor_before(Point::new(query_row_range.start, 0)); + // let end = buffer.anchor_after(Point::new(query_row_range.end, 0)); let mut cursor = self.tree.filter::<_, DiffHunkSummary>(move |summary| { - let before_start = summary.buffer_range.end.cmp(&start, buffer).is_lt(); - let after_end = summary.buffer_range.start.cmp(&end, buffer).is_gt(); + let before_start = summary.buffer_range.end.cmp(&range.start, buffer).is_lt(); + let after_end = summary.buffer_range.start.cmp(&range.end, buffer).is_gt(); !before_start && !after_end }); diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index e8bc2bf314..44fa49495b 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2312,11 +2312,10 @@ impl BufferSnapshot { pub fn git_diff_hunks_in_range<'a>( &'a self, - query_row_range: Range, + range: Range, reversed: bool, ) -> impl 'a + Iterator> { - self.git_diff - .hunks_in_range(query_row_range, self, reversed) + self.git_diff.hunks_in_range(range, self, reversed) } pub fn diagnostics_in_range<'a, T, O>( diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 52200d64cf..88412f6059 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -597,6 +597,10 @@ where self.cursor.item() } + pub fn item_summary(&self) -> Option<&'a T::Summary> { + self.cursor.item_summary() + } + pub fn next(&mut self, cx: &::Context) { self.cursor.next_internal(&mut self.filter_node, cx); } From 7c3dc1e3dca12bd7c1729524f76754bf9d2e75cc Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 12 Dec 2022 11:57:14 -0500 Subject: [PATCH 2/8] Cleanup --- crates/editor/src/multi_buffer.rs | 34 ------------------------------- crates/git/src/diff.rs | 3 --- 2 files changed, 37 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 736db68965..a386403a41 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2635,7 +2635,6 @@ impl MultiBufferSnapshot { row_range: Range, reversed: bool, ) -> impl 'a + Iterator> { - // dbg!(&row_range); let mut lines_advance = 0; let mut cursor = self.excerpts.filter::<_, ExcerptSummary>(move |summary| { let filter = summary.text.lines.row + lines_advance >= row_range.start @@ -2652,8 +2651,6 @@ impl MultiBufferSnapshot { let range = excerpt.range.context.clone(); let range_start_row = range.start.to_point(&excerpt.buffer).row; - let range_end_row = range.end.to_point(&excerpt.buffer).row; - // dbg!(range_start_row); let a = Some(excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( move |mut hunk| { hunk.buffer_range.start = hunk.buffer_range.start.max(range_start_row) @@ -2669,37 +2666,6 @@ impl MultiBufferSnapshot { a }) .flatten() - // let mut cursor = self.excerpts.cursor::(); - // cursor.seek(&Point::new(row_range.start, 0), Bias::Left, &()); - - // let mut is_first = true; - // let mut advance = 0; - // std::iter::from_fn(move || { - // if !is_first { - // cursor.next(&()); - // } - // is_first = false; - - // let (item, summary) = match (cursor.item(), cursor.item_summary()) { - // (Some(item), Some(summary)) => (item, summary), - // _ => return None, - // }; - - // // dbg!(&advance); - // // if advance > row_range.end { - // // println!("returning none"); - // // return None; - // // } - - // // let row_range = row_range.start - advance..row_range.end - advance; - // // println!("returning an iterator, {row_range:?}"); - // // // summary. - // // advance += summary.text.lines.row; - // Some(item.buffer.git_diff_hunks_in_range(row_range, reversed)) - - // item.range - // }) - // .flatten() } pub fn range_for_syntax_ancestor(&self, range: Range) -> Option> { diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 3a818e6505..61396e9278 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -77,9 +77,6 @@ impl BufferDiff { buffer: &'a BufferSnapshot, reversed: bool, ) -> impl 'a + Iterator> { - // let start = buffer.anchor_before(Point::new(query_row_range.start, 0)); - // let end = buffer.anchor_after(Point::new(query_row_range.end, 0)); - let mut cursor = self.tree.filter::<_, DiffHunkSummary>(move |summary| { let before_start = summary.buffer_range.end.cmp(&range.start, buffer).is_lt(); let after_end = summary.buffer_range.start.cmp(&range.end, buffer).is_gt(); From 2cd9987b54daf35e05910a2ac35c348a32c34689 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 12 Dec 2022 16:24:21 -0500 Subject: [PATCH 3/8] Git diff recalc in project search --- crates/search/src/project_search.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/search/src/project_search.rs b/crates/search/src/project_search.rs index 13b754a417..dda8a7ec9c 100644 --- a/crates/search/src/project_search.rs +++ b/crates/search/src/project_search.rs @@ -334,6 +334,15 @@ impl Item for ProjectSearchView { .update(cx, |editor, cx| editor.navigate(data, cx)) } + fn git_diff_recalc( + &mut self, + project: ModelHandle, + cx: &mut ViewContext, + ) -> Task> { + self.results_editor + .update(cx, |editor, cx| editor.git_diff_recalc(project, cx)) + } + fn to_item_events(event: &Self::Event) -> Vec { match event { ViewEvent::UpdateTab => vec![ItemEvent::UpdateBreadcrumbs, ItemEvent::UpdateTab], From ecd44e69144f01a0ac2c52f96d2b2e835b7b2973 Mon Sep 17 00:00:00 2001 From: Julia Date: Mon, 12 Dec 2022 16:54:14 -0500 Subject: [PATCH 4/8] Git diff recalc in project diagnostics --- crates/diagnostics/src/diagnostics.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/crates/diagnostics/src/diagnostics.rs b/crates/diagnostics/src/diagnostics.rs index 9122706ad3..cb1ad13656 100644 --- a/crates/diagnostics/src/diagnostics.rs +++ b/crates/diagnostics/src/diagnostics.rs @@ -575,6 +575,15 @@ impl Item for ProjectDiagnosticsEditor { unreachable!() } + fn git_diff_recalc( + &mut self, + project: ModelHandle, + cx: &mut ViewContext, + ) -> Task> { + self.editor + .update(cx, |editor, cx| editor.git_diff_recalc(project, cx)) + } + fn to_item_events(event: &Self::Event) -> Vec { Editor::to_item_events(event) } From cf721732824de9e716cd380faca829a8ae5ce07d Mon Sep 17 00:00:00 2001 From: Julia Date: Tue, 13 Dec 2022 13:58:50 -0500 Subject: [PATCH 5/8] Clamp end of visual git hunk to requested range --- crates/editor/src/multi_buffer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index a386403a41..92801d1b47 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2651,12 +2651,13 @@ impl MultiBufferSnapshot { let range = excerpt.range.context.clone(); let range_start_row = range.start.to_point(&excerpt.buffer).row; + let range_end_row = range.end.to_point(&excerpt.buffer).row; let a = Some(excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( move |mut hunk| { hunk.buffer_range.start = hunk.buffer_range.start.max(range_start_row) - range_start_row + lines_advance; - hunk.buffer_range.end = hunk.buffer_range.end.max(range_start_row) + hunk.buffer_range.end = hunk.buffer_range.end.min(range_end_row + 1) - range_start_row + lines_advance; hunk From 0dedc1f3a43f93889a651960c98144a1df83b055 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 15 Dec 2022 00:17:28 -0500 Subject: [PATCH 6/8] Get tests building again --- crates/collab/src/integration_tests.rs | 18 +++++++++--------- crates/editor/src/multi_buffer.rs | 8 +++++--- crates/editor/src/test/editor_test_context.rs | 2 +- crates/git/src/diff.rs | 17 +++++++++++++++-- crates/language/src/buffer.rs | 8 ++++++++ 5 files changed, 38 insertions(+), 15 deletions(-) diff --git a/crates/collab/src/integration_tests.rs b/crates/collab/src/integration_tests.rs index 8150b1c0af..ae8949b88f 100644 --- a/crates/collab/src/integration_tests.rs +++ b/crates/collab/src/integration_tests.rs @@ -1813,7 +1813,7 @@ async fn test_git_diff_base_change( buffer_local_a.read_with(cx_a, |buffer, _| { assert_eq!(buffer.diff_base(), Some(diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(1..2, "", "two\n")], @@ -1833,7 +1833,7 @@ async fn test_git_diff_base_change( buffer_remote_a.read_with(cx_b, |buffer, _| { assert_eq!(buffer.diff_base(), Some(diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(1..2, "", "two\n")], @@ -1857,7 +1857,7 @@ async fn test_git_diff_base_change( assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(2..3, "", "three\n")], @@ -1868,7 +1868,7 @@ async fn test_git_diff_base_change( buffer_remote_a.read_with(cx_b, |buffer, _| { assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(2..3, "", "three\n")], @@ -1911,7 +1911,7 @@ async fn test_git_diff_base_change( buffer_local_b.read_with(cx_a, |buffer, _| { assert_eq!(buffer.diff_base(), Some(diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(1..2, "", "two\n")], @@ -1931,7 +1931,7 @@ async fn test_git_diff_base_change( buffer_remote_b.read_with(cx_b, |buffer, _| { assert_eq!(buffer.diff_base(), Some(diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(1..2, "", "two\n")], @@ -1959,12 +1959,12 @@ async fn test_git_diff_base_change( "{:?}", buffer .snapshot() - .git_diff_hunks_in_range(0..4, false) + .git_diff_hunks_in_row_range(0..4, false) .collect::>() ); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(2..3, "", "three\n")], @@ -1975,7 +1975,7 @@ async fn test_git_diff_base_change( buffer_remote_b.read_with(cx_b, |buffer, _| { assert_eq!(buffer.diff_base(), Some(new_diff_base.as_ref())); git::diff::assert_hunks( - buffer.snapshot().git_diff_hunks_in_range(0..4, false), + buffer.snapshot().git_diff_hunks_in_row_range(0..4, false), &buffer, &diff_base, &[(2..3, "", "three\n")], diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 92801d1b47..22e75a219b 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2652,7 +2652,8 @@ impl MultiBufferSnapshot { let range = excerpt.range.context.clone(); let range_start_row = range.start.to_point(&excerpt.buffer).row; let range_end_row = range.end.to_point(&excerpt.buffer).row; - let a = Some(excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( + + let hunks = excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( move |mut hunk| { hunk.buffer_range.start = hunk.buffer_range.start.max(range_start_row) - range_start_row @@ -2662,9 +2663,10 @@ impl MultiBufferSnapshot { + lines_advance; hunk }, - )); + ); + lines_advance += summary.text.lines.row; - a + Some(hunks) }) .flatten() } diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 74b6bdd416..568f29d3e1 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -254,7 +254,7 @@ impl<'a> EditorTestContext<'a> { Actual selections: {} - "}, + "}, self.assertion_context(), expected_marked_text, actual_marked_text, diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 61396e9278..066a7df224 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -71,6 +71,17 @@ impl BufferDiff { } } + pub fn hunks_in_row_range<'a>( + &'a self, + range: Range, + buffer: &'a BufferSnapshot, + reversed: bool, + ) -> impl 'a + Iterator> { + let start = buffer.anchor_before(Point::new(range.start, 0)); + let end = buffer.anchor_after(Point::new(range.end, 0)); + self.hunks_in_range(start..end, buffer, reversed) + } + pub fn hunks_in_range<'a>( &'a self, range: Range, @@ -138,7 +149,9 @@ impl BufferDiff { #[cfg(test)] fn hunks<'a>(&'a self, text: &'a BufferSnapshot) -> impl 'a + Iterator> { - self.hunks_in_range(0..u32::MAX, text, false) + let start = text.anchor_before(Point::new(0, 0)); + let end = text.anchor_after(Point::new(u32::MAX, u32::MAX)); + self.hunks_in_range(start..end, text, false) } fn diff<'a>(head: &'a str, current: &'a str) -> Option> { @@ -352,7 +365,7 @@ mod tests { assert_eq!(diff.hunks(&buffer).count(), 8); assert_hunks( - diff.hunks_in_range(7..12, &buffer, false), + diff.hunks_in_row_range(7..12, &buffer, false), &buffer, &diff_base, &[ diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 44fa49495b..4bf0f91a2a 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2310,6 +2310,14 @@ impl BufferSnapshot { }) } + pub fn git_diff_hunks_in_row_range<'a>( + &'a self, + range: Range, + reversed: bool, + ) -> impl 'a + Iterator> { + self.git_diff.hunks_in_row_range(range, self, reversed) + } + pub fn git_diff_hunks_in_range<'a>( &'a self, range: Range, From f88b413f6a1659147bb1700117a9f30f34b5dca4 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 15 Dec 2022 17:09:09 -0500 Subject: [PATCH 7/8] Rewrite multi-buffer aware git hunks in range to be more correct Less ad-hoc state tracking, rely more on values provided by the underlying data Co-Authored-By: Max Brunsfeld --- crates/editor/src/multi_buffer.rs | 232 ++++++++++++++++++++++++++---- crates/git/src/diff.rs | 6 +- crates/language/src/buffer.rs | 5 +- 3 files changed, 211 insertions(+), 32 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 22e75a219b..fab55a5099 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2635,38 +2635,58 @@ impl MultiBufferSnapshot { row_range: Range, reversed: bool, ) -> impl 'a + Iterator> { - let mut lines_advance = 0; - let mut cursor = self.excerpts.filter::<_, ExcerptSummary>(move |summary| { - let filter = summary.text.lines.row + lines_advance >= row_range.start - && lines_advance <= row_range.end; - lines_advance += summary.text.lines.row; - filter - }); + let mut cursor = self.excerpts.cursor::(); + cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &()); - let mut lines_advance = 0; std::iter::from_fn(move || { - cursor.next(&()); let excerpt = cursor.item()?; - let summary = cursor.item_summary()?; + let multibuffer_start = *cursor.start(); + let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + if multibuffer_start.row >= row_range.end { + return None; + } - let range = excerpt.range.context.clone(); - let range_start_row = range.start.to_point(&excerpt.buffer).row; - let range_end_row = range.end.to_point(&excerpt.buffer).row; + let mut buffer_start = excerpt.range.context.start; + let mut buffer_end = excerpt.range.context.end; + let excerpt_start_point = buffer_start.to_point(&excerpt.buffer); + let excerpt_end_point = excerpt_start_point + excerpt.text_summary.lines; - let hunks = excerpt.buffer.git_diff_hunks_in_range(range, reversed).map( - move |mut hunk| { - hunk.buffer_range.start = hunk.buffer_range.start.max(range_start_row) - - range_start_row - + lines_advance; - hunk.buffer_range.end = hunk.buffer_range.end.min(range_end_row + 1) - - range_start_row - + lines_advance; - hunk - }, - ); + if row_range.start > multibuffer_start.row { + let buffer_start_point = + excerpt_start_point + Point::new(row_range.start - multibuffer_start.row, 0); + buffer_start = excerpt.buffer.anchor_before(buffer_start_point); + } - lines_advance += summary.text.lines.row; - Some(hunks) + if row_range.end < multibuffer_end.row { + let buffer_end_point = + excerpt_start_point + Point::new(row_range.end - multibuffer_start.row, 0); + buffer_end = excerpt.buffer.anchor_before(buffer_end_point); + } + + let buffer_hunks = excerpt + .buffer + .git_diff_hunks_intersecting_range(buffer_start..buffer_end, reversed) + .filter_map(move |hunk| { + let start = multibuffer_start.row + + hunk + .buffer_range + .start + .saturating_sub(excerpt_start_point.row); + let end = multibuffer_start.row + + hunk + .buffer_range + .end + .min(excerpt_end_point.row + 1) + .saturating_sub(excerpt_start_point.row); + + Some(DiffHunk { + buffer_range: start..end, + diff_base_byte_range: hunk.diff_base_byte_range.clone(), + }) + }); + + cursor.next(&()); + Some(buffer_hunks) }) .flatten() } @@ -3488,11 +3508,12 @@ impl ToPointUtf16 for PointUtf16 { #[cfg(test)] mod tests { use super::*; - use gpui::MutableAppContext; + use gpui::{MutableAppContext, TestAppContext}; use language::{Buffer, Rope}; use rand::prelude::*; use settings::Settings; use std::{env, rc::Rc}; + use unindent::Unindent; use util::test::sample_text; @@ -4033,6 +4054,163 @@ mod tests { ); } + #[gpui::test] + async fn test_diff_hunks_in_range(cx: &mut TestAppContext) { + use git::diff::DiffHunkStatus; + + // buffer has two modified hunks with two rows each + let buffer_1 = cx.add_model(|cx| { + let mut buffer = Buffer::new( + 0, + " + 1.zero + 1.ONE + 1.TWO + 1.three + 1.FOUR + 1.FIVE + 1.six + " + .unindent(), + cx, + ); + buffer.set_diff_base( + Some( + " + 1.zero + 1.one + 1.two + 1.three + 1.four + 1.five + 1.six + " + .unindent(), + ), + cx, + ); + buffer + }); + + // buffer has a deletion hunk and an insertion hunk + let buffer_2 = cx.add_model(|cx| { + let mut buffer = Buffer::new( + 0, + " + 2.zero + 2.one + 2.two + 2.three + 2.four + 2.five + 2.six + " + .unindent(), + cx, + ); + buffer.set_diff_base( + Some( + " + 2.zero + 2.one + 2.one-and-a-half + 2.two + 2.three + 2.four + 2.six + " + .unindent(), + ), + cx, + ); + buffer + }); + + cx.foreground().run_until_parked(); + + let multibuffer = cx.add_model(|cx| { + let mut multibuffer = MultiBuffer::new(0); + multibuffer.push_excerpts( + buffer_1.clone(), + [ + // excerpt ends in the middle of a modified hunk + ExcerptRange { + context: Point::new(0, 0)..Point::new(1, 5), + primary: Default::default(), + }, + // excerpt begins in the middle of a modified hunk + ExcerptRange { + context: Point::new(5, 0)..Point::new(6, 5), + primary: Default::default(), + }, + ], + cx, + ); + multibuffer.push_excerpts( + buffer_2.clone(), + [ + // excerpt ends at a deletion + ExcerptRange { + context: Point::new(0, 0)..Point::new(1, 5), + primary: Default::default(), + }, + // excerpt starts at a deletion + ExcerptRange { + context: Point::new(2, 0)..Point::new(2, 5), + primary: Default::default(), + }, + // excerpt fully contains a deletion hunk + ExcerptRange { + context: Point::new(1, 0)..Point::new(2, 5), + primary: Default::default(), + }, + // excerpt fully contains an insertion hunk + ExcerptRange { + context: Point::new(4, 0)..Point::new(6, 5), + primary: Default::default(), + }, + ], + cx, + ); + multibuffer + }); + + let snapshot = multibuffer.read_with(cx, |b, cx| b.snapshot(cx)); + + assert_eq!( + snapshot.text(), + " + 1.zero + 1.ONE + 1.FIVE + 1.six + 2.zero + 2.one + 2.two + 2.one + 2.two + 2.four + 2.five + 2.six" + .unindent() + ); + + assert_eq!( + snapshot + .git_diff_hunks_in_range(0..12, false) + .map(|hunk| (hunk.status(), hunk.buffer_range)) + .collect::>(), + &[ + (DiffHunkStatus::Modified, 1..2), + (DiffHunkStatus::Modified, 2..3), + //TODO: Define better when and where removed hunks show up at range extremities + (DiffHunkStatus::Removed, 6..6), + (DiffHunkStatus::Removed, 8..8), + (DiffHunkStatus::Added, 10..11), + ] + ); + } + #[gpui::test(iterations = 100)] fn test_random_multibuffer(cx: &mut MutableAppContext, mut rng: StdRng) { let operations = env::var("OPERATIONS") diff --git a/crates/git/src/diff.rs b/crates/git/src/diff.rs index 066a7df224..b28af26f16 100644 --- a/crates/git/src/diff.rs +++ b/crates/git/src/diff.rs @@ -79,10 +79,10 @@ impl BufferDiff { ) -> impl 'a + Iterator> { let start = buffer.anchor_before(Point::new(range.start, 0)); let end = buffer.anchor_after(Point::new(range.end, 0)); - self.hunks_in_range(start..end, buffer, reversed) + self.hunks_intersecting_range(start..end, buffer, reversed) } - pub fn hunks_in_range<'a>( + pub fn hunks_intersecting_range<'a>( &'a self, range: Range, buffer: &'a BufferSnapshot, @@ -151,7 +151,7 @@ impl BufferDiff { fn hunks<'a>(&'a self, text: &'a BufferSnapshot) -> impl 'a + Iterator> { let start = text.anchor_before(Point::new(0, 0)); let end = text.anchor_after(Point::new(u32::MAX, u32::MAX)); - self.hunks_in_range(start..end, text, false) + self.hunks_intersecting_range(start..end, text, false) } fn diff<'a>(head: &'a str, current: &'a str) -> Option> { diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 4bf0f91a2a..a78bb4af79 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -2318,12 +2318,13 @@ impl BufferSnapshot { self.git_diff.hunks_in_row_range(range, self, reversed) } - pub fn git_diff_hunks_in_range<'a>( + pub fn git_diff_hunks_intersecting_range<'a>( &'a self, range: Range, reversed: bool, ) -> impl 'a + Iterator> { - self.git_diff.hunks_in_range(range, self, reversed) + self.git_diff + .hunks_intersecting_range(range, self, reversed) } pub fn diagnostics_in_range<'a, T, O>( From ebd0c5d000b1c1b6d8ec1bc225266b2cbf6c2522 Mon Sep 17 00:00:00 2001 From: Julia Date: Thu, 15 Dec 2022 18:17:32 -0500 Subject: [PATCH 8/8] Handle reversed=true for multi-buffer git-hunks-in-range iteration Co-Authored-By: Nathan Sobo --- crates/editor/src/multi_buffer.rs | 48 ++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 10 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index fab55a5099..b76890efb0 100644 --- a/crates/editor/src/multi_buffer.rs +++ b/crates/editor/src/multi_buffer.rs @@ -2636,7 +2636,15 @@ impl MultiBufferSnapshot { reversed: bool, ) -> impl 'a + Iterator> { let mut cursor = self.excerpts.cursor::(); - cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &()); + + if reversed { + cursor.seek(&Point::new(row_range.end, 0), Bias::Left, &()); + if cursor.item().is_none() { + cursor.prev(&()); + } + } else { + cursor.seek(&Point::new(row_range.start, 0), Bias::Right, &()); + } std::iter::from_fn(move || { let excerpt = cursor.item()?; @@ -2685,7 +2693,12 @@ impl MultiBufferSnapshot { }) }); - cursor.next(&()); + if reversed { + cursor.prev(&()); + } else { + cursor.next(&()); + } + Some(buffer_hunks) }) .flatten() @@ -4195,19 +4208,34 @@ mod tests { .unindent() ); + let expected = [ + (DiffHunkStatus::Modified, 1..2), + (DiffHunkStatus::Modified, 2..3), + //TODO: Define better when and where removed hunks show up at range extremities + (DiffHunkStatus::Removed, 6..6), + (DiffHunkStatus::Removed, 8..8), + (DiffHunkStatus::Added, 10..11), + ]; + assert_eq!( snapshot .git_diff_hunks_in_range(0..12, false) .map(|hunk| (hunk.status(), hunk.buffer_range)) .collect::>(), - &[ - (DiffHunkStatus::Modified, 1..2), - (DiffHunkStatus::Modified, 2..3), - //TODO: Define better when and where removed hunks show up at range extremities - (DiffHunkStatus::Removed, 6..6), - (DiffHunkStatus::Removed, 8..8), - (DiffHunkStatus::Added, 10..11), - ] + &expected, + ); + + assert_eq!( + snapshot + .git_diff_hunks_in_range(0..12, true) + .map(|hunk| (hunk.status(), hunk.buffer_range)) + .collect::>(), + expected + .iter() + .rev() + .cloned() + .collect::>() + .as_slice(), ); }