To: vim_dev@googlegroups.com Subject: Patch 8.0.1634 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.0.1634 Problem: The ex_vimgrep() function is too long. Solution: Split it in smaller functions. (Yegappan Lakshmanan) Files: src/quickfix.c *** ../vim-8.0.1633/src/quickfix.c 2018-03-20 13:30:38.541270285 +0100 --- src/quickfix.c 2018-03-24 13:41:36.922735773 +0100 *************** *** 133,161 **** static efm_T *fmt_start = NULL; /* cached across qf_parse_line() calls */ static int qf_init_ext(qf_info_T *qi, int qf_idx, char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast, char_u *qf_title, char_u *enc); - static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title); static void qf_new_list(qf_info_T *qi, char_u *qf_title); - static void ll_free_all(qf_info_T **pqi); static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid); - static qf_info_T *ll_new_list(void); static void qf_free(qf_info_T *qi, int idx); static char_u *qf_types(int, int); static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *); static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack); static char_u *qf_pop_dir(struct dir_stack_T **); static char_u *qf_guess_filepath(qf_info_T *qi, int qf_idx, char_u *); - static int qflist_valid(win_T *wp, int_u qf_id); static void qf_fmt_text(char_u *text, char_u *buf, int bufsize); - static void qf_clean_dir_stack(struct dir_stack_T **); static int qf_win_pos_update(qf_info_T *qi, int old_qf_index); - static int is_qf_win(win_T *win, qf_info_T *qi); static win_T *qf_find_win(qf_info_T *qi); static buf_T *qf_find_buf(qf_info_T *qi); static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last); static void qf_set_title_var(qf_info_T *qi); static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last); static char_u *get_mef_name(void); - static void restore_start_dir(char_u *dirname_start); static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir); static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start); static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start); --- 133,154 ---- *************** *** 4167,4172 **** --- 4160,4412 ---- } /* + * Return the vimgrep autocmd name. + */ + static char_u * + vgr_get_auname(cmdidx_T cmdidx) + { + switch (cmdidx) + { + case CMD_vimgrep: return (char_u *)"vimgrep"; + case CMD_lvimgrep: return (char_u *)"lvimgrep"; + case CMD_vimgrepadd: return (char_u *)"vimgrepadd"; + case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd"; + case CMD_grep: return (char_u *)"grep"; + case CMD_lgrep: return (char_u *)"lgrep"; + case CMD_grepadd: return (char_u *)"grepadd"; + case CMD_lgrepadd: return (char_u *)"lgrepadd"; + default: return NULL; + } + } + + /* + * Initialize the regmatch used by vimgrep for pattern "s". + */ + static void + vgr_init_regmatch(regmmatch_T *regmatch, char_u *s) + { + /* Get the search pattern: either white-separated or enclosed in // */ + regmatch->regprog = NULL; + + if (s == NULL || *s == NUL) + { + /* Pattern is empty, use last search pattern. */ + if (last_search_pat() == NULL) + { + EMSG(_(e_noprevre)); + return; + } + regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC); + } + else + regmatch->regprog = vim_regcomp(s, RE_MAGIC); + + regmatch->rmm_ic = p_ic; + regmatch->rmm_maxcol = 0; + } + + /* + * Display a file name when vimgrep is running. + */ + static void + vgr_display_fname(char_u *fname) + { + char_u *p; + + msg_start(); + p = msg_strtrunc(fname, TRUE); + if (p == NULL) + msg_outtrans(fname); + else + { + msg_outtrans(p); + vim_free(p); + } + msg_clr_eos(); + msg_didout = FALSE; /* overwrite this message */ + msg_nowait = TRUE; /* don't wait for this message */ + msg_col = 0; + out_flush(); + } + + /* + * Load a dummy buffer to search for a pattern using vimgrep. + */ + static buf_T * + vgr_load_dummy_buf( + char_u *fname, + char_u *dirname_start, + char_u *dirname_now) + { + int save_mls; + #if defined(FEAT_SYN_HL) + char_u *save_ei = NULL; + #endif + buf_T *buf; + + #if defined(FEAT_SYN_HL) + /* Don't do Filetype autocommands to avoid loading syntax and + * indent scripts, a great speed improvement. */ + save_ei = au_event_disable(",Filetype"); + #endif + /* Don't use modelines here, it's useless. */ + save_mls = p_mls; + p_mls = 0; + + /* Load file into a buffer, so that 'fileencoding' is detected, + * autocommands applied, etc. */ + buf = load_dummy_buffer(fname, dirname_start, dirname_now); + + p_mls = save_mls; + #if defined(FEAT_SYN_HL) + au_event_restore(save_ei); + #endif + + return buf; + } + + /* + * Check whether a quickfix/location list valid. Autocmds may remove or change + * a quickfix list when vimgrep is running. If the list is not found, create a + * new list. + */ + static int + vgr_qflist_valid( + qf_info_T *qi, + int_u save_qfid, + qfline_T *cur_qf_start, + int loclist_cmd, + char_u *title) + { + if (loclist_cmd) + { + /* + * Verify that the location list is still valid. An autocmd might + * have freed the location list. + */ + if (!qflist_valid(curwin, save_qfid)) + { + EMSG(_(e_loc_list_changed)); + return FALSE; + } + } + if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start) + { + int idx; + + /* Autocommands changed the quickfix list. Find the one we were + * using and restore it. */ + for (idx = 0; idx < LISTCOUNT; ++idx) + if (cur_qf_start == qi->qf_lists[idx].qf_start) + { + qi->qf_curlist = idx; + break; + } + if (idx == LISTCOUNT) + /* List cannot be found, create a new one. */ + qf_new_list(qi, title); + } + + return TRUE; + } + + /* + * Search for a pattern in all the lines in a buffer and add the matching lines + * to a quickfix list. + */ + static int + vgr_match_buflines( + qf_info_T *qi, + char_u *fname, + buf_T *buf, + regmmatch_T *regmatch, + long tomatch, + int duplicate_name, + int flags) + { + int found_match = FALSE; + long lnum; + colnr_T col; + + for (lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; ++lnum) + { + col = 0; + while (vim_regexec_multi(regmatch, curwin, buf, lnum, + col, NULL, NULL) > 0) + { + /* Pass the buffer number so that it gets used even for a + * dummy buffer, unless duplicate_name is set, then the + * buffer will be wiped out below. */ + if (qf_add_entry(qi, + qi->qf_curlist, + NULL, /* dir */ + fname, + duplicate_name ? 0 : buf->b_fnum, + ml_get_buf(buf, + regmatch->startpos[0].lnum + lnum, FALSE), + regmatch->startpos[0].lnum + lnum, + regmatch->startpos[0].col + 1, + FALSE, /* vis_col */ + NULL, /* search pattern */ + 0, /* nr */ + 0, /* type */ + TRUE /* valid */ + ) == FAIL) + { + got_int = TRUE; + break; + } + found_match = TRUE; + if (--tomatch == 0) + break; + if ((flags & VGR_GLOBAL) == 0 + || regmatch->endpos[0].lnum > 0) + break; + col = regmatch->endpos[0].col + + (col == regmatch->endpos[0].col); + if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE))) + break; + } + line_breakcheck(); + if (got_int) + break; + } + + return found_match; + } + + /* + * Jump to the first match and update the directory. + */ + static void + vgr_jump_to_match( + qf_info_T *qi, + int forceit, + int *redraw_for_dummy, + buf_T *first_match_buf, + char_u *target_dir) + { + buf_T *buf; + + buf = curbuf; + qf_jump(qi, 0, 0, forceit); + if (buf != curbuf) + /* If we jumped to another buffer redrawing will already be + * taken care of. */ + *redraw_for_dummy = FALSE; + + /* Jump to the directory used after loading the buffer. */ + if (curbuf == first_match_buf && target_dir != NULL) + { + exarg_T ea; + + ea.arg = target_dir; + ea.cmdidx = CMD_lcd; + ex_cd(&ea); + } + } + + /* * ":vimgrep {pattern} file(s)" * ":vimgrepadd {pattern} file(s)" * ":lvimgrep {pattern} file(s)" *************** *** 4188,4194 **** int_u save_qfid; qfline_T *cur_qf_start; win_T *wp; - long lnum; buf_T *buf; int duplicate_name = FALSE; int using_dummy; --- 4428,4433 ---- *************** *** 4196,4226 **** int found_match; buf_T *first_match_buf = NULL; time_t seconds = 0; - int save_mls; - #if defined(FEAT_SYN_HL) - char_u *save_ei = NULL; - #endif aco_save_T aco; int flags = 0; - colnr_T col; long tomatch; char_u *dirname_start = NULL; char_u *dirname_now = NULL; char_u *target_dir = NULL; char_u *au_name = NULL; ! switch (eap->cmdidx) ! { ! case CMD_vimgrep: au_name = (char_u *)"vimgrep"; break; ! case CMD_lvimgrep: au_name = (char_u *)"lvimgrep"; break; ! case CMD_vimgrepadd: au_name = (char_u *)"vimgrepadd"; break; ! case CMD_lvimgrepadd: au_name = (char_u *)"lvimgrepadd"; break; ! case CMD_grep: au_name = (char_u *)"grep"; break; ! case CMD_lgrep: au_name = (char_u *)"lgrep"; break; ! case CMD_grepadd: au_name = (char_u *)"grepadd"; break; ! case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break; ! default: break; ! } if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, curbuf->b_fname, TRUE, curbuf)) { --- 4435,4449 ---- 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)) { *************** *** 4256,4278 **** goto theend; } ! if (s == NULL || *s == NUL) ! { ! /* Pattern is empty, use last search pattern. */ ! if (last_search_pat() == NULL) ! { ! EMSG(_(e_noprevre)); ! goto theend; ! } ! regmatch.regprog = vim_regcomp(last_search_pat(), RE_MAGIC); ! } ! else ! regmatch.regprog = vim_regcomp(s, RE_MAGIC); ! if (regmatch.regprog == NULL) goto theend; - regmatch.rmm_ic = p_ic; - regmatch.rmm_maxcol = 0; p = skipwhite(p); if (*p == NUL) --- 4479,4487 ---- goto theend; } ! vgr_init_regmatch(®match, s); if (regmatch.regprog == NULL) goto theend; p = skipwhite(p); if (*p == NUL) *************** *** 4282,4288 **** } if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd ! && eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) || qi->qf_curlist == qi->qf_listcount) /* make place for a new list */ qf_new_list(qi, title != NULL ? title : *eap->cmdlinep); --- 4491,4498 ---- } if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd ! && eap->cmdidx != CMD_vimgrepadd ! && eap->cmdidx != CMD_lvimgrepadd) || qi->qf_curlist == qi->qf_listcount) /* make place for a new list */ qf_new_list(qi, title != NULL ? title : *eap->cmdlinep); *************** *** 4322,4341 **** /* Display the file name every second or so, show the user we are * working on it. */ seconds = time(NULL); ! msg_start(); ! p = msg_strtrunc(fname, TRUE); ! if (p == NULL) ! msg_outtrans(fname); ! else ! { ! msg_outtrans(p); ! vim_free(p); ! } ! msg_clr_eos(); ! msg_didout = FALSE; /* overwrite this message */ ! msg_nowait = TRUE; /* don't wait for this message */ ! msg_col = 0; ! out_flush(); } buf = buflist_findname_exp(fnames[fi]); --- 4532,4538 ---- /* Display the file name every second or so, show the user we are * working on it. */ seconds = time(NULL); ! vgr_display_fname(fname); } buf = buflist_findname_exp(fnames[fi]); *************** *** 4346,4404 **** using_dummy = TRUE; redraw_for_dummy = TRUE; ! #if defined(FEAT_SYN_HL) ! /* Don't do Filetype autocommands to avoid loading syntax and ! * indent scripts, a great speed improvement. */ ! save_ei = au_event_disable(",Filetype"); ! #endif ! /* Don't use modelines here, it's useless. */ ! save_mls = p_mls; ! p_mls = 0; ! ! /* Load file into a buffer, so that 'fileencoding' is detected, ! * autocommands applied, etc. */ ! buf = load_dummy_buffer(fname, dirname_start, dirname_now); ! ! p_mls = save_mls; ! #if defined(FEAT_SYN_HL) ! au_event_restore(save_ei); ! #endif } else /* Use existing, loaded buffer. */ using_dummy = FALSE; ! if (loclist_cmd) ! { ! /* ! * Verify that the location list is still valid. An autocmd might ! * have freed the location list. ! */ ! if (!qflist_valid(curwin, save_qfid)) ! { ! EMSG(_(e_loc_list_changed)); ! goto theend; ! } ! } ! if (cur_qf_start != qi->qf_lists[qi->qf_curlist].qf_start) ! { ! int idx; ! ! /* Autocommands changed the quickfix list. Find the one we were ! * using and restore it. */ ! for (idx = 0; idx < LISTCOUNT; ++idx) ! if (cur_qf_start == qi->qf_lists[idx].qf_start) ! { ! qi->qf_curlist = idx; ! break; ! } ! if (idx == LISTCOUNT) ! { ! /* List cannot be found, create a new one. */ ! qf_new_list(qi, *eap->cmdlinep); ! cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; ! } ! } if (buf == NULL) { --- 4543,4559 ---- using_dummy = TRUE; redraw_for_dummy = TRUE; ! buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now); } else /* Use existing, loaded buffer. */ using_dummy = FALSE; ! /* Check whether the quickfix list is still valid */ ! if (!vgr_qflist_valid(qi, save_qfid, cur_qf_start, loclist_cmd, ! *eap->cmdlinep)) ! goto theend; ! cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; if (buf == NULL) { *************** *** 4409,4459 **** { /* Try for a match in all lines of the buffer. * For ":1vimgrep" look for first match only. */ ! found_match = FALSE; ! for (lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; ! ++lnum) ! { ! col = 0; ! while (vim_regexec_multi(®match, curwin, buf, lnum, ! col, NULL, NULL) > 0) ! { ! /* Pass the buffer number so that it gets used even for a ! * dummy buffer, unless duplicate_name is set, then the ! * buffer will be wiped out below. */ ! if (qf_add_entry(qi, ! qi->qf_curlist, ! NULL, /* dir */ ! fname, ! duplicate_name ? 0 : buf->b_fnum, ! ml_get_buf(buf, ! regmatch.startpos[0].lnum + lnum, FALSE), ! regmatch.startpos[0].lnum + lnum, ! regmatch.startpos[0].col + 1, ! FALSE, /* vis_col */ ! NULL, /* search pattern */ ! 0, /* nr */ ! 0, /* type */ ! TRUE /* valid */ ! ) == FAIL) ! { ! got_int = TRUE; ! break; ! } ! found_match = TRUE; ! if (--tomatch == 0) ! break; ! if ((flags & VGR_GLOBAL) == 0 ! || regmatch.endpos[0].lnum > 0) ! break; ! col = regmatch.endpos[0].col ! + (col == regmatch.endpos[0].col); ! if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE))) ! break; ! } ! line_breakcheck(); ! if (got_int) ! break; ! } cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; if (using_dummy) --- 4564,4572 ---- { /* Try for a match in all lines of the buffer. * For ":1vimgrep" look for first match only. */ ! found_match = vgr_match_buflines(qi, fname, buf, ®match, ! tomatch, duplicate_name, flags); ! cur_qf_start = qi->qf_lists[qi->qf_curlist].qf_start; if (using_dummy) *************** *** 4544,4567 **** if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { if ((flags & VGR_NOJUMP) == 0) ! { ! buf = curbuf; ! qf_jump(qi, 0, 0, eap->forceit); ! if (buf != curbuf) ! /* If we jumped to another buffer redrawing will already be ! * taken care of. */ ! redraw_for_dummy = FALSE; ! ! /* Jump to the directory used after loading the buffer. */ ! if (curbuf == first_match_buf && target_dir != NULL) ! { ! exarg_T ea; ! ! ea.arg = target_dir; ! ea.cmdidx = CMD_lcd; ! ex_cd(&ea); ! } ! } } else EMSG2(_(e_nomatch2), s); --- 4657,4664 ---- if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { if ((flags & VGR_NOJUMP) == 0) ! vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, ! first_match_buf, target_dir); } else EMSG2(_(e_nomatch2), s); *** ../vim-8.0.1633/src/version.c 2018-03-23 22:39:27.325233934 +0100 --- src/version.c 2018-03-24 13:35:52.728627086 +0100 *************** *** 768,769 **** --- 768,771 ---- { /* Add new patch number below this line */ + /**/ + 1634, /**/ -- hundred-and-one symptoms of being an internet addict: 47. You are so familiar with the WWW that you find the search engines useless. /// 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 ///