editor: Fix sticky headers not accounting for deleted diff hunks (#49296)
Release Notes: - Fixed sticky headers sometimes disappearing when dealing with expanded deleted diff hunks
This commit is contained in:
1 parent
e9a8ef1c9e
commit
f21d51cf00
2 files changed
+98
-8
No files matched your search
@@ -200,7 +200,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
use task::{ResolvedTask, RunnableTag, TaskTemplate, TaskVariables};
|
||||
use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _};
|
||||
use text::{BufferId, FromAnchor, OffsetUtf16, Rope, ToOffset as _, ToPoint as _};
|
||||
use theme::{
|
||||
AccentColors, ActiveTheme, GlobalTheme, PlayerColor, StatusColors, SyntaxTheme, Theme,
|
||||
ThemeSettings, observe_buffer_font_size_adjustment,
|
||||
@@ -1992,20 +1992,21 @@ impl Editor {
|
||||
return;
|
||||
}
|
||||
let multi_buffer = display_snapshot.buffer_snapshot();
|
||||
let multi_buffer_visible_start = self
|
||||
let scroll_anchor = self
|
||||
.scroll_manager
|
||||
.native_anchor(display_snapshot, cx)
|
||||
.anchor
|
||||
.to_point(&multi_buffer);
|
||||
let max_row = multi_buffer.max_point().row;
|
||||
|
||||
let start_row = (multi_buffer_visible_start.row).min(max_row);
|
||||
let end_row = (multi_buffer_visible_start.row + 10).min(max_row);
|
||||
.anchor;
|
||||
let Some((excerpt_id, _, buffer)) = multi_buffer.as_singleton() else {
|
||||
return;
|
||||
};
|
||||
let buffer = buffer.clone();
|
||||
let &excerpt_id = excerpt_id;
|
||||
|
||||
let buffer_visible_start = scroll_anchor.text_anchor.to_point(&buffer);
|
||||
let max_row = buffer.max_point().row;
|
||||
let start_row = buffer_visible_start.row.min(max_row);
|
||||
let end_row = (buffer_visible_start.row + 10).min(max_row);
|
||||
|
||||
let syntax = self.style(cx).syntax.clone();
|
||||
let background_task = cx.background_spawn(async move {
|
||||
buffer
|
||||
|
||||
@@ -29058,6 +29058,95 @@ async fn test_sticky_scroll(cx: &mut TestAppContext) {
|
||||
assert_eq!(sticky_headers(10.0), vec![]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_sticky_scroll_with_expanded_deleted_diff_hunks(
|
||||
executor: BackgroundExecutor,
|
||||
cx: &mut TestAppContext,
|
||||
) {
|
||||
init_test(cx, |_| {});
|
||||
let mut cx = EditorTestContext::new(cx).await;
|
||||
|
||||
let diff_base = indoc! {"
|
||||
fn foo() {
|
||||
let a = 1;
|
||||
let b = 2;
|
||||
let c = 3;
|
||||
let d = 4;
|
||||
let e = 5;
|
||||
}
|
||||
"};
|
||||
|
||||
let buffer = indoc! {"
|
||||
ˇfn foo() {
|
||||
}
|
||||
"};
|
||||
|
||||
cx.set_state(&buffer);
|
||||
|
||||
cx.update_editor(|e, _, cx| {
|
||||
e.buffer()
|
||||
.read(cx)
|
||||
.as_singleton()
|
||||
.unwrap()
|
||||
.update(cx, |buffer, cx| {
|
||||
buffer.set_language(Some(rust_lang()), cx);
|
||||
})
|
||||
});
|
||||
|
||||
cx.set_head_text(diff_base);
|
||||
executor.run_until_parked();
|
||||
|
||||
cx.update_editor(|editor, window, cx| {
|
||||
editor.expand_all_diff_hunks(&ExpandAllDiffHunks, window, cx);
|
||||
});
|
||||
executor.run_until_parked();
|
||||
|
||||
// After expanding, the display should look like:
|
||||
// row 0: fn foo() {
|
||||
// row 1: - let a = 1; (deleted)
|
||||
// row 2: - let b = 2; (deleted)
|
||||
// row 3: - let c = 3; (deleted)
|
||||
// row 4: - let d = 4; (deleted)
|
||||
// row 5: - let e = 5; (deleted)
|
||||
// row 6: }
|
||||
//
|
||||
// fn foo() spans display rows 0-6. Scrolling into the deleted region
|
||||
// (rows 1-5) should still show fn foo() as a sticky header.
|
||||
|
||||
let fn_foo = Point { row: 0, column: 0 };
|
||||
|
||||
let mut sticky_headers = |offset: ScrollOffset| {
|
||||
cx.update_editor(|e, window, cx| {
|
||||
e.scroll(gpui::Point { x: 0., y: offset }, None, window, cx);
|
||||
});
|
||||
cx.run_until_parked();
|
||||
cx.update_editor(|e, window, cx| {
|
||||
EditorElement::sticky_headers(&e, &e.snapshot(window, cx))
|
||||
.into_iter()
|
||||
.map(
|
||||
|StickyHeader {
|
||||
start_point,
|
||||
offset,
|
||||
..
|
||||
}| { (start_point, offset) },
|
||||
)
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
};
|
||||
|
||||
assert_eq!(sticky_headers(0.0), vec![]);
|
||||
assert_eq!(sticky_headers(0.5), vec![(fn_foo, 0.0)]);
|
||||
assert_eq!(sticky_headers(1.0), vec![(fn_foo, 0.0)]);
|
||||
// Scrolling into deleted lines: fn foo() should still be a sticky header.
|
||||
assert_eq!(sticky_headers(2.0), vec![(fn_foo, 0.0)]);
|
||||
assert_eq!(sticky_headers(3.0), vec![(fn_foo, 0.0)]);
|
||||
assert_eq!(sticky_headers(4.0), vec![(fn_foo, 0.0)]);
|
||||
assert_eq!(sticky_headers(5.0), vec![(fn_foo, 0.0)]);
|
||||
assert_eq!(sticky_headers(5.5), vec![(fn_foo, -0.5)]);
|
||||
// Past the closing brace: no more sticky header.
|
||||
assert_eq!(sticky_headers(6.0), vec![]);
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
fn test_relative_line_numbers(cx: &mut TestAppContext) {
|
||||
init_test(cx, |_| {});
|
||||
|
||||
Reference in new issue
Block a user