Rework diff rendering to allow putting the cursor into deleted text, soft-wrapping and scrolling deleted text correctly (#22994)
Closes #12553 * [x] Fix `diff_hunk_before` * [x] Fix failure to show deleted text when expanding hunk w/ cursor on second line of the hunk * [x] Failure to expand diff hunk below the cursor. * [x] Delete the whole file, and expand the diff. Backspace over the deleted hunk, panic! * [x] Go-to-line now counts the diff hunks, but it should not * [x] backspace at the beginning of a deleted hunk deletes too much text * [x] Indent guides are rendered incorrectly * [ ] Fix randomized multi buffer tests Maybe: * [ ] Buffer search should include deleted text (in vim mode it turns out I use `/x` all the time to jump to the next x I can see). * [ ] vim: should refuse to switch into insert mode if selection is fully within a diff. * [ ] vim `o` command when cursor is on last line of deleted hunk. * [ ] vim `shift-o` on first line of deleted hunk moves cursor but doesn't insert line * [x] `enter` at end of diff hunk inserts a new line but doesn't move cursor * [x] (`shift-enter` at start of diff hunk does nothing) * [ ] Inserting a line just before an expanded hunk collapses it Release Notes: - Improved diff rendering, allowing you to navigate with your cursor inside of deleted text in diff hunks. --------- Co-authored-by: Conrad <conrad@zed.dev> Co-authored-by: Cole <cole@zed.dev> Co-authored-by: Mikayla <mikayla@zed.dev> Co-authored-by: Conrad Irwin <conrad.irwin@gmail.com> Co-authored-by: Michael <michael@zed.dev> Co-authored-by: Agus <agus@zed.dev> Co-authored-by: João <joao@zed.dev>
This commit is contained in:
co-authored by
Conrad
Cole
Mikayla
Conrad Irwin
Michael
Agus
João
parent
1fdae4bae0
commit
d2c55cbe3d
+440
-232
@@ -19,11 +19,11 @@ use language::{
|
||||
},
|
||||
BracketPairConfig,
|
||||
Capability::ReadWrite,
|
||||
FakeLspAdapter, IndentGuide, LanguageConfig, LanguageConfigOverride, LanguageMatcher,
|
||||
LanguageName, Override, ParsedMarkdown, Point,
|
||||
FakeLspAdapter, LanguageConfig, LanguageConfigOverride, LanguageMatcher, LanguageName,
|
||||
Override, ParsedMarkdown, Point,
|
||||
};
|
||||
use language_settings::{Formatter, FormatterList, IndentGuideSettings};
|
||||
use multi_buffer::MultiBufferIndentGuide;
|
||||
use multi_buffer::IndentGuide;
|
||||
use parking_lot::Mutex;
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
use project::{buffer_store::BufferChangeSet, FakeFs};
|
||||
@@ -3363,8 +3363,8 @@ async fn test_custom_newlines_cause_no_false_positive_diffs(
|
||||
let snapshot = editor.snapshot(cx);
|
||||
assert_eq!(
|
||||
snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len(), &snapshot.buffer_snapshot)
|
||||
.buffer_snapshot
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len())
|
||||
.collect::<Vec<_>>(),
|
||||
Vec::new(),
|
||||
"Should not have any diffs for files with custom newlines"
|
||||
@@ -5480,6 +5480,109 @@ async fn test_select_larger_smaller_syntax_node(cx: &mut gpui::TestAppContext) {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_fold_function_bodies(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let base_text = r#"
|
||||
impl A {
|
||||
// this is an unstaged comment
|
||||
|
||||
fn b() {
|
||||
c();
|
||||
}
|
||||
|
||||
// this is another unstaged comment
|
||||
|
||||
fn d() {
|
||||
// e
|
||||
// f
|
||||
}
|
||||
}
|
||||
|
||||
fn g() {
|
||||
// h
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let text = r#"
|
||||
ˇimpl A {
|
||||
|
||||
fn b() {
|
||||
c();
|
||||
}
|
||||
|
||||
fn d() {
|
||||
// e
|
||||
// f
|
||||
}
|
||||
}
|
||||
|
||||
fn g() {
|
||||
// h
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
let mut cx = EditorLspTestContext::new_rust(Default::default(), cx).await;
|
||||
cx.set_state(&text);
|
||||
cx.set_diff_base(&base_text);
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_diff_hunks(&Default::default(), cx);
|
||||
});
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
"
|
||||
ˇimpl A {
|
||||
- // this is an unstaged comment
|
||||
|
||||
fn b() {
|
||||
c();
|
||||
}
|
||||
|
||||
- // this is another unstaged comment
|
||||
-
|
||||
fn d() {
|
||||
// e
|
||||
// f
|
||||
}
|
||||
}
|
||||
|
||||
fn g() {
|
||||
// h
|
||||
}
|
||||
"
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
let expected_display_text = "
|
||||
impl A {
|
||||
// this is an unstaged comment
|
||||
|
||||
fn b() {
|
||||
⋯
|
||||
}
|
||||
|
||||
// this is another unstaged comment
|
||||
|
||||
fn d() {
|
||||
⋯
|
||||
}
|
||||
}
|
||||
|
||||
fn g() {
|
||||
⋯
|
||||
}
|
||||
"
|
||||
.unindent();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.fold_function_bodies(&FoldFunctionBodies, cx);
|
||||
assert_eq!(editor.display_text(cx), expected_display_text);
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_autoindent(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@@ -10319,7 +10422,7 @@ async fn test_diagnostics_with_links(cx: &mut TestAppContext) {
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn go_to_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) {
|
||||
async fn test_go_to_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
@@ -10420,7 +10523,26 @@ async fn go_to_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext)
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
for _ in 0..3 {
|
||||
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| {
|
||||
for _ in 0..2 {
|
||||
editor.go_to_prev_hunk(&GoToPrevHunk, cx);
|
||||
}
|
||||
});
|
||||
@@ -10442,11 +10564,10 @@ async fn go_to_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext)
|
||||
|
||||
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_next_hunk(&GoToHunk, cx);
|
||||
}
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
});
|
||||
|
||||
cx.assert_editor_state(
|
||||
@@ -11815,6 +11936,39 @@ async fn test_modification_reverts(cx: &mut gpui::TestAppContext) {
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_deleting_over_diff_hunk(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorLspTestContext::new_rust(lsp::ServerCapabilities::default(), cx).await;
|
||||
let base_text = indoc! {r#"
|
||||
one
|
||||
|
||||
two
|
||||
three
|
||||
"#};
|
||||
|
||||
cx.set_diff_base(base_text);
|
||||
cx.set_state("\nˇ\n");
|
||||
cx.executor().run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_selected_diff_hunks(cx);
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.backspace(&Default::default(), cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
indoc! {r#"
|
||||
|
||||
- two
|
||||
- threeˇ
|
||||
+
|
||||
"#}
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_deletion_reverts(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@@ -12019,13 +12173,11 @@ async fn test_multibuffer_reverts(cx: &mut gpui::TestAppContext) {
|
||||
(buffer_3.clone(), base_text_3),
|
||||
] {
|
||||
let change_set = cx.new_model(|cx| {
|
||||
BufferChangeSet::new_with_base_text(
|
||||
diff_base.to_string(),
|
||||
buffer.read(cx).text_snapshot(),
|
||||
cx,
|
||||
)
|
||||
BufferChangeSet::new_with_base_text(diff_base.to_string(), &buffer, cx)
|
||||
});
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor
|
||||
.buffer
|
||||
.update(cx, |buffer, cx| buffer.add_change_set(change_set, cx));
|
||||
}
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
@@ -12385,7 +12537,10 @@ async fn test_mutlibuffer_in_navigation_history(cx: &mut gpui::TestAppContext) {
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) {
|
||||
async fn test_toggle_selected_diff_hunks(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
@@ -12423,7 +12578,7 @@ async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::Test
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
editor.toggle_hunk_diff(&ToggleHunkDiff, cx);
|
||||
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12443,12 +12598,34 @@ async fn test_toggle_hunk_diff(executor: BackgroundExecutor, cx: &mut gpui::Test
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
for _ in 0..3 {
|
||||
for _ in 0..2 {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
editor.toggle_hunk_diff(&ToggleHunkDiff, cx);
|
||||
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, cx);
|
||||
}
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod;
|
||||
+ ˇuse some::modified;
|
||||
|
||||
|
||||
fn main() {
|
||||
- println!("hello");
|
||||
+ println!("hello there");
|
||||
|
||||
+ println!("around the");
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.go_to_next_hunk(&GoToHunk, cx);
|
||||
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod;
|
||||
@@ -12534,7 +12711,7 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12579,7 +12756,7 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12602,170 +12779,6 @@ async fn test_diff_base_change_with_expanded_diff_hunks(
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_fold_unfold_diff_hunk(executor: BackgroundExecutor, cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
let diff_base = r#"
|
||||
use some::mod1;
|
||||
use some::mod2;
|
||||
|
||||
const A: u32 = 42;
|
||||
const B: u32 = 42;
|
||||
const C: u32 = 42;
|
||||
|
||||
fn main() {
|
||||
println!("hello");
|
||||
|
||||
println!("world");
|
||||
}
|
||||
|
||||
fn another() {
|
||||
println!("another");
|
||||
}
|
||||
|
||||
fn another2() {
|
||||
println!("another2");
|
||||
}
|
||||
"#
|
||||
.unindent();
|
||||
|
||||
cx.set_state(
|
||||
&r#"
|
||||
«use some::mod2;
|
||||
|
||||
const A: u32 = 42;
|
||||
const C: u32 = 42;
|
||||
|
||||
fn main() {
|
||||
//println!("hello");
|
||||
|
||||
println!("world");
|
||||
//
|
||||
//ˇ»
|
||||
}
|
||||
|
||||
fn another() {
|
||||
println!("another");
|
||||
println!("another");
|
||||
}
|
||||
|
||||
println!("another2");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.set_diff_base(&diff_base);
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod1;
|
||||
«use some::mod2;
|
||||
|
||||
const A: u32 = 42;
|
||||
- const B: u32 = 42;
|
||||
const C: u32 = 42;
|
||||
|
||||
fn main() {
|
||||
- println!("hello");
|
||||
+ //println!("hello");
|
||||
|
||||
println!("world");
|
||||
+ //
|
||||
+ //ˇ»
|
||||
}
|
||||
|
||||
fn another() {
|
||||
println!("another");
|
||||
+ println!("another");
|
||||
}
|
||||
|
||||
- fn another2() {
|
||||
println!("another2");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
// Fold across some of the diff hunks. They should no longer appear expanded.
|
||||
cx.update_editor(|editor, cx| editor.fold_selected_ranges(&FoldSelectedRanges, cx));
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
// Hunks are not shown if their position is within a fold
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
«use some::mod2;
|
||||
|
||||
const A: u32 = 42;
|
||||
const C: u32 = 42;
|
||||
|
||||
fn main() {
|
||||
//println!("hello");
|
||||
|
||||
println!("world");
|
||||
//
|
||||
//ˇ»
|
||||
}
|
||||
|
||||
fn another() {
|
||||
println!("another");
|
||||
+ println!("another");
|
||||
}
|
||||
|
||||
- fn another2() {
|
||||
println!("another2");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.select_all(&SelectAll, cx);
|
||||
editor.unfold_lines(&UnfoldLines, cx);
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
// The deletions reappear when unfolding.
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
- use some::mod1;
|
||||
«use some::mod2;
|
||||
|
||||
const A: u32 = 42;
|
||||
- const B: u32 = 42;
|
||||
const C: u32 = 42;
|
||||
|
||||
fn main() {
|
||||
- println!("hello");
|
||||
+ //println!("hello");
|
||||
|
||||
println!("world");
|
||||
+ //
|
||||
+ //
|
||||
}
|
||||
|
||||
fn another() {
|
||||
println!("another");
|
||||
+ println!("another");
|
||||
}
|
||||
|
||||
- fn another2() {
|
||||
println!("another2");
|
||||
}
|
||||
ˇ»"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@@ -12849,13 +12862,11 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext)
|
||||
(buffer_3.clone(), file_3_old),
|
||||
] {
|
||||
let change_set = cx.new_model(|cx| {
|
||||
BufferChangeSet::new_with_base_text(
|
||||
diff_base.to_string(),
|
||||
buffer.read(cx).text_snapshot(),
|
||||
cx,
|
||||
)
|
||||
BufferChangeSet::new_with_base_text(diff_base.to_string(), &buffer, cx)
|
||||
});
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
editor
|
||||
.buffer
|
||||
.update(cx, |buffer, cx| buffer.add_change_set(change_set, cx));
|
||||
}
|
||||
})
|
||||
.unwrap();
|
||||
@@ -12895,7 +12906,7 @@ async fn test_toggle_diff_expand_in_multi_buffer(cx: &mut gpui::TestAppContext)
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.select_all(&SelectAll, cx);
|
||||
editor.toggle_hunk_diff(&ToggleHunkDiff, cx);
|
||||
editor.toggle_selected_diff_hunks(&ToggleSelectedDiffHunks, cx);
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
@@ -12962,17 +12973,18 @@ async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut gpui::TestAppContext
|
||||
let editor = cx.add_window(|cx| Editor::new(EditorMode::Full, multi_buffer, None, true, cx));
|
||||
editor
|
||||
.update(cx, |editor, cx| {
|
||||
let buffer = buffer.read(cx).text_snapshot();
|
||||
let change_set = cx
|
||||
.new_model(|cx| BufferChangeSet::new_with_base_text(base.to_string(), buffer, cx));
|
||||
editor.diff_map.add_change_set(change_set, cx)
|
||||
.new_model(|cx| BufferChangeSet::new_with_base_text(base.to_string(), &buffer, cx));
|
||||
editor
|
||||
.buffer
|
||||
.update(cx, |buffer, cx| buffer.add_change_set(change_set, cx))
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let mut cx = EditorTestContext::for_editor(editor, cx).await;
|
||||
cx.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| editor.expand_all_hunk_diffs(&Default::default(), cx));
|
||||
cx.update_editor(|editor, cx| editor.expand_all_diff_hunks(&Default::default(), cx));
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
@@ -12981,8 +12993,6 @@ async fn test_expand_diff_hunk_at_excerpt_boundary(cx: &mut gpui::TestAppContext
|
||||
- bbb
|
||||
+ BBB
|
||||
|
||||
- ddd
|
||||
- eee
|
||||
+ EEE
|
||||
fff
|
||||
"
|
||||
@@ -13036,7 +13046,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -13055,7 +13065,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13078,7 +13088,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13102,7 +13112,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13127,7 +13137,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13153,7 +13163,7 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13164,21 +13174,63 @@ async fn test_edits_around_expanded_insertion_hunks(
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
use some::mod1;
|
||||
- use some::mod2;
|
||||
-
|
||||
- const A: u32 = 42;
|
||||
ˇ
|
||||
fn main() {
|
||||
println!("hello");
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_toggling_adjacent_diff_hunks(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
cx.set_diff_base(indoc! { "
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
"
|
||||
});
|
||||
cx.set_state(indoc! { "
|
||||
one
|
||||
ˇthree
|
||||
five
|
||||
"});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.toggle_selected_diff_hunks(&Default::default(), cx);
|
||||
});
|
||||
cx.assert_state_with_diff(
|
||||
indoc! { "
|
||||
one
|
||||
- two
|
||||
ˇthree
|
||||
- four
|
||||
five
|
||||
"}
|
||||
.to_string(),
|
||||
);
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.toggle_selected_diff_hunks(&Default::default(), cx);
|
||||
});
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
indoc! { "
|
||||
one
|
||||
ˇthree
|
||||
five
|
||||
"}
|
||||
.to_string(),
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_edits_around_expanded_deletion_hunks(
|
||||
executor: BackgroundExecutor,
|
||||
@@ -13227,7 +13279,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -13246,7 +13298,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13269,7 +13321,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13292,7 +13344,7 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
@@ -13316,6 +13368,71 @@ async fn test_edits_around_expanded_deletion_hunks(
|
||||
|
||||
println!("world");
|
||||
}
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_backspace_after_deletion_hunk(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
let base_text = r#"
|
||||
one
|
||||
two
|
||||
three
|
||||
four
|
||||
five
|
||||
"#
|
||||
.unindent();
|
||||
executor.run_until_parked();
|
||||
cx.set_state(
|
||||
&r#"
|
||||
one
|
||||
two
|
||||
fˇour
|
||||
five
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.set_diff_base(&base_text);
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
one
|
||||
two
|
||||
- three
|
||||
fˇour
|
||||
five
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.backspace(&Backspace, cx);
|
||||
editor.backspace(&Backspace, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
cx.assert_state_with_diff(
|
||||
r#"
|
||||
one
|
||||
two
|
||||
- threeˇ
|
||||
- four
|
||||
+ our
|
||||
five
|
||||
"#
|
||||
.unindent(),
|
||||
);
|
||||
@@ -13369,7 +13486,7 @@ async fn test_edit_after_expanded_modification_hunk(
|
||||
cx.set_diff_base(&diff_base);
|
||||
executor.run_until_parked();
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.expand_all_hunk_diffs(&ExpandAllHunkDiffs, cx);
|
||||
editor.expand_all_diff_hunks(&ExpandAllHunkDiffs, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
@@ -13478,22 +13595,14 @@ fn assert_indent_guides(
|
||||
);
|
||||
}
|
||||
|
||||
let expected: Vec<_> = expected
|
||||
.into_iter()
|
||||
.map(|guide| MultiBufferIndentGuide {
|
||||
multibuffer_row_range: MultiBufferRow(guide.start_row)..MultiBufferRow(guide.end_row),
|
||||
buffer: guide,
|
||||
})
|
||||
.collect();
|
||||
|
||||
assert_eq!(indent_guides, expected, "Indent guides do not match");
|
||||
}
|
||||
|
||||
fn indent_guide(buffer_id: BufferId, start_row: u32, end_row: u32, depth: u32) -> IndentGuide {
|
||||
IndentGuide {
|
||||
buffer_id,
|
||||
start_row,
|
||||
end_row,
|
||||
start_row: MultiBufferRow(start_row),
|
||||
end_row: MultiBufferRow(end_row),
|
||||
depth,
|
||||
tab_size: 4,
|
||||
settings: IndentGuideSettings {
|
||||
@@ -13945,6 +14054,105 @@ async fn test_active_indent_guide_non_matching_indent(cx: &mut gpui::TestAppCont
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_indent_guide_with_expanded_diff_hunks(cx: &mut gpui::TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
let text = indoc! {
|
||||
"
|
||||
impl A {
|
||||
fn b() {
|
||||
0;
|
||||
3;
|
||||
5;
|
||||
6;
|
||||
7;
|
||||
}
|
||||
}
|
||||
"
|
||||
};
|
||||
let base_text = indoc! {
|
||||
"
|
||||
impl A {
|
||||
fn b() {
|
||||
0;
|
||||
1;
|
||||
2;
|
||||
3;
|
||||
4;
|
||||
}
|
||||
fn c() {
|
||||
5;
|
||||
6;
|
||||
7;
|
||||
}
|
||||
}
|
||||
"
|
||||
};
|
||||
|
||||
cx.update_editor(|editor, cx| {
|
||||
editor.set_text(text, cx);
|
||||
|
||||
editor.buffer().update(cx, |multibuffer, cx| {
|
||||
let buffer = multibuffer.as_singleton().unwrap();
|
||||
let change_set = cx.new_model(|cx| {
|
||||
let mut change_set = BufferChangeSet::new(&buffer, cx);
|
||||
change_set.recalculate_diff_sync(
|
||||
base_text.into(),
|
||||
buffer.read(cx).text_snapshot(),
|
||||
true,
|
||||
cx,
|
||||
);
|
||||
change_set
|
||||
});
|
||||
|
||||
multibuffer.set_all_diff_hunks_expanded(cx);
|
||||
multibuffer.add_change_set(change_set, cx);
|
||||
|
||||
buffer.read(cx).remote_id()
|
||||
})
|
||||
});
|
||||
|
||||
cx.assert_state_with_diff(
|
||||
indoc! { "
|
||||
impl A {
|
||||
fn b() {
|
||||
0;
|
||||
- 1;
|
||||
- 2;
|
||||
3;
|
||||
- 4;
|
||||
- }
|
||||
- fn c() {
|
||||
5;
|
||||
6;
|
||||
7;
|
||||
}
|
||||
}
|
||||
ˇ"
|
||||
}
|
||||
.to_string(),
|
||||
);
|
||||
|
||||
let mut actual_guides = cx.update_editor(|editor, cx| {
|
||||
editor
|
||||
.snapshot(cx)
|
||||
.buffer_snapshot
|
||||
.indent_guides_in_range(Anchor::min()..Anchor::max(), false, cx)
|
||||
.map(|guide| (guide.start_row..=guide.end_row, guide.depth))
|
||||
.collect::<Vec<_>>()
|
||||
});
|
||||
actual_guides.sort_by_key(|item| (*item.0.start(), item.1));
|
||||
assert_eq!(
|
||||
actual_guides,
|
||||
vec![
|
||||
(MultiBufferRow(1)..=MultiBufferRow(12), 0),
|
||||
(MultiBufferRow(2)..=MultiBufferRow(6), 1),
|
||||
(MultiBufferRow(9)..=MultiBufferRow(11), 1),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_crease_insertion_and_rendering(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
@@ -15229,7 +15437,7 @@ pub(crate) fn init_test(cx: &mut TestAppContext, f: fn(&mut AllLanguageSettingsC
|
||||
#[track_caller]
|
||||
fn assert_hunk_revert(
|
||||
not_reverted_text_with_selections: &str,
|
||||
expected_not_reverted_hunk_statuses: Vec<DiffHunkStatus>,
|
||||
expected_hunk_statuses_before: Vec<DiffHunkStatus>,
|
||||
expected_reverted_text_with_selections: &str,
|
||||
base_text: &str,
|
||||
cx: &mut EditorLspTestContext,
|
||||
@@ -15238,12 +15446,12 @@ fn assert_hunk_revert(
|
||||
cx.set_diff_base(base_text);
|
||||
cx.executor().run_until_parked();
|
||||
|
||||
let reverted_hunk_statuses = cx.update_editor(|editor, cx| {
|
||||
let actual_hunk_statuses_before = cx.update_editor(|editor, cx| {
|
||||
let snapshot = editor.snapshot(cx);
|
||||
let reverted_hunk_statuses = snapshot
|
||||
.diff_map
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len(), &snapshot.buffer_snapshot)
|
||||
.map(|hunk| hunk_status(&hunk))
|
||||
.buffer_snapshot
|
||||
.diff_hunks_in_range(0..snapshot.buffer_snapshot.len())
|
||||
.map(|hunk| hunk.status())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
editor.revert_selected_hunks(&RevertSelectedHunks, cx);
|
||||
@@ -15251,5 +15459,5 @@ fn assert_hunk_revert(
|
||||
});
|
||||
cx.executor().run_until_parked();
|
||||
cx.assert_editor_state(expected_reverted_text_with_selections);
|
||||
assert_eq!(reverted_hunk_statuses, expected_not_reverted_hunk_statuses);
|
||||
assert_eq!(actual_hunk_statuses_before, expected_hunk_statuses_before);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user