comparison src/arglist.c @ 30104:dd97e797fffb v9.0.0388

patch 9.0.0388: the do_arg_all() function is too long Commit: https://github.com/vim/vim/commit/8894761daf68220504932c8b3e75f59138cdb617 Author: Yegappan Lakshmanan <yegappan@yahoo.com> Date: Mon Sep 5 18:27:47 2022 +0100 patch 9.0.0388: the do_arg_all() function is too long Problem: The do_arg_all() function is too long. Solution: Split the function in smaller parts. (Yegappan Lakshmanan, closes #11062)
author Bram Moolenaar <Bram@vim.org>
date Mon, 05 Sep 2022 19:30:03 +0200
parents 84c18beec6bc
children 58fb880f3607
comparison
equal deleted inserted replaced
30103:ec4ce9c64e2b 30104:dd97e797fffb
572 ALIST(curwin) = &global_alist; 572 ALIST(curwin) = &global_alist;
573 else // eap->cmdidx == CMD_arglocal 573 else // eap->cmdidx == CMD_arglocal
574 alist_new(); 574 alist_new();
575 } 575 }
576 576
577 // ":args file ..": define new argument list, handle like ":next"
578 // Also for ":argslocal file .." and ":argsglobal file ..".
577 if (*eap->arg != NUL) 579 if (*eap->arg != NUL)
578 { 580 {
579 if (check_arglist_locked() == FAIL) 581 if (check_arglist_locked() == FAIL)
580 return; 582 return;
581 // ":args file ..": define new argument list, handle like ":next"
582 // Also for ":argslocal file .." and ":argsglobal file ..".
583 ex_next(eap); 583 ex_next(eap);
584 } 584 return;
585 else if (eap->cmdidx == CMD_args) 585 }
586
587 // ":args": list arguments.
588 if (eap->cmdidx == CMD_args)
586 { 589 {
587 char_u **items; 590 char_u **items;
588 591
589 // ":args": list arguments.
590 if (ARGCOUNT <= 0) 592 if (ARGCOUNT <= 0)
591 return; 593 return; // empty argument list
592 594
593 items = ALLOC_MULT(char_u *, ARGCOUNT); 595 items = ALLOC_MULT(char_u *, ARGCOUNT);
594 if (items == NULL) 596 if (items == NULL)
595 return; 597 return;
596 598
600 602
601 for (i = 0; i < ARGCOUNT; ++i) 603 for (i = 0; i < ARGCOUNT; ++i)
602 items[i] = alist_name(&ARGLIST[i]); 604 items[i] = alist_name(&ARGLIST[i]);
603 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); 605 list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
604 vim_free(items); 606 vim_free(items);
605 } 607
606 else if (eap->cmdidx == CMD_arglocal) 608 return;
609 }
610
611 // ":argslocal": make a local copy of the global argument list.
612 if (eap->cmdidx == CMD_arglocal)
607 { 613 {
608 garray_T *gap = &curwin->w_alist->al_ga; 614 garray_T *gap = &curwin->w_alist->al_ga;
609 615
610 // ":argslocal": make a local copy of the global argument list.
611 if (GA_GROW_FAILS(gap, GARGCOUNT)) 616 if (GA_GROW_FAILS(gap, GARGCOUNT))
612 return; 617 return;
613 618
614 for (i = 0; i < GARGCOUNT; ++i) 619 for (i = 0; i < GARGCOUNT; ++i)
615 if (GARGLIST[i].ae_fname != NULL) 620 if (GARGLIST[i].ae_fname != NULL)
917 return aep->ae_fname; 922 return aep->ae_fname;
918 return bp->b_fname; 923 return bp->b_fname;
919 } 924 }
920 925
921 /* 926 /*
922 * do_arg_all(): Open up to 'count' windows, one for each argument. 927 * State used by the :all command to open all the files in the argument list in
923 */ 928 * separate windows.
924 static void 929 */
925 do_arg_all( 930 typedef struct {
926 int count, 931 alist_T *alist; // argument list to be used
927 int forceit, // hide buffers in current windows 932 int had_tab;
928 int keep_tabs) // keep current tabs, for ":tab drop file" 933 int keep_tabs;
929 { 934 int forceit;
930 int i; 935
931 win_T *wp, *wpnext; 936 int use_firstwin; // use first window for arglist
932 char_u *opened; // Array of weight for which args are open: 937 char_u *opened; // Array of weight for which args are open:
933 // 0: not opened 938 // 0: not opened
934 // 1: opened in other tab 939 // 1: opened in other tab
935 // 2: opened in curtab 940 // 2: opened in curtab
936 // 3: opened in curtab and curwin 941 // 3: opened in curtab and curwin
937 //
938 int opened_len; // length of opened[] 942 int opened_len; // length of opened[]
939 int use_firstwin = FALSE; // use first window for arglist 943 win_T *new_curwin;
940 int tab_drop_empty_window = FALSE; 944 tabpage_T *new_curtab;
941 int split_ret = OK; 945 } arg_all_state_T;
942 int p_ea_save; 946
943 alist_T *alist; // argument list to be used 947 /*
948 * Close all the windows containing files which are not in the argument list.
949 * Used by the ":all" command.
950 */
951 static void
952 arg_all_close_unused_windows(arg_all_state_T *aall)
953 {
954 win_T *wp;
955 win_T *wpnext;
956 tabpage_T *tpnext;
944 buf_T *buf; 957 buf_T *buf;
945 tabpage_T *tpnext; 958 int i;
946 int had_tab = cmdmod.cmod_tab; 959 win_T *old_curwin;
947 win_T *old_curwin, *last_curwin; 960 tabpage_T *old_curtab;
948 tabpage_T *old_curtab, *last_curtab;
949 win_T *new_curwin = NULL;
950 tabpage_T *new_curtab = NULL;
951 int prev_arglist_locked = arglist_locked;
952
953 #ifdef FEAT_CMDWIN
954 if (cmdwin_type != 0)
955 {
956 emsg(_(e_invalid_in_cmdline_window));
957 return;
958 }
959 #endif
960 if (ARGCOUNT <= 0)
961 {
962 // Don't give an error message. We don't want it when the ":all"
963 // command is in the .vimrc.
964 return;
965 }
966 setpcmark();
967
968 opened_len = ARGCOUNT;
969 opened = alloc_clear(opened_len);
970 if (opened == NULL)
971 return;
972
973 // Autocommands may do anything to the argument list. Make sure it's not
974 // freed while we are working here by "locking" it. We still have to
975 // watch out for its size to be changed.
976 alist = curwin->w_alist;
977 ++alist->al_refcount;
978 arglist_locked = TRUE;
979 961
980 old_curwin = curwin; 962 old_curwin = curwin;
981 old_curtab = curtab; 963 old_curtab = curtab;
982 964
983 #ifdef FEAT_GUI 965 if (aall->had_tab > 0)
984 need_mouse_correct = TRUE;
985 #endif
986
987 // Try closing all windows that are not in the argument list.
988 // Also close windows that are not full width;
989 // When 'hidden' or "forceit" set the buffer becomes hidden.
990 // Windows that have a changed buffer and can't be hidden won't be closed.
991 // When the ":tab" modifier was used do this for all tab pages.
992 if (had_tab > 0)
993 goto_tabpage_tp(first_tabpage, TRUE, TRUE); 966 goto_tabpage_tp(first_tabpage, TRUE, TRUE);
994 for (;;) 967 for (;;)
995 { 968 {
996 tpnext = curtab->tp_next; 969 tpnext = curtab->tp_next;
997 for (wp = firstwin; wp != NULL; wp = wpnext) 970 for (wp = firstwin; wp != NULL; wp = wpnext)
998 { 971 {
999 wpnext = wp->w_next; 972 wpnext = wp->w_next;
1000 buf = wp->w_buffer; 973 buf = wp->w_buffer;
1001 if (buf->b_ffname == NULL 974 if (buf->b_ffname == NULL
1002 || (!keep_tabs && (buf->b_nwindows > 1 975 || (!aall->keep_tabs && (buf->b_nwindows > 1
1003 || wp->w_width != Columns))) 976 || wp->w_width != Columns)))
1004 i = opened_len; 977 i = aall->opened_len;
1005 else 978 else
1006 { 979 {
1007 // check if the buffer in this window is in the arglist 980 // check if the buffer in this window is in the arglist
1008 for (i = 0; i < opened_len; ++i) 981 for (i = 0; i < aall->opened_len; ++i)
1009 { 982 {
1010 if (i < alist->al_ga.ga_len 983 if (i < aall->alist->al_ga.ga_len
1011 && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum 984 && (AARGLIST(aall->alist)[i].ae_fnum == buf->b_fnum
1012 || fullpathcmp(alist_name(&AARGLIST(alist)[i]), 985 || fullpathcmp(alist_name(&AARGLIST(aall->alist)[i]),
1013 buf->b_ffname, TRUE, TRUE) & FPC_SAME)) 986 buf->b_ffname, TRUE, TRUE) & FPC_SAME))
1014 { 987 {
1015 int weight = 1; 988 int weight = 1;
1016 989
1017 if (old_curtab == curtab) 990 if (old_curtab == curtab)
1019 ++weight; 992 ++weight;
1020 if (old_curwin == wp) 993 if (old_curwin == wp)
1021 ++weight; 994 ++weight;
1022 } 995 }
1023 996
1024 if (weight > (int)opened[i]) 997 if (weight > (int)aall->opened[i])
1025 { 998 {
1026 opened[i] = (char_u)weight; 999 aall->opened[i] = (char_u)weight;
1027 if (i == 0) 1000 if (i == 0)
1028 { 1001 {
1029 if (new_curwin != NULL) 1002 if (aall->new_curwin != NULL)
1030 new_curwin->w_arg_idx = opened_len; 1003 aall->new_curwin->w_arg_idx = aall->opened_len;
1031 new_curwin = wp; 1004 aall->new_curwin = wp;
1032 new_curtab = curtab; 1005 aall->new_curtab = curtab;
1033 } 1006 }
1034 } 1007 }
1035 else if (keep_tabs) 1008 else if (aall->keep_tabs)
1036 i = opened_len; 1009 i = aall->opened_len;
1037 1010
1038 if (wp->w_alist != alist) 1011 if (wp->w_alist != aall->alist)
1039 { 1012 {
1040 // Use the current argument list for all windows 1013 // Use the current argument list for all windows
1041 // containing a file from it. 1014 // containing a file from it.
1042 alist_unlink(wp->w_alist); 1015 alist_unlink(wp->w_alist);
1043 wp->w_alist = alist; 1016 wp->w_alist = aall->alist;
1044 ++wp->w_alist->al_refcount; 1017 ++wp->w_alist->al_refcount;
1045 } 1018 }
1046 break; 1019 break;
1047 } 1020 }
1048 } 1021 }
1049 } 1022 }
1050 wp->w_arg_idx = i; 1023 wp->w_arg_idx = i;
1051 1024
1052 if (i == opened_len && !keep_tabs)// close this window 1025 if (i == aall->opened_len && !aall->keep_tabs)// close this window
1053 { 1026 {
1054 if (buf_hide(buf) || forceit || buf->b_nwindows > 1 1027 if (buf_hide(buf) || aall->forceit || buf->b_nwindows > 1
1055 || !bufIsChanged(buf)) 1028 || !bufIsChanged(buf))
1056 { 1029 {
1057 // If the buffer was changed, and we would like to hide it, 1030 // If the buffer was changed, and we would like to hide it,
1058 // try autowriting. 1031 // try autowriting.
1059 if (!buf_hide(buf) && buf->b_nwindows <= 1 1032 if (!buf_hide(buf) && buf->b_nwindows <= 1
1072 continue; 1045 continue;
1073 } 1046 }
1074 } 1047 }
1075 // don't close last window 1048 // don't close last window
1076 if (ONE_WINDOW 1049 if (ONE_WINDOW
1077 && (first_tabpage->tp_next == NULL || !had_tab)) 1050 && (first_tabpage->tp_next == NULL
1078 use_firstwin = TRUE; 1051 || !aall->had_tab))
1052 aall->use_firstwin = TRUE;
1079 else 1053 else
1080 { 1054 {
1081 win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); 1055 win_close(wp, !buf_hide(buf) && !bufIsChanged(buf));
1082 1056
1083 // check if autocommands removed the next window 1057 // check if autocommands removed the next window
1087 } 1061 }
1088 } 1062 }
1089 } 1063 }
1090 1064
1091 // Without the ":tab" modifier only do the current tab page. 1065 // Without the ":tab" modifier only do the current tab page.
1092 if (had_tab == 0 || tpnext == NULL) 1066 if (aall->had_tab == 0 || tpnext == NULL)
1093 break; 1067 break;
1094 1068
1095 // check if autocommands removed the next tab page 1069 // check if autocommands removed the next tab page
1096 if (!valid_tabpage(tpnext)) 1070 if (!valid_tabpage(tpnext))
1097 tpnext = first_tabpage; // start all over... 1071 tpnext = first_tabpage; // start all over...
1098 1072
1099 goto_tabpage_tp(tpnext, TRUE, TRUE); 1073 goto_tabpage_tp(tpnext, TRUE, TRUE);
1100 } 1074 }
1101 1075 }
1102 // Open a window for files in the argument list that don't have one. 1076
1103 // ARGCOUNT may change while doing this, because of autocommands. 1077 /*
1104 if (count > opened_len || count <= 0) 1078 * Open upto "count" windows for the files in the argument list 'aall->alist'.
1105 count = opened_len; 1079 */
1106 1080 static void
1107 // Don't execute Win/Buf Enter/Leave autocommands here. 1081 arg_all_open_windows(arg_all_state_T *aall, int count)
1108 ++autocmd_no_enter; 1082 {
1109 ++autocmd_no_leave; 1083 win_T *wp;
1110 last_curwin = curwin; 1084 int tab_drop_empty_window = FALSE;
1111 last_curtab = curtab; 1085 int i;
1112 win_enter(lastwin, FALSE); 1086 int split_ret = OK;
1087 int p_ea_save;
1088
1113 // ":tab drop file" should re-use an empty window to avoid "--remote-tab" 1089 // ":tab drop file" should re-use an empty window to avoid "--remote-tab"
1114 // leaving an empty tab page when executed locally. 1090 // leaving an empty tab page when executed locally.
1115 if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 1091 if (aall->keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1
1116 && curbuf->b_ffname == NULL && !curbuf->b_changed) 1092 && curbuf->b_ffname == NULL && !curbuf->b_changed)
1117 { 1093 {
1118 use_firstwin = TRUE; 1094 aall->use_firstwin = TRUE;
1119 tab_drop_empty_window = TRUE; 1095 tab_drop_empty_window = TRUE;
1120 } 1096 }
1121 1097
1122 for (i = 0; i < count && !got_int; ++i) 1098 for (i = 0; i < count && !got_int; ++i)
1123 { 1099 {
1124 if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) 1100 if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1)
1125 arg_had_last = TRUE; 1101 arg_had_last = TRUE;
1126 if (opened[i] > 0) 1102 if (aall->opened[i] > 0)
1127 { 1103 {
1128 // Move the already present window to below the current window 1104 // Move the already present window to below the current window
1129 if (curwin->w_arg_idx != i) 1105 if (curwin->w_arg_idx != i)
1130 { 1106 {
1131 FOR_ALL_WINDOWS(wpnext) 1107 FOR_ALL_WINDOWS(wp)
1132 { 1108 {
1133 if (wpnext->w_arg_idx == i) 1109 if (wp->w_arg_idx == i)
1134 { 1110 {
1135 if (keep_tabs) 1111 if (aall->keep_tabs)
1136 { 1112 {
1137 new_curwin = wpnext; 1113 aall->new_curwin = wp;
1138 new_curtab = curtab; 1114 aall->new_curtab = curtab;
1139 } 1115 }
1140 else if (wpnext->w_frame->fr_parent 1116 else if (wp->w_frame->fr_parent
1141 != curwin->w_frame->fr_parent) 1117 != curwin->w_frame->fr_parent)
1142 { 1118 {
1143 emsg(_(e_window_layout_changed_unexpectedly)); 1119 emsg(_(e_window_layout_changed_unexpectedly));
1144 i = count; 1120 i = count;
1145 break; 1121 break;
1146 } 1122 }
1147 else 1123 else
1148 win_move_after(wpnext, curwin); 1124 win_move_after(wp, curwin);
1149 break; 1125 break;
1150 } 1126 }
1151 } 1127 }
1152 } 1128 }
1153 } 1129 }
1154 else if (split_ret == OK) 1130 else if (split_ret == OK)
1155 { 1131 {
1156 // trigger events for tab drop 1132 // trigger events for tab drop
1157 if (tab_drop_empty_window && i == count - 1) 1133 if (tab_drop_empty_window && i == count - 1)
1158 --autocmd_no_enter; 1134 --autocmd_no_enter;
1159 if (!use_firstwin) // split current window 1135 if (!aall->use_firstwin) // split current window
1160 { 1136 {
1161 p_ea_save = p_ea; 1137 p_ea_save = p_ea;
1162 p_ea = TRUE; // use space from all windows 1138 p_ea = TRUE; // use space from all windows
1163 split_ret = win_split(0, WSP_ROOM | WSP_BELOW); 1139 split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
1164 p_ea = p_ea_save; 1140 p_ea = p_ea_save;
1170 1146
1171 // edit file "i" 1147 // edit file "i"
1172 curwin->w_arg_idx = i; 1148 curwin->w_arg_idx = i;
1173 if (i == 0) 1149 if (i == 0)
1174 { 1150 {
1175 new_curwin = curwin; 1151 aall->new_curwin = curwin;
1176 new_curtab = curtab; 1152 aall->new_curtab = curtab;
1177 } 1153 }
1178 (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, 1154 (void)do_ecmd(0, alist_name(&AARGLIST(aall->alist)[i]), NULL, NULL,
1179 ECMD_ONE, 1155 ECMD_ONE,
1180 ((buf_hide(curwin->w_buffer) 1156 ((buf_hide(curwin->w_buffer)
1181 || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) 1157 || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0)
1182 + ECMD_OLDBUF, curwin); 1158 + ECMD_OLDBUF, curwin);
1183 if (tab_drop_empty_window && i == count - 1) 1159 if (tab_drop_empty_window && i == count - 1)
1184 ++autocmd_no_enter; 1160 ++autocmd_no_enter;
1185 if (use_firstwin) 1161 if (aall->use_firstwin)
1186 ++autocmd_no_leave; 1162 ++autocmd_no_leave;
1187 use_firstwin = FALSE; 1163 aall->use_firstwin = FALSE;
1188 } 1164 }
1189 ui_breakcheck(); 1165 ui_breakcheck();
1190 1166
1191 // When ":tab" was used open a new tab for a new window repeatedly. 1167 // When ":tab" was used open a new tab for a new window repeatedly.
1192 if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) 1168 if (aall->had_tab > 0 && tabpage_index(NULL) <= p_tpm)
1193 cmdmod.cmod_tab = 9999; 1169 cmdmod.cmod_tab = 9999;
1194 } 1170 }
1171 }
1172
1173 /*
1174 * do_arg_all(): Open up to "count" windows, one for each argument.
1175 */
1176 static void
1177 do_arg_all(
1178 int count,
1179 int forceit, // hide buffers in current windows
1180 int keep_tabs) // keep current tabs, for ":tab drop file"
1181 {
1182 arg_all_state_T aall;
1183 win_T *last_curwin;
1184 tabpage_T *last_curtab;
1185 int prev_arglist_locked = arglist_locked;
1186
1187 #ifdef FEAT_CMDWIN
1188 if (cmdwin_type != 0)
1189 {
1190 emsg(_(e_invalid_in_cmdline_window));
1191 return;
1192 }
1193 #endif
1194 if (ARGCOUNT <= 0)
1195 {
1196 // Don't give an error message. We don't want it when the ":all"
1197 // command is in the .vimrc.
1198 return;
1199 }
1200 setpcmark();
1201
1202 aall.use_firstwin = FALSE;
1203 aall.had_tab = cmdmod.cmod_tab;
1204 aall.new_curwin = NULL;
1205 aall.new_curtab = NULL;
1206 aall.forceit = forceit;
1207 aall.keep_tabs = keep_tabs;
1208 aall.opened_len = ARGCOUNT;
1209 aall.opened = alloc_clear(aall.opened_len);
1210 if (aall.opened == NULL)
1211 return;
1212
1213 // Autocommands may do anything to the argument list. Make sure it's not
1214 // freed while we are working here by "locking" it. We still have to
1215 // watch out for its size being changed.
1216 aall.alist = curwin->w_alist;
1217 ++aall.alist->al_refcount;
1218 arglist_locked = TRUE;
1219
1220 #ifdef FEAT_GUI
1221 need_mouse_correct = TRUE;
1222 #endif
1223
1224 // Try closing all windows that are not in the argument list.
1225 // Also close windows that are not full width;
1226 // When 'hidden' or "forceit" set the buffer becomes hidden.
1227 // Windows that have a changed buffer and can't be hidden won't be closed.
1228 // When the ":tab" modifier was used do this for all tab pages.
1229 arg_all_close_unused_windows(&aall);
1230
1231 // Open a window for files in the argument list that don't have one.
1232 // ARGCOUNT may change while doing this, because of autocommands.
1233 if (count > aall.opened_len || count <= 0)
1234 count = aall.opened_len;
1235
1236 // Don't execute Win/Buf Enter/Leave autocommands here.
1237 ++autocmd_no_enter;
1238 ++autocmd_no_leave;
1239 last_curwin = curwin;
1240 last_curtab = curtab;
1241 win_enter(lastwin, FALSE);
1242
1243 /*
1244 * Open upto "count" windows.
1245 */
1246 arg_all_open_windows(&aall, count);
1195 1247
1196 // Remove the "lock" on the argument list. 1248 // Remove the "lock" on the argument list.
1197 alist_unlink(alist); 1249 alist_unlink(aall.alist);
1198 arglist_locked = prev_arglist_locked; 1250 arglist_locked = prev_arglist_locked;
1199 1251
1200 --autocmd_no_enter; 1252 --autocmd_no_enter;
1201 1253
1202 // restore last referenced tabpage's curwin 1254 // restore last referenced tabpage's curwin
1203 if (last_curtab != new_curtab) 1255 if (last_curtab != aall.new_curtab)
1204 { 1256 {
1205 if (valid_tabpage(last_curtab)) 1257 if (valid_tabpage(last_curtab))
1206 goto_tabpage_tp(last_curtab, TRUE, TRUE); 1258 goto_tabpage_tp(last_curtab, TRUE, TRUE);
1207 if (win_valid(last_curwin)) 1259 if (win_valid(last_curwin))
1208 win_enter(last_curwin, FALSE); 1260 win_enter(last_curwin, FALSE);
1209 } 1261 }
1210 // to window with first arg 1262 // to window with first arg
1211 if (valid_tabpage(new_curtab)) 1263 if (valid_tabpage(aall.new_curtab))
1212 goto_tabpage_tp(new_curtab, TRUE, TRUE); 1264 goto_tabpage_tp(aall.new_curtab, TRUE, TRUE);
1213 if (win_valid(new_curwin)) 1265 if (win_valid(aall.new_curwin))
1214 win_enter(new_curwin, FALSE); 1266 win_enter(aall.new_curwin, FALSE);
1215 1267
1216 --autocmd_no_leave; 1268 --autocmd_no_leave;
1217 vim_free(opened); 1269 vim_free(aall.opened);
1218 } 1270 }
1219 1271
1220 /* 1272 /*
1221 * ":all" and ":sall". 1273 * ":all" and ":sall".
1222 * Also used for ":tab drop file ..." after setting the argument list. 1274 * Also used for ":tab drop file ..." after setting the argument list.