diff --git a/crates/go_to_line/src/go_to_line.rs b/crates/go_to_line/src/go_to_line.rs index 9b0fb6d8c16b0e44b1bbfd1464f44bb7e88b0cde..b9654ab14e1826c6d90c92878bbc4b55d1ef2959 100644 --- a/crates/go_to_line/src/go_to_line.rs +++ b/crates/go_to_line/src/go_to_line.rs @@ -16,7 +16,7 @@ use text::{Bias, Point}; use theme::ActiveTheme; use ui::prelude::*; use util::paths::FILE_ROW_COLUMN_DELIMITER; -use workspace::ModalView; +use workspace::{DismissDecision, ModalView}; pub fn init(cx: &mut App) { LineIndicatorFormat::register(cx); @@ -31,7 +31,16 @@ pub struct GoToLine { _subscriptions: Vec, } -impl ModalView for GoToLine {} +impl ModalView for GoToLine { + fn on_before_dismiss( + &mut self, + _window: &mut Window, + _cx: &mut Context, + ) -> DismissDecision { + self.prev_scroll_position.take(); + DismissDecision::Dismiss(true) + } +} impl Focusable for GoToLine { fn focus_handle(&self, cx: &App) -> FocusHandle { @@ -769,4 +778,171 @@ mod tests { state }) } + + #[gpui::test] + async fn test_scroll_position_on_outside_click(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + let file_content = (0..100) + .map(|i| format!("struct Line{};", i)) + .collect::>() + .join("\n"); + fs.insert_tree(path!("/dir"), json!({"a.rs": file_content})) + .await; + + let project = Project::test(fs, [path!("/dir").as_ref()], cx).await; + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let worktree_id = workspace.update(cx, |workspace, cx| { + workspace.project().update(cx, |project, cx| { + project.worktrees(cx).next().unwrap().read(cx).id() + }) + }); + let _buffer = project + .update(cx, |project, cx| { + project.open_local_buffer(path!("/dir/a.rs"), cx) + }) + .await + .unwrap(); + let editor = workspace + .update_in(cx, |workspace, window, cx| { + workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + let go_to_line_view = open_go_to_line_view(&workspace, cx); + + let scroll_position_before_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + cx.simulate_input("47"); + let scroll_position_after_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_ne!(scroll_position_before_input, scroll_position_after_input); + + drop(go_to_line_view); + workspace.update_in(cx, |workspace, window, cx| { + workspace.hide_modal(window, cx); + }); + cx.run_until_parked(); + + let scroll_position_after_auto_dismiss = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_eq!( + scroll_position_after_auto_dismiss, scroll_position_after_input, + "Dismissing via outside click should maintain new scroll position" + ); + } + + #[gpui::test] + async fn test_scroll_position_on_cancel(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + let file_content = (0..100) + .map(|i| format!("struct Line{};", i)) + .collect::>() + .join("\n"); + fs.insert_tree(path!("/dir"), json!({"a.rs": file_content})) + .await; + + let project = Project::test(fs, [path!("/dir").as_ref()], cx).await; + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let worktree_id = workspace.update(cx, |workspace, cx| { + workspace.project().update(cx, |project, cx| { + project.worktrees(cx).next().unwrap().read(cx).id() + }) + }); + let _buffer = project + .update(cx, |project, cx| { + project.open_local_buffer(path!("/dir/a.rs"), cx) + }) + .await + .unwrap(); + let editor = workspace + .update_in(cx, |workspace, window, cx| { + workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + let go_to_line_view = open_go_to_line_view(&workspace, cx); + + let scroll_position_before_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + cx.simulate_input("47"); + let scroll_position_after_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_ne!(scroll_position_before_input, scroll_position_after_input); + + cx.dispatch_action(menu::Cancel); + drop(go_to_line_view); + cx.run_until_parked(); + + let scroll_position_after_cancel = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_eq!( + scroll_position_after_cancel, scroll_position_after_input, + "Cancel should maintain new scroll position" + ); + } + + #[gpui::test] + async fn test_scroll_position_on_confirm(cx: &mut TestAppContext) { + init_test(cx); + + let fs = FakeFs::new(cx.executor()); + let file_content = (0..100) + .map(|i| format!("struct Line{};", i)) + .collect::>() + .join("\n"); + fs.insert_tree(path!("/dir"), json!({"a.rs": file_content})) + .await; + + let project = Project::test(fs, [path!("/dir").as_ref()], cx).await; + let (workspace, cx) = + cx.add_window_view(|window, cx| Workspace::test_new(project.clone(), window, cx)); + let worktree_id = workspace.update(cx, |workspace, cx| { + workspace.project().update(cx, |project, cx| { + project.worktrees(cx).next().unwrap().read(cx).id() + }) + }); + let _buffer = project + .update(cx, |project, cx| { + project.open_local_buffer(path!("/dir/a.rs"), cx) + }) + .await + .unwrap(); + let editor = workspace + .update_in(cx, |workspace, window, cx| { + workspace.open_path((worktree_id, rel_path("a.rs")), None, true, window, cx) + }) + .await + .unwrap() + .downcast::() + .unwrap(); + let go_to_line_view = open_go_to_line_view(&workspace, cx); + + let scroll_position_before_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + cx.simulate_input("47"); + let scroll_position_after_input = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_ne!(scroll_position_before_input, scroll_position_after_input); + + cx.dispatch_action(menu::Confirm); + drop(go_to_line_view); + cx.run_until_parked(); + + let scroll_position_after_confirm = + editor.update(cx, |editor, cx| editor.scroll_position(cx)); + assert_eq!( + scroll_position_after_confirm, scroll_position_after_input, + "Confirm should maintain new scroll position" + ); + } }