@@ -899,7 +899,14 @@ impl Pane {
899
899
window : & mut Window ,
900
900
cx : & mut Context < Self > ,
901
901
) {
902
- self . close_items_over_max_tabs ( window, cx) ;
902
+ let item_already_exists = self
903
+ . items
904
+ . iter ( )
905
+ . any ( |existing_item| existing_item. item_id ( ) == item. item_id ( ) ) ;
906
+
907
+ if !item_already_exists {
908
+ self . close_items_over_max_tabs ( window, cx) ;
909
+ }
903
910
904
911
if item. is_singleton ( cx) {
905
912
if let Some ( & entry_id) = item. project_entry_ids ( cx) . first ( ) {
@@ -1404,6 +1411,9 @@ impl Pane {
1404
1411
if let Some ( true ) = self . items . get ( index) . map ( |item| item. is_dirty ( cx) ) {
1405
1412
continue ;
1406
1413
}
1414
+ if self . is_tab_pinned ( index) {
1415
+ continue ;
1416
+ }
1407
1417
1408
1418
index_list. push ( index) ;
1409
1419
items_len -= 1 ;
@@ -2053,13 +2063,15 @@ impl Pane {
2053
2063
self . set_preview_item_id( None , cx) ;
2054
2064
}
2055
2065
2056
- self . workspace
2057
- . update( cx, |_, cx| {
2058
- cx. defer_in( window, move |_, window, cx| {
2059
- move_item( & pane, & pane, id, destination_index, window, cx)
2060
- } ) ;
2061
- } )
2062
- . ok( ) ?;
2066
+ if ix != destination_index {
2067
+ self . workspace
2068
+ . update( cx, |_, cx| {
2069
+ cx. defer_in( window, move |_, window, cx| {
2070
+ move_item( & pane, & pane, id, destination_index, window, cx)
2071
+ } ) ;
2072
+ } )
2073
+ . ok( ) ?;
2074
+ }
2063
2075
2064
2076
Some ( ( ) )
2065
2077
} ) ;
@@ -3789,6 +3801,288 @@ mod tests {
3789
3801
) ;
3790
3802
}
3791
3803
3804
+ #[ gpui:: test]
3805
+ async fn test_allow_pinning_dirty_item_at_max_tabs ( cx : & mut TestAppContext ) {
3806
+ init_test ( cx) ;
3807
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3808
+
3809
+ let project = Project :: test ( fs, None , cx) . await ;
3810
+ let ( workspace, cx) =
3811
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3812
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3813
+
3814
+ set_max_tabs ( cx, Some ( 1 ) ) ;
3815
+ let item_a = add_labeled_item ( & pane, "A" , true , cx) ;
3816
+
3817
+ pane. update_in ( cx, |pane, window, cx| {
3818
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3819
+ pane. pin_tab_at ( ix, window, cx) ;
3820
+ } ) ;
3821
+ assert_item_labels ( & pane, [ "A*^!" ] , cx) ;
3822
+ }
3823
+
3824
+ #[ gpui:: test]
3825
+ async fn test_allow_pinning_non_dirty_item_at_max_tabs ( cx : & mut TestAppContext ) {
3826
+ init_test ( cx) ;
3827
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3828
+
3829
+ let project = Project :: test ( fs, None , cx) . await ;
3830
+ let ( workspace, cx) =
3831
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3832
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3833
+
3834
+ set_max_tabs ( cx, Some ( 1 ) ) ;
3835
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
3836
+
3837
+ pane. update_in ( cx, |pane, window, cx| {
3838
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3839
+ pane. pin_tab_at ( ix, window, cx) ;
3840
+ } ) ;
3841
+ assert_item_labels ( & pane, [ "A*!" ] , cx) ;
3842
+ }
3843
+
3844
+ #[ gpui:: test]
3845
+ async fn test_pin_tabs_incrementally_at_max_capacity ( cx : & mut TestAppContext ) {
3846
+ init_test ( cx) ;
3847
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3848
+
3849
+ let project = Project :: test ( fs, None , cx) . await ;
3850
+ let ( workspace, cx) =
3851
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3852
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3853
+
3854
+ set_max_tabs ( cx, Some ( 3 ) ) ;
3855
+
3856
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
3857
+ assert_item_labels ( & pane, [ "A*" ] , cx) ;
3858
+
3859
+ pane. update_in ( cx, |pane, window, cx| {
3860
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3861
+ pane. pin_tab_at ( ix, window, cx) ;
3862
+ } ) ;
3863
+ assert_item_labels ( & pane, [ "A*!" ] , cx) ;
3864
+
3865
+ let item_b = add_labeled_item ( & pane, "B" , false , cx) ;
3866
+ assert_item_labels ( & pane, [ "A!" , "B*" ] , cx) ;
3867
+
3868
+ pane. update_in ( cx, |pane, window, cx| {
3869
+ let ix = pane. index_for_item_id ( item_b. item_id ( ) ) . unwrap ( ) ;
3870
+ pane. pin_tab_at ( ix, window, cx) ;
3871
+ } ) ;
3872
+ assert_item_labels ( & pane, [ "A!" , "B*!" ] , cx) ;
3873
+
3874
+ let item_c = add_labeled_item ( & pane, "C" , false , cx) ;
3875
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C*" ] , cx) ;
3876
+
3877
+ pane. update_in ( cx, |pane, window, cx| {
3878
+ let ix = pane. index_for_item_id ( item_c. item_id ( ) ) . unwrap ( ) ;
3879
+ pane. pin_tab_at ( ix, window, cx) ;
3880
+ } ) ;
3881
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C*!" ] , cx) ;
3882
+ }
3883
+
3884
+ #[ gpui:: test]
3885
+ async fn test_pin_tabs_left_to_right_after_opening_at_max_capacity ( cx : & mut TestAppContext ) {
3886
+ init_test ( cx) ;
3887
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3888
+
3889
+ let project = Project :: test ( fs, None , cx) . await ;
3890
+ let ( workspace, cx) =
3891
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3892
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3893
+
3894
+ set_max_tabs ( cx, Some ( 3 ) ) ;
3895
+
3896
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
3897
+ assert_item_labels ( & pane, [ "A*" ] , cx) ;
3898
+
3899
+ let item_b = add_labeled_item ( & pane, "B" , false , cx) ;
3900
+ assert_item_labels ( & pane, [ "A" , "B*" ] , cx) ;
3901
+
3902
+ let item_c = add_labeled_item ( & pane, "C" , false , cx) ;
3903
+ assert_item_labels ( & pane, [ "A" , "B" , "C*" ] , cx) ;
3904
+
3905
+ pane. update_in ( cx, |pane, window, cx| {
3906
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3907
+ pane. pin_tab_at ( ix, window, cx) ;
3908
+ } ) ;
3909
+ assert_item_labels ( & pane, [ "A!" , "B" , "C*" ] , cx) ;
3910
+
3911
+ pane. update_in ( cx, |pane, window, cx| {
3912
+ let ix = pane. index_for_item_id ( item_b. item_id ( ) ) . unwrap ( ) ;
3913
+ pane. pin_tab_at ( ix, window, cx) ;
3914
+ } ) ;
3915
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C*" ] , cx) ;
3916
+
3917
+ pane. update_in ( cx, |pane, window, cx| {
3918
+ let ix = pane. index_for_item_id ( item_c. item_id ( ) ) . unwrap ( ) ;
3919
+ pane. pin_tab_at ( ix, window, cx) ;
3920
+ } ) ;
3921
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C*!" ] , cx) ;
3922
+ }
3923
+
3924
+ #[ gpui:: test]
3925
+ async fn test_pin_tabs_right_to_left_after_opening_at_max_capacity ( cx : & mut TestAppContext ) {
3926
+ init_test ( cx) ;
3927
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3928
+
3929
+ let project = Project :: test ( fs, None , cx) . await ;
3930
+ let ( workspace, cx) =
3931
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3932
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3933
+
3934
+ set_max_tabs ( cx, Some ( 3 ) ) ;
3935
+
3936
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
3937
+ assert_item_labels ( & pane, [ "A*" ] , cx) ;
3938
+
3939
+ let item_b = add_labeled_item ( & pane, "B" , false , cx) ;
3940
+ assert_item_labels ( & pane, [ "A" , "B*" ] , cx) ;
3941
+
3942
+ let item_c = add_labeled_item ( & pane, "C" , false , cx) ;
3943
+ assert_item_labels ( & pane, [ "A" , "B" , "C*" ] , cx) ;
3944
+
3945
+ pane. update_in ( cx, |pane, window, cx| {
3946
+ let ix = pane. index_for_item_id ( item_c. item_id ( ) ) . unwrap ( ) ;
3947
+ pane. pin_tab_at ( ix, window, cx) ;
3948
+ } ) ;
3949
+ assert_item_labels ( & pane, [ "C*!" , "A" , "B" ] , cx) ;
3950
+
3951
+ pane. update_in ( cx, |pane, window, cx| {
3952
+ let ix = pane. index_for_item_id ( item_b. item_id ( ) ) . unwrap ( ) ;
3953
+ pane. pin_tab_at ( ix, window, cx) ;
3954
+ } ) ;
3955
+ assert_item_labels ( & pane, [ "C!" , "B*!" , "A" ] , cx) ;
3956
+
3957
+ pane. update_in ( cx, |pane, window, cx| {
3958
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3959
+ pane. pin_tab_at ( ix, window, cx) ;
3960
+ } ) ;
3961
+ assert_item_labels ( & pane, [ "C!" , "B*!" , "A!" ] , cx) ;
3962
+ }
3963
+
3964
+ #[ gpui:: test]
3965
+ async fn test_pinned_tabs_never_closed_at_max_tabs ( cx : & mut TestAppContext ) {
3966
+ init_test ( cx) ;
3967
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
3968
+
3969
+ let project = Project :: test ( fs, None , cx) . await ;
3970
+ let ( workspace, cx) =
3971
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
3972
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
3973
+
3974
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
3975
+ pane. update_in ( cx, |pane, window, cx| {
3976
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
3977
+ pane. pin_tab_at ( ix, window, cx) ;
3978
+ } ) ;
3979
+
3980
+ let item_b = add_labeled_item ( & pane, "B" , false , cx) ;
3981
+ pane. update_in ( cx, |pane, window, cx| {
3982
+ let ix = pane. index_for_item_id ( item_b. item_id ( ) ) . unwrap ( ) ;
3983
+ pane. pin_tab_at ( ix, window, cx) ;
3984
+ } ) ;
3985
+
3986
+ add_labeled_item ( & pane, "C" , false , cx) ;
3987
+ add_labeled_item ( & pane, "D" , false , cx) ;
3988
+ add_labeled_item ( & pane, "E" , false , cx) ;
3989
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C" , "D" , "E*" ] , cx) ;
3990
+
3991
+ set_max_tabs ( cx, Some ( 3 ) ) ;
3992
+ add_labeled_item ( & pane, "F" , false , cx) ;
3993
+ assert_item_labels ( & pane, [ "A!" , "B!" , "F*" ] , cx) ;
3994
+
3995
+ add_labeled_item ( & pane, "G" , false , cx) ;
3996
+ assert_item_labels ( & pane, [ "A!" , "B!" , "G*" ] , cx) ;
3997
+
3998
+ add_labeled_item ( & pane, "H" , false , cx) ;
3999
+ assert_item_labels ( & pane, [ "A!" , "B!" , "H*" ] , cx) ;
4000
+ }
4001
+
4002
+ #[ gpui:: test]
4003
+ async fn test_always_allows_one_unpinned_item_over_max_tabs_regardless_of_pinned_count (
4004
+ cx : & mut TestAppContext ,
4005
+ ) {
4006
+ init_test ( cx) ;
4007
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
4008
+
4009
+ let project = Project :: test ( fs, None , cx) . await ;
4010
+ let ( workspace, cx) =
4011
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
4012
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
4013
+
4014
+ set_max_tabs ( cx, Some ( 3 ) ) ;
4015
+
4016
+ let item_a = add_labeled_item ( & pane, "A" , false , cx) ;
4017
+ pane. update_in ( cx, |pane, window, cx| {
4018
+ let ix = pane. index_for_item_id ( item_a. item_id ( ) ) . unwrap ( ) ;
4019
+ pane. pin_tab_at ( ix, window, cx) ;
4020
+ } ) ;
4021
+
4022
+ let item_b = add_labeled_item ( & pane, "B" , false , cx) ;
4023
+ pane. update_in ( cx, |pane, window, cx| {
4024
+ let ix = pane. index_for_item_id ( item_b. item_id ( ) ) . unwrap ( ) ;
4025
+ pane. pin_tab_at ( ix, window, cx) ;
4026
+ } ) ;
4027
+
4028
+ let item_c = add_labeled_item ( & pane, "C" , false , cx) ;
4029
+ pane. update_in ( cx, |pane, window, cx| {
4030
+ let ix = pane. index_for_item_id ( item_c. item_id ( ) ) . unwrap ( ) ;
4031
+ pane. pin_tab_at ( ix, window, cx) ;
4032
+ } ) ;
4033
+
4034
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C*!" ] , cx) ;
4035
+
4036
+ let item_d = add_labeled_item ( & pane, "D" , false , cx) ;
4037
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C!" , "D*" ] , cx) ;
4038
+
4039
+ pane. update_in ( cx, |pane, window, cx| {
4040
+ let ix = pane. index_for_item_id ( item_d. item_id ( ) ) . unwrap ( ) ;
4041
+ pane. pin_tab_at ( ix, window, cx) ;
4042
+ } ) ;
4043
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C!" , "D*!" ] , cx) ;
4044
+
4045
+ add_labeled_item ( & pane, "E" , false , cx) ;
4046
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C!" , "D!" , "E*" ] , cx) ;
4047
+
4048
+ add_labeled_item ( & pane, "F" , false , cx) ;
4049
+ assert_item_labels ( & pane, [ "A!" , "B!" , "C!" , "D!" , "F*" ] , cx) ;
4050
+ }
4051
+
4052
+ #[ gpui:: test]
4053
+ async fn test_can_open_one_item_when_all_tabs_are_dirty_at_max ( cx : & mut TestAppContext ) {
4054
+ init_test ( cx) ;
4055
+ let fs = FakeFs :: new ( cx. executor ( ) ) ;
4056
+
4057
+ let project = Project :: test ( fs, None , cx) . await ;
4058
+ let ( workspace, cx) =
4059
+ cx. add_window_view ( |window, cx| Workspace :: test_new ( project. clone ( ) , window, cx) ) ;
4060
+ let pane = workspace. read_with ( cx, |workspace, _| workspace. active_pane ( ) . clone ( ) ) ;
4061
+
4062
+ set_max_tabs ( cx, Some ( 3 ) ) ;
4063
+
4064
+ add_labeled_item ( & pane, "A" , true , cx) ;
4065
+ assert_item_labels ( & pane, [ "A*^" ] , cx) ;
4066
+
4067
+ add_labeled_item ( & pane, "B" , true , cx) ;
4068
+ assert_item_labels ( & pane, [ "A^" , "B*^" ] , cx) ;
4069
+
4070
+ add_labeled_item ( & pane, "C" , true , cx) ;
4071
+ assert_item_labels ( & pane, [ "A^" , "B^" , "C*^" ] , cx) ;
4072
+
4073
+ add_labeled_item ( & pane, "D" , false , cx) ;
4074
+ assert_item_labels ( & pane, [ "A^" , "B^" , "C^" , "D*" ] , cx) ;
4075
+
4076
+ add_labeled_item ( & pane, "E" , false , cx) ;
4077
+ assert_item_labels ( & pane, [ "A^" , "B^" , "C^" , "E*" ] , cx) ;
4078
+
4079
+ add_labeled_item ( & pane, "F" , false , cx) ;
4080
+ assert_item_labels ( & pane, [ "A^" , "B^" , "C^" , "F*" ] , cx) ;
4081
+
4082
+ add_labeled_item ( & pane, "G" , true , cx) ;
4083
+ assert_item_labels ( & pane, [ "A^" , "B^" , "C^" , "G*^" ] , cx) ;
4084
+ }
4085
+
3792
4086
#[ gpui:: test]
3793
4087
async fn test_add_item_with_new_item ( cx : & mut TestAppContext ) {
3794
4088
init_test ( cx) ;
0 commit comments