# HG changeset patch # User Bram Moolenaar # Date 1662399003 -7200 # Node ID dd97e797fffb99888b0e9774d34073172a6675b0 # Parent ec4ce9c64e2b1fcb831a0f7501f54314c5f8e417 patch 9.0.0388: the do_arg_all() function is too long Commit: https://github.com/vim/vim/commit/8894761daf68220504932c8b3e75f59138cdb617 Author: Yegappan Lakshmanan 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) diff --git a/src/arglist.c b/src/arglist.c --- a/src/arglist.c +++ b/src/arglist.c @@ -574,21 +574,23 @@ ex_args(exarg_T *eap) alist_new(); } + // ":args file ..": define new argument list, handle like ":next" + // Also for ":argslocal file .." and ":argsglobal file ..". if (*eap->arg != NUL) { if (check_arglist_locked() == FAIL) return; - // ":args file ..": define new argument list, handle like ":next" - // Also for ":argslocal file .." and ":argsglobal file ..". ex_next(eap); + return; } - else if (eap->cmdidx == CMD_args) + + // ":args": list arguments. + if (eap->cmdidx == CMD_args) { char_u **items; - // ":args": list arguments. if (ARGCOUNT <= 0) - return; + return; // empty argument list items = ALLOC_MULT(char_u *, ARGCOUNT); if (items == NULL) @@ -602,12 +604,15 @@ ex_args(exarg_T *eap) items[i] = alist_name(&ARGLIST[i]); list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); vim_free(items); + + return; } - else if (eap->cmdidx == CMD_arglocal) + + // ":argslocal": make a local copy of the global argument list. + if (eap->cmdidx == CMD_arglocal) { garray_T *gap = &curwin->w_alist->al_ga; - // ":argslocal": make a local copy of the global argument list. if (GA_GROW_FAILS(gap, GARGCOUNT)) return; @@ -919,77 +924,45 @@ alist_name(aentry_T *aep) } /* - * do_arg_all(): Open up to 'count' windows, one for each argument. + * State used by the :all command to open all the files in the argument list in + * separate windows. */ - static void -do_arg_all( - int count, - int forceit, // hide buffers in current windows - int keep_tabs) // keep current tabs, for ":tab drop file" -{ - int i; - win_T *wp, *wpnext; +typedef struct { + alist_T *alist; // argument list to be used + int had_tab; + int keep_tabs; + int forceit; + + int use_firstwin; // use first window for arglist char_u *opened; // Array of weight for which args are open: // 0: not opened // 1: opened in other tab // 2: opened in curtab // 3: opened in curtab and curwin - // int opened_len; // length of opened[] - int use_firstwin = FALSE; // use first window for arglist - int tab_drop_empty_window = FALSE; - int split_ret = OK; - int p_ea_save; - alist_T *alist; // argument list to be used - buf_T *buf; - tabpage_T *tpnext; - int had_tab = cmdmod.cmod_tab; - win_T *old_curwin, *last_curwin; - tabpage_T *old_curtab, *last_curtab; - win_T *new_curwin = NULL; - tabpage_T *new_curtab = NULL; - int prev_arglist_locked = arglist_locked; + win_T *new_curwin; + tabpage_T *new_curtab; +} arg_all_state_T; -#ifdef FEAT_CMDWIN - if (cmdwin_type != 0) - { - emsg(_(e_invalid_in_cmdline_window)); - return; - } -#endif - if (ARGCOUNT <= 0) - { - // Don't give an error message. We don't want it when the ":all" - // command is in the .vimrc. - return; - } - setpcmark(); - - opened_len = ARGCOUNT; - opened = alloc_clear(opened_len); - if (opened == NULL) - return; - - // Autocommands may do anything to the argument list. Make sure it's not - // freed while we are working here by "locking" it. We still have to - // watch out for its size to be changed. - alist = curwin->w_alist; - ++alist->al_refcount; - arglist_locked = TRUE; +/* + * Close all the windows containing files which are not in the argument list. + * Used by the ":all" command. + */ + static void +arg_all_close_unused_windows(arg_all_state_T *aall) +{ + win_T *wp; + win_T *wpnext; + tabpage_T *tpnext; + buf_T *buf; + int i; + win_T *old_curwin; + tabpage_T *old_curtab; old_curwin = curwin; old_curtab = curtab; -#ifdef FEAT_GUI - need_mouse_correct = TRUE; -#endif - - // Try closing all windows that are not in the argument list. - // Also close windows that are not full width; - // When 'hidden' or "forceit" set the buffer becomes hidden. - // Windows that have a changed buffer and can't be hidden won't be closed. - // When the ":tab" modifier was used do this for all tab pages. - if (had_tab > 0) + if (aall->had_tab > 0) goto_tabpage_tp(first_tabpage, TRUE, TRUE); for (;;) { @@ -999,17 +972,17 @@ do_arg_all( wpnext = wp->w_next; buf = wp->w_buffer; if (buf->b_ffname == NULL - || (!keep_tabs && (buf->b_nwindows > 1 + || (!aall->keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) - i = opened_len; + i = aall->opened_len; else { // check if the buffer in this window is in the arglist - for (i = 0; i < opened_len; ++i) + for (i = 0; i < aall->opened_len; ++i) { - if (i < alist->al_ga.ga_len - && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum - || fullpathcmp(alist_name(&AARGLIST(alist)[i]), + if (i < aall->alist->al_ga.ga_len + && (AARGLIST(aall->alist)[i].ae_fnum == buf->b_fnum + || fullpathcmp(alist_name(&AARGLIST(aall->alist)[i]), buf->b_ffname, TRUE, TRUE) & FPC_SAME)) { int weight = 1; @@ -1021,26 +994,26 @@ do_arg_all( ++weight; } - if (weight > (int)opened[i]) + if (weight > (int)aall->opened[i]) { - opened[i] = (char_u)weight; + aall->opened[i] = (char_u)weight; if (i == 0) { - if (new_curwin != NULL) - new_curwin->w_arg_idx = opened_len; - new_curwin = wp; - new_curtab = curtab; + if (aall->new_curwin != NULL) + aall->new_curwin->w_arg_idx = aall->opened_len; + aall->new_curwin = wp; + aall->new_curtab = curtab; } } - else if (keep_tabs) - i = opened_len; + else if (aall->keep_tabs) + i = aall->opened_len; - if (wp->w_alist != alist) + if (wp->w_alist != aall->alist) { // Use the current argument list for all windows // containing a file from it. alist_unlink(wp->w_alist); - wp->w_alist = alist; + wp->w_alist = aall->alist; ++wp->w_alist->al_refcount; } break; @@ -1049,9 +1022,9 @@ do_arg_all( } wp->w_arg_idx = i; - if (i == opened_len && !keep_tabs)// close this window + if (i == aall->opened_len && !aall->keep_tabs)// close this window { - if (buf_hide(buf) || forceit || buf->b_nwindows > 1 + if (buf_hide(buf) || aall->forceit || buf->b_nwindows > 1 || !bufIsChanged(buf)) { // If the buffer was changed, and we would like to hide it, @@ -1074,8 +1047,9 @@ do_arg_all( } // don't close last window if (ONE_WINDOW - && (first_tabpage->tp_next == NULL || !had_tab)) - use_firstwin = TRUE; + && (first_tabpage->tp_next == NULL + || !aall->had_tab)) + aall->use_firstwin = TRUE; else { win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); @@ -1089,7 +1063,7 @@ do_arg_all( } // Without the ":tab" modifier only do the current tab page. - if (had_tab == 0 || tpnext == NULL) + if (aall->had_tab == 0 || tpnext == NULL) break; // check if autocommands removed the next tab page @@ -1098,54 +1072,56 @@ do_arg_all( goto_tabpage_tp(tpnext, TRUE, TRUE); } - - // Open a window for files in the argument list that don't have one. - // ARGCOUNT may change while doing this, because of autocommands. - if (count > opened_len || count <= 0) - count = opened_len; +} - // Don't execute Win/Buf Enter/Leave autocommands here. - ++autocmd_no_enter; - ++autocmd_no_leave; - last_curwin = curwin; - last_curtab = curtab; - win_enter(lastwin, FALSE); +/* + * Open upto "count" windows for the files in the argument list 'aall->alist'. + */ + static void +arg_all_open_windows(arg_all_state_T *aall, int count) +{ + win_T *wp; + int tab_drop_empty_window = FALSE; + int i; + int split_ret = OK; + int p_ea_save; + // ":tab drop file" should re-use an empty window to avoid "--remote-tab" // leaving an empty tab page when executed locally. - if (keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 + if (aall->keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 && curbuf->b_ffname == NULL && !curbuf->b_changed) { - use_firstwin = TRUE; + aall->use_firstwin = TRUE; tab_drop_empty_window = TRUE; } for (i = 0; i < count && !got_int; ++i) { - if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) + if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1) arg_had_last = TRUE; - if (opened[i] > 0) + if (aall->opened[i] > 0) { // Move the already present window to below the current window if (curwin->w_arg_idx != i) { - FOR_ALL_WINDOWS(wpnext) + FOR_ALL_WINDOWS(wp) { - if (wpnext->w_arg_idx == i) + if (wp->w_arg_idx == i) { - if (keep_tabs) + if (aall->keep_tabs) { - new_curwin = wpnext; - new_curtab = curtab; + aall->new_curwin = wp; + aall->new_curtab = curtab; } - else if (wpnext->w_frame->fr_parent - != curwin->w_frame->fr_parent) + else if (wp->w_frame->fr_parent + != curwin->w_frame->fr_parent) { emsg(_(e_window_layout_changed_unexpectedly)); i = count; break; } else - win_move_after(wpnext, curwin); + win_move_after(wp, curwin); break; } } @@ -1156,7 +1132,7 @@ do_arg_all( // trigger events for tab drop if (tab_drop_empty_window && i == count - 1) --autocmd_no_enter; - if (!use_firstwin) // split current window + if (!aall->use_firstwin) // split current window { p_ea_save = p_ea; p_ea = TRUE; // use space from all windows @@ -1172,35 +1148,111 @@ do_arg_all( curwin->w_arg_idx = i; if (i == 0) { - new_curwin = curwin; - new_curtab = curtab; + aall->new_curwin = curwin; + aall->new_curtab = curtab; } - (void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, - ECMD_ONE, - ((buf_hide(curwin->w_buffer) - || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) - + ECMD_OLDBUF, curwin); + (void)do_ecmd(0, alist_name(&AARGLIST(aall->alist)[i]), NULL, NULL, + ECMD_ONE, + ((buf_hide(curwin->w_buffer) + || bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + + ECMD_OLDBUF, curwin); if (tab_drop_empty_window && i == count - 1) ++autocmd_no_enter; - if (use_firstwin) + if (aall->use_firstwin) ++autocmd_no_leave; - use_firstwin = FALSE; + aall->use_firstwin = FALSE; } ui_breakcheck(); // When ":tab" was used open a new tab for a new window repeatedly. - if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) + if (aall->had_tab > 0 && tabpage_index(NULL) <= p_tpm) cmdmod.cmod_tab = 9999; } +} + +/* + * do_arg_all(): Open up to "count" windows, one for each argument. + */ + static void +do_arg_all( + int count, + int forceit, // hide buffers in current windows + int keep_tabs) // keep current tabs, for ":tab drop file" +{ + arg_all_state_T aall; + win_T *last_curwin; + tabpage_T *last_curtab; + int prev_arglist_locked = arglist_locked; + +#ifdef FEAT_CMDWIN + if (cmdwin_type != 0) + { + emsg(_(e_invalid_in_cmdline_window)); + return; + } +#endif + if (ARGCOUNT <= 0) + { + // Don't give an error message. We don't want it when the ":all" + // command is in the .vimrc. + return; + } + setpcmark(); + + aall.use_firstwin = FALSE; + aall.had_tab = cmdmod.cmod_tab; + aall.new_curwin = NULL; + aall.new_curtab = NULL; + aall.forceit = forceit; + aall.keep_tabs = keep_tabs; + aall.opened_len = ARGCOUNT; + aall.opened = alloc_clear(aall.opened_len); + if (aall.opened == NULL) + return; + + // Autocommands may do anything to the argument list. Make sure it's not + // freed while we are working here by "locking" it. We still have to + // watch out for its size being changed. + aall.alist = curwin->w_alist; + ++aall.alist->al_refcount; + arglist_locked = TRUE; + +#ifdef FEAT_GUI + need_mouse_correct = TRUE; +#endif + + // Try closing all windows that are not in the argument list. + // Also close windows that are not full width; + // When 'hidden' or "forceit" set the buffer becomes hidden. + // Windows that have a changed buffer and can't be hidden won't be closed. + // When the ":tab" modifier was used do this for all tab pages. + arg_all_close_unused_windows(&aall); + + // Open a window for files in the argument list that don't have one. + // ARGCOUNT may change while doing this, because of autocommands. + if (count > aall.opened_len || count <= 0) + count = aall.opened_len; + + // Don't execute Win/Buf Enter/Leave autocommands here. + ++autocmd_no_enter; + ++autocmd_no_leave; + last_curwin = curwin; + last_curtab = curtab; + win_enter(lastwin, FALSE); + + /* + * Open upto "count" windows. + */ + arg_all_open_windows(&aall, count); // Remove the "lock" on the argument list. - alist_unlink(alist); + alist_unlink(aall.alist); arglist_locked = prev_arglist_locked; --autocmd_no_enter; // restore last referenced tabpage's curwin - if (last_curtab != new_curtab) + if (last_curtab != aall.new_curtab) { if (valid_tabpage(last_curtab)) goto_tabpage_tp(last_curtab, TRUE, TRUE); @@ -1208,13 +1260,13 @@ do_arg_all( win_enter(last_curwin, FALSE); } // to window with first arg - if (valid_tabpage(new_curtab)) - goto_tabpage_tp(new_curtab, TRUE, TRUE); - if (win_valid(new_curwin)) - win_enter(new_curwin, FALSE); + if (valid_tabpage(aall.new_curtab)) + goto_tabpage_tp(aall.new_curtab, TRUE, TRUE); + if (win_valid(aall.new_curwin)) + win_enter(aall.new_curwin, FALSE); --autocmd_no_leave; - vim_free(opened); + vim_free(aall.opened); } /* diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 388, +/**/ 387, /**/ 386,