From 8361b4d47a3c1f402f45cde00a35952e631ce740 Mon Sep 17 00:00:00 2001 From: Julia Date: Fri, 28 Oct 2022 15:07:53 -0400 Subject: [PATCH] Add test for go-to hunk and fix discovered bugs --- crates/editor/src/editor.rs | 15 ++- crates/editor/src/editor_tests.rs | 110 +++++++++++++++++- crates/editor/src/git.rs | 24 +++- crates/editor/src/test.rs | 1 - .../src/test/editor_git_test_context.rs | 56 --------- crates/editor/src/test/editor_test_context.rs | 5 + crates/language/src/buffer.rs | 2 +- crates/project/src/project.rs | 4 +- 8 files changed, 145 insertions(+), 72 deletions(-) delete mode 100644 crates/editor/src/test/editor_git_test_context.rs diff --git a/crates/editor/src/editor.rs b/crates/editor/src/editor.rs index 42f26b2cf1..d1bd1622b4 100644 --- a/crates/editor/src/editor.rs +++ b/crates/editor/src/editor.rs @@ -5258,6 +5258,7 @@ impl Editor { this: &mut Editor, snapshot: &DisplaySnapshot, initial_point: Point, + is_wrapped: bool, direction: Direction, cx: &mut ViewContext, ) -> bool { @@ -5274,12 +5275,18 @@ impl Editor { let display_point = initial_point.to_display_point(snapshot); let mut hunks = hunks .map(|hunk| diff_hunk_to_display(hunk, &snapshot)) - .skip_while(|hunk| hunk.display_row_range().contains(&display_point.row())) + .skip_while(|hunk| { + if is_wrapped { + false + } else { + hunk.contains_display_row(display_point.row()) + } + }) .dedup(); if let Some(hunk) = hunks.next() { this.change_selections(Some(Autoscroll::Center), cx, |s| { - let row = hunk.display_row_range().start; + let row = hunk.start_display_row(); let point = DisplayPoint::new(row, 0); s.select_display_ranges([point..point]); }); @@ -5290,12 +5297,12 @@ impl Editor { } } - if !seek_in_direction(self, &snapshot, selection.head(), direction, cx) { + if !seek_in_direction(self, &snapshot, selection.head(), false, direction, cx) { let wrapped_point = match direction { Direction::Next => Point::zero(), Direction::Prev => snapshot.buffer_snapshot.max_point(), }; - seek_in_direction(self, &snapshot, wrapped_point, direction, cx); + seek_in_direction(self, &snapshot, wrapped_point, true, direction, cx); } } diff --git a/crates/editor/src/editor_tests.rs b/crates/editor/src/editor_tests.rs index af1af933c5..c958117676 100644 --- a/crates/editor/src/editor_tests.rs +++ b/crates/editor/src/editor_tests.rs @@ -7,11 +7,11 @@ use unindent::Unindent; use super::*; use crate::test::{ - assert_text_with_selections, build_editor, editor_git_test_context::EditorGitTestContext, - editor_lsp_test_context::EditorLspTestContext, editor_test_context::EditorTestContext, - select_ranges, + assert_text_with_selections, build_editor, editor_lsp_test_context::EditorLspTestContext, + editor_test_context::EditorTestContext, select_ranges, }; use gpui::{ + executor::Deterministic, geometry::rect::RectF, platform::{WindowBounds, WindowOptions}, }; @@ -5081,8 +5081,108 @@ fn test_combine_syntax_and_fuzzy_match_highlights() { } #[gpui::test] -fn go_to_hunk(cx: &mut gpui::TestAppContext) { - let mut cx = EditorGitTestContext::new(cx); +async fn go_to_hunk(deterministic: Arc, cx: &mut gpui::TestAppContext) { + let mut cx = EditorTestContext::new(cx); + + let diff_base = r#" + use some::mod; + + const A: u32 = 42; + + fn main() { + println!("hello"); + + println!("world"); + } + "# + .unindent(); + + // Edits are modified, removed, modified, added + cx.set_state( + &r#" + use some::modified; + + ˇ + fn main() { + println!("hello there"); + + println!("around the"); + println!("world"); + } + "# + .unindent(), + ); + + cx.set_diff_base(Some(&diff_base)); + deterministic.run_until_parked(); + + cx.update_editor(|editor, cx| { + //Wrap around the bottom of the buffer + for _ in 0..3 { + editor.go_to_hunk(&GoToHunk, cx); + } + }); + + cx.assert_editor_state( + &r#" + ˇuse some::modified; + + + fn main() { + println!("hello there"); + + println!("around the"); + println!("world"); + } + "# + .unindent(), + ); + + cx.update_editor(|editor, cx| { + //Wrap around the top of the buffer + for _ in 0..2 { + editor.go_to_prev_hunk(&GoToPrevHunk, cx); + } + }); + + cx.assert_editor_state( + &r#" + use some::modified; + + + fn main() { + ˇ println!("hello there"); + + println!("around the"); + println!("world"); + } + "# + .unindent(), + ); + + cx.update_editor(|editor, cx| { + editor.fold(&Fold, cx); + + //Make sure that the fold only gets one hunk + for _ in 0..4 { + editor.go_to_hunk(&GoToHunk, cx); + } + }); + + cx.assert_editor_state( + &r#" + ˇuse some::modified; + + + fn main() { + println!("hello there"); + + println!("around the"); + println!("world"); + } + "# + .unindent(), + ); } fn empty_range(row: usize, column: usize) -> Range { diff --git a/crates/editor/src/git.rs b/crates/editor/src/git.rs index 0c3302bfba..28db27c6ab 100644 --- a/crates/editor/src/git.rs +++ b/crates/editor/src/git.rs @@ -21,14 +21,32 @@ pub enum DisplayDiffHunk { } impl DisplayDiffHunk { - pub fn display_row_range(&self) -> Range { + pub fn start_display_row(&self) -> u32 { match self { - &DisplayDiffHunk::Folded { display_row } => display_row..display_row + 1, + &DisplayDiffHunk::Folded { display_row } => display_row, DisplayDiffHunk::Unfolded { display_row_range, .. - } => display_row_range.clone(), + } => display_row_range.start, } } + + pub fn contains_display_row(&self, display_row: u32) -> bool { + let range = match self { + &DisplayDiffHunk::Folded { display_row } => display_row..=display_row, + + DisplayDiffHunk::Unfolded { + display_row_range, .. + } => { + if display_row_range.len() == 0 { + display_row_range.start..=display_row_range.end + } else { + display_row_range.start..=display_row_range.end - 1 + } + } + }; + + range.contains(&display_row) + } } pub fn diff_hunk_to_display(hunk: DiffHunk, snapshot: &DisplaySnapshot) -> DisplayDiffHunk { diff --git a/crates/editor/src/test.rs b/crates/editor/src/test.rs index e4146e38bb..48652c44b7 100644 --- a/crates/editor/src/test.rs +++ b/crates/editor/src/test.rs @@ -1,4 +1,3 @@ -pub mod editor_git_test_context; pub mod editor_lsp_test_context; pub mod editor_test_context; diff --git a/crates/editor/src/test/editor_git_test_context.rs b/crates/editor/src/test/editor_git_test_context.rs deleted file mode 100644 index 10f0e002aa..0000000000 --- a/crates/editor/src/test/editor_git_test_context.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use gpui::ModelHandle; -use language::Buffer; -use settings::Settings; - -use crate::MultiBuffer; - -use super::{build_editor, editor_test_context::EditorTestContext}; - -pub struct EditorGitTestContext<'a> { - pub cx: EditorTestContext<'a>, - pub buffer: ModelHandle, -} - -impl<'a> EditorGitTestContext<'a> { - pub async fn new(cx: &'a mut gpui::TestAppContext) -> EditorGitTestContext<'a> { - let (window_id, buffer, editor) = cx.update(|cx| { - cx.set_global(Settings::test(cx)); - crate::init(cx); - - let buffer = cx.add_model(|cx| Buffer::new(0, "", cx)); - let multibuffer = cx.add_model(|cx| MultiBuffer::singleton(buffer.clone(), cx)); - - let (window_id, editor) = - cx.add_window(Default::default(), |cx| build_editor(multibuffer, cx)); - - editor.update(cx, |_, cx| cx.focus_self()); - - (window_id, buffer, editor) - }); - - Self { - cx: EditorTestContext { - cx, - window_id, - editor, - }, - buffer, - } - } -} - -impl<'a> Deref for EditorGitTestContext<'a> { - type Target = EditorTestContext<'a>; - - fn deref(&self) -> &Self::Target { - &self.cx - } -} - -impl<'a> DerefMut for EditorGitTestContext<'a> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.cx - } -} diff --git a/crates/editor/src/test/editor_test_context.rs b/crates/editor/src/test/editor_test_context.rs index 73dc6bfd6e..c55b8b7fdf 100644 --- a/crates/editor/src/test/editor_test_context.rs +++ b/crates/editor/src/test/editor_test_context.rs @@ -151,6 +151,11 @@ impl<'a> EditorTestContext<'a> { snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end) } + pub fn set_diff_base(&mut self, diff_base: Option<&str>) { + let diff_base = diff_base.map(String::from); + self.update_buffer(|buffer, cx| buffer.set_diff_base(diff_base, cx)); + } + /// Change the editor's text and selections using a string containing /// embedded range markers that represent the ranges and directions of /// each selection. diff --git a/crates/language/src/buffer.rs b/crates/language/src/buffer.rs index 3ac4ea9667..41e2c64415 100644 --- a/crates/language/src/buffer.rs +++ b/crates/language/src/buffer.rs @@ -681,7 +681,7 @@ impl Buffer { self.diff_base.as_deref() } - pub fn update_diff_base(&mut self, diff_base: Option, cx: &mut ModelContext) { + pub fn set_diff_base(&mut self, diff_base: Option, cx: &mut ModelContext) { self.diff_base = diff_base; self.git_diff_recalc(cx); } diff --git a/crates/project/src/project.rs b/crates/project/src/project.rs index f11049336b..3ad87ab7a6 100644 --- a/crates/project/src/project.rs +++ b/crates/project/src/project.rs @@ -4410,7 +4410,7 @@ impl Project { .await; let buffer_id = buffer.update(&mut cx, |buffer, cx| { - buffer.update_diff_base(diff_base.clone(), cx); + buffer.set_diff_base(diff_base.clone(), cx); buffer.remote_id() }); @@ -4968,7 +4968,7 @@ impl Project { .and_then(|b| b.upgrade(cx)) .ok_or_else(|| anyhow!("No such buffer {}", buffer_id))?; - buffer.update(cx, |buffer, cx| buffer.update_diff_base(diff_base, cx)); + buffer.update(cx, |buffer, cx| buffer.set_diff_base(diff_base, cx)); Ok(()) })