To: vim_dev@googlegroups.com Subject: Patch 9.0.0388 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 9.0.0388 Problem: The do_arg_all() function is too long. Solution: Split the function in smaller parts. (Yegappan Lakshmanan, closes #11062) Files: src/arglist.c *** ../vim-9.0.0387/src/arglist.c 2022-09-05 14:33:42.202419990 +0100 --- src/arglist.c 2022-09-05 18:24:52.327375787 +0100 *************** *** 574,594 **** alist_new(); } 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); } ! else if (eap->cmdidx == CMD_args) { char_u **items; - // ":args": list arguments. if (ARGCOUNT <= 0) ! return; items = ALLOC_MULT(char_u *, ARGCOUNT); if (items == NULL) --- 574,596 ---- 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; ex_next(eap); + return; } ! ! // ":args": list arguments. ! if (eap->cmdidx == CMD_args) { char_u **items; if (ARGCOUNT <= 0) ! return; // empty argument list items = ALLOC_MULT(char_u *, ARGCOUNT); if (items == NULL) *************** *** 602,613 **** items[i] = alist_name(&ARGLIST[i]); list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); vim_free(items); } ! else 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; --- 604,618 ---- items[i] = alist_name(&ARGLIST[i]); list_in_columns(items, ARGCOUNT, curwin->w_arg_idx); vim_free(items); + + return; } ! ! // ":argslocal": make a local copy of the global argument list. ! if (eap->cmdidx == CMD_arglocal) { garray_T *gap = &curwin->w_alist->al_ga; if (GA_GROW_FAILS(gap, GARGCOUNT)) return; *************** *** 919,995 **** } /* ! * 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" ! { ! int i; ! win_T *wp, *wpnext; 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; ! #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; 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) goto_tabpage_tp(first_tabpage, TRUE, TRUE); for (;;) { --- 924,968 ---- } /* ! * State used by the :all command to open all the files in the argument list in ! * separate windows. */ ! 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[] ! win_T *new_curwin; ! tabpage_T *new_curtab; ! } arg_all_state_T; ! /* ! * 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; ! if (aall->had_tab > 0) goto_tabpage_tp(first_tabpage, TRUE, TRUE); for (;;) { *************** *** 999,1015 **** wpnext = wp->w_next; buf = wp->w_buffer; if (buf->b_ffname == NULL ! || (!keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) ! i = opened_len; else { // check if the buffer in this window is in the arglist ! for (i = 0; i < opened_len; ++i) { ! if (i < alist->al_ga.ga_len ! && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum ! || fullpathcmp(alist_name(&AARGLIST(alist)[i]), buf->b_ffname, TRUE, TRUE) & FPC_SAME)) { int weight = 1; --- 972,988 ---- wpnext = wp->w_next; buf = wp->w_buffer; if (buf->b_ffname == NULL ! || (!aall->keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) ! i = aall->opened_len; else { // check if the buffer in this window is in the arglist ! for (i = 0; i < aall->opened_len; ++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,1046 **** ++weight; } ! if (weight > (int)opened[i]) { ! 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; } } ! else if (keep_tabs) ! i = opened_len; ! if (wp->w_alist != 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->al_refcount; } break; --- 994,1019 ---- ++weight; } ! if (weight > (int)aall->opened[i]) { ! aall->opened[i] = (char_u)weight; if (i == 0) { ! if (aall->new_curwin != NULL) ! aall->new_curwin->w_arg_idx = aall->opened_len; ! aall->new_curwin = wp; ! aall->new_curtab = curtab; } } ! else if (aall->keep_tabs) ! i = aall->opened_len; ! 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 = aall->alist; ++wp->w_alist->al_refcount; } break; *************** *** 1049,1057 **** } wp->w_arg_idx = i; ! if (i == opened_len && !keep_tabs)// close this window { ! if (buf_hide(buf) || forceit || buf->b_nwindows > 1 || !bufIsChanged(buf)) { // If the buffer was changed, and we would like to hide it, --- 1022,1030 ---- } wp->w_arg_idx = i; ! if (i == aall->opened_len && !aall->keep_tabs)// close this window { ! 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,1081 **** } // don't close last window if (ONE_WINDOW ! && (first_tabpage->tp_next == NULL || !had_tab)) ! use_firstwin = TRUE; else { win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); --- 1047,1055 ---- } // don't close last window if (ONE_WINDOW ! && (first_tabpage->tp_next == NULL ! || !aall->had_tab)) ! aall->use_firstwin = TRUE; else { win_close(wp, !buf_hide(buf) && !bufIsChanged(buf)); *************** *** 1089,1095 **** } // Without the ":tab" modifier only do the current tab page. ! if (had_tab == 0 || tpnext == NULL) break; // check if autocommands removed the next tab page --- 1063,1069 ---- } // Without the ":tab" modifier only do the current tab page. ! if (aall->had_tab == 0 || tpnext == NULL) break; // check if autocommands removed the next tab page *************** *** 1098,1151 **** 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); // ":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 && curbuf->b_ffname == NULL && !curbuf->b_changed) { ! 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) arg_had_last = TRUE; ! if (opened[i] > 0) { // Move the already present window to below the current window if (curwin->w_arg_idx != i) { ! FOR_ALL_WINDOWS(wpnext) { ! if (wpnext->w_arg_idx == i) { ! if (keep_tabs) { ! new_curwin = wpnext; ! new_curtab = curtab; } ! else if (wpnext->w_frame->fr_parent ! != curwin->w_frame->fr_parent) { emsg(_(e_window_layout_changed_unexpectedly)); i = count; break; } else ! win_move_after(wpnext, curwin); break; } } --- 1072,1127 ---- goto_tabpage_tp(tpnext, TRUE, TRUE); } + } ! /* ! * 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 (aall->keep_tabs && BUFEMPTY() && curbuf->b_nwindows == 1 && curbuf->b_ffname == NULL && !curbuf->b_changed) { ! aall->use_firstwin = TRUE; tab_drop_empty_window = TRUE; } for (i = 0; i < count && !got_int; ++i) { ! if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1) arg_had_last = TRUE; ! if (aall->opened[i] > 0) { // Move the already present window to below the current window if (curwin->w_arg_idx != i) { ! FOR_ALL_WINDOWS(wp) { ! if (wp->w_arg_idx == i) { ! if (aall->keep_tabs) { ! aall->new_curwin = wp; ! aall->new_curtab = curtab; } ! 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(wp, curwin); break; } } *************** *** 1156,1162 **** // trigger events for tab drop if (tab_drop_empty_window && i == count - 1) --autocmd_no_enter; ! if (!use_firstwin) // split current window { p_ea_save = p_ea; p_ea = TRUE; // use space from all windows --- 1132,1138 ---- // trigger events for tab drop if (tab_drop_empty_window && i == count - 1) --autocmd_no_enter; ! if (!aall->use_firstwin) // split current window { p_ea_save = p_ea; p_ea = TRUE; // use space from all windows *************** *** 1172,1206 **** curwin->w_arg_idx = i; if (i == 0) { ! new_curwin = curwin; ! 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); if (tab_drop_empty_window && i == count - 1) ++autocmd_no_enter; ! if (use_firstwin) ++autocmd_no_leave; ! 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) cmdmod.cmod_tab = 9999; } // Remove the "lock" on the argument list. ! alist_unlink(alist); arglist_locked = prev_arglist_locked; --autocmd_no_enter; // restore last referenced tabpage's curwin ! if (last_curtab != new_curtab) { if (valid_tabpage(last_curtab)) goto_tabpage_tp(last_curtab, TRUE, TRUE); --- 1148,1258 ---- curwin->w_arg_idx = i; if (i == 0) { ! aall->new_curwin = curwin; ! aall->new_curtab = curtab; } ! (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 (aall->use_firstwin) ++autocmd_no_leave; ! aall->use_firstwin = FALSE; } ui_breakcheck(); // When ":tab" was used open a new tab for a new window repeatedly. ! 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(aall.alist); arglist_locked = prev_arglist_locked; --autocmd_no_enter; // restore last referenced tabpage's curwin ! if (last_curtab != aall.new_curtab) { if (valid_tabpage(last_curtab)) goto_tabpage_tp(last_curtab, TRUE, TRUE); *************** *** 1208,1220 **** 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); --autocmd_no_leave; ! vim_free(opened); } /* --- 1260,1272 ---- win_enter(last_curwin, FALSE); } // to window with first arg ! 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(aall.opened); } /* *** ../vim-9.0.0387/src/version.c 2022-09-05 16:53:17.115566769 +0100 --- src/version.c 2022-09-05 18:16:41.403970414 +0100 *************** *** 705,706 **** --- 705,708 ---- { /* Add new patch number below this line */ + /**/ + 388, /**/ -- hundred-and-one symptoms of being an internet addict: 7. You finally do take that vacation, but only after buying a USB modem and a laptop. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///