comparison src/quickfix.c @ 18607:fbeb1bf0cea8 v8.1.2297

patch 8.1.2297: the ex_vimgrep() function is too long Commit: https://github.com/vim/vim/commit/d6a98a3a9768568b668f91a53267b36f86b84466 Author: Bram Moolenaar <Bram@vim.org> Date: Tue Nov 12 22:59:51 2019 +0100 patch 8.1.2297: the ex_vimgrep() function is too long Problem: The ex_vimgrep() function is too long. Solution: Split it in three parts. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/5211)
author Bram Moolenaar <Bram@vim.org>
date Tue, 12 Nov 2019 23:00:04 +0100
parents 9e6d5a4abb1c
children 394abd397e15
comparison
equal deleted inserted replaced
18606:83eec237947f 18607:fbeb1bf0cea8
5317 * Get the nth quickfix entry below the specified entry. Searches forward in 5317 * Get the nth quickfix entry below the specified entry. Searches forward in
5318 * the list. If linewise is TRUE, then treat multiple entries on a single line 5318 * the list. If linewise is TRUE, then treat multiple entries on a single line
5319 * as one. 5319 * as one.
5320 */ 5320 */
5321 static void 5321 static void
5322 qf_get_nth_below_entry(qfline_T *entry, int n, int linewise, int *errornr) 5322 qf_get_nth_below_entry(qfline_T *entry_arg, int n, int linewise, int *errornr)
5323 { 5323 {
5324 qfline_T *entry = entry_arg;
5325
5324 while (n-- > 0 && !got_int) 5326 while (n-- > 0 && !got_int)
5325 { 5327 {
5326 qfline_T *first_entry = entry;
5327 int first_errornr = *errornr; 5328 int first_errornr = *errornr;
5328 5329
5329 if (linewise) 5330 if (linewise)
5330 // Treat all the entries on the same line in this file as one 5331 // Treat all the entries on the same line in this file as one
5331 entry = qf_find_last_entry_on_line(entry, errornr); 5332 entry = qf_find_last_entry_on_line(entry, errornr);
5332 5333
5333 if (entry->qf_next == NULL 5334 if (entry->qf_next == NULL
5334 || entry->qf_next->qf_fnum != entry->qf_fnum) 5335 || entry->qf_next->qf_fnum != entry->qf_fnum)
5335 { 5336 {
5336 if (linewise) 5337 if (linewise)
5337 {
5338 // If multiple entries are on the same line, then use the first
5339 // entry
5340 entry = first_entry;
5341 *errornr = first_errornr; 5338 *errornr = first_errornr;
5342 }
5343 break; 5339 break;
5344 } 5340 }
5345 5341
5346 entry = entry->qf_next; 5342 entry = entry->qf_next;
5347 ++*errornr; 5343 ++*errornr;
5813 ex_cd(&ea); 5809 ex_cd(&ea);
5814 } 5810 }
5815 } 5811 }
5816 5812
5817 /* 5813 /*
5818 * ":vimgrep {pattern} file(s)" 5814 * :vimgrep command arguments
5819 * ":vimgrepadd {pattern} file(s)" 5815 */
5820 * ":lvimgrep {pattern} file(s)" 5816 typedef struct
5821 * ":lvimgrepadd {pattern} file(s)" 5817 {
5822 */ 5818 long tomatch; // maximum number of matches to find
5823 void 5819 char_u *spat; // search pattern
5824 ex_vimgrep(exarg_T *eap) 5820 int flags; // search modifier
5825 { 5821 char_u **fnames; // list of files to search
5826 regmmatch_T regmatch; 5822 int fcount; // number of files
5827 int fcount; 5823 regmmatch_T regmatch; // compiled search pattern
5828 char_u **fnames; 5824 char_u *qf_title; // quickfix list title
5825 } vgr_args_T;
5826
5827 /*
5828 * Process :vimgrep command arguments. The command syntax is:
5829 *
5830 * :{count}vimgrep /{pattern}/[g][j] {file} ...
5831 */
5832 static int
5833 vgr_process_args(
5834 exarg_T *eap,
5835 vgr_args_T *args)
5836 {
5837 char_u *p;
5838
5839 vim_memset(args, 0, sizeof(*args));
5840
5841 args->regmatch.regprog = NULL;
5842 args->qf_title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
5843
5844 if (eap->addr_count > 0)
5845 args->tomatch = eap->line2;
5846 else
5847 args->tomatch = MAXLNUM;
5848
5849 // Get the search pattern: either white-separated or enclosed in //
5850 p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags);
5851 if (p == NULL)
5852 {
5853 emsg(_(e_invalpat));
5854 return FAIL;
5855 }
5856
5857 vgr_init_regmatch(&args->regmatch, args->spat);
5858 if (args->regmatch.regprog == NULL)
5859 return FAIL;
5860
5861 p = skipwhite(p);
5862 if (*p == NUL)
5863 {
5864 emsg(_("E683: File name missing or invalid pattern"));
5865 return FAIL;
5866 }
5867
5868 // parse the list of arguments
5869 if (get_arglist_exp(p, &args->fcount, &args->fnames, TRUE) == FAIL)
5870 return FAIL;
5871 if (args->fcount == 0)
5872 {
5873 emsg(_(e_nomatch));
5874 return FAIL;
5875 }
5876
5877 return OK;
5878 }
5879
5880 /*
5881 * Search for a pattern in a list of files and populate the quickfix list with
5882 * the matches.
5883 */
5884 static int
5885 vgr_process_files(
5886 win_T *wp,
5887 qf_info_T *qi,
5888 vgr_args_T *cmd_args,
5889 int *redraw_for_dummy,
5890 buf_T **first_match_buf,
5891 char_u **target_dir)
5892 {
5893 int status = FAIL;
5894 int_u save_qfid = qf_get_curlist(qi)->qf_id;
5895 time_t seconds = 0;
5829 char_u *fname; 5896 char_u *fname;
5830 char_u *title;
5831 char_u *s;
5832 char_u *p;
5833 int fi; 5897 int fi;
5834 qf_info_T *qi;
5835 qf_list_T *qfl;
5836 int_u save_qfid;
5837 win_T *wp = NULL;
5838 buf_T *buf; 5898 buf_T *buf;
5839 int duplicate_name = FALSE; 5899 int duplicate_name = FALSE;
5840 int using_dummy; 5900 int using_dummy;
5841 int redraw_for_dummy = FALSE;
5842 int found_match;
5843 buf_T *first_match_buf = NULL;
5844 time_t seconds = 0;
5845 aco_save_T aco;
5846 int flags = 0;
5847 long tomatch;
5848 char_u *dirname_start = NULL; 5901 char_u *dirname_start = NULL;
5849 char_u *dirname_now = NULL; 5902 char_u *dirname_now = NULL;
5850 char_u *target_dir = NULL; 5903 int found_match;
5851 char_u *au_name = NULL; 5904 aco_save_T aco;
5852
5853 au_name = vgr_get_auname(eap->cmdidx);
5854 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
5855 curbuf->b_fname, TRUE, curbuf))
5856 {
5857 #ifdef FEAT_EVAL
5858 if (aborting())
5859 return;
5860 #endif
5861 }
5862
5863 qi = qf_cmd_get_or_alloc_stack(eap, &wp);
5864 if (qi == NULL)
5865 return;
5866
5867 if (eap->addr_count > 0)
5868 tomatch = eap->line2;
5869 else
5870 tomatch = MAXLNUM;
5871
5872 // Get the search pattern: either white-separated or enclosed in //
5873 regmatch.regprog = NULL;
5874 title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
5875 p = skip_vimgrep_pat(eap->arg, &s, &flags);
5876 if (p == NULL)
5877 {
5878 emsg(_(e_invalpat));
5879 goto theend;
5880 }
5881
5882 vgr_init_regmatch(&regmatch, s);
5883 if (regmatch.regprog == NULL)
5884 goto theend;
5885
5886 p = skipwhite(p);
5887 if (*p == NUL)
5888 {
5889 emsg(_("E683: File name missing or invalid pattern"));
5890 goto theend;
5891 }
5892
5893 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
5894 && eap->cmdidx != CMD_vimgrepadd
5895 && eap->cmdidx != CMD_lvimgrepadd)
5896 || qf_stack_empty(qi))
5897 // make place for a new list
5898 qf_new_list(qi, title != NULL ? title : qf_cmdtitle(*eap->cmdlinep));
5899
5900 // parse the list of arguments
5901 if (get_arglist_exp(p, &fcount, &fnames, TRUE) == FAIL)
5902 goto theend;
5903 if (fcount == 0)
5904 {
5905 emsg(_(e_nomatch));
5906 goto theend;
5907 }
5908 5905
5909 dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start); 5906 dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start);
5910 dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now); 5907 dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now);
5911 if (dirname_start == NULL || dirname_now == NULL) 5908 if (dirname_start == NULL || dirname_now == NULL)
5912 {
5913 FreeWild(fcount, fnames);
5914 goto theend; 5909 goto theend;
5915 }
5916 5910
5917 // Remember the current directory, because a BufRead autocommand that does 5911 // Remember the current directory, because a BufRead autocommand that does
5918 // ":lcd %:p:h" changes the meaning of short path names. 5912 // ":lcd %:p:h" changes the meaning of short path names.
5919 mch_dirname(dirname_start, MAXPATHL); 5913 mch_dirname(dirname_start, MAXPATHL);
5920 5914
5921 incr_quickfix_busy();
5922
5923 // Remember the current quickfix list identifier, so that we can check for
5924 // autocommands changing the current quickfix list.
5925 save_qfid = qf_get_curlist(qi)->qf_id;
5926
5927 seconds = (time_t)0; 5915 seconds = (time_t)0;
5928 for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) 5916 for (fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0;
5929 { 5917 ++fi)
5930 fname = shorten_fname1(fnames[fi]); 5918 {
5919 fname = shorten_fname1(cmd_args->fnames[fi]);
5931 if (time(NULL) > seconds) 5920 if (time(NULL) > seconds)
5932 { 5921 {
5933 // Display the file name every second or so, show the user we are 5922 // Display the file name every second or so, show the user we are
5934 // working on it. 5923 // working on it.
5935 seconds = time(NULL); 5924 seconds = time(NULL);
5936 vgr_display_fname(fname); 5925 vgr_display_fname(fname);
5937 } 5926 }
5938 5927
5939 buf = buflist_findname_exp(fnames[fi]); 5928 buf = buflist_findname_exp(cmd_args->fnames[fi]);
5940 if (buf == NULL || buf->b_ml.ml_mfp == NULL) 5929 if (buf == NULL || buf->b_ml.ml_mfp == NULL)
5941 { 5930 {
5942 // Remember that a buffer with this name already exists. 5931 // Remember that a buffer with this name already exists.
5943 duplicate_name = (buf != NULL); 5932 duplicate_name = (buf != NULL);
5944 using_dummy = TRUE; 5933 using_dummy = TRUE;
5945 redraw_for_dummy = TRUE; 5934 *redraw_for_dummy = TRUE;
5946 5935
5947 buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now); 5936 buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now);
5948 } 5937 }
5949 else 5938 else
5950 // Use existing, loaded buffer. 5939 // Use existing, loaded buffer.
5951 using_dummy = FALSE; 5940 using_dummy = FALSE;
5952 5941
5953 // Check whether the quickfix list is still valid. When loading a 5942 // Check whether the quickfix list is still valid. When loading a
5954 // buffer above, autocommands might have changed the quickfix list. 5943 // buffer above, autocommands might have changed the quickfix list.
5955 if (!vgr_qflist_valid(wp, qi, save_qfid, qf_cmdtitle(*eap->cmdlinep))) 5944 if (!vgr_qflist_valid(wp, qi, save_qfid, cmd_args->qf_title))
5956 {
5957 FreeWild(fcount, fnames);
5958 decr_quickfix_busy();
5959 goto theend; 5945 goto theend;
5960 } 5946
5961 save_qfid = qf_get_curlist(qi)->qf_id; 5947 save_qfid = qf_get_curlist(qi)->qf_id;
5962 5948
5963 if (buf == NULL) 5949 if (buf == NULL)
5964 { 5950 {
5965 if (!got_int) 5951 if (!got_int)
5968 else 5954 else
5969 { 5955 {
5970 // Try for a match in all lines of the buffer. 5956 // Try for a match in all lines of the buffer.
5971 // For ":1vimgrep" look for first match only. 5957 // For ":1vimgrep" look for first match only.
5972 found_match = vgr_match_buflines(qf_get_curlist(qi), 5958 found_match = vgr_match_buflines(qf_get_curlist(qi),
5973 fname, buf, &regmatch, 5959 fname, buf, &cmd_args->regmatch,
5974 &tomatch, duplicate_name, flags); 5960 &cmd_args->tomatch, duplicate_name, cmd_args->flags);
5975 5961
5976 if (using_dummy) 5962 if (using_dummy)
5977 { 5963 {
5978 if (found_match && first_match_buf == NULL) 5964 if (found_match && *first_match_buf == NULL)
5979 first_match_buf = buf; 5965 *first_match_buf = buf;
5980 if (duplicate_name) 5966 if (duplicate_name)
5981 { 5967 {
5982 // Never keep a dummy buffer if there is another buffer 5968 // Never keep a dummy buffer if there is another buffer
5983 // with the same name. 5969 // with the same name.
5984 wipe_dummy_buffer(buf, dirname_start); 5970 wipe_dummy_buffer(buf, dirname_start);
5998 if (!found_match) 5984 if (!found_match)
5999 { 5985 {
6000 wipe_dummy_buffer(buf, dirname_start); 5986 wipe_dummy_buffer(buf, dirname_start);
6001 buf = NULL; 5987 buf = NULL;
6002 } 5988 }
6003 else if (buf != first_match_buf || (flags & VGR_NOJUMP)) 5989 else if (buf != *first_match_buf
5990 || (cmd_args->flags & VGR_NOJUMP))
6004 { 5991 {
6005 unload_dummy_buffer(buf, dirname_start); 5992 unload_dummy_buffer(buf, dirname_start);
6006 // Keeping the buffer, remove the dummy flag. 5993 // Keeping the buffer, remove the dummy flag.
6007 buf->b_flags &= ~BF_DUMMY; 5994 buf->b_flags &= ~BF_DUMMY;
6008 buf = NULL; 5995 buf = NULL;
6014 // Keeping the buffer, remove the dummy flag. 6001 // Keeping the buffer, remove the dummy flag.
6015 buf->b_flags &= ~BF_DUMMY; 6002 buf->b_flags &= ~BF_DUMMY;
6016 6003
6017 // If the buffer is still loaded we need to use the 6004 // If the buffer is still loaded we need to use the
6018 // directory we jumped to below. 6005 // directory we jumped to below.
6019 if (buf == first_match_buf 6006 if (buf == *first_match_buf
6020 && target_dir == NULL 6007 && *target_dir == NULL
6021 && STRCMP(dirname_start, dirname_now) != 0) 6008 && STRCMP(dirname_start, dirname_now) != 0)
6022 target_dir = vim_strsave(dirname_now); 6009 *target_dir = vim_strsave(dirname_now);
6023 6010
6024 // The buffer is still loaded, the Filetype autocommands 6011 // The buffer is still loaded, the Filetype autocommands
6025 // need to be done now, in that buffer. And the modelines 6012 // need to be done now, in that buffer. And the modelines
6026 // need to be done (again). But not the window-local 6013 // need to be done (again). But not the window-local
6027 // options! 6014 // options!
6035 } 6022 }
6036 } 6023 }
6037 } 6024 }
6038 } 6025 }
6039 6026
6040 FreeWild(fcount, fnames); 6027 status = OK;
6028
6029 theend:
6030 vim_free(dirname_now);
6031 vim_free(dirname_start);
6032 return status;
6033 }
6034
6035 /*
6036 * ":vimgrep {pattern} file(s)"
6037 * ":vimgrepadd {pattern} file(s)"
6038 * ":lvimgrep {pattern} file(s)"
6039 * ":lvimgrepadd {pattern} file(s)"
6040 */
6041 void
6042 ex_vimgrep(exarg_T *eap)
6043 {
6044 vgr_args_T args;
6045 qf_info_T *qi;
6046 qf_list_T *qfl;
6047 int_u save_qfid;
6048 win_T *wp = NULL;
6049 int redraw_for_dummy = FALSE;
6050 buf_T *first_match_buf = NULL;
6051 char_u *target_dir = NULL;
6052 char_u *au_name = NULL;
6053 int status;
6054
6055 au_name = vgr_get_auname(eap->cmdidx);
6056 if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
6057 curbuf->b_fname, TRUE, curbuf))
6058 {
6059 #ifdef FEAT_EVAL
6060 if (aborting())
6061 return;
6062 #endif
6063 }
6064
6065 qi = qf_cmd_get_or_alloc_stack(eap, &wp);
6066 if (qi == NULL)
6067 return;
6068
6069 if (vgr_process_args(eap, &args) == FAIL)
6070 goto theend;
6071
6072 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
6073 && eap->cmdidx != CMD_vimgrepadd
6074 && eap->cmdidx != CMD_lvimgrepadd)
6075 || qf_stack_empty(qi))
6076 // make place for a new list
6077 qf_new_list(qi, args.qf_title);
6078
6079 incr_quickfix_busy();
6080
6081 status = vgr_process_files(wp, qi, &args, &redraw_for_dummy,
6082 &first_match_buf, &target_dir);
6083 if (status != OK)
6084 {
6085 FreeWild(args.fcount, args.fnames);
6086 decr_quickfix_busy();
6087 goto theend;
6088 }
6089
6090 FreeWild(args.fcount, args.fnames);
6041 6091
6042 qfl = qf_get_curlist(qi); 6092 qfl = qf_get_curlist(qi);
6043 qfl->qf_nonevalid = FALSE; 6093 qfl->qf_nonevalid = FALSE;
6044 qfl->qf_ptr = qfl->qf_start; 6094 qfl->qf_ptr = qfl->qf_start;
6045 qfl->qf_index = 1; 6095 qfl->qf_index = 1;
6046 qf_list_changed(qfl); 6096 qf_list_changed(qfl);
6047 6097
6048 qf_update_buffer(qi, NULL); 6098 qf_update_buffer(qi, NULL);
6099
6100 // Remember the current quickfix list identifier, so that we can check for
6101 // autocommands changing the current quickfix list.
6102 save_qfid = qf_get_curlist(qi)->qf_id;
6049 6103
6050 if (au_name != NULL) 6104 if (au_name != NULL)
6051 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, 6105 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
6052 curbuf->b_fname, TRUE, curbuf); 6106 curbuf->b_fname, TRUE, curbuf);
6053 // The QuickFixCmdPost autocmd may free the quickfix list. Check the list 6107 // The QuickFixCmdPost autocmd may free the quickfix list. Check the list
6060 } 6114 }
6061 6115
6062 // Jump to first match. 6116 // Jump to first match.
6063 if (!qf_list_empty(qf_get_curlist(qi))) 6117 if (!qf_list_empty(qf_get_curlist(qi)))
6064 { 6118 {
6065 if ((flags & VGR_NOJUMP) == 0) 6119 if ((args.flags & VGR_NOJUMP) == 0)
6066 vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy, 6120 vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
6067 first_match_buf, target_dir); 6121 first_match_buf, target_dir);
6068 } 6122 }
6069 else 6123 else
6070 semsg(_(e_nomatch2), s); 6124 semsg(_(e_nomatch2), args.spat);
6071 6125
6072 decr_quickfix_busy(); 6126 decr_quickfix_busy();
6073 6127
6074 // If we loaded a dummy buffer into the current window, the autocommands 6128 // If we loaded a dummy buffer into the current window, the autocommands
6075 // may have messed up things, need to redraw and recompute folds. 6129 // may have messed up things, need to redraw and recompute folds.
6081 redraw_later(NOT_VALID); 6135 redraw_later(NOT_VALID);
6082 #endif 6136 #endif
6083 } 6137 }
6084 6138
6085 theend: 6139 theend:
6086 vim_free(title); 6140 vim_free(args.qf_title);
6087 vim_free(dirname_now);
6088 vim_free(dirname_start);
6089 vim_free(target_dir); 6141 vim_free(target_dir);
6090 vim_regfree(regmatch.regprog); 6142 vim_regfree(args.regmatch.regprog);
6091 } 6143 }
6092 6144
6093 /* 6145 /*
6094 * Restore current working directory to "dirname_start" if they differ, taking 6146 * Restore current working directory to "dirname_start" if they differ, taking
6095 * into account whether it is set locally or globally. 6147 * into account whether it is set locally or globally.