To: vim_dev@googlegroups.com Subject: Patch 8.1.2297 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.1.2297 Problem: The ex_vimgrep() function is too long. Solution: Split it in three parts. (Yegappan Lakshmanan, closes #5211) Files: src/quickfix.c *** ../vim-8.1.2296/src/quickfix.c 2019-11-02 22:54:37.405188813 +0100 --- src/quickfix.c 2019-11-12 22:58:43.664763269 +0100 *************** *** 5319,5329 **** * as one. */ static void ! qf_get_nth_below_entry(qfline_T *entry, int n, int linewise, int *errornr) { while (n-- > 0 && !got_int) { - qfline_T *first_entry = entry; int first_errornr = *errornr; if (linewise) --- 5319,5330 ---- * as one. */ static void ! qf_get_nth_below_entry(qfline_T *entry_arg, int n, int linewise, int *errornr) { + qfline_T *entry = entry_arg; + while (n-- > 0 && !got_int) { int first_errornr = *errornr; if (linewise) *************** *** 5334,5345 **** || entry->qf_next->qf_fnum != entry->qf_fnum) { if (linewise) - { - // If multiple entries are on the same line, then use the first - // entry - entry = first_entry; *errornr = first_errornr; - } break; } --- 5335,5341 ---- *************** *** 5815,5933 **** } /* ! * ":vimgrep {pattern} file(s)" ! * ":vimgrepadd {pattern} file(s)" ! * ":lvimgrep {pattern} file(s)" ! * ":lvimgrepadd {pattern} file(s)" */ ! void ! ex_vimgrep(exarg_T *eap) { - regmmatch_T regmatch; - int fcount; - char_u **fnames; - char_u *fname; - char_u *title; - char_u *s; char_u *p; - int fi; - qf_info_T *qi; - qf_list_T *qfl; - int_u save_qfid; - win_T *wp = NULL; - buf_T *buf; - int duplicate_name = FALSE; - int using_dummy; - int redraw_for_dummy = FALSE; - int found_match; - buf_T *first_match_buf = NULL; - time_t seconds = 0; - aco_save_T aco; - int flags = 0; - long tomatch; - char_u *dirname_start = NULL; - char_u *dirname_now = NULL; - char_u *target_dir = NULL; - char_u *au_name = NULL; ! au_name = vgr_get_auname(eap->cmdidx); ! if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, ! curbuf->b_fname, TRUE, curbuf)) ! { ! #ifdef FEAT_EVAL ! if (aborting()) ! return; ! #endif ! } ! qi = qf_cmd_get_or_alloc_stack(eap, &wp); ! if (qi == NULL) ! return; if (eap->addr_count > 0) ! tomatch = eap->line2; else ! tomatch = MAXLNUM; // Get the search pattern: either white-separated or enclosed in // ! regmatch.regprog = NULL; ! title = vim_strsave(qf_cmdtitle(*eap->cmdlinep)); ! p = skip_vimgrep_pat(eap->arg, &s, &flags); if (p == NULL) { emsg(_(e_invalpat)); ! goto theend; } ! vgr_init_regmatch(®match, s); ! if (regmatch.regprog == NULL) ! goto theend; p = skipwhite(p); if (*p == NUL) { emsg(_("E683: File name missing or invalid pattern")); ! goto theend; } - if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd - && eap->cmdidx != CMD_vimgrepadd - && eap->cmdidx != CMD_lvimgrepadd) - || qf_stack_empty(qi)) - // make place for a new list - qf_new_list(qi, title != NULL ? title : qf_cmdtitle(*eap->cmdlinep)); - // parse the list of arguments ! if (get_arglist_exp(p, &fcount, &fnames, TRUE) == FAIL) ! goto theend; ! if (fcount == 0) { emsg(_(e_nomatch)); ! goto theend; } dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start); dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now); if (dirname_start == NULL || dirname_now == NULL) - { - FreeWild(fcount, fnames); goto theend; - } // Remember the current directory, because a BufRead autocommand that does // ":lcd %:p:h" changes the meaning of short path names. mch_dirname(dirname_start, MAXPATHL); - incr_quickfix_busy(); - - // Remember the current quickfix list identifier, so that we can check for - // autocommands changing the current quickfix list. - save_qfid = qf_get_curlist(qi)->qf_id; - seconds = (time_t)0; ! for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) { ! fname = shorten_fname1(fnames[fi]); if (time(NULL) > seconds) { // Display the file name every second or so, show the user we are --- 5811,5922 ---- } /* ! * :vimgrep command arguments */ ! typedef struct ! { ! long tomatch; // maximum number of matches to find ! char_u *spat; // search pattern ! int flags; // search modifier ! char_u **fnames; // list of files to search ! int fcount; // number of files ! regmmatch_T regmatch; // compiled search pattern ! char_u *qf_title; // quickfix list title ! } vgr_args_T; ! ! /* ! * Process :vimgrep command arguments. The command syntax is: ! * ! * :{count}vimgrep /{pattern}/[g][j] {file} ... ! */ ! static int ! vgr_process_args( ! exarg_T *eap, ! vgr_args_T *args) { char_u *p; ! vim_memset(args, 0, sizeof(*args)); ! args->regmatch.regprog = NULL; ! args->qf_title = vim_strsave(qf_cmdtitle(*eap->cmdlinep)); if (eap->addr_count > 0) ! args->tomatch = eap->line2; else ! args->tomatch = MAXLNUM; // Get the search pattern: either white-separated or enclosed in // ! p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags); if (p == NULL) { emsg(_(e_invalpat)); ! return FAIL; } ! vgr_init_regmatch(&args->regmatch, args->spat); ! if (args->regmatch.regprog == NULL) ! return FAIL; p = skipwhite(p); if (*p == NUL) { emsg(_("E683: File name missing or invalid pattern")); ! return FAIL; } // parse the list of arguments ! if (get_arglist_exp(p, &args->fcount, &args->fnames, TRUE) == FAIL) ! return FAIL; ! if (args->fcount == 0) { emsg(_(e_nomatch)); ! return FAIL; } + return OK; + } + + /* + * Search for a pattern in a list of files and populate the quickfix list with + * the matches. + */ + static int + vgr_process_files( + win_T *wp, + qf_info_T *qi, + vgr_args_T *cmd_args, + int *redraw_for_dummy, + buf_T **first_match_buf, + char_u **target_dir) + { + int status = FAIL; + int_u save_qfid = qf_get_curlist(qi)->qf_id; + time_t seconds = 0; + char_u *fname; + int fi; + buf_T *buf; + int duplicate_name = FALSE; + int using_dummy; + char_u *dirname_start = NULL; + char_u *dirname_now = NULL; + int found_match; + aco_save_T aco; + dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start); dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now); if (dirname_start == NULL || dirname_now == NULL) goto theend; // Remember the current directory, because a BufRead autocommand that does // ":lcd %:p:h" changes the meaning of short path names. mch_dirname(dirname_start, MAXPATHL); seconds = (time_t)0; ! for (fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0; ! ++fi) { ! fname = shorten_fname1(cmd_args->fnames[fi]); if (time(NULL) > seconds) { // Display the file name every second or so, show the user we are *************** *** 5936,5948 **** vgr_display_fname(fname); } ! buf = buflist_findname_exp(fnames[fi]); if (buf == NULL || buf->b_ml.ml_mfp == NULL) { // Remember that a buffer with this name already exists. duplicate_name = (buf != NULL); using_dummy = TRUE; ! redraw_for_dummy = TRUE; buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now); } --- 5925,5937 ---- vgr_display_fname(fname); } ! buf = buflist_findname_exp(cmd_args->fnames[fi]); if (buf == NULL || buf->b_ml.ml_mfp == NULL) { // Remember that a buffer with this name already exists. duplicate_name = (buf != NULL); using_dummy = TRUE; ! *redraw_for_dummy = TRUE; buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now); } *************** *** 5952,5963 **** // Check whether the quickfix list is still valid. When loading a // buffer above, autocommands might have changed the quickfix list. ! if (!vgr_qflist_valid(wp, qi, save_qfid, qf_cmdtitle(*eap->cmdlinep))) ! { ! FreeWild(fcount, fnames); ! decr_quickfix_busy(); goto theend; ! } save_qfid = qf_get_curlist(qi)->qf_id; if (buf == NULL) --- 5941,5949 ---- // Check whether the quickfix list is still valid. When loading a // buffer above, autocommands might have changed the quickfix list. ! if (!vgr_qflist_valid(wp, qi, save_qfid, cmd_args->qf_title)) goto theend; ! save_qfid = qf_get_curlist(qi)->qf_id; if (buf == NULL) *************** *** 5970,5982 **** // Try for a match in all lines of the buffer. // For ":1vimgrep" look for first match only. found_match = vgr_match_buflines(qf_get_curlist(qi), ! fname, buf, ®match, ! &tomatch, duplicate_name, flags); if (using_dummy) { ! if (found_match && first_match_buf == NULL) ! first_match_buf = buf; if (duplicate_name) { // Never keep a dummy buffer if there is another buffer --- 5956,5968 ---- // Try for a match in all lines of the buffer. // For ":1vimgrep" look for first match only. found_match = vgr_match_buflines(qf_get_curlist(qi), ! fname, buf, &cmd_args->regmatch, ! &cmd_args->tomatch, duplicate_name, cmd_args->flags); if (using_dummy) { ! if (found_match && *first_match_buf == NULL) ! *first_match_buf = buf; if (duplicate_name) { // Never keep a dummy buffer if there is another buffer *************** *** 6000,6006 **** wipe_dummy_buffer(buf, dirname_start); buf = NULL; } ! else if (buf != first_match_buf || (flags & VGR_NOJUMP)) { unload_dummy_buffer(buf, dirname_start); // Keeping the buffer, remove the dummy flag. --- 5986,5993 ---- wipe_dummy_buffer(buf, dirname_start); buf = NULL; } ! else if (buf != *first_match_buf ! || (cmd_args->flags & VGR_NOJUMP)) { unload_dummy_buffer(buf, dirname_start); // Keeping the buffer, remove the dummy flag. *************** *** 6016,6025 **** // If the buffer is still loaded we need to use the // directory we jumped to below. ! if (buf == first_match_buf ! && target_dir == NULL && STRCMP(dirname_start, dirname_now) != 0) ! target_dir = vim_strsave(dirname_now); // The buffer is still loaded, the Filetype autocommands // need to be done now, in that buffer. And the modelines --- 6003,6012 ---- // If the buffer is still loaded we need to use the // directory we jumped to below. ! if (buf == *first_match_buf ! && *target_dir == NULL && STRCMP(dirname_start, dirname_now) != 0) ! *target_dir = vim_strsave(dirname_now); // The buffer is still loaded, the Filetype autocommands // need to be done now, in that buffer. And the modelines *************** *** 6037,6043 **** } } ! FreeWild(fcount, fnames); qfl = qf_get_curlist(qi); qfl->qf_nonevalid = FALSE; --- 6024,6093 ---- } } ! status = OK; ! ! theend: ! vim_free(dirname_now); ! vim_free(dirname_start); ! return status; ! } ! ! /* ! * ":vimgrep {pattern} file(s)" ! * ":vimgrepadd {pattern} file(s)" ! * ":lvimgrep {pattern} file(s)" ! * ":lvimgrepadd {pattern} file(s)" ! */ ! void ! ex_vimgrep(exarg_T *eap) ! { ! vgr_args_T args; ! qf_info_T *qi; ! qf_list_T *qfl; ! int_u save_qfid; ! win_T *wp = NULL; ! int redraw_for_dummy = FALSE; ! buf_T *first_match_buf = NULL; ! char_u *target_dir = NULL; ! char_u *au_name = NULL; ! int status; ! ! au_name = vgr_get_auname(eap->cmdidx); ! if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, ! curbuf->b_fname, TRUE, curbuf)) ! { ! #ifdef FEAT_EVAL ! if (aborting()) ! return; ! #endif ! } ! ! qi = qf_cmd_get_or_alloc_stack(eap, &wp); ! if (qi == NULL) ! return; ! ! if (vgr_process_args(eap, &args) == FAIL) ! goto theend; ! ! if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd ! && eap->cmdidx != CMD_vimgrepadd ! && eap->cmdidx != CMD_lvimgrepadd) ! || qf_stack_empty(qi)) ! // make place for a new list ! qf_new_list(qi, args.qf_title); ! ! incr_quickfix_busy(); ! ! status = vgr_process_files(wp, qi, &args, &redraw_for_dummy, ! &first_match_buf, &target_dir); ! if (status != OK) ! { ! FreeWild(args.fcount, args.fnames); ! decr_quickfix_busy(); ! goto theend; ! } ! ! FreeWild(args.fcount, args.fnames); qfl = qf_get_curlist(qi); qfl->qf_nonevalid = FALSE; *************** *** 6047,6052 **** --- 6097,6106 ---- qf_update_buffer(qi, NULL); + // Remember the current quickfix list identifier, so that we can check for + // autocommands changing the current quickfix list. + save_qfid = qf_get_curlist(qi)->qf_id; + if (au_name != NULL) apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname, TRUE, curbuf); *************** *** 6062,6073 **** // Jump to first match. if (!qf_list_empty(qf_get_curlist(qi))) { ! if ((flags & VGR_NOJUMP) == 0) vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf, target_dir); } else ! semsg(_(e_nomatch2), s); decr_quickfix_busy(); --- 6116,6127 ---- // Jump to first match. if (!qf_list_empty(qf_get_curlist(qi))) { ! if ((args.flags & VGR_NOJUMP) == 0) vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, first_match_buf, target_dir); } else ! semsg(_(e_nomatch2), args.spat); decr_quickfix_busy(); *************** *** 6083,6093 **** } theend: ! vim_free(title); ! vim_free(dirname_now); ! vim_free(dirname_start); vim_free(target_dir); ! vim_regfree(regmatch.regprog); } /* --- 6137,6145 ---- } theend: ! vim_free(args.qf_title); vim_free(target_dir); ! vim_regfree(args.regmatch.regprog); } /* *** ../vim-8.1.2296/src/version.c 2019-11-12 22:44:16.415538386 +0100 --- src/version.c 2019-11-12 22:48:11.278841830 +0100 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 2297, /**/ -- ASCII stupid question, get a stupid ANSI. /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///