@@ -16,7 +16,7 @@ use text::{Bias, Point};
1616use theme:: ActiveTheme ;
1717use ui:: prelude:: * ;
1818use util:: paths:: FILE_ROW_COLUMN_DELIMITER ;
19- use workspace:: ModalView ;
19+ use workspace:: { DismissDecision , ModalView } ;
2020
2121pub 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
3645impl 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