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 d758792e6c29f88e1b17a344c949d2c50f999454..736db68965e9053d733c8ee058df974578a4e2c3 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 e808eee24f4f850a30c00c6813459a1ec1e243c8..3a818e65055d4dccfe2676ff7e4a6e26f49757bb 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 e8bc2bf314c45784de7653c1d63d803379166f2c..44fa49495b38a804d73211ed607433e010e01ae4 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 52200d64cf781bd9f07f9222891711bbed720a15..88412f60598e8e5eaafbb52515089b580e2613a2 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 736db68965e9053d733c8ee058df974578a4e2c3..a386403a4132da5a35b85b3991fbe05dc13f3fa0 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 3a818e65055d4dccfe2676ff7e4a6e26f49757bb..61396e9278115cc9b1aa3a0f680395d76f3f96e4 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 13b754a4178eae117aea5b1090751c6b738c27ec..dda8a7ec9ce758864be0077dc3fd0abe8198da73 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 9122706ad388b1f736c4b7eca6cf853bdb3c92f2..cb1ad13656c317170c15b5b05ef6b8ada0e3dbc4 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 a386403a4132da5a35b85b3991fbe05dc13f3fa0..92801d1b47671670201e01b7d8eefdaac3b0fa5a 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 8150b1c0af53563d068603f73434f120560b536c..ae8949b88f81dce8cc2c5c4bb0c347c9a8b35e29 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 92801d1b47671670201e01b7d8eefdaac3b0fa5a..22e75a219b47e62c7dfe6ee67ccca574e39ba4c0 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 74b6bdd416b681fffefed91c8e5546c4b70b5703..568f29d3e11caa8667d524e49786b1e34058ce20 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 61396e9278115cc9b1aa3a0f680395d76f3f96e4..066a7df2248a0bfb44359cb54d4b9dd6eceb5b5f 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 44fa49495b38a804d73211ed607433e010e01ae4..4bf0f91a2a5833d4d755eb5de0bcb5b0676f0a79 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 | 236 ++++++++++++++++++++++++++---- crates/git/src/diff.rs | 6 +- crates/language/src/buffer.rs | 5 +- 3 files changed, 213 insertions(+), 34 deletions(-) diff --git a/crates/editor/src/multi_buffer.rs b/crates/editor/src/multi_buffer.rs index 22e75a219b47e62c7dfe6ee67ccca574e39ba4c0..fab55a5099d9abd6eaa393c359d83cf784849ff5 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 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 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 - }, - ); + let multibuffer_start = *cursor.start(); + let multibuffer_end = multibuffer_start + excerpt.text_summary.lines; + if multibuffer_start.row >= row_range.end { + return None; + } + + 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; + + 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); + } + + 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(), + }) + }); - lines_advance += summary.text.lines.row; - Some(hunks) + 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 066a7df2248a0bfb44359cb54d4b9dd6eceb5b5f..b28af26f1679da459aaaab270233f8fabda00c2c 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 4bf0f91a2a5833d4d755eb5de0bcb5b0676f0a79..a78bb4af79a4b69796e787a80602063d1cae9ba3 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 fab55a5099d9abd6eaa393c359d83cf784849ff5..b76890efb0d74d154f42885d8240076dcbd86ac8 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(), ); }