Skip to content

Commit 8725a2d

Browse files
authored
go_to_line: Fix scroll position restore on dismiss (#41234)
Closes #35347 Release Notes: - Fixed Go To Line jumping back to previous position on dismiss
1 parent f9c97d2 commit 8725a2d

File tree

1 file changed

+178
-2
lines changed

1 file changed

+178
-2
lines changed

crates/go_to_line/src/go_to_line.rs

Lines changed: 178 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use text::{Bias, Point};
1616
use theme::ActiveTheme;
1717
use ui::prelude::*;
1818
use util::paths::FILE_ROW_COLUMN_DELIMITER;
19-
use workspace::ModalView;
19+
use workspace::{DismissDecision, ModalView};
2020

2121
pub fn init(cx: &mut App) {
2222
LineIndicatorFormat::register(cx);
@@ -31,7 +31,16 @@ pub struct GoToLine {
3131
_subscriptions: Vec<Subscription>,
3232
}
3333

34-
impl ModalView for GoToLine {}
34+
impl ModalView for GoToLine {
35+
fn on_before_dismiss(
36+
&mut self,
37+
_window: &mut Window,
38+
_cx: &mut Context<Self>,
39+
) -> DismissDecision {
40+
self.prev_scroll_position.take();
41+
DismissDecision::Dismiss(true)
42+
}
43+
}
3544

3645
impl Focusable for GoToLine {
3746
fn focus_handle(&self, cx: &App) -> FocusHandle {
@@ -769,4 +778,171 @@ mod tests {
769778
state
770779
})
771780
}
781+
782+
#[gpui::test]
783+
async fn test_scroll_position_on_outside_click(cx: &mut TestAppContext) {
784+
init_test(cx);
785+
786+
let fs = FakeFs::new(cx.executor());
787+
let file_content = (0..100)
788+
.map(|i| format!("struct Line{};", i))
789+
.collect::<Vec<_>>()
790+
.join("\n");
791+
fs.insert_tree(path!("/dir"), json!({"a.rs": file_content}))
792+
.await;
793+
794+
let project = Project::test(fs, [path!("/dir").as_ref()], cx).await;
795+
let (workspace, cx) =
796+
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
797+
let worktree_id = workspace.update(cx, |workspace, cx| {
798+
workspace.project().update(cx, |project, cx| {
799+
project.worktrees(cx).next().unwrap().read(cx).id()
800+
})
801+
});
802+
let _buffer = project
803+
.update(cx, |project, cx| {
804+
project.open_local_buffer(path!("/dir/a.rs"), cx)
805+
})
806+
.await
807+
.unwrap();
808+
let editor = workspace
809+
.update_in(cx, |workspace, window, cx| {
810+
workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx)
811+
})
812+
.await
813+
.unwrap()
814+
.downcast::<Editor>()
815+
.unwrap();
816+
let go_to_line_view = open_go_to_line_view(&workspace, cx);
817+
818+
let scroll_position_before_input =
819+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
820+
cx.simulate_input("47");
821+
let scroll_position_after_input =
822+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
823+
assert_ne!(scroll_position_before_input, scroll_position_after_input);
824+
825+
drop(go_to_line_view);
826+
workspace.update_in(cx, |workspace, window, cx| {
827+
workspace.hide_modal(window, cx);
828+
});
829+
cx.run_until_parked();
830+
831+
let scroll_position_after_auto_dismiss =
832+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
833+
assert_eq!(
834+
scroll_position_after_auto_dismiss, scroll_position_after_input,
835+
"Dismissing via outside click should maintain new scroll position"
836+
);
837+
}
838+
839+
#[gpui::test]
840+
async fn test_scroll_position_on_cancel(cx: &mut TestAppContext) {
841+
init_test(cx);
842+
843+
let fs = FakeFs::new(cx.executor());
844+
let file_content = (0..100)
845+
.map(|i| format!("struct Line{};", i))
846+
.collect::<Vec<_>>()
847+
.join("\n");
848+
fs.insert_tree(path!("/dir"), json!({"a.rs": file_content}))
849+
.await;
850+
851+
let project = Project::test(fs, [path!("/dir").as_ref()], cx).await;
852+
let (workspace, cx) =
853+
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
854+
let worktree_id = workspace.update(cx, |workspace, cx| {
855+
workspace.project().update(cx, |project, cx| {
856+
project.worktrees(cx).next().unwrap().read(cx).id()
857+
})
858+
});
859+
let _buffer = project
860+
.update(cx, |project, cx| {
861+
project.open_local_buffer(path!("/dir/a.rs"), cx)
862+
})
863+
.await
864+
.unwrap();
865+
let editor = workspace
866+
.update_in(cx, |workspace, window, cx| {
867+
workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx)
868+
})
869+
.await
870+
.unwrap()
871+
.downcast::<Editor>()
872+
.unwrap();
873+
let go_to_line_view = open_go_to_line_view(&workspace, cx);
874+
875+
let scroll_position_before_input =
876+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
877+
cx.simulate_input("47");
878+
let scroll_position_after_input =
879+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
880+
assert_ne!(scroll_position_before_input, scroll_position_after_input);
881+
882+
cx.dispatch_action(menu::Cancel);
883+
drop(go_to_line_view);
884+
cx.run_until_parked();
885+
886+
let scroll_position_after_cancel =
887+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
888+
assert_eq!(
889+
scroll_position_after_cancel, scroll_position_after_input,
890+
"Cancel should maintain new scroll position"
891+
);
892+
}
893+
894+
#[gpui::test]
895+
async fn test_scroll_position_on_confirm(cx: &mut TestAppContext) {
896+
init_test(cx);
897+
898+
let fs = FakeFs::new(cx.executor());
899+
let file_content = (0..100)
900+
.map(|i| format!("struct Line{};", i))
901+
.collect::<Vec<_>>()
902+
.join("\n");
903+
fs.insert_tree(path!("/dir"), json!({"a.rs": file_content}))
904+
.await;
905+
906+
let project = Project::test(fs, [path!("/dir").as_ref()], cx).await;
907+
let (workspace, cx) =
908+
cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx));
909+
let worktree_id = workspace.update(cx, |workspace, cx| {
910+
workspace.project().update(cx, |project, cx| {
911+
project.worktrees(cx).next().unwrap().read(cx).id()
912+
})
913+
});
914+
let _buffer = project
915+
.update(cx, |project, cx| {
916+
project.open_local_buffer(path!("/dir/a.rs"), cx)
917+
})
918+
.await
919+
.unwrap();
920+
let editor = workspace
921+
.update_in(cx, |workspace, window, cx| {
922+
workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx)
923+
})
924+
.await
925+
.unwrap()
926+
.downcast::<Editor>()
927+
.unwrap();
928+
let go_to_line_view = open_go_to_line_view(&workspace, cx);
929+
930+
let scroll_position_before_input =
931+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
932+
cx.simulate_input("47");
933+
let scroll_position_after_input =
934+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
935+
assert_ne!(scroll_position_before_input, scroll_position_after_input);
936+
937+
cx.dispatch_action(menu::Confirm);
938+
drop(go_to_line_view);
939+
cx.run_until_parked();
940+
941+
let scroll_position_after_confirm =
942+
editor.update(cx, |editor, cx| editor.scroll_position(cx));
943+
assert_eq!(
944+
scroll_position_after_confirm, scroll_position_after_input,
945+
"Confirm should maintain new scroll position"
946+
);
947+
}
772948
}

0 commit comments

Comments
 (0)