Mercurial > vim
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(®match, 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, ®match, | 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. |