1edf3f97aSBram Moolenaar /* vi:set ts=8 sts=4 sw=4 noet:
2071d4279SBram Moolenaar *
3071d4279SBram Moolenaar * VIM - Vi IMproved by Bram Moolenaar
4071d4279SBram Moolenaar *
5071d4279SBram Moolenaar * Do ":help uganda" in Vim to read copying and usage conditions.
6071d4279SBram Moolenaar * Do ":help credits" in Vim to see a list of people who contributed.
7071d4279SBram Moolenaar * See README.txt for an overview of the Vim source code.
8071d4279SBram Moolenaar */
9071d4279SBram Moolenaar
10071d4279SBram Moolenaar /*
11071d4279SBram Moolenaar * quickfix.c: functions for quickfix mode, using a file with error messages
12071d4279SBram Moolenaar */
13071d4279SBram Moolenaar
14071d4279SBram Moolenaar #include "vim.h"
15071d4279SBram Moolenaar
16071d4279SBram Moolenaar #if defined(FEAT_QUICKFIX) || defined(PROTO)
17071d4279SBram Moolenaar
18071d4279SBram Moolenaar struct dir_stack_T
19071d4279SBram Moolenaar {
20071d4279SBram Moolenaar struct dir_stack_T *next;
21071d4279SBram Moolenaar char_u *dirname;
22071d4279SBram Moolenaar };
23071d4279SBram Moolenaar
24071d4279SBram Moolenaar /*
2568b76a69SBram Moolenaar * For each error the next struct is allocated and linked in a list.
26071d4279SBram Moolenaar */
2768b76a69SBram Moolenaar typedef struct qfline_S qfline_T;
2868b76a69SBram Moolenaar struct qfline_S
29071d4279SBram Moolenaar {
3000bf8cd2SBram Moolenaar qfline_T *qf_next; // pointer to next error in the list
3100bf8cd2SBram Moolenaar qfline_T *qf_prev; // pointer to previous error in the list
3200bf8cd2SBram Moolenaar linenr_T qf_lnum; // line number where the error occurred
336864efa5Sthinca linenr_T qf_end_lnum; // line number when the error has range or zero
3400bf8cd2SBram Moolenaar int qf_fnum; // file number for the line
3500bf8cd2SBram Moolenaar int qf_col; // column where the error occurred
366864efa5Sthinca int qf_end_col; // column when the error has range or zero
3700bf8cd2SBram Moolenaar int qf_nr; // error number
3800bf8cd2SBram Moolenaar char_u *qf_module; // module name for this error
3900bf8cd2SBram Moolenaar char_u *qf_pattern; // search pattern for the error
4000bf8cd2SBram Moolenaar char_u *qf_text; // description of the error
416864efa5Sthinca char_u qf_viscol; // set to TRUE if qf_col and qf_end_col is
426864efa5Sthinca // screen column
4300bf8cd2SBram Moolenaar char_u qf_cleared; // set to TRUE if line has been deleted
4400bf8cd2SBram Moolenaar char_u qf_type; // type of the error (mostly 'E'); 1 for
4500bf8cd2SBram Moolenaar // :helpgrep
4600bf8cd2SBram Moolenaar char_u qf_valid; // valid error message detected
47071d4279SBram Moolenaar };
48071d4279SBram Moolenaar
49071d4279SBram Moolenaar /*
50071d4279SBram Moolenaar * There is a stack of error lists.
51071d4279SBram Moolenaar */
52071d4279SBram Moolenaar #define LISTCOUNT 10
53a2aa8a2bSBram Moolenaar #define INVALID_QFIDX (-1)
54ee8188fcSBram Moolenaar #define INVALID_QFBUFNR (0)
55071d4279SBram Moolenaar
566a8958dbSBram Moolenaar /*
572d67d307SBram Moolenaar * Quickfix list type.
582d67d307SBram Moolenaar */
592d67d307SBram Moolenaar typedef enum
602d67d307SBram Moolenaar {
612d67d307SBram Moolenaar QFLT_QUICKFIX, // Quickfix list - global list
622d67d307SBram Moolenaar QFLT_LOCATION, // Location list - per window list
632d67d307SBram Moolenaar QFLT_INTERNAL // Internal - Temporary list used by getqflist()/getloclist()
642d67d307SBram Moolenaar } qfltype_T;
652d67d307SBram Moolenaar
662d67d307SBram Moolenaar /*
676a8958dbSBram Moolenaar * Quickfix/Location list definition
686a8958dbSBram Moolenaar * Contains a list of entries (qfline_T). qf_start points to the first entry
696a8958dbSBram Moolenaar * and qf_last points to the last entry. qf_count contains the list size.
706a8958dbSBram Moolenaar *
716a8958dbSBram Moolenaar * Usually the list contains one or more entries. But an empty list can be
726a8958dbSBram Moolenaar * created using setqflist()/setloclist() with a title and/or user context
736a8958dbSBram Moolenaar * information and entries can be added later using setqflist()/setloclist().
746a8958dbSBram Moolenaar */
75d12f5c17SBram Moolenaar typedef struct qf_list_S
76071d4279SBram Moolenaar {
7700bf8cd2SBram Moolenaar int_u qf_id; // Unique identifier for this list
782d67d307SBram Moolenaar qfltype_T qfl_type;
7900bf8cd2SBram Moolenaar qfline_T *qf_start; // pointer to the first error
8000bf8cd2SBram Moolenaar qfline_T *qf_last; // pointer to the last error
8100bf8cd2SBram Moolenaar qfline_T *qf_ptr; // pointer to the current error
8200bf8cd2SBram Moolenaar int qf_count; // number of errors (0 means empty list)
8300bf8cd2SBram Moolenaar int qf_index; // current index in the error list
8400bf8cd2SBram Moolenaar int qf_nonevalid; // TRUE if not a single valid entry found
8500bf8cd2SBram Moolenaar char_u *qf_title; // title derived from the command that created
8600bf8cd2SBram Moolenaar // the error list or set by setqflist
8700bf8cd2SBram Moolenaar typval_T *qf_ctx; // context set by setqflist/setloclist
88d43906d2SBram Moolenaar callback_T qftf_cb; // 'quickfixtextfunc' callback function
89a7df8c70SBram Moolenaar
90a7df8c70SBram Moolenaar struct dir_stack_T *qf_dir_stack;
91a7df8c70SBram Moolenaar char_u *qf_directory;
92a7df8c70SBram Moolenaar struct dir_stack_T *qf_file_stack;
93a7df8c70SBram Moolenaar char_u *qf_currfile;
94a7df8c70SBram Moolenaar int qf_multiline;
95a7df8c70SBram Moolenaar int qf_multiignore;
96a7df8c70SBram Moolenaar int qf_multiscan;
97b254af31SBram Moolenaar long qf_changedtick;
98d12f5c17SBram Moolenaar } qf_list_T;
99071d4279SBram Moolenaar
1006a8958dbSBram Moolenaar /*
1016a8958dbSBram Moolenaar * Quickfix/Location list stack definition
1026a8958dbSBram Moolenaar * Contains a list of quickfix/location lists (qf_list_T)
1036a8958dbSBram Moolenaar */
104d12f5c17SBram Moolenaar struct qf_info_S
105d12f5c17SBram Moolenaar {
10600bf8cd2SBram Moolenaar // Count of references to this list. Used only for location lists.
10700bf8cd2SBram Moolenaar // When a location list window reference this list, qf_refcount
10800bf8cd2SBram Moolenaar // will be 2. Otherwise, qf_refcount will be 1. When qf_refcount
10900bf8cd2SBram Moolenaar // reaches 0, the list is freed.
110d12f5c17SBram Moolenaar int qf_refcount;
11100bf8cd2SBram Moolenaar int qf_listcount; // current number of lists
11200bf8cd2SBram Moolenaar int qf_curlist; // current error list
113d12f5c17SBram Moolenaar qf_list_T qf_lists[LISTCOUNT];
1142d67d307SBram Moolenaar qfltype_T qfl_type; // type of list
115ee8188fcSBram Moolenaar int qf_bufnr; // quickfix window buffer number
116d12f5c17SBram Moolenaar };
117d12f5c17SBram Moolenaar
11800bf8cd2SBram Moolenaar static qf_info_T ql_info; // global quickfix list
11900bf8cd2SBram Moolenaar static int_u last_qf_id = 0; // Last used quickfix list id
120071d4279SBram Moolenaar
12100bf8cd2SBram Moolenaar #define FMT_PATTERNS 11 // maximum number of % recognized
122071d4279SBram Moolenaar
123071d4279SBram Moolenaar /*
124071d4279SBram Moolenaar * Structure used to hold the info of one part of 'errorformat'
125071d4279SBram Moolenaar */
1260126585dSBram Moolenaar typedef struct efm_S efm_T;
1270126585dSBram Moolenaar struct efm_S
128071d4279SBram Moolenaar {
12900bf8cd2SBram Moolenaar regprog_T *prog; // pre-formatted part of 'errorformat'
13000bf8cd2SBram Moolenaar efm_T *next; // pointer to next (NULL if last)
13100bf8cd2SBram Moolenaar char_u addr[FMT_PATTERNS]; // indices of used % patterns
13200bf8cd2SBram Moolenaar char_u prefix; // prefix of this format line:
13300bf8cd2SBram Moolenaar // 'D' enter directory
13400bf8cd2SBram Moolenaar // 'X' leave directory
13500bf8cd2SBram Moolenaar // 'A' start of multi-line message
13600bf8cd2SBram Moolenaar // 'E' error message
13700bf8cd2SBram Moolenaar // 'W' warning message
13800bf8cd2SBram Moolenaar // 'I' informational message
139e928366dSBram Moolenaar // 'N' note message
14000bf8cd2SBram Moolenaar // 'C' continuation line
14100bf8cd2SBram Moolenaar // 'Z' end of multi-line message
14200bf8cd2SBram Moolenaar // 'G' general, unspecific message
14300bf8cd2SBram Moolenaar // 'P' push file (partial) message
14400bf8cd2SBram Moolenaar // 'Q' pop/quit file (partial) message
14500bf8cd2SBram Moolenaar // 'O' overread (partial) message
14600bf8cd2SBram Moolenaar char_u flags; // additional flags given in prefix
14700bf8cd2SBram Moolenaar // '-' do not include this line
14800bf8cd2SBram Moolenaar // '+' include whole line in message
14900bf8cd2SBram Moolenaar int conthere; // %> used
150071d4279SBram Moolenaar };
151071d4279SBram Moolenaar
1529f84ded3SBram Moolenaar // List of location lists to be deleted.
1539f84ded3SBram Moolenaar // Used to delay the deletion of locations lists by autocmds.
1549f84ded3SBram Moolenaar typedef struct qf_delq_S
1559f84ded3SBram Moolenaar {
1569f84ded3SBram Moolenaar struct qf_delq_S *next;
1579f84ded3SBram Moolenaar qf_info_T *qi;
1589f84ded3SBram Moolenaar } qf_delq_T;
1599f84ded3SBram Moolenaar static qf_delq_T *qf_delq_head = NULL;
1609f84ded3SBram Moolenaar
1619f84ded3SBram Moolenaar // Counter to prevent autocmds from freeing up location lists when they are
1629f84ded3SBram Moolenaar // still being used.
1639f84ded3SBram Moolenaar static int quickfix_busy = 0;
1649f84ded3SBram Moolenaar
16500bf8cd2SBram Moolenaar static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls
16663bed3d3SBram Moolenaar
167d43906d2SBram Moolenaar // callback function for 'quickfixtextfunc'
168d43906d2SBram Moolenaar static callback_T qftf_cb;
169d43906d2SBram Moolenaar
170baaa7e9eSBram Moolenaar static void qf_new_list(qf_info_T *qi, char_u *qf_title);
1716864efa5Sthinca static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, long end_lnum, int col, int end_col, int vis_col, char_u *pattern, int nr, int type, int valid);
172fe15b7dfSBram Moolenaar static void qf_free(qf_list_T *qfl);
173baaa7e9eSBram Moolenaar static char_u *qf_types(int, int);
1740398e00aSBram Moolenaar static int qf_get_fnum(qf_list_T *qfl, char_u *, char_u *);
175361c8f0eSBram Moolenaar static char_u *qf_push_dir(char_u *, struct dir_stack_T **, int is_file_stack);
176baaa7e9eSBram Moolenaar static char_u *qf_pop_dir(struct dir_stack_T **);
177fe15b7dfSBram Moolenaar static char_u *qf_guess_filepath(qf_list_T *qfl, char_u *);
1785843f5f3SBram Moolenaar static void qf_jump_newwin(qf_info_T *qi, int dir, int errornr, int forceit, int newwin);
179baaa7e9eSBram Moolenaar static void qf_fmt_text(char_u *text, char_u *buf, int bufsize);
1806864efa5Sthinca static void qf_range_text(qfline_T *qfp, char_u *buf, int bufsize);
181baaa7e9eSBram Moolenaar static int qf_win_pos_update(qf_info_T *qi, int old_qf_index);
182baaa7e9eSBram Moolenaar static win_T *qf_find_win(qf_info_T *qi);
183baaa7e9eSBram Moolenaar static buf_T *qf_find_buf(qf_info_T *qi);
184864293abSBram Moolenaar static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last);
1857ba5a7efSBram Moolenaar static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid);
186baaa7e9eSBram Moolenaar static buf_T *load_dummy_buffer(char_u *fname, char_u *dirname_start, char_u *resulting_dir);
187baaa7e9eSBram Moolenaar static void wipe_dummy_buffer(buf_T *buf, char_u *dirname_start);
188baaa7e9eSBram Moolenaar static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start);
189baaa7e9eSBram Moolenaar static qf_info_T *ll_get_or_alloc_list(win_T *);
1903ff33114SBram Moolenaar static char_u *e_no_more_items = (char_u *)N_("E553: No more items");
191071d4279SBram Moolenaar
19200bf8cd2SBram Moolenaar // Quickfix window check helper macro
193d12f5c17SBram Moolenaar #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL)
19400bf8cd2SBram Moolenaar // Location list window check helper macro
195d12f5c17SBram Moolenaar #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL)
1964d77c65aSBram Moolenaar
1974d77c65aSBram Moolenaar // Quickfix and location list stack check helper macros
1982d67d307SBram Moolenaar #define IS_QF_STACK(qi) (qi->qfl_type == QFLT_QUICKFIX)
1992d67d307SBram Moolenaar #define IS_LL_STACK(qi) (qi->qfl_type == QFLT_LOCATION)
2002d67d307SBram Moolenaar #define IS_QF_LIST(qfl) (qfl->qfl_type == QFLT_QUICKFIX)
2012d67d307SBram Moolenaar #define IS_LL_LIST(qfl) (qfl->qfl_type == QFLT_LOCATION)
2024d77c65aSBram Moolenaar
203d12f5c17SBram Moolenaar /*
204d12f5c17SBram Moolenaar * Return location list for window 'wp'
205d12f5c17SBram Moolenaar * For location list window, return the referenced location list
206d12f5c17SBram Moolenaar */
207d12f5c17SBram Moolenaar #define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist)
208d12f5c17SBram Moolenaar
20995946f12SBram Moolenaar // Macro to loop through all the items in a quickfix list
21095946f12SBram Moolenaar // Quickfix item index starts from 1, so i below starts at 1
211a16123a6SBram Moolenaar #define FOR_ALL_QFL_ITEMS(qfl, qfp, i) \
21295946f12SBram Moolenaar for (i = 1, qfp = qfl->qf_start; \
21395946f12SBram Moolenaar !got_int && i <= qfl->qf_count && qfp != NULL; \
214a16123a6SBram Moolenaar ++i, qfp = qfp->qf_next)
215a16123a6SBram Moolenaar
216071d4279SBram Moolenaar /*
2176dd4a535SBram Moolenaar * Looking up a buffer can be slow if there are many. Remember the last one
2186dd4a535SBram Moolenaar * to make this a lot faster if there are multiple matches in the same file.
2196dd4a535SBram Moolenaar */
2206dd4a535SBram Moolenaar static char_u *qf_last_bufname = NULL;
22145e5fd13SBram Moolenaar static bufref_T qf_last_bufref = {NULL, 0, 0};
2226dd4a535SBram Moolenaar
2234d170af0SBram Moolenaar static char *e_current_quickfix_list_was_changed =
2244d170af0SBram Moolenaar N_("E925: Current quickfix list was changed");
2254d170af0SBram Moolenaar static char *e_current_location_list_was_changed =
2263c097226SBram Moolenaar N_("E926: Current location list was changed");
2273c097226SBram Moolenaar
2286dd4a535SBram Moolenaar /*
2296be8c8e1SBram Moolenaar * Maximum number of bytes allowed per line while reading a errorfile.
2306be8c8e1SBram Moolenaar */
2316be8c8e1SBram Moolenaar #define LINE_MAXLEN 4096
2326be8c8e1SBram Moolenaar
233071d4279SBram Moolenaar static struct fmtpattern
234071d4279SBram Moolenaar {
235071d4279SBram Moolenaar char_u convchar;
236071d4279SBram Moolenaar char *pattern;
237071d4279SBram Moolenaar } fmt_pat[FMT_PATTERNS] =
238071d4279SBram Moolenaar {
23900bf8cd2SBram Moolenaar {'f', ".\\+"}, // only used when at end
240071d4279SBram Moolenaar {'n', "\\d\\+"},
241071d4279SBram Moolenaar {'l', "\\d\\+"},
242071d4279SBram Moolenaar {'c', "\\d\\+"},
243071d4279SBram Moolenaar {'t', "."},
244071d4279SBram Moolenaar {'m', ".\\+"},
245071d4279SBram Moolenaar {'r', ".*"},
246071d4279SBram Moolenaar {'p', "[- .]*"},
24768b76a69SBram Moolenaar {'v', "\\d\\+"},
248d76ce852SBram Moolenaar {'s', ".\\+"},
249d76ce852SBram Moolenaar {'o', ".\\+"}
250071d4279SBram Moolenaar };
251071d4279SBram Moolenaar
252688e3d1fSBram Moolenaar /*
2536bff719fSBram Moolenaar * Convert an errorformat pattern to a regular expression pattern.
254de3b3677SBram Moolenaar * See fmt_pat definition above for the list of supported patterns. The
255de3b3677SBram Moolenaar * pattern specifier is supplied in "efmpat". The converted pattern is stored
256de3b3677SBram Moolenaar * in "regpat". Returns a pointer to the location after the pattern.
257688e3d1fSBram Moolenaar */
2586bff719fSBram Moolenaar static char_u *
efmpat_to_regpat(char_u * efmpat,char_u * regpat,efm_T * efminfo,int idx,int round)259de3b3677SBram Moolenaar efmpat_to_regpat(
260de3b3677SBram Moolenaar char_u *efmpat,
261de3b3677SBram Moolenaar char_u *regpat,
262de3b3677SBram Moolenaar efm_T *efminfo,
2636bff719fSBram Moolenaar int idx,
264f9e3e09fSBram Moolenaar int round)
265071d4279SBram Moolenaar {
266688e3d1fSBram Moolenaar char_u *srcptr;
267071d4279SBram Moolenaar
268de3b3677SBram Moolenaar if (efminfo->addr[idx])
269071d4279SBram Moolenaar {
27000bf8cd2SBram Moolenaar // Each errorformat pattern can occur only once
271f9e3e09fSBram Moolenaar semsg(_("E372: Too many %%%c in format string"), *efmpat);
2726bff719fSBram Moolenaar return NULL;
273071d4279SBram Moolenaar }
2746bff719fSBram Moolenaar if ((idx && idx < 6
275de3b3677SBram Moolenaar && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
276071d4279SBram Moolenaar || (idx == 6
277de3b3677SBram Moolenaar && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL))
278071d4279SBram Moolenaar {
279f9e3e09fSBram Moolenaar semsg(_("E373: Unexpected %%%c in format string"), *efmpat);
2806bff719fSBram Moolenaar return NULL;
281071d4279SBram Moolenaar }
282de3b3677SBram Moolenaar efminfo->addr[idx] = (char_u)++round;
283de3b3677SBram Moolenaar *regpat++ = '\\';
284de3b3677SBram Moolenaar *regpat++ = '(';
285071d4279SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
286de3b3677SBram Moolenaar if (*efmpat == 'f')
287071d4279SBram Moolenaar {
28800bf8cd2SBram Moolenaar // Also match "c:" in the file name, even when
28900bf8cd2SBram Moolenaar // checking for a colon next: "%f:".
29000bf8cd2SBram Moolenaar // "\%(\a:\)\="
291de3b3677SBram Moolenaar STRCPY(regpat, "\\%(\\a:\\)\\=");
292de3b3677SBram Moolenaar regpat += 10;
293071d4279SBram Moolenaar }
294071d4279SBram Moolenaar #endif
295de3b3677SBram Moolenaar if (*efmpat == 'f' && efmpat[1] != NUL)
296071d4279SBram Moolenaar {
297de3b3677SBram Moolenaar if (efmpat[1] != '\\' && efmpat[1] != '%')
298e344beadSBram Moolenaar {
29900bf8cd2SBram Moolenaar // A file name may contain spaces, but this isn't
30000bf8cd2SBram Moolenaar // in "\f". For "%f:%l:%m" there may be a ":" in
30100bf8cd2SBram Moolenaar // the file name. Use ".\{-1,}x" instead (x is
30200bf8cd2SBram Moolenaar // the next character), the requirement that :999:
30300bf8cd2SBram Moolenaar // follows should work.
304de3b3677SBram Moolenaar STRCPY(regpat, ".\\{-1,}");
305de3b3677SBram Moolenaar regpat += 7;
306071d4279SBram Moolenaar }
307071d4279SBram Moolenaar else
308071d4279SBram Moolenaar {
30900bf8cd2SBram Moolenaar // File name followed by '\\' or '%': include as
31000bf8cd2SBram Moolenaar // many file name chars as possible.
311de3b3677SBram Moolenaar STRCPY(regpat, "\\f\\+");
312de3b3677SBram Moolenaar regpat += 4;
313e344beadSBram Moolenaar }
314e344beadSBram Moolenaar }
315e344beadSBram Moolenaar else
316e344beadSBram Moolenaar {
317071d4279SBram Moolenaar srcptr = (char_u *)fmt_pat[idx].pattern;
318de3b3677SBram Moolenaar while ((*regpat = *srcptr++) != NUL)
319de3b3677SBram Moolenaar ++regpat;
320071d4279SBram Moolenaar }
321de3b3677SBram Moolenaar *regpat++ = '\\';
322de3b3677SBram Moolenaar *regpat++ = ')';
3236bff719fSBram Moolenaar
324de3b3677SBram Moolenaar return regpat;
325071d4279SBram Moolenaar }
3266bff719fSBram Moolenaar
3276bff719fSBram Moolenaar /*
3286bff719fSBram Moolenaar * Convert a scanf like format in 'errorformat' to a regular expression.
329de3b3677SBram Moolenaar * Returns a pointer to the location after the pattern.
3306bff719fSBram Moolenaar */
3316bff719fSBram Moolenaar static char_u *
scanf_fmt_to_regpat(char_u ** pefmp,char_u * efm,int len,char_u * regpat)3326bff719fSBram Moolenaar scanf_fmt_to_regpat(
333de3b3677SBram Moolenaar char_u **pefmp,
3346bff719fSBram Moolenaar char_u *efm,
3356bff719fSBram Moolenaar int len,
336f9e3e09fSBram Moolenaar char_u *regpat)
337071d4279SBram Moolenaar {
3386bff719fSBram Moolenaar char_u *efmp = *pefmp;
3396bff719fSBram Moolenaar
340de3b3677SBram Moolenaar if (*efmp == '[' || *efmp == '\\')
341071d4279SBram Moolenaar {
34200bf8cd2SBram Moolenaar if ((*regpat++ = *efmp) == '[') // %*[^a-z0-9] etc.
343071d4279SBram Moolenaar {
344071d4279SBram Moolenaar if (efmp[1] == '^')
345de3b3677SBram Moolenaar *regpat++ = *++efmp;
346071d4279SBram Moolenaar if (efmp < efm + len)
347071d4279SBram Moolenaar {
34800bf8cd2SBram Moolenaar *regpat++ = *++efmp; // could be ']'
349071d4279SBram Moolenaar while (efmp < efm + len
350de3b3677SBram Moolenaar && (*regpat++ = *++efmp) != ']')
35100bf8cd2SBram Moolenaar // skip ;
352071d4279SBram Moolenaar if (efmp == efm + len)
353071d4279SBram Moolenaar {
354f9e3e09fSBram Moolenaar emsg(_("E374: Missing ] in format string"));
3556bff719fSBram Moolenaar return NULL;
356071d4279SBram Moolenaar }
357071d4279SBram Moolenaar }
358071d4279SBram Moolenaar }
35900bf8cd2SBram Moolenaar else if (efmp < efm + len) // %*\D, %*\s etc.
360de3b3677SBram Moolenaar *regpat++ = *++efmp;
361de3b3677SBram Moolenaar *regpat++ = '\\';
362de3b3677SBram Moolenaar *regpat++ = '+';
363071d4279SBram Moolenaar }
364071d4279SBram Moolenaar else
365071d4279SBram Moolenaar {
36600bf8cd2SBram Moolenaar // TODO: scanf()-like: %*ud, %*3c, %*f, ... ?
367f9e3e09fSBram Moolenaar semsg(_("E375: Unsupported %%%c in format string"), *efmp);
3686bff719fSBram Moolenaar return NULL;
369071d4279SBram Moolenaar }
3706bff719fSBram Moolenaar
3716bff719fSBram Moolenaar *pefmp = efmp;
3726bff719fSBram Moolenaar
373de3b3677SBram Moolenaar return regpat;
374071d4279SBram Moolenaar }
3756bff719fSBram Moolenaar
3766bff719fSBram Moolenaar /*
3776bff719fSBram Moolenaar * Analyze/parse an errorformat prefix.
3786bff719fSBram Moolenaar */
379de3b3677SBram Moolenaar static char_u *
efm_analyze_prefix(char_u * efmp,efm_T * efminfo)380f9e3e09fSBram Moolenaar efm_analyze_prefix(char_u *efmp, efm_T *efminfo)
381071d4279SBram Moolenaar {
382071d4279SBram Moolenaar if (vim_strchr((char_u *)"+-", *efmp) != NULL)
383de3b3677SBram Moolenaar efminfo->flags = *efmp++;
384e928366dSBram Moolenaar if (vim_strchr((char_u *)"DXAEWINCZGOPQ", *efmp) != NULL)
385de3b3677SBram Moolenaar efminfo->prefix = *efmp;
386071d4279SBram Moolenaar else
387071d4279SBram Moolenaar {
388f9e3e09fSBram Moolenaar semsg(_("E376: Invalid %%%c in format string prefix"), *efmp);
389de3b3677SBram Moolenaar return NULL;
3906bff719fSBram Moolenaar }
3916bff719fSBram Moolenaar
392de3b3677SBram Moolenaar return efmp;
3936bff719fSBram Moolenaar }
3946bff719fSBram Moolenaar
3956bff719fSBram Moolenaar /*
396de3b3677SBram Moolenaar * Converts a 'errorformat' string part in 'efm' to a regular expression
397de3b3677SBram Moolenaar * pattern. The resulting regex pattern is returned in "regpat". Additional
398de3b3677SBram Moolenaar * information about the 'erroformat' pattern is returned in "fmt_ptr".
399de3b3677SBram Moolenaar * Returns OK or FAIL.
4006bff719fSBram Moolenaar */
4016bff719fSBram Moolenaar static int
efm_to_regpat(char_u * efm,int len,efm_T * fmt_ptr,char_u * regpat)4026bff719fSBram Moolenaar efm_to_regpat(
4036bff719fSBram Moolenaar char_u *efm,
4046bff719fSBram Moolenaar int len,
4056bff719fSBram Moolenaar efm_T *fmt_ptr,
406f9e3e09fSBram Moolenaar char_u *regpat)
4076bff719fSBram Moolenaar {
4086bff719fSBram Moolenaar char_u *ptr;
4096bff719fSBram Moolenaar char_u *efmp;
4106bff719fSBram Moolenaar int round;
4116bff719fSBram Moolenaar int idx = 0;
4126bff719fSBram Moolenaar
41300bf8cd2SBram Moolenaar // Build a regexp pattern for a 'errorformat' option part
4146bff719fSBram Moolenaar ptr = regpat;
4156bff719fSBram Moolenaar *ptr++ = '^';
4166bff719fSBram Moolenaar round = 0;
4176bff719fSBram Moolenaar for (efmp = efm; efmp < efm + len; ++efmp)
4186bff719fSBram Moolenaar {
4196bff719fSBram Moolenaar if (*efmp == '%')
4206bff719fSBram Moolenaar {
4216bff719fSBram Moolenaar ++efmp;
4226bff719fSBram Moolenaar for (idx = 0; idx < FMT_PATTERNS; ++idx)
4236bff719fSBram Moolenaar if (fmt_pat[idx].convchar == *efmp)
4246bff719fSBram Moolenaar break;
4256bff719fSBram Moolenaar if (idx < FMT_PATTERNS)
4266bff719fSBram Moolenaar {
427f9e3e09fSBram Moolenaar ptr = efmpat_to_regpat(efmp, ptr, fmt_ptr, idx, round);
4286bff719fSBram Moolenaar if (ptr == NULL)
429de3b3677SBram Moolenaar return FAIL;
4306bff719fSBram Moolenaar round++;
4316bff719fSBram Moolenaar }
4326bff719fSBram Moolenaar else if (*efmp == '*')
4336bff719fSBram Moolenaar {
434de3b3677SBram Moolenaar ++efmp;
435f9e3e09fSBram Moolenaar ptr = scanf_fmt_to_regpat(&efmp, efm, len, ptr);
4366bff719fSBram Moolenaar if (ptr == NULL)
437de3b3677SBram Moolenaar return FAIL;
438071d4279SBram Moolenaar }
4396bff719fSBram Moolenaar else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL)
44000bf8cd2SBram Moolenaar *ptr++ = *efmp; // regexp magic characters
4416bff719fSBram Moolenaar else if (*efmp == '#')
4426bff719fSBram Moolenaar *ptr++ = '*';
4436bff719fSBram Moolenaar else if (*efmp == '>')
4446bff719fSBram Moolenaar fmt_ptr->conthere = TRUE;
44500bf8cd2SBram Moolenaar else if (efmp == efm + 1) // analyse prefix
4466bff719fSBram Moolenaar {
44700bf8cd2SBram Moolenaar // prefix is allowed only at the beginning of the errorformat
44800bf8cd2SBram Moolenaar // option part
449f9e3e09fSBram Moolenaar efmp = efm_analyze_prefix(efmp, fmt_ptr);
450de3b3677SBram Moolenaar if (efmp == NULL)
451de3b3677SBram Moolenaar return FAIL;
452071d4279SBram Moolenaar }
453071d4279SBram Moolenaar else
454071d4279SBram Moolenaar {
455f9e3e09fSBram Moolenaar semsg(_("E377: Invalid %%%c in format string"), *efmp);
456de3b3677SBram Moolenaar return FAIL;
457071d4279SBram Moolenaar }
458071d4279SBram Moolenaar }
45900bf8cd2SBram Moolenaar else // copy normal character
460071d4279SBram Moolenaar {
461071d4279SBram Moolenaar if (*efmp == '\\' && efmp + 1 < efm + len)
462071d4279SBram Moolenaar ++efmp;
463071d4279SBram Moolenaar else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL)
46400bf8cd2SBram Moolenaar *ptr++ = '\\'; // escape regexp atoms
465071d4279SBram Moolenaar if (*efmp)
466071d4279SBram Moolenaar *ptr++ = *efmp;
467071d4279SBram Moolenaar }
468071d4279SBram Moolenaar }
469071d4279SBram Moolenaar *ptr++ = '$';
470071d4279SBram Moolenaar *ptr = NUL;
471688e3d1fSBram Moolenaar
472de3b3677SBram Moolenaar return OK;
473688e3d1fSBram Moolenaar }
474688e3d1fSBram Moolenaar
475de3b3677SBram Moolenaar /*
476de3b3677SBram Moolenaar * Free the 'errorformat' information list
477de3b3677SBram Moolenaar */
478688e3d1fSBram Moolenaar static void
free_efm_list(efm_T ** efm_first)479688e3d1fSBram Moolenaar free_efm_list(efm_T **efm_first)
480688e3d1fSBram Moolenaar {
481688e3d1fSBram Moolenaar efm_T *efm_ptr;
482688e3d1fSBram Moolenaar
483688e3d1fSBram Moolenaar for (efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first)
484688e3d1fSBram Moolenaar {
485688e3d1fSBram Moolenaar *efm_first = efm_ptr->next;
486688e3d1fSBram Moolenaar vim_regfree(efm_ptr->prog);
487688e3d1fSBram Moolenaar vim_free(efm_ptr);
488688e3d1fSBram Moolenaar }
48963bed3d3SBram Moolenaar fmt_start = NULL;
490688e3d1fSBram Moolenaar }
491688e3d1fSBram Moolenaar
492de3b3677SBram Moolenaar /*
493de3b3677SBram Moolenaar * Compute the size of the buffer used to convert a 'errorformat' pattern into
494de3b3677SBram Moolenaar * a regular expression pattern.
495de3b3677SBram Moolenaar */
496de3b3677SBram Moolenaar static int
efm_regpat_bufsz(char_u * efm)497de3b3677SBram Moolenaar efm_regpat_bufsz(char_u *efm)
498de3b3677SBram Moolenaar {
499de3b3677SBram Moolenaar int sz;
500de3b3677SBram Moolenaar int i;
501de3b3677SBram Moolenaar
502de3b3677SBram Moolenaar sz = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2);
503de3b3677SBram Moolenaar for (i = FMT_PATTERNS; i > 0; )
504de3b3677SBram Moolenaar sz += (int)STRLEN(fmt_pat[--i].pattern);
505de3b3677SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
50600bf8cd2SBram Moolenaar sz += 12; // "%f" can become twelve chars longer (see efm_to_regpat)
507de3b3677SBram Moolenaar #else
50800bf8cd2SBram Moolenaar sz += 2; // "%f" can become two chars longer
509de3b3677SBram Moolenaar #endif
510de3b3677SBram Moolenaar
511de3b3677SBram Moolenaar return sz;
512de3b3677SBram Moolenaar }
513de3b3677SBram Moolenaar
514de3b3677SBram Moolenaar /*
515de3b3677SBram Moolenaar * Return the length of a 'errorformat' option part (separated by ",").
516de3b3677SBram Moolenaar */
517de3b3677SBram Moolenaar static int
efm_option_part_len(char_u * efm)518de3b3677SBram Moolenaar efm_option_part_len(char_u *efm)
519de3b3677SBram Moolenaar {
520de3b3677SBram Moolenaar int len;
521de3b3677SBram Moolenaar
522de3b3677SBram Moolenaar for (len = 0; efm[len] != NUL && efm[len] != ','; ++len)
523de3b3677SBram Moolenaar if (efm[len] == '\\' && efm[len + 1] != NUL)
524de3b3677SBram Moolenaar ++len;
525de3b3677SBram Moolenaar
526de3b3677SBram Moolenaar return len;
527de3b3677SBram Moolenaar }
528de3b3677SBram Moolenaar
529de3b3677SBram Moolenaar /*
530de3b3677SBram Moolenaar * Parse the 'errorformat' option. Multiple parts in the 'errorformat' option
531de3b3677SBram Moolenaar * are parsed and converted to regular expressions. Returns information about
532de3b3677SBram Moolenaar * the parsed 'errorformat' option.
533de3b3677SBram Moolenaar */
534688e3d1fSBram Moolenaar static efm_T *
parse_efm_option(char_u * efm)535688e3d1fSBram Moolenaar parse_efm_option(char_u *efm)
536688e3d1fSBram Moolenaar {
537688e3d1fSBram Moolenaar efm_T *fmt_ptr = NULL;
538688e3d1fSBram Moolenaar efm_T *fmt_first = NULL;
539688e3d1fSBram Moolenaar efm_T *fmt_last = NULL;
540688e3d1fSBram Moolenaar char_u *fmtstr = NULL;
541688e3d1fSBram Moolenaar int len;
542de3b3677SBram Moolenaar int sz;
543688e3d1fSBram Moolenaar
54400bf8cd2SBram Moolenaar // Each part of the format string is copied and modified from errorformat
54500bf8cd2SBram Moolenaar // to regex prog. Only a few % characters are allowed.
546e87e6dddSBram Moolenaar
54700bf8cd2SBram Moolenaar // Get some space to modify the format string into.
548de3b3677SBram Moolenaar sz = efm_regpat_bufsz(efm);
549de3b3677SBram Moolenaar if ((fmtstr = alloc(sz)) == NULL)
550688e3d1fSBram Moolenaar goto parse_efm_error;
551688e3d1fSBram Moolenaar
552688e3d1fSBram Moolenaar while (efm[0] != NUL)
553688e3d1fSBram Moolenaar {
55400bf8cd2SBram Moolenaar // Allocate a new eformat structure and put it at the end of the list
555c799fe20SBram Moolenaar fmt_ptr = ALLOC_CLEAR_ONE(efm_T);
556688e3d1fSBram Moolenaar if (fmt_ptr == NULL)
557688e3d1fSBram Moolenaar goto parse_efm_error;
55800bf8cd2SBram Moolenaar if (fmt_first == NULL) // first one
559688e3d1fSBram Moolenaar fmt_first = fmt_ptr;
560688e3d1fSBram Moolenaar else
561688e3d1fSBram Moolenaar fmt_last->next = fmt_ptr;
562688e3d1fSBram Moolenaar fmt_last = fmt_ptr;
563688e3d1fSBram Moolenaar
56400bf8cd2SBram Moolenaar // Isolate one part in the 'errorformat' option
565de3b3677SBram Moolenaar len = efm_option_part_len(efm);
566688e3d1fSBram Moolenaar
567f9e3e09fSBram Moolenaar if (efm_to_regpat(efm, len, fmt_ptr, fmtstr) == FAIL)
568688e3d1fSBram Moolenaar goto parse_efm_error;
569071d4279SBram Moolenaar if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL)
570688e3d1fSBram Moolenaar goto parse_efm_error;
57100bf8cd2SBram Moolenaar // Advance to next part
57200bf8cd2SBram Moolenaar efm = skip_to_option_part(efm + len); // skip comma and spaces
573071d4279SBram Moolenaar }
574688e3d1fSBram Moolenaar
57500bf8cd2SBram Moolenaar if (fmt_first == NULL) // nothing found
576f9e3e09fSBram Moolenaar emsg(_("E378: 'errorformat' contains no pattern"));
577688e3d1fSBram Moolenaar
578688e3d1fSBram Moolenaar goto parse_efm_end;
579688e3d1fSBram Moolenaar
580688e3d1fSBram Moolenaar parse_efm_error:
581688e3d1fSBram Moolenaar free_efm_list(&fmt_first);
582688e3d1fSBram Moolenaar
583688e3d1fSBram Moolenaar parse_efm_end:
584688e3d1fSBram Moolenaar vim_free(fmtstr);
585688e3d1fSBram Moolenaar
586688e3d1fSBram Moolenaar return fmt_first;
587071d4279SBram Moolenaar }
588071d4279SBram Moolenaar
589e0d37976SBram Moolenaar enum {
590e0d37976SBram Moolenaar QF_FAIL = 0,
591e0d37976SBram Moolenaar QF_OK = 1,
592e0d37976SBram Moolenaar QF_END_OF_INPUT = 2,
593e87e6dddSBram Moolenaar QF_NOMEM = 3,
59418cebf44SBram Moolenaar QF_IGNORE_LINE = 4,
59518cebf44SBram Moolenaar QF_MULTISCAN = 5,
596e0d37976SBram Moolenaar };
597e0d37976SBram Moolenaar
598de3b3677SBram Moolenaar /*
599de3b3677SBram Moolenaar * State information used to parse lines and add entries to a quickfix/location
600de3b3677SBram Moolenaar * list.
601de3b3677SBram Moolenaar */
602e0d37976SBram Moolenaar typedef struct {
603e0d37976SBram Moolenaar char_u *linebuf;
604e0d37976SBram Moolenaar int linelen;
605e0d37976SBram Moolenaar char_u *growbuf;
606e0d37976SBram Moolenaar int growbufsiz;
607e0d37976SBram Moolenaar FILE *fd;
608e0d37976SBram Moolenaar typval_T *tv;
609e0d37976SBram Moolenaar char_u *p_str;
610e0d37976SBram Moolenaar listitem_T *p_li;
611e0d37976SBram Moolenaar buf_T *buf;
612e0d37976SBram Moolenaar linenr_T buflnum;
613e0d37976SBram Moolenaar linenr_T lnumlast;
6142c7292dcSBram Moolenaar vimconv_T vc;
615e0d37976SBram Moolenaar } qfstate_T;
616e0d37976SBram Moolenaar
617de3b3677SBram Moolenaar /*
618de3b3677SBram Moolenaar * Allocate more memory for the line buffer used for parsing lines.
619de3b3677SBram Moolenaar */
620e0d37976SBram Moolenaar static char_u *
qf_grow_linebuf(qfstate_T * state,int newsz)621e0d37976SBram Moolenaar qf_grow_linebuf(qfstate_T *state, int newsz)
622e0d37976SBram Moolenaar {
62318cebf44SBram Moolenaar char_u *p;
62418cebf44SBram Moolenaar
62500bf8cd2SBram Moolenaar // If the line exceeds LINE_MAXLEN exclude the last
62600bf8cd2SBram Moolenaar // byte since it's not a NL character.
627e0d37976SBram Moolenaar state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz;
628e0d37976SBram Moolenaar if (state->growbuf == NULL)
629e0d37976SBram Moolenaar {
630e0d37976SBram Moolenaar state->growbuf = alloc(state->linelen + 1);
631e0d37976SBram Moolenaar if (state->growbuf == NULL)
632e0d37976SBram Moolenaar return NULL;
633e0d37976SBram Moolenaar state->growbufsiz = state->linelen;
634e0d37976SBram Moolenaar }
635e0d37976SBram Moolenaar else if (state->linelen > state->growbufsiz)
636e0d37976SBram Moolenaar {
63718cebf44SBram Moolenaar if ((p = vim_realloc(state->growbuf, state->linelen + 1)) == NULL)
638e0d37976SBram Moolenaar return NULL;
63918cebf44SBram Moolenaar state->growbuf = p;
640e0d37976SBram Moolenaar state->growbufsiz = state->linelen;
641e0d37976SBram Moolenaar }
642e0d37976SBram Moolenaar return state->growbuf;
643e0d37976SBram Moolenaar }
644e0d37976SBram Moolenaar
645e0d37976SBram Moolenaar /*
646e0d37976SBram Moolenaar * Get the next string (separated by newline) from state->p_str.
647e0d37976SBram Moolenaar */
648e0d37976SBram Moolenaar static int
qf_get_next_str_line(qfstate_T * state)649e0d37976SBram Moolenaar qf_get_next_str_line(qfstate_T *state)
650e0d37976SBram Moolenaar {
65100bf8cd2SBram Moolenaar // Get the next line from the supplied string
652e0d37976SBram Moolenaar char_u *p_str = state->p_str;
653e0d37976SBram Moolenaar char_u *p;
654e0d37976SBram Moolenaar int len;
655e0d37976SBram Moolenaar
65600bf8cd2SBram Moolenaar if (*p_str == NUL) // Reached the end of the string
657e0d37976SBram Moolenaar return QF_END_OF_INPUT;
658e0d37976SBram Moolenaar
659e0d37976SBram Moolenaar p = vim_strchr(p_str, '\n');
660e0d37976SBram Moolenaar if (p != NULL)
661e0d37976SBram Moolenaar len = (int)(p - p_str) + 1;
662e0d37976SBram Moolenaar else
663e0d37976SBram Moolenaar len = (int)STRLEN(p_str);
664e0d37976SBram Moolenaar
665e0d37976SBram Moolenaar if (len > IOSIZE - 2)
666e0d37976SBram Moolenaar {
667e0d37976SBram Moolenaar state->linebuf = qf_grow_linebuf(state, len);
668e0d37976SBram Moolenaar if (state->linebuf == NULL)
669e0d37976SBram Moolenaar return QF_NOMEM;
670e0d37976SBram Moolenaar }
671e0d37976SBram Moolenaar else
672e0d37976SBram Moolenaar {
673e0d37976SBram Moolenaar state->linebuf = IObuff;
674e0d37976SBram Moolenaar state->linelen = len;
675e0d37976SBram Moolenaar }
676e0d37976SBram Moolenaar vim_strncpy(state->linebuf, p_str, state->linelen);
677e0d37976SBram Moolenaar
67800bf8cd2SBram Moolenaar // Increment using len in order to discard the rest of the
67900bf8cd2SBram Moolenaar // line if it exceeds LINE_MAXLEN.
680e0d37976SBram Moolenaar p_str += len;
681e0d37976SBram Moolenaar state->p_str = p_str;
682e0d37976SBram Moolenaar
683e0d37976SBram Moolenaar return QF_OK;
684e0d37976SBram Moolenaar }
685e0d37976SBram Moolenaar
686e0d37976SBram Moolenaar /*
687e0d37976SBram Moolenaar * Get the next string from state->p_Li.
688e0d37976SBram Moolenaar */
689e0d37976SBram Moolenaar static int
qf_get_next_list_line(qfstate_T * state)690e0d37976SBram Moolenaar qf_get_next_list_line(qfstate_T *state)
691e0d37976SBram Moolenaar {
692e0d37976SBram Moolenaar listitem_T *p_li = state->p_li;
693e0d37976SBram Moolenaar int len;
694e0d37976SBram Moolenaar
695e0d37976SBram Moolenaar while (p_li != NULL
696e0d37976SBram Moolenaar && (p_li->li_tv.v_type != VAR_STRING
697e0d37976SBram Moolenaar || p_li->li_tv.vval.v_string == NULL))
69800bf8cd2SBram Moolenaar p_li = p_li->li_next; // Skip non-string items
699e0d37976SBram Moolenaar
70000bf8cd2SBram Moolenaar if (p_li == NULL) // End of the list
701e0d37976SBram Moolenaar {
702e0d37976SBram Moolenaar state->p_li = NULL;
703e0d37976SBram Moolenaar return QF_END_OF_INPUT;
704e0d37976SBram Moolenaar }
705e0d37976SBram Moolenaar
706e0d37976SBram Moolenaar len = (int)STRLEN(p_li->li_tv.vval.v_string);
707e0d37976SBram Moolenaar if (len > IOSIZE - 2)
708e0d37976SBram Moolenaar {
709e0d37976SBram Moolenaar state->linebuf = qf_grow_linebuf(state, len);
710e0d37976SBram Moolenaar if (state->linebuf == NULL)
711e0d37976SBram Moolenaar return QF_NOMEM;
712e0d37976SBram Moolenaar }
713e0d37976SBram Moolenaar else
714e0d37976SBram Moolenaar {
715e0d37976SBram Moolenaar state->linebuf = IObuff;
716e0d37976SBram Moolenaar state->linelen = len;
717e0d37976SBram Moolenaar }
718e0d37976SBram Moolenaar
719e0d37976SBram Moolenaar vim_strncpy(state->linebuf, p_li->li_tv.vval.v_string, state->linelen);
720e0d37976SBram Moolenaar
72100bf8cd2SBram Moolenaar state->p_li = p_li->li_next; // next item
722e0d37976SBram Moolenaar return QF_OK;
723e0d37976SBram Moolenaar }
724e0d37976SBram Moolenaar
725e0d37976SBram Moolenaar /*
726e0d37976SBram Moolenaar * Get the next string from state->buf.
727e0d37976SBram Moolenaar */
728e0d37976SBram Moolenaar static int
qf_get_next_buf_line(qfstate_T * state)729e0d37976SBram Moolenaar qf_get_next_buf_line(qfstate_T *state)
730e0d37976SBram Moolenaar {
731e0d37976SBram Moolenaar char_u *p_buf = NULL;
732e0d37976SBram Moolenaar int len;
733e0d37976SBram Moolenaar
73400bf8cd2SBram Moolenaar // Get the next line from the supplied buffer
735e0d37976SBram Moolenaar if (state->buflnum > state->lnumlast)
736e0d37976SBram Moolenaar return QF_END_OF_INPUT;
737e0d37976SBram Moolenaar
738e0d37976SBram Moolenaar p_buf = ml_get_buf(state->buf, state->buflnum, FALSE);
739e0d37976SBram Moolenaar state->buflnum += 1;
740e0d37976SBram Moolenaar
741e0d37976SBram Moolenaar len = (int)STRLEN(p_buf);
742e0d37976SBram Moolenaar if (len > IOSIZE - 2)
743e0d37976SBram Moolenaar {
744e0d37976SBram Moolenaar state->linebuf = qf_grow_linebuf(state, len);
745e0d37976SBram Moolenaar if (state->linebuf == NULL)
746e0d37976SBram Moolenaar return QF_NOMEM;
747e0d37976SBram Moolenaar }
748e0d37976SBram Moolenaar else
749e0d37976SBram Moolenaar {
750e0d37976SBram Moolenaar state->linebuf = IObuff;
751e0d37976SBram Moolenaar state->linelen = len;
752e0d37976SBram Moolenaar }
753e0d37976SBram Moolenaar vim_strncpy(state->linebuf, p_buf, state->linelen);
754e0d37976SBram Moolenaar
755e0d37976SBram Moolenaar return QF_OK;
756e0d37976SBram Moolenaar }
757e0d37976SBram Moolenaar
758e0d37976SBram Moolenaar /*
759e0d37976SBram Moolenaar * Get the next string from file state->fd.
760e0d37976SBram Moolenaar */
761e0d37976SBram Moolenaar static int
qf_get_next_file_line(qfstate_T * state)762e0d37976SBram Moolenaar qf_get_next_file_line(qfstate_T *state)
763e0d37976SBram Moolenaar {
764e0d37976SBram Moolenaar int discard;
765e0d37976SBram Moolenaar int growbuflen;
766e0d37976SBram Moolenaar
767e0d37976SBram Moolenaar if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL)
768e0d37976SBram Moolenaar return QF_END_OF_INPUT;
769e0d37976SBram Moolenaar
770e0d37976SBram Moolenaar discard = FALSE;
771e0d37976SBram Moolenaar state->linelen = (int)STRLEN(IObuff);
772796aa9c8SBram Moolenaar if (state->linelen == IOSIZE - 1 && !(IObuff[state->linelen - 1] == '\n'))
773e0d37976SBram Moolenaar {
77400bf8cd2SBram Moolenaar // The current line exceeds IObuff, continue reading using
77500bf8cd2SBram Moolenaar // growbuf until EOL or LINE_MAXLEN bytes is read.
776e0d37976SBram Moolenaar if (state->growbuf == NULL)
777e0d37976SBram Moolenaar {
778e0d37976SBram Moolenaar state->growbufsiz = 2 * (IOSIZE - 1);
779e0d37976SBram Moolenaar state->growbuf = alloc(state->growbufsiz);
780e0d37976SBram Moolenaar if (state->growbuf == NULL)
781e0d37976SBram Moolenaar return QF_NOMEM;
782e0d37976SBram Moolenaar }
783e0d37976SBram Moolenaar
78400bf8cd2SBram Moolenaar // Copy the read part of the line, excluding null-terminator
785e0d37976SBram Moolenaar memcpy(state->growbuf, IObuff, IOSIZE - 1);
786e0d37976SBram Moolenaar growbuflen = state->linelen;
787e0d37976SBram Moolenaar
788e0d37976SBram Moolenaar for (;;)
789e0d37976SBram Moolenaar {
79018cebf44SBram Moolenaar char_u *p;
79118cebf44SBram Moolenaar
792e0d37976SBram Moolenaar if (fgets((char *)state->growbuf + growbuflen,
793e0d37976SBram Moolenaar state->growbufsiz - growbuflen, state->fd) == NULL)
794e0d37976SBram Moolenaar break;
795e0d37976SBram Moolenaar state->linelen = (int)STRLEN(state->growbuf + growbuflen);
796e0d37976SBram Moolenaar growbuflen += state->linelen;
797796aa9c8SBram Moolenaar if ((state->growbuf)[growbuflen - 1] == '\n')
798e0d37976SBram Moolenaar break;
799e0d37976SBram Moolenaar if (state->growbufsiz == LINE_MAXLEN)
800e0d37976SBram Moolenaar {
801e0d37976SBram Moolenaar discard = TRUE;
802e0d37976SBram Moolenaar break;
803e0d37976SBram Moolenaar }
804e0d37976SBram Moolenaar
805e0d37976SBram Moolenaar state->growbufsiz = 2 * state->growbufsiz < LINE_MAXLEN
806e0d37976SBram Moolenaar ? 2 * state->growbufsiz : LINE_MAXLEN;
80718cebf44SBram Moolenaar if ((p = vim_realloc(state->growbuf, state->growbufsiz)) == NULL)
808e0d37976SBram Moolenaar return QF_NOMEM;
80918cebf44SBram Moolenaar state->growbuf = p;
810e0d37976SBram Moolenaar }
811e0d37976SBram Moolenaar
812e0d37976SBram Moolenaar while (discard)
813e0d37976SBram Moolenaar {
81400bf8cd2SBram Moolenaar // The current line is longer than LINE_MAXLEN, continue
81500bf8cd2SBram Moolenaar // reading but discard everything until EOL or EOF is
81600bf8cd2SBram Moolenaar // reached.
817e0d37976SBram Moolenaar if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL
818e0d37976SBram Moolenaar || (int)STRLEN(IObuff) < IOSIZE - 1
81959941cbdSBram Moolenaar || IObuff[IOSIZE - 2] == '\n')
820e0d37976SBram Moolenaar break;
821e0d37976SBram Moolenaar }
822e0d37976SBram Moolenaar
823e0d37976SBram Moolenaar state->linebuf = state->growbuf;
824e0d37976SBram Moolenaar state->linelen = growbuflen;
825e0d37976SBram Moolenaar }
826e0d37976SBram Moolenaar else
827e0d37976SBram Moolenaar state->linebuf = IObuff;
828e0d37976SBram Moolenaar
82900bf8cd2SBram Moolenaar // Convert a line if it contains a non-ASCII character.
830b6fa30ccSBram Moolenaar if (state->vc.vc_type != CONV_NONE && has_non_ascii(state->linebuf))
831b6fa30ccSBram Moolenaar {
8322c7292dcSBram Moolenaar char_u *line;
8332c7292dcSBram Moolenaar
8342c7292dcSBram Moolenaar line = string_convert(&state->vc, state->linebuf, &state->linelen);
8352c7292dcSBram Moolenaar if (line != NULL)
8362c7292dcSBram Moolenaar {
8372c7292dcSBram Moolenaar if (state->linelen < IOSIZE)
8382c7292dcSBram Moolenaar {
8392c7292dcSBram Moolenaar STRCPY(state->linebuf, line);
8402c7292dcSBram Moolenaar vim_free(line);
8412c7292dcSBram Moolenaar }
8422c7292dcSBram Moolenaar else
8432c7292dcSBram Moolenaar {
8442c7292dcSBram Moolenaar vim_free(state->growbuf);
8452c7292dcSBram Moolenaar state->linebuf = state->growbuf = line;
8462c7292dcSBram Moolenaar state->growbufsiz = state->linelen < LINE_MAXLEN
8472c7292dcSBram Moolenaar ? state->linelen : LINE_MAXLEN;
8482c7292dcSBram Moolenaar }
8492c7292dcSBram Moolenaar }
8502c7292dcSBram Moolenaar }
8512c7292dcSBram Moolenaar
852e0d37976SBram Moolenaar return QF_OK;
853e0d37976SBram Moolenaar }
854e0d37976SBram Moolenaar
855e0d37976SBram Moolenaar /*
856e0d37976SBram Moolenaar * Get the next string from a file/buffer/list/string.
857e0d37976SBram Moolenaar */
858e0d37976SBram Moolenaar static int
qf_get_nextline(qfstate_T * state)859e0d37976SBram Moolenaar qf_get_nextline(qfstate_T *state)
860e0d37976SBram Moolenaar {
861e0d37976SBram Moolenaar int status = QF_FAIL;
862e0d37976SBram Moolenaar
863e0d37976SBram Moolenaar if (state->fd == NULL)
864e0d37976SBram Moolenaar {
865e0d37976SBram Moolenaar if (state->tv != NULL)
866e0d37976SBram Moolenaar {
867e0d37976SBram Moolenaar if (state->tv->v_type == VAR_STRING)
86800bf8cd2SBram Moolenaar // Get the next line from the supplied string
869e0d37976SBram Moolenaar status = qf_get_next_str_line(state);
870e0d37976SBram Moolenaar else if (state->tv->v_type == VAR_LIST)
87100bf8cd2SBram Moolenaar // Get the next line from the supplied list
872e0d37976SBram Moolenaar status = qf_get_next_list_line(state);
873e0d37976SBram Moolenaar }
874e0d37976SBram Moolenaar else
87500bf8cd2SBram Moolenaar // Get the next line from the supplied buffer
876e0d37976SBram Moolenaar status = qf_get_next_buf_line(state);
877e0d37976SBram Moolenaar }
878e0d37976SBram Moolenaar else
87900bf8cd2SBram Moolenaar // Get the next line from the supplied file
880e0d37976SBram Moolenaar status = qf_get_next_file_line(state);
881e0d37976SBram Moolenaar
882e0d37976SBram Moolenaar if (status != QF_OK)
883e0d37976SBram Moolenaar return status;
884e0d37976SBram Moolenaar
88500bf8cd2SBram Moolenaar // remove newline/CR from the line
886e0d37976SBram Moolenaar if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n')
887796aa9c8SBram Moolenaar {
888e0d37976SBram Moolenaar state->linebuf[state->linelen - 1] = NUL;
889e0d37976SBram Moolenaar #ifdef USE_CRNL
890796aa9c8SBram Moolenaar if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r')
891796aa9c8SBram Moolenaar state->linebuf[state->linelen - 2] = NUL;
892e0d37976SBram Moolenaar #endif
893796aa9c8SBram Moolenaar }
894e0d37976SBram Moolenaar
895e0d37976SBram Moolenaar remove_bom(state->linebuf);
896e0d37976SBram Moolenaar
897e0d37976SBram Moolenaar return QF_OK;
898e0d37976SBram Moolenaar }
899e0d37976SBram Moolenaar
900e87e6dddSBram Moolenaar typedef struct {
901e87e6dddSBram Moolenaar char_u *namebuf;
902d76ce852SBram Moolenaar char_u *module;
903e87e6dddSBram Moolenaar char_u *errmsg;
904e87e6dddSBram Moolenaar int errmsglen;
905e87e6dddSBram Moolenaar long lnum;
9066864efa5Sthinca long end_lnum;
907e87e6dddSBram Moolenaar int col;
9086864efa5Sthinca int end_col;
909e87e6dddSBram Moolenaar char_u use_viscol;
910e87e6dddSBram Moolenaar char_u *pattern;
911e87e6dddSBram Moolenaar int enr;
912e87e6dddSBram Moolenaar int type;
913e87e6dddSBram Moolenaar int valid;
914e87e6dddSBram Moolenaar } qffields_T;
915e87e6dddSBram Moolenaar
916e87e6dddSBram Moolenaar /*
917de3b3677SBram Moolenaar * Parse the match for filename ('%f') pattern in regmatch.
918de3b3677SBram Moolenaar * Return the matched value in "fields->namebuf".
919de3b3677SBram Moolenaar */
920de3b3677SBram Moolenaar static int
qf_parse_fmt_f(regmatch_T * rmp,int midx,qffields_T * fields,int prefix)921de3b3677SBram Moolenaar qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int prefix)
922de3b3677SBram Moolenaar {
923de3b3677SBram Moolenaar int c;
924de3b3677SBram Moolenaar
925de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
926de3b3677SBram Moolenaar return QF_FAIL;
927de3b3677SBram Moolenaar
92800bf8cd2SBram Moolenaar // Expand ~/file and $HOME/file to full path.
929de3b3677SBram Moolenaar c = *rmp->endp[midx];
930de3b3677SBram Moolenaar *rmp->endp[midx] = NUL;
931de3b3677SBram Moolenaar expand_env(rmp->startp[midx], fields->namebuf, CMDBUFFSIZE);
932de3b3677SBram Moolenaar *rmp->endp[midx] = c;
933de3b3677SBram Moolenaar
93400bf8cd2SBram Moolenaar // For separate filename patterns (%O, %P and %Q), the specified file
93500bf8cd2SBram Moolenaar // should exist.
936de3b3677SBram Moolenaar if (vim_strchr((char_u *)"OPQ", prefix) != NULL
937de3b3677SBram Moolenaar && mch_getperm(fields->namebuf) == -1)
938de3b3677SBram Moolenaar return QF_FAIL;
939de3b3677SBram Moolenaar
940de3b3677SBram Moolenaar return QF_OK;
941de3b3677SBram Moolenaar }
942de3b3677SBram Moolenaar
943de3b3677SBram Moolenaar /*
944de3b3677SBram Moolenaar * Parse the match for error number ('%n') pattern in regmatch.
945de3b3677SBram Moolenaar * Return the matched value in "fields->enr".
946de3b3677SBram Moolenaar */
947de3b3677SBram Moolenaar static int
qf_parse_fmt_n(regmatch_T * rmp,int midx,qffields_T * fields)948de3b3677SBram Moolenaar qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
949de3b3677SBram Moolenaar {
950de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
951de3b3677SBram Moolenaar return QF_FAIL;
952de3b3677SBram Moolenaar fields->enr = (int)atol((char *)rmp->startp[midx]);
953de3b3677SBram Moolenaar return QF_OK;
954de3b3677SBram Moolenaar }
955de3b3677SBram Moolenaar
956de3b3677SBram Moolenaar /*
957de3b3677SBram Moolenaar * Parse the match for line number (%l') pattern in regmatch.
958de3b3677SBram Moolenaar * Return the matched value in "fields->lnum".
959de3b3677SBram Moolenaar */
960de3b3677SBram Moolenaar static int
qf_parse_fmt_l(regmatch_T * rmp,int midx,qffields_T * fields)961de3b3677SBram Moolenaar qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
962de3b3677SBram Moolenaar {
963de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
964de3b3677SBram Moolenaar return QF_FAIL;
965de3b3677SBram Moolenaar fields->lnum = atol((char *)rmp->startp[midx]);
966de3b3677SBram Moolenaar return QF_OK;
967de3b3677SBram Moolenaar }
968de3b3677SBram Moolenaar
969de3b3677SBram Moolenaar /*
970de3b3677SBram Moolenaar * Parse the match for column number ('%c') pattern in regmatch.
971de3b3677SBram Moolenaar * Return the matched value in "fields->col".
972de3b3677SBram Moolenaar */
973de3b3677SBram Moolenaar static int
qf_parse_fmt_c(regmatch_T * rmp,int midx,qffields_T * fields)974de3b3677SBram Moolenaar qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
975de3b3677SBram Moolenaar {
976de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
977de3b3677SBram Moolenaar return QF_FAIL;
978de3b3677SBram Moolenaar fields->col = (int)atol((char *)rmp->startp[midx]);
979de3b3677SBram Moolenaar return QF_OK;
980de3b3677SBram Moolenaar }
981de3b3677SBram Moolenaar
982de3b3677SBram Moolenaar /*
983de3b3677SBram Moolenaar * Parse the match for error type ('%t') pattern in regmatch.
984de3b3677SBram Moolenaar * Return the matched value in "fields->type".
985de3b3677SBram Moolenaar */
986de3b3677SBram Moolenaar static int
qf_parse_fmt_t(regmatch_T * rmp,int midx,qffields_T * fields)987de3b3677SBram Moolenaar qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
988de3b3677SBram Moolenaar {
989de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
990de3b3677SBram Moolenaar return QF_FAIL;
991de3b3677SBram Moolenaar fields->type = *rmp->startp[midx];
992de3b3677SBram Moolenaar return QF_OK;
993de3b3677SBram Moolenaar }
994de3b3677SBram Moolenaar
995de3b3677SBram Moolenaar /*
996f4140488SBram Moolenaar * Copy a non-error line into the error string. Return the matched line in
997f4140488SBram Moolenaar * "fields->errmsg".
998de3b3677SBram Moolenaar */
999de3b3677SBram Moolenaar static int
copy_nonerror_line(char_u * linebuf,int linelen,qffields_T * fields)1000f4140488SBram Moolenaar copy_nonerror_line(char_u *linebuf, int linelen, qffields_T *fields)
1001de3b3677SBram Moolenaar {
1002de3b3677SBram Moolenaar char_u *p;
1003de3b3677SBram Moolenaar
1004de3b3677SBram Moolenaar if (linelen >= fields->errmsglen)
1005de3b3677SBram Moolenaar {
100600bf8cd2SBram Moolenaar // linelen + null terminator
1007de3b3677SBram Moolenaar if ((p = vim_realloc(fields->errmsg, linelen + 1)) == NULL)
1008de3b3677SBram Moolenaar return QF_NOMEM;
1009de3b3677SBram Moolenaar fields->errmsg = p;
1010de3b3677SBram Moolenaar fields->errmsglen = linelen + 1;
1011de3b3677SBram Moolenaar }
1012f4140488SBram Moolenaar // copy whole line to error message
1013de3b3677SBram Moolenaar vim_strncpy(fields->errmsg, linebuf, linelen);
1014f4140488SBram Moolenaar
1015de3b3677SBram Moolenaar return QF_OK;
1016de3b3677SBram Moolenaar }
1017de3b3677SBram Moolenaar
1018de3b3677SBram Moolenaar /*
1019de3b3677SBram Moolenaar * Parse the match for error message ('%m') pattern in regmatch.
1020de3b3677SBram Moolenaar * Return the matched value in "fields->errmsg".
1021de3b3677SBram Moolenaar */
1022de3b3677SBram Moolenaar static int
qf_parse_fmt_m(regmatch_T * rmp,int midx,qffields_T * fields)1023de3b3677SBram Moolenaar qf_parse_fmt_m(regmatch_T *rmp, int midx, qffields_T *fields)
1024de3b3677SBram Moolenaar {
1025de3b3677SBram Moolenaar char_u *p;
1026de3b3677SBram Moolenaar int len;
1027de3b3677SBram Moolenaar
1028de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1029de3b3677SBram Moolenaar return QF_FAIL;
1030de3b3677SBram Moolenaar len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1031de3b3677SBram Moolenaar if (len >= fields->errmsglen)
1032de3b3677SBram Moolenaar {
103300bf8cd2SBram Moolenaar // len + null terminator
1034de3b3677SBram Moolenaar if ((p = vim_realloc(fields->errmsg, len + 1)) == NULL)
1035de3b3677SBram Moolenaar return QF_NOMEM;
1036de3b3677SBram Moolenaar fields->errmsg = p;
1037de3b3677SBram Moolenaar fields->errmsglen = len + 1;
1038de3b3677SBram Moolenaar }
1039de3b3677SBram Moolenaar vim_strncpy(fields->errmsg, rmp->startp[midx], len);
1040de3b3677SBram Moolenaar return QF_OK;
1041de3b3677SBram Moolenaar }
1042de3b3677SBram Moolenaar
1043de3b3677SBram Moolenaar /*
1044de3b3677SBram Moolenaar * Parse the match for rest of a single-line file message ('%r') pattern.
1045de3b3677SBram Moolenaar * Return the matched value in "tail".
1046de3b3677SBram Moolenaar */
1047de3b3677SBram Moolenaar static int
qf_parse_fmt_r(regmatch_T * rmp,int midx,char_u ** tail)1048de3b3677SBram Moolenaar qf_parse_fmt_r(regmatch_T *rmp, int midx, char_u **tail)
1049de3b3677SBram Moolenaar {
1050de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
1051de3b3677SBram Moolenaar return QF_FAIL;
1052de3b3677SBram Moolenaar *tail = rmp->startp[midx];
1053de3b3677SBram Moolenaar return QF_OK;
1054de3b3677SBram Moolenaar }
1055de3b3677SBram Moolenaar
1056de3b3677SBram Moolenaar /*
1057de3b3677SBram Moolenaar * Parse the match for the pointer line ('%p') pattern in regmatch.
1058de3b3677SBram Moolenaar * Return the matched value in "fields->col".
1059de3b3677SBram Moolenaar */
1060de3b3677SBram Moolenaar static int
qf_parse_fmt_p(regmatch_T * rmp,int midx,qffields_T * fields)1061de3b3677SBram Moolenaar qf_parse_fmt_p(regmatch_T *rmp, int midx, qffields_T *fields)
1062de3b3677SBram Moolenaar {
1063de3b3677SBram Moolenaar char_u *match_ptr;
1064de3b3677SBram Moolenaar
1065de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1066de3b3677SBram Moolenaar return QF_FAIL;
1067de3b3677SBram Moolenaar fields->col = 0;
1068de3b3677SBram Moolenaar for (match_ptr = rmp->startp[midx]; match_ptr != rmp->endp[midx];
1069de3b3677SBram Moolenaar ++match_ptr)
1070de3b3677SBram Moolenaar {
1071de3b3677SBram Moolenaar ++fields->col;
1072de3b3677SBram Moolenaar if (*match_ptr == TAB)
1073de3b3677SBram Moolenaar {
1074de3b3677SBram Moolenaar fields->col += 7;
1075de3b3677SBram Moolenaar fields->col -= fields->col % 8;
1076de3b3677SBram Moolenaar }
1077de3b3677SBram Moolenaar }
1078de3b3677SBram Moolenaar ++fields->col;
1079de3b3677SBram Moolenaar fields->use_viscol = TRUE;
1080de3b3677SBram Moolenaar return QF_OK;
1081de3b3677SBram Moolenaar }
1082de3b3677SBram Moolenaar
1083de3b3677SBram Moolenaar /*
1084de3b3677SBram Moolenaar * Parse the match for the virtual column number ('%v') pattern in regmatch.
1085de3b3677SBram Moolenaar * Return the matched value in "fields->col".
1086de3b3677SBram Moolenaar */
1087de3b3677SBram Moolenaar static int
qf_parse_fmt_v(regmatch_T * rmp,int midx,qffields_T * fields)1088de3b3677SBram Moolenaar qf_parse_fmt_v(regmatch_T *rmp, int midx, qffields_T *fields)
1089de3b3677SBram Moolenaar {
1090de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL)
1091de3b3677SBram Moolenaar return QF_FAIL;
1092de3b3677SBram Moolenaar fields->col = (int)atol((char *)rmp->startp[midx]);
1093de3b3677SBram Moolenaar fields->use_viscol = TRUE;
1094de3b3677SBram Moolenaar return QF_OK;
1095de3b3677SBram Moolenaar }
1096de3b3677SBram Moolenaar
1097de3b3677SBram Moolenaar /*
1098de3b3677SBram Moolenaar * Parse the match for the search text ('%s') pattern in regmatch.
1099de3b3677SBram Moolenaar * Return the matched value in "fields->pattern".
1100de3b3677SBram Moolenaar */
1101de3b3677SBram Moolenaar static int
qf_parse_fmt_s(regmatch_T * rmp,int midx,qffields_T * fields)1102de3b3677SBram Moolenaar qf_parse_fmt_s(regmatch_T *rmp, int midx, qffields_T *fields)
1103de3b3677SBram Moolenaar {
1104de3b3677SBram Moolenaar int len;
1105de3b3677SBram Moolenaar
1106de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1107de3b3677SBram Moolenaar return QF_FAIL;
1108de3b3677SBram Moolenaar len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1109de3b3677SBram Moolenaar if (len > CMDBUFFSIZE - 5)
1110de3b3677SBram Moolenaar len = CMDBUFFSIZE - 5;
1111de3b3677SBram Moolenaar STRCPY(fields->pattern, "^\\V");
1112de3b3677SBram Moolenaar STRNCAT(fields->pattern, rmp->startp[midx], len);
1113de3b3677SBram Moolenaar fields->pattern[len + 3] = '\\';
1114de3b3677SBram Moolenaar fields->pattern[len + 4] = '$';
1115de3b3677SBram Moolenaar fields->pattern[len + 5] = NUL;
1116de3b3677SBram Moolenaar return QF_OK;
1117de3b3677SBram Moolenaar }
1118de3b3677SBram Moolenaar
1119de3b3677SBram Moolenaar /*
1120de3b3677SBram Moolenaar * Parse the match for the module ('%o') pattern in regmatch.
1121de3b3677SBram Moolenaar * Return the matched value in "fields->module".
1122de3b3677SBram Moolenaar */
1123de3b3677SBram Moolenaar static int
qf_parse_fmt_o(regmatch_T * rmp,int midx,qffields_T * fields)1124de3b3677SBram Moolenaar qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
1125de3b3677SBram Moolenaar {
1126de3b3677SBram Moolenaar int len;
1127de3b3677SBram Moolenaar
1128de3b3677SBram Moolenaar if (rmp->startp[midx] == NULL || rmp->endp[midx] == NULL)
1129de3b3677SBram Moolenaar return QF_FAIL;
1130de3b3677SBram Moolenaar len = (int)(rmp->endp[midx] - rmp->startp[midx]);
1131de3b3677SBram Moolenaar if (len > CMDBUFFSIZE)
1132de3b3677SBram Moolenaar len = CMDBUFFSIZE;
1133de3b3677SBram Moolenaar STRNCAT(fields->module, rmp->startp[midx], len);
1134de3b3677SBram Moolenaar return QF_OK;
1135de3b3677SBram Moolenaar }
1136de3b3677SBram Moolenaar
1137de3b3677SBram Moolenaar /*
1138de3b3677SBram Moolenaar * 'errorformat' format pattern parser functions.
1139de3b3677SBram Moolenaar * The '%f' and '%r' formats are parsed differently from other formats.
1140de3b3677SBram Moolenaar * See qf_parse_match() for details.
1141de3b3677SBram Moolenaar */
1142de3b3677SBram Moolenaar static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) =
1143de3b3677SBram Moolenaar {
1144de3b3677SBram Moolenaar NULL,
1145de3b3677SBram Moolenaar qf_parse_fmt_n,
1146de3b3677SBram Moolenaar qf_parse_fmt_l,
1147de3b3677SBram Moolenaar qf_parse_fmt_c,
1148de3b3677SBram Moolenaar qf_parse_fmt_t,
1149de3b3677SBram Moolenaar qf_parse_fmt_m,
1150de3b3677SBram Moolenaar NULL,
1151de3b3677SBram Moolenaar qf_parse_fmt_p,
1152de3b3677SBram Moolenaar qf_parse_fmt_v,
1153de3b3677SBram Moolenaar qf_parse_fmt_s,
1154de3b3677SBram Moolenaar qf_parse_fmt_o
1155de3b3677SBram Moolenaar };
1156de3b3677SBram Moolenaar
1157de3b3677SBram Moolenaar /*
1158de3b3677SBram Moolenaar * Parse the error format pattern matches in "regmatch" and set the values in
1159de3b3677SBram Moolenaar * "fields". fmt_ptr contains the 'efm' format specifiers/prefixes that have a
1160de3b3677SBram Moolenaar * match. Returns QF_OK if all the matches are successfully parsed. On
1161de3b3677SBram Moolenaar * failure, returns QF_FAIL or QF_NOMEM.
1162e87e6dddSBram Moolenaar */
1163e87e6dddSBram Moolenaar static int
qf_parse_match(char_u * linebuf,int linelen,efm_T * fmt_ptr,regmatch_T * regmatch,qffields_T * fields,int qf_multiline,int qf_multiscan,char_u ** tail)116418cebf44SBram Moolenaar qf_parse_match(
1165e87e6dddSBram Moolenaar char_u *linebuf,
1166e87e6dddSBram Moolenaar int linelen,
116718cebf44SBram Moolenaar efm_T *fmt_ptr,
116818cebf44SBram Moolenaar regmatch_T *regmatch,
116918cebf44SBram Moolenaar qffields_T *fields,
117018cebf44SBram Moolenaar int qf_multiline,
117118cebf44SBram Moolenaar int qf_multiscan,
117218cebf44SBram Moolenaar char_u **tail)
1173e87e6dddSBram Moolenaar {
117418cebf44SBram Moolenaar int idx = fmt_ptr->prefix;
1175e87e6dddSBram Moolenaar int i;
1176de3b3677SBram Moolenaar int midx;
1177de3b3677SBram Moolenaar int status;
1178e87e6dddSBram Moolenaar
117918cebf44SBram Moolenaar if ((idx == 'C' || idx == 'Z') && !qf_multiline)
118018cebf44SBram Moolenaar return QF_FAIL;
1181e928366dSBram Moolenaar if (vim_strchr((char_u *)"EWIN", idx) != NULL)
1182e87e6dddSBram Moolenaar fields->type = idx;
1183e87e6dddSBram Moolenaar else
1184e87e6dddSBram Moolenaar fields->type = 0;
118500bf8cd2SBram Moolenaar
118600bf8cd2SBram Moolenaar // Extract error message data from matched line.
118700bf8cd2SBram Moolenaar // We check for an actual submatch, because "\[" and "\]" in
118800bf8cd2SBram Moolenaar // the 'errorformat' may cause the wrong submatch to be used.
1189de3b3677SBram Moolenaar for (i = 0; i < FMT_PATTERNS; i++)
1190e87e6dddSBram Moolenaar {
1191de3b3677SBram Moolenaar status = QF_OK;
1192de3b3677SBram Moolenaar midx = (int)fmt_ptr->addr[i];
119300bf8cd2SBram Moolenaar if (i == 0 && midx > 0) // %f
1194de3b3677SBram Moolenaar status = qf_parse_fmt_f(regmatch, midx, fields, idx);
1195de3b3677SBram Moolenaar else if (i == 5)
1196e87e6dddSBram Moolenaar {
119700bf8cd2SBram Moolenaar if (fmt_ptr->flags == '+' && !qf_multiscan) // %+
1198f4140488SBram Moolenaar status = copy_nonerror_line(linebuf, linelen, fields);
119900bf8cd2SBram Moolenaar else if (midx > 0) // %m
1200de3b3677SBram Moolenaar status = qf_parse_fmt_m(regmatch, midx, fields);
1201e87e6dddSBram Moolenaar }
120200bf8cd2SBram Moolenaar else if (i == 6 && midx > 0) // %r
1203de3b3677SBram Moolenaar status = qf_parse_fmt_r(regmatch, midx, tail);
120400bf8cd2SBram Moolenaar else if (midx > 0) // others
1205de3b3677SBram Moolenaar status = (qf_parse_fmt[i])(regmatch, midx, fields);
1206e87e6dddSBram Moolenaar
1207de3b3677SBram Moolenaar if (status != QF_OK)
1208de3b3677SBram Moolenaar return status;
1209d76ce852SBram Moolenaar }
1210e87e6dddSBram Moolenaar
121118cebf44SBram Moolenaar return QF_OK;
121218cebf44SBram Moolenaar }
121318cebf44SBram Moolenaar
121418cebf44SBram Moolenaar /*
121518cebf44SBram Moolenaar * Parse an error line in 'linebuf' using a single error format string in
121618cebf44SBram Moolenaar * 'fmt_ptr->prog' and return the matching values in 'fields'.
121718cebf44SBram Moolenaar * Returns QF_OK if the efm format matches completely and the fields are
121818cebf44SBram Moolenaar * successfully copied. Otherwise returns QF_FAIL or QF_NOMEM.
121918cebf44SBram Moolenaar */
122018cebf44SBram Moolenaar static int
qf_parse_get_fields(char_u * linebuf,int linelen,efm_T * fmt_ptr,qffields_T * fields,int qf_multiline,int qf_multiscan,char_u ** tail)122118cebf44SBram Moolenaar qf_parse_get_fields(
122218cebf44SBram Moolenaar char_u *linebuf,
122318cebf44SBram Moolenaar int linelen,
122418cebf44SBram Moolenaar efm_T *fmt_ptr,
122518cebf44SBram Moolenaar qffields_T *fields,
122618cebf44SBram Moolenaar int qf_multiline,
122718cebf44SBram Moolenaar int qf_multiscan,
122818cebf44SBram Moolenaar char_u **tail)
1229e87e6dddSBram Moolenaar {
123018cebf44SBram Moolenaar regmatch_T regmatch;
123118cebf44SBram Moolenaar int status = QF_FAIL;
123218cebf44SBram Moolenaar int r;
123318cebf44SBram Moolenaar
123418cebf44SBram Moolenaar if (qf_multiscan &&
123518cebf44SBram Moolenaar vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)
123618cebf44SBram Moolenaar return QF_FAIL;
123718cebf44SBram Moolenaar
123818cebf44SBram Moolenaar fields->namebuf[0] = NUL;
123918cebf44SBram Moolenaar fields->module[0] = NUL;
124018cebf44SBram Moolenaar fields->pattern[0] = NUL;
124118cebf44SBram Moolenaar if (!qf_multiscan)
124218cebf44SBram Moolenaar fields->errmsg[0] = NUL;
124318cebf44SBram Moolenaar fields->lnum = 0;
12446864efa5Sthinca fields->end_lnum = 0;
124518cebf44SBram Moolenaar fields->col = 0;
12466864efa5Sthinca fields->end_col = 0;
124718cebf44SBram Moolenaar fields->use_viscol = FALSE;
124818cebf44SBram Moolenaar fields->enr = -1;
124918cebf44SBram Moolenaar fields->type = 0;
125018cebf44SBram Moolenaar *tail = NULL;
125118cebf44SBram Moolenaar
125200bf8cd2SBram Moolenaar // Always ignore case when looking for a matching error.
12538b62e310SBram Moolenaar regmatch.rm_ic = TRUE;
125418cebf44SBram Moolenaar regmatch.regprog = fmt_ptr->prog;
125518cebf44SBram Moolenaar r = vim_regexec(®match, linebuf, (colnr_T)0);
125618cebf44SBram Moolenaar fmt_ptr->prog = regmatch.regprog;
125718cebf44SBram Moolenaar if (r)
125818cebf44SBram Moolenaar status = qf_parse_match(linebuf, linelen, fmt_ptr, ®match,
125918cebf44SBram Moolenaar fields, qf_multiline, qf_multiscan, tail);
126018cebf44SBram Moolenaar
126118cebf44SBram Moolenaar return status;
126218cebf44SBram Moolenaar }
126318cebf44SBram Moolenaar
126418cebf44SBram Moolenaar /*
126518cebf44SBram Moolenaar * Parse directory error format prefixes (%D and %X).
126618cebf44SBram Moolenaar * Push and pop directories from the directory stack when scanning directory
126718cebf44SBram Moolenaar * names.
126818cebf44SBram Moolenaar */
126918cebf44SBram Moolenaar static int
qf_parse_dir_pfx(int idx,qffields_T * fields,qf_list_T * qfl)127018cebf44SBram Moolenaar qf_parse_dir_pfx(int idx, qffields_T *fields, qf_list_T *qfl)
1271e87e6dddSBram Moolenaar {
127200bf8cd2SBram Moolenaar if (idx == 'D') // enter directory
1273e87e6dddSBram Moolenaar {
1274e87e6dddSBram Moolenaar if (*fields->namebuf == NUL)
1275e87e6dddSBram Moolenaar {
1276f9e3e09fSBram Moolenaar emsg(_("E379: Missing or empty directory name"));
1277e87e6dddSBram Moolenaar return QF_FAIL;
1278e87e6dddSBram Moolenaar }
1279a7df8c70SBram Moolenaar qfl->qf_directory =
1280a7df8c70SBram Moolenaar qf_push_dir(fields->namebuf, &qfl->qf_dir_stack, FALSE);
1281a7df8c70SBram Moolenaar if (qfl->qf_directory == NULL)
1282e87e6dddSBram Moolenaar return QF_FAIL;
1283e87e6dddSBram Moolenaar }
128400bf8cd2SBram Moolenaar else if (idx == 'X') // leave directory
1285a7df8c70SBram Moolenaar qfl->qf_directory = qf_pop_dir(&qfl->qf_dir_stack);
128618cebf44SBram Moolenaar
128718cebf44SBram Moolenaar return QF_OK;
1288e87e6dddSBram Moolenaar }
128918cebf44SBram Moolenaar
129018cebf44SBram Moolenaar /*
129118cebf44SBram Moolenaar * Parse global file name error format prefixes (%O, %P and %Q).
129218cebf44SBram Moolenaar */
129318cebf44SBram Moolenaar static int
qf_parse_file_pfx(int idx,qffields_T * fields,qf_list_T * qfl,char_u * tail)129418cebf44SBram Moolenaar qf_parse_file_pfx(
129518cebf44SBram Moolenaar int idx,
129618cebf44SBram Moolenaar qffields_T *fields,
129718cebf44SBram Moolenaar qf_list_T *qfl,
129818cebf44SBram Moolenaar char_u *tail)
129918cebf44SBram Moolenaar {
130018cebf44SBram Moolenaar fields->valid = FALSE;
130118cebf44SBram Moolenaar if (*fields->namebuf == NUL || mch_getperm(fields->namebuf) >= 0)
130218cebf44SBram Moolenaar {
130318cebf44SBram Moolenaar if (*fields->namebuf && idx == 'P')
130418cebf44SBram Moolenaar qfl->qf_currfile =
130518cebf44SBram Moolenaar qf_push_dir(fields->namebuf, &qfl->qf_file_stack, TRUE);
130618cebf44SBram Moolenaar else if (idx == 'Q')
130718cebf44SBram Moolenaar qfl->qf_currfile = qf_pop_dir(&qfl->qf_file_stack);
130818cebf44SBram Moolenaar *fields->namebuf = NUL;
130918cebf44SBram Moolenaar if (tail && *tail)
131018cebf44SBram Moolenaar {
131118cebf44SBram Moolenaar STRMOVE(IObuff, skipwhite(tail));
131218cebf44SBram Moolenaar qfl->qf_multiscan = TRUE;
131318cebf44SBram Moolenaar return QF_MULTISCAN;
131418cebf44SBram Moolenaar }
131518cebf44SBram Moolenaar }
131618cebf44SBram Moolenaar
131718cebf44SBram Moolenaar return QF_OK;
131818cebf44SBram Moolenaar }
131918cebf44SBram Moolenaar
132018cebf44SBram Moolenaar /*
132118cebf44SBram Moolenaar * Parse a non-error line (a line which doesn't match any of the error
132218cebf44SBram Moolenaar * format in 'efm').
132318cebf44SBram Moolenaar */
132418cebf44SBram Moolenaar static int
qf_parse_line_nomatch(char_u * linebuf,int linelen,qffields_T * fields)132518cebf44SBram Moolenaar qf_parse_line_nomatch(char_u *linebuf, int linelen, qffields_T *fields)
132618cebf44SBram Moolenaar {
132700bf8cd2SBram Moolenaar fields->namebuf[0] = NUL; // no match found, remove file name
132800bf8cd2SBram Moolenaar fields->lnum = 0; // don't jump to this line
1329e87e6dddSBram Moolenaar fields->valid = FALSE;
1330e87e6dddSBram Moolenaar
1331f4140488SBram Moolenaar return copy_nonerror_line(linebuf, linelen, fields);
1332e87e6dddSBram Moolenaar }
133318cebf44SBram Moolenaar
133418cebf44SBram Moolenaar /*
133518cebf44SBram Moolenaar * Parse multi-line error format prefixes (%C and %Z)
133618cebf44SBram Moolenaar */
133718cebf44SBram Moolenaar static int
qf_parse_multiline_pfx(int idx,qf_list_T * qfl,qffields_T * fields)133818cebf44SBram Moolenaar qf_parse_multiline_pfx(
133918cebf44SBram Moolenaar int idx,
134018cebf44SBram Moolenaar qf_list_T *qfl,
134118cebf44SBram Moolenaar qffields_T *fields)
134218cebf44SBram Moolenaar {
134318cebf44SBram Moolenaar char_u *ptr;
134418cebf44SBram Moolenaar int len;
134518cebf44SBram Moolenaar
1346a7df8c70SBram Moolenaar if (!qfl->qf_multiignore)
13479b457948SBram Moolenaar {
1348a7df8c70SBram Moolenaar qfline_T *qfprev = qfl->qf_last;
1349e87e6dddSBram Moolenaar
1350e87e6dddSBram Moolenaar if (qfprev == NULL)
1351e87e6dddSBram Moolenaar return QF_FAIL;
1352a7df8c70SBram Moolenaar if (*fields->errmsg && !qfl->qf_multiignore)
1353e87e6dddSBram Moolenaar {
1354e87e6dddSBram Moolenaar len = (int)STRLEN(qfprev->qf_text);
1355964b3746SBram Moolenaar if ((ptr = alloc(len + STRLEN(fields->errmsg) + 2))
1356e87e6dddSBram Moolenaar == NULL)
1357e87e6dddSBram Moolenaar return QF_FAIL;
1358e87e6dddSBram Moolenaar STRCPY(ptr, qfprev->qf_text);
1359e87e6dddSBram Moolenaar vim_free(qfprev->qf_text);
1360e87e6dddSBram Moolenaar qfprev->qf_text = ptr;
1361e87e6dddSBram Moolenaar *(ptr += len) = '\n';
1362e87e6dddSBram Moolenaar STRCPY(++ptr, fields->errmsg);
1363e87e6dddSBram Moolenaar }
1364e87e6dddSBram Moolenaar if (qfprev->qf_nr == -1)
1365e87e6dddSBram Moolenaar qfprev->qf_nr = fields->enr;
1366e87e6dddSBram Moolenaar if (vim_isprintc(fields->type) && !qfprev->qf_type)
136700bf8cd2SBram Moolenaar // only printable chars allowed
1368e87e6dddSBram Moolenaar qfprev->qf_type = fields->type;
1369e87e6dddSBram Moolenaar
1370e87e6dddSBram Moolenaar if (!qfprev->qf_lnum)
1371e87e6dddSBram Moolenaar qfprev->qf_lnum = fields->lnum;
1372e87e6dddSBram Moolenaar if (!qfprev->qf_col)
1373c95940c0SBram Moolenaar {
1374e87e6dddSBram Moolenaar qfprev->qf_col = fields->col;
1375e87e6dddSBram Moolenaar qfprev->qf_viscol = fields->use_viscol;
1376c95940c0SBram Moolenaar }
1377e87e6dddSBram Moolenaar if (!qfprev->qf_fnum)
13780398e00aSBram Moolenaar qfprev->qf_fnum = qf_get_fnum(qfl,
1379a7df8c70SBram Moolenaar qfl->qf_directory,
1380a7df8c70SBram Moolenaar *fields->namebuf || qfl->qf_directory != NULL
1381e87e6dddSBram Moolenaar ? fields->namebuf
1382a7df8c70SBram Moolenaar : qfl->qf_currfile != NULL && fields->valid
1383a7df8c70SBram Moolenaar ? qfl->qf_currfile : 0);
13849b457948SBram Moolenaar }
1385e87e6dddSBram Moolenaar if (idx == 'Z')
1386a7df8c70SBram Moolenaar qfl->qf_multiline = qfl->qf_multiignore = FALSE;
1387e87e6dddSBram Moolenaar line_breakcheck();
138818cebf44SBram Moolenaar
1389e87e6dddSBram Moolenaar return QF_IGNORE_LINE;
1390e87e6dddSBram Moolenaar }
139118cebf44SBram Moolenaar
139218cebf44SBram Moolenaar /*
139318cebf44SBram Moolenaar * Parse a line and get the quickfix fields.
139418cebf44SBram Moolenaar * Return the QF_ status.
139518cebf44SBram Moolenaar */
139618cebf44SBram Moolenaar static int
qf_parse_line(qf_list_T * qfl,char_u * linebuf,int linelen,efm_T * fmt_first,qffields_T * fields)139718cebf44SBram Moolenaar qf_parse_line(
13980398e00aSBram Moolenaar qf_list_T *qfl,
139918cebf44SBram Moolenaar char_u *linebuf,
140018cebf44SBram Moolenaar int linelen,
140118cebf44SBram Moolenaar efm_T *fmt_first,
140218cebf44SBram Moolenaar qffields_T *fields)
140318cebf44SBram Moolenaar {
140418cebf44SBram Moolenaar efm_T *fmt_ptr;
140518cebf44SBram Moolenaar int idx = 0;
140618cebf44SBram Moolenaar char_u *tail = NULL;
140718cebf44SBram Moolenaar int status;
140818cebf44SBram Moolenaar
140918cebf44SBram Moolenaar restofline:
141000bf8cd2SBram Moolenaar // If there was no %> item start at the first pattern
141118cebf44SBram Moolenaar if (fmt_start == NULL)
141218cebf44SBram Moolenaar fmt_ptr = fmt_first;
141318cebf44SBram Moolenaar else
141418cebf44SBram Moolenaar {
141500bf8cd2SBram Moolenaar // Otherwise start from the last used pattern
141618cebf44SBram Moolenaar fmt_ptr = fmt_start;
141718cebf44SBram Moolenaar fmt_start = NULL;
141818cebf44SBram Moolenaar }
141918cebf44SBram Moolenaar
142000bf8cd2SBram Moolenaar // Try to match each part of 'errorformat' until we find a complete
142100bf8cd2SBram Moolenaar // match or no match.
142218cebf44SBram Moolenaar fields->valid = TRUE;
142318cebf44SBram Moolenaar for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next)
142418cebf44SBram Moolenaar {
142518cebf44SBram Moolenaar idx = fmt_ptr->prefix;
142618cebf44SBram Moolenaar status = qf_parse_get_fields(linebuf, linelen, fmt_ptr, fields,
142718cebf44SBram Moolenaar qfl->qf_multiline, qfl->qf_multiscan, &tail);
142818cebf44SBram Moolenaar if (status == QF_NOMEM)
142918cebf44SBram Moolenaar return status;
143018cebf44SBram Moolenaar if (status == QF_OK)
143118cebf44SBram Moolenaar break;
143218cebf44SBram Moolenaar }
143318cebf44SBram Moolenaar qfl->qf_multiscan = FALSE;
143418cebf44SBram Moolenaar
143518cebf44SBram Moolenaar if (fmt_ptr == NULL || idx == 'D' || idx == 'X')
143618cebf44SBram Moolenaar {
143718cebf44SBram Moolenaar if (fmt_ptr != NULL)
143818cebf44SBram Moolenaar {
143900bf8cd2SBram Moolenaar // 'D' and 'X' directory specifiers
144018cebf44SBram Moolenaar status = qf_parse_dir_pfx(idx, fields, qfl);
144118cebf44SBram Moolenaar if (status != QF_OK)
144218cebf44SBram Moolenaar return status;
144318cebf44SBram Moolenaar }
144418cebf44SBram Moolenaar
144518cebf44SBram Moolenaar status = qf_parse_line_nomatch(linebuf, linelen, fields);
144618cebf44SBram Moolenaar if (status != QF_OK)
144718cebf44SBram Moolenaar return status;
144818cebf44SBram Moolenaar
144918cebf44SBram Moolenaar if (fmt_ptr == NULL)
145018cebf44SBram Moolenaar qfl->qf_multiline = qfl->qf_multiignore = FALSE;
145118cebf44SBram Moolenaar }
145218cebf44SBram Moolenaar else if (fmt_ptr != NULL)
145318cebf44SBram Moolenaar {
145400bf8cd2SBram Moolenaar // honor %> item
145518cebf44SBram Moolenaar if (fmt_ptr->conthere)
145618cebf44SBram Moolenaar fmt_start = fmt_ptr;
145718cebf44SBram Moolenaar
1458e928366dSBram Moolenaar if (vim_strchr((char_u *)"AEWIN", idx) != NULL)
145918cebf44SBram Moolenaar {
146000bf8cd2SBram Moolenaar qfl->qf_multiline = TRUE; // start of a multi-line message
146100bf8cd2SBram Moolenaar qfl->qf_multiignore = FALSE;// reset continuation
146218cebf44SBram Moolenaar }
146318cebf44SBram Moolenaar else if (vim_strchr((char_u *)"CZ", idx) != NULL)
146400bf8cd2SBram Moolenaar { // continuation of multi-line msg
14650398e00aSBram Moolenaar status = qf_parse_multiline_pfx(idx, qfl, fields);
146618cebf44SBram Moolenaar if (status != QF_OK)
146718cebf44SBram Moolenaar return status;
146818cebf44SBram Moolenaar }
1469e87e6dddSBram Moolenaar else if (vim_strchr((char_u *)"OPQ", idx) != NULL)
147000bf8cd2SBram Moolenaar { // global file names
147118cebf44SBram Moolenaar status = qf_parse_file_pfx(idx, fields, qfl, tail);
147218cebf44SBram Moolenaar if (status == QF_MULTISCAN)
1473e87e6dddSBram Moolenaar goto restofline;
1474e87e6dddSBram Moolenaar }
147500bf8cd2SBram Moolenaar if (fmt_ptr->flags == '-') // generally exclude this line
1476e87e6dddSBram Moolenaar {
1477a7df8c70SBram Moolenaar if (qfl->qf_multiline)
147800bf8cd2SBram Moolenaar // also exclude continuation lines
1479a7df8c70SBram Moolenaar qfl->qf_multiignore = TRUE;
1480e87e6dddSBram Moolenaar return QF_IGNORE_LINE;
1481e87e6dddSBram Moolenaar }
1482e87e6dddSBram Moolenaar }
1483e87e6dddSBram Moolenaar
1484e87e6dddSBram Moolenaar return QF_OK;
1485e87e6dddSBram Moolenaar }
1486e87e6dddSBram Moolenaar
1487071d4279SBram Moolenaar /*
1488019dfe68SBram Moolenaar * Returns TRUE if the specified quickfix/location stack is empty
1489019dfe68SBram Moolenaar */
1490019dfe68SBram Moolenaar static int
qf_stack_empty(qf_info_T * qi)1491019dfe68SBram Moolenaar qf_stack_empty(qf_info_T *qi)
1492019dfe68SBram Moolenaar {
1493019dfe68SBram Moolenaar return qi == NULL || qi->qf_listcount <= 0;
1494019dfe68SBram Moolenaar }
1495019dfe68SBram Moolenaar
1496019dfe68SBram Moolenaar /*
1497de3b3677SBram Moolenaar * Returns TRUE if the specified quickfix/location list is empty.
1498de3b3677SBram Moolenaar */
1499de3b3677SBram Moolenaar static int
qf_list_empty(qf_list_T * qfl)15000398e00aSBram Moolenaar qf_list_empty(qf_list_T *qfl)
1501de3b3677SBram Moolenaar {
15020398e00aSBram Moolenaar return qfl == NULL || qfl->qf_count <= 0;
15030398e00aSBram Moolenaar }
15040398e00aSBram Moolenaar
15050398e00aSBram Moolenaar /*
15063ff33114SBram Moolenaar * Returns TRUE if the specified quickfix/location list is not empty and
15073ff33114SBram Moolenaar * has valid entries.
15083ff33114SBram Moolenaar */
15093ff33114SBram Moolenaar static int
qf_list_has_valid_entries(qf_list_T * qfl)15103ff33114SBram Moolenaar qf_list_has_valid_entries(qf_list_T *qfl)
15113ff33114SBram Moolenaar {
15123ff33114SBram Moolenaar return !qf_list_empty(qfl) && !qfl->qf_nonevalid;
15133ff33114SBram Moolenaar }
15143ff33114SBram Moolenaar
15153ff33114SBram Moolenaar /*
15160398e00aSBram Moolenaar * Return a pointer to a list in the specified quickfix stack
15170398e00aSBram Moolenaar */
15180398e00aSBram Moolenaar static qf_list_T *
qf_get_list(qf_info_T * qi,int idx)15190398e00aSBram Moolenaar qf_get_list(qf_info_T *qi, int idx)
15200398e00aSBram Moolenaar {
15210398e00aSBram Moolenaar return &qi->qf_lists[idx];
1522de3b3677SBram Moolenaar }
1523de3b3677SBram Moolenaar
1524de3b3677SBram Moolenaar /*
15256053f2d2SBram Moolenaar * Allocate the fields used for parsing lines and populating a quickfix list.
15266053f2d2SBram Moolenaar */
15276053f2d2SBram Moolenaar static int
qf_alloc_fields(qffields_T * pfields)15286053f2d2SBram Moolenaar qf_alloc_fields(qffields_T *pfields)
15296053f2d2SBram Moolenaar {
15306053f2d2SBram Moolenaar pfields->namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
15316053f2d2SBram Moolenaar pfields->module = alloc_id(CMDBUFFSIZE + 1, aid_qf_module);
15326053f2d2SBram Moolenaar pfields->errmsglen = CMDBUFFSIZE + 1;
15336053f2d2SBram Moolenaar pfields->errmsg = alloc_id(pfields->errmsglen, aid_qf_errmsg);
15346053f2d2SBram Moolenaar pfields->pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern);
15356053f2d2SBram Moolenaar if (pfields->namebuf == NULL || pfields->errmsg == NULL
15366053f2d2SBram Moolenaar || pfields->pattern == NULL || pfields->module == NULL)
15376053f2d2SBram Moolenaar return FAIL;
15386053f2d2SBram Moolenaar
15396053f2d2SBram Moolenaar return OK;
15406053f2d2SBram Moolenaar }
15416053f2d2SBram Moolenaar
15426053f2d2SBram Moolenaar /*
15436053f2d2SBram Moolenaar * Free the fields used for parsing lines and populating a quickfix list.
15446053f2d2SBram Moolenaar */
15456053f2d2SBram Moolenaar static void
qf_free_fields(qffields_T * pfields)15466053f2d2SBram Moolenaar qf_free_fields(qffields_T *pfields)
15476053f2d2SBram Moolenaar {
15486053f2d2SBram Moolenaar vim_free(pfields->namebuf);
15496053f2d2SBram Moolenaar vim_free(pfields->module);
15506053f2d2SBram Moolenaar vim_free(pfields->errmsg);
15516053f2d2SBram Moolenaar vim_free(pfields->pattern);
15526053f2d2SBram Moolenaar }
15536053f2d2SBram Moolenaar
15546053f2d2SBram Moolenaar /*
15556053f2d2SBram Moolenaar * Setup the state information used for parsing lines and populating a
15566053f2d2SBram Moolenaar * quickfix list.
15576053f2d2SBram Moolenaar */
15586053f2d2SBram Moolenaar static int
qf_setup_state(qfstate_T * pstate,char_u * enc,char_u * efile,typval_T * tv,buf_T * buf,linenr_T lnumfirst,linenr_T lnumlast)15596053f2d2SBram Moolenaar qf_setup_state(
15606053f2d2SBram Moolenaar qfstate_T *pstate,
15616053f2d2SBram Moolenaar char_u *enc,
15626053f2d2SBram Moolenaar char_u *efile,
15636053f2d2SBram Moolenaar typval_T *tv,
15646053f2d2SBram Moolenaar buf_T *buf,
15656053f2d2SBram Moolenaar linenr_T lnumfirst,
15666053f2d2SBram Moolenaar linenr_T lnumlast)
15676053f2d2SBram Moolenaar {
15686053f2d2SBram Moolenaar pstate->vc.vc_type = CONV_NONE;
15696053f2d2SBram Moolenaar if (enc != NULL && *enc != NUL)
15706053f2d2SBram Moolenaar convert_setup(&pstate->vc, enc, p_enc);
15716053f2d2SBram Moolenaar
15726053f2d2SBram Moolenaar if (efile != NULL && (pstate->fd = mch_fopen((char *)efile, "r")) == NULL)
15736053f2d2SBram Moolenaar {
1574e29a27f6SBram Moolenaar semsg(_(e_cant_open_errorfile_str), efile);
15756053f2d2SBram Moolenaar return FAIL;
15766053f2d2SBram Moolenaar }
15776053f2d2SBram Moolenaar
15786053f2d2SBram Moolenaar if (tv != NULL)
15796053f2d2SBram Moolenaar {
15806053f2d2SBram Moolenaar if (tv->v_type == VAR_STRING)
15816053f2d2SBram Moolenaar pstate->p_str = tv->vval.v_string;
15826053f2d2SBram Moolenaar else if (tv->v_type == VAR_LIST)
15836053f2d2SBram Moolenaar pstate->p_li = tv->vval.v_list->lv_first;
15846053f2d2SBram Moolenaar pstate->tv = tv;
15856053f2d2SBram Moolenaar }
15866053f2d2SBram Moolenaar pstate->buf = buf;
15876053f2d2SBram Moolenaar pstate->buflnum = lnumfirst;
15886053f2d2SBram Moolenaar pstate->lnumlast = lnumlast;
15896053f2d2SBram Moolenaar
15906053f2d2SBram Moolenaar return OK;
15916053f2d2SBram Moolenaar }
15926053f2d2SBram Moolenaar
15936053f2d2SBram Moolenaar /*
15946053f2d2SBram Moolenaar * Cleanup the state information used for parsing lines and populating a
15956053f2d2SBram Moolenaar * quickfix list.
15966053f2d2SBram Moolenaar */
15976053f2d2SBram Moolenaar static void
qf_cleanup_state(qfstate_T * pstate)15986053f2d2SBram Moolenaar qf_cleanup_state(qfstate_T *pstate)
15996053f2d2SBram Moolenaar {
16006053f2d2SBram Moolenaar if (pstate->fd != NULL)
16016053f2d2SBram Moolenaar fclose(pstate->fd);
16026053f2d2SBram Moolenaar
16036053f2d2SBram Moolenaar vim_free(pstate->growbuf);
16046053f2d2SBram Moolenaar if (pstate->vc.vc_type != CONV_NONE)
16056053f2d2SBram Moolenaar convert_setup(&pstate->vc, NULL, NULL);
16066053f2d2SBram Moolenaar }
16076053f2d2SBram Moolenaar
16086053f2d2SBram Moolenaar /*
160995946f12SBram Moolenaar * Process the next line from a file/buffer/list/string and add it
161095946f12SBram Moolenaar * to the quickfix list 'qfl'.
161195946f12SBram Moolenaar */
161295946f12SBram Moolenaar static int
qf_init_process_nextline(qf_list_T * qfl,efm_T * fmt_first,qfstate_T * state,qffields_T * fields)161395946f12SBram Moolenaar qf_init_process_nextline(
161495946f12SBram Moolenaar qf_list_T *qfl,
161595946f12SBram Moolenaar efm_T *fmt_first,
161695946f12SBram Moolenaar qfstate_T *state,
161795946f12SBram Moolenaar qffields_T *fields)
161895946f12SBram Moolenaar {
161995946f12SBram Moolenaar int status;
162095946f12SBram Moolenaar
162195946f12SBram Moolenaar // Get the next line from a file/buffer/list/string
162295946f12SBram Moolenaar status = qf_get_nextline(state);
162395946f12SBram Moolenaar if (status != QF_OK)
162495946f12SBram Moolenaar return status;
162595946f12SBram Moolenaar
162695946f12SBram Moolenaar status = qf_parse_line(qfl, state->linebuf, state->linelen,
162795946f12SBram Moolenaar fmt_first, fields);
162895946f12SBram Moolenaar if (status != QF_OK)
162995946f12SBram Moolenaar return status;
163095946f12SBram Moolenaar
163195946f12SBram Moolenaar return qf_add_entry(qfl,
163295946f12SBram Moolenaar qfl->qf_directory,
163395946f12SBram Moolenaar (*fields->namebuf || qfl->qf_directory != NULL)
163495946f12SBram Moolenaar ? fields->namebuf
163595946f12SBram Moolenaar : ((qfl->qf_currfile != NULL && fields->valid)
163695946f12SBram Moolenaar ? qfl->qf_currfile : (char_u *)NULL),
163795946f12SBram Moolenaar fields->module,
163895946f12SBram Moolenaar 0,
163995946f12SBram Moolenaar fields->errmsg,
164095946f12SBram Moolenaar fields->lnum,
16416864efa5Sthinca fields->end_lnum,
164295946f12SBram Moolenaar fields->col,
16436864efa5Sthinca fields->end_col,
164495946f12SBram Moolenaar fields->use_viscol,
164595946f12SBram Moolenaar fields->pattern,
164695946f12SBram Moolenaar fields->enr,
164795946f12SBram Moolenaar fields->type,
164895946f12SBram Moolenaar fields->valid);
164995946f12SBram Moolenaar }
165095946f12SBram Moolenaar
165195946f12SBram Moolenaar /*
1652688e3d1fSBram Moolenaar * Read the errorfile "efile" into memory, line by line, building the error
1653688e3d1fSBram Moolenaar * list.
1654688e3d1fSBram Moolenaar * Alternative: when "efile" is NULL read errors from buffer "buf".
1655688e3d1fSBram Moolenaar * Alternative: when "tv" is not NULL get errors from the string or list.
1656688e3d1fSBram Moolenaar * Always use 'errorformat' from "buf" if there is a local value.
1657688e3d1fSBram Moolenaar * Then "lnumfirst" and "lnumlast" specify the range of lines to use.
1658688e3d1fSBram Moolenaar * Set the title of the list to "qf_title".
1659688e3d1fSBram Moolenaar * Return -1 for error, number of errors for success.
1660688e3d1fSBram Moolenaar */
1661688e3d1fSBram Moolenaar 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)1662688e3d1fSBram Moolenaar qf_init_ext(
1663688e3d1fSBram Moolenaar qf_info_T *qi,
1664a7df8c70SBram Moolenaar int qf_idx,
1665688e3d1fSBram Moolenaar char_u *efile,
1666688e3d1fSBram Moolenaar buf_T *buf,
1667688e3d1fSBram Moolenaar typval_T *tv,
1668688e3d1fSBram Moolenaar char_u *errorformat,
166900bf8cd2SBram Moolenaar int newlist, // TRUE: start a new error list
167000bf8cd2SBram Moolenaar linenr_T lnumfirst, // first line number to use
167100bf8cd2SBram Moolenaar linenr_T lnumlast, // last line number to use
16722c7292dcSBram Moolenaar char_u *qf_title,
16732c7292dcSBram Moolenaar char_u *enc)
1674688e3d1fSBram Moolenaar {
1675a7df8c70SBram Moolenaar qf_list_T *qfl;
16762c7292dcSBram Moolenaar qfstate_T state;
16772c7292dcSBram Moolenaar qffields_T fields;
1678688e3d1fSBram Moolenaar qfline_T *old_last = NULL;
167986f100dcSBram Moolenaar int adding = FALSE;
1680361c8f0eSBram Moolenaar static efm_T *fmt_first = NULL;
1681688e3d1fSBram Moolenaar char_u *efm;
1682361c8f0eSBram Moolenaar static char_u *last_efm = NULL;
168300bf8cd2SBram Moolenaar int retval = -1; // default: return error flag
1684e0d37976SBram Moolenaar int status;
1685688e3d1fSBram Moolenaar
168600bf8cd2SBram Moolenaar // Do not used the cached buffer, it may have been wiped out.
1687d23a8236SBram Moolenaar VIM_CLEAR(qf_last_bufname);
16886dd4a535SBram Moolenaar
1689a80faa89SBram Moolenaar CLEAR_FIELD(state);
1690a80faa89SBram Moolenaar CLEAR_FIELD(fields);
16916053f2d2SBram Moolenaar if ((qf_alloc_fields(&fields) == FAIL) ||
16926053f2d2SBram Moolenaar (qf_setup_state(&state, enc, efile, tv, buf,
16936053f2d2SBram Moolenaar lnumfirst, lnumlast) == FAIL))
1694688e3d1fSBram Moolenaar goto qf_init_end;
1695688e3d1fSBram Moolenaar
1696a7df8c70SBram Moolenaar if (newlist || qf_idx == qi->qf_listcount)
1697a7df8c70SBram Moolenaar {
169800bf8cd2SBram Moolenaar // make place for a new list
1699688e3d1fSBram Moolenaar qf_new_list(qi, qf_title);
1700a7df8c70SBram Moolenaar qf_idx = qi->qf_curlist;
17019afe5e9cSBram Moolenaar qfl = qf_get_list(qi, qf_idx);
1702a7df8c70SBram Moolenaar }
170386f100dcSBram Moolenaar else
1704688e3d1fSBram Moolenaar {
170500bf8cd2SBram Moolenaar // Adding to existing list, use last entry.
17062b946c9fSBram Moolenaar adding = TRUE;
17070398e00aSBram Moolenaar qfl = qf_get_list(qi, qf_idx);
17089afe5e9cSBram Moolenaar if (!qf_list_empty(qfl))
17099afe5e9cSBram Moolenaar old_last = qfl->qf_last;
17109afe5e9cSBram Moolenaar }
1711a7df8c70SBram Moolenaar
171200bf8cd2SBram Moolenaar // Use the local value of 'errorformat' if it's set.
1713688e3d1fSBram Moolenaar if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL)
1714688e3d1fSBram Moolenaar efm = buf->b_p_efm;
1715688e3d1fSBram Moolenaar else
1716688e3d1fSBram Moolenaar efm = errorformat;
1717688e3d1fSBram Moolenaar
171800bf8cd2SBram Moolenaar // If the errorformat didn't change between calls, then reuse the
171900bf8cd2SBram Moolenaar // previously parsed values.
1720361c8f0eSBram Moolenaar if (last_efm == NULL || (STRCMP(last_efm, efm) != 0))
1721361c8f0eSBram Moolenaar {
172200bf8cd2SBram Moolenaar // free the previously parsed data
1723d23a8236SBram Moolenaar VIM_CLEAR(last_efm);
1724361c8f0eSBram Moolenaar free_efm_list(&fmt_first);
1725361c8f0eSBram Moolenaar
172600bf8cd2SBram Moolenaar // parse the current 'efm'
1727688e3d1fSBram Moolenaar fmt_first = parse_efm_option(efm);
1728361c8f0eSBram Moolenaar if (fmt_first != NULL)
1729361c8f0eSBram Moolenaar last_efm = vim_strsave(efm);
1730361c8f0eSBram Moolenaar }
1731361c8f0eSBram Moolenaar
173200bf8cd2SBram Moolenaar if (fmt_first == NULL) // nothing found
1733688e3d1fSBram Moolenaar goto error2;
1734688e3d1fSBram Moolenaar
173500bf8cd2SBram Moolenaar // got_int is reset here, because it was probably set when killing the
173600bf8cd2SBram Moolenaar // ":make" command, but we still want to read the errorfile then.
1737071d4279SBram Moolenaar got_int = FALSE;
1738071d4279SBram Moolenaar
173900bf8cd2SBram Moolenaar // Read the lines in the error file one by one.
174000bf8cd2SBram Moolenaar // Try to recognize one of the error formats in each line.
174186b68359SBram Moolenaar while (!got_int)
1742071d4279SBram Moolenaar {
174395946f12SBram Moolenaar status = qf_init_process_nextline(qfl, fmt_first, &state, &fields);
174400bf8cd2SBram Moolenaar if (status == QF_NOMEM) // memory alloc failure
17456be8c8e1SBram Moolenaar goto qf_init_end;
174600bf8cd2SBram Moolenaar if (status == QF_END_OF_INPUT) // end of input
174787e25fdfSBram Moolenaar break;
1748e87e6dddSBram Moolenaar if (status == QF_FAIL)
1749e87e6dddSBram Moolenaar goto error2;
1750071d4279SBram Moolenaar
1751071d4279SBram Moolenaar line_breakcheck();
1752071d4279SBram Moolenaar }
1753e0d37976SBram Moolenaar if (state.fd == NULL || !ferror(state.fd))
1754071d4279SBram Moolenaar {
1755a7df8c70SBram Moolenaar if (qfl->qf_index == 0)
1756071d4279SBram Moolenaar {
175700bf8cd2SBram Moolenaar // no valid entry found
1758a7df8c70SBram Moolenaar qfl->qf_ptr = qfl->qf_start;
1759a7df8c70SBram Moolenaar qfl->qf_index = 1;
1760a7df8c70SBram Moolenaar qfl->qf_nonevalid = TRUE;
1761071d4279SBram Moolenaar }
1762071d4279SBram Moolenaar else
1763071d4279SBram Moolenaar {
1764a7df8c70SBram Moolenaar qfl->qf_nonevalid = FALSE;
1765a7df8c70SBram Moolenaar if (qfl->qf_ptr == NULL)
1766a7df8c70SBram Moolenaar qfl->qf_ptr = qfl->qf_start;
1767071d4279SBram Moolenaar }
176800bf8cd2SBram Moolenaar // return number of matches
1769a7df8c70SBram Moolenaar retval = qfl->qf_count;
1770bcf7772aSBram Moolenaar goto qf_init_end;
1771071d4279SBram Moolenaar }
1772d8e44476SBram Moolenaar emsg(_(e_error_while_reading_errorfile));
1773071d4279SBram Moolenaar error2:
17742b946c9fSBram Moolenaar if (!adding)
17752b946c9fSBram Moolenaar {
177600bf8cd2SBram Moolenaar // Error when creating a new list. Free the new list
1777108e7b42SBram Moolenaar qf_free(qfl);
1778d12f5c17SBram Moolenaar qi->qf_listcount--;
1779d12f5c17SBram Moolenaar if (qi->qf_curlist > 0)
1780d12f5c17SBram Moolenaar --qi->qf_curlist;
17812b946c9fSBram Moolenaar }
1782bcf7772aSBram Moolenaar qf_init_end:
1783a7df8c70SBram Moolenaar if (qf_idx == qi->qf_curlist)
1784864293abSBram Moolenaar qf_update_buffer(qi, old_last);
17856053f2d2SBram Moolenaar qf_cleanup_state(&state);
17866053f2d2SBram Moolenaar qf_free_fields(&fields);
1787071d4279SBram Moolenaar
1788071d4279SBram Moolenaar return retval;
1789071d4279SBram Moolenaar }
1790071d4279SBram Moolenaar
179118cebf44SBram Moolenaar /*
17926053f2d2SBram Moolenaar * Read the errorfile "efile" into memory, line by line, building the error
17936053f2d2SBram Moolenaar * list. Set the error list's title to qf_title.
17946053f2d2SBram Moolenaar * Return -1 for error, number of errors for success.
17956053f2d2SBram Moolenaar */
17966053f2d2SBram Moolenaar int
qf_init(win_T * wp,char_u * efile,char_u * errorformat,int newlist,char_u * qf_title,char_u * enc)17976053f2d2SBram Moolenaar qf_init(win_T *wp,
17986053f2d2SBram Moolenaar char_u *efile,
17996053f2d2SBram Moolenaar char_u *errorformat,
180000bf8cd2SBram Moolenaar int newlist, // TRUE: start a new error list
18016053f2d2SBram Moolenaar char_u *qf_title,
18026053f2d2SBram Moolenaar char_u *enc)
18036053f2d2SBram Moolenaar {
18046053f2d2SBram Moolenaar qf_info_T *qi = &ql_info;
18056053f2d2SBram Moolenaar
18066053f2d2SBram Moolenaar if (wp != NULL)
18076053f2d2SBram Moolenaar {
18086053f2d2SBram Moolenaar qi = ll_get_or_alloc_list(wp);
18096053f2d2SBram Moolenaar if (qi == NULL)
18106053f2d2SBram Moolenaar return FAIL;
18116053f2d2SBram Moolenaar }
18126053f2d2SBram Moolenaar
18136053f2d2SBram Moolenaar return qf_init_ext(qi, qi->qf_curlist, efile, curbuf, NULL, errorformat,
18146053f2d2SBram Moolenaar newlist, (linenr_T)0, (linenr_T)0, qf_title, enc);
18156053f2d2SBram Moolenaar }
18166053f2d2SBram Moolenaar
18176053f2d2SBram Moolenaar /*
181818cebf44SBram Moolenaar * Set the title of the specified quickfix list. Frees the previous title.
181918cebf44SBram Moolenaar * Prepends ':' to the title.
182018cebf44SBram Moolenaar */
1821fb60409aSBram Moolenaar static void
qf_store_title(qf_list_T * qfl,char_u * title)1822fe15b7dfSBram Moolenaar qf_store_title(qf_list_T *qfl, char_u *title)
1823fb60409aSBram Moolenaar {
1824fe15b7dfSBram Moolenaar VIM_CLEAR(qfl->qf_title);
18256a8958dbSBram Moolenaar
1826fb60409aSBram Moolenaar if (title != NULL)
1827fb60409aSBram Moolenaar {
182851e14387SBram Moolenaar char_u *p = alloc(STRLEN(title) + 2);
1829fb60409aSBram Moolenaar
1830fe15b7dfSBram Moolenaar qfl->qf_title = p;
1831fb60409aSBram Moolenaar if (p != NULL)
18328b62e310SBram Moolenaar STRCPY(p, title);
1833fb60409aSBram Moolenaar }
1834fb60409aSBram Moolenaar }
1835fb60409aSBram Moolenaar
1836071d4279SBram Moolenaar /*
18378b62e310SBram Moolenaar * The title of a quickfix/location list is set, by default, to the command
18388b62e310SBram Moolenaar * that created the quickfix list with the ":" prefix.
18398b62e310SBram Moolenaar * Create a quickfix list title string by prepending ":" to a user command.
18408b62e310SBram Moolenaar * Returns a pointer to a static buffer with the title.
18418b62e310SBram Moolenaar */
18428b62e310SBram Moolenaar static char_u *
qf_cmdtitle(char_u * cmd)18438b62e310SBram Moolenaar qf_cmdtitle(char_u *cmd)
18448b62e310SBram Moolenaar {
18458b62e310SBram Moolenaar static char_u qftitle_str[IOSIZE];
18468b62e310SBram Moolenaar
18478b62e310SBram Moolenaar vim_snprintf((char *)qftitle_str, IOSIZE, ":%s", (char *)cmd);
18488b62e310SBram Moolenaar return qftitle_str;
18498b62e310SBram Moolenaar }
18508b62e310SBram Moolenaar
18518b62e310SBram Moolenaar /*
18524aa47b28SBram Moolenaar * Return a pointer to the current list in the specified quickfix stack
18534aa47b28SBram Moolenaar */
18544aa47b28SBram Moolenaar static qf_list_T *
qf_get_curlist(qf_info_T * qi)18554aa47b28SBram Moolenaar qf_get_curlist(qf_info_T *qi)
18564aa47b28SBram Moolenaar {
18570398e00aSBram Moolenaar return qf_get_list(qi, qi->qf_curlist);
18584aa47b28SBram Moolenaar }
18594aa47b28SBram Moolenaar
18604aa47b28SBram Moolenaar /*
186155b69264SBram Moolenaar * Prepare for adding a new quickfix list. If the current list is in the
186255b69264SBram Moolenaar * middle of the stack, then all the following lists are freed and then
186355b69264SBram Moolenaar * the new list is added.
1864071d4279SBram Moolenaar */
1865071d4279SBram Moolenaar static void
qf_new_list(qf_info_T * qi,char_u * qf_title)186605540976SBram Moolenaar qf_new_list(qf_info_T *qi, char_u *qf_title)
1867071d4279SBram Moolenaar {
1868071d4279SBram Moolenaar int i;
1869108e7b42SBram Moolenaar qf_list_T *qfl;
1870071d4279SBram Moolenaar
187100bf8cd2SBram Moolenaar // If the current entry is not the last entry, delete entries beyond
187200bf8cd2SBram Moolenaar // the current entry. This makes it possible to browse in a tree-like
187332aa1020SBram Moolenaar // way with ":grep".
1874d12f5c17SBram Moolenaar while (qi->qf_listcount > qi->qf_curlist + 1)
1875fe15b7dfSBram Moolenaar qf_free(&qi->qf_lists[--qi->qf_listcount]);
1876071d4279SBram Moolenaar
187700bf8cd2SBram Moolenaar // When the stack is full, remove to oldest entry
187800bf8cd2SBram Moolenaar // Otherwise, add a new entry.
1879d12f5c17SBram Moolenaar if (qi->qf_listcount == LISTCOUNT)
1880071d4279SBram Moolenaar {
1881fe15b7dfSBram Moolenaar qf_free(&qi->qf_lists[0]);
1882071d4279SBram Moolenaar for (i = 1; i < LISTCOUNT; ++i)
1883d12f5c17SBram Moolenaar qi->qf_lists[i - 1] = qi->qf_lists[i];
1884d12f5c17SBram Moolenaar qi->qf_curlist = LISTCOUNT - 1;
1885071d4279SBram Moolenaar }
1886071d4279SBram Moolenaar else
1887d12f5c17SBram Moolenaar qi->qf_curlist = qi->qf_listcount++;
18884aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
1889a80faa89SBram Moolenaar CLEAR_POINTER(qfl);
1890108e7b42SBram Moolenaar qf_store_title(qfl, qf_title);
18912d67d307SBram Moolenaar qfl->qfl_type = qi->qfl_type;
1892108e7b42SBram Moolenaar qfl->qf_id = ++last_qf_id;
1893071d4279SBram Moolenaar }
1894071d4279SBram Moolenaar
1895d12f5c17SBram Moolenaar /*
18969f84ded3SBram Moolenaar * Queue location list stack delete request.
18979f84ded3SBram Moolenaar */
18989f84ded3SBram Moolenaar static void
locstack_queue_delreq(qf_info_T * qi)18999f84ded3SBram Moolenaar locstack_queue_delreq(qf_info_T *qi)
19009f84ded3SBram Moolenaar {
19019f84ded3SBram Moolenaar qf_delq_T *q;
19029f84ded3SBram Moolenaar
1903c799fe20SBram Moolenaar q = ALLOC_ONE(qf_delq_T);
19049f84ded3SBram Moolenaar if (q != NULL)
19059f84ded3SBram Moolenaar {
19069f84ded3SBram Moolenaar q->qi = qi;
19079f84ded3SBram Moolenaar q->next = qf_delq_head;
19089f84ded3SBram Moolenaar qf_delq_head = q;
19099f84ded3SBram Moolenaar }
19109f84ded3SBram Moolenaar }
19119f84ded3SBram Moolenaar
19129f84ded3SBram Moolenaar /*
1913ee8188fcSBram Moolenaar * Return the global quickfix stack window buffer number.
1914ee8188fcSBram Moolenaar */
1915ee8188fcSBram Moolenaar int
qf_stack_get_bufnr(void)1916ee8188fcSBram Moolenaar qf_stack_get_bufnr(void)
1917ee8188fcSBram Moolenaar {
1918ee8188fcSBram Moolenaar return ql_info.qf_bufnr;
1919ee8188fcSBram Moolenaar }
1920ee8188fcSBram Moolenaar
1921ee8188fcSBram Moolenaar /*
1922ee8188fcSBram Moolenaar * Wipe the quickfix window buffer (if present) for the specified
1923ee8188fcSBram Moolenaar * quickfix/location list.
1924ee8188fcSBram Moolenaar */
1925ee8188fcSBram Moolenaar static void
wipe_qf_buffer(qf_info_T * qi)1926ee8188fcSBram Moolenaar wipe_qf_buffer(qf_info_T *qi)
1927ee8188fcSBram Moolenaar {
1928ee8188fcSBram Moolenaar buf_T *qfbuf;
1929ee8188fcSBram Moolenaar
1930ee8188fcSBram Moolenaar if (qi->qf_bufnr != INVALID_QFBUFNR)
1931ee8188fcSBram Moolenaar {
1932ee8188fcSBram Moolenaar qfbuf = buflist_findnr(qi->qf_bufnr);
1933ee8188fcSBram Moolenaar if (qfbuf != NULL && qfbuf->b_nwindows == 0)
1934ee8188fcSBram Moolenaar {
1935ee8188fcSBram Moolenaar // If the quickfix buffer is not loaded in any window, then
1936ee8188fcSBram Moolenaar // wipe the buffer.
1937a6e8f888SBram Moolenaar close_buffer(NULL, qfbuf, DOBUF_WIPE, FALSE, FALSE);
1938ee8188fcSBram Moolenaar qi->qf_bufnr = INVALID_QFBUFNR;
1939ee8188fcSBram Moolenaar }
1940ee8188fcSBram Moolenaar }
1941ee8188fcSBram Moolenaar }
1942ee8188fcSBram Moolenaar
1943ee8188fcSBram Moolenaar /*
1944fe15b7dfSBram Moolenaar * Free a location list stack
1945d12f5c17SBram Moolenaar */
1946d12f5c17SBram Moolenaar static void
ll_free_all(qf_info_T ** pqi)194705540976SBram Moolenaar ll_free_all(qf_info_T **pqi)
1948f461c8e7SBram Moolenaar {
1949f461c8e7SBram Moolenaar int i;
1950d12f5c17SBram Moolenaar qf_info_T *qi;
1951f461c8e7SBram Moolenaar
1952d12f5c17SBram Moolenaar qi = *pqi;
1953d12f5c17SBram Moolenaar if (qi == NULL)
1954d12f5c17SBram Moolenaar return;
195500bf8cd2SBram Moolenaar *pqi = NULL; // Remove reference to this list
1956d12f5c17SBram Moolenaar
1957eeb1b9c7SBram Moolenaar // If the location list is still in use, then queue the delete request
1958eeb1b9c7SBram Moolenaar // to be processed later.
1959eeb1b9c7SBram Moolenaar if (quickfix_busy > 0)
1960eeb1b9c7SBram Moolenaar {
1961eeb1b9c7SBram Moolenaar locstack_queue_delreq(qi);
1962eeb1b9c7SBram Moolenaar return;
1963eeb1b9c7SBram Moolenaar }
1964eeb1b9c7SBram Moolenaar
1965d12f5c17SBram Moolenaar qi->qf_refcount--;
1966d12f5c17SBram Moolenaar if (qi->qf_refcount < 1)
1967d12f5c17SBram Moolenaar {
19689f84ded3SBram Moolenaar // No references to this location list.
1969ee8188fcSBram Moolenaar // If the quickfix window buffer is loaded, then wipe it
1970ee8188fcSBram Moolenaar wipe_qf_buffer(qi);
1971ee8188fcSBram Moolenaar
1972d12f5c17SBram Moolenaar for (i = 0; i < qi->qf_listcount; ++i)
19730398e00aSBram Moolenaar qf_free(qf_get_list(qi, i));
1974d12f5c17SBram Moolenaar vim_free(qi);
1975f461c8e7SBram Moolenaar }
1976d12f5c17SBram Moolenaar }
1977d12f5c17SBram Moolenaar
197818cebf44SBram Moolenaar /*
197918cebf44SBram Moolenaar * Free all the quickfix/location lists in the stack.
198018cebf44SBram Moolenaar */
1981d12f5c17SBram Moolenaar void
qf_free_all(win_T * wp)198205540976SBram Moolenaar qf_free_all(win_T *wp)
1983d12f5c17SBram Moolenaar {
1984d12f5c17SBram Moolenaar int i;
1985d12f5c17SBram Moolenaar qf_info_T *qi = &ql_info;
1986d12f5c17SBram Moolenaar
1987d12f5c17SBram Moolenaar if (wp != NULL)
1988d12f5c17SBram Moolenaar {
198900bf8cd2SBram Moolenaar // location list
1990d12f5c17SBram Moolenaar ll_free_all(&wp->w_llist);
1991d12f5c17SBram Moolenaar ll_free_all(&wp->w_llist_ref);
1992d12f5c17SBram Moolenaar }
1993d12f5c17SBram Moolenaar else
199400bf8cd2SBram Moolenaar // quickfix list
1995d12f5c17SBram Moolenaar for (i = 0; i < qi->qf_listcount; ++i)
19960398e00aSBram Moolenaar qf_free(qf_get_list(qi, i));
1997d12f5c17SBram Moolenaar }
1998f461c8e7SBram Moolenaar
1999071d4279SBram Moolenaar /*
20009f84ded3SBram Moolenaar * Delay freeing of location list stacks when the quickfix code is running.
20019f84ded3SBram Moolenaar * Used to avoid problems with autocmds freeing location list stacks when the
20029f84ded3SBram Moolenaar * quickfix code is still referencing the stack.
20039f84ded3SBram Moolenaar * Must always call decr_quickfix_busy() exactly once after this.
20049f84ded3SBram Moolenaar */
20059f84ded3SBram Moolenaar static void
incr_quickfix_busy(void)20069f84ded3SBram Moolenaar incr_quickfix_busy(void)
20079f84ded3SBram Moolenaar {
20089f84ded3SBram Moolenaar quickfix_busy++;
20099f84ded3SBram Moolenaar }
20109f84ded3SBram Moolenaar
20119f84ded3SBram Moolenaar /*
20129f84ded3SBram Moolenaar * Safe to free location list stacks. Process any delayed delete requests.
20139f84ded3SBram Moolenaar */
20149f84ded3SBram Moolenaar static void
decr_quickfix_busy(void)20159f84ded3SBram Moolenaar decr_quickfix_busy(void)
20169f84ded3SBram Moolenaar {
20179f84ded3SBram Moolenaar if (--quickfix_busy == 0)
20189f84ded3SBram Moolenaar {
20199f84ded3SBram Moolenaar // No longer referencing the location lists. Process all the pending
20209f84ded3SBram Moolenaar // delete requests.
20219f84ded3SBram Moolenaar while (qf_delq_head != NULL)
20229f84ded3SBram Moolenaar {
20239f84ded3SBram Moolenaar qf_delq_T *q = qf_delq_head;
20249f84ded3SBram Moolenaar
20259f84ded3SBram Moolenaar qf_delq_head = q->next;
20269f84ded3SBram Moolenaar ll_free_all(&q->qi);
20279f84ded3SBram Moolenaar vim_free(q);
20289f84ded3SBram Moolenaar }
20299f84ded3SBram Moolenaar }
20309f84ded3SBram Moolenaar #ifdef ABORT_ON_INTERNAL_ERROR
20319f84ded3SBram Moolenaar if (quickfix_busy < 0)
20329f84ded3SBram Moolenaar {
2033f9e3e09fSBram Moolenaar emsg("quickfix_busy has become negative");
20349f84ded3SBram Moolenaar abort();
20359f84ded3SBram Moolenaar }
20369f84ded3SBram Moolenaar #endif
20379f84ded3SBram Moolenaar }
20389f84ded3SBram Moolenaar
20399f84ded3SBram Moolenaar #if defined(EXITFREE) || defined(PROTO)
20409f84ded3SBram Moolenaar void
check_quickfix_busy(void)20419f84ded3SBram Moolenaar check_quickfix_busy(void)
20429f84ded3SBram Moolenaar {
20439f84ded3SBram Moolenaar if (quickfix_busy != 0)
20449f84ded3SBram Moolenaar {
2045f9e3e09fSBram Moolenaar semsg("quickfix_busy not zero on exit: %ld", (long)quickfix_busy);
20469f84ded3SBram Moolenaar # ifdef ABORT_ON_INTERNAL_ERROR
20479f84ded3SBram Moolenaar abort();
20489f84ded3SBram Moolenaar # endif
20499f84ded3SBram Moolenaar }
20509f84ded3SBram Moolenaar }
20519f84ded3SBram Moolenaar #endif
20529f84ded3SBram Moolenaar
20539f84ded3SBram Moolenaar /*
2054071d4279SBram Moolenaar * Add an entry to the end of the list of errors.
205595946f12SBram Moolenaar * Returns QF_OK or QF_FAIL.
2056071d4279SBram Moolenaar */
2057071d4279SBram Moolenaar static int
qf_add_entry(qf_list_T * qfl,char_u * dir,char_u * fname,char_u * module,int bufnum,char_u * mesg,long lnum,long end_lnum,int col,int end_col,int vis_col,char_u * pattern,int nr,int type,int valid)205805540976SBram Moolenaar qf_add_entry(
20590398e00aSBram Moolenaar qf_list_T *qfl, // quickfix list entry
206000bf8cd2SBram Moolenaar char_u *dir, // optional directory name
206100bf8cd2SBram Moolenaar char_u *fname, // file name or NULL
206200bf8cd2SBram Moolenaar char_u *module, // module name or NULL
206300bf8cd2SBram Moolenaar int bufnum, // buffer number or zero
206400bf8cd2SBram Moolenaar char_u *mesg, // message
206500bf8cd2SBram Moolenaar long lnum, // line number
20666864efa5Sthinca long end_lnum, // line number for end
206700bf8cd2SBram Moolenaar int col, // column
20686864efa5Sthinca int end_col, // column for end
206900bf8cd2SBram Moolenaar int vis_col, // using visual column
207000bf8cd2SBram Moolenaar char_u *pattern, // search pattern
207100bf8cd2SBram Moolenaar int nr, // error number
207200bf8cd2SBram Moolenaar int type, // type character
207300bf8cd2SBram Moolenaar int valid) // valid entry
2074071d4279SBram Moolenaar {
207568b76a69SBram Moolenaar qfline_T *qfp;
207600bf8cd2SBram Moolenaar qfline_T **lastp; // pointer to qf_last or NULL
2077071d4279SBram Moolenaar
2078c799fe20SBram Moolenaar if ((qfp = ALLOC_ONE(qfline_T)) == NULL)
207995946f12SBram Moolenaar return QF_FAIL;
208048b66fb5SBram Moolenaar if (bufnum != 0)
20812f095a4bSBram Moolenaar {
20822f095a4bSBram Moolenaar buf_T *buf = buflist_findnr(bufnum);
20832f095a4bSBram Moolenaar
208448b66fb5SBram Moolenaar qfp->qf_fnum = bufnum;
20852f095a4bSBram Moolenaar if (buf != NULL)
2086c1542744SBram Moolenaar buf->b_has_qf_entry |=
20872d67d307SBram Moolenaar IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
20882f095a4bSBram Moolenaar }
208948b66fb5SBram Moolenaar else
20900398e00aSBram Moolenaar qfp->qf_fnum = qf_get_fnum(qfl, dir, fname);
2091071d4279SBram Moolenaar if ((qfp->qf_text = vim_strsave(mesg)) == NULL)
2092071d4279SBram Moolenaar {
2093071d4279SBram Moolenaar vim_free(qfp);
209495946f12SBram Moolenaar return QF_FAIL;
2095071d4279SBram Moolenaar }
2096071d4279SBram Moolenaar qfp->qf_lnum = lnum;
20976864efa5Sthinca qfp->qf_end_lnum = end_lnum;
2098071d4279SBram Moolenaar qfp->qf_col = col;
20996864efa5Sthinca qfp->qf_end_col = end_col;
210005159a0cSBram Moolenaar qfp->qf_viscol = vis_col;
210168b76a69SBram Moolenaar if (pattern == NULL || *pattern == NUL)
210268b76a69SBram Moolenaar qfp->qf_pattern = NULL;
210368b76a69SBram Moolenaar else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL)
210468b76a69SBram Moolenaar {
210568b76a69SBram Moolenaar vim_free(qfp->qf_text);
210668b76a69SBram Moolenaar vim_free(qfp);
210795946f12SBram Moolenaar return QF_FAIL;
210868b76a69SBram Moolenaar }
2109d76ce852SBram Moolenaar if (module == NULL || *module == NUL)
2110d76ce852SBram Moolenaar qfp->qf_module = NULL;
2111d76ce852SBram Moolenaar else if ((qfp->qf_module = vim_strsave(module)) == NULL)
2112d76ce852SBram Moolenaar {
2113d76ce852SBram Moolenaar vim_free(qfp->qf_text);
2114d76ce852SBram Moolenaar vim_free(qfp->qf_pattern);
2115d76ce852SBram Moolenaar vim_free(qfp);
211695946f12SBram Moolenaar return QF_FAIL;
2117d76ce852SBram Moolenaar }
2118071d4279SBram Moolenaar qfp->qf_nr = nr;
211900bf8cd2SBram Moolenaar if (type != 1 && !vim_isprintc(type)) // only printable chars allowed
2120071d4279SBram Moolenaar type = 0;
2121071d4279SBram Moolenaar qfp->qf_type = type;
2122071d4279SBram Moolenaar qfp->qf_valid = valid;
2123071d4279SBram Moolenaar
2124fe15b7dfSBram Moolenaar lastp = &qfl->qf_last;
21250398e00aSBram Moolenaar if (qf_list_empty(qfl)) // first element in the list
2126071d4279SBram Moolenaar {
2127fe15b7dfSBram Moolenaar qfl->qf_start = qfp;
2128fe15b7dfSBram Moolenaar qfl->qf_ptr = qfp;
2129fe15b7dfSBram Moolenaar qfl->qf_index = 0;
213083e6d7acSBram Moolenaar qfp->qf_prev = NULL;
2131071d4279SBram Moolenaar }
2132071d4279SBram Moolenaar else
2133071d4279SBram Moolenaar {
213483e6d7acSBram Moolenaar qfp->qf_prev = *lastp;
213583e6d7acSBram Moolenaar (*lastp)->qf_next = qfp;
2136071d4279SBram Moolenaar }
213783e6d7acSBram Moolenaar qfp->qf_next = NULL;
2138071d4279SBram Moolenaar qfp->qf_cleared = FALSE;
213983e6d7acSBram Moolenaar *lastp = qfp;
2140fe15b7dfSBram Moolenaar ++qfl->qf_count;
214100bf8cd2SBram Moolenaar if (qfl->qf_index == 0 && qfp->qf_valid) // first valid entry
2142071d4279SBram Moolenaar {
2143fe15b7dfSBram Moolenaar qfl->qf_index = qfl->qf_count;
2144fe15b7dfSBram Moolenaar qfl->qf_ptr = qfp;
2145071d4279SBram Moolenaar }
2146071d4279SBram Moolenaar
214795946f12SBram Moolenaar return QF_OK;
2148071d4279SBram Moolenaar }
2149071d4279SBram Moolenaar
2150071d4279SBram Moolenaar /*
21512d67d307SBram Moolenaar * Allocate a new quickfix/location list stack
2152d12f5c17SBram Moolenaar */
21538b6144bdSBram Moolenaar static qf_info_T *
qf_alloc_stack(qfltype_T qfltype)21542d67d307SBram Moolenaar qf_alloc_stack(qfltype_T qfltype)
2155d12f5c17SBram Moolenaar {
21568b6144bdSBram Moolenaar qf_info_T *qi;
2157d12f5c17SBram Moolenaar
2158c799fe20SBram Moolenaar qi = ALLOC_CLEAR_ONE(qf_info_T);
21598b6144bdSBram Moolenaar if (qi != NULL)
21602d67d307SBram Moolenaar {
21618b6144bdSBram Moolenaar qi->qf_refcount++;
21622d67d307SBram Moolenaar qi->qfl_type = qfltype;
2163ee8188fcSBram Moolenaar qi->qf_bufnr = INVALID_QFBUFNR;
21642d67d307SBram Moolenaar }
21658b6144bdSBram Moolenaar return qi;
2166d12f5c17SBram Moolenaar }
2167d12f5c17SBram Moolenaar
2168d12f5c17SBram Moolenaar /*
2169fe15b7dfSBram Moolenaar * Return the location list stack for window 'wp'.
2170fe15b7dfSBram Moolenaar * If not present, allocate a location list stack
2171d12f5c17SBram Moolenaar */
2172d12f5c17SBram Moolenaar static qf_info_T *
ll_get_or_alloc_list(win_T * wp)217305540976SBram Moolenaar ll_get_or_alloc_list(win_T *wp)
2174d12f5c17SBram Moolenaar {
2175d12f5c17SBram Moolenaar if (IS_LL_WINDOW(wp))
217600bf8cd2SBram Moolenaar // For a location list window, use the referenced location list
2177d12f5c17SBram Moolenaar return wp->w_llist_ref;
2178d12f5c17SBram Moolenaar
217900bf8cd2SBram Moolenaar // For a non-location list window, w_llist_ref should not point to a
218000bf8cd2SBram Moolenaar // location list.
2181d12f5c17SBram Moolenaar ll_free_all(&wp->w_llist_ref);
2182d12f5c17SBram Moolenaar
2183d12f5c17SBram Moolenaar if (wp->w_llist == NULL)
21842d67d307SBram Moolenaar wp->w_llist = qf_alloc_stack(QFLT_LOCATION); // new location list
2185d12f5c17SBram Moolenaar return wp->w_llist;
2186d12f5c17SBram Moolenaar }
2187d12f5c17SBram Moolenaar
2188d12f5c17SBram Moolenaar /*
218987f59b09SBram Moolenaar * Get the quickfix/location list stack to use for the specified Ex command.
219087f59b09SBram Moolenaar * For a location list command, returns the stack for the current window. If
219187f59b09SBram Moolenaar * the location list is not found, then returns NULL and prints an error
219287f59b09SBram Moolenaar * message if 'print_emsg' is TRUE.
219387f59b09SBram Moolenaar */
219487f59b09SBram Moolenaar static qf_info_T *
qf_cmd_get_stack(exarg_T * eap,int print_emsg)219587f59b09SBram Moolenaar qf_cmd_get_stack(exarg_T *eap, int print_emsg)
219687f59b09SBram Moolenaar {
219787f59b09SBram Moolenaar qf_info_T *qi = &ql_info;
219887f59b09SBram Moolenaar
219987f59b09SBram Moolenaar if (is_loclist_cmd(eap->cmdidx))
220087f59b09SBram Moolenaar {
220187f59b09SBram Moolenaar qi = GET_LOC_LIST(curwin);
220287f59b09SBram Moolenaar if (qi == NULL)
220387f59b09SBram Moolenaar {
220487f59b09SBram Moolenaar if (print_emsg)
220587f59b09SBram Moolenaar emsg(_(e_loclist));
220687f59b09SBram Moolenaar return NULL;
220787f59b09SBram Moolenaar }
220887f59b09SBram Moolenaar }
220987f59b09SBram Moolenaar
221087f59b09SBram Moolenaar return qi;
221187f59b09SBram Moolenaar }
221287f59b09SBram Moolenaar
221387f59b09SBram Moolenaar /*
221487f59b09SBram Moolenaar * Get the quickfix/location list stack to use for the specified Ex command.
221587f59b09SBram Moolenaar * For a location list command, returns the stack for the current window.
221687f59b09SBram Moolenaar * If the location list is not present, then allocates a new one.
221787f59b09SBram Moolenaar * Returns NULL if the allocation fails. For a location list command, sets
221887f59b09SBram Moolenaar * 'pwinp' to curwin.
221987f59b09SBram Moolenaar */
222087f59b09SBram Moolenaar static qf_info_T *
qf_cmd_get_or_alloc_stack(exarg_T * eap,win_T ** pwinp)222187f59b09SBram Moolenaar qf_cmd_get_or_alloc_stack(exarg_T *eap, win_T **pwinp)
222287f59b09SBram Moolenaar {
222387f59b09SBram Moolenaar qf_info_T *qi = &ql_info;
222487f59b09SBram Moolenaar
222587f59b09SBram Moolenaar if (is_loclist_cmd(eap->cmdidx))
222687f59b09SBram Moolenaar {
222787f59b09SBram Moolenaar qi = ll_get_or_alloc_list(curwin);
222887f59b09SBram Moolenaar if (qi == NULL)
222987f59b09SBram Moolenaar return NULL;
223087f59b09SBram Moolenaar *pwinp = curwin;
223187f59b09SBram Moolenaar }
223287f59b09SBram Moolenaar
223387f59b09SBram Moolenaar return qi;
223487f59b09SBram Moolenaar }
223587f59b09SBram Moolenaar
223687f59b09SBram Moolenaar /*
223709037503SBram Moolenaar * Copy location list entries from 'from_qfl' to 'to_qfl'.
2238d12f5c17SBram Moolenaar */
223909037503SBram Moolenaar static int
copy_loclist_entries(qf_list_T * from_qfl,qf_list_T * to_qfl)22400398e00aSBram Moolenaar copy_loclist_entries(qf_list_T *from_qfl, qf_list_T *to_qfl)
2241d12f5c17SBram Moolenaar {
2242d12f5c17SBram Moolenaar int i;
224309037503SBram Moolenaar qfline_T *from_qfp;
224409037503SBram Moolenaar qfline_T *prevp;
224509037503SBram Moolenaar
224609037503SBram Moolenaar // copy all the location entries in this list
2247a16123a6SBram Moolenaar FOR_ALL_QFL_ITEMS(from_qfl, from_qfp, i)
224809037503SBram Moolenaar {
22490398e00aSBram Moolenaar if (qf_add_entry(to_qfl,
225009037503SBram Moolenaar NULL,
225109037503SBram Moolenaar NULL,
225209037503SBram Moolenaar from_qfp->qf_module,
225309037503SBram Moolenaar 0,
225409037503SBram Moolenaar from_qfp->qf_text,
225509037503SBram Moolenaar from_qfp->qf_lnum,
22566864efa5Sthinca from_qfp->qf_end_lnum,
225709037503SBram Moolenaar from_qfp->qf_col,
22586864efa5Sthinca from_qfp->qf_end_col,
225909037503SBram Moolenaar from_qfp->qf_viscol,
226009037503SBram Moolenaar from_qfp->qf_pattern,
226109037503SBram Moolenaar from_qfp->qf_nr,
226209037503SBram Moolenaar 0,
226395946f12SBram Moolenaar from_qfp->qf_valid) == QF_FAIL)
226409037503SBram Moolenaar return FAIL;
226509037503SBram Moolenaar
226609037503SBram Moolenaar // qf_add_entry() will not set the qf_num field, as the
226709037503SBram Moolenaar // directory and file names are not supplied. So the qf_fnum
226809037503SBram Moolenaar // field is copied here.
226909037503SBram Moolenaar prevp = to_qfl->qf_last;
227009037503SBram Moolenaar prevp->qf_fnum = from_qfp->qf_fnum; // file number
227109037503SBram Moolenaar prevp->qf_type = from_qfp->qf_type; // error type
227209037503SBram Moolenaar if (from_qfl->qf_ptr == from_qfp)
227309037503SBram Moolenaar to_qfl->qf_ptr = prevp; // current location
227409037503SBram Moolenaar }
227509037503SBram Moolenaar
227609037503SBram Moolenaar return OK;
227709037503SBram Moolenaar }
2278d12f5c17SBram Moolenaar
2279d12f5c17SBram Moolenaar /*
228009037503SBram Moolenaar * Copy the specified location list 'from_qfl' to 'to_qfl'.
2281d12f5c17SBram Moolenaar */
228209037503SBram Moolenaar static int
copy_loclist(qf_list_T * from_qfl,qf_list_T * to_qfl)22830398e00aSBram Moolenaar copy_loclist(qf_list_T *from_qfl, qf_list_T *to_qfl)
2284d12f5c17SBram Moolenaar {
228509037503SBram Moolenaar // Some of the fields are populated by qf_add_entry()
22862d67d307SBram Moolenaar to_qfl->qfl_type = from_qfl->qfl_type;
2287d12f5c17SBram Moolenaar to_qfl->qf_nonevalid = from_qfl->qf_nonevalid;
2288d12f5c17SBram Moolenaar to_qfl->qf_count = 0;
2289d12f5c17SBram Moolenaar to_qfl->qf_index = 0;
2290d12f5c17SBram Moolenaar to_qfl->qf_start = NULL;
229183e6d7acSBram Moolenaar to_qfl->qf_last = NULL;
2292d12f5c17SBram Moolenaar to_qfl->qf_ptr = NULL;
22937fd73200SBram Moolenaar if (from_qfl->qf_title != NULL)
22947fd73200SBram Moolenaar to_qfl->qf_title = vim_strsave(from_qfl->qf_title);
22957fd73200SBram Moolenaar else
22967fd73200SBram Moolenaar to_qfl->qf_title = NULL;
22978f77c5a4SBram Moolenaar if (from_qfl->qf_ctx != NULL)
22988f77c5a4SBram Moolenaar {
22998f77c5a4SBram Moolenaar to_qfl->qf_ctx = alloc_tv();
23008f77c5a4SBram Moolenaar if (to_qfl->qf_ctx != NULL)
23018f77c5a4SBram Moolenaar copy_tv(from_qfl->qf_ctx, to_qfl->qf_ctx);
23028f77c5a4SBram Moolenaar }
23038f77c5a4SBram Moolenaar else
23048f77c5a4SBram Moolenaar to_qfl->qf_ctx = NULL;
2305d43906d2SBram Moolenaar if (from_qfl->qftf_cb.cb_name != NULL)
2306d43906d2SBram Moolenaar copy_callback(&to_qfl->qftf_cb, &from_qfl->qftf_cb);
2307858ba06dSBram Moolenaar else
2308d43906d2SBram Moolenaar to_qfl->qftf_cb.cb_name = NULL;
2309d12f5c17SBram Moolenaar
2310d12f5c17SBram Moolenaar if (from_qfl->qf_count)
23110398e00aSBram Moolenaar if (copy_loclist_entries(from_qfl, to_qfl) == FAIL)
231209037503SBram Moolenaar return FAIL;
2313d12f5c17SBram Moolenaar
231409037503SBram Moolenaar to_qfl->qf_index = from_qfl->qf_index; // current index in the list
2315d12f5c17SBram Moolenaar
231609037503SBram Moolenaar // Assign a new ID for the location list
2317a539f4f1SBram Moolenaar to_qfl->qf_id = ++last_qf_id;
2318b254af31SBram Moolenaar to_qfl->qf_changedtick = 0L;
2319a539f4f1SBram Moolenaar
232009037503SBram Moolenaar // When no valid entries are present in the list, qf_ptr points to
232109037503SBram Moolenaar // the first item in the list
2322d236ac0dSBram Moolenaar if (to_qfl->qf_nonevalid)
2323730d2c07SBram Moolenaar {
2324d12f5c17SBram Moolenaar to_qfl->qf_ptr = to_qfl->qf_start;
2325730d2c07SBram Moolenaar to_qfl->qf_index = 1;
2326730d2c07SBram Moolenaar }
232709037503SBram Moolenaar
232809037503SBram Moolenaar return OK;
2329d12f5c17SBram Moolenaar }
2330d12f5c17SBram Moolenaar
233109037503SBram Moolenaar /*
233209037503SBram Moolenaar * Copy the location list stack 'from' window to 'to' window.
233309037503SBram Moolenaar */
233409037503SBram Moolenaar void
copy_loclist_stack(win_T * from,win_T * to)233509037503SBram Moolenaar copy_loclist_stack(win_T *from, win_T *to)
233609037503SBram Moolenaar {
233709037503SBram Moolenaar qf_info_T *qi;
233809037503SBram Moolenaar int idx;
233909037503SBram Moolenaar
234009037503SBram Moolenaar // When copying from a location list window, copy the referenced
234109037503SBram Moolenaar // location list. For other windows, copy the location list for
234209037503SBram Moolenaar // that window.
234309037503SBram Moolenaar if (IS_LL_WINDOW(from))
234409037503SBram Moolenaar qi = from->w_llist_ref;
234509037503SBram Moolenaar else
234609037503SBram Moolenaar qi = from->w_llist;
234709037503SBram Moolenaar
234809037503SBram Moolenaar if (qi == NULL) // no location list to copy
234909037503SBram Moolenaar return;
235009037503SBram Moolenaar
235109037503SBram Moolenaar // allocate a new location list
23522d67d307SBram Moolenaar if ((to->w_llist = qf_alloc_stack(QFLT_LOCATION)) == NULL)
235309037503SBram Moolenaar return;
235409037503SBram Moolenaar
235509037503SBram Moolenaar to->w_llist->qf_listcount = qi->qf_listcount;
235609037503SBram Moolenaar
235709037503SBram Moolenaar // Copy the location lists one at a time
235809037503SBram Moolenaar for (idx = 0; idx < qi->qf_listcount; ++idx)
235909037503SBram Moolenaar {
236009037503SBram Moolenaar to->w_llist->qf_curlist = idx;
236109037503SBram Moolenaar
23620398e00aSBram Moolenaar if (copy_loclist(qf_get_list(qi, idx),
23630398e00aSBram Moolenaar qf_get_list(to->w_llist, idx)) == FAIL)
236409037503SBram Moolenaar {
236509037503SBram Moolenaar qf_free_all(to);
236609037503SBram Moolenaar return;
236709037503SBram Moolenaar }
236809037503SBram Moolenaar }
236909037503SBram Moolenaar
237009037503SBram Moolenaar to->w_llist->qf_curlist = qi->qf_curlist; // current list
2371d12f5c17SBram Moolenaar }
2372d12f5c17SBram Moolenaar
2373d12f5c17SBram Moolenaar /*
23747618e00dSBram Moolenaar * Get buffer number for file "directory/fname".
23752f095a4bSBram Moolenaar * Also sets the b_has_qf_entry flag.
2376071d4279SBram Moolenaar */
2377071d4279SBram Moolenaar static int
qf_get_fnum(qf_list_T * qfl,char_u * directory,char_u * fname)23780398e00aSBram Moolenaar qf_get_fnum(qf_list_T *qfl, char_u *directory, char_u *fname)
2379071d4279SBram Moolenaar {
23808240433fSBram Moolenaar char_u *ptr = NULL;
23812f095a4bSBram Moolenaar buf_T *buf;
23828240433fSBram Moolenaar char_u *bufname;
23832f095a4bSBram Moolenaar
238400bf8cd2SBram Moolenaar if (fname == NULL || *fname == NUL) // no file name
2385071d4279SBram Moolenaar return 0;
2386071d4279SBram Moolenaar
2387071d4279SBram Moolenaar #ifdef VMS
2388071d4279SBram Moolenaar vms_remove_version(fname);
2389071d4279SBram Moolenaar #endif
2390071d4279SBram Moolenaar #ifdef BACKSLASH_IN_FILENAME
2391071d4279SBram Moolenaar if (directory != NULL)
2392071d4279SBram Moolenaar slash_adjust(directory);
2393071d4279SBram Moolenaar slash_adjust(fname);
2394071d4279SBram Moolenaar #endif
2395071d4279SBram Moolenaar if (directory != NULL && !vim_isAbsName(fname)
2396071d4279SBram Moolenaar && (ptr = concat_fnames(directory, fname, TRUE)) != NULL)
2397071d4279SBram Moolenaar {
239800bf8cd2SBram Moolenaar // Here we check if the file really exists.
239900bf8cd2SBram Moolenaar // This should normally be true, but if make works without
240000bf8cd2SBram Moolenaar // "leaving directory"-messages we might have missed a
240100bf8cd2SBram Moolenaar // directory change.
2402071d4279SBram Moolenaar if (mch_getperm(ptr) < 0)
2403071d4279SBram Moolenaar {
2404071d4279SBram Moolenaar vim_free(ptr);
2405108e7b42SBram Moolenaar directory = qf_guess_filepath(qfl, fname);
2406071d4279SBram Moolenaar if (directory)
2407071d4279SBram Moolenaar ptr = concat_fnames(directory, fname, TRUE);
2408071d4279SBram Moolenaar else
2409071d4279SBram Moolenaar ptr = vim_strsave(fname);
2410071d4279SBram Moolenaar }
241100bf8cd2SBram Moolenaar // Use concatenated directory name and file name
24128240433fSBram Moolenaar bufname = ptr;
24138240433fSBram Moolenaar }
24148240433fSBram Moolenaar else
24158240433fSBram Moolenaar bufname = fname;
24168240433fSBram Moolenaar
24178240433fSBram Moolenaar if (qf_last_bufname != NULL && STRCMP(bufname, qf_last_bufname) == 0
2418b25f9a97SBram Moolenaar && bufref_valid(&qf_last_bufref))
24198240433fSBram Moolenaar {
2420b25f9a97SBram Moolenaar buf = qf_last_bufref.br_buf;
2421071d4279SBram Moolenaar vim_free(ptr);
2422071d4279SBram Moolenaar }
24232f095a4bSBram Moolenaar else
24248240433fSBram Moolenaar {
24258240433fSBram Moolenaar vim_free(qf_last_bufname);
24268240433fSBram Moolenaar buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT);
24278240433fSBram Moolenaar if (bufname == ptr)
24288240433fSBram Moolenaar qf_last_bufname = bufname;
24298240433fSBram Moolenaar else
24308240433fSBram Moolenaar qf_last_bufname = vim_strsave(bufname);
2431b25f9a97SBram Moolenaar set_bufref(&qf_last_bufref, buf);
24328240433fSBram Moolenaar }
24332f095a4bSBram Moolenaar if (buf == NULL)
24342f095a4bSBram Moolenaar return 0;
24358240433fSBram Moolenaar
2436c1542744SBram Moolenaar buf->b_has_qf_entry =
24372d67d307SBram Moolenaar IS_QF_LIST(qfl) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
24382f095a4bSBram Moolenaar return buf->b_fnum;
2439071d4279SBram Moolenaar }
2440071d4279SBram Moolenaar
2441071d4279SBram Moolenaar /*
244238df43bdSBram Moolenaar * Push dirbuf onto the directory stack and return pointer to actual dir or
244338df43bdSBram Moolenaar * NULL on error.
2444071d4279SBram Moolenaar */
2445071d4279SBram Moolenaar static char_u *
qf_push_dir(char_u * dirbuf,struct dir_stack_T ** stackptr,int is_file_stack)2446361c8f0eSBram Moolenaar qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, int is_file_stack)
2447071d4279SBram Moolenaar {
2448071d4279SBram Moolenaar struct dir_stack_T *ds_new;
2449071d4279SBram Moolenaar struct dir_stack_T *ds_ptr;
2450071d4279SBram Moolenaar
245100bf8cd2SBram Moolenaar // allocate new stack element and hook it in
2452c799fe20SBram Moolenaar ds_new = ALLOC_ONE(struct dir_stack_T);
2453071d4279SBram Moolenaar if (ds_new == NULL)
2454071d4279SBram Moolenaar return NULL;
2455071d4279SBram Moolenaar
2456071d4279SBram Moolenaar ds_new->next = *stackptr;
2457071d4279SBram Moolenaar *stackptr = ds_new;
2458071d4279SBram Moolenaar
245900bf8cd2SBram Moolenaar // store directory on the stack
2460071d4279SBram Moolenaar if (vim_isAbsName(dirbuf)
2461071d4279SBram Moolenaar || (*stackptr)->next == NULL
2462361c8f0eSBram Moolenaar || (*stackptr && is_file_stack))
2463071d4279SBram Moolenaar (*stackptr)->dirname = vim_strsave(dirbuf);
2464071d4279SBram Moolenaar else
2465071d4279SBram Moolenaar {
246600bf8cd2SBram Moolenaar // Okay we don't have an absolute path.
246700bf8cd2SBram Moolenaar // dirbuf must be a subdir of one of the directories on the stack.
246800bf8cd2SBram Moolenaar // Let's search...
2469071d4279SBram Moolenaar ds_new = (*stackptr)->next;
2470071d4279SBram Moolenaar (*stackptr)->dirname = NULL;
2471071d4279SBram Moolenaar while (ds_new)
2472071d4279SBram Moolenaar {
2473071d4279SBram Moolenaar vim_free((*stackptr)->dirname);
2474071d4279SBram Moolenaar (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf,
2475071d4279SBram Moolenaar TRUE);
2476071d4279SBram Moolenaar if (mch_isdir((*stackptr)->dirname) == TRUE)
2477071d4279SBram Moolenaar break;
2478071d4279SBram Moolenaar
2479071d4279SBram Moolenaar ds_new = ds_new->next;
2480071d4279SBram Moolenaar }
2481071d4279SBram Moolenaar
248200bf8cd2SBram Moolenaar // clean up all dirs we already left
2483071d4279SBram Moolenaar while ((*stackptr)->next != ds_new)
2484071d4279SBram Moolenaar {
2485071d4279SBram Moolenaar ds_ptr = (*stackptr)->next;
2486071d4279SBram Moolenaar (*stackptr)->next = (*stackptr)->next->next;
2487071d4279SBram Moolenaar vim_free(ds_ptr->dirname);
2488071d4279SBram Moolenaar vim_free(ds_ptr);
2489071d4279SBram Moolenaar }
2490071d4279SBram Moolenaar
249100bf8cd2SBram Moolenaar // Nothing found -> it must be on top level
2492071d4279SBram Moolenaar if (ds_new == NULL)
2493071d4279SBram Moolenaar {
2494071d4279SBram Moolenaar vim_free((*stackptr)->dirname);
2495071d4279SBram Moolenaar (*stackptr)->dirname = vim_strsave(dirbuf);
2496071d4279SBram Moolenaar }
2497071d4279SBram Moolenaar }
2498071d4279SBram Moolenaar
2499071d4279SBram Moolenaar if ((*stackptr)->dirname != NULL)
2500071d4279SBram Moolenaar return (*stackptr)->dirname;
2501071d4279SBram Moolenaar else
2502071d4279SBram Moolenaar {
2503071d4279SBram Moolenaar ds_ptr = *stackptr;
2504071d4279SBram Moolenaar *stackptr = (*stackptr)->next;
2505071d4279SBram Moolenaar vim_free(ds_ptr);
2506071d4279SBram Moolenaar return NULL;
2507071d4279SBram Moolenaar }
2508071d4279SBram Moolenaar }
2509071d4279SBram Moolenaar
2510071d4279SBram Moolenaar /*
2511071d4279SBram Moolenaar * pop dirbuf from the directory stack and return previous directory or NULL if
2512071d4279SBram Moolenaar * stack is empty
2513071d4279SBram Moolenaar */
2514071d4279SBram Moolenaar static char_u *
qf_pop_dir(struct dir_stack_T ** stackptr)251505540976SBram Moolenaar qf_pop_dir(struct dir_stack_T **stackptr)
2516071d4279SBram Moolenaar {
2517071d4279SBram Moolenaar struct dir_stack_T *ds_ptr;
2518071d4279SBram Moolenaar
251900bf8cd2SBram Moolenaar // TODO: Should we check if dirbuf is the directory on top of the stack?
252000bf8cd2SBram Moolenaar // What to do if it isn't?
2521071d4279SBram Moolenaar
252200bf8cd2SBram Moolenaar // pop top element and free it
2523071d4279SBram Moolenaar if (*stackptr != NULL)
2524071d4279SBram Moolenaar {
2525071d4279SBram Moolenaar ds_ptr = *stackptr;
2526071d4279SBram Moolenaar *stackptr = (*stackptr)->next;
2527071d4279SBram Moolenaar vim_free(ds_ptr->dirname);
2528071d4279SBram Moolenaar vim_free(ds_ptr);
2529071d4279SBram Moolenaar }
2530071d4279SBram Moolenaar
253100bf8cd2SBram Moolenaar // return NEW top element as current dir or NULL if stack is empty
2532071d4279SBram Moolenaar return *stackptr ? (*stackptr)->dirname : NULL;
2533071d4279SBram Moolenaar }
2534071d4279SBram Moolenaar
2535071d4279SBram Moolenaar /*
2536071d4279SBram Moolenaar * clean up directory stack
2537071d4279SBram Moolenaar */
2538071d4279SBram Moolenaar static void
qf_clean_dir_stack(struct dir_stack_T ** stackptr)253905540976SBram Moolenaar qf_clean_dir_stack(struct dir_stack_T **stackptr)
2540071d4279SBram Moolenaar {
2541071d4279SBram Moolenaar struct dir_stack_T *ds_ptr;
2542071d4279SBram Moolenaar
2543071d4279SBram Moolenaar while ((ds_ptr = *stackptr) != NULL)
2544071d4279SBram Moolenaar {
2545071d4279SBram Moolenaar *stackptr = (*stackptr)->next;
2546071d4279SBram Moolenaar vim_free(ds_ptr->dirname);
2547071d4279SBram Moolenaar vim_free(ds_ptr);
2548071d4279SBram Moolenaar }
2549071d4279SBram Moolenaar }
2550071d4279SBram Moolenaar
2551071d4279SBram Moolenaar /*
2552071d4279SBram Moolenaar * Check in which directory of the directory stack the given file can be
2553071d4279SBram Moolenaar * found.
2554aa23b379SBram Moolenaar * Returns a pointer to the directory name or NULL if not found.
2555071d4279SBram Moolenaar * Cleans up intermediate directory entries.
2556071d4279SBram Moolenaar *
2557071d4279SBram Moolenaar * TODO: How to solve the following problem?
25587a2b0e55SBram Moolenaar * If we have this directory tree:
2559071d4279SBram Moolenaar * ./
2560071d4279SBram Moolenaar * ./aa
2561071d4279SBram Moolenaar * ./aa/bb
2562071d4279SBram Moolenaar * ./bb
2563071d4279SBram Moolenaar * ./bb/x.c
2564071d4279SBram Moolenaar * and make says:
2565071d4279SBram Moolenaar * making all in aa
2566071d4279SBram Moolenaar * making all in bb
2567071d4279SBram Moolenaar * x.c:9: Error
2568071d4279SBram Moolenaar * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb.
2569071d4279SBram Moolenaar * qf_guess_filepath will return NULL.
2570071d4279SBram Moolenaar */
2571071d4279SBram Moolenaar static char_u *
qf_guess_filepath(qf_list_T * qfl,char_u * filename)2572fe15b7dfSBram Moolenaar qf_guess_filepath(qf_list_T *qfl, char_u *filename)
2573071d4279SBram Moolenaar {
2574071d4279SBram Moolenaar struct dir_stack_T *ds_ptr;
2575071d4279SBram Moolenaar struct dir_stack_T *ds_tmp;
2576071d4279SBram Moolenaar char_u *fullname;
2577071d4279SBram Moolenaar
257800bf8cd2SBram Moolenaar // no dirs on the stack - there's nothing we can do
2579a7df8c70SBram Moolenaar if (qfl->qf_dir_stack == NULL)
2580071d4279SBram Moolenaar return NULL;
2581071d4279SBram Moolenaar
2582a7df8c70SBram Moolenaar ds_ptr = qfl->qf_dir_stack->next;
2583071d4279SBram Moolenaar fullname = NULL;
2584071d4279SBram Moolenaar while (ds_ptr)
2585071d4279SBram Moolenaar {
2586071d4279SBram Moolenaar vim_free(fullname);
2587071d4279SBram Moolenaar fullname = concat_fnames(ds_ptr->dirname, filename, TRUE);
2588071d4279SBram Moolenaar
258900bf8cd2SBram Moolenaar // If concat_fnames failed, just go on. The worst thing that can happen
259000bf8cd2SBram Moolenaar // is that we delete the entire stack.
2591071d4279SBram Moolenaar if ((fullname != NULL) && (mch_getperm(fullname) >= 0))
2592071d4279SBram Moolenaar break;
2593071d4279SBram Moolenaar
2594071d4279SBram Moolenaar ds_ptr = ds_ptr->next;
2595071d4279SBram Moolenaar }
2596071d4279SBram Moolenaar
2597071d4279SBram Moolenaar vim_free(fullname);
2598071d4279SBram Moolenaar
259900bf8cd2SBram Moolenaar // clean up all dirs we already left
2600a7df8c70SBram Moolenaar while (qfl->qf_dir_stack->next != ds_ptr)
2601071d4279SBram Moolenaar {
2602a7df8c70SBram Moolenaar ds_tmp = qfl->qf_dir_stack->next;
2603a7df8c70SBram Moolenaar qfl->qf_dir_stack->next = qfl->qf_dir_stack->next->next;
2604071d4279SBram Moolenaar vim_free(ds_tmp->dirname);
2605071d4279SBram Moolenaar vim_free(ds_tmp);
2606071d4279SBram Moolenaar }
2607071d4279SBram Moolenaar
2608071d4279SBram Moolenaar return ds_ptr == NULL ? NULL : ds_ptr->dirname;
2609071d4279SBram Moolenaar }
2610071d4279SBram Moolenaar
2611071d4279SBram Moolenaar /*
26123c097226SBram Moolenaar * Returns TRUE if a quickfix/location list with the given identifier exists.
26133c097226SBram Moolenaar */
26143c097226SBram Moolenaar static int
qflist_valid(win_T * wp,int_u qf_id)26153c097226SBram Moolenaar qflist_valid(win_T *wp, int_u qf_id)
26163c097226SBram Moolenaar {
26173c097226SBram Moolenaar qf_info_T *qi = &ql_info;
26183c097226SBram Moolenaar int i;
26193c097226SBram Moolenaar
26203c097226SBram Moolenaar if (wp != NULL)
26213c097226SBram Moolenaar {
26222c7080bfSBram Moolenaar if (!win_valid(wp))
26232c7080bfSBram Moolenaar return FALSE;
262400bf8cd2SBram Moolenaar qi = GET_LOC_LIST(wp); // Location list
26253c097226SBram Moolenaar if (qi == NULL)
26263c097226SBram Moolenaar return FALSE;
26273c097226SBram Moolenaar }
26283c097226SBram Moolenaar
26293c097226SBram Moolenaar for (i = 0; i < qi->qf_listcount; ++i)
26303c097226SBram Moolenaar if (qi->qf_lists[i].qf_id == qf_id)
26313c097226SBram Moolenaar return TRUE;
26323c097226SBram Moolenaar
26333c097226SBram Moolenaar return FALSE;
26343c097226SBram Moolenaar }
26353c097226SBram Moolenaar
26363c097226SBram Moolenaar /*
2637ffec3c53SBram Moolenaar * When loading a file from the quickfix, the autocommands may modify it.
2638ffec3c53SBram Moolenaar * This may invalidate the current quickfix entry. This function checks
26397a2b0e55SBram Moolenaar * whether an entry is still present in the quickfix list.
2640ffec3c53SBram Moolenaar * Similar to location list.
2641ffec3c53SBram Moolenaar */
2642ffec3c53SBram Moolenaar static int
is_qf_entry_present(qf_list_T * qfl,qfline_T * qf_ptr)2643fe15b7dfSBram Moolenaar is_qf_entry_present(qf_list_T *qfl, qfline_T *qf_ptr)
2644ffec3c53SBram Moolenaar {
2645ffec3c53SBram Moolenaar qfline_T *qfp;
2646ffec3c53SBram Moolenaar int i;
2647ffec3c53SBram Moolenaar
264800bf8cd2SBram Moolenaar // Search for the entry in the current list
2649a16123a6SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
2650a16123a6SBram Moolenaar if (qfp == qf_ptr)
2651ffec3c53SBram Moolenaar break;
2652ffec3c53SBram Moolenaar
265395946f12SBram Moolenaar if (i > qfl->qf_count) // Entry is not found
2654ffec3c53SBram Moolenaar return FALSE;
2655ffec3c53SBram Moolenaar
2656ffec3c53SBram Moolenaar return TRUE;
2657ffec3c53SBram Moolenaar }
2658ffec3c53SBram Moolenaar
2659ffec3c53SBram Moolenaar /*
2660ef6b8de4SBram Moolenaar * Get the next valid entry in the current quickfix/location list. The search
26619cb03716SBram Moolenaar * starts from the current entry. Returns NULL on failure.
2662ef6b8de4SBram Moolenaar */
2663ef6b8de4SBram Moolenaar static qfline_T *
get_next_valid_entry(qf_list_T * qfl,qfline_T * qf_ptr,int * qf_index,int dir)2664ef6b8de4SBram Moolenaar get_next_valid_entry(
2665fe15b7dfSBram Moolenaar qf_list_T *qfl,
2666ef6b8de4SBram Moolenaar qfline_T *qf_ptr,
2667ef6b8de4SBram Moolenaar int *qf_index,
2668ef6b8de4SBram Moolenaar int dir)
2669ef6b8de4SBram Moolenaar {
2670ef6b8de4SBram Moolenaar int idx;
2671ef6b8de4SBram Moolenaar int old_qf_fnum;
2672ef6b8de4SBram Moolenaar
2673ef6b8de4SBram Moolenaar idx = *qf_index;
2674ef6b8de4SBram Moolenaar old_qf_fnum = qf_ptr->qf_fnum;
2675ef6b8de4SBram Moolenaar
2676ef6b8de4SBram Moolenaar do
2677ef6b8de4SBram Moolenaar {
2678fe15b7dfSBram Moolenaar if (idx == qfl->qf_count || qf_ptr->qf_next == NULL)
2679ef6b8de4SBram Moolenaar return NULL;
2680ef6b8de4SBram Moolenaar ++idx;
2681ef6b8de4SBram Moolenaar qf_ptr = qf_ptr->qf_next;
2682fe15b7dfSBram Moolenaar } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
2683ef6b8de4SBram Moolenaar || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
2684ef6b8de4SBram Moolenaar
2685ef6b8de4SBram Moolenaar *qf_index = idx;
2686ef6b8de4SBram Moolenaar return qf_ptr;
2687ef6b8de4SBram Moolenaar }
2688ef6b8de4SBram Moolenaar
2689ef6b8de4SBram Moolenaar /*
2690ef6b8de4SBram Moolenaar * Get the previous valid entry in the current quickfix/location list. The
26919cb03716SBram Moolenaar * search starts from the current entry. Returns NULL on failure.
2692ef6b8de4SBram Moolenaar */
2693ef6b8de4SBram Moolenaar static qfline_T *
get_prev_valid_entry(qf_list_T * qfl,qfline_T * qf_ptr,int * qf_index,int dir)2694ef6b8de4SBram Moolenaar get_prev_valid_entry(
2695fe15b7dfSBram Moolenaar qf_list_T *qfl,
2696ef6b8de4SBram Moolenaar qfline_T *qf_ptr,
2697ef6b8de4SBram Moolenaar int *qf_index,
2698ef6b8de4SBram Moolenaar int dir)
2699ef6b8de4SBram Moolenaar {
2700ef6b8de4SBram Moolenaar int idx;
2701ef6b8de4SBram Moolenaar int old_qf_fnum;
2702ef6b8de4SBram Moolenaar
2703ef6b8de4SBram Moolenaar idx = *qf_index;
2704ef6b8de4SBram Moolenaar old_qf_fnum = qf_ptr->qf_fnum;
2705ef6b8de4SBram Moolenaar
2706ef6b8de4SBram Moolenaar do
2707ef6b8de4SBram Moolenaar {
2708ef6b8de4SBram Moolenaar if (idx == 1 || qf_ptr->qf_prev == NULL)
2709ef6b8de4SBram Moolenaar return NULL;
2710ef6b8de4SBram Moolenaar --idx;
2711ef6b8de4SBram Moolenaar qf_ptr = qf_ptr->qf_prev;
2712fe15b7dfSBram Moolenaar } while ((!qfl->qf_nonevalid && !qf_ptr->qf_valid)
2713ef6b8de4SBram Moolenaar || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum));
2714ef6b8de4SBram Moolenaar
2715ef6b8de4SBram Moolenaar *qf_index = idx;
2716ef6b8de4SBram Moolenaar return qf_ptr;
2717ef6b8de4SBram Moolenaar }
2718ef6b8de4SBram Moolenaar
2719ef6b8de4SBram Moolenaar /*
2720ef6b8de4SBram Moolenaar * Get the n'th (errornr) previous/next valid entry from the current entry in
2721ef6b8de4SBram Moolenaar * the quickfix list.
2722ef6b8de4SBram Moolenaar * dir == FORWARD or FORWARD_FILE: next valid entry
2723ef6b8de4SBram Moolenaar * dir == BACKWARD or BACKWARD_FILE: previous valid entry
2724ef6b8de4SBram Moolenaar */
2725ef6b8de4SBram Moolenaar static qfline_T *
get_nth_valid_entry(qf_list_T * qfl,int errornr,int dir,int * new_qfidx)2726ef6b8de4SBram Moolenaar get_nth_valid_entry(
2727fe15b7dfSBram Moolenaar qf_list_T *qfl,
2728ef6b8de4SBram Moolenaar int errornr,
27296dae96efSBram Moolenaar int dir,
27306dae96efSBram Moolenaar int *new_qfidx)
2731ef6b8de4SBram Moolenaar {
27326dae96efSBram Moolenaar qfline_T *qf_ptr = qfl->qf_ptr;
27336dae96efSBram Moolenaar int qf_idx = qfl->qf_index;
2734ef6b8de4SBram Moolenaar qfline_T *prev_qf_ptr;
2735ef6b8de4SBram Moolenaar int prev_index;
2736ef6b8de4SBram Moolenaar char_u *err = e_no_more_items;
2737ef6b8de4SBram Moolenaar
2738ef6b8de4SBram Moolenaar while (errornr--)
2739ef6b8de4SBram Moolenaar {
2740ef6b8de4SBram Moolenaar prev_qf_ptr = qf_ptr;
27416dae96efSBram Moolenaar prev_index = qf_idx;
2742ef6b8de4SBram Moolenaar
2743ef6b8de4SBram Moolenaar if (dir == FORWARD || dir == FORWARD_FILE)
27446dae96efSBram Moolenaar qf_ptr = get_next_valid_entry(qfl, qf_ptr, &qf_idx, dir);
2745ef6b8de4SBram Moolenaar else
27466dae96efSBram Moolenaar qf_ptr = get_prev_valid_entry(qfl, qf_ptr, &qf_idx, dir);
2747ef6b8de4SBram Moolenaar if (qf_ptr == NULL)
2748ef6b8de4SBram Moolenaar {
2749ef6b8de4SBram Moolenaar qf_ptr = prev_qf_ptr;
27506dae96efSBram Moolenaar qf_idx = prev_index;
2751ef6b8de4SBram Moolenaar if (err != NULL)
2752ef6b8de4SBram Moolenaar {
2753f9e3e09fSBram Moolenaar emsg(_(err));
2754ef6b8de4SBram Moolenaar return NULL;
2755ef6b8de4SBram Moolenaar }
2756ef6b8de4SBram Moolenaar break;
2757ef6b8de4SBram Moolenaar }
2758ef6b8de4SBram Moolenaar
2759ef6b8de4SBram Moolenaar err = NULL;
2760ef6b8de4SBram Moolenaar }
2761ef6b8de4SBram Moolenaar
27626dae96efSBram Moolenaar *new_qfidx = qf_idx;
2763ef6b8de4SBram Moolenaar return qf_ptr;
2764ef6b8de4SBram Moolenaar }
2765ef6b8de4SBram Moolenaar
2766ef6b8de4SBram Moolenaar /*
27676dae96efSBram Moolenaar * Get n'th (errornr) quickfix entry from the current entry in the quickfix
27686dae96efSBram Moolenaar * list 'qfl'. Returns a pointer to the new entry and the index in 'new_qfidx'
2769ef6b8de4SBram Moolenaar */
2770ef6b8de4SBram Moolenaar static qfline_T *
get_nth_entry(qf_list_T * qfl,int errornr,int * new_qfidx)27716dae96efSBram Moolenaar get_nth_entry(qf_list_T *qfl, int errornr, int *new_qfidx)
2772ef6b8de4SBram Moolenaar {
27736dae96efSBram Moolenaar qfline_T *qf_ptr = qfl->qf_ptr;
27746dae96efSBram Moolenaar int qf_idx = qfl->qf_index;
2775ef6b8de4SBram Moolenaar
27766dae96efSBram Moolenaar // New error number is less than the current error number
2777ef6b8de4SBram Moolenaar while (errornr < qf_idx && qf_idx > 1 && qf_ptr->qf_prev != NULL)
2778ef6b8de4SBram Moolenaar {
2779ef6b8de4SBram Moolenaar --qf_idx;
2780ef6b8de4SBram Moolenaar qf_ptr = qf_ptr->qf_prev;
2781ef6b8de4SBram Moolenaar }
27826dae96efSBram Moolenaar // New error number is greater than the current error number
2783fe15b7dfSBram Moolenaar while (errornr > qf_idx && qf_idx < qfl->qf_count &&
2784ef6b8de4SBram Moolenaar qf_ptr->qf_next != NULL)
2785ef6b8de4SBram Moolenaar {
2786ef6b8de4SBram Moolenaar ++qf_idx;
2787ef6b8de4SBram Moolenaar qf_ptr = qf_ptr->qf_next;
2788ef6b8de4SBram Moolenaar }
2789ef6b8de4SBram Moolenaar
27906dae96efSBram Moolenaar *new_qfidx = qf_idx;
27916dae96efSBram Moolenaar return qf_ptr;
27926dae96efSBram Moolenaar }
27936dae96efSBram Moolenaar
27946dae96efSBram Moolenaar /*
27954b96df5aSBram Moolenaar * Get a entry specified by 'errornr' and 'dir' from the current
27966dae96efSBram Moolenaar * quickfix/location list. 'errornr' specifies the index of the entry and 'dir'
27976dae96efSBram Moolenaar * specifies the direction (FORWARD/BACKWARD/FORWARD_FILE/BACKWARD_FILE).
27986dae96efSBram Moolenaar * Returns a pointer to the entry and the index of the new entry is stored in
27996dae96efSBram Moolenaar * 'new_qfidx'.
28006dae96efSBram Moolenaar */
28016dae96efSBram Moolenaar static qfline_T *
qf_get_entry(qf_list_T * qfl,int errornr,int dir,int * new_qfidx)28026dae96efSBram Moolenaar qf_get_entry(
28036dae96efSBram Moolenaar qf_list_T *qfl,
28046dae96efSBram Moolenaar int errornr,
28056dae96efSBram Moolenaar int dir,
28066dae96efSBram Moolenaar int *new_qfidx)
28076dae96efSBram Moolenaar {
28086dae96efSBram Moolenaar qfline_T *qf_ptr = qfl->qf_ptr;
28096dae96efSBram Moolenaar int qfidx = qfl->qf_index;
28106dae96efSBram Moolenaar
28116dae96efSBram Moolenaar if (dir != 0) // next/prev valid entry
28126dae96efSBram Moolenaar qf_ptr = get_nth_valid_entry(qfl, errornr, dir, &qfidx);
28136dae96efSBram Moolenaar else if (errornr != 0) // go to specified number
28146dae96efSBram Moolenaar qf_ptr = get_nth_entry(qfl, errornr, &qfidx);
28156dae96efSBram Moolenaar
28166dae96efSBram Moolenaar *new_qfidx = qfidx;
2817ef6b8de4SBram Moolenaar return qf_ptr;
2818ef6b8de4SBram Moolenaar }
2819ef6b8de4SBram Moolenaar
2820ef6b8de4SBram Moolenaar /*
28217a2b0e55SBram Moolenaar * Find a window displaying a Vim help file.
28227a2b0e55SBram Moolenaar */
28237a2b0e55SBram Moolenaar static win_T *
qf_find_help_win(void)28247a2b0e55SBram Moolenaar qf_find_help_win(void)
28257a2b0e55SBram Moolenaar {
28267a2b0e55SBram Moolenaar win_T *wp;
28277a2b0e55SBram Moolenaar
28287a2b0e55SBram Moolenaar FOR_ALL_WINDOWS(wp)
28297a2b0e55SBram Moolenaar if (bt_help(wp->w_buffer))
28307a2b0e55SBram Moolenaar return wp;
28317a2b0e55SBram Moolenaar
28327a2b0e55SBram Moolenaar return NULL;
28337a2b0e55SBram Moolenaar }
28347a2b0e55SBram Moolenaar
28357a2b0e55SBram Moolenaar /*
28364aa47b28SBram Moolenaar * Set the location list for the specified window to 'qi'.
28374aa47b28SBram Moolenaar */
28384aa47b28SBram Moolenaar static void
win_set_loclist(win_T * wp,qf_info_T * qi)28394aa47b28SBram Moolenaar win_set_loclist(win_T *wp, qf_info_T *qi)
28404aa47b28SBram Moolenaar {
28414aa47b28SBram Moolenaar wp->w_llist = qi;
28424aa47b28SBram Moolenaar qi->qf_refcount++;
28434aa47b28SBram Moolenaar }
28444aa47b28SBram Moolenaar
28454aa47b28SBram Moolenaar /*
2846b244373bSBram Moolenaar * Find a help window or open one. If 'newwin' is TRUE, then open a new help
2847b244373bSBram Moolenaar * window.
2848ef6b8de4SBram Moolenaar */
2849ef6b8de4SBram Moolenaar static int
jump_to_help_window(qf_info_T * qi,int newwin,int * opened_window)2850b244373bSBram Moolenaar jump_to_help_window(qf_info_T *qi, int newwin, int *opened_window)
2851ef6b8de4SBram Moolenaar {
2852ef6b8de4SBram Moolenaar win_T *wp;
2853ef6b8de4SBram Moolenaar int flags;
2854ef6b8de4SBram Moolenaar
2855e1004401SBram Moolenaar if (cmdmod.cmod_tab != 0 || newwin)
2856ef6b8de4SBram Moolenaar wp = NULL;
2857ef6b8de4SBram Moolenaar else
28587a2b0e55SBram Moolenaar wp = qf_find_help_win();
2859ef6b8de4SBram Moolenaar if (wp != NULL && wp->w_buffer->b_nwindows > 0)
2860ef6b8de4SBram Moolenaar win_enter(wp, TRUE);
2861ef6b8de4SBram Moolenaar else
2862ef6b8de4SBram Moolenaar {
286300bf8cd2SBram Moolenaar // Split off help window; put it at far top if no position
286400bf8cd2SBram Moolenaar // specified, the current window is vertically split and narrow.
2865ef6b8de4SBram Moolenaar flags = WSP_HELP;
2866e1004401SBram Moolenaar if (cmdmod.cmod_split == 0 && curwin->w_width != Columns
2867ef6b8de4SBram Moolenaar && curwin->w_width < 80)
2868ef6b8de4SBram Moolenaar flags |= WSP_TOP;
2869b244373bSBram Moolenaar // If the user asks to open a new window, then copy the location list.
2870b244373bSBram Moolenaar // Otherwise, don't copy the location list.
2871b244373bSBram Moolenaar if (IS_LL_STACK(qi) && !newwin)
2872b244373bSBram Moolenaar flags |= WSP_NEWLOC;
2873ef6b8de4SBram Moolenaar
2874ef6b8de4SBram Moolenaar if (win_split(0, flags) == FAIL)
2875ef6b8de4SBram Moolenaar return FAIL;
2876ef6b8de4SBram Moolenaar
2877ef6b8de4SBram Moolenaar *opened_window = TRUE;
2878ef6b8de4SBram Moolenaar
2879ef6b8de4SBram Moolenaar if (curwin->w_height < p_hh)
2880ef6b8de4SBram Moolenaar win_setheight((int)p_hh);
2881ef6b8de4SBram Moolenaar
2882b244373bSBram Moolenaar // When using location list, the new window should use the supplied
2883b244373bSBram Moolenaar // location list. If the user asks to open a new window, then the new
2884b244373bSBram Moolenaar // window will get a copy of the location list.
2885b244373bSBram Moolenaar if (IS_LL_STACK(qi) && !newwin)
28864aa47b28SBram Moolenaar win_set_loclist(curwin, qi);
2887ef6b8de4SBram Moolenaar }
2888ef6b8de4SBram Moolenaar
2889ef6b8de4SBram Moolenaar if (!p_im)
289000bf8cd2SBram Moolenaar restart_edit = 0; // don't want insert mode in help file
2891ef6b8de4SBram Moolenaar
2892ef6b8de4SBram Moolenaar return OK;
2893ef6b8de4SBram Moolenaar }
2894ef6b8de4SBram Moolenaar
2895ef6b8de4SBram Moolenaar /*
2896ee8188fcSBram Moolenaar * Find a non-quickfix window in the current tabpage using the given location
2897ee8188fcSBram Moolenaar * list stack.
28987a2b0e55SBram Moolenaar * Returns NULL if a matching window is not found.
2899071d4279SBram Moolenaar */
29007a2b0e55SBram Moolenaar static win_T *
qf_find_win_with_loclist(qf_info_T * ll)29017a2b0e55SBram Moolenaar qf_find_win_with_loclist(qf_info_T *ll)
2902071d4279SBram Moolenaar {
29037a2b0e55SBram Moolenaar win_T *wp;
2904071d4279SBram Moolenaar
29057a2b0e55SBram Moolenaar FOR_ALL_WINDOWS(wp)
29067a2b0e55SBram Moolenaar if (wp->w_llist == ll && !bt_quickfix(wp->w_buffer))
29077a2b0e55SBram Moolenaar return wp;
290824862855SBram Moolenaar
29097a2b0e55SBram Moolenaar return NULL;
291024862855SBram Moolenaar }
2911d12f5c17SBram Moolenaar
2912071d4279SBram Moolenaar /*
29137a2b0e55SBram Moolenaar * Find a window containing a normal buffer
2914071d4279SBram Moolenaar */
29157a2b0e55SBram Moolenaar static win_T *
qf_find_win_with_normal_buf(void)29167a2b0e55SBram Moolenaar qf_find_win_with_normal_buf(void)
29177a2b0e55SBram Moolenaar {
29187a2b0e55SBram Moolenaar win_T *wp;
29197a2b0e55SBram Moolenaar
29207a2b0e55SBram Moolenaar FOR_ALL_WINDOWS(wp)
292191335e5aSBram Moolenaar if (bt_normal(wp->w_buffer))
29227a2b0e55SBram Moolenaar return wp;
29237a2b0e55SBram Moolenaar
29247a2b0e55SBram Moolenaar return NULL;
29257a2b0e55SBram Moolenaar }
29267a2b0e55SBram Moolenaar
29277a2b0e55SBram Moolenaar /*
29287a2b0e55SBram Moolenaar * Go to a window in any tabpage containing the specified file. Returns TRUE
29297a2b0e55SBram Moolenaar * if successfully jumped to the window. Otherwise returns FALSE.
29307a2b0e55SBram Moolenaar */
29317a2b0e55SBram Moolenaar static int
qf_goto_tabwin_with_file(int fnum)29327a2b0e55SBram Moolenaar qf_goto_tabwin_with_file(int fnum)
293338c0a6e6SBram Moolenaar {
293438c0a6e6SBram Moolenaar tabpage_T *tp;
293538c0a6e6SBram Moolenaar win_T *wp;
293638c0a6e6SBram Moolenaar
293738c0a6e6SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, wp)
29387a2b0e55SBram Moolenaar if (wp->w_buffer->b_fnum == fnum)
293938c0a6e6SBram Moolenaar {
294038c0a6e6SBram Moolenaar goto_tabpage_win(tp, wp);
29417a2b0e55SBram Moolenaar return TRUE;
294238c0a6e6SBram Moolenaar }
29437a2b0e55SBram Moolenaar
29447a2b0e55SBram Moolenaar return FALSE;
294538c0a6e6SBram Moolenaar }
294638c0a6e6SBram Moolenaar
294738c0a6e6SBram Moolenaar /*
29487a2b0e55SBram Moolenaar * Create a new window to show a file above the quickfix window. Called when
29497a2b0e55SBram Moolenaar * only the quickfix window is present.
295038c0a6e6SBram Moolenaar */
29517a2b0e55SBram Moolenaar static int
qf_open_new_file_win(qf_info_T * ll_ref)29527a2b0e55SBram Moolenaar qf_open_new_file_win(qf_info_T *ll_ref)
2953071d4279SBram Moolenaar {
29547a2b0e55SBram Moolenaar int flags;
29557a2b0e55SBram Moolenaar
2956884ae644SBram Moolenaar flags = WSP_ABOVE;
2957884ae644SBram Moolenaar if (ll_ref != NULL)
2958884ae644SBram Moolenaar flags |= WSP_NEWLOC;
2959884ae644SBram Moolenaar if (win_split(0, flags) == FAIL)
296000bf8cd2SBram Moolenaar return FAIL; // not enough room for window
296100bf8cd2SBram Moolenaar p_swb = empty_option; // don't split again
2962446cb837SBram Moolenaar swb_flags = 0;
29633368ea21SBram Moolenaar RESET_BINDING(curwin);
2964d12f5c17SBram Moolenaar if (ll_ref != NULL)
296500bf8cd2SBram Moolenaar // The new window should use the location list from the
296600bf8cd2SBram Moolenaar // location list window
29674aa47b28SBram Moolenaar win_set_loclist(curwin, ll_ref);
29687a2b0e55SBram Moolenaar return OK;
2969071d4279SBram Moolenaar }
29707a2b0e55SBram Moolenaar
29717a2b0e55SBram Moolenaar /*
29727a2b0e55SBram Moolenaar * Go to a window that shows the right buffer. If the window is not found, go
29737a2b0e55SBram Moolenaar * to the window just above the location list window. This is used for opening
29747a2b0e55SBram Moolenaar * a file from a location window and not from a quickfix window. If some usable
29757a2b0e55SBram Moolenaar * window is previously found, then it is supplied in 'use_win'.
29767a2b0e55SBram Moolenaar */
29777a2b0e55SBram Moolenaar static void
qf_goto_win_with_ll_file(win_T * use_win,int qf_fnum,qf_info_T * ll_ref)29787a2b0e55SBram Moolenaar qf_goto_win_with_ll_file(win_T *use_win, int qf_fnum, qf_info_T *ll_ref)
2979071d4279SBram Moolenaar {
29807a2b0e55SBram Moolenaar win_T *win = use_win;
29817a2b0e55SBram Moolenaar
2982d12f5c17SBram Moolenaar if (win == NULL)
2983d12f5c17SBram Moolenaar {
298400bf8cd2SBram Moolenaar // Find the window showing the selected file
2985d12f5c17SBram Moolenaar FOR_ALL_WINDOWS(win)
29869cb03716SBram Moolenaar if (win->w_buffer->b_fnum == qf_fnum)
2987d12f5c17SBram Moolenaar break;
2988d12f5c17SBram Moolenaar if (win == NULL)
2989d12f5c17SBram Moolenaar {
299000bf8cd2SBram Moolenaar // Find a previous usable window
2991d12f5c17SBram Moolenaar win = curwin;
2992d12f5c17SBram Moolenaar do
2993d12f5c17SBram Moolenaar {
299491335e5aSBram Moolenaar if (bt_normal(win->w_buffer))
2995d12f5c17SBram Moolenaar break;
2996d12f5c17SBram Moolenaar if (win->w_prev == NULL)
299700bf8cd2SBram Moolenaar win = lastwin; // wrap around the top
2998d12f5c17SBram Moolenaar else
299900bf8cd2SBram Moolenaar win = win->w_prev; // go to previous window
3000d12f5c17SBram Moolenaar } while (win != curwin);
3001d12f5c17SBram Moolenaar }
3002d12f5c17SBram Moolenaar }
3003d12f5c17SBram Moolenaar win_goto(win);
3004d12f5c17SBram Moolenaar
300500bf8cd2SBram Moolenaar // If the location list for the window is not set, then set it
300600bf8cd2SBram Moolenaar // to the location list from the location window
30070398e00aSBram Moolenaar if (win->w_llist == NULL && ll_ref != NULL)
30084aa47b28SBram Moolenaar win_set_loclist(win, ll_ref);
3009d12f5c17SBram Moolenaar }
3010d12f5c17SBram Moolenaar
3011071d4279SBram Moolenaar /*
3012fe15b7dfSBram Moolenaar * Go to a window that contains the specified buffer 'qf_fnum'. If a window is
3013fe15b7dfSBram Moolenaar * not found, then go to the window just above the quickfix window. This is
3014fe15b7dfSBram Moolenaar * used for opening a file from a quickfix window and not from a location
3015fe15b7dfSBram Moolenaar * window.
3016071d4279SBram Moolenaar */
30177a2b0e55SBram Moolenaar static void
qf_goto_win_with_qfl_file(int qf_fnum)30187a2b0e55SBram Moolenaar qf_goto_win_with_qfl_file(int qf_fnum)
30197a2b0e55SBram Moolenaar {
30207a2b0e55SBram Moolenaar win_T *win;
30217a2b0e55SBram Moolenaar win_T *altwin;
30227a2b0e55SBram Moolenaar
3023071d4279SBram Moolenaar win = curwin;
3024071d4279SBram Moolenaar altwin = NULL;
3025071d4279SBram Moolenaar for (;;)
3026071d4279SBram Moolenaar {
30279cb03716SBram Moolenaar if (win->w_buffer->b_fnum == qf_fnum)
3028071d4279SBram Moolenaar break;
3029071d4279SBram Moolenaar if (win->w_prev == NULL)
303000bf8cd2SBram Moolenaar win = lastwin; // wrap around the top
3031071d4279SBram Moolenaar else
303200bf8cd2SBram Moolenaar win = win->w_prev; // go to previous window
3033071d4279SBram Moolenaar
3034d12f5c17SBram Moolenaar if (IS_QF_WINDOW(win))
3035071d4279SBram Moolenaar {
303600bf8cd2SBram Moolenaar // Didn't find it, go to the window before the quickfix
3037539aa6b2SBram Moolenaar // window, unless 'switchbuf' contains 'uselast': in this case we
3038539aa6b2SBram Moolenaar // try to jump to the previously used window first.
3039539aa6b2SBram Moolenaar if ((swb_flags & SWB_USELAST) && win_valid(prevwin))
3040539aa6b2SBram Moolenaar win = prevwin;
3041539aa6b2SBram Moolenaar else if (altwin != NULL)
3042071d4279SBram Moolenaar win = altwin;
3043071d4279SBram Moolenaar else if (curwin->w_prev != NULL)
3044071d4279SBram Moolenaar win = curwin->w_prev;
3045071d4279SBram Moolenaar else
3046071d4279SBram Moolenaar win = curwin->w_next;
3047071d4279SBram Moolenaar break;
3048071d4279SBram Moolenaar }
3049071d4279SBram Moolenaar
305000bf8cd2SBram Moolenaar // Remember a usable window.
305191335e5aSBram Moolenaar if (altwin == NULL && !win->w_p_pvw && bt_normal(win->w_buffer))
3052071d4279SBram Moolenaar altwin = win;
3053071d4279SBram Moolenaar }
3054071d4279SBram Moolenaar
3055071d4279SBram Moolenaar win_goto(win);
3056071d4279SBram Moolenaar }
30577a2b0e55SBram Moolenaar
30587a2b0e55SBram Moolenaar /*
30597a2b0e55SBram Moolenaar * Find a suitable window for opening a file (qf_fnum) from the
30607a2b0e55SBram Moolenaar * quickfix/location list and jump to it. If the file is already opened in a
3061b244373bSBram Moolenaar * window, jump to it. Otherwise open a new window to display the file. If
3062b244373bSBram Moolenaar * 'newwin' is TRUE, then always open a new window. This is called from either
3063b244373bSBram Moolenaar * a quickfix or a location list window.
30647a2b0e55SBram Moolenaar */
30657a2b0e55SBram Moolenaar static int
qf_jump_to_usable_window(int qf_fnum,int newwin,int * opened_window)3066b244373bSBram Moolenaar qf_jump_to_usable_window(int qf_fnum, int newwin, int *opened_window)
30677a2b0e55SBram Moolenaar {
3068f9ae154cSBram Moolenaar win_T *usable_wp = NULL;
3069f9ae154cSBram Moolenaar int usable_win = FALSE;
3070b244373bSBram Moolenaar qf_info_T *ll_ref = NULL;
30717a2b0e55SBram Moolenaar
3072b244373bSBram Moolenaar // If opening a new window, then don't use the location list referred by
3073b244373bSBram Moolenaar // the current window. Otherwise two windows will refer to the same
3074b244373bSBram Moolenaar // location list.
3075b244373bSBram Moolenaar if (!newwin)
30767a2b0e55SBram Moolenaar ll_ref = curwin->w_llist_ref;
3077b244373bSBram Moolenaar
30787a2b0e55SBram Moolenaar if (ll_ref != NULL)
30797a2b0e55SBram Moolenaar {
308000bf8cd2SBram Moolenaar // Find a non-quickfix window with this location list
3081f9ae154cSBram Moolenaar usable_wp = qf_find_win_with_loclist(ll_ref);
3082f9ae154cSBram Moolenaar if (usable_wp != NULL)
3083f9ae154cSBram Moolenaar usable_win = TRUE;
30847a2b0e55SBram Moolenaar }
30857a2b0e55SBram Moolenaar
30867a2b0e55SBram Moolenaar if (!usable_win)
30877a2b0e55SBram Moolenaar {
308800bf8cd2SBram Moolenaar // Locate a window showing a normal buffer
3089f9ae154cSBram Moolenaar win_T *win = qf_find_win_with_normal_buf();
30907a2b0e55SBram Moolenaar if (win != NULL)
3091f9ae154cSBram Moolenaar usable_win = TRUE;
30927a2b0e55SBram Moolenaar }
30937a2b0e55SBram Moolenaar
309400bf8cd2SBram Moolenaar // If no usable window is found and 'switchbuf' contains "usetab"
309500bf8cd2SBram Moolenaar // then search in other tabs.
30967a2b0e55SBram Moolenaar if (!usable_win && (swb_flags & SWB_USETAB))
30977a2b0e55SBram Moolenaar usable_win = qf_goto_tabwin_with_file(qf_fnum);
30987a2b0e55SBram Moolenaar
309900bf8cd2SBram Moolenaar // If there is only one window and it is the quickfix window, create a
310000bf8cd2SBram Moolenaar // new one above the quickfix window.
3101b244373bSBram Moolenaar if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win || newwin)
31027a2b0e55SBram Moolenaar {
31037a2b0e55SBram Moolenaar if (qf_open_new_file_win(ll_ref) != OK)
31047a2b0e55SBram Moolenaar return FAIL;
310500bf8cd2SBram Moolenaar *opened_window = TRUE; // close it when fail
31067a2b0e55SBram Moolenaar }
31077a2b0e55SBram Moolenaar else
31087a2b0e55SBram Moolenaar {
310900bf8cd2SBram Moolenaar if (curwin->w_llist_ref != NULL) // In a location window
3110f9ae154cSBram Moolenaar qf_goto_win_with_ll_file(usable_wp, qf_fnum, ll_ref);
311100bf8cd2SBram Moolenaar else // In a quickfix window
31127a2b0e55SBram Moolenaar qf_goto_win_with_qfl_file(qf_fnum);
3113071d4279SBram Moolenaar }
31149cb03716SBram Moolenaar
31159cb03716SBram Moolenaar return OK;
3116d12f5c17SBram Moolenaar }
3117071d4279SBram Moolenaar
3118071d4279SBram Moolenaar /*
31199cb03716SBram Moolenaar * Edit the selected file or help file.
31206dae96efSBram Moolenaar * Returns OK if successfully edited the file, FAIL on failing to open the
31216dae96efSBram Moolenaar * buffer and NOTDONE if the quickfix/location list was freed by an autocmd
31226dae96efSBram Moolenaar * when opening the buffer.
3123071d4279SBram Moolenaar */
31249cb03716SBram Moolenaar static int
qf_jump_edit_buffer(qf_info_T * qi,qfline_T * qf_ptr,int forceit,int prev_winid,int * opened_window)31259cb03716SBram Moolenaar qf_jump_edit_buffer(
31269cb03716SBram Moolenaar qf_info_T *qi,
31279cb03716SBram Moolenaar qfline_T *qf_ptr,
31289cb03716SBram Moolenaar int forceit,
3129eeb1b9c7SBram Moolenaar int prev_winid,
31306dae96efSBram Moolenaar int *opened_window)
313169a7cb47SBram Moolenaar {
31324aa47b28SBram Moolenaar qf_list_T *qfl = qf_get_curlist(qi);
31334d170af0SBram Moolenaar int old_changedtick = qfl->qf_changedtick;
31342d67d307SBram Moolenaar qfltype_T qfl_type = qfl->qfl_type;
31359cb03716SBram Moolenaar int retval = OK;
3136b6f1480aSBram Moolenaar int old_qf_curlist = qi->qf_curlist;
3137b6f1480aSBram Moolenaar int save_qfid = qfl->qf_id;
31389cb03716SBram Moolenaar
313969a7cb47SBram Moolenaar if (qf_ptr->qf_type == 1)
314069a7cb47SBram Moolenaar {
314100bf8cd2SBram Moolenaar // Open help file (do_ecmd() will set b_help flag, readfile() will
314200bf8cd2SBram Moolenaar // set b_p_ro flag).
314369a7cb47SBram Moolenaar if (!can_abandon(curbuf, forceit))
314469a7cb47SBram Moolenaar {
3145f5be7cd0SBram Moolenaar no_write_message();
3146b6f1480aSBram Moolenaar return FAIL;
314769a7cb47SBram Moolenaar }
3148b6f1480aSBram Moolenaar
31499cb03716SBram Moolenaar retval = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1,
3150701f7afcSBram Moolenaar ECMD_HIDE + ECMD_SET_HELP,
3151eeb1b9c7SBram Moolenaar prev_winid == curwin->w_id ? curwin : NULL);
315269a7cb47SBram Moolenaar }
315369a7cb47SBram Moolenaar else
31549cb03716SBram Moolenaar retval = buflist_getfile(qf_ptr->qf_fnum,
315569a7cb47SBram Moolenaar (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit);
31563c097226SBram Moolenaar
3157b6f1480aSBram Moolenaar // If a location list, check whether the associated window is still
3158b6f1480aSBram Moolenaar // present.
3159eeb1b9c7SBram Moolenaar if (qfl_type == QFLT_LOCATION)
3160eeb1b9c7SBram Moolenaar {
3161eeb1b9c7SBram Moolenaar win_T *wp = win_id2wp(prev_winid);
3162eeb1b9c7SBram Moolenaar if (wp == NULL && curwin->w_llist != qi)
31630899d698SBram Moolenaar {
3164f9e3e09fSBram Moolenaar emsg(_("E924: Current window was closed"));
31659cb03716SBram Moolenaar *opened_window = FALSE;
31666dae96efSBram Moolenaar return NOTDONE;
3167ffec3c53SBram Moolenaar }
3168eeb1b9c7SBram Moolenaar }
3169b6f1480aSBram Moolenaar
31702d67d307SBram Moolenaar if (qfl_type == QFLT_QUICKFIX && !qflist_valid(NULL, save_qfid))
31713c097226SBram Moolenaar {
31724d170af0SBram Moolenaar emsg(_(e_current_quickfix_list_was_changed));
31736dae96efSBram Moolenaar return NOTDONE;
31743c097226SBram Moolenaar }
3175b6f1480aSBram Moolenaar
31764d170af0SBram Moolenaar // Check if the list was changed. The pointers may happen to be identical,
31774d170af0SBram Moolenaar // thus also check qf_changedtick.
3178b6f1480aSBram Moolenaar if (old_qf_curlist != qi->qf_curlist
31794d170af0SBram Moolenaar || old_changedtick != qfl->qf_changedtick
3180fe15b7dfSBram Moolenaar || !is_qf_entry_present(qfl, qf_ptr))
3181ffec3c53SBram Moolenaar {
31822d67d307SBram Moolenaar if (qfl_type == QFLT_QUICKFIX)
31834d170af0SBram Moolenaar emsg(_(e_current_quickfix_list_was_changed));
3184ffec3c53SBram Moolenaar else
31854d170af0SBram Moolenaar emsg(_(e_current_location_list_was_changed));
31866dae96efSBram Moolenaar return NOTDONE;
3187ffec3c53SBram Moolenaar }
31889cb03716SBram Moolenaar
31899cb03716SBram Moolenaar return retval;
31909cb03716SBram Moolenaar }
31919cb03716SBram Moolenaar
31929cb03716SBram Moolenaar /*
31937a2b0e55SBram Moolenaar * Go to the error line in the current file using either line/column number or
31947a2b0e55SBram Moolenaar * a search pattern.
31959cb03716SBram Moolenaar */
31969cb03716SBram Moolenaar static void
qf_jump_goto_line(linenr_T qf_lnum,int qf_col,char_u qf_viscol,char_u * qf_pattern)31979cb03716SBram Moolenaar qf_jump_goto_line(
31989cb03716SBram Moolenaar linenr_T qf_lnum,
31999cb03716SBram Moolenaar int qf_col,
32009cb03716SBram Moolenaar char_u qf_viscol,
32019cb03716SBram Moolenaar char_u *qf_pattern)
3202ffec3c53SBram Moolenaar {
32039cb03716SBram Moolenaar linenr_T i;
320469a7cb47SBram Moolenaar
32059cb03716SBram Moolenaar if (qf_pattern == NULL)
320668b76a69SBram Moolenaar {
320700bf8cd2SBram Moolenaar // Go to line with error, unless qf_lnum is 0.
32089cb03716SBram Moolenaar i = qf_lnum;
3209071d4279SBram Moolenaar if (i > 0)
3210071d4279SBram Moolenaar {
3211071d4279SBram Moolenaar if (i > curbuf->b_ml.ml_line_count)
3212071d4279SBram Moolenaar i = curbuf->b_ml.ml_line_count;
3213071d4279SBram Moolenaar curwin->w_cursor.lnum = i;
3214071d4279SBram Moolenaar }
32159cb03716SBram Moolenaar if (qf_col > 0)
3216071d4279SBram Moolenaar {
3217b8c89003SBram Moolenaar curwin->w_cursor.coladd = 0;
32189cb03716SBram Moolenaar if (qf_viscol == TRUE)
3219c45eb770SBram Moolenaar coladvance(qf_col - 1);
3220071d4279SBram Moolenaar else
3221c45eb770SBram Moolenaar curwin->w_cursor.col = qf_col - 1;
32222dfcef4cSBram Moolenaar curwin->w_set_curswant = TRUE;
3223071d4279SBram Moolenaar check_cursor();
3224071d4279SBram Moolenaar }
3225071d4279SBram Moolenaar else
3226071d4279SBram Moolenaar beginline(BL_WHITE | BL_FIX);
322768b76a69SBram Moolenaar }
322868b76a69SBram Moolenaar else
322968b76a69SBram Moolenaar {
323068b76a69SBram Moolenaar pos_T save_cursor;
323168b76a69SBram Moolenaar
323200bf8cd2SBram Moolenaar // Move the cursor to the first line in the buffer
323368b76a69SBram Moolenaar save_cursor = curwin->w_cursor;
323468b76a69SBram Moolenaar curwin->w_cursor.lnum = 0;
3235c036e87bSBram Moolenaar if (!do_search(NULL, '/', '/', qf_pattern, (long)1, SEARCH_KEEP, NULL))
323668b76a69SBram Moolenaar curwin->w_cursor = save_cursor;
323768b76a69SBram Moolenaar }
32389cb03716SBram Moolenaar }
3239071d4279SBram Moolenaar
32409cb03716SBram Moolenaar /*
32419cb03716SBram Moolenaar * Display quickfix list index and size message
32429cb03716SBram Moolenaar */
32439cb03716SBram Moolenaar static void
qf_jump_print_msg(qf_info_T * qi,int qf_index,qfline_T * qf_ptr,buf_T * old_curbuf,linenr_T old_lnum)32449cb03716SBram Moolenaar qf_jump_print_msg(
32459cb03716SBram Moolenaar qf_info_T *qi,
32469cb03716SBram Moolenaar int qf_index,
32479cb03716SBram Moolenaar qfline_T *qf_ptr,
32489cb03716SBram Moolenaar buf_T *old_curbuf,
32499cb03716SBram Moolenaar linenr_T old_lnum)
3250071d4279SBram Moolenaar {
32519cb03716SBram Moolenaar linenr_T i;
32529cb03716SBram Moolenaar int len;
32539cb03716SBram Moolenaar
325400bf8cd2SBram Moolenaar // Update the screen before showing the message, unless the screen
325500bf8cd2SBram Moolenaar // scrolled up.
32568f55d103SBram Moolenaar if (!msg_scrolled)
3257071d4279SBram Moolenaar update_topline_redraw();
3258071d4279SBram Moolenaar sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index,
32594aa47b28SBram Moolenaar qf_get_curlist(qi)->qf_count,
3260071d4279SBram Moolenaar qf_ptr->qf_cleared ? _(" (line deleted)") : "",
3261071d4279SBram Moolenaar (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr));
326200bf8cd2SBram Moolenaar // Add the message, skipping leading whitespace and newlines.
3263071d4279SBram Moolenaar len = (int)STRLEN(IObuff);
3264071d4279SBram Moolenaar qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len);
3265071d4279SBram Moolenaar
326600bf8cd2SBram Moolenaar // Output the message. Overwrite to avoid scrolling when the 'O'
326700bf8cd2SBram Moolenaar // flag is present in 'shortmess'; But when not jumping, print the
326800bf8cd2SBram Moolenaar // whole message.
3269071d4279SBram Moolenaar i = msg_scroll;
3270071d4279SBram Moolenaar if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum)
3271071d4279SBram Moolenaar msg_scroll = TRUE;
3272071d4279SBram Moolenaar else if (!msg_scrolled && shortmess(SHM_OVERALL))
3273071d4279SBram Moolenaar msg_scroll = FALSE;
327432526b3cSBram Moolenaar msg_attr_keep((char *)IObuff, 0, TRUE);
3275071d4279SBram Moolenaar msg_scroll = i;
3276071d4279SBram Moolenaar }
32779cb03716SBram Moolenaar
32789cb03716SBram Moolenaar /*
32796dae96efSBram Moolenaar * Find a usable window for opening a file from the quickfix/location list. If
3280b244373bSBram Moolenaar * a window is not found then open a new window. If 'newwin' is TRUE, then open
3281b244373bSBram Moolenaar * a new window.
32826dae96efSBram Moolenaar * Returns OK if successfully jumped or opened a window. Returns FAIL if not
32836dae96efSBram Moolenaar * able to jump/open a window. Returns NOTDONE if a file is not associated
32846dae96efSBram Moolenaar * with the entry.
32856dae96efSBram Moolenaar */
32866dae96efSBram Moolenaar static int
qf_jump_open_window(qf_info_T * qi,qfline_T * qf_ptr,int newwin,int * opened_window)3287b244373bSBram Moolenaar qf_jump_open_window(
3288b244373bSBram Moolenaar qf_info_T *qi,
3289b244373bSBram Moolenaar qfline_T *qf_ptr,
3290b244373bSBram Moolenaar int newwin,
3291b244373bSBram Moolenaar int *opened_window)
32926dae96efSBram Moolenaar {
32934d170af0SBram Moolenaar qf_list_T *qfl = qf_get_curlist(qi);
32944d170af0SBram Moolenaar int old_changedtick = qfl->qf_changedtick;
32954d170af0SBram Moolenaar int old_qf_curlist = qi->qf_curlist;
32964d170af0SBram Moolenaar qfltype_T qfl_type = qfl->qfl_type;
32974d170af0SBram Moolenaar
32986dae96efSBram Moolenaar // For ":helpgrep" find a help window or open one.
3299e1004401SBram Moolenaar if (qf_ptr->qf_type == 1 && (!bt_help(curwin->w_buffer)
3300e1004401SBram Moolenaar || cmdmod.cmod_tab != 0))
3301b244373bSBram Moolenaar if (jump_to_help_window(qi, newwin, opened_window) == FAIL)
33026dae96efSBram Moolenaar return FAIL;
33034d170af0SBram Moolenaar if (old_qf_curlist != qi->qf_curlist
33044d170af0SBram Moolenaar || old_changedtick != qfl->qf_changedtick
33054d170af0SBram Moolenaar || !is_qf_entry_present(qfl, qf_ptr))
33064d170af0SBram Moolenaar {
33074d170af0SBram Moolenaar if (qfl_type == QFLT_QUICKFIX)
33084d170af0SBram Moolenaar emsg(_(e_current_quickfix_list_was_changed));
33094d170af0SBram Moolenaar else
33104d170af0SBram Moolenaar emsg(_(e_current_location_list_was_changed));
33114d170af0SBram Moolenaar return FAIL;
33124d170af0SBram Moolenaar }
33136dae96efSBram Moolenaar
33146dae96efSBram Moolenaar // If currently in the quickfix window, find another window to show the
33156dae96efSBram Moolenaar // file in.
33166dae96efSBram Moolenaar if (bt_quickfix(curbuf) && !*opened_window)
33176dae96efSBram Moolenaar {
33186dae96efSBram Moolenaar // If there is no file specified, we don't know where to go.
33196dae96efSBram Moolenaar // But do advance, otherwise ":cn" gets stuck.
33206dae96efSBram Moolenaar if (qf_ptr->qf_fnum == 0)
33216dae96efSBram Moolenaar return NOTDONE;
33226dae96efSBram Moolenaar
3323b244373bSBram Moolenaar if (qf_jump_to_usable_window(qf_ptr->qf_fnum, newwin,
3324b244373bSBram Moolenaar opened_window) == FAIL)
33256dae96efSBram Moolenaar return FAIL;
33266dae96efSBram Moolenaar }
33274d170af0SBram Moolenaar if (old_qf_curlist != qi->qf_curlist
33284d170af0SBram Moolenaar || old_changedtick != qfl->qf_changedtick
33294d170af0SBram Moolenaar || !is_qf_entry_present(qfl, qf_ptr))
33304d170af0SBram Moolenaar {
33314d170af0SBram Moolenaar if (qfl_type == QFLT_QUICKFIX)
33324d170af0SBram Moolenaar emsg(_(e_current_quickfix_list_was_changed));
33334d170af0SBram Moolenaar else
33344d170af0SBram Moolenaar emsg(_(e_current_location_list_was_changed));
33354d170af0SBram Moolenaar return FAIL;
33364d170af0SBram Moolenaar }
33376dae96efSBram Moolenaar
33386dae96efSBram Moolenaar return OK;
33396dae96efSBram Moolenaar }
33406dae96efSBram Moolenaar
33416dae96efSBram Moolenaar /*
33426dae96efSBram Moolenaar * Edit a selected file from the quickfix/location list and jump to a
33436dae96efSBram Moolenaar * particular line/column, adjust the folds and display a message about the
33446dae96efSBram Moolenaar * jump.
33456dae96efSBram Moolenaar * Returns OK on success and FAIL on failing to open the file/buffer. Returns
33466dae96efSBram Moolenaar * NOTDONE if the quickfix/location list is freed by an autocmd when opening
33476dae96efSBram Moolenaar * the file.
33486dae96efSBram Moolenaar */
33496dae96efSBram Moolenaar static int
qf_jump_to_buffer(qf_info_T * qi,int qf_index,qfline_T * qf_ptr,int forceit,int prev_winid,int * opened_window,int openfold,int print_message)33506dae96efSBram Moolenaar qf_jump_to_buffer(
33516dae96efSBram Moolenaar qf_info_T *qi,
33526dae96efSBram Moolenaar int qf_index,
33536dae96efSBram Moolenaar qfline_T *qf_ptr,
33546dae96efSBram Moolenaar int forceit,
3355eeb1b9c7SBram Moolenaar int prev_winid,
33566dae96efSBram Moolenaar int *opened_window,
33576dae96efSBram Moolenaar int openfold,
33586dae96efSBram Moolenaar int print_message)
33596dae96efSBram Moolenaar {
33606dae96efSBram Moolenaar buf_T *old_curbuf;
33616dae96efSBram Moolenaar linenr_T old_lnum;
33626dae96efSBram Moolenaar int retval = OK;
33636dae96efSBram Moolenaar
33646dae96efSBram Moolenaar // If there is a file name, read the wanted file if needed, and check
33656dae96efSBram Moolenaar // autowrite etc.
33666dae96efSBram Moolenaar old_curbuf = curbuf;
33676dae96efSBram Moolenaar old_lnum = curwin->w_cursor.lnum;
33686dae96efSBram Moolenaar
33696dae96efSBram Moolenaar if (qf_ptr->qf_fnum != 0)
33706dae96efSBram Moolenaar {
3371eeb1b9c7SBram Moolenaar retval = qf_jump_edit_buffer(qi, qf_ptr, forceit, prev_winid,
33726dae96efSBram Moolenaar opened_window);
33736dae96efSBram Moolenaar if (retval != OK)
33746dae96efSBram Moolenaar return retval;
33756dae96efSBram Moolenaar }
33766dae96efSBram Moolenaar
33776dae96efSBram Moolenaar // When not switched to another buffer, still need to set pc mark
33786dae96efSBram Moolenaar if (curbuf == old_curbuf)
33796dae96efSBram Moolenaar setpcmark();
33806dae96efSBram Moolenaar
33816dae96efSBram Moolenaar qf_jump_goto_line(qf_ptr->qf_lnum, qf_ptr->qf_col, qf_ptr->qf_viscol,
33826dae96efSBram Moolenaar qf_ptr->qf_pattern);
33836dae96efSBram Moolenaar
33846dae96efSBram Moolenaar #ifdef FEAT_FOLDING
33856dae96efSBram Moolenaar if ((fdo_flags & FDO_QUICKFIX) && openfold)
33866dae96efSBram Moolenaar foldOpenCursor();
33876dae96efSBram Moolenaar #endif
33886dae96efSBram Moolenaar if (print_message)
33896dae96efSBram Moolenaar qf_jump_print_msg(qi, qf_index, qf_ptr, old_curbuf, old_lnum);
33906dae96efSBram Moolenaar
33916dae96efSBram Moolenaar return retval;
33926dae96efSBram Moolenaar }
33936dae96efSBram Moolenaar
33946dae96efSBram Moolenaar /*
33955b69c22fSBram Moolenaar * Jump to a quickfix line and try to use an existing window.
33969cb03716SBram Moolenaar */
33979cb03716SBram Moolenaar void
qf_jump(qf_info_T * qi,int dir,int errornr,int forceit)33989cb03716SBram Moolenaar qf_jump(qf_info_T *qi,
33999cb03716SBram Moolenaar int dir,
34009cb03716SBram Moolenaar int errornr,
34019cb03716SBram Moolenaar int forceit)
34029cb03716SBram Moolenaar {
3403b244373bSBram Moolenaar qf_jump_newwin(qi, dir, errornr, forceit, FALSE);
3404b244373bSBram Moolenaar }
3405b244373bSBram Moolenaar
3406b244373bSBram Moolenaar /*
34075b69c22fSBram Moolenaar * Jump to a quickfix line.
34085b69c22fSBram Moolenaar * If dir == 0 go to entry "errornr".
34095b69c22fSBram Moolenaar * If dir == FORWARD go "errornr" valid entries forward.
34105b69c22fSBram Moolenaar * If dir == BACKWARD go "errornr" valid entries backward.
34115b69c22fSBram Moolenaar * If dir == FORWARD_FILE go "errornr" valid entries files backward.
34125b69c22fSBram Moolenaar * If dir == BACKWARD_FILE go "errornr" valid entries files backward
34135b69c22fSBram Moolenaar * else if "errornr" is zero, redisplay the same line
34145b69c22fSBram Moolenaar * If 'forceit' is TRUE, then can discard changes to the current buffer.
3415b244373bSBram Moolenaar * If 'newwin' is TRUE, then open the file in a new window.
3416b244373bSBram Moolenaar */
34175843f5f3SBram Moolenaar static void
qf_jump_newwin(qf_info_T * qi,int dir,int errornr,int forceit,int newwin)3418b244373bSBram Moolenaar qf_jump_newwin(qf_info_T *qi,
3419b244373bSBram Moolenaar int dir,
3420b244373bSBram Moolenaar int errornr,
3421b244373bSBram Moolenaar int forceit,
3422b244373bSBram Moolenaar int newwin)
3423b244373bSBram Moolenaar {
3424fe15b7dfSBram Moolenaar qf_list_T *qfl;
34259cb03716SBram Moolenaar qfline_T *qf_ptr;
34269cb03716SBram Moolenaar qfline_T *old_qf_ptr;
34279cb03716SBram Moolenaar int qf_index;
34289cb03716SBram Moolenaar int old_qf_index;
34299cb03716SBram Moolenaar char_u *old_swb = p_swb;
34309cb03716SBram Moolenaar unsigned old_swb_flags = swb_flags;
3431eeb1b9c7SBram Moolenaar int prev_winid;
34329cb03716SBram Moolenaar int opened_window = FALSE;
34339cb03716SBram Moolenaar int print_message = TRUE;
34346dae96efSBram Moolenaar int old_KeyTyped = KeyTyped; // getting file may reset it
34359cb03716SBram Moolenaar int retval = OK;
34369cb03716SBram Moolenaar
34379cb03716SBram Moolenaar if (qi == NULL)
34389cb03716SBram Moolenaar qi = &ql_info;
34399cb03716SBram Moolenaar
34400398e00aSBram Moolenaar if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi)))
34419cb03716SBram Moolenaar {
3442e29a27f6SBram Moolenaar emsg(_(e_no_errors));
34439cb03716SBram Moolenaar return;
34449cb03716SBram Moolenaar }
34459cb03716SBram Moolenaar
3446eeb1b9c7SBram Moolenaar incr_quickfix_busy();
3447eeb1b9c7SBram Moolenaar
34484aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
3449fe15b7dfSBram Moolenaar
3450fe15b7dfSBram Moolenaar qf_ptr = qfl->qf_ptr;
34519cb03716SBram Moolenaar old_qf_ptr = qf_ptr;
3452fe15b7dfSBram Moolenaar qf_index = qfl->qf_index;
34539cb03716SBram Moolenaar old_qf_index = qf_index;
34546dae96efSBram Moolenaar
34556dae96efSBram Moolenaar qf_ptr = qf_get_entry(qfl, errornr, dir, &qf_index);
34569cb03716SBram Moolenaar if (qf_ptr == NULL)
34579cb03716SBram Moolenaar {
34589cb03716SBram Moolenaar qf_ptr = old_qf_ptr;
34599cb03716SBram Moolenaar qf_index = old_qf_index;
34609cb03716SBram Moolenaar goto theend;
34619cb03716SBram Moolenaar }
34629cb03716SBram Moolenaar
3463fe15b7dfSBram Moolenaar qfl->qf_index = qf_index;
34641557b16dSWei-Chung Wen qfl->qf_ptr = qf_ptr;
34659cb03716SBram Moolenaar if (qf_win_pos_update(qi, old_qf_index))
34666dae96efSBram Moolenaar // No need to print the error message if it's visible in the error
34676dae96efSBram Moolenaar // window
34689cb03716SBram Moolenaar print_message = FALSE;
34699cb03716SBram Moolenaar
3470eeb1b9c7SBram Moolenaar prev_winid = curwin->w_id;
3471eeb1b9c7SBram Moolenaar
3472b244373bSBram Moolenaar retval = qf_jump_open_window(qi, qf_ptr, newwin, &opened_window);
34736dae96efSBram Moolenaar if (retval == FAIL)
34749cb03716SBram Moolenaar goto failed;
34756dae96efSBram Moolenaar if (retval == NOTDONE)
34766dae96efSBram Moolenaar goto theend;
34779cb03716SBram Moolenaar
3478eeb1b9c7SBram Moolenaar retval = qf_jump_to_buffer(qi, qf_index, qf_ptr, forceit, prev_winid,
34796dae96efSBram Moolenaar &opened_window, old_KeyTyped, print_message);
34806dae96efSBram Moolenaar if (retval == NOTDONE)
34819cb03716SBram Moolenaar {
34826dae96efSBram Moolenaar // Quickfix/location list is freed by an autocmd
34839cb03716SBram Moolenaar qi = NULL;
34849cb03716SBram Moolenaar qf_ptr = NULL;
34859cb03716SBram Moolenaar }
34869cb03716SBram Moolenaar
34876dae96efSBram Moolenaar if (retval != OK)
3488071d4279SBram Moolenaar {
3489071d4279SBram Moolenaar if (opened_window)
34906dae96efSBram Moolenaar win_close(curwin, TRUE); // Close opened window
34910899d698SBram Moolenaar if (qf_ptr != NULL && qf_ptr->qf_fnum != 0)
3492071d4279SBram Moolenaar {
34936dae96efSBram Moolenaar // Couldn't open file, so put index back where it was. This could
34946dae96efSBram Moolenaar // happen if the file was readonly and we changed something.
3495071d4279SBram Moolenaar failed:
3496071d4279SBram Moolenaar qf_ptr = old_qf_ptr;
3497071d4279SBram Moolenaar qf_index = old_qf_index;
3498071d4279SBram Moolenaar }
3499071d4279SBram Moolenaar }
3500071d4279SBram Moolenaar theend:
35010899d698SBram Moolenaar if (qi != NULL)
35020899d698SBram Moolenaar {
3503fe15b7dfSBram Moolenaar qfl->qf_ptr = qf_ptr;
3504fe15b7dfSBram Moolenaar qfl->qf_index = qf_index;
35050899d698SBram Moolenaar }
3506f9ae154cSBram Moolenaar if (p_swb != old_swb && p_swb == empty_option)
3507071d4279SBram Moolenaar {
35086dae96efSBram Moolenaar // Restore old 'switchbuf' value, but not when an autocommand or
35096dae96efSBram Moolenaar // modeline has changed the value.
3510071d4279SBram Moolenaar p_swb = old_swb;
3511446cb837SBram Moolenaar swb_flags = old_swb_flags;
3512446cb837SBram Moolenaar }
3513eeb1b9c7SBram Moolenaar decr_quickfix_busy();
3514071d4279SBram Moolenaar }
3515071d4279SBram Moolenaar
351600bf8cd2SBram Moolenaar // Highlight attributes used for displaying entries from the quickfix list.
3517de3b3677SBram Moolenaar static int qfFileAttr;
3518de3b3677SBram Moolenaar static int qfSepAttr;
3519de3b3677SBram Moolenaar static int qfLineAttr;
3520de3b3677SBram Moolenaar
3521de3b3677SBram Moolenaar /*
3522de3b3677SBram Moolenaar * Display information about a single entry from the quickfix/location list.
3523de3b3677SBram Moolenaar * Used by ":clist/:llist" commands.
3524fe15b7dfSBram Moolenaar * 'cursel' will be set to TRUE for the currently selected entry in the
3525fe15b7dfSBram Moolenaar * quickfix list.
3526de3b3677SBram Moolenaar */
3527de3b3677SBram Moolenaar static void
qf_list_entry(qfline_T * qfp,int qf_idx,int cursel)3528fe15b7dfSBram Moolenaar qf_list_entry(qfline_T *qfp, int qf_idx, int cursel)
3529de3b3677SBram Moolenaar {
3530de3b3677SBram Moolenaar char_u *fname;
3531de3b3677SBram Moolenaar buf_T *buf;
3532de3b3677SBram Moolenaar int filter_entry;
3533de3b3677SBram Moolenaar
3534de3b3677SBram Moolenaar fname = NULL;
3535de3b3677SBram Moolenaar if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3536de3b3677SBram Moolenaar vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", qf_idx,
3537de3b3677SBram Moolenaar (char *)qfp->qf_module);
3538de3b3677SBram Moolenaar else {
3539de3b3677SBram Moolenaar if (qfp->qf_fnum != 0
3540de3b3677SBram Moolenaar && (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
3541de3b3677SBram Moolenaar {
3542de3b3677SBram Moolenaar fname = buf->b_fname;
354300bf8cd2SBram Moolenaar if (qfp->qf_type == 1) // :helpgrep
3544de3b3677SBram Moolenaar fname = gettail(fname);
3545de3b3677SBram Moolenaar }
3546de3b3677SBram Moolenaar if (fname == NULL)
3547de3b3677SBram Moolenaar sprintf((char *)IObuff, "%2d", qf_idx);
3548de3b3677SBram Moolenaar else
3549de3b3677SBram Moolenaar vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
3550de3b3677SBram Moolenaar qf_idx, (char *)fname);
3551de3b3677SBram Moolenaar }
3552de3b3677SBram Moolenaar
3553de3b3677SBram Moolenaar // Support for filtering entries using :filter /pat/ clist
3554de3b3677SBram Moolenaar // Match against the module name, file name, search pattern and
3555de3b3677SBram Moolenaar // text of the entry.
3556de3b3677SBram Moolenaar filter_entry = TRUE;
3557de3b3677SBram Moolenaar if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
3558de3b3677SBram Moolenaar filter_entry &= message_filtered(qfp->qf_module);
3559de3b3677SBram Moolenaar if (filter_entry && fname != NULL)
3560de3b3677SBram Moolenaar filter_entry &= message_filtered(fname);
3561de3b3677SBram Moolenaar if (filter_entry && qfp->qf_pattern != NULL)
3562de3b3677SBram Moolenaar filter_entry &= message_filtered(qfp->qf_pattern);
3563de3b3677SBram Moolenaar if (filter_entry)
3564de3b3677SBram Moolenaar filter_entry &= message_filtered(qfp->qf_text);
3565de3b3677SBram Moolenaar if (filter_entry)
3566de3b3677SBram Moolenaar return;
3567de3b3677SBram Moolenaar
3568de3b3677SBram Moolenaar msg_putchar('\n');
3569fe15b7dfSBram Moolenaar msg_outtrans_attr(IObuff, cursel ? HL_ATTR(HLF_QFL) : qfFileAttr);
3570de3b3677SBram Moolenaar
3571de3b3677SBram Moolenaar if (qfp->qf_lnum != 0)
357232526b3cSBram Moolenaar msg_puts_attr(":", qfSepAttr);
3573de3b3677SBram Moolenaar if (qfp->qf_lnum == 0)
3574de3b3677SBram Moolenaar IObuff[0] = NUL;
3575de3b3677SBram Moolenaar else
35766864efa5Sthinca qf_range_text(qfp, IObuff, IOSIZE);
3577de3b3677SBram Moolenaar sprintf((char *)IObuff + STRLEN(IObuff), "%s",
3578de3b3677SBram Moolenaar (char *)qf_types(qfp->qf_type, qfp->qf_nr));
357932526b3cSBram Moolenaar msg_puts_attr((char *)IObuff, qfLineAttr);
358032526b3cSBram Moolenaar msg_puts_attr(":", qfSepAttr);
3581de3b3677SBram Moolenaar if (qfp->qf_pattern != NULL)
3582de3b3677SBram Moolenaar {
3583de3b3677SBram Moolenaar qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE);
358432526b3cSBram Moolenaar msg_puts((char *)IObuff);
358532526b3cSBram Moolenaar msg_puts_attr(":", qfSepAttr);
3586de3b3677SBram Moolenaar }
358732526b3cSBram Moolenaar msg_puts(" ");
3588de3b3677SBram Moolenaar
358900bf8cd2SBram Moolenaar // Remove newlines and leading whitespace from the text. For an
359000bf8cd2SBram Moolenaar // unrecognized line keep the indent, the compiler may mark a word
359100bf8cd2SBram Moolenaar // with ^^^^.
3592de3b3677SBram Moolenaar qf_fmt_text((fname != NULL || qfp->qf_lnum != 0)
3593de3b3677SBram Moolenaar ? skipwhite(qfp->qf_text) : qfp->qf_text,
3594de3b3677SBram Moolenaar IObuff, IOSIZE);
3595de3b3677SBram Moolenaar msg_prt_line(IObuff, FALSE);
359600bf8cd2SBram Moolenaar out_flush(); // show one line at a time
3597de3b3677SBram Moolenaar }
3598de3b3677SBram Moolenaar
3599de3b3677SBram Moolenaar /*
3600071d4279SBram Moolenaar * ":clist": list all errors
3601d12f5c17SBram Moolenaar * ":llist": list all locations
3602071d4279SBram Moolenaar */
3603071d4279SBram Moolenaar void
qf_list(exarg_T * eap)360405540976SBram Moolenaar qf_list(exarg_T *eap)
3605071d4279SBram Moolenaar {
3606fe15b7dfSBram Moolenaar qf_list_T *qfl;
360768b76a69SBram Moolenaar qfline_T *qfp;
3608071d4279SBram Moolenaar int i;
3609071d4279SBram Moolenaar int idx1 = 1;
3610071d4279SBram Moolenaar int idx2 = -1;
3611071d4279SBram Moolenaar char_u *arg = eap->arg;
3612e8fea072SBram Moolenaar int plus = FALSE;
361300bf8cd2SBram Moolenaar int all = eap->forceit; // if not :cl!, only show
361400bf8cd2SBram Moolenaar // recognised errors
361587f59b09SBram Moolenaar qf_info_T *qi;
3616071d4279SBram Moolenaar
361787f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
3618d12f5c17SBram Moolenaar return;
3619d12f5c17SBram Moolenaar
36200398e00aSBram Moolenaar if (qf_stack_empty(qi) || qf_list_empty(qf_get_curlist(qi)))
3621071d4279SBram Moolenaar {
3622e29a27f6SBram Moolenaar emsg(_(e_no_errors));
3623071d4279SBram Moolenaar return;
3624071d4279SBram Moolenaar }
3625e8fea072SBram Moolenaar if (*arg == '+')
3626e8fea072SBram Moolenaar {
3627e8fea072SBram Moolenaar ++arg;
3628e8fea072SBram Moolenaar plus = TRUE;
3629e8fea072SBram Moolenaar }
3630071d4279SBram Moolenaar if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL)
3631071d4279SBram Moolenaar {
36322d06bfdeSBram Moolenaar semsg(_(e_trailing_arg), arg);
3633071d4279SBram Moolenaar return;
3634071d4279SBram Moolenaar }
36354aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
3636e8fea072SBram Moolenaar if (plus)
3637e8fea072SBram Moolenaar {
3638fe15b7dfSBram Moolenaar i = qfl->qf_index;
3639e8fea072SBram Moolenaar idx2 = i + idx1;
3640e8fea072SBram Moolenaar idx1 = i;
3641e8fea072SBram Moolenaar }
3642e8fea072SBram Moolenaar else
3643e8fea072SBram Moolenaar {
3644fe15b7dfSBram Moolenaar i = qfl->qf_count;
3645071d4279SBram Moolenaar if (idx1 < 0)
3646071d4279SBram Moolenaar idx1 = (-idx1 > i) ? 0 : idx1 + i + 1;
3647071d4279SBram Moolenaar if (idx2 < 0)
3648071d4279SBram Moolenaar idx2 = (-idx2 > i) ? 0 : idx2 + i + 1;
3649e8fea072SBram Moolenaar }
3650071d4279SBram Moolenaar
365100bf8cd2SBram Moolenaar // Shorten all the file names, so that it is easy to read
3652a796d46fSBram Moolenaar shorten_fnames(FALSE);
3653a796d46fSBram Moolenaar
365400bf8cd2SBram Moolenaar // Get the attributes for the different quickfix highlight items. Note
365500bf8cd2SBram Moolenaar // that this depends on syntax items defined in the qf.vim syntax file
365693a32e2eSBram Moolenaar qfFileAttr = syn_name2attr((char_u *)"qfFileName");
365793a32e2eSBram Moolenaar if (qfFileAttr == 0)
365893a32e2eSBram Moolenaar qfFileAttr = HL_ATTR(HLF_D);
365993a32e2eSBram Moolenaar qfSepAttr = syn_name2attr((char_u *)"qfSeparator");
366093a32e2eSBram Moolenaar if (qfSepAttr == 0)
366193a32e2eSBram Moolenaar qfSepAttr = HL_ATTR(HLF_D);
366293a32e2eSBram Moolenaar qfLineAttr = syn_name2attr((char_u *)"qfLineNr");
366393a32e2eSBram Moolenaar if (qfLineAttr == 0)
366493a32e2eSBram Moolenaar qfLineAttr = HL_ATTR(HLF_N);
366593a32e2eSBram Moolenaar
3666fe15b7dfSBram Moolenaar if (qfl->qf_nonevalid)
3667071d4279SBram Moolenaar all = TRUE;
366895946f12SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
3669071d4279SBram Moolenaar {
3670071d4279SBram Moolenaar if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2)
3671fe15b7dfSBram Moolenaar qf_list_entry(qfp, i, i == qfl->qf_index);
36724cde86c2SBram Moolenaar
3673071d4279SBram Moolenaar ui_breakcheck();
3674071d4279SBram Moolenaar }
3675071d4279SBram Moolenaar }
3676071d4279SBram Moolenaar
3677071d4279SBram Moolenaar /*
3678071d4279SBram Moolenaar * Remove newlines and leading whitespace from an error message.
3679071d4279SBram Moolenaar * Put the result in "buf[bufsize]".
3680071d4279SBram Moolenaar */
3681071d4279SBram Moolenaar static void
qf_fmt_text(char_u * text,char_u * buf,int bufsize)368205540976SBram Moolenaar qf_fmt_text(char_u *text, char_u *buf, int bufsize)
3683071d4279SBram Moolenaar {
3684071d4279SBram Moolenaar int i;
3685071d4279SBram Moolenaar char_u *p = text;
3686071d4279SBram Moolenaar
3687071d4279SBram Moolenaar for (i = 0; *p != NUL && i < bufsize - 1; ++i)
3688071d4279SBram Moolenaar {
3689071d4279SBram Moolenaar if (*p == '\n')
3690071d4279SBram Moolenaar {
3691071d4279SBram Moolenaar buf[i] = ' ';
3692071d4279SBram Moolenaar while (*++p != NUL)
36931c465444SBram Moolenaar if (!VIM_ISWHITE(*p) && *p != '\n')
3694071d4279SBram Moolenaar break;
3695071d4279SBram Moolenaar }
3696071d4279SBram Moolenaar else
3697071d4279SBram Moolenaar buf[i] = *p++;
3698071d4279SBram Moolenaar }
3699071d4279SBram Moolenaar buf[i] = NUL;
3700071d4279SBram Moolenaar }
3701071d4279SBram Moolenaar
370218cebf44SBram Moolenaar /*
37036864efa5Sthinca * Range information from lnum, col, end_lnum, and end_col.
37046864efa5Sthinca * Put the result in "buf[bufsize]".
37056864efa5Sthinca */
37066864efa5Sthinca static void
qf_range_text(qfline_T * qfp,char_u * buf,int bufsize)37076864efa5Sthinca qf_range_text(qfline_T *qfp, char_u *buf, int bufsize)
37086864efa5Sthinca {
37096864efa5Sthinca int len;
37106864efa5Sthinca vim_snprintf((char *)buf, bufsize, "%ld", qfp->qf_lnum);
37116864efa5Sthinca len = (int)STRLEN(buf);
37126864efa5Sthinca
37136864efa5Sthinca if (qfp->qf_end_lnum > 0 && qfp->qf_lnum != qfp->qf_end_lnum)
37146864efa5Sthinca {
37156864efa5Sthinca vim_snprintf((char *)buf + len, bufsize - len,
37166864efa5Sthinca "-%ld", qfp->qf_end_lnum);
37176864efa5Sthinca len += (int)STRLEN(buf + len);
37186864efa5Sthinca }
37196864efa5Sthinca if (qfp->qf_col > 0)
37206864efa5Sthinca {
37216864efa5Sthinca vim_snprintf((char *)buf + len, bufsize - len, " col %d", qfp->qf_col);
37226864efa5Sthinca len += (int)STRLEN(buf + len);
37236864efa5Sthinca if (qfp->qf_end_col > 0 && qfp->qf_col != qfp->qf_end_col)
37246864efa5Sthinca {
37256864efa5Sthinca vim_snprintf((char *)buf + len, bufsize - len,
37266864efa5Sthinca "-%d", qfp->qf_end_col);
37276864efa5Sthinca len += (int)STRLEN(buf + len);
37286864efa5Sthinca }
37296864efa5Sthinca }
37306864efa5Sthinca buf[len] = NUL;
37316864efa5Sthinca }
37326864efa5Sthinca
37336864efa5Sthinca /*
373418cebf44SBram Moolenaar * Display information (list number, list size and the title) about a
373518cebf44SBram Moolenaar * quickfix/location list.
373618cebf44SBram Moolenaar */
3737f6acffbeSBram Moolenaar static void
qf_msg(qf_info_T * qi,int which,char * lead)3738f6acffbeSBram Moolenaar qf_msg(qf_info_T *qi, int which, char *lead)
3739f6acffbeSBram Moolenaar {
3740f6acffbeSBram Moolenaar char *title = (char *)qi->qf_lists[which].qf_title;
3741f6acffbeSBram Moolenaar int count = qi->qf_lists[which].qf_count;
3742f6acffbeSBram Moolenaar char_u buf[IOSIZE];
3743f6acffbeSBram Moolenaar
3744f6acffbeSBram Moolenaar vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "),
3745f6acffbeSBram Moolenaar lead,
3746f6acffbeSBram Moolenaar which + 1,
3747f6acffbeSBram Moolenaar qi->qf_listcount,
3748f6acffbeSBram Moolenaar count);
3749f6acffbeSBram Moolenaar
3750f6acffbeSBram Moolenaar if (title != NULL)
3751f6acffbeSBram Moolenaar {
375216ec3c9bSBram Moolenaar size_t len = STRLEN(buf);
375316ec3c9bSBram Moolenaar
375416ec3c9bSBram Moolenaar if (len < 34)
375516ec3c9bSBram Moolenaar {
375616ec3c9bSBram Moolenaar vim_memset(buf + len, ' ', 34 - len);
375716ec3c9bSBram Moolenaar buf[34] = NUL;
375816ec3c9bSBram Moolenaar }
375916ec3c9bSBram Moolenaar vim_strcat(buf, (char_u *)title, IOSIZE);
3760f6acffbeSBram Moolenaar }
3761f6acffbeSBram Moolenaar trunc_string(buf, buf, Columns - 1, IOSIZE);
376232526b3cSBram Moolenaar msg((char *)buf);
3763f6acffbeSBram Moolenaar }
3764f6acffbeSBram Moolenaar
3765071d4279SBram Moolenaar /*
3766071d4279SBram Moolenaar * ":colder [count]": Up in the quickfix stack.
3767071d4279SBram Moolenaar * ":cnewer [count]": Down in the quickfix stack.
3768d12f5c17SBram Moolenaar * ":lolder [count]": Up in the location list stack.
3769d12f5c17SBram Moolenaar * ":lnewer [count]": Down in the location list stack.
3770071d4279SBram Moolenaar */
3771071d4279SBram Moolenaar void
qf_age(exarg_T * eap)377205540976SBram Moolenaar qf_age(exarg_T *eap)
3773071d4279SBram Moolenaar {
377487f59b09SBram Moolenaar qf_info_T *qi;
3775071d4279SBram Moolenaar int count;
3776071d4279SBram Moolenaar
377787f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
3778d12f5c17SBram Moolenaar return;
3779d12f5c17SBram Moolenaar
3780071d4279SBram Moolenaar if (eap->addr_count != 0)
3781071d4279SBram Moolenaar count = eap->line2;
3782071d4279SBram Moolenaar else
3783071d4279SBram Moolenaar count = 1;
3784071d4279SBram Moolenaar while (count--)
3785071d4279SBram Moolenaar {
3786d12f5c17SBram Moolenaar if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder)
3787071d4279SBram Moolenaar {
3788d12f5c17SBram Moolenaar if (qi->qf_curlist == 0)
3789071d4279SBram Moolenaar {
3790f9e3e09fSBram Moolenaar emsg(_("E380: At bottom of quickfix stack"));
379182e803b0SBram Moolenaar break;
3792071d4279SBram Moolenaar }
3793d12f5c17SBram Moolenaar --qi->qf_curlist;
3794071d4279SBram Moolenaar }
3795071d4279SBram Moolenaar else
3796071d4279SBram Moolenaar {
3797d12f5c17SBram Moolenaar if (qi->qf_curlist >= qi->qf_listcount - 1)
3798071d4279SBram Moolenaar {
3799f9e3e09fSBram Moolenaar emsg(_("E381: At top of quickfix stack"));
380082e803b0SBram Moolenaar break;
3801071d4279SBram Moolenaar }
3802d12f5c17SBram Moolenaar ++qi->qf_curlist;
3803071d4279SBram Moolenaar }
3804071d4279SBram Moolenaar }
3805f6acffbeSBram Moolenaar qf_msg(qi, qi->qf_curlist, "");
3806864293abSBram Moolenaar qf_update_buffer(qi, NULL);
3807071d4279SBram Moolenaar }
3808071d4279SBram Moolenaar
380918cebf44SBram Moolenaar /*
381018cebf44SBram Moolenaar * Display the information about all the quickfix/location lists in the stack
381118cebf44SBram Moolenaar */
3812f6acffbeSBram Moolenaar void
qf_history(exarg_T * eap)3813f6acffbeSBram Moolenaar qf_history(exarg_T *eap)
3814f6acffbeSBram Moolenaar {
381587f59b09SBram Moolenaar qf_info_T *qi = qf_cmd_get_stack(eap, FALSE);
3816f6acffbeSBram Moolenaar int i;
3817f6acffbeSBram Moolenaar
38188ffc7c8bSBram Moolenaar if (eap->addr_count > 0)
38198ffc7c8bSBram Moolenaar {
38208ffc7c8bSBram Moolenaar if (qi == NULL)
38218ffc7c8bSBram Moolenaar {
38228ffc7c8bSBram Moolenaar emsg(_(e_loclist));
38238ffc7c8bSBram Moolenaar return;
38248ffc7c8bSBram Moolenaar }
38258ffc7c8bSBram Moolenaar
38268ffc7c8bSBram Moolenaar // Jump to the specified quickfix list
38278ffc7c8bSBram Moolenaar if (eap->line2 > 0 && eap->line2 <= qi->qf_listcount)
38288ffc7c8bSBram Moolenaar {
38298ffc7c8bSBram Moolenaar qi->qf_curlist = eap->line2 - 1;
38308ffc7c8bSBram Moolenaar qf_msg(qi, qi->qf_curlist, "");
38318ffc7c8bSBram Moolenaar qf_update_buffer(qi, NULL);
38328ffc7c8bSBram Moolenaar }
38338ffc7c8bSBram Moolenaar else
3834108010aaSBram Moolenaar emsg(_(e_invalid_range));
38358ffc7c8bSBram Moolenaar
38368ffc7c8bSBram Moolenaar return;
38378ffc7c8bSBram Moolenaar }
38388ffc7c8bSBram Moolenaar
38395b69c22fSBram Moolenaar if (qf_stack_empty(qi))
384032526b3cSBram Moolenaar msg(_("No entries"));
3841f6acffbeSBram Moolenaar else
3842f6acffbeSBram Moolenaar for (i = 0; i < qi->qf_listcount; ++i)
3843f6acffbeSBram Moolenaar qf_msg(qi, i, i == qi->qf_curlist ? "> " : " ");
3844f6acffbeSBram Moolenaar }
3845f6acffbeSBram Moolenaar
3846071d4279SBram Moolenaar /*
38476a8958dbSBram Moolenaar * Free all the entries in the error list "idx". Note that other information
38486a8958dbSBram Moolenaar * associated with the list like context and title are not freed.
3849071d4279SBram Moolenaar */
3850071d4279SBram Moolenaar static void
qf_free_items(qf_list_T * qfl)3851fe15b7dfSBram Moolenaar qf_free_items(qf_list_T *qfl)
3852071d4279SBram Moolenaar {
385368b76a69SBram Moolenaar qfline_T *qfp;
385483e6d7acSBram Moolenaar qfline_T *qfpnext;
385581484f42SBram Moolenaar int stop = FALSE;
3856071d4279SBram Moolenaar
3857a7df8c70SBram Moolenaar while (qfl->qf_count && qfl->qf_start != NULL)
3858071d4279SBram Moolenaar {
3859a7df8c70SBram Moolenaar qfp = qfl->qf_start;
386083e6d7acSBram Moolenaar qfpnext = qfp->qf_next;
38617adf06f4SBram Moolenaar if (!stop)
3862c83a44bfSBram Moolenaar {
3863d76ce852SBram Moolenaar vim_free(qfp->qf_module);
386483e6d7acSBram Moolenaar vim_free(qfp->qf_text);
386583e6d7acSBram Moolenaar vim_free(qfp->qf_pattern);
3866d76ce852SBram Moolenaar stop = (qfp == qfpnext);
386783e6d7acSBram Moolenaar vim_free(qfp);
386881484f42SBram Moolenaar if (stop)
386900bf8cd2SBram Moolenaar // Somehow qf_count may have an incorrect value, set it to 1
387000bf8cd2SBram Moolenaar // to avoid crashing when it's wrong.
387100bf8cd2SBram Moolenaar // TODO: Avoid qf_count being incorrect.
3872a7df8c70SBram Moolenaar qfl->qf_count = 1;
3873c83a44bfSBram Moolenaar }
3874a7df8c70SBram Moolenaar qfl->qf_start = qfpnext;
3875a7df8c70SBram Moolenaar --qfl->qf_count;
3876071d4279SBram Moolenaar }
38776a8958dbSBram Moolenaar
3878a7df8c70SBram Moolenaar qfl->qf_index = 0;
3879a7df8c70SBram Moolenaar qfl->qf_start = NULL;
3880a7df8c70SBram Moolenaar qfl->qf_last = NULL;
3881a7df8c70SBram Moolenaar qfl->qf_ptr = NULL;
3882a7df8c70SBram Moolenaar qfl->qf_nonevalid = TRUE;
3883361c8f0eSBram Moolenaar
3884a7df8c70SBram Moolenaar qf_clean_dir_stack(&qfl->qf_dir_stack);
3885a7df8c70SBram Moolenaar qfl->qf_directory = NULL;
3886a7df8c70SBram Moolenaar qf_clean_dir_stack(&qfl->qf_file_stack);
3887a7df8c70SBram Moolenaar qfl->qf_currfile = NULL;
3888a7df8c70SBram Moolenaar qfl->qf_multiline = FALSE;
3889a7df8c70SBram Moolenaar qfl->qf_multiignore = FALSE;
3890a7df8c70SBram Moolenaar qfl->qf_multiscan = FALSE;
3891071d4279SBram Moolenaar }
3892071d4279SBram Moolenaar
3893071d4279SBram Moolenaar /*
38946a8958dbSBram Moolenaar * Free error list "idx". Frees all the entries in the quickfix list,
38956a8958dbSBram Moolenaar * associated context information and the title.
38966a8958dbSBram Moolenaar */
38976a8958dbSBram Moolenaar static void
qf_free(qf_list_T * qfl)3898fe15b7dfSBram Moolenaar qf_free(qf_list_T *qfl)
38996a8958dbSBram Moolenaar {
3900fe15b7dfSBram Moolenaar qf_free_items(qfl);
39016a8958dbSBram Moolenaar
3902d23a8236SBram Moolenaar VIM_CLEAR(qfl->qf_title);
3903a7df8c70SBram Moolenaar free_tv(qfl->qf_ctx);
3904a7df8c70SBram Moolenaar qfl->qf_ctx = NULL;
3905d43906d2SBram Moolenaar free_callback(&qfl->qftf_cb);
3906a539f4f1SBram Moolenaar qfl->qf_id = 0;
3907b254af31SBram Moolenaar qfl->qf_changedtick = 0L;
39086a8958dbSBram Moolenaar }
39096a8958dbSBram Moolenaar
39106a8958dbSBram Moolenaar /*
3911071d4279SBram Moolenaar * qf_mark_adjust: adjust marks
3912071d4279SBram Moolenaar */
3913071d4279SBram Moolenaar void
qf_mark_adjust(win_T * wp,linenr_T line1,linenr_T line2,long amount,long amount_after)391405540976SBram Moolenaar qf_mark_adjust(
391505540976SBram Moolenaar win_T *wp,
391605540976SBram Moolenaar linenr_T line1,
391705540976SBram Moolenaar linenr_T line2,
391805540976SBram Moolenaar long amount,
391905540976SBram Moolenaar long amount_after)
3920071d4279SBram Moolenaar {
3921071d4279SBram Moolenaar int i;
392268b76a69SBram Moolenaar qfline_T *qfp;
3923071d4279SBram Moolenaar int idx;
3924d12f5c17SBram Moolenaar qf_info_T *qi = &ql_info;
39252f095a4bSBram Moolenaar int found_one = FALSE;
3926c1542744SBram Moolenaar int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY;
3927071d4279SBram Moolenaar
3928c1542744SBram Moolenaar if (!(curbuf->b_has_qf_entry & buf_has_flag))
39292f095a4bSBram Moolenaar return;
3930d12f5c17SBram Moolenaar if (wp != NULL)
3931d12f5c17SBram Moolenaar {
3932d12f5c17SBram Moolenaar if (wp->w_llist == NULL)
3933d12f5c17SBram Moolenaar return;
3934d12f5c17SBram Moolenaar qi = wp->w_llist;
3935d12f5c17SBram Moolenaar }
3936d12f5c17SBram Moolenaar
3937d12f5c17SBram Moolenaar for (idx = 0; idx < qi->qf_listcount; ++idx)
39380398e00aSBram Moolenaar {
39390398e00aSBram Moolenaar qf_list_T *qfl = qf_get_list(qi, idx);
39400398e00aSBram Moolenaar
39410398e00aSBram Moolenaar if (!qf_list_empty(qfl))
3942a16123a6SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
3943071d4279SBram Moolenaar if (qfp->qf_fnum == curbuf->b_fnum)
3944071d4279SBram Moolenaar {
39452f095a4bSBram Moolenaar found_one = TRUE;
3946071d4279SBram Moolenaar if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2)
3947071d4279SBram Moolenaar {
3948071d4279SBram Moolenaar if (amount == MAXLNUM)
3949071d4279SBram Moolenaar qfp->qf_cleared = TRUE;
3950071d4279SBram Moolenaar else
3951071d4279SBram Moolenaar qfp->qf_lnum += amount;
3952071d4279SBram Moolenaar }
3953071d4279SBram Moolenaar else if (amount_after && qfp->qf_lnum > line2)
3954071d4279SBram Moolenaar qfp->qf_lnum += amount_after;
3955071d4279SBram Moolenaar }
39560398e00aSBram Moolenaar }
39572f095a4bSBram Moolenaar
39582f095a4bSBram Moolenaar if (!found_one)
3959c1542744SBram Moolenaar curbuf->b_has_qf_entry &= ~buf_has_flag;
3960071d4279SBram Moolenaar }
3961071d4279SBram Moolenaar
3962071d4279SBram Moolenaar /*
3963071d4279SBram Moolenaar * Make a nice message out of the error character and the error number:
3964071d4279SBram Moolenaar * char number message
3965071d4279SBram Moolenaar * e or E 0 " error"
3966071d4279SBram Moolenaar * w or W 0 " warning"
3967071d4279SBram Moolenaar * i or I 0 " info"
3968e928366dSBram Moolenaar * n or N 0 " note"
3969071d4279SBram Moolenaar * 0 0 ""
3970071d4279SBram Moolenaar * other 0 " c"
3971071d4279SBram Moolenaar * e or E n " error n"
3972071d4279SBram Moolenaar * w or W n " warning n"
3973071d4279SBram Moolenaar * i or I n " info n"
3974e928366dSBram Moolenaar * n or N n " note n"
3975071d4279SBram Moolenaar * 0 n " error n"
3976071d4279SBram Moolenaar * other n " c n"
3977071d4279SBram Moolenaar * 1 x "" :helpgrep
3978071d4279SBram Moolenaar */
3979071d4279SBram Moolenaar static char_u *
qf_types(int c,int nr)398005540976SBram Moolenaar qf_types(int c, int nr)
3981071d4279SBram Moolenaar {
3982071d4279SBram Moolenaar static char_u buf[20];
3983071d4279SBram Moolenaar static char_u cc[3];
3984071d4279SBram Moolenaar char_u *p;
3985071d4279SBram Moolenaar
3986071d4279SBram Moolenaar if (c == 'W' || c == 'w')
3987071d4279SBram Moolenaar p = (char_u *)" warning";
3988071d4279SBram Moolenaar else if (c == 'I' || c == 'i')
3989071d4279SBram Moolenaar p = (char_u *)" info";
3990e928366dSBram Moolenaar else if (c == 'N' || c == 'n')
3991e928366dSBram Moolenaar p = (char_u *)" note";
3992071d4279SBram Moolenaar else if (c == 'E' || c == 'e' || (c == 0 && nr > 0))
3993071d4279SBram Moolenaar p = (char_u *)" error";
3994071d4279SBram Moolenaar else if (c == 0 || c == 1)
3995071d4279SBram Moolenaar p = (char_u *)"";
3996071d4279SBram Moolenaar else
3997071d4279SBram Moolenaar {
3998071d4279SBram Moolenaar cc[0] = ' ';
3999071d4279SBram Moolenaar cc[1] = c;
4000071d4279SBram Moolenaar cc[2] = NUL;
4001071d4279SBram Moolenaar p = cc;
4002071d4279SBram Moolenaar }
4003071d4279SBram Moolenaar
4004071d4279SBram Moolenaar if (nr <= 0)
4005071d4279SBram Moolenaar return p;
4006071d4279SBram Moolenaar
4007071d4279SBram Moolenaar sprintf((char *)buf, "%s %3d", (char *)p, nr);
4008071d4279SBram Moolenaar return buf;
4009071d4279SBram Moolenaar }
4010071d4279SBram Moolenaar
4011071d4279SBram Moolenaar /*
40120a08c63dSBram Moolenaar * When "split" is FALSE: Open the entry/result under the cursor.
40130a08c63dSBram Moolenaar * When "split" is TRUE: Open the entry/result under the cursor in a new window.
40140a08c63dSBram Moolenaar */
40150a08c63dSBram Moolenaar void
qf_view_result(int split)40160a08c63dSBram Moolenaar qf_view_result(int split)
40170a08c63dSBram Moolenaar {
40180a08c63dSBram Moolenaar qf_info_T *qi = &ql_info;
40190a08c63dSBram Moolenaar
40200a08c63dSBram Moolenaar if (!bt_quickfix(curbuf))
40210a08c63dSBram Moolenaar return;
40220a08c63dSBram Moolenaar
40230a08c63dSBram Moolenaar if (IS_LL_WINDOW(curwin))
40240a08c63dSBram Moolenaar qi = GET_LOC_LIST(curwin);
40250a08c63dSBram Moolenaar
40260398e00aSBram Moolenaar if (qf_list_empty(qf_get_curlist(qi)))
40270a08c63dSBram Moolenaar {
4028e29a27f6SBram Moolenaar emsg(_(e_no_errors));
40290a08c63dSBram Moolenaar return;
40300a08c63dSBram Moolenaar }
40310a08c63dSBram Moolenaar
40320a08c63dSBram Moolenaar if (split)
40330a08c63dSBram Moolenaar {
4034b244373bSBram Moolenaar // Open the selected entry in a new window
4035b244373bSBram Moolenaar qf_jump_newwin(qi, 0, (long)curwin->w_cursor.lnum, FALSE, TRUE);
40360a08c63dSBram Moolenaar do_cmdline_cmd((char_u *) "clearjumps");
40370a08c63dSBram Moolenaar return;
40380a08c63dSBram Moolenaar }
40390a08c63dSBram Moolenaar
40400a08c63dSBram Moolenaar do_cmdline_cmd((char_u *)(IS_LL_WINDOW(curwin) ? ".ll" : ".cc"));
40410a08c63dSBram Moolenaar }
40420a08c63dSBram Moolenaar
40430a08c63dSBram Moolenaar /*
4044071d4279SBram Moolenaar * ":cwindow": open the quickfix window if we have errors to display,
4045071d4279SBram Moolenaar * close it if not.
4046d12f5c17SBram Moolenaar * ":lwindow": open the location list window if we have locations to display,
4047d12f5c17SBram Moolenaar * close it if not.
4048071d4279SBram Moolenaar */
4049071d4279SBram Moolenaar void
ex_cwindow(exarg_T * eap)405005540976SBram Moolenaar ex_cwindow(exarg_T *eap)
4051071d4279SBram Moolenaar {
405287f59b09SBram Moolenaar qf_info_T *qi;
4053108e7b42SBram Moolenaar qf_list_T *qfl;
4054071d4279SBram Moolenaar win_T *win;
4055071d4279SBram Moolenaar
405687f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4057d12f5c17SBram Moolenaar return;
4058d12f5c17SBram Moolenaar
40594aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
4060108e7b42SBram Moolenaar
406100bf8cd2SBram Moolenaar // Look for an existing quickfix window.
4062d12f5c17SBram Moolenaar win = qf_find_win(qi);
4063071d4279SBram Moolenaar
406400bf8cd2SBram Moolenaar // If a quickfix window is open but we have no errors to display,
406500bf8cd2SBram Moolenaar // close the window. If a quickfix window is not open, then open
406600bf8cd2SBram Moolenaar // it if we have errors; otherwise, leave it closed.
4067019dfe68SBram Moolenaar if (qf_stack_empty(qi)
4068108e7b42SBram Moolenaar || qfl->qf_nonevalid
40699afe5e9cSBram Moolenaar || qf_list_empty(qfl))
4070071d4279SBram Moolenaar {
4071071d4279SBram Moolenaar if (win != NULL)
4072071d4279SBram Moolenaar ex_cclose(eap);
4073071d4279SBram Moolenaar }
4074071d4279SBram Moolenaar else if (win == NULL)
4075071d4279SBram Moolenaar ex_copen(eap);
4076071d4279SBram Moolenaar }
4077071d4279SBram Moolenaar
4078071d4279SBram Moolenaar /*
4079071d4279SBram Moolenaar * ":cclose": close the window showing the list of errors.
4080d12f5c17SBram Moolenaar * ":lclose": close the window showing the location list
4081071d4279SBram Moolenaar */
4082071d4279SBram Moolenaar void
ex_cclose(exarg_T * eap)408305540976SBram Moolenaar ex_cclose(exarg_T *eap)
4084071d4279SBram Moolenaar {
4085d12f5c17SBram Moolenaar win_T *win = NULL;
408687f59b09SBram Moolenaar qf_info_T *qi;
4087071d4279SBram Moolenaar
408887f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
4089d12f5c17SBram Moolenaar return;
4090071d4279SBram Moolenaar
409100bf8cd2SBram Moolenaar // Find existing quickfix window and close it.
4092d12f5c17SBram Moolenaar win = qf_find_win(qi);
4093071d4279SBram Moolenaar if (win != NULL)
4094071d4279SBram Moolenaar win_close(win, FALSE);
4095071d4279SBram Moolenaar }
4096071d4279SBram Moolenaar
4097071d4279SBram Moolenaar /*
4098fe15b7dfSBram Moolenaar * Set "w:quickfix_title" if "qi" has a title.
4099fe15b7dfSBram Moolenaar */
4100fe15b7dfSBram Moolenaar static void
qf_set_title_var(qf_list_T * qfl)4101fe15b7dfSBram Moolenaar qf_set_title_var(qf_list_T *qfl)
4102fe15b7dfSBram Moolenaar {
4103fe15b7dfSBram Moolenaar if (qfl->qf_title != NULL)
4104fe15b7dfSBram Moolenaar set_internal_string_var((char_u *)"w:quickfix_title", qfl->qf_title);
4105fe15b7dfSBram Moolenaar }
4106fe15b7dfSBram Moolenaar
4107fe15b7dfSBram Moolenaar /*
4108476c0db0SBram Moolenaar * Goto a quickfix or location list window (if present).
4109476c0db0SBram Moolenaar * Returns OK if the window is found, FAIL otherwise.
4110476c0db0SBram Moolenaar */
4111476c0db0SBram Moolenaar static int
qf_goto_cwindow(qf_info_T * qi,int resize,int sz,int vertsplit)4112476c0db0SBram Moolenaar qf_goto_cwindow(qf_info_T *qi, int resize, int sz, int vertsplit)
4113476c0db0SBram Moolenaar {
4114476c0db0SBram Moolenaar win_T *win;
4115476c0db0SBram Moolenaar
4116476c0db0SBram Moolenaar win = qf_find_win(qi);
4117476c0db0SBram Moolenaar if (win == NULL)
4118476c0db0SBram Moolenaar return FAIL;
4119476c0db0SBram Moolenaar
4120476c0db0SBram Moolenaar win_goto(win);
4121476c0db0SBram Moolenaar if (resize)
4122476c0db0SBram Moolenaar {
4123476c0db0SBram Moolenaar if (vertsplit)
4124476c0db0SBram Moolenaar {
4125476c0db0SBram Moolenaar if (sz != win->w_width)
4126476c0db0SBram Moolenaar win_setwidth(sz);
4127476c0db0SBram Moolenaar }
41281142a31bSBram Moolenaar else if (sz != win->w_height && win->w_height
41291142a31bSBram Moolenaar + win->w_status_height + tabline_height() < cmdline_row)
4130476c0db0SBram Moolenaar win_setheight(sz);
4131476c0db0SBram Moolenaar }
4132476c0db0SBram Moolenaar
4133476c0db0SBram Moolenaar return OK;
4134476c0db0SBram Moolenaar }
4135476c0db0SBram Moolenaar
4136476c0db0SBram Moolenaar /*
4137d82a81caSBram Moolenaar * Set options for the buffer in the quickfix or location list window.
4138d82a81caSBram Moolenaar */
4139d82a81caSBram Moolenaar static void
qf_set_cwindow_options(void)4140d82a81caSBram Moolenaar qf_set_cwindow_options(void)
4141d82a81caSBram Moolenaar {
4142d82a81caSBram Moolenaar // switch off 'swapfile'
4143d82a81caSBram Moolenaar set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL);
4144d82a81caSBram Moolenaar set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix",
4145d82a81caSBram Moolenaar OPT_LOCAL);
4146d82a81caSBram Moolenaar set_option_value((char_u *)"bh", 0L, (char_u *)"hide", OPT_LOCAL);
4147d82a81caSBram Moolenaar RESET_BINDING(curwin);
4148d82a81caSBram Moolenaar #ifdef FEAT_DIFF
4149d82a81caSBram Moolenaar curwin->w_p_diff = FALSE;
4150d82a81caSBram Moolenaar #endif
4151d82a81caSBram Moolenaar #ifdef FEAT_FOLDING
4152d82a81caSBram Moolenaar set_option_value((char_u *)"fdm", 0L, (char_u *)"manual",
4153d82a81caSBram Moolenaar OPT_LOCAL);
4154d82a81caSBram Moolenaar #endif
4155d82a81caSBram Moolenaar }
4156d82a81caSBram Moolenaar
4157d82a81caSBram Moolenaar /*
4158476c0db0SBram Moolenaar * Open a new quickfix or location list window, load the quickfix buffer and
4159476c0db0SBram Moolenaar * set the appropriate options for the window.
4160476c0db0SBram Moolenaar * Returns FAIL if the window could not be opened.
4161476c0db0SBram Moolenaar */
4162476c0db0SBram Moolenaar static int
qf_open_new_cwindow(qf_info_T * qi,int height)4163476c0db0SBram Moolenaar qf_open_new_cwindow(qf_info_T *qi, int height)
4164476c0db0SBram Moolenaar {
4165476c0db0SBram Moolenaar buf_T *qf_buf;
4166476c0db0SBram Moolenaar win_T *oldwin = curwin;
4167476c0db0SBram Moolenaar tabpage_T *prevtab = curtab;
4168476c0db0SBram Moolenaar int flags = 0;
4169476c0db0SBram Moolenaar win_T *win;
4170476c0db0SBram Moolenaar
4171476c0db0SBram Moolenaar qf_buf = qf_find_buf(qi);
4172476c0db0SBram Moolenaar
4173476c0db0SBram Moolenaar // The current window becomes the previous window afterwards.
4174476c0db0SBram Moolenaar win = curwin;
4175476c0db0SBram Moolenaar
4176e1004401SBram Moolenaar if (IS_QF_STACK(qi) && cmdmod.cmod_split == 0)
4177476c0db0SBram Moolenaar // Create the new quickfix window at the very bottom, except when
4178476c0db0SBram Moolenaar // :belowright or :aboveleft is used.
4179476c0db0SBram Moolenaar win_goto(lastwin);
4180476c0db0SBram Moolenaar // Default is to open the window below the current window
4181e1004401SBram Moolenaar if (cmdmod.cmod_split == 0)
4182476c0db0SBram Moolenaar flags = WSP_BELOW;
4183476c0db0SBram Moolenaar flags |= WSP_NEWLOC;
4184476c0db0SBram Moolenaar if (win_split(height, flags) == FAIL)
4185476c0db0SBram Moolenaar return FAIL; // not enough room for window
4186476c0db0SBram Moolenaar RESET_BINDING(curwin);
4187476c0db0SBram Moolenaar
4188476c0db0SBram Moolenaar if (IS_LL_STACK(qi))
4189476c0db0SBram Moolenaar {
4190476c0db0SBram Moolenaar // For the location list window, create a reference to the
4191eeb1b9c7SBram Moolenaar // location list stack from the window 'win'.
4192eeb1b9c7SBram Moolenaar curwin->w_llist_ref = qi;
4193eeb1b9c7SBram Moolenaar qi->qf_refcount++;
4194476c0db0SBram Moolenaar }
4195476c0db0SBram Moolenaar
4196476c0db0SBram Moolenaar if (oldwin != curwin)
4197476c0db0SBram Moolenaar oldwin = NULL; // don't store info when in another window
4198476c0db0SBram Moolenaar if (qf_buf != NULL)
4199476c0db0SBram Moolenaar {
4200476c0db0SBram Moolenaar // Use the existing quickfix buffer
42019e40c4b1SBram Moolenaar if (do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE,
42021d30fde3SBram Moolenaar ECMD_HIDE + ECMD_OLDBUF + ECMD_NOWINENTER, oldwin) == FAIL)
42039e40c4b1SBram Moolenaar return FAIL;
4204476c0db0SBram Moolenaar }
4205476c0db0SBram Moolenaar else
4206476c0db0SBram Moolenaar {
4207476c0db0SBram Moolenaar // Create a new quickfix buffer
42081d30fde3SBram Moolenaar if (do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE + ECMD_NOWINENTER,
42091d30fde3SBram Moolenaar oldwin) == FAIL)
42109e40c4b1SBram Moolenaar return FAIL;
4211476c0db0SBram Moolenaar
4212ee8188fcSBram Moolenaar // save the number of the new buffer
4213ee8188fcSBram Moolenaar qi->qf_bufnr = curbuf->b_fnum;
4214476c0db0SBram Moolenaar }
4215476c0db0SBram Moolenaar
4216d82a81caSBram Moolenaar // Set the options for the quickfix buffer/window (if not already done)
4217d82a81caSBram Moolenaar // Do this even if the quickfix buffer was already present, as an autocmd
4218d82a81caSBram Moolenaar // might have previously deleted (:bdelete) the quickfix buffer.
421961eeeea8SBram Moolenaar if (!bt_quickfix(curbuf))
4220d82a81caSBram Moolenaar qf_set_cwindow_options();
4221d82a81caSBram Moolenaar
4222476c0db0SBram Moolenaar // Only set the height when still in the same tab page and there is no
4223476c0db0SBram Moolenaar // window to the side.
4224476c0db0SBram Moolenaar if (curtab == prevtab && curwin->w_width == Columns)
4225476c0db0SBram Moolenaar win_setheight(height);
4226476c0db0SBram Moolenaar curwin->w_p_wfh = TRUE; // set 'winfixheight'
4227476c0db0SBram Moolenaar if (win_valid(win))
4228476c0db0SBram Moolenaar prevwin = win;
4229476c0db0SBram Moolenaar
4230476c0db0SBram Moolenaar return OK;
4231476c0db0SBram Moolenaar }
4232476c0db0SBram Moolenaar
4233476c0db0SBram Moolenaar /*
4234071d4279SBram Moolenaar * ":copen": open a window that shows the list of errors.
4235d12f5c17SBram Moolenaar * ":lopen": open a window that shows the location list.
4236071d4279SBram Moolenaar */
4237071d4279SBram Moolenaar void
ex_copen(exarg_T * eap)423805540976SBram Moolenaar ex_copen(exarg_T *eap)
4239071d4279SBram Moolenaar {
424087f59b09SBram Moolenaar qf_info_T *qi;
4241108e7b42SBram Moolenaar qf_list_T *qfl;
4242071d4279SBram Moolenaar int height;
4243476c0db0SBram Moolenaar int status = FAIL;
42449f84ded3SBram Moolenaar int lnum;
4245071d4279SBram Moolenaar
424687f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4247d12f5c17SBram Moolenaar return;
4248d12f5c17SBram Moolenaar
42499f84ded3SBram Moolenaar incr_quickfix_busy();
42509f84ded3SBram Moolenaar
4251071d4279SBram Moolenaar if (eap->addr_count != 0)
4252071d4279SBram Moolenaar height = eap->line2;
4253071d4279SBram Moolenaar else
4254071d4279SBram Moolenaar height = QF_WINHEIGHT;
4255071d4279SBram Moolenaar
4256476c0db0SBram Moolenaar reset_VIsual_and_resel(); // stop Visual mode
4257071d4279SBram Moolenaar #ifdef FEAT_GUI
4258071d4279SBram Moolenaar need_mouse_correct = TRUE;
4259071d4279SBram Moolenaar #endif
4260071d4279SBram Moolenaar
4261476c0db0SBram Moolenaar // Find an existing quickfix window, or open a new one.
4262e1004401SBram Moolenaar if (cmdmod.cmod_tab == 0)
4263476c0db0SBram Moolenaar status = qf_goto_cwindow(qi, eap->addr_count != 0, height,
4264e1004401SBram Moolenaar cmdmod.cmod_split & WSP_VERT);
4265476c0db0SBram Moolenaar if (status == FAIL)
4266476c0db0SBram Moolenaar if (qf_open_new_cwindow(qi, height) == FAIL)
42679f84ded3SBram Moolenaar {
42689f84ded3SBram Moolenaar decr_quickfix_busy();
4269476c0db0SBram Moolenaar return;
42709f84ded3SBram Moolenaar }
4271071d4279SBram Moolenaar
42724aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
4273108e7b42SBram Moolenaar qf_set_title_var(qfl);
42749f84ded3SBram Moolenaar // Save the current index here, as updating the quickfix buffer may free
42759f84ded3SBram Moolenaar // the quickfix list
42769f84ded3SBram Moolenaar lnum = qfl->qf_index;
427781278efaSBram Moolenaar
4278476c0db0SBram Moolenaar // Fill the buffer with the quickfix list.
42797ba5a7efSBram Moolenaar qf_fill_buffer(qfl, curbuf, NULL, curwin->w_id);
4280071d4279SBram Moolenaar
42819f84ded3SBram Moolenaar decr_quickfix_busy();
42829f84ded3SBram Moolenaar
42839f84ded3SBram Moolenaar curwin->w_cursor.lnum = lnum;
4284071d4279SBram Moolenaar curwin->w_cursor.col = 0;
4285071d4279SBram Moolenaar check_cursor();
4286476c0db0SBram Moolenaar update_topline(); // scroll to show the line
4287071d4279SBram Moolenaar }
4288071d4279SBram Moolenaar
4289071d4279SBram Moolenaar /*
4290dcb17001SBram Moolenaar * Move the cursor in the quickfix window to "lnum".
4291dcb17001SBram Moolenaar */
4292dcb17001SBram Moolenaar static void
qf_win_goto(win_T * win,linenr_T lnum)4293dcb17001SBram Moolenaar qf_win_goto(win_T *win, linenr_T lnum)
4294dcb17001SBram Moolenaar {
4295dcb17001SBram Moolenaar win_T *old_curwin = curwin;
4296dcb17001SBram Moolenaar
4297dcb17001SBram Moolenaar curwin = win;
4298dcb17001SBram Moolenaar curbuf = win->w_buffer;
4299dcb17001SBram Moolenaar curwin->w_cursor.lnum = lnum;
4300dcb17001SBram Moolenaar curwin->w_cursor.col = 0;
4301dcb17001SBram Moolenaar curwin->w_cursor.coladd = 0;
4302dcb17001SBram Moolenaar curwin->w_curswant = 0;
430300bf8cd2SBram Moolenaar update_topline(); // scroll to show the line
4304dcb17001SBram Moolenaar redraw_later(VALID);
430500bf8cd2SBram Moolenaar curwin->w_redr_status = TRUE; // update ruler
4306dcb17001SBram Moolenaar curwin = old_curwin;
4307dcb17001SBram Moolenaar curbuf = curwin->w_buffer;
4308dcb17001SBram Moolenaar }
4309dcb17001SBram Moolenaar
4310dcb17001SBram Moolenaar /*
4311537ef084SBram Moolenaar * :cbottom/:lbottom commands.
4312dcb17001SBram Moolenaar */
4313dcb17001SBram Moolenaar void
ex_cbottom(exarg_T * eap)431439665959SBram Moolenaar ex_cbottom(exarg_T *eap)
4315dcb17001SBram Moolenaar {
431687f59b09SBram Moolenaar qf_info_T *qi;
4317537ef084SBram Moolenaar win_T *win;
4318dcb17001SBram Moolenaar
431987f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
4320537ef084SBram Moolenaar return;
4321537ef084SBram Moolenaar
4322537ef084SBram Moolenaar win = qf_find_win(qi);
4323dcb17001SBram Moolenaar if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count)
4324dcb17001SBram Moolenaar qf_win_goto(win, win->w_buffer->b_ml.ml_line_count);
4325dcb17001SBram Moolenaar }
4326dcb17001SBram Moolenaar
4327dcb17001SBram Moolenaar /*
4328071d4279SBram Moolenaar * Return the number of the current entry (line number in the quickfix
4329071d4279SBram Moolenaar * window).
4330071d4279SBram Moolenaar */
4331071d4279SBram Moolenaar linenr_T
qf_current_entry(win_T * wp)433205540976SBram Moolenaar qf_current_entry(win_T *wp)
4333071d4279SBram Moolenaar {
4334d12f5c17SBram Moolenaar qf_info_T *qi = &ql_info;
4335d12f5c17SBram Moolenaar
4336d12f5c17SBram Moolenaar if (IS_LL_WINDOW(wp))
433700bf8cd2SBram Moolenaar // In the location list window, use the referenced location list
4338d12f5c17SBram Moolenaar qi = wp->w_llist_ref;
4339d12f5c17SBram Moolenaar
43404aa47b28SBram Moolenaar return qf_get_curlist(qi)->qf_index;
4341071d4279SBram Moolenaar }
4342071d4279SBram Moolenaar
4343071d4279SBram Moolenaar /*
4344071d4279SBram Moolenaar * Update the cursor position in the quickfix window to the current error.
4345071d4279SBram Moolenaar * Return TRUE if there is a quickfix window.
4346071d4279SBram Moolenaar */
4347071d4279SBram Moolenaar static int
qf_win_pos_update(qf_info_T * qi,int old_qf_index)434805540976SBram Moolenaar qf_win_pos_update(
434905540976SBram Moolenaar qf_info_T *qi,
435000bf8cd2SBram Moolenaar int old_qf_index) // previous qf_index or zero
4351071d4279SBram Moolenaar {
4352071d4279SBram Moolenaar win_T *win;
43534aa47b28SBram Moolenaar int qf_index = qf_get_curlist(qi)->qf_index;
4354071d4279SBram Moolenaar
435500bf8cd2SBram Moolenaar // Put the cursor on the current error in the quickfix window, so that
435600bf8cd2SBram Moolenaar // it's viewable.
4357d12f5c17SBram Moolenaar win = qf_find_win(qi);
4358071d4279SBram Moolenaar if (win != NULL
4359071d4279SBram Moolenaar && qf_index <= win->w_buffer->b_ml.ml_line_count
4360071d4279SBram Moolenaar && old_qf_index != qf_index)
4361071d4279SBram Moolenaar {
4362071d4279SBram Moolenaar if (qf_index > old_qf_index)
4363071d4279SBram Moolenaar {
4364dcb17001SBram Moolenaar win->w_redraw_top = old_qf_index;
4365dcb17001SBram Moolenaar win->w_redraw_bot = qf_index;
4366071d4279SBram Moolenaar }
4367071d4279SBram Moolenaar else
4368071d4279SBram Moolenaar {
4369dcb17001SBram Moolenaar win->w_redraw_top = qf_index;
4370dcb17001SBram Moolenaar win->w_redraw_bot = old_qf_index;
4371071d4279SBram Moolenaar }
4372dcb17001SBram Moolenaar qf_win_goto(win, qf_index);
4373071d4279SBram Moolenaar }
4374071d4279SBram Moolenaar return win != NULL;
4375071d4279SBram Moolenaar }
4376071d4279SBram Moolenaar
4377071d4279SBram Moolenaar /*
43789c102387SBram Moolenaar * Check whether the given window is displaying the specified quickfix/location
4379fe15b7dfSBram Moolenaar * stack.
43809c102387SBram Moolenaar */
43819c102387SBram Moolenaar static int
is_qf_win(win_T * win,qf_info_T * qi)438205540976SBram Moolenaar is_qf_win(win_T *win, qf_info_T *qi)
43839c102387SBram Moolenaar {
438400bf8cd2SBram Moolenaar // A window displaying the quickfix buffer will have the w_llist_ref field
438500bf8cd2SBram Moolenaar // set to NULL.
438600bf8cd2SBram Moolenaar // A window displaying a location list buffer will have the w_llist_ref
438700bf8cd2SBram Moolenaar // pointing to the location list.
43889c102387SBram Moolenaar if (bt_quickfix(win->w_buffer))
43894d77c65aSBram Moolenaar if ((IS_QF_STACK(qi) && win->w_llist_ref == NULL)
43904d77c65aSBram Moolenaar || (IS_LL_STACK(qi) && win->w_llist_ref == qi))
43919c102387SBram Moolenaar return TRUE;
43929c102387SBram Moolenaar
43939c102387SBram Moolenaar return FALSE;
43949c102387SBram Moolenaar }
43959c102387SBram Moolenaar
43969c102387SBram Moolenaar /*
4397fe15b7dfSBram Moolenaar * Find a window displaying the quickfix/location stack 'qi'
43982ec364e9SBram Moolenaar * Only searches in the current tabpage.
4399d12f5c17SBram Moolenaar */
4400d12f5c17SBram Moolenaar static win_T *
qf_find_win(qf_info_T * qi)440105540976SBram Moolenaar qf_find_win(qf_info_T *qi)
4402d12f5c17SBram Moolenaar {
4403d12f5c17SBram Moolenaar win_T *win;
4404d12f5c17SBram Moolenaar
4405d12f5c17SBram Moolenaar FOR_ALL_WINDOWS(win)
44069c102387SBram Moolenaar if (is_qf_win(win, qi))
4407d12f5c17SBram Moolenaar return win;
44082ec364e9SBram Moolenaar return NULL;
4409d12f5c17SBram Moolenaar }
4410d12f5c17SBram Moolenaar
4411d12f5c17SBram Moolenaar /*
44129c102387SBram Moolenaar * Find a quickfix buffer.
44139c102387SBram Moolenaar * Searches in windows opened in all the tabs.
4414071d4279SBram Moolenaar */
4415071d4279SBram Moolenaar static buf_T *
qf_find_buf(qf_info_T * qi)441605540976SBram Moolenaar qf_find_buf(qf_info_T *qi)
4417071d4279SBram Moolenaar {
44189c102387SBram Moolenaar tabpage_T *tp;
4419d12f5c17SBram Moolenaar win_T *win;
4420071d4279SBram Moolenaar
4421ee8188fcSBram Moolenaar if (qi->qf_bufnr != INVALID_QFBUFNR)
4422ee8188fcSBram Moolenaar {
4423ee8188fcSBram Moolenaar buf_T *qfbuf;
4424ee8188fcSBram Moolenaar qfbuf = buflist_findnr(qi->qf_bufnr);
4425ee8188fcSBram Moolenaar if (qfbuf != NULL)
4426ee8188fcSBram Moolenaar return qfbuf;
4427ee8188fcSBram Moolenaar // buffer is no longer present
4428ee8188fcSBram Moolenaar qi->qf_bufnr = INVALID_QFBUFNR;
4429ee8188fcSBram Moolenaar }
4430ee8188fcSBram Moolenaar
44319c102387SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, win)
44329c102387SBram Moolenaar if (is_qf_win(win, qi))
44339c102387SBram Moolenaar return win->w_buffer;
4434d12f5c17SBram Moolenaar
44359c102387SBram Moolenaar return NULL;
4436071d4279SBram Moolenaar }
4437071d4279SBram Moolenaar
4438071d4279SBram Moolenaar /*
4439d43906d2SBram Moolenaar * Process the 'quickfixtextfunc' option value.
4440*777175b0SYegappan Lakshmanan * Returns OK or FAIL.
4441d43906d2SBram Moolenaar */
4442d43906d2SBram Moolenaar int
qf_process_qftf_option(void)4443d43906d2SBram Moolenaar qf_process_qftf_option(void)
4444d43906d2SBram Moolenaar {
4445*777175b0SYegappan Lakshmanan return option_set_callback_func(p_qftf, &qftf_cb);
4446d43906d2SBram Moolenaar }
4447d43906d2SBram Moolenaar
4448d43906d2SBram Moolenaar /*
4449530bed99SBram Moolenaar * Update the w:quickfix_title variable in the quickfix/location list window in
4450530bed99SBram Moolenaar * all the tab pages.
4451d823fa91SBram Moolenaar */
4452d823fa91SBram Moolenaar static void
qf_update_win_titlevar(qf_info_T * qi)4453d823fa91SBram Moolenaar qf_update_win_titlevar(qf_info_T *qi)
4454d823fa91SBram Moolenaar {
4455530bed99SBram Moolenaar qf_list_T *qfl = qf_get_curlist(qi);
4456530bed99SBram Moolenaar tabpage_T *tp;
4457d823fa91SBram Moolenaar win_T *win;
4458530bed99SBram Moolenaar win_T *save_curwin = curwin;
4459d823fa91SBram Moolenaar
4460530bed99SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, win)
4461d823fa91SBram Moolenaar {
4462530bed99SBram Moolenaar if (is_qf_win(win, qi))
4463530bed99SBram Moolenaar {
4464d823fa91SBram Moolenaar curwin = win;
4465530bed99SBram Moolenaar qf_set_title_var(qfl);
4466d823fa91SBram Moolenaar }
4467d823fa91SBram Moolenaar }
4468530bed99SBram Moolenaar curwin = save_curwin;
4469530bed99SBram Moolenaar }
4470d823fa91SBram Moolenaar
4471d823fa91SBram Moolenaar /*
4472071d4279SBram Moolenaar * Find the quickfix buffer. If it exists, update the contents.
4473071d4279SBram Moolenaar */
4474071d4279SBram Moolenaar static void
qf_update_buffer(qf_info_T * qi,qfline_T * old_last)4475864293abSBram Moolenaar qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
4476071d4279SBram Moolenaar {
4477071d4279SBram Moolenaar buf_T *buf;
4478c95e3263SBram Moolenaar win_T *win;
4479071d4279SBram Moolenaar aco_save_T aco;
4480071d4279SBram Moolenaar
448100bf8cd2SBram Moolenaar // Check if a buffer for the quickfix list exists. Update it.
4482d12f5c17SBram Moolenaar buf = qf_find_buf(qi);
4483071d4279SBram Moolenaar if (buf != NULL)
4484071d4279SBram Moolenaar {
4485864293abSBram Moolenaar linenr_T old_line_count = buf->b_ml.ml_line_count;
44867ba5a7efSBram Moolenaar int qf_winid = 0;
44877ba5a7efSBram Moolenaar
44887ba5a7efSBram Moolenaar if (IS_LL_STACK(qi))
4489ad52f96aSYegappan Lakshmanan {
4490ad52f96aSYegappan Lakshmanan if (curwin->w_llist == qi)
4491ad52f96aSYegappan Lakshmanan win = curwin;
4492ad52f96aSYegappan Lakshmanan else
4493ad52f96aSYegappan Lakshmanan {
4494ad52f96aSYegappan Lakshmanan win = qf_find_win_with_loclist(qi);
4495ad52f96aSYegappan Lakshmanan if (win == NULL)
4496ad52f96aSYegappan Lakshmanan return;
4497ad52f96aSYegappan Lakshmanan }
4498ad52f96aSYegappan Lakshmanan qf_winid = win->w_id;
4499ad52f96aSYegappan Lakshmanan }
4500864293abSBram Moolenaar
4501864293abSBram Moolenaar if (old_last == NULL)
450200bf8cd2SBram Moolenaar // set curwin/curbuf to buf and save a few things
4503071d4279SBram Moolenaar aucmd_prepbuf(&aco, buf);
4504071d4279SBram Moolenaar
4505d823fa91SBram Moolenaar qf_update_win_titlevar(qi);
4506c95e3263SBram Moolenaar
45077ba5a7efSBram Moolenaar qf_fill_buffer(qf_get_curlist(qi), buf, old_last, qf_winid);
4508a8788f4dSBram Moolenaar ++CHANGEDTICK(buf);
4509864293abSBram Moolenaar
4510864293abSBram Moolenaar if (old_last == NULL)
4511864293abSBram Moolenaar {
4512864293abSBram Moolenaar (void)qf_win_pos_update(qi, 0);
45136920c72dSBram Moolenaar
451400bf8cd2SBram Moolenaar // restore curwin/curbuf and a few other things
4515071d4279SBram Moolenaar aucmd_restbuf(&aco);
4516864293abSBram Moolenaar }
4517071d4279SBram Moolenaar
451800bf8cd2SBram Moolenaar // Only redraw when added lines are visible. This avoids flickering
451900bf8cd2SBram Moolenaar // when the added lines are not visible.
4520864293abSBram Moolenaar if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline)
4521864293abSBram Moolenaar redraw_buf_later(buf, NOT_VALID);
4522071d4279SBram Moolenaar }
4523071d4279SBram Moolenaar }
4524071d4279SBram Moolenaar
452581278efaSBram Moolenaar /*
45266053f2d2SBram Moolenaar * Add an error line to the quickfix buffer.
4527071d4279SBram Moolenaar */
45286053f2d2SBram Moolenaar static int
qf_buf_add_line(buf_T * buf,linenr_T lnum,qfline_T * qfp,char_u * dirname,int first_bufline,char_u * qftf_str)4529858ba06dSBram Moolenaar qf_buf_add_line(
4530858ba06dSBram Moolenaar buf_T *buf, // quickfix window buffer
4531858ba06dSBram Moolenaar linenr_T lnum,
4532858ba06dSBram Moolenaar qfline_T *qfp,
45337ba5a7efSBram Moolenaar char_u *dirname,
45348ec92c97SBram Moolenaar int first_bufline,
453500e260bbSBram Moolenaar char_u *qftf_str)
4536071d4279SBram Moolenaar {
4537071d4279SBram Moolenaar int len;
45386053f2d2SBram Moolenaar buf_T *errbuf;
4539071d4279SBram Moolenaar
4540d43906d2SBram Moolenaar // If the 'quickfixtextfunc' function returned an non-empty custom string
4541d43906d2SBram Moolenaar // for this entry, then use it.
4542d43906d2SBram Moolenaar if (qftf_str != NULL && *qftf_str != NUL)
454300e260bbSBram Moolenaar vim_strncpy(IObuff, qftf_str, IOSIZE - 1);
4544858ba06dSBram Moolenaar else
4545858ba06dSBram Moolenaar {
4546d76ce852SBram Moolenaar if (qfp->qf_module != NULL)
4547d76ce852SBram Moolenaar {
4548a106e6cdSBram Moolenaar vim_strncpy(IObuff, qfp->qf_module, IOSIZE - 1);
4549d76ce852SBram Moolenaar len = (int)STRLEN(IObuff);
4550d76ce852SBram Moolenaar }
4551d76ce852SBram Moolenaar else if (qfp->qf_fnum != 0
4552071d4279SBram Moolenaar && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
4553071d4279SBram Moolenaar && errbuf->b_fname != NULL)
4554071d4279SBram Moolenaar {
455500bf8cd2SBram Moolenaar if (qfp->qf_type == 1) // :helpgrep
4556a106e6cdSBram Moolenaar vim_strncpy(IObuff, gettail(errbuf->b_fname), IOSIZE - 1);
4557071d4279SBram Moolenaar else
4558a796d46fSBram Moolenaar {
45598ec92c97SBram Moolenaar // Shorten the file name if not done already.
45608ec92c97SBram Moolenaar // For optimization, do this only for the first entry in a
45618ec92c97SBram Moolenaar // buffer.
45628ec92c97SBram Moolenaar if (first_bufline && (errbuf->b_sfname == NULL
45638ec92c97SBram Moolenaar || mch_isFullName(errbuf->b_sfname)))
4564a796d46fSBram Moolenaar {
4565a796d46fSBram Moolenaar if (*dirname == NUL)
4566a796d46fSBram Moolenaar mch_dirname(dirname, MAXPATHL);
4567a796d46fSBram Moolenaar shorten_buf_fname(errbuf, dirname, FALSE);
4568a796d46fSBram Moolenaar }
4569a106e6cdSBram Moolenaar vim_strncpy(IObuff, errbuf->b_fname, IOSIZE - 1);
4570a796d46fSBram Moolenaar }
4571071d4279SBram Moolenaar len = (int)STRLEN(IObuff);
4572071d4279SBram Moolenaar }
4573071d4279SBram Moolenaar else
4574071d4279SBram Moolenaar len = 0;
4575a106e6cdSBram Moolenaar
4576a106e6cdSBram Moolenaar if (len < IOSIZE - 1)
4577071d4279SBram Moolenaar IObuff[len++] = '|';
4578071d4279SBram Moolenaar
4579071d4279SBram Moolenaar if (qfp->qf_lnum > 0)
4580071d4279SBram Moolenaar {
45816864efa5Sthinca qf_range_text(qfp, IObuff + len, IOSIZE - len);
4582071d4279SBram Moolenaar len += (int)STRLEN(IObuff + len);
4583071d4279SBram Moolenaar
4584a106e6cdSBram Moolenaar vim_snprintf((char *)IObuff + len, IOSIZE - len, "%s",
4585071d4279SBram Moolenaar (char *)qf_types(qfp->qf_type, qfp->qf_nr));
4586071d4279SBram Moolenaar len += (int)STRLEN(IObuff + len);
4587071d4279SBram Moolenaar }
458868b76a69SBram Moolenaar else if (qfp->qf_pattern != NULL)
458968b76a69SBram Moolenaar {
459068b76a69SBram Moolenaar qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
459168b76a69SBram Moolenaar len += (int)STRLEN(IObuff + len);
459268b76a69SBram Moolenaar }
4593a106e6cdSBram Moolenaar if (len < IOSIZE - 2)
4594a106e6cdSBram Moolenaar {
4595071d4279SBram Moolenaar IObuff[len++] = '|';
4596071d4279SBram Moolenaar IObuff[len++] = ' ';
4597a106e6cdSBram Moolenaar }
4598071d4279SBram Moolenaar
459900bf8cd2SBram Moolenaar // Remove newlines and leading whitespace from the text.
460000bf8cd2SBram Moolenaar // For an unrecognized line keep the indent, the compiler may
460100bf8cd2SBram Moolenaar // mark a word with ^^^^.
4602071d4279SBram Moolenaar qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
4603071d4279SBram Moolenaar IObuff + len, IOSIZE - len);
4604858ba06dSBram Moolenaar }
4605071d4279SBram Moolenaar
4606864293abSBram Moolenaar if (ml_append_buf(buf, lnum, IObuff,
4607864293abSBram Moolenaar (colnr_T)STRLEN(IObuff) + 1, FALSE) == FAIL)
46086053f2d2SBram Moolenaar return FAIL;
46096053f2d2SBram Moolenaar
46106053f2d2SBram Moolenaar return OK;
46116053f2d2SBram Moolenaar }
46126053f2d2SBram Moolenaar
4613d43906d2SBram Moolenaar /*
4614d43906d2SBram Moolenaar * Call the 'quickfixtextfunc' function to get the list of lines to display in
4615d43906d2SBram Moolenaar * the quickfix window for the entries 'start_idx' to 'end_idx'.
4616d43906d2SBram Moolenaar */
461700e260bbSBram Moolenaar static list_T *
call_qftf_func(qf_list_T * qfl,int qf_winid,long start_idx,long end_idx)461800e260bbSBram Moolenaar call_qftf_func(qf_list_T *qfl, int qf_winid, long start_idx, long end_idx)
461900e260bbSBram Moolenaar {
4620d43906d2SBram Moolenaar callback_T *cb = &qftf_cb;
462100e260bbSBram Moolenaar list_T *qftf_list = NULL;
462200e260bbSBram Moolenaar
462300e260bbSBram Moolenaar // If 'quickfixtextfunc' is set, then use the user-supplied function to get
462400e260bbSBram Moolenaar // the text to display. Use the local value of 'quickfixtextfunc' if it is
462500e260bbSBram Moolenaar // set.
4626d43906d2SBram Moolenaar if (qfl->qftf_cb.cb_name != NULL)
4627d43906d2SBram Moolenaar cb = &qfl->qftf_cb;
4628d43906d2SBram Moolenaar if (cb != NULL && cb->cb_name != NULL)
462900e260bbSBram Moolenaar {
463000e260bbSBram Moolenaar typval_T args[1];
463100e260bbSBram Moolenaar dict_T *d;
4632d43906d2SBram Moolenaar typval_T rettv;
463300e260bbSBram Moolenaar
463400e260bbSBram Moolenaar // create the dict argument
463500e260bbSBram Moolenaar if ((d = dict_alloc_lock(VAR_FIXED)) == NULL)
463600e260bbSBram Moolenaar return NULL;
463700e260bbSBram Moolenaar dict_add_number(d, "quickfix", (long)IS_QF_LIST(qfl));
463800e260bbSBram Moolenaar dict_add_number(d, "winid", (long)qf_winid);
463900e260bbSBram Moolenaar dict_add_number(d, "id", (long)qfl->qf_id);
464000e260bbSBram Moolenaar dict_add_number(d, "start_idx", start_idx);
464100e260bbSBram Moolenaar dict_add_number(d, "end_idx", end_idx);
464200e260bbSBram Moolenaar ++d->dv_refcount;
464300e260bbSBram Moolenaar args[0].v_type = VAR_DICT;
464400e260bbSBram Moolenaar args[0].vval.v_dict = d;
464500e260bbSBram Moolenaar
4646d43906d2SBram Moolenaar qftf_list = NULL;
4647d43906d2SBram Moolenaar if (call_callback(cb, 0, &rettv, 1, args) != FAIL)
4648d43906d2SBram Moolenaar {
4649d43906d2SBram Moolenaar if (rettv.v_type == VAR_LIST)
4650d43906d2SBram Moolenaar {
4651d43906d2SBram Moolenaar qftf_list = rettv.vval.v_list;
4652d43906d2SBram Moolenaar qftf_list->lv_refcount++;
4653d43906d2SBram Moolenaar }
4654d43906d2SBram Moolenaar clear_tv(&rettv);
4655d43906d2SBram Moolenaar }
4656d43906d2SBram Moolenaar dict_unref(d);
465700e260bbSBram Moolenaar }
465800e260bbSBram Moolenaar
465900e260bbSBram Moolenaar return qftf_list;
466000e260bbSBram Moolenaar }
466100e260bbSBram Moolenaar
46626053f2d2SBram Moolenaar /*
46636053f2d2SBram Moolenaar * Fill current buffer with quickfix errors, replacing any previous contents.
46646053f2d2SBram Moolenaar * curbuf must be the quickfix buffer!
46656053f2d2SBram Moolenaar * If "old_last" is not NULL append the items after this one.
46666053f2d2SBram Moolenaar * When "old_last" is NULL then "buf" must equal "curbuf"! Because
46676053f2d2SBram Moolenaar * ml_delete() is used and autocommands will be triggered.
46686053f2d2SBram Moolenaar */
46696053f2d2SBram Moolenaar static void
qf_fill_buffer(qf_list_T * qfl,buf_T * buf,qfline_T * old_last,int qf_winid)46707ba5a7efSBram Moolenaar qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int qf_winid)
46716053f2d2SBram Moolenaar {
46726053f2d2SBram Moolenaar linenr_T lnum;
46736053f2d2SBram Moolenaar qfline_T *qfp;
46746053f2d2SBram Moolenaar int old_KeyTyped = KeyTyped;
467500e260bbSBram Moolenaar list_T *qftf_list = NULL;
467600e260bbSBram Moolenaar listitem_T *qftf_li = NULL;
46776053f2d2SBram Moolenaar
46786053f2d2SBram Moolenaar if (old_last == NULL)
46796053f2d2SBram Moolenaar {
46806053f2d2SBram Moolenaar if (buf != curbuf)
46816053f2d2SBram Moolenaar {
46826053f2d2SBram Moolenaar internal_error("qf_fill_buffer()");
46836053f2d2SBram Moolenaar return;
46846053f2d2SBram Moolenaar }
46856053f2d2SBram Moolenaar
468600bf8cd2SBram Moolenaar // delete all existing lines
46876053f2d2SBram Moolenaar while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0)
4688ca70c07bSBram Moolenaar (void)ml_delete((linenr_T)1);
46896053f2d2SBram Moolenaar }
46906053f2d2SBram Moolenaar
469100bf8cd2SBram Moolenaar // Check if there is anything to display
46924aa47b28SBram Moolenaar if (qfl != NULL)
46936053f2d2SBram Moolenaar {
46946053f2d2SBram Moolenaar char_u dirname[MAXPATHL];
4695d43906d2SBram Moolenaar int invalid_val = FALSE;
46968ec92c97SBram Moolenaar int prev_bufnr = -1;
46976053f2d2SBram Moolenaar
46986053f2d2SBram Moolenaar *dirname = NUL;
46996053f2d2SBram Moolenaar
470000bf8cd2SBram Moolenaar // Add one line for each error
47012ce77903SBram Moolenaar if (old_last == NULL)
47026053f2d2SBram Moolenaar {
4703108e7b42SBram Moolenaar qfp = qfl->qf_start;
47046053f2d2SBram Moolenaar lnum = 0;
47056053f2d2SBram Moolenaar }
47066053f2d2SBram Moolenaar else
47076053f2d2SBram Moolenaar {
47082ce77903SBram Moolenaar if (old_last->qf_next != NULL)
47096053f2d2SBram Moolenaar qfp = old_last->qf_next;
47102ce77903SBram Moolenaar else
47112ce77903SBram Moolenaar qfp = old_last;
47126053f2d2SBram Moolenaar lnum = buf->b_ml.ml_line_count;
47136053f2d2SBram Moolenaar }
471400e260bbSBram Moolenaar
471500e260bbSBram Moolenaar qftf_list = call_qftf_func(qfl, qf_winid, (long)(lnum + 1),
471600e260bbSBram Moolenaar (long)qfl->qf_count);
471700e260bbSBram Moolenaar if (qftf_list != NULL)
471800e260bbSBram Moolenaar qftf_li = qftf_list->lv_first;
471900e260bbSBram Moolenaar
4720108e7b42SBram Moolenaar while (lnum < qfl->qf_count)
47216053f2d2SBram Moolenaar {
472200e260bbSBram Moolenaar char_u *qftf_str = NULL;
472300e260bbSBram Moolenaar
4724d43906d2SBram Moolenaar // Use the text supplied by the user defined function (if any).
4725d43906d2SBram Moolenaar // If the returned value is not string, then ignore the rest
4726d43906d2SBram Moolenaar // of the returned values and use the default.
4727d43906d2SBram Moolenaar if (qftf_li != NULL && !invalid_val)
4728d43906d2SBram Moolenaar {
472900e260bbSBram Moolenaar qftf_str = tv_get_string_chk(&qftf_li->li_tv);
4730d43906d2SBram Moolenaar if (qftf_str == NULL)
4731d43906d2SBram Moolenaar invalid_val = TRUE;
4732d43906d2SBram Moolenaar }
473300e260bbSBram Moolenaar
47348ec92c97SBram Moolenaar if (qf_buf_add_line(buf, lnum, qfp, dirname,
47358ec92c97SBram Moolenaar prev_bufnr != qfp->qf_fnum, qftf_str) == FAIL)
4736071d4279SBram Moolenaar break;
47376053f2d2SBram Moolenaar
47388ec92c97SBram Moolenaar prev_bufnr = qfp->qf_fnum;
4739864293abSBram Moolenaar ++lnum;
4740071d4279SBram Moolenaar qfp = qfp->qf_next;
474183e6d7acSBram Moolenaar if (qfp == NULL)
474283e6d7acSBram Moolenaar break;
474300e260bbSBram Moolenaar
474400e260bbSBram Moolenaar if (qftf_li != NULL)
474500e260bbSBram Moolenaar qftf_li = qftf_li->li_next;
4746071d4279SBram Moolenaar }
4747864293abSBram Moolenaar
4748864293abSBram Moolenaar if (old_last == NULL)
474900bf8cd2SBram Moolenaar // Delete the empty line which is now at the end
4750ca70c07bSBram Moolenaar (void)ml_delete(lnum + 1);
4751071d4279SBram Moolenaar }
4752071d4279SBram Moolenaar
475300bf8cd2SBram Moolenaar // correct cursor position
4754071d4279SBram Moolenaar check_lnums(TRUE);
4755071d4279SBram Moolenaar
4756864293abSBram Moolenaar if (old_last == NULL)
4757864293abSBram Moolenaar {
475800bf8cd2SBram Moolenaar // Set the 'filetype' to "qf" each time after filling the buffer.
475900bf8cd2SBram Moolenaar // This resembles reading a file into a buffer, it's more logical when
476000bf8cd2SBram Moolenaar // using autocommands.
47611814183bSBram Moolenaar ++curbuf_lock;
4762071d4279SBram Moolenaar set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL);
4763071d4279SBram Moolenaar curbuf->b_p_ma = FALSE;
4764071d4279SBram Moolenaar
476500bf8cd2SBram Moolenaar keep_filetype = TRUE; // don't detect 'filetype'
4766071d4279SBram Moolenaar apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL,
4767071d4279SBram Moolenaar FALSE, curbuf);
4768071d4279SBram Moolenaar apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL,
4769071d4279SBram Moolenaar FALSE, curbuf);
477004c0f8a9SBram Moolenaar keep_filetype = FALSE;
47711814183bSBram Moolenaar --curbuf_lock;
4772f2bd8ef2SBram Moolenaar
477300bf8cd2SBram Moolenaar // make sure it will be redrawn
4774071d4279SBram Moolenaar redraw_curbuf_later(NOT_VALID);
4775864293abSBram Moolenaar }
4776071d4279SBram Moolenaar
477700bf8cd2SBram Moolenaar // Restore KeyTyped, setting 'filetype' may reset it.
4778071d4279SBram Moolenaar KeyTyped = old_KeyTyped;
4779071d4279SBram Moolenaar }
4780071d4279SBram Moolenaar
478118cebf44SBram Moolenaar /*
478218cebf44SBram Moolenaar * For every change made to the quickfix list, update the changed tick.
478318cebf44SBram Moolenaar */
4784b254af31SBram Moolenaar static void
qf_list_changed(qf_list_T * qfl)4785108e7b42SBram Moolenaar qf_list_changed(qf_list_T *qfl)
4786b254af31SBram Moolenaar {
4787108e7b42SBram Moolenaar qfl->qf_changedtick++;
4788b254af31SBram Moolenaar }
4789b254af31SBram Moolenaar
4790071d4279SBram Moolenaar /*
4791531b9a3aSBram Moolenaar * Return the quickfix/location list number with the given identifier.
4792531b9a3aSBram Moolenaar * Returns -1 if list is not found.
4793531b9a3aSBram Moolenaar */
4794531b9a3aSBram Moolenaar static int
qf_id2nr(qf_info_T * qi,int_u qfid)4795531b9a3aSBram Moolenaar qf_id2nr(qf_info_T *qi, int_u qfid)
4796531b9a3aSBram Moolenaar {
4797531b9a3aSBram Moolenaar int qf_idx;
4798531b9a3aSBram Moolenaar
4799531b9a3aSBram Moolenaar for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++)
4800531b9a3aSBram Moolenaar if (qi->qf_lists[qf_idx].qf_id == qfid)
4801531b9a3aSBram Moolenaar return qf_idx;
4802531b9a3aSBram Moolenaar return INVALID_QFIDX;
4803531b9a3aSBram Moolenaar }
4804531b9a3aSBram Moolenaar
4805531b9a3aSBram Moolenaar /*
480638efd1d1SBram Moolenaar * If the current list is not "save_qfid" and we can find the list with that ID
480738efd1d1SBram Moolenaar * then make it the current list.
480838efd1d1SBram Moolenaar * This is used when autocommands may have changed the current list.
480990f1e2b7SBram Moolenaar * Returns OK if successfully restored the list. Returns FAIL if the list with
481090f1e2b7SBram Moolenaar * the specified identifier (save_qfid) is not found in the stack.
481138efd1d1SBram Moolenaar */
481290f1e2b7SBram Moolenaar static int
qf_restore_list(qf_info_T * qi,int_u save_qfid)481338efd1d1SBram Moolenaar qf_restore_list(qf_info_T *qi, int_u save_qfid)
481438efd1d1SBram Moolenaar {
481538efd1d1SBram Moolenaar int curlist;
481638efd1d1SBram Moolenaar
48174aa47b28SBram Moolenaar if (qf_get_curlist(qi)->qf_id != save_qfid)
481838efd1d1SBram Moolenaar {
481938efd1d1SBram Moolenaar curlist = qf_id2nr(qi, save_qfid);
482090f1e2b7SBram Moolenaar if (curlist < 0)
482190f1e2b7SBram Moolenaar // list is not present
482290f1e2b7SBram Moolenaar return FAIL;
482338efd1d1SBram Moolenaar qi->qf_curlist = curlist;
482438efd1d1SBram Moolenaar }
482590f1e2b7SBram Moolenaar return OK;
482638efd1d1SBram Moolenaar }
482738efd1d1SBram Moolenaar
482838efd1d1SBram Moolenaar /*
48298d8a65e3SBram Moolenaar * Jump to the first entry if there is one.
48308d8a65e3SBram Moolenaar */
48318d8a65e3SBram Moolenaar static void
qf_jump_first(qf_info_T * qi,int_u save_qfid,int forceit)48328d8a65e3SBram Moolenaar qf_jump_first(qf_info_T *qi, int_u save_qfid, int forceit)
48338d8a65e3SBram Moolenaar {
483490f1e2b7SBram Moolenaar if (qf_restore_list(qi, save_qfid) == FAIL)
483590f1e2b7SBram Moolenaar return;
48368d8a65e3SBram Moolenaar
483790f1e2b7SBram Moolenaar // Autocommands might have cleared the list, check for that.
48380398e00aSBram Moolenaar if (!qf_list_empty(qf_get_curlist(qi)))
48398d8a65e3SBram Moolenaar qf_jump(qi, 0, 0, forceit);
48408d8a65e3SBram Moolenaar }
48418d8a65e3SBram Moolenaar
48428d8a65e3SBram Moolenaar /*
484386b68359SBram Moolenaar * Return TRUE when using ":vimgrep" for ":grep".
484486b68359SBram Moolenaar */
484586b68359SBram Moolenaar int
grep_internal(cmdidx_T cmdidx)484605540976SBram Moolenaar grep_internal(cmdidx_T cmdidx)
484786b68359SBram Moolenaar {
4848754b5608SBram Moolenaar return ((cmdidx == CMD_grep
4849754b5608SBram Moolenaar || cmdidx == CMD_lgrep
4850754b5608SBram Moolenaar || cmdidx == CMD_grepadd
4851754b5608SBram Moolenaar || cmdidx == CMD_lgrepadd)
485286b68359SBram Moolenaar && STRCMP("internal",
485386b68359SBram Moolenaar *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
485486b68359SBram Moolenaar }
485586b68359SBram Moolenaar
485686b68359SBram Moolenaar /*
4857b434ae2aSBram Moolenaar * Return the make/grep autocmd name.
4858071d4279SBram Moolenaar */
4859b434ae2aSBram Moolenaar static char_u *
make_get_auname(cmdidx_T cmdidx)4860b434ae2aSBram Moolenaar make_get_auname(cmdidx_T cmdidx)
4861071d4279SBram Moolenaar {
4862b434ae2aSBram Moolenaar switch (cmdidx)
4863d88e02deSBram Moolenaar {
4864b434ae2aSBram Moolenaar case CMD_make: return (char_u *)"make";
4865b434ae2aSBram Moolenaar case CMD_lmake: return (char_u *)"lmake";
4866b434ae2aSBram Moolenaar case CMD_grep: return (char_u *)"grep";
4867b434ae2aSBram Moolenaar case CMD_lgrep: return (char_u *)"lgrep";
4868b434ae2aSBram Moolenaar case CMD_grepadd: return (char_u *)"grepadd";
4869b434ae2aSBram Moolenaar case CMD_lgrepadd: return (char_u *)"lgrepadd";
4870b434ae2aSBram Moolenaar default: return NULL;
4871d88e02deSBram Moolenaar }
4872071d4279SBram Moolenaar }
4873071d4279SBram Moolenaar
4874071d4279SBram Moolenaar /*
4875071d4279SBram Moolenaar * Return the name for the errorfile, in allocated memory.
4876071d4279SBram Moolenaar * Find a new unique name when 'makeef' contains "##".
4877071d4279SBram Moolenaar * Returns NULL for error.
4878071d4279SBram Moolenaar */
4879071d4279SBram Moolenaar static char_u *
get_mef_name(void)488005540976SBram Moolenaar get_mef_name(void)
4881071d4279SBram Moolenaar {
4882071d4279SBram Moolenaar char_u *p;
4883071d4279SBram Moolenaar char_u *name;
4884071d4279SBram Moolenaar static int start = -1;
4885071d4279SBram Moolenaar static int off = 0;
4886071d4279SBram Moolenaar #ifdef HAVE_LSTAT
48878767f52fSBram Moolenaar stat_T sb;
4888071d4279SBram Moolenaar #endif
4889071d4279SBram Moolenaar
4890071d4279SBram Moolenaar if (*p_mef == NUL)
4891071d4279SBram Moolenaar {
4892e5c421cfSBram Moolenaar name = vim_tempname('e', FALSE);
4893071d4279SBram Moolenaar if (name == NULL)
4894f9e3e09fSBram Moolenaar emsg(_(e_notmp));
4895071d4279SBram Moolenaar return name;
4896071d4279SBram Moolenaar }
4897071d4279SBram Moolenaar
4898071d4279SBram Moolenaar for (p = p_mef; *p; ++p)
4899071d4279SBram Moolenaar if (p[0] == '#' && p[1] == '#')
4900071d4279SBram Moolenaar break;
4901071d4279SBram Moolenaar
4902071d4279SBram Moolenaar if (*p == NUL)
4903071d4279SBram Moolenaar return vim_strsave(p_mef);
4904071d4279SBram Moolenaar
4905b434ae2aSBram Moolenaar // Keep trying until the name doesn't exist yet.
4906071d4279SBram Moolenaar for (;;)
4907071d4279SBram Moolenaar {
4908071d4279SBram Moolenaar if (start == -1)
4909071d4279SBram Moolenaar start = mch_get_pid();
4910071d4279SBram Moolenaar else
4911071d4279SBram Moolenaar off += 19;
4912071d4279SBram Moolenaar
4913964b3746SBram Moolenaar name = alloc(STRLEN(p_mef) + 30);
4914071d4279SBram Moolenaar if (name == NULL)
4915071d4279SBram Moolenaar break;
4916071d4279SBram Moolenaar STRCPY(name, p_mef);
4917071d4279SBram Moolenaar sprintf((char *)name + (p - p_mef), "%d%d", start, off);
4918071d4279SBram Moolenaar STRCAT(name, p + 2);
4919071d4279SBram Moolenaar if (mch_getperm(name) < 0
4920071d4279SBram Moolenaar #ifdef HAVE_LSTAT
4921b434ae2aSBram Moolenaar // Don't accept a symbolic link, it's a security risk.
4922071d4279SBram Moolenaar && mch_lstat((char *)name, &sb) < 0
4923071d4279SBram Moolenaar #endif
4924071d4279SBram Moolenaar )
4925071d4279SBram Moolenaar break;
4926071d4279SBram Moolenaar vim_free(name);
4927071d4279SBram Moolenaar }
4928071d4279SBram Moolenaar return name;
4929071d4279SBram Moolenaar }
4930071d4279SBram Moolenaar
4931071d4279SBram Moolenaar /*
4932b434ae2aSBram Moolenaar * Form the complete command line to invoke 'make'/'grep'. Quote the command
4933b434ae2aSBram Moolenaar * using 'shellquote' and append 'shellpipe'. Echo the fully formed command.
4934b434ae2aSBram Moolenaar */
4935b434ae2aSBram Moolenaar static char_u *
make_get_fullcmd(char_u * makecmd,char_u * fname)4936b434ae2aSBram Moolenaar make_get_fullcmd(char_u *makecmd, char_u *fname)
4937b434ae2aSBram Moolenaar {
4938b434ae2aSBram Moolenaar char_u *cmd;
4939b434ae2aSBram Moolenaar unsigned len;
4940b434ae2aSBram Moolenaar
4941b434ae2aSBram Moolenaar len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(makecmd) + 1;
4942b434ae2aSBram Moolenaar if (*p_sp != NUL)
4943b434ae2aSBram Moolenaar len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3;
4944b434ae2aSBram Moolenaar cmd = alloc(len);
4945b434ae2aSBram Moolenaar if (cmd == NULL)
4946b434ae2aSBram Moolenaar return NULL;
4947b434ae2aSBram Moolenaar sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)makecmd,
4948b434ae2aSBram Moolenaar (char *)p_shq);
4949b434ae2aSBram Moolenaar
4950b434ae2aSBram Moolenaar // If 'shellpipe' empty: don't redirect to 'errorfile'.
4951b434ae2aSBram Moolenaar if (*p_sp != NUL)
4952b434ae2aSBram Moolenaar append_redir(cmd, len, p_sp, fname);
4953b434ae2aSBram Moolenaar
4954b434ae2aSBram Moolenaar // Display the fully formed command. Output a newline if there's something
4955b434ae2aSBram Moolenaar // else than the :make command that was typed (in which case the cursor is
4956b434ae2aSBram Moolenaar // in column 0).
4957b434ae2aSBram Moolenaar if (msg_col == 0)
4958b434ae2aSBram Moolenaar msg_didout = FALSE;
4959b434ae2aSBram Moolenaar msg_start();
496032526b3cSBram Moolenaar msg_puts(":!");
4961b434ae2aSBram Moolenaar msg_outtrans(cmd); // show what we are doing
4962b434ae2aSBram Moolenaar
4963b434ae2aSBram Moolenaar return cmd;
4964b434ae2aSBram Moolenaar }
4965b434ae2aSBram Moolenaar
4966b434ae2aSBram Moolenaar /*
4967b434ae2aSBram Moolenaar * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd"
4968b434ae2aSBram Moolenaar */
4969b434ae2aSBram Moolenaar void
ex_make(exarg_T * eap)4970b434ae2aSBram Moolenaar ex_make(exarg_T *eap)
4971b434ae2aSBram Moolenaar {
4972b434ae2aSBram Moolenaar char_u *fname;
4973b434ae2aSBram Moolenaar char_u *cmd;
4974b434ae2aSBram Moolenaar char_u *enc = NULL;
4975b434ae2aSBram Moolenaar win_T *wp = NULL;
4976b434ae2aSBram Moolenaar qf_info_T *qi = &ql_info;
4977b434ae2aSBram Moolenaar int res;
4978b434ae2aSBram Moolenaar char_u *au_name = NULL;
4979b434ae2aSBram Moolenaar int_u save_qfid;
4980b434ae2aSBram Moolenaar
4981b434ae2aSBram Moolenaar // Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal".
4982b434ae2aSBram Moolenaar if (grep_internal(eap->cmdidx))
4983b434ae2aSBram Moolenaar {
4984b434ae2aSBram Moolenaar ex_vimgrep(eap);
4985b434ae2aSBram Moolenaar return;
4986b434ae2aSBram Moolenaar }
4987b434ae2aSBram Moolenaar
4988b434ae2aSBram Moolenaar au_name = make_get_auname(eap->cmdidx);
4989b434ae2aSBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
4990b434ae2aSBram Moolenaar curbuf->b_fname, TRUE, curbuf))
4991b434ae2aSBram Moolenaar {
4992b434ae2aSBram Moolenaar #ifdef FEAT_EVAL
4993b434ae2aSBram Moolenaar if (aborting())
4994b434ae2aSBram Moolenaar return;
4995b434ae2aSBram Moolenaar #endif
4996b434ae2aSBram Moolenaar }
4997b434ae2aSBram Moolenaar enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
4998b434ae2aSBram Moolenaar
4999b434ae2aSBram Moolenaar if (is_loclist_cmd(eap->cmdidx))
5000b434ae2aSBram Moolenaar wp = curwin;
5001b434ae2aSBram Moolenaar
5002b434ae2aSBram Moolenaar autowrite_all();
5003b434ae2aSBram Moolenaar fname = get_mef_name();
5004b434ae2aSBram Moolenaar if (fname == NULL)
5005b434ae2aSBram Moolenaar return;
5006b434ae2aSBram Moolenaar mch_remove(fname); // in case it's not unique
5007b434ae2aSBram Moolenaar
5008b434ae2aSBram Moolenaar cmd = make_get_fullcmd(eap->arg, fname);
5009b434ae2aSBram Moolenaar if (cmd == NULL)
5010b434ae2aSBram Moolenaar return;
5011b434ae2aSBram Moolenaar
5012b434ae2aSBram Moolenaar // let the shell know if we are redirecting output or not
5013b434ae2aSBram Moolenaar do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0);
5014b434ae2aSBram Moolenaar
5015b434ae2aSBram Moolenaar #ifdef AMIGA
5016b434ae2aSBram Moolenaar out_flush();
5017b434ae2aSBram Moolenaar // read window status report and redraw before message
5018b434ae2aSBram Moolenaar (void)char_avail();
5019b434ae2aSBram Moolenaar #endif
5020b434ae2aSBram Moolenaar
50219f84ded3SBram Moolenaar incr_quickfix_busy();
50229f84ded3SBram Moolenaar
5023b434ae2aSBram Moolenaar res = qf_init(wp, fname, (eap->cmdidx != CMD_make
5024b434ae2aSBram Moolenaar && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm,
5025b434ae2aSBram Moolenaar (eap->cmdidx != CMD_grepadd
5026b434ae2aSBram Moolenaar && eap->cmdidx != CMD_lgrepadd),
5027b434ae2aSBram Moolenaar qf_cmdtitle(*eap->cmdlinep), enc);
5028b434ae2aSBram Moolenaar if (wp != NULL)
5029b434ae2aSBram Moolenaar {
5030b434ae2aSBram Moolenaar qi = GET_LOC_LIST(wp);
5031b434ae2aSBram Moolenaar if (qi == NULL)
5032b434ae2aSBram Moolenaar goto cleanup;
5033b434ae2aSBram Moolenaar }
5034b434ae2aSBram Moolenaar if (res >= 0)
50354aa47b28SBram Moolenaar qf_list_changed(qf_get_curlist(qi));
5036b434ae2aSBram Moolenaar
5037b434ae2aSBram Moolenaar // Remember the current quickfix list identifier, so that we can
5038b434ae2aSBram Moolenaar // check for autocommands changing the current quickfix list.
50394aa47b28SBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
5040b434ae2aSBram Moolenaar if (au_name != NULL)
5041b434ae2aSBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
5042b434ae2aSBram Moolenaar curbuf->b_fname, TRUE, curbuf);
5043b434ae2aSBram Moolenaar if (res > 0 && !eap->forceit && qflist_valid(wp, save_qfid))
5044b434ae2aSBram Moolenaar // display the first error
5045b434ae2aSBram Moolenaar qf_jump_first(qi, save_qfid, FALSE);
5046b434ae2aSBram Moolenaar
5047b434ae2aSBram Moolenaar cleanup:
50489f84ded3SBram Moolenaar decr_quickfix_busy();
5049b434ae2aSBram Moolenaar mch_remove(fname);
5050b434ae2aSBram Moolenaar vim_free(fname);
5051b434ae2aSBram Moolenaar vim_free(cmd);
5052b434ae2aSBram Moolenaar }
5053b434ae2aSBram Moolenaar
5054b434ae2aSBram Moolenaar /*
505525190db2SBram Moolenaar * Returns the number of entries in the current quickfix/location list.
5056aa23b379SBram Moolenaar */
5057aa23b379SBram Moolenaar int
qf_get_size(exarg_T * eap)505805540976SBram Moolenaar qf_get_size(exarg_T *eap)
5059aa23b379SBram Moolenaar {
506087f59b09SBram Moolenaar qf_info_T *qi;
506125190db2SBram Moolenaar
506225190db2SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
506325190db2SBram Moolenaar return 0;
506425190db2SBram Moolenaar return qf_get_curlist(qi)->qf_count;
506525190db2SBram Moolenaar }
506625190db2SBram Moolenaar
506725190db2SBram Moolenaar /*
506825190db2SBram Moolenaar * Returns the number of valid entries in the current quickfix/location list.
506925190db2SBram Moolenaar */
507025190db2SBram Moolenaar int
qf_get_valid_size(exarg_T * eap)507125190db2SBram Moolenaar qf_get_valid_size(exarg_T *eap)
507225190db2SBram Moolenaar {
507325190db2SBram Moolenaar qf_info_T *qi;
5074108e7b42SBram Moolenaar qf_list_T *qfl;
5075aa23b379SBram Moolenaar qfline_T *qfp;
5076aa23b379SBram Moolenaar int i, sz = 0;
5077aa23b379SBram Moolenaar int prev_fnum = 0;
5078aa23b379SBram Moolenaar
507987f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5080aa23b379SBram Moolenaar return 0;
5081aa23b379SBram Moolenaar
50824aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
5083a16123a6SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
5084aa23b379SBram Moolenaar {
5085aa23b379SBram Moolenaar if (qfp->qf_valid)
5086aa23b379SBram Moolenaar {
5087aa23b379SBram Moolenaar if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo)
508800bf8cd2SBram Moolenaar sz++; // Count all valid entries
5089aa23b379SBram Moolenaar else if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5090aa23b379SBram Moolenaar {
509100bf8cd2SBram Moolenaar // Count the number of files
5092aa23b379SBram Moolenaar sz++;
5093aa23b379SBram Moolenaar prev_fnum = qfp->qf_fnum;
5094aa23b379SBram Moolenaar }
5095aa23b379SBram Moolenaar }
5096aa23b379SBram Moolenaar }
5097aa23b379SBram Moolenaar
5098aa23b379SBram Moolenaar return sz;
5099aa23b379SBram Moolenaar }
5100aa23b379SBram Moolenaar
5101aa23b379SBram Moolenaar /*
5102aa23b379SBram Moolenaar * Returns the current index of the quickfix/location list.
5103aa23b379SBram Moolenaar * Returns 0 if there is an error.
5104aa23b379SBram Moolenaar */
5105aa23b379SBram Moolenaar int
qf_get_cur_idx(exarg_T * eap)510605540976SBram Moolenaar qf_get_cur_idx(exarg_T *eap)
5107aa23b379SBram Moolenaar {
510887f59b09SBram Moolenaar qf_info_T *qi;
5109aa23b379SBram Moolenaar
511087f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5111aa23b379SBram Moolenaar return 0;
5112aa23b379SBram Moolenaar
51134aa47b28SBram Moolenaar return qf_get_curlist(qi)->qf_index;
5114aa23b379SBram Moolenaar }
5115aa23b379SBram Moolenaar
5116aa23b379SBram Moolenaar /*
5117aa23b379SBram Moolenaar * Returns the current index in the quickfix/location list (counting only valid
5118aa23b379SBram Moolenaar * entries). If no valid entries are in the list, then returns 1.
5119aa23b379SBram Moolenaar */
5120aa23b379SBram Moolenaar int
qf_get_cur_valid_idx(exarg_T * eap)512105540976SBram Moolenaar qf_get_cur_valid_idx(exarg_T *eap)
5122aa23b379SBram Moolenaar {
512387f59b09SBram Moolenaar qf_info_T *qi;
5124aa23b379SBram Moolenaar qf_list_T *qfl;
5125aa23b379SBram Moolenaar qfline_T *qfp;
5126aa23b379SBram Moolenaar int i, eidx = 0;
5127aa23b379SBram Moolenaar int prev_fnum = 0;
5128aa23b379SBram Moolenaar
512987f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, FALSE)) == NULL)
5130aa23b379SBram Moolenaar return 1;
5131aa23b379SBram Moolenaar
51324aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
5133aa23b379SBram Moolenaar qfp = qfl->qf_start;
5134aa23b379SBram Moolenaar
513500bf8cd2SBram Moolenaar // check if the list has valid errors
51363ff33114SBram Moolenaar if (!qf_list_has_valid_entries(qfl))
5137aa23b379SBram Moolenaar return 1;
5138aa23b379SBram Moolenaar
5139aa23b379SBram Moolenaar for (i = 1; i <= qfl->qf_index && qfp!= NULL; i++, qfp = qfp->qf_next)
5140aa23b379SBram Moolenaar {
5141aa23b379SBram Moolenaar if (qfp->qf_valid)
5142aa23b379SBram Moolenaar {
5143aa23b379SBram Moolenaar if (eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
5144aa23b379SBram Moolenaar {
5145aa23b379SBram Moolenaar if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5146aa23b379SBram Moolenaar {
514700bf8cd2SBram Moolenaar // Count the number of files
5148aa23b379SBram Moolenaar eidx++;
5149aa23b379SBram Moolenaar prev_fnum = qfp->qf_fnum;
5150aa23b379SBram Moolenaar }
5151aa23b379SBram Moolenaar }
5152aa23b379SBram Moolenaar else
5153aa23b379SBram Moolenaar eidx++;
5154aa23b379SBram Moolenaar }
5155aa23b379SBram Moolenaar }
5156aa23b379SBram Moolenaar
5157aa23b379SBram Moolenaar return eidx ? eidx : 1;
5158aa23b379SBram Moolenaar }
5159aa23b379SBram Moolenaar
5160aa23b379SBram Moolenaar /*
5161aa23b379SBram Moolenaar * Get the 'n'th valid error entry in the quickfix or location list.
5162aa23b379SBram Moolenaar * Used by :cdo, :ldo, :cfdo and :lfdo commands.
5163aa23b379SBram Moolenaar * For :cdo and :ldo returns the 'n'th valid error entry.
5164aa23b379SBram Moolenaar * For :cfdo and :lfdo returns the 'n'th valid file entry.
5165aa23b379SBram Moolenaar */
5166aa23b379SBram Moolenaar static int
qf_get_nth_valid_entry(qf_list_T * qfl,int n,int fdo)5167fe15b7dfSBram Moolenaar qf_get_nth_valid_entry(qf_list_T *qfl, int n, int fdo)
5168aa23b379SBram Moolenaar {
516995946f12SBram Moolenaar qfline_T *qfp;
5170aa23b379SBram Moolenaar int i, eidx;
5171aa23b379SBram Moolenaar int prev_fnum = 0;
5172aa23b379SBram Moolenaar
517300bf8cd2SBram Moolenaar // check if the list has valid errors
51743ff33114SBram Moolenaar if (!qf_list_has_valid_entries(qfl))
5175aa23b379SBram Moolenaar return 1;
5176aa23b379SBram Moolenaar
517795946f12SBram Moolenaar eidx = 0;
517895946f12SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
5179aa23b379SBram Moolenaar {
5180aa23b379SBram Moolenaar if (qfp->qf_valid)
5181aa23b379SBram Moolenaar {
5182aa23b379SBram Moolenaar if (fdo)
5183aa23b379SBram Moolenaar {
5184aa23b379SBram Moolenaar if (qfp->qf_fnum > 0 && qfp->qf_fnum != prev_fnum)
5185aa23b379SBram Moolenaar {
518600bf8cd2SBram Moolenaar // Count the number of files
5187aa23b379SBram Moolenaar eidx++;
5188aa23b379SBram Moolenaar prev_fnum = qfp->qf_fnum;
5189aa23b379SBram Moolenaar }
5190aa23b379SBram Moolenaar }
5191aa23b379SBram Moolenaar else
5192aa23b379SBram Moolenaar eidx++;
5193aa23b379SBram Moolenaar }
5194aa23b379SBram Moolenaar
5195aa23b379SBram Moolenaar if (eidx == n)
5196aa23b379SBram Moolenaar break;
5197aa23b379SBram Moolenaar }
5198aa23b379SBram Moolenaar
5199aa23b379SBram Moolenaar if (i <= qfl->qf_count)
5200aa23b379SBram Moolenaar return i;
5201aa23b379SBram Moolenaar else
5202aa23b379SBram Moolenaar return 1;
5203aa23b379SBram Moolenaar }
5204aa23b379SBram Moolenaar
5205aa23b379SBram Moolenaar /*
5206071d4279SBram Moolenaar * ":cc", ":crewind", ":cfirst" and ":clast".
5207d12f5c17SBram Moolenaar * ":ll", ":lrewind", ":lfirst" and ":llast".
5208aa23b379SBram Moolenaar * ":cdo", ":ldo", ":cfdo" and ":lfdo"
5209071d4279SBram Moolenaar */
5210071d4279SBram Moolenaar void
ex_cc(exarg_T * eap)521105540976SBram Moolenaar ex_cc(exarg_T *eap)
5212071d4279SBram Moolenaar {
521387f59b09SBram Moolenaar qf_info_T *qi;
5214aa23b379SBram Moolenaar int errornr;
5215d12f5c17SBram Moolenaar
521687f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
5217d12f5c17SBram Moolenaar return;
5218d12f5c17SBram Moolenaar
5219aa23b379SBram Moolenaar if (eap->addr_count > 0)
5220aa23b379SBram Moolenaar errornr = (int)eap->line2;
5221aa23b379SBram Moolenaar else
5222aa23b379SBram Moolenaar {
522339665959SBram Moolenaar switch (eap->cmdidx)
522439665959SBram Moolenaar {
522539665959SBram Moolenaar case CMD_cc: case CMD_ll:
5226aa23b379SBram Moolenaar errornr = 0;
522739665959SBram Moolenaar break;
522839665959SBram Moolenaar case CMD_crewind: case CMD_lrewind: case CMD_cfirst:
522939665959SBram Moolenaar case CMD_lfirst:
5230aa23b379SBram Moolenaar errornr = 1;
523139665959SBram Moolenaar break;
523239665959SBram Moolenaar default:
5233aa23b379SBram Moolenaar errornr = 32767;
5234aa23b379SBram Moolenaar }
523539665959SBram Moolenaar }
5236aa23b379SBram Moolenaar
523700bf8cd2SBram Moolenaar // For cdo and ldo commands, jump to the nth valid error.
523800bf8cd2SBram Moolenaar // For cfdo and lfdo commands, jump to the nth valid file entry.
523955b69264SBram Moolenaar if (eap->cmdidx == CMD_cdo || eap->cmdidx == CMD_ldo
524055b69264SBram Moolenaar || eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo)
52414aa47b28SBram Moolenaar errornr = qf_get_nth_valid_entry(qf_get_curlist(qi),
5242aa23b379SBram Moolenaar eap->addr_count > 0 ? (int)eap->line1 : 1,
5243aa23b379SBram Moolenaar eap->cmdidx == CMD_cfdo || eap->cmdidx == CMD_lfdo);
5244aa23b379SBram Moolenaar
5245aa23b379SBram Moolenaar qf_jump(qi, 0, errornr, eap->forceit);
5246071d4279SBram Moolenaar }
5247071d4279SBram Moolenaar
5248071d4279SBram Moolenaar /*
5249071d4279SBram Moolenaar * ":cnext", ":cnfile", ":cNext" and ":cprevious".
5250d12f5c17SBram Moolenaar * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile".
5251aa23b379SBram Moolenaar * Also, used by ":cdo", ":ldo", ":cfdo" and ":lfdo" commands.
5252071d4279SBram Moolenaar */
5253071d4279SBram Moolenaar void
ex_cnext(exarg_T * eap)525405540976SBram Moolenaar ex_cnext(exarg_T *eap)
5255071d4279SBram Moolenaar {
525687f59b09SBram Moolenaar qf_info_T *qi;
5257aa23b379SBram Moolenaar int errornr;
525839665959SBram Moolenaar int dir;
5259d12f5c17SBram Moolenaar
526087f59b09SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
5261d12f5c17SBram Moolenaar return;
5262d12f5c17SBram Moolenaar
526355b69264SBram Moolenaar if (eap->addr_count > 0
526455b69264SBram Moolenaar && (eap->cmdidx != CMD_cdo && eap->cmdidx != CMD_ldo
526555b69264SBram Moolenaar && eap->cmdidx != CMD_cfdo && eap->cmdidx != CMD_lfdo))
5266aa23b379SBram Moolenaar errornr = (int)eap->line2;
5267aa23b379SBram Moolenaar else
5268aa23b379SBram Moolenaar errornr = 1;
5269aa23b379SBram Moolenaar
527039665959SBram Moolenaar // Depending on the command jump to either next or previous entry/file.
527139665959SBram Moolenaar switch (eap->cmdidx)
527239665959SBram Moolenaar {
527339665959SBram Moolenaar case CMD_cnext: case CMD_lnext: case CMD_cdo: case CMD_ldo:
527439665959SBram Moolenaar dir = FORWARD;
527539665959SBram Moolenaar break;
527639665959SBram Moolenaar case CMD_cprevious: case CMD_lprevious: case CMD_cNext:
527739665959SBram Moolenaar case CMD_lNext:
527839665959SBram Moolenaar dir = BACKWARD;
527939665959SBram Moolenaar break;
528039665959SBram Moolenaar case CMD_cnfile: case CMD_lnfile: case CMD_cfdo: case CMD_lfdo:
528139665959SBram Moolenaar dir = FORWARD_FILE;
528239665959SBram Moolenaar break;
528339665959SBram Moolenaar case CMD_cpfile: case CMD_lpfile: case CMD_cNfile: case CMD_lNfile:
528439665959SBram Moolenaar dir = BACKWARD_FILE;
528539665959SBram Moolenaar break;
528639665959SBram Moolenaar default:
528739665959SBram Moolenaar dir = FORWARD;
528839665959SBram Moolenaar break;
528939665959SBram Moolenaar }
529039665959SBram Moolenaar
529139665959SBram Moolenaar qf_jump(qi, dir, errornr, eap->forceit);
5292071d4279SBram Moolenaar }
5293071d4279SBram Moolenaar
5294071d4279SBram Moolenaar /*
52953ff33114SBram Moolenaar * Find the first entry in the quickfix list 'qfl' from buffer 'bnr'.
52963ff33114SBram Moolenaar * The index of the entry is stored in 'errornr'.
52973ff33114SBram Moolenaar * Returns NULL if an entry is not found.
52983ff33114SBram Moolenaar */
52993ff33114SBram Moolenaar static qfline_T *
qf_find_first_entry_in_buf(qf_list_T * qfl,int bnr,int * errornr)53003ff33114SBram Moolenaar qf_find_first_entry_in_buf(qf_list_T *qfl, int bnr, int *errornr)
53013ff33114SBram Moolenaar {
53023ff33114SBram Moolenaar qfline_T *qfp = NULL;
53033ff33114SBram Moolenaar int idx = 0;
53043ff33114SBram Moolenaar
53053ff33114SBram Moolenaar // Find the first entry in this file
53063ff33114SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, idx)
53073ff33114SBram Moolenaar if (qfp->qf_fnum == bnr)
53083ff33114SBram Moolenaar break;
53093ff33114SBram Moolenaar
53103ff33114SBram Moolenaar *errornr = idx;
53113ff33114SBram Moolenaar return qfp;
53123ff33114SBram Moolenaar }
53133ff33114SBram Moolenaar
53143ff33114SBram Moolenaar /*
53153ff33114SBram Moolenaar * Find the first quickfix entry on the same line as 'entry'. Updates 'errornr'
53163ff33114SBram Moolenaar * with the error number for the first entry. Assumes the entries are sorted in
53173ff33114SBram Moolenaar * the quickfix list by line number.
53183ff33114SBram Moolenaar */
53193ff33114SBram Moolenaar static qfline_T *
qf_find_first_entry_on_line(qfline_T * entry,int * errornr)53203ff33114SBram Moolenaar qf_find_first_entry_on_line(qfline_T *entry, int *errornr)
53213ff33114SBram Moolenaar {
53223ff33114SBram Moolenaar while (!got_int
53233ff33114SBram Moolenaar && entry->qf_prev != NULL
53243ff33114SBram Moolenaar && entry->qf_fnum == entry->qf_prev->qf_fnum
53253ff33114SBram Moolenaar && entry->qf_lnum == entry->qf_prev->qf_lnum)
53263ff33114SBram Moolenaar {
53273ff33114SBram Moolenaar entry = entry->qf_prev;
53283ff33114SBram Moolenaar --*errornr;
53293ff33114SBram Moolenaar }
53303ff33114SBram Moolenaar
53313ff33114SBram Moolenaar return entry;
53323ff33114SBram Moolenaar }
53333ff33114SBram Moolenaar
53343ff33114SBram Moolenaar /*
53353ff33114SBram Moolenaar * Find the last quickfix entry on the same line as 'entry'. Updates 'errornr'
53363ff33114SBram Moolenaar * with the error number for the last entry. Assumes the entries are sorted in
53373ff33114SBram Moolenaar * the quickfix list by line number.
53383ff33114SBram Moolenaar */
53393ff33114SBram Moolenaar static qfline_T *
qf_find_last_entry_on_line(qfline_T * entry,int * errornr)53403ff33114SBram Moolenaar qf_find_last_entry_on_line(qfline_T *entry, int *errornr)
53413ff33114SBram Moolenaar {
53423ff33114SBram Moolenaar while (!got_int &&
53433ff33114SBram Moolenaar entry->qf_next != NULL
53443ff33114SBram Moolenaar && entry->qf_fnum == entry->qf_next->qf_fnum
53453ff33114SBram Moolenaar && entry->qf_lnum == entry->qf_next->qf_lnum)
53463ff33114SBram Moolenaar {
53473ff33114SBram Moolenaar entry = entry->qf_next;
53483ff33114SBram Moolenaar ++*errornr;
53493ff33114SBram Moolenaar }
53503ff33114SBram Moolenaar
53513ff33114SBram Moolenaar return entry;
53523ff33114SBram Moolenaar }
53533ff33114SBram Moolenaar
53543ff33114SBram Moolenaar /*
5355cf6a55c4SBram Moolenaar * Returns TRUE if the specified quickfix entry is
5356cf6a55c4SBram Moolenaar * after the given line (linewise is TRUE)
5357cf6a55c4SBram Moolenaar * or after the line and column.
5358cf6a55c4SBram Moolenaar */
5359cf6a55c4SBram Moolenaar static int
qf_entry_after_pos(qfline_T * qfp,pos_T * pos,int linewise)5360cf6a55c4SBram Moolenaar qf_entry_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
5361cf6a55c4SBram Moolenaar {
5362cf6a55c4SBram Moolenaar if (linewise)
5363cf6a55c4SBram Moolenaar return qfp->qf_lnum > pos->lnum;
5364cf6a55c4SBram Moolenaar else
5365cf6a55c4SBram Moolenaar return (qfp->qf_lnum > pos->lnum ||
5366cf6a55c4SBram Moolenaar (qfp->qf_lnum == pos->lnum && qfp->qf_col > pos->col));
5367cf6a55c4SBram Moolenaar }
5368cf6a55c4SBram Moolenaar
5369cf6a55c4SBram Moolenaar /*
5370cf6a55c4SBram Moolenaar * Returns TRUE if the specified quickfix entry is
5371cf6a55c4SBram Moolenaar * before the given line (linewise is TRUE)
5372cf6a55c4SBram Moolenaar * or before the line and column.
5373cf6a55c4SBram Moolenaar */
5374cf6a55c4SBram Moolenaar static int
qf_entry_before_pos(qfline_T * qfp,pos_T * pos,int linewise)5375cf6a55c4SBram Moolenaar qf_entry_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
5376cf6a55c4SBram Moolenaar {
5377cf6a55c4SBram Moolenaar if (linewise)
5378cf6a55c4SBram Moolenaar return qfp->qf_lnum < pos->lnum;
5379cf6a55c4SBram Moolenaar else
5380cf6a55c4SBram Moolenaar return (qfp->qf_lnum < pos->lnum ||
5381cf6a55c4SBram Moolenaar (qfp->qf_lnum == pos->lnum && qfp->qf_col < pos->col));
5382cf6a55c4SBram Moolenaar }
5383cf6a55c4SBram Moolenaar
5384cf6a55c4SBram Moolenaar /*
5385cf6a55c4SBram Moolenaar * Returns TRUE if the specified quickfix entry is
5386cf6a55c4SBram Moolenaar * on or after the given line (linewise is TRUE)
5387cf6a55c4SBram Moolenaar * or on or after the line and column.
5388cf6a55c4SBram Moolenaar */
5389cf6a55c4SBram Moolenaar static int
qf_entry_on_or_after_pos(qfline_T * qfp,pos_T * pos,int linewise)5390cf6a55c4SBram Moolenaar qf_entry_on_or_after_pos(qfline_T *qfp, pos_T *pos, int linewise)
5391cf6a55c4SBram Moolenaar {
5392cf6a55c4SBram Moolenaar if (linewise)
5393cf6a55c4SBram Moolenaar return qfp->qf_lnum >= pos->lnum;
5394cf6a55c4SBram Moolenaar else
5395cf6a55c4SBram Moolenaar return (qfp->qf_lnum > pos->lnum ||
5396cf6a55c4SBram Moolenaar (qfp->qf_lnum == pos->lnum && qfp->qf_col >= pos->col));
5397cf6a55c4SBram Moolenaar }
5398cf6a55c4SBram Moolenaar
5399cf6a55c4SBram Moolenaar /*
5400cf6a55c4SBram Moolenaar * Returns TRUE if the specified quickfix entry is
5401cf6a55c4SBram Moolenaar * on or before the given line (linewise is TRUE)
5402cf6a55c4SBram Moolenaar * or on or before the line and column.
5403cf6a55c4SBram Moolenaar */
5404cf6a55c4SBram Moolenaar static int
qf_entry_on_or_before_pos(qfline_T * qfp,pos_T * pos,int linewise)5405cf6a55c4SBram Moolenaar qf_entry_on_or_before_pos(qfline_T *qfp, pos_T *pos, int linewise)
5406cf6a55c4SBram Moolenaar {
5407cf6a55c4SBram Moolenaar if (linewise)
5408cf6a55c4SBram Moolenaar return qfp->qf_lnum <= pos->lnum;
5409cf6a55c4SBram Moolenaar else
5410cf6a55c4SBram Moolenaar return (qfp->qf_lnum < pos->lnum ||
5411cf6a55c4SBram Moolenaar (qfp->qf_lnum == pos->lnum && qfp->qf_col <= pos->col));
5412cf6a55c4SBram Moolenaar }
5413cf6a55c4SBram Moolenaar
5414cf6a55c4SBram Moolenaar /*
5415cf6a55c4SBram Moolenaar * Find the first quickfix entry after position 'pos' in buffer 'bnr'.
5416cf6a55c4SBram Moolenaar * If 'linewise' is TRUE, returns the entry after the specified line and treats
5417cf6a55c4SBram Moolenaar * multiple entries on a single line as one. Otherwise returns the entry after
5418cf6a55c4SBram Moolenaar * the specified line and column.
54193ff33114SBram Moolenaar * 'qfp' points to the very first entry in the buffer and 'errornr' is the
54203ff33114SBram Moolenaar * index of the very first entry in the quickfix list.
5421cf6a55c4SBram Moolenaar * Returns NULL if an entry is not found after 'pos'.
54223ff33114SBram Moolenaar */
54233ff33114SBram Moolenaar static qfline_T *
qf_find_entry_after_pos(int bnr,pos_T * pos,int linewise,qfline_T * qfp,int * errornr)5424cf6a55c4SBram Moolenaar qf_find_entry_after_pos(
54253ff33114SBram Moolenaar int bnr,
5426cf6a55c4SBram Moolenaar pos_T *pos,
5427cf6a55c4SBram Moolenaar int linewise,
54283ff33114SBram Moolenaar qfline_T *qfp,
54293ff33114SBram Moolenaar int *errornr)
54303ff33114SBram Moolenaar {
5431cf6a55c4SBram Moolenaar if (qf_entry_after_pos(qfp, pos, linewise))
543232aa1020SBram Moolenaar // First entry is after position 'pos'
54333ff33114SBram Moolenaar return qfp;
54343ff33114SBram Moolenaar
5435cf6a55c4SBram Moolenaar // Find the entry just before or at the position 'pos'
54363ff33114SBram Moolenaar while (qfp->qf_next != NULL
54373ff33114SBram Moolenaar && qfp->qf_next->qf_fnum == bnr
5438cf6a55c4SBram Moolenaar && qf_entry_on_or_before_pos(qfp->qf_next, pos, linewise))
54393ff33114SBram Moolenaar {
54403ff33114SBram Moolenaar qfp = qfp->qf_next;
54413ff33114SBram Moolenaar ++*errornr;
54423ff33114SBram Moolenaar }
54433ff33114SBram Moolenaar
54443ff33114SBram Moolenaar if (qfp->qf_next == NULL || qfp->qf_next->qf_fnum != bnr)
5445cf6a55c4SBram Moolenaar // No entries found after position 'pos'
54463ff33114SBram Moolenaar return NULL;
54473ff33114SBram Moolenaar
5448cf6a55c4SBram Moolenaar // Use the entry just after position 'pos'
54493ff33114SBram Moolenaar qfp = qfp->qf_next;
54503ff33114SBram Moolenaar ++*errornr;
54513ff33114SBram Moolenaar
54523ff33114SBram Moolenaar return qfp;
54533ff33114SBram Moolenaar }
54543ff33114SBram Moolenaar
54553ff33114SBram Moolenaar /*
5456cf6a55c4SBram Moolenaar * Find the first quickfix entry before position 'pos' in buffer 'bnr'.
5457cf6a55c4SBram Moolenaar * If 'linewise' is TRUE, returns the entry before the specified line and
5458cf6a55c4SBram Moolenaar * treats multiple entries on a single line as one. Otherwise returns the entry
5459cf6a55c4SBram Moolenaar * before the specified line and column.
54603ff33114SBram Moolenaar * 'qfp' points to the very first entry in the buffer and 'errornr' is the
54613ff33114SBram Moolenaar * index of the very first entry in the quickfix list.
5462cf6a55c4SBram Moolenaar * Returns NULL if an entry is not found before 'pos'.
54633ff33114SBram Moolenaar */
54643ff33114SBram Moolenaar static qfline_T *
qf_find_entry_before_pos(int bnr,pos_T * pos,int linewise,qfline_T * qfp,int * errornr)5465cf6a55c4SBram Moolenaar qf_find_entry_before_pos(
54663ff33114SBram Moolenaar int bnr,
5467cf6a55c4SBram Moolenaar pos_T *pos,
5468cf6a55c4SBram Moolenaar int linewise,
54693ff33114SBram Moolenaar qfline_T *qfp,
54703ff33114SBram Moolenaar int *errornr)
54713ff33114SBram Moolenaar {
5472cf6a55c4SBram Moolenaar // Find the entry just before the position 'pos'
54733ff33114SBram Moolenaar while (qfp->qf_next != NULL
54743ff33114SBram Moolenaar && qfp->qf_next->qf_fnum == bnr
5475cf6a55c4SBram Moolenaar && qf_entry_before_pos(qfp->qf_next, pos, linewise))
54763ff33114SBram Moolenaar {
54773ff33114SBram Moolenaar qfp = qfp->qf_next;
54783ff33114SBram Moolenaar ++*errornr;
54793ff33114SBram Moolenaar }
54803ff33114SBram Moolenaar
5481cf6a55c4SBram Moolenaar if (qf_entry_on_or_after_pos(qfp, pos, linewise))
54823ff33114SBram Moolenaar return NULL;
54833ff33114SBram Moolenaar
5484cf6a55c4SBram Moolenaar if (linewise)
54853ff33114SBram Moolenaar // If multiple entries are on the same line, then use the first entry
54863ff33114SBram Moolenaar qfp = qf_find_first_entry_on_line(qfp, errornr);
54873ff33114SBram Moolenaar
54883ff33114SBram Moolenaar return qfp;
54893ff33114SBram Moolenaar }
54903ff33114SBram Moolenaar
54913ff33114SBram Moolenaar /*
5492cf6a55c4SBram Moolenaar * Find a quickfix entry in 'qfl' closest to position 'pos' in buffer 'bnr' in
54933ff33114SBram Moolenaar * the direction 'dir'.
54943ff33114SBram Moolenaar */
54953ff33114SBram Moolenaar static qfline_T *
qf_find_closest_entry(qf_list_T * qfl,int bnr,pos_T * pos,int dir,int linewise,int * errornr)54963ff33114SBram Moolenaar qf_find_closest_entry(
54973ff33114SBram Moolenaar qf_list_T *qfl,
54983ff33114SBram Moolenaar int bnr,
5499cf6a55c4SBram Moolenaar pos_T *pos,
55003ff33114SBram Moolenaar int dir,
5501cf6a55c4SBram Moolenaar int linewise,
55023ff33114SBram Moolenaar int *errornr)
55033ff33114SBram Moolenaar {
55043ff33114SBram Moolenaar qfline_T *qfp;
55053ff33114SBram Moolenaar
55063ff33114SBram Moolenaar *errornr = 0;
55073ff33114SBram Moolenaar
55083ff33114SBram Moolenaar // Find the first entry in this file
55093ff33114SBram Moolenaar qfp = qf_find_first_entry_in_buf(qfl, bnr, errornr);
55103ff33114SBram Moolenaar if (qfp == NULL)
55113ff33114SBram Moolenaar return NULL; // no entry in this file
55123ff33114SBram Moolenaar
55133ff33114SBram Moolenaar if (dir == FORWARD)
5514cf6a55c4SBram Moolenaar qfp = qf_find_entry_after_pos(bnr, pos, linewise, qfp, errornr);
55153ff33114SBram Moolenaar else
5516cf6a55c4SBram Moolenaar qfp = qf_find_entry_before_pos(bnr, pos, linewise, qfp, errornr);
55173ff33114SBram Moolenaar
55183ff33114SBram Moolenaar return qfp;
55193ff33114SBram Moolenaar }
55203ff33114SBram Moolenaar
55213ff33114SBram Moolenaar /*
5522cf6a55c4SBram Moolenaar * Get the nth quickfix entry below the specified entry. Searches forward in
5523cf6a55c4SBram Moolenaar * the list. If linewise is TRUE, then treat multiple entries on a single line
5524cf6a55c4SBram Moolenaar * as one.
55253ff33114SBram Moolenaar */
552664416127SBram Moolenaar static void
qf_get_nth_below_entry(qfline_T * entry_arg,int n,int linewise,int * errornr)5527d6a98a3aSBram Moolenaar qf_get_nth_below_entry(qfline_T *entry_arg, int n, int linewise, int *errornr)
55283ff33114SBram Moolenaar {
5529d6a98a3aSBram Moolenaar qfline_T *entry = entry_arg;
5530d6a98a3aSBram Moolenaar
55313ff33114SBram Moolenaar while (n-- > 0 && !got_int)
55323ff33114SBram Moolenaar {
55333ff33114SBram Moolenaar int first_errornr = *errornr;
55343ff33114SBram Moolenaar
5535cf6a55c4SBram Moolenaar if (linewise)
55363ff33114SBram Moolenaar // Treat all the entries on the same line in this file as one
55373ff33114SBram Moolenaar entry = qf_find_last_entry_on_line(entry, errornr);
55383ff33114SBram Moolenaar
55393ff33114SBram Moolenaar if (entry->qf_next == NULL
55403ff33114SBram Moolenaar || entry->qf_next->qf_fnum != entry->qf_fnum)
55413ff33114SBram Moolenaar {
5542cf6a55c4SBram Moolenaar if (linewise)
55433ff33114SBram Moolenaar *errornr = first_errornr;
55443ff33114SBram Moolenaar break;
55453ff33114SBram Moolenaar }
55463ff33114SBram Moolenaar
55473ff33114SBram Moolenaar entry = entry->qf_next;
55483ff33114SBram Moolenaar ++*errornr;
55493ff33114SBram Moolenaar }
55503ff33114SBram Moolenaar }
55513ff33114SBram Moolenaar
55523ff33114SBram Moolenaar /*
5553cf6a55c4SBram Moolenaar * Get the nth quickfix entry above the specified entry. Searches backwards in
5554cf6a55c4SBram Moolenaar * the list. If linewise is TRUE, then treat multiple entries on a single line
5555cf6a55c4SBram Moolenaar * as one.
55563ff33114SBram Moolenaar */
555764416127SBram Moolenaar static void
qf_get_nth_above_entry(qfline_T * entry,int n,int linewise,int * errornr)5558cf6a55c4SBram Moolenaar qf_get_nth_above_entry(qfline_T *entry, int n, int linewise, int *errornr)
55593ff33114SBram Moolenaar {
55603ff33114SBram Moolenaar while (n-- > 0 && !got_int)
55613ff33114SBram Moolenaar {
55623ff33114SBram Moolenaar if (entry->qf_prev == NULL
55633ff33114SBram Moolenaar || entry->qf_prev->qf_fnum != entry->qf_fnum)
55643ff33114SBram Moolenaar break;
55653ff33114SBram Moolenaar
55663ff33114SBram Moolenaar entry = entry->qf_prev;
55673ff33114SBram Moolenaar --*errornr;
55683ff33114SBram Moolenaar
55693ff33114SBram Moolenaar // If multiple entries are on the same line, then use the first entry
5570cf6a55c4SBram Moolenaar if (linewise)
55713ff33114SBram Moolenaar entry = qf_find_first_entry_on_line(entry, errornr);
55723ff33114SBram Moolenaar }
55733ff33114SBram Moolenaar }
55743ff33114SBram Moolenaar
55753ff33114SBram Moolenaar /*
5576cf6a55c4SBram Moolenaar * Find the n'th quickfix entry adjacent to position 'pos' in buffer 'bnr' in
5577cf6a55c4SBram Moolenaar * the specified direction. Returns the error number in the quickfix list or 0
5578cf6a55c4SBram Moolenaar * if an entry is not found.
55793ff33114SBram Moolenaar */
55803ff33114SBram Moolenaar static int
qf_find_nth_adj_entry(qf_list_T * qfl,int bnr,pos_T * pos,int n,int dir,int linewise)5581cf6a55c4SBram Moolenaar qf_find_nth_adj_entry(
5582cf6a55c4SBram Moolenaar qf_list_T *qfl,
5583cf6a55c4SBram Moolenaar int bnr,
5584cf6a55c4SBram Moolenaar pos_T *pos,
5585cf6a55c4SBram Moolenaar int n,
5586cf6a55c4SBram Moolenaar int dir,
5587cf6a55c4SBram Moolenaar int linewise)
55883ff33114SBram Moolenaar {
55893ff33114SBram Moolenaar qfline_T *adj_entry;
55903ff33114SBram Moolenaar int errornr;
55913ff33114SBram Moolenaar
5592cf6a55c4SBram Moolenaar // Find an entry closest to the specified position
5593cf6a55c4SBram Moolenaar adj_entry = qf_find_closest_entry(qfl, bnr, pos, dir, linewise, &errornr);
55943ff33114SBram Moolenaar if (adj_entry == NULL)
55953ff33114SBram Moolenaar return 0;
55963ff33114SBram Moolenaar
55973ff33114SBram Moolenaar if (--n > 0)
55983ff33114SBram Moolenaar {
55993ff33114SBram Moolenaar // Go to the n'th entry in the current buffer
56003ff33114SBram Moolenaar if (dir == FORWARD)
560164416127SBram Moolenaar qf_get_nth_below_entry(adj_entry, n, linewise, &errornr);
56023ff33114SBram Moolenaar else
560364416127SBram Moolenaar qf_get_nth_above_entry(adj_entry, n, linewise, &errornr);
56043ff33114SBram Moolenaar }
56053ff33114SBram Moolenaar
56063ff33114SBram Moolenaar return errornr;
56073ff33114SBram Moolenaar }
56083ff33114SBram Moolenaar
56093ff33114SBram Moolenaar /*
5610cf6a55c4SBram Moolenaar * Jump to a quickfix entry in the current file nearest to the current line or
5611cf6a55c4SBram Moolenaar * current line/col.
5612cf6a55c4SBram Moolenaar * ":cabove", ":cbelow", ":labove", ":lbelow", ":cafter", ":cbefore",
5613cf6a55c4SBram Moolenaar * ":lafter" and ":lbefore" commands
56143ff33114SBram Moolenaar */
56153ff33114SBram Moolenaar void
ex_cbelow(exarg_T * eap)56163ff33114SBram Moolenaar ex_cbelow(exarg_T *eap)
56173ff33114SBram Moolenaar {
56183ff33114SBram Moolenaar qf_info_T *qi;
56193ff33114SBram Moolenaar qf_list_T *qfl;
56203ff33114SBram Moolenaar int dir;
56213ff33114SBram Moolenaar int buf_has_flag;
56223ff33114SBram Moolenaar int errornr = 0;
5623cf6a55c4SBram Moolenaar pos_T pos;
56243ff33114SBram Moolenaar
56253ff33114SBram Moolenaar if (eap->addr_count > 0 && eap->line2 <= 0)
56263ff33114SBram Moolenaar {
5627108010aaSBram Moolenaar emsg(_(e_invalid_range));
56283ff33114SBram Moolenaar return;
56293ff33114SBram Moolenaar }
56303ff33114SBram Moolenaar
56313ff33114SBram Moolenaar // Check whether the current buffer has any quickfix entries
5632cf6a55c4SBram Moolenaar if (eap->cmdidx == CMD_cabove || eap->cmdidx == CMD_cbelow
5633cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_cbefore || eap->cmdidx == CMD_cafter)
56343ff33114SBram Moolenaar buf_has_flag = BUF_HAS_QF_ENTRY;
56353ff33114SBram Moolenaar else
56363ff33114SBram Moolenaar buf_has_flag = BUF_HAS_LL_ENTRY;
56373ff33114SBram Moolenaar if (!(curbuf->b_has_qf_entry & buf_has_flag))
56383ff33114SBram Moolenaar {
5639e29a27f6SBram Moolenaar emsg(_(e_no_errors));
56403ff33114SBram Moolenaar return;
56413ff33114SBram Moolenaar }
56423ff33114SBram Moolenaar
56433ff33114SBram Moolenaar if ((qi = qf_cmd_get_stack(eap, TRUE)) == NULL)
56443ff33114SBram Moolenaar return;
56453ff33114SBram Moolenaar
56463ff33114SBram Moolenaar qfl = qf_get_curlist(qi);
56473ff33114SBram Moolenaar // check if the list has valid errors
56483ff33114SBram Moolenaar if (!qf_list_has_valid_entries(qfl))
56493ff33114SBram Moolenaar {
5650e29a27f6SBram Moolenaar emsg(_(e_no_errors));
56513ff33114SBram Moolenaar return;
56523ff33114SBram Moolenaar }
56533ff33114SBram Moolenaar
5654cf6a55c4SBram Moolenaar if (eap->cmdidx == CMD_cbelow
5655cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_lbelow
5656cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_cafter
5657cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_lafter)
5658cf6a55c4SBram Moolenaar // Forward motion commands
56593ff33114SBram Moolenaar dir = FORWARD;
56603ff33114SBram Moolenaar else
56613ff33114SBram Moolenaar dir = BACKWARD;
56623ff33114SBram Moolenaar
5663cf6a55c4SBram Moolenaar pos = curwin->w_cursor;
5664cf6a55c4SBram Moolenaar // A quickfix entry column number is 1 based whereas cursor column
5665cf6a55c4SBram Moolenaar // number is 0 based. Adjust the column number.
5666cf6a55c4SBram Moolenaar pos.col++;
5667cf6a55c4SBram Moolenaar errornr = qf_find_nth_adj_entry(qfl, curbuf->b_fnum, &pos,
5668cf6a55c4SBram Moolenaar eap->addr_count > 0 ? eap->line2 : 0, dir,
5669cf6a55c4SBram Moolenaar eap->cmdidx == CMD_cbelow
5670cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_lbelow
5671cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_cabove
5672cf6a55c4SBram Moolenaar || eap->cmdidx == CMD_labove);
56733ff33114SBram Moolenaar
56743ff33114SBram Moolenaar if (errornr > 0)
56753ff33114SBram Moolenaar qf_jump(qi, 0, errornr, FALSE);
56763ff33114SBram Moolenaar else
56773ff33114SBram Moolenaar emsg(_(e_no_more_items));
56783ff33114SBram Moolenaar }
56793ff33114SBram Moolenaar
56803ff33114SBram Moolenaar /*
5681a16123a6SBram Moolenaar * Return the autocmd name for the :cfile Ex commands
5682a16123a6SBram Moolenaar */
5683a16123a6SBram Moolenaar static char_u *
cfile_get_auname(cmdidx_T cmdidx)5684a16123a6SBram Moolenaar cfile_get_auname(cmdidx_T cmdidx)
5685a16123a6SBram Moolenaar {
5686a16123a6SBram Moolenaar switch (cmdidx)
5687a16123a6SBram Moolenaar {
5688a16123a6SBram Moolenaar case CMD_cfile: return (char_u *)"cfile";
5689a16123a6SBram Moolenaar case CMD_cgetfile: return (char_u *)"cgetfile";
5690a16123a6SBram Moolenaar case CMD_caddfile: return (char_u *)"caddfile";
5691a16123a6SBram Moolenaar case CMD_lfile: return (char_u *)"lfile";
5692a16123a6SBram Moolenaar case CMD_lgetfile: return (char_u *)"lgetfile";
5693a16123a6SBram Moolenaar case CMD_laddfile: return (char_u *)"laddfile";
5694a16123a6SBram Moolenaar default: return NULL;
5695a16123a6SBram Moolenaar }
5696a16123a6SBram Moolenaar }
5697a16123a6SBram Moolenaar
5698a16123a6SBram Moolenaar /*
569987e25fdfSBram Moolenaar * ":cfile"/":cgetfile"/":caddfile" commands.
5700d12f5c17SBram Moolenaar * ":lfile"/":lgetfile"/":laddfile" commands.
5701071d4279SBram Moolenaar */
5702071d4279SBram Moolenaar void
ex_cfile(exarg_T * eap)570305540976SBram Moolenaar ex_cfile(exarg_T *eap)
5704071d4279SBram Moolenaar {
57052c7292dcSBram Moolenaar char_u *enc = NULL;
5706d12f5c17SBram Moolenaar win_T *wp = NULL;
57078b6144bdSBram Moolenaar qf_info_T *qi = &ql_info;
57088ec1f852SBram Moolenaar char_u *au_name = NULL;
570900bf8cd2SBram Moolenaar int_u save_qfid = 0; // init for gcc
57101ed2276fSBram Moolenaar int res;
5711d12f5c17SBram Moolenaar
5712a16123a6SBram Moolenaar au_name = cfile_get_auname(eap->cmdidx);
57136a0cc916SBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
57146a0cc916SBram Moolenaar NULL, FALSE, curbuf))
57156a0cc916SBram Moolenaar {
57166a0cc916SBram Moolenaar #ifdef FEAT_EVAL
57176a0cc916SBram Moolenaar if (aborting())
57186a0cc916SBram Moolenaar return;
57196a0cc916SBram Moolenaar #endif
57206a0cc916SBram Moolenaar }
5721a16123a6SBram Moolenaar
57222c7292dcSBram Moolenaar enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc;
57239028b10dSBram Moolenaar #ifdef FEAT_BROWSE
5724e1004401SBram Moolenaar if (cmdmod.cmod_flags & CMOD_BROWSE)
57259028b10dSBram Moolenaar {
57269028b10dSBram Moolenaar char_u *browse_file = do_browse(0, (char_u *)_("Error file"), eap->arg,
5727c36651b4SBram Moolenaar NULL, NULL,
5728c36651b4SBram Moolenaar (char_u *)_(BROWSE_FILTER_ALL_FILES), NULL);
57299028b10dSBram Moolenaar if (browse_file == NULL)
57309028b10dSBram Moolenaar return;
57319028b10dSBram Moolenaar set_string_option_direct((char_u *)"ef", -1, browse_file, OPT_FREE, 0);
57329028b10dSBram Moolenaar vim_free(browse_file);
57339028b10dSBram Moolenaar }
57349028b10dSBram Moolenaar else
57359028b10dSBram Moolenaar #endif
5736071d4279SBram Moolenaar if (*eap->arg != NUL)
57375e3cb7e8SBram Moolenaar set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0);
573887e25fdfSBram Moolenaar
573939665959SBram Moolenaar if (is_loclist_cmd(eap->cmdidx))
574014a4deb0SBram Moolenaar wp = curwin;
574114a4deb0SBram Moolenaar
57429f84ded3SBram Moolenaar incr_quickfix_busy();
57439f84ded3SBram Moolenaar
574400bf8cd2SBram Moolenaar // This function is used by the :cfile, :cgetfile and :caddfile
574500bf8cd2SBram Moolenaar // commands.
574600bf8cd2SBram Moolenaar // :cfile always creates a new quickfix list and jumps to the
574700bf8cd2SBram Moolenaar // first error.
574800bf8cd2SBram Moolenaar // :cgetfile creates a new quickfix list but doesn't jump to the
574900bf8cd2SBram Moolenaar // first error.
575000bf8cd2SBram Moolenaar // :caddfile adds to an existing quickfix list. If there is no
575100bf8cd2SBram Moolenaar // quickfix list then a new list is created.
57521ed2276fSBram Moolenaar res = qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile
57538b62e310SBram Moolenaar && eap->cmdidx != CMD_laddfile),
57548b62e310SBram Moolenaar qf_cmdtitle(*eap->cmdlinep), enc);
5755b254af31SBram Moolenaar if (wp != NULL)
5756531b9a3aSBram Moolenaar {
5757b254af31SBram Moolenaar qi = GET_LOC_LIST(wp);
5758531b9a3aSBram Moolenaar if (qi == NULL)
57599f84ded3SBram Moolenaar {
57609f84ded3SBram Moolenaar decr_quickfix_busy();
5761531b9a3aSBram Moolenaar return;
5762531b9a3aSBram Moolenaar }
57639f84ded3SBram Moolenaar }
5764531b9a3aSBram Moolenaar if (res >= 0)
57654aa47b28SBram Moolenaar qf_list_changed(qf_get_curlist(qi));
57664aa47b28SBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
57678ec1f852SBram Moolenaar if (au_name != NULL)
57688ec1f852SBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, NULL, FALSE, curbuf);
57690549a1e1SBram Moolenaar
5770531b9a3aSBram Moolenaar // Jump to the first error for a new list and if autocmds didn't
5771531b9a3aSBram Moolenaar // free the list.
5772531b9a3aSBram Moolenaar if (res > 0 && (eap->cmdidx == CMD_cfile || eap->cmdidx == CMD_lfile)
5773531b9a3aSBram Moolenaar && qflist_valid(wp, save_qfid))
57748d8a65e3SBram Moolenaar // display the first error
57758d8a65e3SBram Moolenaar qf_jump_first(qi, save_qfid, eap->forceit);
57769f84ded3SBram Moolenaar
57779f84ded3SBram Moolenaar decr_quickfix_busy();
5778071d4279SBram Moolenaar }
5779e1bb879fSBram Moolenaar
5780e1bb879fSBram Moolenaar /*
578175b0a888SBram Moolenaar * Return the vimgrep autocmd name.
578275b0a888SBram Moolenaar */
578375b0a888SBram Moolenaar static char_u *
vgr_get_auname(cmdidx_T cmdidx)578475b0a888SBram Moolenaar vgr_get_auname(cmdidx_T cmdidx)
578575b0a888SBram Moolenaar {
578675b0a888SBram Moolenaar switch (cmdidx)
578775b0a888SBram Moolenaar {
578875b0a888SBram Moolenaar case CMD_vimgrep: return (char_u *)"vimgrep";
578975b0a888SBram Moolenaar case CMD_lvimgrep: return (char_u *)"lvimgrep";
579075b0a888SBram Moolenaar case CMD_vimgrepadd: return (char_u *)"vimgrepadd";
579175b0a888SBram Moolenaar case CMD_lvimgrepadd: return (char_u *)"lvimgrepadd";
579275b0a888SBram Moolenaar case CMD_grep: return (char_u *)"grep";
579375b0a888SBram Moolenaar case CMD_lgrep: return (char_u *)"lgrep";
579475b0a888SBram Moolenaar case CMD_grepadd: return (char_u *)"grepadd";
579575b0a888SBram Moolenaar case CMD_lgrepadd: return (char_u *)"lgrepadd";
579675b0a888SBram Moolenaar default: return NULL;
579775b0a888SBram Moolenaar }
579875b0a888SBram Moolenaar }
579975b0a888SBram Moolenaar
580075b0a888SBram Moolenaar /*
580175b0a888SBram Moolenaar * Initialize the regmatch used by vimgrep for pattern "s".
580275b0a888SBram Moolenaar */
580375b0a888SBram Moolenaar static void
vgr_init_regmatch(regmmatch_T * regmatch,char_u * s)580475b0a888SBram Moolenaar vgr_init_regmatch(regmmatch_T *regmatch, char_u *s)
580575b0a888SBram Moolenaar {
580600bf8cd2SBram Moolenaar // Get the search pattern: either white-separated or enclosed in //
580775b0a888SBram Moolenaar regmatch->regprog = NULL;
580875b0a888SBram Moolenaar
580975b0a888SBram Moolenaar if (s == NULL || *s == NUL)
581075b0a888SBram Moolenaar {
581100bf8cd2SBram Moolenaar // Pattern is empty, use last search pattern.
581275b0a888SBram Moolenaar if (last_search_pat() == NULL)
581375b0a888SBram Moolenaar {
5814e29a27f6SBram Moolenaar emsg(_(e_no_previous_regular_expression));
581575b0a888SBram Moolenaar return;
581675b0a888SBram Moolenaar }
581775b0a888SBram Moolenaar regmatch->regprog = vim_regcomp(last_search_pat(), RE_MAGIC);
581875b0a888SBram Moolenaar }
581975b0a888SBram Moolenaar else
582075b0a888SBram Moolenaar regmatch->regprog = vim_regcomp(s, RE_MAGIC);
582175b0a888SBram Moolenaar
582275b0a888SBram Moolenaar regmatch->rmm_ic = p_ic;
582375b0a888SBram Moolenaar regmatch->rmm_maxcol = 0;
582475b0a888SBram Moolenaar }
582575b0a888SBram Moolenaar
582675b0a888SBram Moolenaar /*
582775b0a888SBram Moolenaar * Display a file name when vimgrep is running.
582875b0a888SBram Moolenaar */
582975b0a888SBram Moolenaar static void
vgr_display_fname(char_u * fname)583075b0a888SBram Moolenaar vgr_display_fname(char_u *fname)
583175b0a888SBram Moolenaar {
583275b0a888SBram Moolenaar char_u *p;
583375b0a888SBram Moolenaar
583475b0a888SBram Moolenaar msg_start();
583575b0a888SBram Moolenaar p = msg_strtrunc(fname, TRUE);
583675b0a888SBram Moolenaar if (p == NULL)
583775b0a888SBram Moolenaar msg_outtrans(fname);
583875b0a888SBram Moolenaar else
583975b0a888SBram Moolenaar {
584075b0a888SBram Moolenaar msg_outtrans(p);
584175b0a888SBram Moolenaar vim_free(p);
584275b0a888SBram Moolenaar }
584375b0a888SBram Moolenaar msg_clr_eos();
584400bf8cd2SBram Moolenaar msg_didout = FALSE; // overwrite this message
584500bf8cd2SBram Moolenaar msg_nowait = TRUE; // don't wait for this message
584675b0a888SBram Moolenaar msg_col = 0;
584775b0a888SBram Moolenaar out_flush();
584875b0a888SBram Moolenaar }
584975b0a888SBram Moolenaar
585075b0a888SBram Moolenaar /*
585175b0a888SBram Moolenaar * Load a dummy buffer to search for a pattern using vimgrep.
585275b0a888SBram Moolenaar */
585375b0a888SBram Moolenaar static buf_T *
vgr_load_dummy_buf(char_u * fname,char_u * dirname_start,char_u * dirname_now)585475b0a888SBram Moolenaar vgr_load_dummy_buf(
585575b0a888SBram Moolenaar char_u *fname,
585675b0a888SBram Moolenaar char_u *dirname_start,
585775b0a888SBram Moolenaar char_u *dirname_now)
585875b0a888SBram Moolenaar {
585975b0a888SBram Moolenaar int save_mls;
586075b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
586175b0a888SBram Moolenaar char_u *save_ei = NULL;
586275b0a888SBram Moolenaar #endif
586375b0a888SBram Moolenaar buf_T *buf;
586475b0a888SBram Moolenaar
586575b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
586600bf8cd2SBram Moolenaar // Don't do Filetype autocommands to avoid loading syntax and
586700bf8cd2SBram Moolenaar // indent scripts, a great speed improvement.
586875b0a888SBram Moolenaar save_ei = au_event_disable(",Filetype");
586975b0a888SBram Moolenaar #endif
587000bf8cd2SBram Moolenaar // Don't use modelines here, it's useless.
587175b0a888SBram Moolenaar save_mls = p_mls;
587275b0a888SBram Moolenaar p_mls = 0;
587375b0a888SBram Moolenaar
587400bf8cd2SBram Moolenaar // Load file into a buffer, so that 'fileencoding' is detected,
587500bf8cd2SBram Moolenaar // autocommands applied, etc.
587675b0a888SBram Moolenaar buf = load_dummy_buffer(fname, dirname_start, dirname_now);
587775b0a888SBram Moolenaar
587875b0a888SBram Moolenaar p_mls = save_mls;
587975b0a888SBram Moolenaar #if defined(FEAT_SYN_HL)
588075b0a888SBram Moolenaar au_event_restore(save_ei);
588175b0a888SBram Moolenaar #endif
588275b0a888SBram Moolenaar
588375b0a888SBram Moolenaar return buf;
588475b0a888SBram Moolenaar }
588575b0a888SBram Moolenaar
588675b0a888SBram Moolenaar /*
58874aa47b28SBram Moolenaar * Check whether a quickfix/location list is valid. Autocmds may remove or
58884aa47b28SBram Moolenaar * change a quickfix list when vimgrep is running. If the list is not found,
58894aa47b28SBram Moolenaar * create a new list.
589075b0a888SBram Moolenaar */
589175b0a888SBram Moolenaar static int
vgr_qflist_valid(win_T * wp,qf_info_T * qi,int_u qfid,char_u * title)589275b0a888SBram Moolenaar vgr_qflist_valid(
5893e1bb879fSBram Moolenaar win_T *wp,
589475b0a888SBram Moolenaar qf_info_T *qi,
5895e1bb879fSBram Moolenaar int_u qfid,
589675b0a888SBram Moolenaar char_u *title)
589775b0a888SBram Moolenaar {
589800bf8cd2SBram Moolenaar // Verify that the quickfix/location list was not freed by an autocmd
5899e1bb879fSBram Moolenaar if (!qflist_valid(wp, qfid))
590075b0a888SBram Moolenaar {
5901e1bb879fSBram Moolenaar if (wp != NULL)
590275b0a888SBram Moolenaar {
590300bf8cd2SBram Moolenaar // An autocmd has freed the location list.
59044d170af0SBram Moolenaar emsg(_(e_current_location_list_was_changed));
590575b0a888SBram Moolenaar return FALSE;
590675b0a888SBram Moolenaar }
5907e1bb879fSBram Moolenaar else
590875b0a888SBram Moolenaar {
590900bf8cd2SBram Moolenaar // Quickfix list is not found, create a new one.
5910e1bb879fSBram Moolenaar qf_new_list(qi, title);
5911e1bb879fSBram Moolenaar return TRUE;
5912e1bb879fSBram Moolenaar }
5913e1bb879fSBram Moolenaar }
591475b0a888SBram Moolenaar
591590f1e2b7SBram Moolenaar if (qf_restore_list(qi, qfid) == FAIL)
591690f1e2b7SBram Moolenaar return FALSE;
591775b0a888SBram Moolenaar
591875b0a888SBram Moolenaar return TRUE;
591975b0a888SBram Moolenaar }
592075b0a888SBram Moolenaar
592175b0a888SBram Moolenaar /*
592275b0a888SBram Moolenaar * Search for a pattern in all the lines in a buffer and add the matching lines
592375b0a888SBram Moolenaar * to a quickfix list.
592475b0a888SBram Moolenaar */
592575b0a888SBram Moolenaar static int
vgr_match_buflines(qf_list_T * qfl,char_u * fname,buf_T * buf,char_u * spat,regmmatch_T * regmatch,long * tomatch,int duplicate_name,int flags)592675b0a888SBram Moolenaar vgr_match_buflines(
59279afe5e9cSBram Moolenaar qf_list_T *qfl,
592875b0a888SBram Moolenaar char_u *fname,
592975b0a888SBram Moolenaar buf_T *buf,
5930bb01a1efSYegappan Lakshmanan char_u *spat,
593175b0a888SBram Moolenaar regmmatch_T *regmatch,
59321c299434SBram Moolenaar long *tomatch,
593375b0a888SBram Moolenaar int duplicate_name,
593475b0a888SBram Moolenaar int flags)
593575b0a888SBram Moolenaar {
593675b0a888SBram Moolenaar int found_match = FALSE;
593775b0a888SBram Moolenaar long lnum;
593875b0a888SBram Moolenaar colnr_T col;
5939551c1aedSBram Moolenaar int pat_len = (int)STRLEN(spat);
594075b0a888SBram Moolenaar
59411c299434SBram Moolenaar for (lnum = 1; lnum <= buf->b_ml.ml_line_count && *tomatch > 0; ++lnum)
594275b0a888SBram Moolenaar {
594375b0a888SBram Moolenaar col = 0;
5944bb01a1efSYegappan Lakshmanan if (!(flags & VGR_FUZZY))
5945bb01a1efSYegappan Lakshmanan {
5946bb01a1efSYegappan Lakshmanan // Regular expression match
594775b0a888SBram Moolenaar while (vim_regexec_multi(regmatch, curwin, buf, lnum,
594875b0a888SBram Moolenaar col, NULL, NULL) > 0)
594975b0a888SBram Moolenaar {
595000bf8cd2SBram Moolenaar // Pass the buffer number so that it gets used even for a
595100bf8cd2SBram Moolenaar // dummy buffer, unless duplicate_name is set, then the
595200bf8cd2SBram Moolenaar // buffer will be wiped out below.
59539afe5e9cSBram Moolenaar if (qf_add_entry(qfl,
595400bf8cd2SBram Moolenaar NULL, // dir
595575b0a888SBram Moolenaar fname,
5956d76ce852SBram Moolenaar NULL,
595775b0a888SBram Moolenaar duplicate_name ? 0 : buf->b_fnum,
595875b0a888SBram Moolenaar ml_get_buf(buf,
595975b0a888SBram Moolenaar regmatch->startpos[0].lnum + lnum, FALSE),
596075b0a888SBram Moolenaar regmatch->startpos[0].lnum + lnum,
59616864efa5Sthinca regmatch->endpos[0].lnum + lnum,
596275b0a888SBram Moolenaar regmatch->startpos[0].col + 1,
59636864efa5Sthinca regmatch->endpos[0].col + 1,
596400bf8cd2SBram Moolenaar FALSE, // vis_col
596500bf8cd2SBram Moolenaar NULL, // search pattern
596600bf8cd2SBram Moolenaar 0, // nr
596700bf8cd2SBram Moolenaar 0, // type
596800bf8cd2SBram Moolenaar TRUE // valid
596995946f12SBram Moolenaar ) == QF_FAIL)
597075b0a888SBram Moolenaar {
597175b0a888SBram Moolenaar got_int = TRUE;
597275b0a888SBram Moolenaar break;
597375b0a888SBram Moolenaar }
597475b0a888SBram Moolenaar found_match = TRUE;
59751c299434SBram Moolenaar if (--*tomatch == 0)
597675b0a888SBram Moolenaar break;
597775b0a888SBram Moolenaar if ((flags & VGR_GLOBAL) == 0
597875b0a888SBram Moolenaar || regmatch->endpos[0].lnum > 0)
597975b0a888SBram Moolenaar break;
598075b0a888SBram Moolenaar col = regmatch->endpos[0].col
598175b0a888SBram Moolenaar + (col == regmatch->endpos[0].col);
598275b0a888SBram Moolenaar if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE)))
598375b0a888SBram Moolenaar break;
598475b0a888SBram Moolenaar }
5985bb01a1efSYegappan Lakshmanan }
5986bb01a1efSYegappan Lakshmanan else
5987bb01a1efSYegappan Lakshmanan {
5988bb01a1efSYegappan Lakshmanan char_u *str = ml_get_buf(buf, lnum, FALSE);
5989bb01a1efSYegappan Lakshmanan int score;
5990bb01a1efSYegappan Lakshmanan int_u matches[MAX_FUZZY_MATCHES];
5991eeec2548SK.Takata int_u sz = ARRAY_LENGTH(matches);
5992bb01a1efSYegappan Lakshmanan
5993bb01a1efSYegappan Lakshmanan // Fuzzy string match
5994bb01a1efSYegappan Lakshmanan while (fuzzy_match(str + col, spat, FALSE, &score, matches, sz) > 0)
5995bb01a1efSYegappan Lakshmanan {
5996bb01a1efSYegappan Lakshmanan // Pass the buffer number so that it gets used even for a
5997bb01a1efSYegappan Lakshmanan // dummy buffer, unless duplicate_name is set, then the
5998bb01a1efSYegappan Lakshmanan // buffer will be wiped out below.
5999bb01a1efSYegappan Lakshmanan if (qf_add_entry(qfl,
6000bb01a1efSYegappan Lakshmanan NULL, // dir
6001bb01a1efSYegappan Lakshmanan fname,
6002bb01a1efSYegappan Lakshmanan NULL,
6003bb01a1efSYegappan Lakshmanan duplicate_name ? 0 : buf->b_fnum,
6004bb01a1efSYegappan Lakshmanan str,
6005bb01a1efSYegappan Lakshmanan lnum,
60066864efa5Sthinca 0,
6007bb01a1efSYegappan Lakshmanan matches[0] + col + 1,
60086864efa5Sthinca 0,
6009bb01a1efSYegappan Lakshmanan FALSE, // vis_col
6010bb01a1efSYegappan Lakshmanan NULL, // search pattern
6011bb01a1efSYegappan Lakshmanan 0, // nr
6012bb01a1efSYegappan Lakshmanan 0, // type
6013bb01a1efSYegappan Lakshmanan TRUE // valid
6014bb01a1efSYegappan Lakshmanan ) == QF_FAIL)
6015bb01a1efSYegappan Lakshmanan {
6016bb01a1efSYegappan Lakshmanan got_int = TRUE;
6017bb01a1efSYegappan Lakshmanan break;
6018bb01a1efSYegappan Lakshmanan }
6019bb01a1efSYegappan Lakshmanan found_match = TRUE;
6020bb01a1efSYegappan Lakshmanan if (--*tomatch == 0)
6021bb01a1efSYegappan Lakshmanan break;
6022bb01a1efSYegappan Lakshmanan if ((flags & VGR_GLOBAL) == 0)
6023bb01a1efSYegappan Lakshmanan break;
6024bb01a1efSYegappan Lakshmanan col = matches[pat_len - 1] + col + 1;
6025bb01a1efSYegappan Lakshmanan if (col > (colnr_T)STRLEN(str))
6026bb01a1efSYegappan Lakshmanan break;
6027bb01a1efSYegappan Lakshmanan }
6028bb01a1efSYegappan Lakshmanan }
602975b0a888SBram Moolenaar line_breakcheck();
603075b0a888SBram Moolenaar if (got_int)
603175b0a888SBram Moolenaar break;
603275b0a888SBram Moolenaar }
603375b0a888SBram Moolenaar
603475b0a888SBram Moolenaar return found_match;
603575b0a888SBram Moolenaar }
603675b0a888SBram Moolenaar
603775b0a888SBram Moolenaar /*
603875b0a888SBram Moolenaar * Jump to the first match and update the directory.
603975b0a888SBram Moolenaar */
604075b0a888SBram Moolenaar 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)604175b0a888SBram Moolenaar vgr_jump_to_match(
604275b0a888SBram Moolenaar qf_info_T *qi,
604375b0a888SBram Moolenaar int forceit,
604475b0a888SBram Moolenaar int *redraw_for_dummy,
604575b0a888SBram Moolenaar buf_T *first_match_buf,
604675b0a888SBram Moolenaar char_u *target_dir)
604775b0a888SBram Moolenaar {
604875b0a888SBram Moolenaar buf_T *buf;
604975b0a888SBram Moolenaar
605075b0a888SBram Moolenaar buf = curbuf;
605175b0a888SBram Moolenaar qf_jump(qi, 0, 0, forceit);
605275b0a888SBram Moolenaar if (buf != curbuf)
605300bf8cd2SBram Moolenaar // If we jumped to another buffer redrawing will already be
605400bf8cd2SBram Moolenaar // taken care of.
605575b0a888SBram Moolenaar *redraw_for_dummy = FALSE;
605675b0a888SBram Moolenaar
605700bf8cd2SBram Moolenaar // Jump to the directory used after loading the buffer.
605875b0a888SBram Moolenaar if (curbuf == first_match_buf && target_dir != NULL)
605975b0a888SBram Moolenaar {
606075b0a888SBram Moolenaar exarg_T ea;
606175b0a888SBram Moolenaar
6062a80faa89SBram Moolenaar CLEAR_FIELD(ea);
606375b0a888SBram Moolenaar ea.arg = target_dir;
606475b0a888SBram Moolenaar ea.cmdidx = CMD_lcd;
606575b0a888SBram Moolenaar ex_cd(&ea);
606675b0a888SBram Moolenaar }
606775b0a888SBram Moolenaar }
606875b0a888SBram Moolenaar
606975b0a888SBram Moolenaar /*
6070d6a98a3aSBram Moolenaar * :vimgrep command arguments
607186b68359SBram Moolenaar */
6072d6a98a3aSBram Moolenaar typedef struct
607386b68359SBram Moolenaar {
6074d6a98a3aSBram Moolenaar long tomatch; // maximum number of matches to find
6075d6a98a3aSBram Moolenaar char_u *spat; // search pattern
6076d6a98a3aSBram Moolenaar int flags; // search modifier
6077d6a98a3aSBram Moolenaar char_u **fnames; // list of files to search
6078d6a98a3aSBram Moolenaar int fcount; // number of files
6079d6a98a3aSBram Moolenaar regmmatch_T regmatch; // compiled search pattern
6080d6a98a3aSBram Moolenaar char_u *qf_title; // quickfix list title
6081d6a98a3aSBram Moolenaar } vgr_args_T;
6082d6a98a3aSBram Moolenaar
6083d6a98a3aSBram Moolenaar /*
6084d6a98a3aSBram Moolenaar * Process :vimgrep command arguments. The command syntax is:
6085d6a98a3aSBram Moolenaar *
6086d6a98a3aSBram Moolenaar * :{count}vimgrep /{pattern}/[g][j] {file} ...
6087d6a98a3aSBram Moolenaar */
6088d6a98a3aSBram Moolenaar static int
vgr_process_args(exarg_T * eap,vgr_args_T * args)6089d6a98a3aSBram Moolenaar vgr_process_args(
6090d6a98a3aSBram Moolenaar exarg_T *eap,
6091d6a98a3aSBram Moolenaar vgr_args_T *args)
6092d6a98a3aSBram Moolenaar {
609386b68359SBram Moolenaar char_u *p;
60947c62692dSBram Moolenaar
6095d6a98a3aSBram Moolenaar vim_memset(args, 0, sizeof(*args));
609686b68359SBram Moolenaar
6097d6a98a3aSBram Moolenaar args->regmatch.regprog = NULL;
6098d6a98a3aSBram Moolenaar args->qf_title = vim_strsave(qf_cmdtitle(*eap->cmdlinep));
6099a6557605SBram Moolenaar
61001f35bf9cSBram Moolenaar if (eap->addr_count > 0)
6101d6a98a3aSBram Moolenaar args->tomatch = eap->line2;
61021f35bf9cSBram Moolenaar else
6103d6a98a3aSBram Moolenaar args->tomatch = MAXLNUM;
61041f35bf9cSBram Moolenaar
610500bf8cd2SBram Moolenaar // Get the search pattern: either white-separated or enclosed in //
6106d6a98a3aSBram Moolenaar p = skip_vimgrep_pat(eap->arg, &args->spat, &args->flags);
6107748bf037SBram Moolenaar if (p == NULL)
610886b68359SBram Moolenaar {
6109f9e3e09fSBram Moolenaar emsg(_(e_invalpat));
6110d6a98a3aSBram Moolenaar return FAIL;
611186b68359SBram Moolenaar }
611260abe753SBram Moolenaar
6113d6a98a3aSBram Moolenaar vgr_init_regmatch(&args->regmatch, args->spat);
6114d6a98a3aSBram Moolenaar if (args->regmatch.regprog == NULL)
6115d6a98a3aSBram Moolenaar return FAIL;
611686b68359SBram Moolenaar
611786b68359SBram Moolenaar p = skipwhite(p);
611886b68359SBram Moolenaar if (*p == NUL)
611986b68359SBram Moolenaar {
6120f9e3e09fSBram Moolenaar emsg(_("E683: File name missing or invalid pattern"));
6121d6a98a3aSBram Moolenaar return FAIL;
612286b68359SBram Moolenaar }
612386b68359SBram Moolenaar
6124f8c6a171SBram Moolenaar // Parse the list of arguments, wildcards have already been expanded.
6125d6a98a3aSBram Moolenaar if (get_arglist_exp(p, &args->fcount, &args->fnames, TRUE) == FAIL)
6126d6a98a3aSBram Moolenaar return FAIL;
6127d6a98a3aSBram Moolenaar if (args->fcount == 0)
612886b68359SBram Moolenaar {
6129f9e3e09fSBram Moolenaar emsg(_(e_nomatch));
6130d6a98a3aSBram Moolenaar return FAIL;
613186b68359SBram Moolenaar }
613286b68359SBram Moolenaar
6133d6a98a3aSBram Moolenaar return OK;
6134d6a98a3aSBram Moolenaar }
6135d6a98a3aSBram Moolenaar
6136d6a98a3aSBram Moolenaar /*
61378ce4b7edSBram Moolenaar * Return TRUE if "buf" had an existing swap file, the current swap file does
61388ce4b7edSBram Moolenaar * not end in ".swp".
61398ce4b7edSBram Moolenaar */
61408ce4b7edSBram Moolenaar static int
existing_swapfile(buf_T * buf)61418ce4b7edSBram Moolenaar existing_swapfile(buf_T *buf)
61428ce4b7edSBram Moolenaar {
6143997cd1a1SBram Moolenaar if (buf->b_ml.ml_mfp != NULL && buf->b_ml.ml_mfp->mf_fname != NULL)
61448ce4b7edSBram Moolenaar {
61458ce4b7edSBram Moolenaar char_u *fname = buf->b_ml.ml_mfp->mf_fname;
61468ce4b7edSBram Moolenaar size_t len = STRLEN(fname);
61478ce4b7edSBram Moolenaar
61488ce4b7edSBram Moolenaar return fname[len - 1] != 'p' || fname[len - 2] != 'w';
61498ce4b7edSBram Moolenaar }
61508ce4b7edSBram Moolenaar return FALSE;
61518ce4b7edSBram Moolenaar }
61528ce4b7edSBram Moolenaar
61538ce4b7edSBram Moolenaar /*
6154d6a98a3aSBram Moolenaar * Search for a pattern in a list of files and populate the quickfix list with
6155d6a98a3aSBram Moolenaar * the matches.
6156d6a98a3aSBram Moolenaar */
6157d6a98a3aSBram Moolenaar 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)6158d6a98a3aSBram Moolenaar vgr_process_files(
6159d6a98a3aSBram Moolenaar win_T *wp,
6160d6a98a3aSBram Moolenaar qf_info_T *qi,
6161d6a98a3aSBram Moolenaar vgr_args_T *cmd_args,
6162d6a98a3aSBram Moolenaar int *redraw_for_dummy,
6163d6a98a3aSBram Moolenaar buf_T **first_match_buf,
6164d6a98a3aSBram Moolenaar char_u **target_dir)
6165d6a98a3aSBram Moolenaar {
6166d6a98a3aSBram Moolenaar int status = FAIL;
6167d6a98a3aSBram Moolenaar int_u save_qfid = qf_get_curlist(qi)->qf_id;
6168d6a98a3aSBram Moolenaar time_t seconds = 0;
6169d6a98a3aSBram Moolenaar char_u *fname;
6170d6a98a3aSBram Moolenaar int fi;
6171d6a98a3aSBram Moolenaar buf_T *buf;
6172d6a98a3aSBram Moolenaar int duplicate_name = FALSE;
6173d6a98a3aSBram Moolenaar int using_dummy;
6174d6a98a3aSBram Moolenaar char_u *dirname_start = NULL;
6175d6a98a3aSBram Moolenaar char_u *dirname_now = NULL;
6176d6a98a3aSBram Moolenaar int found_match;
6177d6a98a3aSBram Moolenaar aco_save_T aco;
6178d6a98a3aSBram Moolenaar
6179b86a3432SBram Moolenaar dirname_start = alloc_id(MAXPATHL, aid_qf_dirname_start);
6180b86a3432SBram Moolenaar dirname_now = alloc_id(MAXPATHL, aid_qf_dirname_now);
6181d9462e39SBram Moolenaar if (dirname_start == NULL || dirname_now == NULL)
6182d9462e39SBram Moolenaar goto theend;
6183d9462e39SBram Moolenaar
618400bf8cd2SBram Moolenaar // Remember the current directory, because a BufRead autocommand that does
618500bf8cd2SBram Moolenaar // ":lcd %:p:h" changes the meaning of short path names.
6186d089d9b3SBram Moolenaar mch_dirname(dirname_start, MAXPATHL);
6187d089d9b3SBram Moolenaar
6188dcaf10e1SBram Moolenaar seconds = (time_t)0;
6189d6a98a3aSBram Moolenaar for (fi = 0; fi < cmd_args->fcount && !got_int && cmd_args->tomatch > 0;
6190d6a98a3aSBram Moolenaar ++fi)
619186b68359SBram Moolenaar {
6192d6a98a3aSBram Moolenaar fname = shorten_fname1(cmd_args->fnames[fi]);
6193dcaf10e1SBram Moolenaar if (time(NULL) > seconds)
6194dcaf10e1SBram Moolenaar {
619500bf8cd2SBram Moolenaar // Display the file name every second or so, show the user we are
619600bf8cd2SBram Moolenaar // working on it.
6197dcaf10e1SBram Moolenaar seconds = time(NULL);
619875b0a888SBram Moolenaar vgr_display_fname(fname);
6199dcaf10e1SBram Moolenaar }
6200dcaf10e1SBram Moolenaar
6201d6a98a3aSBram Moolenaar buf = buflist_findname_exp(cmd_args->fnames[fi]);
620281695250SBram Moolenaar if (buf == NULL || buf->b_ml.ml_mfp == NULL)
620381695250SBram Moolenaar {
620400bf8cd2SBram Moolenaar // Remember that a buffer with this name already exists.
620581695250SBram Moolenaar duplicate_name = (buf != NULL);
6206dcaf10e1SBram Moolenaar using_dummy = TRUE;
6207d6a98a3aSBram Moolenaar *redraw_for_dummy = TRUE;
6208dcaf10e1SBram Moolenaar
620975b0a888SBram Moolenaar buf = vgr_load_dummy_buf(fname, dirname_start, dirname_now);
621081695250SBram Moolenaar }
621181695250SBram Moolenaar else
621200bf8cd2SBram Moolenaar // Use existing, loaded buffer.
621381695250SBram Moolenaar using_dummy = FALSE;
6214dcaf10e1SBram Moolenaar
621500bf8cd2SBram Moolenaar // Check whether the quickfix list is still valid. When loading a
621600bf8cd2SBram Moolenaar // buffer above, autocommands might have changed the quickfix list.
6217d6a98a3aSBram Moolenaar if (!vgr_qflist_valid(wp, qi, save_qfid, cmd_args->qf_title))
62183c097226SBram Moolenaar goto theend;
6219d6a98a3aSBram Moolenaar
62204aa47b28SBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
6221321a9ec6SBram Moolenaar
622281695250SBram Moolenaar if (buf == NULL)
6223dcaf10e1SBram Moolenaar {
6224dcaf10e1SBram Moolenaar if (!got_int)
6225f9e3e09fSBram Moolenaar smsg(_("Cannot open file \"%s\""), fname);
6226dcaf10e1SBram Moolenaar }
622786b68359SBram Moolenaar else
622886b68359SBram Moolenaar {
622900bf8cd2SBram Moolenaar // Try for a match in all lines of the buffer.
623000bf8cd2SBram Moolenaar // For ":1vimgrep" look for first match only.
62319afe5e9cSBram Moolenaar found_match = vgr_match_buflines(qf_get_curlist(qi),
6232bb01a1efSYegappan Lakshmanan fname, buf, cmd_args->spat, &cmd_args->regmatch,
6233d6a98a3aSBram Moolenaar &cmd_args->tomatch, duplicate_name, cmd_args->flags);
623475b0a888SBram Moolenaar
623581695250SBram Moolenaar if (using_dummy)
623681695250SBram Moolenaar {
6237d6a98a3aSBram Moolenaar if (found_match && *first_match_buf == NULL)
6238d6a98a3aSBram Moolenaar *first_match_buf = buf;
623981695250SBram Moolenaar if (duplicate_name)
6240dcaf10e1SBram Moolenaar {
624100bf8cd2SBram Moolenaar // Never keep a dummy buffer if there is another buffer
624200bf8cd2SBram Moolenaar // with the same name.
62437f51a82cSBram Moolenaar wipe_dummy_buffer(buf, dirname_start);
6244dcaf10e1SBram Moolenaar buf = NULL;
6245dcaf10e1SBram Moolenaar }
6246e1004401SBram Moolenaar else if ((cmdmod.cmod_flags & CMOD_HIDE) == 0
624700bf8cd2SBram Moolenaar || buf->b_p_bh[0] == 'u' // "unload"
624800bf8cd2SBram Moolenaar || buf->b_p_bh[0] == 'w' // "wipe"
624900bf8cd2SBram Moolenaar || buf->b_p_bh[0] == 'd') // "delete"
625081695250SBram Moolenaar {
625100bf8cd2SBram Moolenaar // When no match was found we don't need to remember the
625200bf8cd2SBram Moolenaar // buffer, wipe it out. If there was a match and it
625300bf8cd2SBram Moolenaar // wasn't the first one or we won't jump there: only
625400bf8cd2SBram Moolenaar // unload the buffer.
625500bf8cd2SBram Moolenaar // Ignore 'hidden' here, because it may lead to having too
625600bf8cd2SBram Moolenaar // many swap files.
625781695250SBram Moolenaar if (!found_match)
6258dcaf10e1SBram Moolenaar {
62597f51a82cSBram Moolenaar wipe_dummy_buffer(buf, dirname_start);
6260dcaf10e1SBram Moolenaar buf = NULL;
6261dcaf10e1SBram Moolenaar }
6262d6a98a3aSBram Moolenaar else if (buf != *first_match_buf
62638ce4b7edSBram Moolenaar || (cmd_args->flags & VGR_NOJUMP)
62648ce4b7edSBram Moolenaar || existing_swapfile(buf))
6265dcaf10e1SBram Moolenaar {
62667f51a82cSBram Moolenaar unload_dummy_buffer(buf, dirname_start);
626700bf8cd2SBram Moolenaar // Keeping the buffer, remove the dummy flag.
6268015102e9SBram Moolenaar buf->b_flags &= ~BF_DUMMY;
6269dcaf10e1SBram Moolenaar buf = NULL;
627081695250SBram Moolenaar }
627181695250SBram Moolenaar }
6272dcaf10e1SBram Moolenaar
6273dcaf10e1SBram Moolenaar if (buf != NULL)
6274dcaf10e1SBram Moolenaar {
627500bf8cd2SBram Moolenaar // Keeping the buffer, remove the dummy flag.
6276015102e9SBram Moolenaar buf->b_flags &= ~BF_DUMMY;
6277015102e9SBram Moolenaar
627800bf8cd2SBram Moolenaar // If the buffer is still loaded we need to use the
627900bf8cd2SBram Moolenaar // directory we jumped to below.
6280d6a98a3aSBram Moolenaar if (buf == *first_match_buf
6281d6a98a3aSBram Moolenaar && *target_dir == NULL
6282d089d9b3SBram Moolenaar && STRCMP(dirname_start, dirname_now) != 0)
6283d6a98a3aSBram Moolenaar *target_dir = vim_strsave(dirname_now);
6284d089d9b3SBram Moolenaar
628500bf8cd2SBram Moolenaar // The buffer is still loaded, the Filetype autocommands
628600bf8cd2SBram Moolenaar // need to be done now, in that buffer. And the modelines
628700bf8cd2SBram Moolenaar // need to be done (again). But not the window-local
628800bf8cd2SBram Moolenaar // options!
6289dcaf10e1SBram Moolenaar aucmd_prepbuf(&aco, buf);
6290f2bd8ef2SBram Moolenaar #if defined(FEAT_SYN_HL)
6291dcaf10e1SBram Moolenaar apply_autocmds(EVENT_FILETYPE, buf->b_p_ft,
6292dcaf10e1SBram Moolenaar buf->b_fname, TRUE, buf);
6293dcaf10e1SBram Moolenaar #endif
6294a3227e2bSBram Moolenaar do_modelines(OPT_NOWIN);
6295faa959a8SBram Moolenaar aucmd_restbuf(&aco);
6296faa959a8SBram Moolenaar }
6297dcaf10e1SBram Moolenaar }
629886b68359SBram Moolenaar }
629986b68359SBram Moolenaar }
630086b68359SBram Moolenaar
6301d6a98a3aSBram Moolenaar status = OK;
6302d6a98a3aSBram Moolenaar
6303d6a98a3aSBram Moolenaar theend:
6304d6a98a3aSBram Moolenaar vim_free(dirname_now);
6305d6a98a3aSBram Moolenaar vim_free(dirname_start);
6306d6a98a3aSBram Moolenaar return status;
6307d6a98a3aSBram Moolenaar }
6308d6a98a3aSBram Moolenaar
6309d6a98a3aSBram Moolenaar /*
6310d6a98a3aSBram Moolenaar * ":vimgrep {pattern} file(s)"
6311d6a98a3aSBram Moolenaar * ":vimgrepadd {pattern} file(s)"
6312d6a98a3aSBram Moolenaar * ":lvimgrep {pattern} file(s)"
6313d6a98a3aSBram Moolenaar * ":lvimgrepadd {pattern} file(s)"
6314d6a98a3aSBram Moolenaar */
6315d6a98a3aSBram Moolenaar void
ex_vimgrep(exarg_T * eap)6316d6a98a3aSBram Moolenaar ex_vimgrep(exarg_T *eap)
6317d6a98a3aSBram Moolenaar {
6318d6a98a3aSBram Moolenaar vgr_args_T args;
6319d6a98a3aSBram Moolenaar qf_info_T *qi;
6320d6a98a3aSBram Moolenaar qf_list_T *qfl;
6321d6a98a3aSBram Moolenaar int_u save_qfid;
6322d6a98a3aSBram Moolenaar win_T *wp = NULL;
6323d6a98a3aSBram Moolenaar int redraw_for_dummy = FALSE;
6324d6a98a3aSBram Moolenaar buf_T *first_match_buf = NULL;
6325d6a98a3aSBram Moolenaar char_u *target_dir = NULL;
6326d6a98a3aSBram Moolenaar char_u *au_name = NULL;
6327d6a98a3aSBram Moolenaar int status;
6328d6a98a3aSBram Moolenaar
6329d6a98a3aSBram Moolenaar au_name = vgr_get_auname(eap->cmdidx);
6330d6a98a3aSBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
6331d6a98a3aSBram Moolenaar curbuf->b_fname, TRUE, curbuf))
6332d6a98a3aSBram Moolenaar {
6333d6a98a3aSBram Moolenaar #ifdef FEAT_EVAL
6334d6a98a3aSBram Moolenaar if (aborting())
6335d6a98a3aSBram Moolenaar return;
6336d6a98a3aSBram Moolenaar #endif
6337d6a98a3aSBram Moolenaar }
6338d6a98a3aSBram Moolenaar
6339d6a98a3aSBram Moolenaar qi = qf_cmd_get_or_alloc_stack(eap, &wp);
6340d6a98a3aSBram Moolenaar if (qi == NULL)
6341d6a98a3aSBram Moolenaar return;
6342d6a98a3aSBram Moolenaar
6343d6a98a3aSBram Moolenaar if (vgr_process_args(eap, &args) == FAIL)
6344d6a98a3aSBram Moolenaar goto theend;
6345d6a98a3aSBram Moolenaar
6346d6a98a3aSBram Moolenaar if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd
6347d6a98a3aSBram Moolenaar && eap->cmdidx != CMD_vimgrepadd
6348d6a98a3aSBram Moolenaar && eap->cmdidx != CMD_lvimgrepadd)
6349d6a98a3aSBram Moolenaar || qf_stack_empty(qi))
6350d6a98a3aSBram Moolenaar // make place for a new list
6351d6a98a3aSBram Moolenaar qf_new_list(qi, args.qf_title);
6352d6a98a3aSBram Moolenaar
6353d6a98a3aSBram Moolenaar incr_quickfix_busy();
6354d6a98a3aSBram Moolenaar
6355d6a98a3aSBram Moolenaar status = vgr_process_files(wp, qi, &args, &redraw_for_dummy,
6356d6a98a3aSBram Moolenaar &first_match_buf, &target_dir);
6357d6a98a3aSBram Moolenaar if (status != OK)
6358d6a98a3aSBram Moolenaar {
6359d6a98a3aSBram Moolenaar FreeWild(args.fcount, args.fnames);
6360d6a98a3aSBram Moolenaar decr_quickfix_busy();
6361d6a98a3aSBram Moolenaar goto theend;
6362d6a98a3aSBram Moolenaar }
6363d6a98a3aSBram Moolenaar
6364d6a98a3aSBram Moolenaar FreeWild(args.fcount, args.fnames);
636586b68359SBram Moolenaar
63664aa47b28SBram Moolenaar qfl = qf_get_curlist(qi);
6367108e7b42SBram Moolenaar qfl->qf_nonevalid = FALSE;
6368108e7b42SBram Moolenaar qfl->qf_ptr = qfl->qf_start;
6369108e7b42SBram Moolenaar qfl->qf_index = 1;
6370108e7b42SBram Moolenaar qf_list_changed(qfl);
637186b68359SBram Moolenaar
6372864293abSBram Moolenaar qf_update_buffer(qi, NULL);
637386b68359SBram Moolenaar
6374d6a98a3aSBram Moolenaar // Remember the current quickfix list identifier, so that we can check for
6375d6a98a3aSBram Moolenaar // autocommands changing the current quickfix list.
6376d6a98a3aSBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
6377d6a98a3aSBram Moolenaar
6378f9393ef5SBram Moolenaar if (au_name != NULL)
6379f9393ef5SBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
6380f9393ef5SBram Moolenaar curbuf->b_fname, TRUE, curbuf);
638100bf8cd2SBram Moolenaar // The QuickFixCmdPost autocmd may free the quickfix list. Check the list
638200bf8cd2SBram Moolenaar // is still valid.
63839f84ded3SBram Moolenaar if (!qflist_valid(wp, save_qfid)
63849f84ded3SBram Moolenaar || qf_restore_list(qi, save_qfid) == FAIL)
63859f84ded3SBram Moolenaar {
63869f84ded3SBram Moolenaar decr_quickfix_busy();
63873c097226SBram Moolenaar goto theend;
63889f84ded3SBram Moolenaar }
6389531b9a3aSBram Moolenaar
6390c631f2dfSBram Moolenaar // Jump to first match.
63910398e00aSBram Moolenaar if (!qf_list_empty(qf_get_curlist(qi)))
639205159a0cSBram Moolenaar {
6393d6a98a3aSBram Moolenaar if ((args.flags & VGR_NOJUMP) == 0)
639475b0a888SBram Moolenaar vgr_jump_to_match(qi, eap->forceit, &redraw_for_dummy,
639575b0a888SBram Moolenaar first_match_buf, target_dir);
639605159a0cSBram Moolenaar }
639781695250SBram Moolenaar else
6398d6a98a3aSBram Moolenaar semsg(_(e_nomatch2), args.spat);
639986b68359SBram Moolenaar
64009f84ded3SBram Moolenaar decr_quickfix_busy();
64019f84ded3SBram Moolenaar
640200bf8cd2SBram Moolenaar // If we loaded a dummy buffer into the current window, the autocommands
640300bf8cd2SBram Moolenaar // may have messed up things, need to redraw and recompute folds.
64041042fa38SBram Moolenaar if (redraw_for_dummy)
64051042fa38SBram Moolenaar {
64061042fa38SBram Moolenaar #ifdef FEAT_FOLDING
64071042fa38SBram Moolenaar foldUpdateAll(curwin);
64081042fa38SBram Moolenaar #else
64091042fa38SBram Moolenaar redraw_later(NOT_VALID);
64101042fa38SBram Moolenaar #endif
64111042fa38SBram Moolenaar }
64121042fa38SBram Moolenaar
641386b68359SBram Moolenaar theend:
6414d6a98a3aSBram Moolenaar vim_free(args.qf_title);
6415d089d9b3SBram Moolenaar vim_free(target_dir);
6416d6a98a3aSBram Moolenaar vim_regfree(args.regmatch.regprog);
641786b68359SBram Moolenaar }
641886b68359SBram Moolenaar
641986b68359SBram Moolenaar /*
64207f51a82cSBram Moolenaar * Restore current working directory to "dirname_start" if they differ, taking
64217f51a82cSBram Moolenaar * into account whether it is set locally or globally.
64227f51a82cSBram Moolenaar */
64237f51a82cSBram Moolenaar static void
restore_start_dir(char_u * dirname_start)642405540976SBram Moolenaar restore_start_dir(char_u *dirname_start)
64257f51a82cSBram Moolenaar {
64267f51a82cSBram Moolenaar char_u *dirname_now = alloc(MAXPATHL);
64277f51a82cSBram Moolenaar
64287f51a82cSBram Moolenaar if (NULL != dirname_now)
64297f51a82cSBram Moolenaar {
64307f51a82cSBram Moolenaar mch_dirname(dirname_now, MAXPATHL);
64317f51a82cSBram Moolenaar if (STRCMP(dirname_start, dirname_now) != 0)
64327f51a82cSBram Moolenaar {
643300bf8cd2SBram Moolenaar // If the directory has changed, change it back by building up an
643400bf8cd2SBram Moolenaar // appropriate ex command and executing it.
64357f51a82cSBram Moolenaar exarg_T ea;
64367f51a82cSBram Moolenaar
6437a80faa89SBram Moolenaar CLEAR_FIELD(ea);
64387f51a82cSBram Moolenaar ea.arg = dirname_start;
64397f51a82cSBram Moolenaar ea.cmdidx = (curwin->w_localdir == NULL) ? CMD_cd : CMD_lcd;
64407f51a82cSBram Moolenaar ex_cd(&ea);
64417f51a82cSBram Moolenaar }
6442f135435fSBram Moolenaar vim_free(dirname_now);
64437f51a82cSBram Moolenaar }
64447f51a82cSBram Moolenaar }
64457f51a82cSBram Moolenaar
64467f51a82cSBram Moolenaar /*
64477f51a82cSBram Moolenaar * Load file "fname" into a dummy buffer and return the buffer pointer,
64487f51a82cSBram Moolenaar * placing the directory resulting from the buffer load into the
64497f51a82cSBram Moolenaar * "resulting_dir" pointer. "resulting_dir" must be allocated by the caller
64507f51a82cSBram Moolenaar * prior to calling this function. Restores directory to "dirname_start" prior
64517f51a82cSBram Moolenaar * to returning, if autocmds or the 'autochdir' option have changed it.
64527f51a82cSBram Moolenaar *
64537f51a82cSBram Moolenaar * If creating the dummy buffer does not fail, must call unload_dummy_buffer()
64547f51a82cSBram Moolenaar * or wipe_dummy_buffer() later!
64557f51a82cSBram Moolenaar *
645681695250SBram Moolenaar * Returns NULL if it fails.
645781695250SBram Moolenaar */
645881695250SBram Moolenaar static buf_T *
load_dummy_buffer(char_u * fname,char_u * dirname_start,char_u * resulting_dir)645905540976SBram Moolenaar load_dummy_buffer(
646005540976SBram Moolenaar char_u *fname,
646100bf8cd2SBram Moolenaar char_u *dirname_start, // in: old directory
646200bf8cd2SBram Moolenaar char_u *resulting_dir) // out: new directory
646381695250SBram Moolenaar {
646481695250SBram Moolenaar buf_T *newbuf;
64657c0a2f36SBram Moolenaar bufref_T newbufref;
64667c0a2f36SBram Moolenaar bufref_T newbuf_to_wipe;
646781695250SBram Moolenaar int failed = TRUE;
646881695250SBram Moolenaar aco_save_T aco;
64694fb921e3SBram Moolenaar int readfile_result;
647081695250SBram Moolenaar
647100bf8cd2SBram Moolenaar // Allocate a buffer without putting it in the buffer list.
647281695250SBram Moolenaar newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY);
647381695250SBram Moolenaar if (newbuf == NULL)
647481695250SBram Moolenaar return NULL;
64757c0a2f36SBram Moolenaar set_bufref(&newbufref, newbuf);
647681695250SBram Moolenaar
647700bf8cd2SBram Moolenaar // Init the options.
64788cd06cabSBram Moolenaar buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP);
64798cd06cabSBram Moolenaar
648000bf8cd2SBram Moolenaar // need to open the memfile before putting the buffer in a window
6481f061e0beSBram Moolenaar if (ml_open(newbuf) == OK)
6482f061e0beSBram Moolenaar {
648300bf8cd2SBram Moolenaar // Make sure this buffer isn't wiped out by autocommands.
64844fb921e3SBram Moolenaar ++newbuf->b_locked;
64854fb921e3SBram Moolenaar
648600bf8cd2SBram Moolenaar // set curwin/curbuf to buf and save a few things
648781695250SBram Moolenaar aucmd_prepbuf(&aco, newbuf);
648881695250SBram Moolenaar
648900bf8cd2SBram Moolenaar // Need to set the filename for autocommands.
649081695250SBram Moolenaar (void)setfname(curbuf, fname, NULL, FALSE);
649181695250SBram Moolenaar
649200bf8cd2SBram Moolenaar // Create swap file now to avoid the ATTENTION message.
649381695250SBram Moolenaar check_need_swap(TRUE);
649481695250SBram Moolenaar
649500bf8cd2SBram Moolenaar // Remove the "dummy" flag, otherwise autocommands may not
649600bf8cd2SBram Moolenaar // work.
649781695250SBram Moolenaar curbuf->b_flags &= ~BF_DUMMY;
649881695250SBram Moolenaar
64997c0a2f36SBram Moolenaar newbuf_to_wipe.br_buf = NULL;
65004fb921e3SBram Moolenaar readfile_result = readfile(fname, NULL,
650181695250SBram Moolenaar (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM,
65024fb921e3SBram Moolenaar NULL, READ_NEW | READ_DUMMY);
65034fb921e3SBram Moolenaar --newbuf->b_locked;
65044fb921e3SBram Moolenaar if (readfile_result == OK
6505d68071d8SBram Moolenaar && !got_int
650681695250SBram Moolenaar && !(curbuf->b_flags & BF_NEW))
650781695250SBram Moolenaar {
650881695250SBram Moolenaar failed = FALSE;
650981695250SBram Moolenaar if (curbuf != newbuf)
651081695250SBram Moolenaar {
651100bf8cd2SBram Moolenaar // Bloody autocommands changed the buffer! Can happen when
651200bf8cd2SBram Moolenaar // using netrw and editing a remote file. Use the current
651300bf8cd2SBram Moolenaar // buffer instead, delete the dummy one after restoring the
651400bf8cd2SBram Moolenaar // window stuff.
65157c0a2f36SBram Moolenaar set_bufref(&newbuf_to_wipe, newbuf);
651681695250SBram Moolenaar newbuf = curbuf;
651781695250SBram Moolenaar }
651881695250SBram Moolenaar }
651981695250SBram Moolenaar
652000bf8cd2SBram Moolenaar // restore curwin/curbuf and a few other things
652181695250SBram Moolenaar aucmd_restbuf(&aco);
65227c0a2f36SBram Moolenaar if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe))
65237c0a2f36SBram Moolenaar wipe_buffer(newbuf_to_wipe.br_buf, FALSE);
6524ea3f2e7bSBram Moolenaar
652500bf8cd2SBram Moolenaar // Add back the "dummy" flag, otherwise buflist_findname_stat() won't
652600bf8cd2SBram Moolenaar // skip it.
6527ea3f2e7bSBram Moolenaar newbuf->b_flags |= BF_DUMMY;
6528f061e0beSBram Moolenaar }
652981695250SBram Moolenaar
653000bf8cd2SBram Moolenaar // When autocommands/'autochdir' option changed directory: go back.
653100bf8cd2SBram Moolenaar // Let the caller know what the resulting dir was first, in case it is
653200bf8cd2SBram Moolenaar // important.
65337f51a82cSBram Moolenaar mch_dirname(resulting_dir, MAXPATHL);
65347f51a82cSBram Moolenaar restore_start_dir(dirname_start);
65357f51a82cSBram Moolenaar
65367c0a2f36SBram Moolenaar if (!bufref_valid(&newbufref))
653781695250SBram Moolenaar return NULL;
653881695250SBram Moolenaar if (failed)
653981695250SBram Moolenaar {
65407f51a82cSBram Moolenaar wipe_dummy_buffer(newbuf, dirname_start);
654181695250SBram Moolenaar return NULL;
654281695250SBram Moolenaar }
654381695250SBram Moolenaar return newbuf;
654481695250SBram Moolenaar }
654581695250SBram Moolenaar
654681695250SBram Moolenaar /*
65477f51a82cSBram Moolenaar * Wipe out the dummy buffer that load_dummy_buffer() created. Restores
65487f51a82cSBram Moolenaar * directory to "dirname_start" prior to returning, if autocmds or the
65497f51a82cSBram Moolenaar * 'autochdir' option have changed it.
655081695250SBram Moolenaar */
655181695250SBram Moolenaar static void
wipe_dummy_buffer(buf_T * buf,char_u * dirname_start)655205540976SBram Moolenaar wipe_dummy_buffer(buf_T *buf, char_u *dirname_start)
655381695250SBram Moolenaar {
65542573af35SBram Moolenaar // If any autocommand opened a window on the dummy buffer, close that
65552573af35SBram Moolenaar // window. If we can't close them all then give up.
65562573af35SBram Moolenaar while (buf->b_nwindows > 0)
65572573af35SBram Moolenaar {
65582573af35SBram Moolenaar int did_one = FALSE;
65592573af35SBram Moolenaar win_T *wp;
65602573af35SBram Moolenaar
65612573af35SBram Moolenaar if (firstwin->w_next != NULL)
656200d253e2SBram Moolenaar FOR_ALL_WINDOWS(wp)
65632573af35SBram Moolenaar if (wp->w_buffer == buf)
65642573af35SBram Moolenaar {
65652573af35SBram Moolenaar if (win_close(wp, FALSE) == OK)
65662573af35SBram Moolenaar did_one = TRUE;
65672573af35SBram Moolenaar break;
65682573af35SBram Moolenaar }
65692573af35SBram Moolenaar if (!did_one)
65702573af35SBram Moolenaar return;
65712573af35SBram Moolenaar }
65722573af35SBram Moolenaar
65732573af35SBram Moolenaar if (curbuf != buf && buf->b_nwindows == 0) // safety check
6574d68071d8SBram Moolenaar {
6575f2bd8ef2SBram Moolenaar #if defined(FEAT_EVAL)
6576d68071d8SBram Moolenaar cleanup_T cs;
6577d68071d8SBram Moolenaar
657800bf8cd2SBram Moolenaar // Reset the error/interrupt/exception state here so that aborting()
657900bf8cd2SBram Moolenaar // returns FALSE when wiping out the buffer. Otherwise it doesn't
658000bf8cd2SBram Moolenaar // work when got_int is set.
6581d68071d8SBram Moolenaar enter_cleanup(&cs);
6582d68071d8SBram Moolenaar #endif
6583d68071d8SBram Moolenaar
65841cfb9bb5SBram Moolenaar wipe_buffer(buf, TRUE);
6585d68071d8SBram Moolenaar
6586f2bd8ef2SBram Moolenaar #if defined(FEAT_EVAL)
658700bf8cd2SBram Moolenaar // Restore the error/interrupt/exception state if not discarded by a
658800bf8cd2SBram Moolenaar // new aborting error, interrupt, or uncaught exception.
6589d68071d8SBram Moolenaar leave_cleanup(&cs);
6590d68071d8SBram Moolenaar #endif
659100bf8cd2SBram Moolenaar // When autocommands/'autochdir' option changed directory: go back.
65927f51a82cSBram Moolenaar restore_start_dir(dirname_start);
6593d68071d8SBram Moolenaar }
659481695250SBram Moolenaar }
659581695250SBram Moolenaar
659681695250SBram Moolenaar /*
65977f51a82cSBram Moolenaar * Unload the dummy buffer that load_dummy_buffer() created. Restores
65987f51a82cSBram Moolenaar * directory to "dirname_start" prior to returning, if autocmds or the
65997f51a82cSBram Moolenaar * 'autochdir' option have changed it.
660081695250SBram Moolenaar */
660181695250SBram Moolenaar static void
unload_dummy_buffer(buf_T * buf,char_u * dirname_start)660205540976SBram Moolenaar unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
660381695250SBram Moolenaar {
660400bf8cd2SBram Moolenaar if (curbuf != buf) // safety check
66057f51a82cSBram Moolenaar {
6606a6e8f888SBram Moolenaar close_buffer(NULL, buf, DOBUF_UNLOAD, FALSE, TRUE);
66077f51a82cSBram Moolenaar
660800bf8cd2SBram Moolenaar // When autocommands/'autochdir' option changed directory: go back.
66097f51a82cSBram Moolenaar restore_start_dir(dirname_start);
66107f51a82cSBram Moolenaar }
661181695250SBram Moolenaar }
661281695250SBram Moolenaar
661305159a0cSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
661405159a0cSBram Moolenaar /*
66154b96df5aSBram Moolenaar * Copy the specified quickfix entry items into a new dict and append the dict
6616a16123a6SBram Moolenaar * to 'list'. Returns OK on success.
661705159a0cSBram Moolenaar */
6618a16123a6SBram Moolenaar static int
get_qfline_items(qfline_T * qfp,list_T * list)6619a16123a6SBram Moolenaar get_qfline_items(qfline_T *qfp, list_T *list)
662005159a0cSBram Moolenaar {
6621a16123a6SBram Moolenaar int bufnum;
662205159a0cSBram Moolenaar dict_T *dict;
662305159a0cSBram Moolenaar char_u buf[2];
662405159a0cSBram Moolenaar
662500bf8cd2SBram Moolenaar // Handle entries with a non-existing buffer number.
662648b66fb5SBram Moolenaar bufnum = qfp->qf_fnum;
662748b66fb5SBram Moolenaar if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
662848b66fb5SBram Moolenaar bufnum = 0;
662948b66fb5SBram Moolenaar
663005159a0cSBram Moolenaar if ((dict = dict_alloc()) == NULL)
663105159a0cSBram Moolenaar return FAIL;
663205159a0cSBram Moolenaar if (list_append_dict(list, dict) == FAIL)
663305159a0cSBram Moolenaar return FAIL;
663405159a0cSBram Moolenaar
663505159a0cSBram Moolenaar buf[0] = qfp->qf_type;
663605159a0cSBram Moolenaar buf[1] = NUL;
6637e0be167aSBram Moolenaar if (dict_add_number(dict, "bufnr", (long)bufnum) == FAIL
6638e0be167aSBram Moolenaar || dict_add_number(dict, "lnum", (long)qfp->qf_lnum) == FAIL
66396864efa5Sthinca || dict_add_number(dict, "end_lnum", (long)qfp->qf_end_lnum) == FAIL
6640e0be167aSBram Moolenaar || dict_add_number(dict, "col", (long)qfp->qf_col) == FAIL
66416864efa5Sthinca || dict_add_number(dict, "end_col", (long)qfp->qf_end_col) == FAIL
6642e0be167aSBram Moolenaar || dict_add_number(dict, "vcol", (long)qfp->qf_viscol) == FAIL
6643e0be167aSBram Moolenaar || dict_add_number(dict, "nr", (long)qfp->qf_nr) == FAIL
6644e0be167aSBram Moolenaar || dict_add_string(dict, "module", qfp->qf_module) == FAIL
6645e0be167aSBram Moolenaar || dict_add_string(dict, "pattern", qfp->qf_pattern) == FAIL
6646e0be167aSBram Moolenaar || dict_add_string(dict, "text", qfp->qf_text) == FAIL
6647e0be167aSBram Moolenaar || dict_add_string(dict, "type", buf) == FAIL
6648e0be167aSBram Moolenaar || dict_add_number(dict, "valid", (long)qfp->qf_valid) == FAIL)
664905159a0cSBram Moolenaar return FAIL;
665005159a0cSBram Moolenaar
6651a16123a6SBram Moolenaar return OK;
665205159a0cSBram Moolenaar }
6653a16123a6SBram Moolenaar
6654a16123a6SBram Moolenaar /*
6655a16123a6SBram Moolenaar * Add each quickfix error to list "list" as a dictionary.
6656a16123a6SBram Moolenaar * If qf_idx is -1, use the current list. Otherwise, use the specified list.
6657858ba06dSBram Moolenaar * If eidx is not 0, then return only the specified entry. Otherwise return
6658858ba06dSBram Moolenaar * all the entries.
6659a16123a6SBram Moolenaar */
6660e677df8dSBram Moolenaar static int
get_errorlist(qf_info_T * qi_arg,win_T * wp,int qf_idx,int eidx,list_T * list)6661858ba06dSBram Moolenaar get_errorlist(
6662858ba06dSBram Moolenaar qf_info_T *qi_arg,
6663858ba06dSBram Moolenaar win_T *wp,
6664858ba06dSBram Moolenaar int qf_idx,
6665858ba06dSBram Moolenaar int eidx,
6666858ba06dSBram Moolenaar list_T *list)
6667a16123a6SBram Moolenaar {
6668a16123a6SBram Moolenaar qf_info_T *qi = qi_arg;
6669a16123a6SBram Moolenaar qf_list_T *qfl;
6670a16123a6SBram Moolenaar qfline_T *qfp;
6671a16123a6SBram Moolenaar int i;
6672a16123a6SBram Moolenaar
6673a16123a6SBram Moolenaar if (qi == NULL)
6674a16123a6SBram Moolenaar {
6675a16123a6SBram Moolenaar qi = &ql_info;
6676a16123a6SBram Moolenaar if (wp != NULL)
6677a16123a6SBram Moolenaar {
6678a16123a6SBram Moolenaar qi = GET_LOC_LIST(wp);
6679a16123a6SBram Moolenaar if (qi == NULL)
6680a16123a6SBram Moolenaar return FAIL;
6681a16123a6SBram Moolenaar }
6682a16123a6SBram Moolenaar }
6683a16123a6SBram Moolenaar
6684858ba06dSBram Moolenaar if (eidx < 0)
6685858ba06dSBram Moolenaar return OK;
6686858ba06dSBram Moolenaar
6687a16123a6SBram Moolenaar if (qf_idx == INVALID_QFIDX)
6688a16123a6SBram Moolenaar qf_idx = qi->qf_curlist;
6689a16123a6SBram Moolenaar
6690a16123a6SBram Moolenaar if (qf_idx >= qi->qf_listcount)
6691a16123a6SBram Moolenaar return FAIL;
6692a16123a6SBram Moolenaar
6693a16123a6SBram Moolenaar qfl = qf_get_list(qi, qf_idx);
6694a16123a6SBram Moolenaar if (qf_list_empty(qfl))
6695a16123a6SBram Moolenaar return FAIL;
6696a16123a6SBram Moolenaar
6697a16123a6SBram Moolenaar FOR_ALL_QFL_ITEMS(qfl, qfp, i)
6698a16123a6SBram Moolenaar {
6699858ba06dSBram Moolenaar if (eidx > 0)
6700858ba06dSBram Moolenaar {
6701858ba06dSBram Moolenaar if (eidx == i)
6702858ba06dSBram Moolenaar return get_qfline_items(qfp, list);
6703858ba06dSBram Moolenaar }
6704858ba06dSBram Moolenaar else if (get_qfline_items(qfp, list) == FAIL)
6705a16123a6SBram Moolenaar return FAIL;
6706a16123a6SBram Moolenaar }
6707a16123a6SBram Moolenaar
670805159a0cSBram Moolenaar return OK;
670905159a0cSBram Moolenaar }
671068b76a69SBram Moolenaar
671100bf8cd2SBram Moolenaar // Flags used by getqflist()/getloclist() to determine which fields to return.
6712d823fa91SBram Moolenaar enum {
6713d823fa91SBram Moolenaar QF_GETLIST_NONE = 0x0,
6714d823fa91SBram Moolenaar QF_GETLIST_TITLE = 0x1,
6715d823fa91SBram Moolenaar QF_GETLIST_ITEMS = 0x2,
6716d823fa91SBram Moolenaar QF_GETLIST_NR = 0x4,
6717d823fa91SBram Moolenaar QF_GETLIST_WINID = 0x8,
67188f77c5a4SBram Moolenaar QF_GETLIST_CONTEXT = 0x10,
6719a539f4f1SBram Moolenaar QF_GETLIST_ID = 0x20,
6720fc2b270cSBram Moolenaar QF_GETLIST_IDX = 0x40,
6721fc2b270cSBram Moolenaar QF_GETLIST_SIZE = 0x80,
6722b254af31SBram Moolenaar QF_GETLIST_TICK = 0x100,
6723c9cc9c78SBram Moolenaar QF_GETLIST_FILEWINID = 0x200,
6724647e24baSBram Moolenaar QF_GETLIST_QFBUFNR = 0x400,
6725d43906d2SBram Moolenaar QF_GETLIST_QFTF = 0x800,
6726d43906d2SBram Moolenaar QF_GETLIST_ALL = 0xFFF,
6727d823fa91SBram Moolenaar };
6728d823fa91SBram Moolenaar
6729d823fa91SBram Moolenaar /*
6730353eeeacSBram Moolenaar * Parse text from 'di' and return the quickfix list items.
6731353eeeacSBram Moolenaar * Existing quickfix lists are not modified.
67327adf06f4SBram Moolenaar */
67337adf06f4SBram Moolenaar static int
qf_get_list_from_lines(dict_T * what,dictitem_T * di,dict_T * retdict)673436538225SBram Moolenaar qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
67357adf06f4SBram Moolenaar {
67367adf06f4SBram Moolenaar int status = FAIL;
67377adf06f4SBram Moolenaar qf_info_T *qi;
673836538225SBram Moolenaar char_u *errorformat = p_efm;
673936538225SBram Moolenaar dictitem_T *efm_di;
674036538225SBram Moolenaar list_T *l;
67417adf06f4SBram Moolenaar
674200bf8cd2SBram Moolenaar // Only a List value is supported
67432c809b7cSBram Moolenaar if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL)
67447adf06f4SBram Moolenaar {
674500bf8cd2SBram Moolenaar // If errorformat is supplied then use it, otherwise use the 'efm'
674600bf8cd2SBram Moolenaar // option setting
674736538225SBram Moolenaar if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
674836538225SBram Moolenaar {
674936538225SBram Moolenaar if (efm_di->di_tv.v_type != VAR_STRING ||
675036538225SBram Moolenaar efm_di->di_tv.vval.v_string == NULL)
675136538225SBram Moolenaar return FAIL;
675236538225SBram Moolenaar errorformat = efm_di->di_tv.vval.v_string;
675336538225SBram Moolenaar }
6754da73253aSBram Moolenaar
675536538225SBram Moolenaar l = list_alloc();
6756da73253aSBram Moolenaar if (l == NULL)
6757da73253aSBram Moolenaar return FAIL;
6758da73253aSBram Moolenaar
67592d67d307SBram Moolenaar qi = qf_alloc_stack(QFLT_INTERNAL);
67607adf06f4SBram Moolenaar if (qi != NULL)
67617adf06f4SBram Moolenaar {
676236538225SBram Moolenaar if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
67637adf06f4SBram Moolenaar TRUE, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0)
67647adf06f4SBram Moolenaar {
6765858ba06dSBram Moolenaar (void)get_errorlist(qi, NULL, 0, 0, l);
6766fe15b7dfSBram Moolenaar qf_free(&qi->qf_lists[0]);
67677adf06f4SBram Moolenaar }
67687adf06f4SBram Moolenaar free(qi);
67697adf06f4SBram Moolenaar }
6770da73253aSBram Moolenaar dict_add_list(retdict, "items", l);
6771da73253aSBram Moolenaar status = OK;
67727adf06f4SBram Moolenaar }
67737adf06f4SBram Moolenaar
67747adf06f4SBram Moolenaar return status;
67757adf06f4SBram Moolenaar }
67767adf06f4SBram Moolenaar
67777adf06f4SBram Moolenaar /*
67782ec364e9SBram Moolenaar * Return the quickfix/location list window identifier in the current tabpage.
67792ec364e9SBram Moolenaar */
67802ec364e9SBram Moolenaar static int
qf_winid(qf_info_T * qi)67812ec364e9SBram Moolenaar qf_winid(qf_info_T *qi)
67822ec364e9SBram Moolenaar {
67832ec364e9SBram Moolenaar win_T *win;
67842ec364e9SBram Moolenaar
678500bf8cd2SBram Moolenaar // The quickfix window can be opened even if the quickfix list is not set
678600bf8cd2SBram Moolenaar // using ":copen". This is not true for location lists.
67872ec364e9SBram Moolenaar if (qi == NULL)
67882ec364e9SBram Moolenaar return 0;
67892ec364e9SBram Moolenaar win = qf_find_win(qi);
67902ec364e9SBram Moolenaar if (win != NULL)
67912ec364e9SBram Moolenaar return win->w_id;
67922ec364e9SBram Moolenaar return 0;
67932ec364e9SBram Moolenaar }
67942ec364e9SBram Moolenaar
67952ec364e9SBram Moolenaar /*
6796647e24baSBram Moolenaar * Returns the number of the buffer displayed in the quickfix/location list
6797647e24baSBram Moolenaar * window. If there is no buffer associated with the list, then returns 0.
6798647e24baSBram Moolenaar */
6799647e24baSBram Moolenaar static int
qf_getprop_qfbufnr(qf_info_T * qi,dict_T * retdict)6800647e24baSBram Moolenaar qf_getprop_qfbufnr(qf_info_T *qi, dict_T *retdict)
6801647e24baSBram Moolenaar {
6802647e24baSBram Moolenaar return dict_add_number(retdict, "qfbufnr",
6803647e24baSBram Moolenaar (qi == NULL) ? 0 : qi->qf_bufnr);
6804647e24baSBram Moolenaar }
6805647e24baSBram Moolenaar
6806647e24baSBram Moolenaar /*
6807353eeeacSBram Moolenaar * Convert the keys in 'what' to quickfix list property flags.
680868b76a69SBram Moolenaar */
6809353eeeacSBram Moolenaar static int
qf_getprop_keys2flags(dict_T * what,int loclist)6810c9cc9c78SBram Moolenaar qf_getprop_keys2flags(dict_T *what, int loclist)
6811d823fa91SBram Moolenaar {
6812d823fa91SBram Moolenaar int flags = QF_GETLIST_NONE;
6813d823fa91SBram Moolenaar
6814a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"all", -1) != NULL)
6815c9cc9c78SBram Moolenaar {
6816a6d4849cSBram Moolenaar flags |= QF_GETLIST_ALL;
6817c9cc9c78SBram Moolenaar if (!loclist)
6818c9cc9c78SBram Moolenaar // File window ID is applicable only to location list windows
6819c9cc9c78SBram Moolenaar flags &= ~ QF_GETLIST_FILEWINID;
6820c9cc9c78SBram Moolenaar }
6821d823fa91SBram Moolenaar
6822a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"title", -1) != NULL)
6823a6d4849cSBram Moolenaar flags |= QF_GETLIST_TITLE;
6824a6d4849cSBram Moolenaar
6825a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"nr", -1) != NULL)
6826a6d4849cSBram Moolenaar flags |= QF_GETLIST_NR;
6827a6d4849cSBram Moolenaar
6828a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"winid", -1) != NULL)
6829a6d4849cSBram Moolenaar flags |= QF_GETLIST_WINID;
6830a6d4849cSBram Moolenaar
6831a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"context", -1) != NULL)
6832a6d4849cSBram Moolenaar flags |= QF_GETLIST_CONTEXT;
6833a6d4849cSBram Moolenaar
6834a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"id", -1) != NULL)
6835a6d4849cSBram Moolenaar flags |= QF_GETLIST_ID;
6836a6d4849cSBram Moolenaar
6837a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"items", -1) != NULL)
6838a6d4849cSBram Moolenaar flags |= QF_GETLIST_ITEMS;
6839a6d4849cSBram Moolenaar
6840a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"idx", -1) != NULL)
6841a6d4849cSBram Moolenaar flags |= QF_GETLIST_IDX;
6842a6d4849cSBram Moolenaar
6843a6d4849cSBram Moolenaar if (dict_find(what, (char_u *)"size", -1) != NULL)
6844a6d4849cSBram Moolenaar flags |= QF_GETLIST_SIZE;
6845a6d4849cSBram Moolenaar
6846b254af31SBram Moolenaar if (dict_find(what, (char_u *)"changedtick", -1) != NULL)
6847b254af31SBram Moolenaar flags |= QF_GETLIST_TICK;
6848b254af31SBram Moolenaar
6849c9cc9c78SBram Moolenaar if (loclist && dict_find(what, (char_u *)"filewinid", -1) != NULL)
6850c9cc9c78SBram Moolenaar flags |= QF_GETLIST_FILEWINID;
6851c9cc9c78SBram Moolenaar
6852647e24baSBram Moolenaar if (dict_find(what, (char_u *)"qfbufnr", -1) != NULL)
6853647e24baSBram Moolenaar flags |= QF_GETLIST_QFBUFNR;
6854647e24baSBram Moolenaar
6855d43906d2SBram Moolenaar if (dict_find(what, (char_u *)"quickfixtextfunc", -1) != NULL)
6856d43906d2SBram Moolenaar flags |= QF_GETLIST_QFTF;
6857d43906d2SBram Moolenaar
6858353eeeacSBram Moolenaar return flags;
6859353eeeacSBram Moolenaar }
6860353eeeacSBram Moolenaar
6861353eeeacSBram Moolenaar /*
6862353eeeacSBram Moolenaar * Return the quickfix list index based on 'nr' or 'id' in 'what'.
6863353eeeacSBram Moolenaar * If 'nr' and 'id' are not present in 'what' then return the current
6864353eeeacSBram Moolenaar * quickfix list index.
6865353eeeacSBram Moolenaar * If 'nr' is zero then return the current quickfix list index.
6866353eeeacSBram Moolenaar * If 'nr' is '$' then return the last quickfix list index.
6867353eeeacSBram Moolenaar * If 'id' is present then return the index of the quickfix list with that id.
6868353eeeacSBram Moolenaar * If 'id' is zero then return the quickfix list index specified by 'nr'.
6869353eeeacSBram Moolenaar * Return -1, if quickfix list is not present or if the stack is empty.
6870353eeeacSBram Moolenaar */
6871353eeeacSBram Moolenaar static int
qf_getprop_qfidx(qf_info_T * qi,dict_T * what)6872353eeeacSBram Moolenaar qf_getprop_qfidx(qf_info_T *qi, dict_T *what)
6873a6d4849cSBram Moolenaar {
6874353eeeacSBram Moolenaar int qf_idx;
6875353eeeacSBram Moolenaar dictitem_T *di;
6876353eeeacSBram Moolenaar
687700bf8cd2SBram Moolenaar qf_idx = qi->qf_curlist; // default is the current list
6878d823fa91SBram Moolenaar if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
6879d823fa91SBram Moolenaar {
688000bf8cd2SBram Moolenaar // Use the specified quickfix/location list
6881d823fa91SBram Moolenaar if (di->di_tv.v_type == VAR_NUMBER)
6882d823fa91SBram Moolenaar {
688300bf8cd2SBram Moolenaar // for zero use the current list
6884890680caSBram Moolenaar if (di->di_tv.vval.v_number != 0)
6885890680caSBram Moolenaar {
6886d823fa91SBram Moolenaar qf_idx = di->di_tv.vval.v_number - 1;
6887d823fa91SBram Moolenaar if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
6888a2aa8a2bSBram Moolenaar qf_idx = INVALID_QFIDX;
688955b69264SBram Moolenaar }
689055b69264SBram Moolenaar }
6891a0ca7d00SBram Moolenaar else if (di->di_tv.v_type == VAR_STRING
6892a0ca7d00SBram Moolenaar && di->di_tv.vval.v_string != NULL
6893a0ca7d00SBram Moolenaar && STRCMP(di->di_tv.vval.v_string, "$") == 0)
689400bf8cd2SBram Moolenaar // Get the last quickfix list number
6895875feea6SBram Moolenaar qf_idx = qi->qf_listcount - 1;
6896875feea6SBram Moolenaar else
6897a2aa8a2bSBram Moolenaar qf_idx = INVALID_QFIDX;
6898d823fa91SBram Moolenaar }
6899a539f4f1SBram Moolenaar
6900a539f4f1SBram Moolenaar if ((di = dict_find(what, (char_u *)"id", -1)) != NULL)
6901a539f4f1SBram Moolenaar {
690200bf8cd2SBram Moolenaar // Look for a list with the specified id
6903a539f4f1SBram Moolenaar if (di->di_tv.v_type == VAR_NUMBER)
6904a539f4f1SBram Moolenaar {
690500bf8cd2SBram Moolenaar // For zero, use the current list or the list specified by 'nr'
6906a539f4f1SBram Moolenaar if (di->di_tv.vval.v_number != 0)
6907b4d5fbabSBram Moolenaar qf_idx = qf_id2nr(qi, di->di_tv.vval.v_number);
6908a539f4f1SBram Moolenaar }
6909d823fa91SBram Moolenaar else
6910a2aa8a2bSBram Moolenaar qf_idx = INVALID_QFIDX;
6911a6d4849cSBram Moolenaar }
6912353eeeacSBram Moolenaar
6913353eeeacSBram Moolenaar return qf_idx;
6914d823fa91SBram Moolenaar }
6915d823fa91SBram Moolenaar
6916353eeeacSBram Moolenaar /*
6917353eeeacSBram Moolenaar * Return default values for quickfix list properties in retdict.
6918353eeeacSBram Moolenaar */
6919353eeeacSBram Moolenaar static int
qf_getprop_defaults(qf_info_T * qi,int flags,int locstack,dict_T * retdict)69202d67d307SBram Moolenaar qf_getprop_defaults(qf_info_T *qi, int flags, int locstack, dict_T *retdict)
6921a6d4849cSBram Moolenaar {
6922353eeeacSBram Moolenaar int status = OK;
6923353eeeacSBram Moolenaar
6924a6d4849cSBram Moolenaar if (flags & QF_GETLIST_TITLE)
6925e0be167aSBram Moolenaar status = dict_add_string(retdict, "title", (char_u *)"");
6926a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_ITEMS))
6927a6d4849cSBram Moolenaar {
6928a6d4849cSBram Moolenaar list_T *l = list_alloc();
6929a6d4849cSBram Moolenaar if (l != NULL)
6930a6d4849cSBram Moolenaar status = dict_add_list(retdict, "items", l);
6931a6d4849cSBram Moolenaar else
6932a6d4849cSBram Moolenaar status = FAIL;
6933a6d4849cSBram Moolenaar }
6934a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_NR))
6935e0be167aSBram Moolenaar status = dict_add_number(retdict, "nr", 0);
6936a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_WINID))
6937e0be167aSBram Moolenaar status = dict_add_number(retdict, "winid", qf_winid(qi));
6938a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
6939e0be167aSBram Moolenaar status = dict_add_string(retdict, "context", (char_u *)"");
6940a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_ID))
6941e0be167aSBram Moolenaar status = dict_add_number(retdict, "id", 0);
6942a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_IDX))
6943e0be167aSBram Moolenaar status = dict_add_number(retdict, "idx", 0);
6944a6d4849cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_SIZE))
6945e0be167aSBram Moolenaar status = dict_add_number(retdict, "size", 0);
6946b254af31SBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_TICK))
6947e0be167aSBram Moolenaar status = dict_add_number(retdict, "changedtick", 0);
69482d67d307SBram Moolenaar if ((status == OK) && locstack && (flags & QF_GETLIST_FILEWINID))
6949c9cc9c78SBram Moolenaar status = dict_add_number(retdict, "filewinid", 0);
6950647e24baSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
6951647e24baSBram Moolenaar status = qf_getprop_qfbufnr(qi, retdict);
6952d43906d2SBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_QFTF))
6953d43906d2SBram Moolenaar status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
6954d823fa91SBram Moolenaar
6955a6d4849cSBram Moolenaar return status;
6956a6d4849cSBram Moolenaar }
6957fc2b270cSBram Moolenaar
6958353eeeacSBram Moolenaar /*
6959353eeeacSBram Moolenaar * Return the quickfix list title as 'title' in retdict
6960353eeeacSBram Moolenaar */
6961353eeeacSBram Moolenaar static int
qf_getprop_title(qf_list_T * qfl,dict_T * retdict)6962108e7b42SBram Moolenaar qf_getprop_title(qf_list_T *qfl, dict_T *retdict)
6963d823fa91SBram Moolenaar {
6964108e7b42SBram Moolenaar return dict_add_string(retdict, "title", qfl->qf_title);
6965d823fa91SBram Moolenaar }
6966353eeeacSBram Moolenaar
6967353eeeacSBram Moolenaar /*
6968c9cc9c78SBram Moolenaar * Returns the identifier of the window used to display files from a location
6969c9cc9c78SBram Moolenaar * list. If there is no associated window, then returns 0. Useful only when
6970c9cc9c78SBram Moolenaar * called from a location list window.
6971c9cc9c78SBram Moolenaar */
6972c9cc9c78SBram Moolenaar static int
qf_getprop_filewinid(win_T * wp,qf_info_T * qi,dict_T * retdict)6973c9cc9c78SBram Moolenaar qf_getprop_filewinid(win_T *wp, qf_info_T *qi, dict_T *retdict)
6974c9cc9c78SBram Moolenaar {
6975c9cc9c78SBram Moolenaar int winid = 0;
6976c9cc9c78SBram Moolenaar
6977c9cc9c78SBram Moolenaar if (wp != NULL && IS_LL_WINDOW(wp))
6978c9cc9c78SBram Moolenaar {
6979c9cc9c78SBram Moolenaar win_T *ll_wp = qf_find_win_with_loclist(qi);
6980c9cc9c78SBram Moolenaar if (ll_wp != NULL)
6981c9cc9c78SBram Moolenaar winid = ll_wp->w_id;
6982c9cc9c78SBram Moolenaar }
6983c9cc9c78SBram Moolenaar
6984c9cc9c78SBram Moolenaar return dict_add_number(retdict, "filewinid", winid);
6985c9cc9c78SBram Moolenaar }
6986c9cc9c78SBram Moolenaar
6987c9cc9c78SBram Moolenaar /*
6988858ba06dSBram Moolenaar * Return the quickfix list items/entries as 'items' in retdict.
6989858ba06dSBram Moolenaar * If eidx is not 0, then return the item at the specified index.
6990353eeeacSBram Moolenaar */
6991353eeeacSBram Moolenaar static int
qf_getprop_items(qf_info_T * qi,int qf_idx,int eidx,dict_T * retdict)6992858ba06dSBram Moolenaar qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx, dict_T *retdict)
69936a8958dbSBram Moolenaar {
6994353eeeacSBram Moolenaar int status = OK;
69956a8958dbSBram Moolenaar list_T *l = list_alloc();
69966a8958dbSBram Moolenaar if (l != NULL)
69976a8958dbSBram Moolenaar {
6998858ba06dSBram Moolenaar (void)get_errorlist(qi, NULL, qf_idx, eidx, l);
69996a8958dbSBram Moolenaar dict_add_list(retdict, "items", l);
70006a8958dbSBram Moolenaar }
700186f100dcSBram Moolenaar else
700286f100dcSBram Moolenaar status = FAIL;
7003353eeeacSBram Moolenaar
7004353eeeacSBram Moolenaar return status;
70056a8958dbSBram Moolenaar }
7006d823fa91SBram Moolenaar
7007353eeeacSBram Moolenaar /*
7008353eeeacSBram Moolenaar * Return the quickfix list context (if any) as 'context' in retdict.
7009353eeeacSBram Moolenaar */
7010353eeeacSBram Moolenaar static int
qf_getprop_ctx(qf_list_T * qfl,dict_T * retdict)7011108e7b42SBram Moolenaar qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
70128f77c5a4SBram Moolenaar {
7013353eeeacSBram Moolenaar int status;
7014353eeeacSBram Moolenaar dictitem_T *di;
7015353eeeacSBram Moolenaar
7016108e7b42SBram Moolenaar if (qfl->qf_ctx != NULL)
70178f77c5a4SBram Moolenaar {
70188f77c5a4SBram Moolenaar di = dictitem_alloc((char_u *)"context");
70198f77c5a4SBram Moolenaar if (di != NULL)
70208f77c5a4SBram Moolenaar {
7021108e7b42SBram Moolenaar copy_tv(qfl->qf_ctx, &di->di_tv);
702286f100dcSBram Moolenaar status = dict_add(retdict, di);
702386f100dcSBram Moolenaar if (status == FAIL)
7024beb9cb19SBram Moolenaar dictitem_free(di);
70258f77c5a4SBram Moolenaar }
702686f100dcSBram Moolenaar else
702786f100dcSBram Moolenaar status = FAIL;
70288f77c5a4SBram Moolenaar }
70298f77c5a4SBram Moolenaar else
7030e0be167aSBram Moolenaar status = dict_add_string(retdict, "context", (char_u *)"");
7031353eeeacSBram Moolenaar
7032353eeeacSBram Moolenaar return status;
70338f77c5a4SBram Moolenaar }
70348f77c5a4SBram Moolenaar
7035353eeeacSBram Moolenaar /*
7036858ba06dSBram Moolenaar * Return the current quickfix list index as 'idx' in retdict.
7037858ba06dSBram Moolenaar * If a specific entry index (eidx) is supplied, then use that.
7038353eeeacSBram Moolenaar */
7039353eeeacSBram Moolenaar static int
qf_getprop_idx(qf_list_T * qfl,int eidx,dict_T * retdict)7040858ba06dSBram Moolenaar qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict)
7041fc2b270cSBram Moolenaar {
7042858ba06dSBram Moolenaar if (eidx == 0)
7043858ba06dSBram Moolenaar {
7044858ba06dSBram Moolenaar eidx = qfl->qf_index;
70450398e00aSBram Moolenaar if (qf_list_empty(qfl))
7046108e7b42SBram Moolenaar // For empty lists, current index is set to 0
7047858ba06dSBram Moolenaar eidx = 0;
7048858ba06dSBram Moolenaar }
7049858ba06dSBram Moolenaar return dict_add_number(retdict, "idx", eidx);
7050fc2b270cSBram Moolenaar }
7051fc2b270cSBram Moolenaar
7052353eeeacSBram Moolenaar /*
7053d43906d2SBram Moolenaar * Return the 'quickfixtextfunc' function of a quickfix/location list
7054d43906d2SBram Moolenaar */
7055d43906d2SBram Moolenaar static int
qf_getprop_qftf(qf_list_T * qfl,dict_T * retdict)7056d43906d2SBram Moolenaar qf_getprop_qftf(qf_list_T *qfl, dict_T *retdict)
7057d43906d2SBram Moolenaar {
7058d43906d2SBram Moolenaar int status;
7059d43906d2SBram Moolenaar
7060d43906d2SBram Moolenaar if (qfl->qftf_cb.cb_name != NULL)
7061d43906d2SBram Moolenaar {
7062d43906d2SBram Moolenaar typval_T tv;
7063d43906d2SBram Moolenaar
7064d43906d2SBram Moolenaar put_callback(&qfl->qftf_cb, &tv);
7065d43906d2SBram Moolenaar status = dict_add_tv(retdict, "quickfixtextfunc", &tv);
7066d43906d2SBram Moolenaar clear_tv(&tv);
7067d43906d2SBram Moolenaar }
7068d43906d2SBram Moolenaar else
7069d43906d2SBram Moolenaar status = dict_add_string(retdict, "quickfixtextfunc", (char_u *)"");
7070d43906d2SBram Moolenaar
7071d43906d2SBram Moolenaar return status;
7072d43906d2SBram Moolenaar }
7073d43906d2SBram Moolenaar
7074d43906d2SBram Moolenaar /*
7075353eeeacSBram Moolenaar * Return quickfix/location list details (title) as a
7076353eeeacSBram Moolenaar * dictionary. 'what' contains the details to return. If 'list_idx' is -1,
7077353eeeacSBram Moolenaar * then current list is used. Otherwise the specified list is used.
7078353eeeacSBram Moolenaar */
7079e677df8dSBram Moolenaar static int
qf_get_properties(win_T * wp,dict_T * what,dict_T * retdict)7080353eeeacSBram Moolenaar qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
7081353eeeacSBram Moolenaar {
7082353eeeacSBram Moolenaar qf_info_T *qi = &ql_info;
7083fe15b7dfSBram Moolenaar qf_list_T *qfl;
7084353eeeacSBram Moolenaar int status = OK;
7085108e7b42SBram Moolenaar int qf_idx = INVALID_QFIDX;
7086858ba06dSBram Moolenaar int eidx = 0;
7087353eeeacSBram Moolenaar dictitem_T *di;
7088353eeeacSBram Moolenaar int flags = QF_GETLIST_NONE;
7089353eeeacSBram Moolenaar
7090353eeeacSBram Moolenaar if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
7091353eeeacSBram Moolenaar return qf_get_list_from_lines(what, di, retdict);
7092353eeeacSBram Moolenaar
7093353eeeacSBram Moolenaar if (wp != NULL)
7094353eeeacSBram Moolenaar qi = GET_LOC_LIST(wp);
7095353eeeacSBram Moolenaar
7096c9cc9c78SBram Moolenaar flags = qf_getprop_keys2flags(what, (wp != NULL));
7097353eeeacSBram Moolenaar
7098019dfe68SBram Moolenaar if (!qf_stack_empty(qi))
7099353eeeacSBram Moolenaar qf_idx = qf_getprop_qfidx(qi, what);
7100353eeeacSBram Moolenaar
710100bf8cd2SBram Moolenaar // List is not present or is empty
7102019dfe68SBram Moolenaar if (qf_stack_empty(qi) || qf_idx == INVALID_QFIDX)
71032d67d307SBram Moolenaar return qf_getprop_defaults(qi, flags, wp != NULL, retdict);
7104353eeeacSBram Moolenaar
71050398e00aSBram Moolenaar qfl = qf_get_list(qi, qf_idx);
7106fe15b7dfSBram Moolenaar
7107858ba06dSBram Moolenaar // If an entry index is specified, use that
7108858ba06dSBram Moolenaar if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
7109858ba06dSBram Moolenaar {
7110858ba06dSBram Moolenaar if (di->di_tv.v_type != VAR_NUMBER)
7111858ba06dSBram Moolenaar return FAIL;
7112858ba06dSBram Moolenaar eidx = di->di_tv.vval.v_number;
7113858ba06dSBram Moolenaar }
7114858ba06dSBram Moolenaar
7115353eeeacSBram Moolenaar if (flags & QF_GETLIST_TITLE)
7116108e7b42SBram Moolenaar status = qf_getprop_title(qfl, retdict);
7117353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_NR))
7118e0be167aSBram Moolenaar status = dict_add_number(retdict, "nr", qf_idx + 1);
7119353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_WINID))
7120e0be167aSBram Moolenaar status = dict_add_number(retdict, "winid", qf_winid(qi));
7121353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_ITEMS))
7122858ba06dSBram Moolenaar status = qf_getprop_items(qi, qf_idx, eidx, retdict);
7123353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_CONTEXT))
7124108e7b42SBram Moolenaar status = qf_getprop_ctx(qfl, retdict);
7125353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_ID))
7126fe15b7dfSBram Moolenaar status = dict_add_number(retdict, "id", qfl->qf_id);
7127353eeeacSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_IDX))
7128858ba06dSBram Moolenaar status = qf_getprop_idx(qfl, eidx, retdict);
7129fc2b270cSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_SIZE))
7130fe15b7dfSBram Moolenaar status = dict_add_number(retdict, "size", qfl->qf_count);
7131b254af31SBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_TICK))
7132fe15b7dfSBram Moolenaar status = dict_add_number(retdict, "changedtick", qfl->qf_changedtick);
7133c9cc9c78SBram Moolenaar if ((status == OK) && (wp != NULL) && (flags & QF_GETLIST_FILEWINID))
7134c9cc9c78SBram Moolenaar status = qf_getprop_filewinid(wp, qi, retdict);
7135647e24baSBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_QFBUFNR))
7136647e24baSBram Moolenaar status = qf_getprop_qfbufnr(qi, retdict);
7137d43906d2SBram Moolenaar if ((status == OK) && (flags & QF_GETLIST_QFTF))
7138d43906d2SBram Moolenaar status = qf_getprop_qftf(qfl, retdict);
7139b254af31SBram Moolenaar
7140d823fa91SBram Moolenaar return status;
7141d823fa91SBram Moolenaar }
7142d823fa91SBram Moolenaar
7143d823fa91SBram Moolenaar /*
71446f6ef7c1SBram Moolenaar * Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
71459752c72fSBram Moolenaar * items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
71469752c72fSBram Moolenaar * to TRUE.
71476f6ef7c1SBram Moolenaar */
71486f6ef7c1SBram Moolenaar static int
qf_add_entry_from_dict(qf_list_T * qfl,dict_T * d,int first_entry,int * valid_entry)71496f6ef7c1SBram Moolenaar qf_add_entry_from_dict(
71500398e00aSBram Moolenaar qf_list_T *qfl,
71516f6ef7c1SBram Moolenaar dict_T *d,
71529752c72fSBram Moolenaar int first_entry,
71539752c72fSBram Moolenaar int *valid_entry)
71546f6ef7c1SBram Moolenaar {
71556f6ef7c1SBram Moolenaar static int did_bufnr_emsg;
71566f6ef7c1SBram Moolenaar char_u *filename, *module, *pattern, *text, *type;
71576864efa5Sthinca int bufnum, valid, status, col, end_col, vcol, nr;
71586864efa5Sthinca long lnum, end_lnum;
71596f6ef7c1SBram Moolenaar
71606f6ef7c1SBram Moolenaar if (first_entry)
71616f6ef7c1SBram Moolenaar did_bufnr_emsg = FALSE;
71626f6ef7c1SBram Moolenaar
71638f66717aSBram Moolenaar filename = dict_get_string(d, (char_u *)"filename", TRUE);
71648f66717aSBram Moolenaar module = dict_get_string(d, (char_u *)"module", TRUE);
71658f66717aSBram Moolenaar bufnum = (int)dict_get_number(d, (char_u *)"bufnr");
71668f66717aSBram Moolenaar lnum = (int)dict_get_number(d, (char_u *)"lnum");
71676864efa5Sthinca end_lnum = (int)dict_get_number(d, (char_u *)"end_lnum");
71688f66717aSBram Moolenaar col = (int)dict_get_number(d, (char_u *)"col");
71696864efa5Sthinca end_col = (int)dict_get_number(d, (char_u *)"end_col");
71708f66717aSBram Moolenaar vcol = (int)dict_get_number(d, (char_u *)"vcol");
71718f66717aSBram Moolenaar nr = (int)dict_get_number(d, (char_u *)"nr");
71728f66717aSBram Moolenaar type = dict_get_string(d, (char_u *)"type", TRUE);
71738f66717aSBram Moolenaar pattern = dict_get_string(d, (char_u *)"pattern", TRUE);
71748f66717aSBram Moolenaar text = dict_get_string(d, (char_u *)"text", TRUE);
71756f6ef7c1SBram Moolenaar if (text == NULL)
71766f6ef7c1SBram Moolenaar text = vim_strsave((char_u *)"");
71776f6ef7c1SBram Moolenaar
71786f6ef7c1SBram Moolenaar valid = TRUE;
71796f6ef7c1SBram Moolenaar if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL))
71806f6ef7c1SBram Moolenaar valid = FALSE;
71816f6ef7c1SBram Moolenaar
71826f6ef7c1SBram Moolenaar // Mark entries with non-existing buffer number as not valid. Give the
71836f6ef7c1SBram Moolenaar // error message only once.
71846f6ef7c1SBram Moolenaar if (bufnum != 0 && (buflist_findnr(bufnum) == NULL))
71856f6ef7c1SBram Moolenaar {
71866f6ef7c1SBram Moolenaar if (!did_bufnr_emsg)
71876f6ef7c1SBram Moolenaar {
71886f6ef7c1SBram Moolenaar did_bufnr_emsg = TRUE;
7189b5443cc4SBram Moolenaar semsg(_("E92: Buffer %d not found"), bufnum);
71906f6ef7c1SBram Moolenaar }
71916f6ef7c1SBram Moolenaar valid = FALSE;
71926f6ef7c1SBram Moolenaar bufnum = 0;
71936f6ef7c1SBram Moolenaar }
71946f6ef7c1SBram Moolenaar
71956f6ef7c1SBram Moolenaar // If the 'valid' field is present it overrules the detected value.
71966f6ef7c1SBram Moolenaar if ((dict_find(d, (char_u *)"valid", -1)) != NULL)
7197401f0c07SBram Moolenaar valid = (int)dict_get_bool(d, (char_u *)"valid", FALSE);
71986f6ef7c1SBram Moolenaar
71990398e00aSBram Moolenaar status = qf_add_entry(qfl,
72006f6ef7c1SBram Moolenaar NULL, // dir
72016f6ef7c1SBram Moolenaar filename,
72026f6ef7c1SBram Moolenaar module,
72036f6ef7c1SBram Moolenaar bufnum,
72046f6ef7c1SBram Moolenaar text,
72056f6ef7c1SBram Moolenaar lnum,
72066864efa5Sthinca end_lnum,
72076f6ef7c1SBram Moolenaar col,
72086864efa5Sthinca end_col,
72096f6ef7c1SBram Moolenaar vcol, // vis_col
72106f6ef7c1SBram Moolenaar pattern, // search pattern
72116f6ef7c1SBram Moolenaar nr,
72126f6ef7c1SBram Moolenaar type == NULL ? NUL : *type,
72136f6ef7c1SBram Moolenaar valid);
72146f6ef7c1SBram Moolenaar
72156f6ef7c1SBram Moolenaar vim_free(filename);
72166f6ef7c1SBram Moolenaar vim_free(module);
72176f6ef7c1SBram Moolenaar vim_free(pattern);
72186f6ef7c1SBram Moolenaar vim_free(text);
72196f6ef7c1SBram Moolenaar vim_free(type);
72206f6ef7c1SBram Moolenaar
72219752c72fSBram Moolenaar if (valid)
72229752c72fSBram Moolenaar *valid_entry = TRUE;
72239752c72fSBram Moolenaar
72246f6ef7c1SBram Moolenaar return status;
72256f6ef7c1SBram Moolenaar }
72266f6ef7c1SBram Moolenaar
72276f6ef7c1SBram Moolenaar /*
7228d823fa91SBram Moolenaar * Add list of entries to quickfix/location list. Each list entry is
7229d823fa91SBram Moolenaar * a dictionary with item information.
7230d823fa91SBram Moolenaar */
7231d823fa91SBram Moolenaar static int
qf_add_entries(qf_info_T * qi,int qf_idx,list_T * list,char_u * title,int action)7232d823fa91SBram Moolenaar qf_add_entries(
7233d823fa91SBram Moolenaar qf_info_T *qi,
7234a3921f48SBram Moolenaar int qf_idx,
723505540976SBram Moolenaar list_T *list,
7236d823fa91SBram Moolenaar char_u *title,
7237d823fa91SBram Moolenaar int action)
723868b76a69SBram Moolenaar {
72390398e00aSBram Moolenaar qf_list_T *qfl = qf_get_list(qi, qf_idx);
724068b76a69SBram Moolenaar listitem_T *li;
724168b76a69SBram Moolenaar dict_T *d;
7242864293abSBram Moolenaar qfline_T *old_last = NULL;
724368b76a69SBram Moolenaar int retval = OK;
72449752c72fSBram Moolenaar int valid_entry = FALSE;
724568b76a69SBram Moolenaar
7246a3921f48SBram Moolenaar if (action == ' ' || qf_idx == qi->qf_listcount)
7247a3921f48SBram Moolenaar {
724800bf8cd2SBram Moolenaar // make place for a new list
724994116159SBram Moolenaar qf_new_list(qi, title);
7250a3921f48SBram Moolenaar qf_idx = qi->qf_curlist;
72510398e00aSBram Moolenaar qfl = qf_get_list(qi, qf_idx);
7252a3921f48SBram Moolenaar }
72530398e00aSBram Moolenaar else if (action == 'a' && !qf_list_empty(qfl))
725400bf8cd2SBram Moolenaar // Adding to existing list, use last entry.
7255fe15b7dfSBram Moolenaar old_last = qfl->qf_last;
725635c54e56SBram Moolenaar else if (action == 'r')
7257fb60409aSBram Moolenaar {
7258fe15b7dfSBram Moolenaar qf_free_items(qfl);
7259fe15b7dfSBram Moolenaar qf_store_title(qfl, title);
7260fb60409aSBram Moolenaar }
726168b76a69SBram Moolenaar
7262aeea7215SBram Moolenaar FOR_ALL_LIST_ITEMS(list, li)
726368b76a69SBram Moolenaar {
726468b76a69SBram Moolenaar if (li->li_tv.v_type != VAR_DICT)
726500bf8cd2SBram Moolenaar continue; // Skip non-dict items
726668b76a69SBram Moolenaar
726768b76a69SBram Moolenaar d = li->li_tv.vval.v_dict;
726868b76a69SBram Moolenaar if (d == NULL)
726968b76a69SBram Moolenaar continue;
727068b76a69SBram Moolenaar
72710398e00aSBram Moolenaar retval = qf_add_entry_from_dict(qfl, d, li == list->lv_first,
72729752c72fSBram Moolenaar &valid_entry);
727395946f12SBram Moolenaar if (retval == QF_FAIL)
727468b76a69SBram Moolenaar break;
727568b76a69SBram Moolenaar }
727668b76a69SBram Moolenaar
72779752c72fSBram Moolenaar // Check if any valid error entries are added to the list.
72789752c72fSBram Moolenaar if (valid_entry)
72799752c72fSBram Moolenaar qfl->qf_nonevalid = FALSE;
72809752c72fSBram Moolenaar else if (qfl->qf_index == 0)
728100bf8cd2SBram Moolenaar // no valid entry
7282fe15b7dfSBram Moolenaar qfl->qf_nonevalid = TRUE;
72839752c72fSBram Moolenaar
72849752c72fSBram Moolenaar // If not appending to the list, set the current error to the first entry
7285b6fa30ccSBram Moolenaar if (action != 'a')
7286fe15b7dfSBram Moolenaar qfl->qf_ptr = qfl->qf_start;
72879752c72fSBram Moolenaar
72889752c72fSBram Moolenaar // Update the current error index if not appending to the list or if the
72899752c72fSBram Moolenaar // list was empty before and it is not empty now.
72900398e00aSBram Moolenaar if ((action != 'a' || qfl->qf_index == 0) && !qf_list_empty(qfl))
7291fe15b7dfSBram Moolenaar qfl->qf_index = 1;
729268b76a69SBram Moolenaar
729300bf8cd2SBram Moolenaar // Don't update the cursor in quickfix window when appending entries
7294864293abSBram Moolenaar qf_update_buffer(qi, old_last);
729568b76a69SBram Moolenaar
729668b76a69SBram Moolenaar return retval;
729768b76a69SBram Moolenaar }
7298d823fa91SBram Moolenaar
7299a2aa8a2bSBram Moolenaar /*
7300a2aa8a2bSBram Moolenaar * Get the quickfix list index from 'nr' or 'id'
7301a2aa8a2bSBram Moolenaar */
7302d823fa91SBram Moolenaar static int
qf_setprop_get_qfidx(qf_info_T * qi,dict_T * what,int action,int * newlist)7303a2aa8a2bSBram Moolenaar qf_setprop_get_qfidx(
7304a2aa8a2bSBram Moolenaar qf_info_T *qi,
7305a2aa8a2bSBram Moolenaar dict_T *what,
7306a2aa8a2bSBram Moolenaar int action,
7307a2aa8a2bSBram Moolenaar int *newlist)
7308d823fa91SBram Moolenaar {
7309d823fa91SBram Moolenaar dictitem_T *di;
731000bf8cd2SBram Moolenaar int qf_idx = qi->qf_curlist; // default is the current list
73112b529bb6SBram Moolenaar
7312d823fa91SBram Moolenaar if ((di = dict_find(what, (char_u *)"nr", -1)) != NULL)
7313d823fa91SBram Moolenaar {
731400bf8cd2SBram Moolenaar // Use the specified quickfix/location list
7315d823fa91SBram Moolenaar if (di->di_tv.v_type == VAR_NUMBER)
7316d823fa91SBram Moolenaar {
731700bf8cd2SBram Moolenaar // for zero use the current list
73186e62da3eSBram Moolenaar if (di->di_tv.vval.v_number != 0)
7319d823fa91SBram Moolenaar qf_idx = di->di_tv.vval.v_number - 1;
73206a8958dbSBram Moolenaar
732155b69264SBram Moolenaar if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount)
732255b69264SBram Moolenaar {
732300bf8cd2SBram Moolenaar // When creating a new list, accept qf_idx pointing to the next
732400bf8cd2SBram Moolenaar // non-available list and add the new list at the end of the
732500bf8cd2SBram Moolenaar // stack.
7326a2aa8a2bSBram Moolenaar *newlist = TRUE;
7327019dfe68SBram Moolenaar qf_idx = qf_stack_empty(qi) ? 0 : qi->qf_listcount - 1;
732855b69264SBram Moolenaar }
73296a8958dbSBram Moolenaar else if (qf_idx < 0 || qf_idx >= qi->qf_listcount)
7330a2aa8a2bSBram Moolenaar return INVALID_QFIDX;
733155b69264SBram Moolenaar else if (action != ' ')
733200bf8cd2SBram Moolenaar *newlist = FALSE; // use the specified list
733355b69264SBram Moolenaar }
733455b69264SBram Moolenaar else if (di->di_tv.v_type == VAR_STRING
7335a0ca7d00SBram Moolenaar && di->di_tv.vval.v_string != NULL
733655b69264SBram Moolenaar && STRCMP(di->di_tv.vval.v_string, "$") == 0)
73376a8958dbSBram Moolenaar {
7338019dfe68SBram Moolenaar if (!qf_stack_empty(qi))
7339875feea6SBram Moolenaar qf_idx = qi->qf_listcount - 1;
7340a2aa8a2bSBram Moolenaar else if (*newlist)
734155b69264SBram Moolenaar qf_idx = 0;
734255b69264SBram Moolenaar else
7343a2aa8a2bSBram Moolenaar return INVALID_QFIDX;
73446a8958dbSBram Moolenaar }
7345d823fa91SBram Moolenaar else
7346a2aa8a2bSBram Moolenaar return INVALID_QFIDX;
73472b529bb6SBram Moolenaar }
73482b529bb6SBram Moolenaar
7349a2aa8a2bSBram Moolenaar if (!*newlist && (di = dict_find(what, (char_u *)"id", -1)) != NULL)
7350a539f4f1SBram Moolenaar {
735100bf8cd2SBram Moolenaar // Use the quickfix/location list with the specified id
7352a2aa8a2bSBram Moolenaar if (di->di_tv.v_type != VAR_NUMBER)
7353a2aa8a2bSBram Moolenaar return INVALID_QFIDX;
7354a2aa8a2bSBram Moolenaar
7355a2aa8a2bSBram Moolenaar return qf_id2nr(qi, di->di_tv.vval.v_number);
7356a539f4f1SBram Moolenaar }
7357a2aa8a2bSBram Moolenaar
7358a2aa8a2bSBram Moolenaar return qf_idx;
7359a2aa8a2bSBram Moolenaar }
7360a2aa8a2bSBram Moolenaar
7361a2aa8a2bSBram Moolenaar /*
7362a2aa8a2bSBram Moolenaar * Set the quickfix list title.
7363a2aa8a2bSBram Moolenaar */
7364a2aa8a2bSBram Moolenaar static int
qf_setprop_title(qf_info_T * qi,int qf_idx,dict_T * what,dictitem_T * di)7365a2aa8a2bSBram Moolenaar qf_setprop_title(qf_info_T *qi, int qf_idx, dict_T *what, dictitem_T *di)
7366a2aa8a2bSBram Moolenaar {
73670398e00aSBram Moolenaar qf_list_T *qfl = qf_get_list(qi, qf_idx);
7368108e7b42SBram Moolenaar
7369a2aa8a2bSBram Moolenaar if (di->di_tv.v_type != VAR_STRING)
7370a539f4f1SBram Moolenaar return FAIL;
7371a539f4f1SBram Moolenaar
7372108e7b42SBram Moolenaar vim_free(qfl->qf_title);
73738f66717aSBram Moolenaar qfl->qf_title = dict_get_string(what, (char_u *)"title", TRUE);
7374d823fa91SBram Moolenaar if (qf_idx == qi->qf_curlist)
7375d823fa91SBram Moolenaar qf_update_win_titlevar(qi);
7376a2aa8a2bSBram Moolenaar
7377a2aa8a2bSBram Moolenaar return OK;
7378d823fa91SBram Moolenaar }
737936538225SBram Moolenaar
7380a2aa8a2bSBram Moolenaar /*
7381a2aa8a2bSBram Moolenaar * Set quickfix list items/entries.
7382a2aa8a2bSBram Moolenaar */
7383a2aa8a2bSBram Moolenaar static int
qf_setprop_items(qf_info_T * qi,int qf_idx,dictitem_T * di,int action)7384a2aa8a2bSBram Moolenaar qf_setprop_items(qf_info_T *qi, int qf_idx, dictitem_T *di, int action)
73856a8958dbSBram Moolenaar {
7386a2aa8a2bSBram Moolenaar int retval = FAIL;
7387a2aa8a2bSBram Moolenaar char_u *title_save;
73886a8958dbSBram Moolenaar
7389a2aa8a2bSBram Moolenaar if (di->di_tv.v_type != VAR_LIST)
7390a2aa8a2bSBram Moolenaar return FAIL;
7391a2aa8a2bSBram Moolenaar
7392a2aa8a2bSBram Moolenaar title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
73936a8958dbSBram Moolenaar retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
73946a8958dbSBram Moolenaar title_save, action == ' ' ? 'a' : action);
73956a8958dbSBram Moolenaar vim_free(title_save);
7396a2aa8a2bSBram Moolenaar
7397a2aa8a2bSBram Moolenaar return retval;
73986a8958dbSBram Moolenaar }
7399d823fa91SBram Moolenaar
7400a2aa8a2bSBram Moolenaar /*
7401a2aa8a2bSBram Moolenaar * Set quickfix list items/entries from a list of lines.
7402a2aa8a2bSBram Moolenaar */
7403a2aa8a2bSBram Moolenaar static int
qf_setprop_items_from_lines(qf_info_T * qi,int qf_idx,dict_T * what,dictitem_T * di,int action)7404a2aa8a2bSBram Moolenaar qf_setprop_items_from_lines(
7405a2aa8a2bSBram Moolenaar qf_info_T *qi,
7406a2aa8a2bSBram Moolenaar int qf_idx,
7407a2aa8a2bSBram Moolenaar dict_T *what,
7408a2aa8a2bSBram Moolenaar dictitem_T *di,
7409a2aa8a2bSBram Moolenaar int action)
741036538225SBram Moolenaar {
7411a2aa8a2bSBram Moolenaar char_u *errorformat = p_efm;
7412a2aa8a2bSBram Moolenaar dictitem_T *efm_di;
7413a2aa8a2bSBram Moolenaar int retval = FAIL;
7414a2aa8a2bSBram Moolenaar
741500bf8cd2SBram Moolenaar // Use the user supplied errorformat settings (if present)
7416a2aa8a2bSBram Moolenaar if ((efm_di = dict_find(what, (char_u *)"efm", -1)) != NULL)
7417a2aa8a2bSBram Moolenaar {
7418a2aa8a2bSBram Moolenaar if (efm_di->di_tv.v_type != VAR_STRING ||
7419a2aa8a2bSBram Moolenaar efm_di->di_tv.vval.v_string == NULL)
742036538225SBram Moolenaar return FAIL;
7421a2aa8a2bSBram Moolenaar errorformat = efm_di->di_tv.vval.v_string;
742236538225SBram Moolenaar }
742336538225SBram Moolenaar
742400bf8cd2SBram Moolenaar // Only a List value is supported
7425a2aa8a2bSBram Moolenaar if (di->di_tv.v_type != VAR_LIST || di->di_tv.vval.v_list == NULL)
7426a2aa8a2bSBram Moolenaar return FAIL;
7427a2aa8a2bSBram Moolenaar
7428ae338338SBram Moolenaar if (action == 'r')
7429fe15b7dfSBram Moolenaar qf_free_items(&qi->qf_lists[qf_idx]);
743036538225SBram Moolenaar if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
7431287153c5SBram Moolenaar FALSE, (linenr_T)0, (linenr_T)0, NULL, NULL) >= 0)
7432ae338338SBram Moolenaar retval = OK;
7433a2aa8a2bSBram Moolenaar
7434a2aa8a2bSBram Moolenaar return retval;
7435ae338338SBram Moolenaar }
7436ae338338SBram Moolenaar
7437a2aa8a2bSBram Moolenaar /*
7438a2aa8a2bSBram Moolenaar * Set quickfix list context.
7439a2aa8a2bSBram Moolenaar */
7440a2aa8a2bSBram Moolenaar static int
qf_setprop_context(qf_list_T * qfl,dictitem_T * di)7441fe15b7dfSBram Moolenaar qf_setprop_context(qf_list_T *qfl, dictitem_T *di)
74428f77c5a4SBram Moolenaar {
74438f77c5a4SBram Moolenaar typval_T *ctx;
7444875feea6SBram Moolenaar
7445fe15b7dfSBram Moolenaar free_tv(qfl->qf_ctx);
74468f77c5a4SBram Moolenaar ctx = alloc_tv();
74478f77c5a4SBram Moolenaar if (ctx != NULL)
74488f77c5a4SBram Moolenaar copy_tv(&di->di_tv, ctx);
7449fe15b7dfSBram Moolenaar qfl->qf_ctx = ctx;
7450a2aa8a2bSBram Moolenaar
7451a2aa8a2bSBram Moolenaar return OK;
74528f77c5a4SBram Moolenaar }
74538f77c5a4SBram Moolenaar
7454a2aa8a2bSBram Moolenaar /*
74555b69c22fSBram Moolenaar * Set the current index in the specified quickfix list
74565b69c22fSBram Moolenaar */
74575b69c22fSBram Moolenaar static int
qf_setprop_curidx(qf_info_T * qi,qf_list_T * qfl,dictitem_T * di)74585b69c22fSBram Moolenaar qf_setprop_curidx(qf_info_T *qi, qf_list_T *qfl, dictitem_T *di)
74595b69c22fSBram Moolenaar {
74605b69c22fSBram Moolenaar int denote = FALSE;
74615b69c22fSBram Moolenaar int newidx;
74625b69c22fSBram Moolenaar int old_qfidx;
74635b69c22fSBram Moolenaar qfline_T *qf_ptr;
74645b69c22fSBram Moolenaar
74655b69c22fSBram Moolenaar // If the specified index is '$', then use the last entry
74665b69c22fSBram Moolenaar if (di->di_tv.v_type == VAR_STRING
74675b69c22fSBram Moolenaar && di->di_tv.vval.v_string != NULL
74685b69c22fSBram Moolenaar && STRCMP(di->di_tv.vval.v_string, "$") == 0)
74695b69c22fSBram Moolenaar newidx = qfl->qf_count;
74705b69c22fSBram Moolenaar else
74715b69c22fSBram Moolenaar {
74725b69c22fSBram Moolenaar // Otherwise use the specified index
74735b69c22fSBram Moolenaar newidx = tv_get_number_chk(&di->di_tv, &denote);
74745b69c22fSBram Moolenaar if (denote)
74755b69c22fSBram Moolenaar return FAIL;
74765b69c22fSBram Moolenaar }
74775b69c22fSBram Moolenaar
74785b69c22fSBram Moolenaar if (newidx < 1) // sanity check
74795b69c22fSBram Moolenaar return FAIL;
74805b69c22fSBram Moolenaar if (newidx > qfl->qf_count)
74815b69c22fSBram Moolenaar newidx = qfl->qf_count;
74825b69c22fSBram Moolenaar
74835b69c22fSBram Moolenaar old_qfidx = qfl->qf_index;
74845b69c22fSBram Moolenaar qf_ptr = get_nth_entry(qfl, newidx, &newidx);
74855b69c22fSBram Moolenaar if (qf_ptr == NULL)
74865b69c22fSBram Moolenaar return FAIL;
74875b69c22fSBram Moolenaar qfl->qf_ptr = qf_ptr;
74885b69c22fSBram Moolenaar qfl->qf_index = newidx;
74895b69c22fSBram Moolenaar
74905b69c22fSBram Moolenaar // If the current list is modified and it is displayed in the quickfix
74915b69c22fSBram Moolenaar // window, then Update it.
74924aa47b28SBram Moolenaar if (qf_get_curlist(qi)->qf_id == qfl->qf_id)
74935b69c22fSBram Moolenaar qf_win_pos_update(qi, old_qfidx);
74945b69c22fSBram Moolenaar
74955b69c22fSBram Moolenaar return OK;
74965b69c22fSBram Moolenaar }
74975b69c22fSBram Moolenaar
74985b69c22fSBram Moolenaar /*
7499858ba06dSBram Moolenaar * Set the current index in the specified quickfix list
7500858ba06dSBram Moolenaar */
7501858ba06dSBram Moolenaar static int
qf_setprop_qftf(qf_info_T * qi UNUSED,qf_list_T * qfl,dictitem_T * di)7502858ba06dSBram Moolenaar qf_setprop_qftf(qf_info_T *qi UNUSED, qf_list_T *qfl, dictitem_T *di)
7503858ba06dSBram Moolenaar {
7504d43906d2SBram Moolenaar callback_T cb;
7505d43906d2SBram Moolenaar
7506d43906d2SBram Moolenaar free_callback(&qfl->qftf_cb);
7507d43906d2SBram Moolenaar cb = get_callback(&di->di_tv);
7508d43906d2SBram Moolenaar if (cb.cb_name != NULL && *cb.cb_name != NUL)
7509d43906d2SBram Moolenaar set_callback(&qfl->qftf_cb, &cb);
7510858ba06dSBram Moolenaar
7511858ba06dSBram Moolenaar return OK;
7512858ba06dSBram Moolenaar }
7513858ba06dSBram Moolenaar
7514858ba06dSBram Moolenaar /*
7515a2aa8a2bSBram Moolenaar * Set quickfix/location list properties (title, items, context).
7516a2aa8a2bSBram Moolenaar * Also used to add items from parsing a list of lines.
75177a2b0e55SBram Moolenaar * Used by the setqflist() and setloclist() Vim script functions.
7518a2aa8a2bSBram Moolenaar */
7519a2aa8a2bSBram Moolenaar static int
qf_set_properties(qf_info_T * qi,dict_T * what,int action,char_u * title)7520a2aa8a2bSBram Moolenaar qf_set_properties(qf_info_T *qi, dict_T *what, int action, char_u *title)
7521a2aa8a2bSBram Moolenaar {
7522a2aa8a2bSBram Moolenaar dictitem_T *di;
7523a2aa8a2bSBram Moolenaar int retval = FAIL;
7524a2aa8a2bSBram Moolenaar int qf_idx;
7525a2aa8a2bSBram Moolenaar int newlist = FALSE;
7526108e7b42SBram Moolenaar qf_list_T *qfl;
7527a2aa8a2bSBram Moolenaar
7528019dfe68SBram Moolenaar if (action == ' ' || qf_stack_empty(qi))
7529a2aa8a2bSBram Moolenaar newlist = TRUE;
7530a2aa8a2bSBram Moolenaar
7531a2aa8a2bSBram Moolenaar qf_idx = qf_setprop_get_qfidx(qi, what, action, &newlist);
753200bf8cd2SBram Moolenaar if (qf_idx == INVALID_QFIDX) // List not found
7533a2aa8a2bSBram Moolenaar return FAIL;
7534a2aa8a2bSBram Moolenaar
7535a2aa8a2bSBram Moolenaar if (newlist)
7536a2aa8a2bSBram Moolenaar {
7537a2aa8a2bSBram Moolenaar qi->qf_curlist = qf_idx;
7538a2aa8a2bSBram Moolenaar qf_new_list(qi, title);
7539a2aa8a2bSBram Moolenaar qf_idx = qi->qf_curlist;
7540a2aa8a2bSBram Moolenaar }
7541a2aa8a2bSBram Moolenaar
75420398e00aSBram Moolenaar qfl = qf_get_list(qi, qf_idx);
7543a2aa8a2bSBram Moolenaar if ((di = dict_find(what, (char_u *)"title", -1)) != NULL)
7544a2aa8a2bSBram Moolenaar retval = qf_setprop_title(qi, qf_idx, what, di);
7545a2aa8a2bSBram Moolenaar if ((di = dict_find(what, (char_u *)"items", -1)) != NULL)
7546a2aa8a2bSBram Moolenaar retval = qf_setprop_items(qi, qf_idx, di, action);
7547a2aa8a2bSBram Moolenaar if ((di = dict_find(what, (char_u *)"lines", -1)) != NULL)
7548a2aa8a2bSBram Moolenaar retval = qf_setprop_items_from_lines(qi, qf_idx, what, di, action);
7549a2aa8a2bSBram Moolenaar if ((di = dict_find(what, (char_u *)"context", -1)) != NULL)
7550108e7b42SBram Moolenaar retval = qf_setprop_context(qfl, di);
75515b69c22fSBram Moolenaar if ((di = dict_find(what, (char_u *)"idx", -1)) != NULL)
75525b69c22fSBram Moolenaar retval = qf_setprop_curidx(qi, qfl, di);
7553858ba06dSBram Moolenaar if ((di = dict_find(what, (char_u *)"quickfixtextfunc", -1)) != NULL)
7554858ba06dSBram Moolenaar retval = qf_setprop_qftf(qi, qfl, di);
7555a2aa8a2bSBram Moolenaar
7556287153c5SBram Moolenaar if (newlist || retval == OK)
7557108e7b42SBram Moolenaar qf_list_changed(qfl);
7558287153c5SBram Moolenaar if (newlist)
7559287153c5SBram Moolenaar qf_update_buffer(qi, NULL);
7560b254af31SBram Moolenaar
7561d823fa91SBram Moolenaar return retval;
7562d823fa91SBram Moolenaar }
7563d823fa91SBram Moolenaar
756469f40be6SBram Moolenaar /*
756569f40be6SBram Moolenaar * Free the entire quickfix/location list stack.
756669f40be6SBram Moolenaar * If the quickfix/location list window is open, then clear it.
756769f40be6SBram Moolenaar */
7568b6fa30ccSBram Moolenaar static void
qf_free_stack(win_T * wp,qf_info_T * qi)7569b6fa30ccSBram Moolenaar qf_free_stack(win_T *wp, qf_info_T *qi)
7570b6fa30ccSBram Moolenaar {
757169f40be6SBram Moolenaar win_T *qfwin = qf_find_win(qi);
757269f40be6SBram Moolenaar win_T *llwin = NULL;
757369f40be6SBram Moolenaar
757469f40be6SBram Moolenaar if (qfwin != NULL)
757569f40be6SBram Moolenaar {
757600bf8cd2SBram Moolenaar // If the quickfix/location list window is open, then clear it
757769f40be6SBram Moolenaar if (qi->qf_curlist < qi->qf_listcount)
75784aa47b28SBram Moolenaar qf_free(qf_get_curlist(qi));
757969f40be6SBram Moolenaar qf_update_buffer(qi, NULL);
758069f40be6SBram Moolenaar }
758169f40be6SBram Moolenaar
758269f40be6SBram Moolenaar if (wp != NULL && IS_LL_WINDOW(wp))
758369f40be6SBram Moolenaar {
758400bf8cd2SBram Moolenaar // If in the location list window, then use the non-location list
758500bf8cd2SBram Moolenaar // window with this location list (if present)
7586ee8188fcSBram Moolenaar llwin = qf_find_win_with_loclist(qi);
758769f40be6SBram Moolenaar if (llwin != NULL)
758869f40be6SBram Moolenaar wp = llwin;
758969f40be6SBram Moolenaar }
759069f40be6SBram Moolenaar
7591b6fa30ccSBram Moolenaar qf_free_all(wp);
7592b6fa30ccSBram Moolenaar if (wp == NULL)
7593b6fa30ccSBram Moolenaar {
759400bf8cd2SBram Moolenaar // quickfix list
7595b6fa30ccSBram Moolenaar qi->qf_curlist = 0;
7596b6fa30ccSBram Moolenaar qi->qf_listcount = 0;
7597b6fa30ccSBram Moolenaar }
7598ee8188fcSBram Moolenaar else if (qfwin != NULL)
759969f40be6SBram Moolenaar {
760000bf8cd2SBram Moolenaar // If the location list window is open, then create a new empty
760100bf8cd2SBram Moolenaar // location list
76022d67d307SBram Moolenaar qf_info_T *new_ll = qf_alloc_stack(QFLT_LOCATION);
760395946f12SBram Moolenaar
760495946f12SBram Moolenaar if (new_ll != NULL)
760595946f12SBram Moolenaar {
7606ee8188fcSBram Moolenaar new_ll->qf_bufnr = qfwin->w_buffer->b_fnum;
760799895eacSBram Moolenaar
760800bf8cd2SBram Moolenaar // first free the list reference in the location list window
7609ee8188fcSBram Moolenaar ll_free_all(&qfwin->w_llist_ref);
7610d788f6feSBram Moolenaar
7611ee8188fcSBram Moolenaar qfwin->w_llist_ref = new_ll;
7612ee8188fcSBram Moolenaar if (wp != qfwin)
76134aa47b28SBram Moolenaar win_set_loclist(wp, new_ll);
761469f40be6SBram Moolenaar }
7615b6fa30ccSBram Moolenaar }
761695946f12SBram Moolenaar }
7617b6fa30ccSBram Moolenaar
7618d823fa91SBram Moolenaar /*
7619d823fa91SBram Moolenaar * Populate the quickfix list with the items supplied in the list
7620d823fa91SBram Moolenaar * of dictionaries. "title" will be copied to w:quickfix_title.
7621d823fa91SBram Moolenaar * "action" is 'a' for add, 'r' for replace. Otherwise create a new list.
762290049492SBram Moolenaar * When "what" is not NULL then only set some properties.
7623d823fa91SBram Moolenaar */
7624d823fa91SBram Moolenaar int
set_errorlist(win_T * wp,list_T * list,int action,char_u * title,dict_T * what)7625d823fa91SBram Moolenaar set_errorlist(
7626d823fa91SBram Moolenaar win_T *wp,
7627d823fa91SBram Moolenaar list_T *list,
7628d823fa91SBram Moolenaar int action,
7629d823fa91SBram Moolenaar char_u *title,
7630d823fa91SBram Moolenaar dict_T *what)
7631d823fa91SBram Moolenaar {
7632d823fa91SBram Moolenaar qf_info_T *qi = &ql_info;
7633d823fa91SBram Moolenaar int retval = OK;
7634d823fa91SBram Moolenaar
7635d823fa91SBram Moolenaar if (wp != NULL)
7636d823fa91SBram Moolenaar {
7637d823fa91SBram Moolenaar qi = ll_get_or_alloc_list(wp);
7638d823fa91SBram Moolenaar if (qi == NULL)
7639d823fa91SBram Moolenaar return FAIL;
7640d823fa91SBram Moolenaar }
7641d823fa91SBram Moolenaar
7642b6fa30ccSBram Moolenaar if (action == 'f')
7643b6fa30ccSBram Moolenaar {
764400bf8cd2SBram Moolenaar // Free the entire quickfix or location list stack
7645b6fa30ccSBram Moolenaar qf_free_stack(wp, qi);
76469f84ded3SBram Moolenaar return OK;
7647b6fa30ccSBram Moolenaar }
76489f84ded3SBram Moolenaar
7649be7a50c2SBram Moolenaar // A dict argument cannot be specified with a non-empty list argument
765090049492SBram Moolenaar if (list->lv_len != 0 && what != NULL)
7651be7a50c2SBram Moolenaar {
7652be7a50c2SBram Moolenaar semsg(_(e_invarg2),
7653be7a50c2SBram Moolenaar _("cannot have both a list and a \"what\" argument"));
7654be7a50c2SBram Moolenaar return FAIL;
7655be7a50c2SBram Moolenaar }
7656be7a50c2SBram Moolenaar
76579f84ded3SBram Moolenaar incr_quickfix_busy();
76589f84ded3SBram Moolenaar
76599f84ded3SBram Moolenaar if (what != NULL)
7660ae338338SBram Moolenaar retval = qf_set_properties(qi, what, action, title);
7661d823fa91SBram Moolenaar else
7662b254af31SBram Moolenaar {
7663a3921f48SBram Moolenaar retval = qf_add_entries(qi, qi->qf_curlist, list, title, action);
7664b254af31SBram Moolenaar if (retval == OK)
76654aa47b28SBram Moolenaar qf_list_changed(qf_get_curlist(qi));
7666b254af31SBram Moolenaar }
7667d823fa91SBram Moolenaar
76689f84ded3SBram Moolenaar decr_quickfix_busy();
76699f84ded3SBram Moolenaar
7670d823fa91SBram Moolenaar return retval;
7671d823fa91SBram Moolenaar }
76728f77c5a4SBram Moolenaar
767318cebf44SBram Moolenaar /*
767418cebf44SBram Moolenaar * Mark the context as in use for all the lists in a quickfix stack.
767518cebf44SBram Moolenaar */
76768f77c5a4SBram Moolenaar static int
mark_quickfix_ctx(qf_info_T * qi,int copyID)76778f77c5a4SBram Moolenaar mark_quickfix_ctx(qf_info_T *qi, int copyID)
76788f77c5a4SBram Moolenaar {
76798f77c5a4SBram Moolenaar int i;
76808f77c5a4SBram Moolenaar int abort = FALSE;
76818f77c5a4SBram Moolenaar typval_T *ctx;
76828f77c5a4SBram Moolenaar
76838f77c5a4SBram Moolenaar for (i = 0; i < LISTCOUNT && !abort; ++i)
76848f77c5a4SBram Moolenaar {
76858f77c5a4SBram Moolenaar ctx = qi->qf_lists[i].qf_ctx;
768655b69264SBram Moolenaar if (ctx != NULL && ctx->v_type != VAR_NUMBER
768755b69264SBram Moolenaar && ctx->v_type != VAR_STRING && ctx->v_type != VAR_FLOAT)
76888f77c5a4SBram Moolenaar abort = set_ref_in_item(ctx, copyID, NULL, NULL);
76898f77c5a4SBram Moolenaar }
76908f77c5a4SBram Moolenaar
76918f77c5a4SBram Moolenaar return abort;
76928f77c5a4SBram Moolenaar }
76938f77c5a4SBram Moolenaar
76948f77c5a4SBram Moolenaar /*
76958f77c5a4SBram Moolenaar * Mark the context of the quickfix list and the location lists (if present) as
7696353eeeacSBram Moolenaar * "in use". So that garbage collection doesn't free the context.
76978f77c5a4SBram Moolenaar */
76988f77c5a4SBram Moolenaar int
set_ref_in_quickfix(int copyID)76998f77c5a4SBram Moolenaar set_ref_in_quickfix(int copyID)
77008f77c5a4SBram Moolenaar {
77018f77c5a4SBram Moolenaar int abort = FALSE;
77028f77c5a4SBram Moolenaar tabpage_T *tp;
77038f77c5a4SBram Moolenaar win_T *win;
77048f77c5a4SBram Moolenaar
77058f77c5a4SBram Moolenaar abort = mark_quickfix_ctx(&ql_info, copyID);
77068f77c5a4SBram Moolenaar if (abort)
77078f77c5a4SBram Moolenaar return abort;
77088f77c5a4SBram Moolenaar
77098f77c5a4SBram Moolenaar FOR_ALL_TAB_WINDOWS(tp, win)
77108f77c5a4SBram Moolenaar {
77118f77c5a4SBram Moolenaar if (win->w_llist != NULL)
77128f77c5a4SBram Moolenaar {
77138f77c5a4SBram Moolenaar abort = mark_quickfix_ctx(win->w_llist, copyID);
77148f77c5a4SBram Moolenaar if (abort)
77158f77c5a4SBram Moolenaar return abort;
77168f77c5a4SBram Moolenaar }
771712237448SBram Moolenaar if (IS_LL_WINDOW(win) && (win->w_llist_ref->qf_refcount == 1))
771812237448SBram Moolenaar {
771900bf8cd2SBram Moolenaar // In a location list window and none of the other windows is
772000bf8cd2SBram Moolenaar // referring to this location list. Mark the location list
772100bf8cd2SBram Moolenaar // context as still in use.
772212237448SBram Moolenaar abort = mark_quickfix_ctx(win->w_llist_ref, copyID);
772312237448SBram Moolenaar if (abort)
772412237448SBram Moolenaar return abort;
772512237448SBram Moolenaar }
77268f77c5a4SBram Moolenaar }
77278f77c5a4SBram Moolenaar
77288f77c5a4SBram Moolenaar return abort;
77298f77c5a4SBram Moolenaar }
773005159a0cSBram Moolenaar #endif
773105159a0cSBram Moolenaar
773281695250SBram Moolenaar /*
7733a16123a6SBram Moolenaar * Return the autocmd name for the :cbuffer Ex commands
7734a16123a6SBram Moolenaar */
7735a16123a6SBram Moolenaar static char_u *
cbuffer_get_auname(cmdidx_T cmdidx)7736a16123a6SBram Moolenaar cbuffer_get_auname(cmdidx_T cmdidx)
7737a16123a6SBram Moolenaar {
7738a16123a6SBram Moolenaar switch (cmdidx)
7739a16123a6SBram Moolenaar {
7740a16123a6SBram Moolenaar case CMD_cbuffer: return (char_u *)"cbuffer";
7741a16123a6SBram Moolenaar case CMD_cgetbuffer: return (char_u *)"cgetbuffer";
7742a16123a6SBram Moolenaar case CMD_caddbuffer: return (char_u *)"caddbuffer";
7743a16123a6SBram Moolenaar case CMD_lbuffer: return (char_u *)"lbuffer";
7744a16123a6SBram Moolenaar case CMD_lgetbuffer: return (char_u *)"lgetbuffer";
7745a16123a6SBram Moolenaar case CMD_laddbuffer: return (char_u *)"laddbuffer";
7746a16123a6SBram Moolenaar default: return NULL;
7747a16123a6SBram Moolenaar }
7748a16123a6SBram Moolenaar }
7749a16123a6SBram Moolenaar
7750a16123a6SBram Moolenaar /*
7751a16123a6SBram Moolenaar * Process and validate the arguments passed to the :cbuffer, :caddbuffer,
7752a16123a6SBram Moolenaar * :cgetbuffer, :lbuffer, :laddbuffer, :lgetbuffer Ex commands.
7753a16123a6SBram Moolenaar */
7754a16123a6SBram Moolenaar static int
cbuffer_process_args(exarg_T * eap,buf_T ** bufp,linenr_T * line1,linenr_T * line2)7755a16123a6SBram Moolenaar cbuffer_process_args(
7756a16123a6SBram Moolenaar exarg_T *eap,
7757a16123a6SBram Moolenaar buf_T **bufp,
7758a16123a6SBram Moolenaar linenr_T *line1,
7759a16123a6SBram Moolenaar linenr_T *line2)
7760a16123a6SBram Moolenaar {
7761a16123a6SBram Moolenaar buf_T *buf = NULL;
7762a16123a6SBram Moolenaar
7763a16123a6SBram Moolenaar if (*eap->arg == NUL)
7764a16123a6SBram Moolenaar buf = curbuf;
7765a16123a6SBram Moolenaar else if (*skipwhite(skipdigits(eap->arg)) == NUL)
7766a16123a6SBram Moolenaar buf = buflist_findnr(atoi((char *)eap->arg));
7767a16123a6SBram Moolenaar
7768a16123a6SBram Moolenaar if (buf == NULL)
7769a16123a6SBram Moolenaar {
7770a16123a6SBram Moolenaar emsg(_(e_invarg));
7771a16123a6SBram Moolenaar return FAIL;
7772a16123a6SBram Moolenaar }
7773a16123a6SBram Moolenaar
7774a16123a6SBram Moolenaar if (buf->b_ml.ml_mfp == NULL)
7775a16123a6SBram Moolenaar {
7776a16123a6SBram Moolenaar emsg(_("E681: Buffer is not loaded"));
7777a16123a6SBram Moolenaar return FAIL;
7778a16123a6SBram Moolenaar }
7779a16123a6SBram Moolenaar
7780a16123a6SBram Moolenaar if (eap->addr_count == 0)
7781a16123a6SBram Moolenaar {
7782a16123a6SBram Moolenaar eap->line1 = 1;
7783a16123a6SBram Moolenaar eap->line2 = buf->b_ml.ml_line_count;
7784a16123a6SBram Moolenaar }
7785a16123a6SBram Moolenaar
7786a16123a6SBram Moolenaar if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
7787a16123a6SBram Moolenaar || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
7788a16123a6SBram Moolenaar {
7789108010aaSBram Moolenaar emsg(_(e_invalid_range));
7790a16123a6SBram Moolenaar return FAIL;
7791a16123a6SBram Moolenaar }
7792a16123a6SBram Moolenaar
7793a16123a6SBram Moolenaar *line1 = eap->line1;
7794a16123a6SBram Moolenaar *line2 = eap->line2;
7795a16123a6SBram Moolenaar *bufp = buf;
7796a16123a6SBram Moolenaar
7797a16123a6SBram Moolenaar return OK;
7798a16123a6SBram Moolenaar }
7799a16123a6SBram Moolenaar
7800a16123a6SBram Moolenaar /*
780186b68359SBram Moolenaar * ":[range]cbuffer [bufnr]" command.
7802a6557605SBram Moolenaar * ":[range]caddbuffer [bufnr]" command.
7803db552d60SBram Moolenaar * ":[range]cgetbuffer [bufnr]" command.
7804d12f5c17SBram Moolenaar * ":[range]lbuffer [bufnr]" command.
7805a6557605SBram Moolenaar * ":[range]laddbuffer [bufnr]" command.
7806db552d60SBram Moolenaar * ":[range]lgetbuffer [bufnr]" command.
780786b68359SBram Moolenaar */
780886b68359SBram Moolenaar void
ex_cbuffer(exarg_T * eap)780905540976SBram Moolenaar ex_cbuffer(exarg_T *eap)
781086b68359SBram Moolenaar {
781186b68359SBram Moolenaar buf_T *buf = NULL;
781287f59b09SBram Moolenaar qf_info_T *qi;
781304c4ce65SBram Moolenaar char_u *au_name = NULL;
78141ed2276fSBram Moolenaar int res;
7815531b9a3aSBram Moolenaar int_u save_qfid;
7816531b9a3aSBram Moolenaar win_T *wp = NULL;
7817a16123a6SBram Moolenaar char_u *qf_title;
7818a16123a6SBram Moolenaar linenr_T line1;
7819a16123a6SBram Moolenaar linenr_T line2;
7820d12f5c17SBram Moolenaar
7821a16123a6SBram Moolenaar au_name = cbuffer_get_auname(eap->cmdidx);
782221662be2SBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
782321662be2SBram Moolenaar curbuf->b_fname, TRUE, curbuf))
782404c4ce65SBram Moolenaar {
782504c4ce65SBram Moolenaar #ifdef FEAT_EVAL
782621662be2SBram Moolenaar if (aborting())
782704c4ce65SBram Moolenaar return;
782804c4ce65SBram Moolenaar #endif
782904c4ce65SBram Moolenaar }
783004c4ce65SBram Moolenaar
783100bf8cd2SBram Moolenaar // Must come after autocommands.
783287f59b09SBram Moolenaar qi = qf_cmd_get_or_alloc_stack(eap, &wp);
7833aaf6e43bSBram Moolenaar if (qi == NULL)
7834aaf6e43bSBram Moolenaar return;
7835aaf6e43bSBram Moolenaar
7836a16123a6SBram Moolenaar if (cbuffer_process_args(eap, &buf, &line1, &line2) == FAIL)
7837a16123a6SBram Moolenaar return;
7838a16123a6SBram Moolenaar
7839a16123a6SBram Moolenaar qf_title = qf_cmdtitle(*eap->cmdlinep);
78407fd73200SBram Moolenaar
78417fd73200SBram Moolenaar if (buf->b_sfname)
78427fd73200SBram Moolenaar {
78437fd73200SBram Moolenaar vim_snprintf((char *)IObuff, IOSIZE, "%s (%s)",
78447fd73200SBram Moolenaar (char *)qf_title, (char *)buf->b_sfname);
78457fd73200SBram Moolenaar qf_title = IObuff;
78467fd73200SBram Moolenaar }
78477fd73200SBram Moolenaar
78489f84ded3SBram Moolenaar incr_quickfix_busy();
78499f84ded3SBram Moolenaar
78501ed2276fSBram Moolenaar res = qf_init_ext(qi, qi->qf_curlist, NULL, buf, NULL, p_efm,
7851db552d60SBram Moolenaar (eap->cmdidx != CMD_caddbuffer
7852db552d60SBram Moolenaar && eap->cmdidx != CMD_laddbuffer),
7853a16123a6SBram Moolenaar line1, line2,
78541ed2276fSBram Moolenaar qf_title, NULL);
78559f84ded3SBram Moolenaar if (qf_stack_empty(qi))
78569f84ded3SBram Moolenaar {
78579f84ded3SBram Moolenaar decr_quickfix_busy();
78589f84ded3SBram Moolenaar return;
78599f84ded3SBram Moolenaar }
7860b254af31SBram Moolenaar if (res >= 0)
78614aa47b28SBram Moolenaar qf_list_changed(qf_get_curlist(qi));
7862531b9a3aSBram Moolenaar
7863531b9a3aSBram Moolenaar // Remember the current quickfix list identifier, so that we can
7864531b9a3aSBram Moolenaar // check for autocommands changing the current quickfix list.
78654aa47b28SBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
786604c4ce65SBram Moolenaar if (au_name != NULL)
7867600323b4SBram Moolenaar {
7868600323b4SBram Moolenaar buf_T *curbuf_old = curbuf;
7869600323b4SBram Moolenaar
7870a16123a6SBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, curbuf->b_fname,
7871a16123a6SBram Moolenaar TRUE, curbuf);
7872600323b4SBram Moolenaar if (curbuf != curbuf_old)
7873600323b4SBram Moolenaar // Autocommands changed buffer, don't jump now, "qi" may
7874600323b4SBram Moolenaar // be invalid.
7875600323b4SBram Moolenaar res = 0;
7876600323b4SBram Moolenaar }
7877531b9a3aSBram Moolenaar // Jump to the first error for a new list and if autocmds didn't
7878531b9a3aSBram Moolenaar // free the list.
78791ed2276fSBram Moolenaar if (res > 0 && (eap->cmdidx == CMD_cbuffer ||
7880531b9a3aSBram Moolenaar eap->cmdidx == CMD_lbuffer)
7881531b9a3aSBram Moolenaar && qflist_valid(wp, save_qfid))
78828d8a65e3SBram Moolenaar // display the first error
78838d8a65e3SBram Moolenaar qf_jump_first(qi, save_qfid, eap->forceit);
78849f84ded3SBram Moolenaar
78859f84ded3SBram Moolenaar decr_quickfix_busy();
7886754b5608SBram Moolenaar }
7887a16123a6SBram Moolenaar
7888a16123a6SBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
7889a16123a6SBram Moolenaar /*
7890a16123a6SBram Moolenaar * Return the autocmd name for the :cexpr Ex commands.
7891a16123a6SBram Moolenaar */
78925f7d4c04SBram Moolenaar char_u *
cexpr_get_auname(cmdidx_T cmdidx)7893a16123a6SBram Moolenaar cexpr_get_auname(cmdidx_T cmdidx)
7894a16123a6SBram Moolenaar {
7895a16123a6SBram Moolenaar switch (cmdidx)
7896a16123a6SBram Moolenaar {
7897a16123a6SBram Moolenaar case CMD_cexpr: return (char_u *)"cexpr";
7898a16123a6SBram Moolenaar case CMD_cgetexpr: return (char_u *)"cgetexpr";
7899a16123a6SBram Moolenaar case CMD_caddexpr: return (char_u *)"caddexpr";
7900a16123a6SBram Moolenaar case CMD_lexpr: return (char_u *)"lexpr";
7901a16123a6SBram Moolenaar case CMD_lgetexpr: return (char_u *)"lgetexpr";
7902a16123a6SBram Moolenaar case CMD_laddexpr: return (char_u *)"laddexpr";
7903a16123a6SBram Moolenaar default: return NULL;
790486b68359SBram Moolenaar }
790586b68359SBram Moolenaar }
790686b68359SBram Moolenaar
79075f7d4c04SBram Moolenaar int
trigger_cexpr_autocmd(int cmdidx)79085f7d4c04SBram Moolenaar trigger_cexpr_autocmd(int cmdidx)
790987e25fdfSBram Moolenaar {
79105f7d4c04SBram Moolenaar char_u *au_name = cexpr_get_auname(cmdidx);
7911d12f5c17SBram Moolenaar
791221662be2SBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
791321662be2SBram Moolenaar curbuf->b_fname, TRUE, curbuf))
791404c4ce65SBram Moolenaar {
791521662be2SBram Moolenaar if (aborting())
79165f7d4c04SBram Moolenaar return FAIL;
791704c4ce65SBram Moolenaar }
79185f7d4c04SBram Moolenaar return OK;
79195f7d4c04SBram Moolenaar }
79205f7d4c04SBram Moolenaar
79215f7d4c04SBram Moolenaar int
cexpr_core(exarg_T * eap,typval_T * tv)79225f7d4c04SBram Moolenaar cexpr_core(exarg_T *eap, typval_T *tv)
79235f7d4c04SBram Moolenaar {
79245f7d4c04SBram Moolenaar qf_info_T *qi;
79255f7d4c04SBram Moolenaar win_T *wp = NULL;
792604c4ce65SBram Moolenaar
792787f59b09SBram Moolenaar qi = qf_cmd_get_or_alloc_stack(eap, &wp);
79283c097226SBram Moolenaar if (qi == NULL)
79295f7d4c04SBram Moolenaar return FAIL;
79303c097226SBram Moolenaar
79314770d09aSBram Moolenaar if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL)
79324770d09aSBram Moolenaar || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL))
79334770d09aSBram Moolenaar {
79345f7d4c04SBram Moolenaar int res;
79355f7d4c04SBram Moolenaar int_u save_qfid;
79365f7d4c04SBram Moolenaar char_u *au_name = cexpr_get_auname(eap->cmdidx);
79375f7d4c04SBram Moolenaar
79389f84ded3SBram Moolenaar incr_quickfix_busy();
79391ed2276fSBram Moolenaar res = qf_init_ext(qi, qi->qf_curlist, NULL, NULL, tv, p_efm,
7940db552d60SBram Moolenaar (eap->cmdidx != CMD_caddexpr
7941db552d60SBram Moolenaar && eap->cmdidx != CMD_laddexpr),
79428b62e310SBram Moolenaar (linenr_T)0, (linenr_T)0,
79438b62e310SBram Moolenaar qf_cmdtitle(*eap->cmdlinep), NULL);
79449f84ded3SBram Moolenaar if (qf_stack_empty(qi))
79459f84ded3SBram Moolenaar {
79469f84ded3SBram Moolenaar decr_quickfix_busy();
79475f7d4c04SBram Moolenaar return FAIL;
79489f84ded3SBram Moolenaar }
7949b254af31SBram Moolenaar if (res >= 0)
79504aa47b28SBram Moolenaar qf_list_changed(qf_get_curlist(qi));
7951531b9a3aSBram Moolenaar
7952531b9a3aSBram Moolenaar // Remember the current quickfix list identifier, so that we can
7953531b9a3aSBram Moolenaar // check for autocommands changing the current quickfix list.
79544aa47b28SBram Moolenaar save_qfid = qf_get_curlist(qi)->qf_id;
795504c4ce65SBram Moolenaar if (au_name != NULL)
795604c4ce65SBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
795704c4ce65SBram Moolenaar curbuf->b_fname, TRUE, curbuf);
7958531b9a3aSBram Moolenaar
7959531b9a3aSBram Moolenaar // Jump to the first error for a new list and if autocmds didn't
7960531b9a3aSBram Moolenaar // free the list.
79615f7d4c04SBram Moolenaar if (res > 0 && (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr)
7962531b9a3aSBram Moolenaar && qflist_valid(wp, save_qfid))
79638d8a65e3SBram Moolenaar // display the first error
79648d8a65e3SBram Moolenaar qf_jump_first(qi, save_qfid, eap->forceit);
79659f84ded3SBram Moolenaar decr_quickfix_busy();
79665f7d4c04SBram Moolenaar return OK;
79674770d09aSBram Moolenaar }
79685f7d4c04SBram Moolenaar
7969f9e3e09fSBram Moolenaar emsg(_("E777: String or List expected"));
79705f7d4c04SBram Moolenaar return FAIL;
79715f7d4c04SBram Moolenaar }
79725f7d4c04SBram Moolenaar
79735f7d4c04SBram Moolenaar /*
79745f7d4c04SBram Moolenaar * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command.
79755f7d4c04SBram Moolenaar * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command.
79765f7d4c04SBram Moolenaar * Also: ":caddexpr", ":cgetexpr", "laddexpr" and "laddexpr".
79775f7d4c04SBram Moolenaar */
79785f7d4c04SBram Moolenaar void
ex_cexpr(exarg_T * eap)79795f7d4c04SBram Moolenaar ex_cexpr(exarg_T *eap)
79805f7d4c04SBram Moolenaar {
79815f7d4c04SBram Moolenaar typval_T *tv;
79825f7d4c04SBram Moolenaar
79835f7d4c04SBram Moolenaar if (trigger_cexpr_autocmd(eap->cmdidx) == FAIL)
79845f7d4c04SBram Moolenaar return;
79855f7d4c04SBram Moolenaar
79865f7d4c04SBram Moolenaar // Evaluate the expression. When the result is a string or a list we can
79875f7d4c04SBram Moolenaar // use it to fill the errorlist.
79885f7d4c04SBram Moolenaar tv = eval_expr(eap->arg, eap);
79895f7d4c04SBram Moolenaar if (tv != NULL)
79905f7d4c04SBram Moolenaar {
79915f7d4c04SBram Moolenaar (void)cexpr_core(eap, tv);
79924770d09aSBram Moolenaar free_tv(tv);
79934770d09aSBram Moolenaar }
799487e25fdfSBram Moolenaar }
79951e015460SBram Moolenaar #endif
799687e25fdfSBram Moolenaar
799787e25fdfSBram Moolenaar /*
79982225ebb4SBram Moolenaar * Get the location list for ":lhelpgrep"
7999071d4279SBram Moolenaar */
80002225ebb4SBram Moolenaar static qf_info_T *
hgr_get_ll(int * new_ll)80012225ebb4SBram Moolenaar hgr_get_ll(int *new_ll)
8002071d4279SBram Moolenaar {
80038b6144bdSBram Moolenaar win_T *wp;
80042225ebb4SBram Moolenaar qf_info_T *qi;
8005071d4279SBram Moolenaar
800600bf8cd2SBram Moolenaar // If the current window is a help window, then use it
8007d28cc3f5SBram Moolenaar if (bt_help(curwin->w_buffer))
8008d28cc3f5SBram Moolenaar wp = curwin;
8009d28cc3f5SBram Moolenaar else
801000bf8cd2SBram Moolenaar // Find an existing help window
80117a2b0e55SBram Moolenaar wp = qf_find_help_win();
80128b6144bdSBram Moolenaar
801300bf8cd2SBram Moolenaar if (wp == NULL) // Help window not found
80148b6144bdSBram Moolenaar qi = NULL;
80158b6144bdSBram Moolenaar else
80168b6144bdSBram Moolenaar qi = wp->w_llist;
80178b6144bdSBram Moolenaar
80188b6144bdSBram Moolenaar if (qi == NULL)
80198b6144bdSBram Moolenaar {
802000bf8cd2SBram Moolenaar // Allocate a new location list for help text matches
80212d67d307SBram Moolenaar if ((qi = qf_alloc_stack(QFLT_LOCATION)) == NULL)
80222225ebb4SBram Moolenaar return NULL;
80232225ebb4SBram Moolenaar *new_ll = TRUE;
80248b6144bdSBram Moolenaar }
80258b6144bdSBram Moolenaar
80262225ebb4SBram Moolenaar return qi;
80272225ebb4SBram Moolenaar }
80282225ebb4SBram Moolenaar
80292225ebb4SBram Moolenaar /*
80302225ebb4SBram Moolenaar * Search for a pattern in a help file.
80312225ebb4SBram Moolenaar */
80322225ebb4SBram Moolenaar static void
hgr_search_file(qf_list_T * qfl,char_u * fname,vimconv_T * p_vc,regmatch_T * p_regmatch)80332225ebb4SBram Moolenaar hgr_search_file(
80349afe5e9cSBram Moolenaar qf_list_T *qfl,
80352225ebb4SBram Moolenaar char_u *fname,
80362225ebb4SBram Moolenaar vimconv_T *p_vc,
80372225ebb4SBram Moolenaar regmatch_T *p_regmatch)
80382225ebb4SBram Moolenaar {
80392225ebb4SBram Moolenaar FILE *fd;
80402225ebb4SBram Moolenaar long lnum;
804110b7b39bSBram Moolenaar
80422225ebb4SBram Moolenaar fd = mch_fopen((char *)fname, "r");
80432225ebb4SBram Moolenaar if (fd == NULL)
80442225ebb4SBram Moolenaar return;
8045071d4279SBram Moolenaar
8046071d4279SBram Moolenaar lnum = 1;
8047071d4279SBram Moolenaar while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
8048071d4279SBram Moolenaar {
804910b7b39bSBram Moolenaar char_u *line = IObuff;
8050a12a161bSBram Moolenaar
805100bf8cd2SBram Moolenaar // Convert a line if 'encoding' is not utf-8 and
805200bf8cd2SBram Moolenaar // the line contains a non-ASCII character.
80532225ebb4SBram Moolenaar if (p_vc->vc_type != CONV_NONE
8054b6fa30ccSBram Moolenaar && has_non_ascii(IObuff))
8055b6fa30ccSBram Moolenaar {
80562225ebb4SBram Moolenaar line = string_convert(p_vc, IObuff, NULL);
805710b7b39bSBram Moolenaar if (line == NULL)
805810b7b39bSBram Moolenaar line = IObuff;
805910b7b39bSBram Moolenaar }
806010b7b39bSBram Moolenaar
80612225ebb4SBram Moolenaar if (vim_regexec(p_regmatch, line, (colnr_T)0))
8062071d4279SBram Moolenaar {
806310b7b39bSBram Moolenaar int l = (int)STRLEN(line);
8064071d4279SBram Moolenaar
806500bf8cd2SBram Moolenaar // remove trailing CR, LF, spaces, etc.
806610b7b39bSBram Moolenaar while (l > 0 && line[l - 1] <= ' ')
806710b7b39bSBram Moolenaar line[--l] = NUL;
8068071d4279SBram Moolenaar
80699afe5e9cSBram Moolenaar if (qf_add_entry(qfl,
807000bf8cd2SBram Moolenaar NULL, // dir
80712225ebb4SBram Moolenaar fname,
8072d76ce852SBram Moolenaar NULL,
807348b66fb5SBram Moolenaar 0,
807410b7b39bSBram Moolenaar line,
8075071d4279SBram Moolenaar lnum,
80766864efa5Sthinca 0,
80772225ebb4SBram Moolenaar (int)(p_regmatch->startp[0] - line)
807800bf8cd2SBram Moolenaar + 1, // col
80796864efa5Sthinca (int)(p_regmatch->endp[0] - line)
80806864efa5Sthinca + 1, // end_col
808100bf8cd2SBram Moolenaar FALSE, // vis_col
808200bf8cd2SBram Moolenaar NULL, // search pattern
808300bf8cd2SBram Moolenaar 0, // nr
808400bf8cd2SBram Moolenaar 1, // type
808500bf8cd2SBram Moolenaar TRUE // valid
808695946f12SBram Moolenaar ) == QF_FAIL)
8087071d4279SBram Moolenaar {
8088071d4279SBram Moolenaar got_int = TRUE;
808910b7b39bSBram Moolenaar if (line != IObuff)
809010b7b39bSBram Moolenaar vim_free(line);
8091071d4279SBram Moolenaar break;
8092071d4279SBram Moolenaar }
8093071d4279SBram Moolenaar }
809410b7b39bSBram Moolenaar if (line != IObuff)
809510b7b39bSBram Moolenaar vim_free(line);
8096071d4279SBram Moolenaar ++lnum;
8097071d4279SBram Moolenaar line_breakcheck();
8098071d4279SBram Moolenaar }
8099071d4279SBram Moolenaar fclose(fd);
8100071d4279SBram Moolenaar }
81012225ebb4SBram Moolenaar
81022225ebb4SBram Moolenaar /*
81032225ebb4SBram Moolenaar * Search for a pattern in all the help files in the doc directory under
81042225ebb4SBram Moolenaar * the given directory.
81052225ebb4SBram Moolenaar */
81062225ebb4SBram Moolenaar static void
hgr_search_files_in_dir(qf_list_T * qfl,char_u * dirname,regmatch_T * p_regmatch,vimconv_T * p_vc,char_u * lang)81072225ebb4SBram Moolenaar hgr_search_files_in_dir(
81089afe5e9cSBram Moolenaar qf_list_T *qfl,
81092225ebb4SBram Moolenaar char_u *dirname,
8110a12a161bSBram Moolenaar regmatch_T *p_regmatch,
8111a12a161bSBram Moolenaar vimconv_T *p_vc
81122225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
81132225ebb4SBram Moolenaar , char_u *lang
81142225ebb4SBram Moolenaar #endif
81152225ebb4SBram Moolenaar )
81162225ebb4SBram Moolenaar {
81172225ebb4SBram Moolenaar int fcount;
81182225ebb4SBram Moolenaar char_u **fnames;
81192225ebb4SBram Moolenaar int fi;
81202225ebb4SBram Moolenaar
812100bf8cd2SBram Moolenaar // Find all "*.txt" and "*.??x" files in the "doc" directory.
81222225ebb4SBram Moolenaar add_pathsep(dirname);
81232225ebb4SBram Moolenaar STRCAT(dirname, "doc/*.\\(txt\\|??x\\)");
81242225ebb4SBram Moolenaar if (gen_expand_wildcards(1, &dirname, &fcount,
81252225ebb4SBram Moolenaar &fnames, EW_FILE|EW_SILENT) == OK
81262225ebb4SBram Moolenaar && fcount > 0)
81272225ebb4SBram Moolenaar {
81282225ebb4SBram Moolenaar for (fi = 0; fi < fcount && !got_int; ++fi)
81292225ebb4SBram Moolenaar {
81302225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
813100bf8cd2SBram Moolenaar // Skip files for a different language.
81322225ebb4SBram Moolenaar if (lang != NULL
81332225ebb4SBram Moolenaar && STRNICMP(lang, fnames[fi]
81342225ebb4SBram Moolenaar + STRLEN(fnames[fi]) - 3, 2) != 0
81352225ebb4SBram Moolenaar && !(STRNICMP(lang, "en", 2) == 0
81362225ebb4SBram Moolenaar && STRNICMP("txt", fnames[fi]
81372225ebb4SBram Moolenaar + STRLEN(fnames[fi]) - 3, 3) == 0))
81382225ebb4SBram Moolenaar continue;
81392225ebb4SBram Moolenaar #endif
81402225ebb4SBram Moolenaar
81419afe5e9cSBram Moolenaar hgr_search_file(qfl, fnames[fi], p_vc, p_regmatch);
8142071d4279SBram Moolenaar }
8143071d4279SBram Moolenaar FreeWild(fcount, fnames);
8144071d4279SBram Moolenaar }
8145071d4279SBram Moolenaar }
814610b7b39bSBram Moolenaar
81472225ebb4SBram Moolenaar /*
814818cebf44SBram Moolenaar * Search for a pattern in all the help files in the 'runtimepath'
814918cebf44SBram Moolenaar * and add the matches to a quickfix list.
8150c631f2dfSBram Moolenaar * 'lang' is the language specifier. If supplied, then only matches in the
815118cebf44SBram Moolenaar * specified language are found.
81522225ebb4SBram Moolenaar */
81532225ebb4SBram Moolenaar static void
hgr_search_in_rtp(qf_list_T * qfl,regmatch_T * p_regmatch,char_u * lang)81549afe5e9cSBram Moolenaar hgr_search_in_rtp(qf_list_T *qfl, regmatch_T *p_regmatch, char_u *lang)
81552225ebb4SBram Moolenaar {
81562225ebb4SBram Moolenaar char_u *p;
81572225ebb4SBram Moolenaar
81582225ebb4SBram Moolenaar vimconv_T vc;
81592225ebb4SBram Moolenaar
816000bf8cd2SBram Moolenaar // Help files are in utf-8 or latin1, convert lines when 'encoding'
816100bf8cd2SBram Moolenaar // differs.
81622225ebb4SBram Moolenaar vc.vc_type = CONV_NONE;
81632225ebb4SBram Moolenaar if (!enc_utf8)
81642225ebb4SBram Moolenaar convert_setup(&vc, (char_u *)"utf-8", p_enc);
81652225ebb4SBram Moolenaar
816600bf8cd2SBram Moolenaar // Go through all the directories in 'runtimepath'
81672225ebb4SBram Moolenaar p = p_rtp;
81682225ebb4SBram Moolenaar while (*p != NUL && !got_int)
81692225ebb4SBram Moolenaar {
81702225ebb4SBram Moolenaar copy_option_part(&p, NameBuff, MAXPATHL, ",");
81712225ebb4SBram Moolenaar
81729afe5e9cSBram Moolenaar hgr_search_files_in_dir(qfl, NameBuff, p_regmatch, &vc
81732225ebb4SBram Moolenaar #ifdef FEAT_MULTI_LANG
81742225ebb4SBram Moolenaar , lang
81752225ebb4SBram Moolenaar #endif
81762225ebb4SBram Moolenaar );
81772225ebb4SBram Moolenaar }
81782225ebb4SBram Moolenaar
817910b7b39bSBram Moolenaar if (vc.vc_type != CONV_NONE)
818010b7b39bSBram Moolenaar convert_setup(&vc, NULL, NULL);
81812225ebb4SBram Moolenaar }
81822225ebb4SBram Moolenaar
81832225ebb4SBram Moolenaar /*
81842225ebb4SBram Moolenaar * ":helpgrep {pattern}"
81852225ebb4SBram Moolenaar */
81862225ebb4SBram Moolenaar void
ex_helpgrep(exarg_T * eap)81872225ebb4SBram Moolenaar ex_helpgrep(exarg_T *eap)
81882225ebb4SBram Moolenaar {
81892225ebb4SBram Moolenaar regmatch_T regmatch;
81902225ebb4SBram Moolenaar char_u *save_cpo;
81912225ebb4SBram Moolenaar qf_info_T *qi = &ql_info;
81922225ebb4SBram Moolenaar int new_qi = FALSE;
81932225ebb4SBram Moolenaar char_u *au_name = NULL;
8194c631f2dfSBram Moolenaar char_u *lang = NULL;
8195e5a2dc87SBram Moolenaar int updated = FALSE;
81962225ebb4SBram Moolenaar
81972225ebb4SBram Moolenaar switch (eap->cmdidx)
81982225ebb4SBram Moolenaar {
81992225ebb4SBram Moolenaar case CMD_helpgrep: au_name = (char_u *)"helpgrep"; break;
82002225ebb4SBram Moolenaar case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break;
82012225ebb4SBram Moolenaar default: break;
82022225ebb4SBram Moolenaar }
82032225ebb4SBram Moolenaar if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name,
82042225ebb4SBram Moolenaar curbuf->b_fname, TRUE, curbuf))
82052225ebb4SBram Moolenaar {
82062225ebb4SBram Moolenaar #ifdef FEAT_EVAL
82072225ebb4SBram Moolenaar if (aborting())
82082225ebb4SBram Moolenaar return;
82092225ebb4SBram Moolenaar #endif
82102225ebb4SBram Moolenaar }
82112225ebb4SBram Moolenaar
821239665959SBram Moolenaar if (is_loclist_cmd(eap->cmdidx))
82132225ebb4SBram Moolenaar {
82142225ebb4SBram Moolenaar qi = hgr_get_ll(&new_qi);
82152225ebb4SBram Moolenaar if (qi == NULL)
82162225ebb4SBram Moolenaar return;
82172225ebb4SBram Moolenaar }
82182225ebb4SBram Moolenaar
8219a16123a6SBram Moolenaar // Make 'cpoptions' empty, the 'l' flag should not be used here.
8220a16123a6SBram Moolenaar save_cpo = p_cpo;
8221a16123a6SBram Moolenaar p_cpo = empty_option;
8222a16123a6SBram Moolenaar
82239f84ded3SBram Moolenaar incr_quickfix_busy();
82249f84ded3SBram Moolenaar
8225c631f2dfSBram Moolenaar #ifdef FEAT_MULTI_LANG
8226c631f2dfSBram Moolenaar // Check for a specified language
8227c631f2dfSBram Moolenaar lang = check_help_lang(eap->arg);
8228c631f2dfSBram Moolenaar #endif
82292225ebb4SBram Moolenaar regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING);
82302225ebb4SBram Moolenaar regmatch.rm_ic = FALSE;
82312225ebb4SBram Moolenaar if (regmatch.regprog != NULL)
82322225ebb4SBram Moolenaar {
8233108e7b42SBram Moolenaar qf_list_T *qfl;
8234108e7b42SBram Moolenaar
8235c631f2dfSBram Moolenaar // create a new quickfix list
82368b62e310SBram Moolenaar qf_new_list(qi, qf_cmdtitle(*eap->cmdlinep));
82379afe5e9cSBram Moolenaar qfl = qf_get_curlist(qi);
82382225ebb4SBram Moolenaar
82399afe5e9cSBram Moolenaar hgr_search_in_rtp(qfl, ®match, lang);
82402225ebb4SBram Moolenaar
82412225ebb4SBram Moolenaar vim_regfree(regmatch.regprog);
8242071d4279SBram Moolenaar
8243108e7b42SBram Moolenaar qfl->qf_nonevalid = FALSE;
8244108e7b42SBram Moolenaar qfl->qf_ptr = qfl->qf_start;
8245108e7b42SBram Moolenaar qfl->qf_index = 1;
8246108e7b42SBram Moolenaar qf_list_changed(qfl);
8247e5a2dc87SBram Moolenaar updated = TRUE;
8248071d4279SBram Moolenaar }
8249071d4279SBram Moolenaar
82509c24ccc7SBram Moolenaar if (p_cpo == empty_option)
8251071d4279SBram Moolenaar p_cpo = save_cpo;
82529c24ccc7SBram Moolenaar else
8253e5a2dc87SBram Moolenaar {
8254e5a2dc87SBram Moolenaar // Darn, some plugin changed the value. If it's still empty it was
8255e5a2dc87SBram Moolenaar // changed and restored, need to restore in the complicated way.
8256e5a2dc87SBram Moolenaar if (*p_cpo == NUL)
8257e5a2dc87SBram Moolenaar set_option_value((char_u *)"cpo", 0L, save_cpo, 0);
82589c24ccc7SBram Moolenaar free_string_option(save_cpo);
8259e5a2dc87SBram Moolenaar }
8260e5a2dc87SBram Moolenaar
8261e5a2dc87SBram Moolenaar if (updated)
8262e5a2dc87SBram Moolenaar // This may open a window and source scripts, do this after 'cpo' was
8263e5a2dc87SBram Moolenaar // restored.
8264e5a2dc87SBram Moolenaar qf_update_buffer(qi, NULL);
8265071d4279SBram Moolenaar
826673633f84SBram Moolenaar if (au_name != NULL)
826773633f84SBram Moolenaar {
826873633f84SBram Moolenaar apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name,
826973633f84SBram Moolenaar curbuf->b_fname, TRUE, curbuf);
8270ec98e93aSBram Moolenaar // When adding a location list to an existing location list stack,
8271ec98e93aSBram Moolenaar // if the autocmd made the stack invalid, then just return.
8272ec98e93aSBram Moolenaar if (!new_qi && IS_LL_STACK(qi) && qf_find_win_with_loclist(qi) == NULL)
82739f84ded3SBram Moolenaar {
82749f84ded3SBram Moolenaar decr_quickfix_busy();
827573633f84SBram Moolenaar return;
827673633f84SBram Moolenaar }
82779f84ded3SBram Moolenaar }
827873633f84SBram Moolenaar
827900bf8cd2SBram Moolenaar // Jump to first match.
82800398e00aSBram Moolenaar if (!qf_list_empty(qf_get_curlist(qi)))
82818b6144bdSBram Moolenaar qf_jump(qi, 0, 0, FALSE);
828269a7cb47SBram Moolenaar else
8283f9e3e09fSBram Moolenaar semsg(_(e_nomatch2), eap->arg);
82848b6144bdSBram Moolenaar
82859f84ded3SBram Moolenaar decr_quickfix_busy();
82869f84ded3SBram Moolenaar
82878b6144bdSBram Moolenaar if (eap->cmdidx == CMD_lhelpgrep)
82888b6144bdSBram Moolenaar {
8289c631f2dfSBram Moolenaar // If the help window is not opened or if it already points to the
8290c631f2dfSBram Moolenaar // correct location list, then free the new location list.
8291d28cc3f5SBram Moolenaar if (!bt_help(curwin->w_buffer) || curwin->w_llist == qi)
82928b6144bdSBram Moolenaar {
82938b6144bdSBram Moolenaar if (new_qi)
82948b6144bdSBram Moolenaar ll_free_all(&qi);
82958b6144bdSBram Moolenaar }
82968b6144bdSBram Moolenaar else if (curwin->w_llist == NULL)
82978b6144bdSBram Moolenaar curwin->w_llist = qi;
82988b6144bdSBram Moolenaar }
8299071d4279SBram Moolenaar }
830063d9e730SBram Moolenaar #endif // FEAT_QUICKFIX
8301e677df8dSBram Moolenaar
8302e677df8dSBram Moolenaar #if defined(FEAT_EVAL) || defined(PROTO)
8303e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8304e677df8dSBram Moolenaar static void
get_qf_loc_list(int is_qf,win_T * wp,typval_T * what_arg,typval_T * rettv)8305e677df8dSBram Moolenaar get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg, typval_T *rettv)
8306e677df8dSBram Moolenaar {
8307e677df8dSBram Moolenaar if (what_arg->v_type == VAR_UNKNOWN)
8308e677df8dSBram Moolenaar {
8309e677df8dSBram Moolenaar if (rettv_list_alloc(rettv) == OK)
8310e677df8dSBram Moolenaar if (is_qf || wp != NULL)
8311858ba06dSBram Moolenaar (void)get_errorlist(NULL, wp, -1, 0, rettv->vval.v_list);
8312e677df8dSBram Moolenaar }
8313e677df8dSBram Moolenaar else
8314e677df8dSBram Moolenaar {
8315e677df8dSBram Moolenaar if (rettv_dict_alloc(rettv) == OK)
8316e677df8dSBram Moolenaar if (is_qf || (wp != NULL))
8317e677df8dSBram Moolenaar {
8318e677df8dSBram Moolenaar if (what_arg->v_type == VAR_DICT)
8319e677df8dSBram Moolenaar {
8320e677df8dSBram Moolenaar dict_T *d = what_arg->vval.v_dict;
8321e677df8dSBram Moolenaar
8322e677df8dSBram Moolenaar if (d != NULL)
8323e677df8dSBram Moolenaar qf_get_properties(wp, d, rettv->vval.v_dict);
8324e677df8dSBram Moolenaar }
8325e677df8dSBram Moolenaar else
8326e677df8dSBram Moolenaar emsg(_(e_dictreq));
8327e677df8dSBram Moolenaar }
8328e677df8dSBram Moolenaar }
8329e677df8dSBram Moolenaar }
8330e677df8dSBram Moolenaar # endif
8331e677df8dSBram Moolenaar
8332e677df8dSBram Moolenaar /*
8333e677df8dSBram Moolenaar * "getloclist()" function
8334e677df8dSBram Moolenaar */
8335e677df8dSBram Moolenaar void
f_getloclist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)8336e677df8dSBram Moolenaar f_getloclist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8337e677df8dSBram Moolenaar {
8338e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8339e677df8dSBram Moolenaar win_T *wp;
8340e677df8dSBram Moolenaar
83414490ec4eSYegappan Lakshmanan if (in_vim9script()
83424490ec4eSYegappan Lakshmanan && (check_for_number_arg(argvars, 0) == FAIL
83434490ec4eSYegappan Lakshmanan || check_for_opt_dict_arg(argvars, 1) == FAIL))
83444490ec4eSYegappan Lakshmanan return;
83454490ec4eSYegappan Lakshmanan
8346e677df8dSBram Moolenaar wp = find_win_by_nr_or_id(&argvars[0]);
8347e677df8dSBram Moolenaar get_qf_loc_list(FALSE, wp, &argvars[1], rettv);
8348e677df8dSBram Moolenaar # endif
8349e677df8dSBram Moolenaar }
8350e677df8dSBram Moolenaar
8351e677df8dSBram Moolenaar /*
8352e677df8dSBram Moolenaar * "getqflist()" function
8353e677df8dSBram Moolenaar */
8354e677df8dSBram Moolenaar void
f_getqflist(typval_T * argvars UNUSED,typval_T * rettv UNUSED)8355e677df8dSBram Moolenaar f_getqflist(typval_T *argvars UNUSED, typval_T *rettv UNUSED)
8356e677df8dSBram Moolenaar {
8357e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
83584490ec4eSYegappan Lakshmanan if (in_vim9script() && check_for_opt_dict_arg(argvars, 0) == FAIL)
83594490ec4eSYegappan Lakshmanan return;
83604490ec4eSYegappan Lakshmanan
8361e677df8dSBram Moolenaar get_qf_loc_list(TRUE, NULL, &argvars[0], rettv);
8362e677df8dSBram Moolenaar # endif
8363e677df8dSBram Moolenaar }
8364e677df8dSBram Moolenaar
8365e677df8dSBram Moolenaar /*
8366e677df8dSBram Moolenaar * Used by "setqflist()" and "setloclist()" functions
8367e677df8dSBram Moolenaar */
8368e677df8dSBram Moolenaar static void
set_qf_ll_list(win_T * wp UNUSED,typval_T * list_arg UNUSED,typval_T * action_arg UNUSED,typval_T * what_arg UNUSED,typval_T * rettv)8369e677df8dSBram Moolenaar set_qf_ll_list(
8370e677df8dSBram Moolenaar win_T *wp UNUSED,
8371e677df8dSBram Moolenaar typval_T *list_arg UNUSED,
8372e677df8dSBram Moolenaar typval_T *action_arg UNUSED,
8373e677df8dSBram Moolenaar typval_T *what_arg UNUSED,
8374e677df8dSBram Moolenaar typval_T *rettv)
8375e677df8dSBram Moolenaar {
8376e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8377e677df8dSBram Moolenaar static char *e_invact = N_("E927: Invalid action: '%s'");
8378e677df8dSBram Moolenaar char_u *act;
8379e677df8dSBram Moolenaar int action = 0;
8380e677df8dSBram Moolenaar static int recursive = 0;
8381e677df8dSBram Moolenaar # endif
8382e677df8dSBram Moolenaar
8383e677df8dSBram Moolenaar rettv->vval.v_number = -1;
8384e677df8dSBram Moolenaar
8385e677df8dSBram Moolenaar # ifdef FEAT_QUICKFIX
8386e677df8dSBram Moolenaar if (list_arg->v_type != VAR_LIST)
8387e677df8dSBram Moolenaar emsg(_(e_listreq));
8388e677df8dSBram Moolenaar else if (recursive != 0)
8389e677df8dSBram Moolenaar emsg(_(e_au_recursive));
8390e677df8dSBram Moolenaar else
8391e677df8dSBram Moolenaar {
8392e677df8dSBram Moolenaar list_T *l = list_arg->vval.v_list;
839390049492SBram Moolenaar dict_T *what = NULL;
8394e677df8dSBram Moolenaar int valid_dict = TRUE;
8395e677df8dSBram Moolenaar
8396e677df8dSBram Moolenaar if (action_arg->v_type == VAR_STRING)
8397e677df8dSBram Moolenaar {
8398e677df8dSBram Moolenaar act = tv_get_string_chk(action_arg);
8399e677df8dSBram Moolenaar if (act == NULL)
8400e677df8dSBram Moolenaar return; // type error; errmsg already given
8401e677df8dSBram Moolenaar if ((*act == 'a' || *act == 'r' || *act == ' ' || *act == 'f') &&
8402e677df8dSBram Moolenaar act[1] == NUL)
8403e677df8dSBram Moolenaar action = *act;
8404e677df8dSBram Moolenaar else
8405e677df8dSBram Moolenaar semsg(_(e_invact), act);
8406e677df8dSBram Moolenaar }
8407e677df8dSBram Moolenaar else if (action_arg->v_type == VAR_UNKNOWN)
8408e677df8dSBram Moolenaar action = ' ';
8409e677df8dSBram Moolenaar else
8410e677df8dSBram Moolenaar emsg(_(e_stringreq));
8411e677df8dSBram Moolenaar
8412e677df8dSBram Moolenaar if (action_arg->v_type != VAR_UNKNOWN
8413e677df8dSBram Moolenaar && what_arg->v_type != VAR_UNKNOWN)
8414e677df8dSBram Moolenaar {
841590049492SBram Moolenaar if (what_arg->v_type == VAR_DICT && what_arg->vval.v_dict != NULL)
841690049492SBram Moolenaar what = what_arg->vval.v_dict;
8417e677df8dSBram Moolenaar else
8418e677df8dSBram Moolenaar {
8419e677df8dSBram Moolenaar emsg(_(e_dictreq));
8420e677df8dSBram Moolenaar valid_dict = FALSE;
8421e677df8dSBram Moolenaar }
8422e677df8dSBram Moolenaar }
8423e677df8dSBram Moolenaar
8424e677df8dSBram Moolenaar ++recursive;
842590049492SBram Moolenaar if (l != NULL && action && valid_dict
842690049492SBram Moolenaar && set_errorlist(wp, l, action,
8427e677df8dSBram Moolenaar (char_u *)(wp == NULL ? ":setqflist()" : ":setloclist()"),
842890049492SBram Moolenaar what) == OK)
8429e677df8dSBram Moolenaar rettv->vval.v_number = 0;
8430e677df8dSBram Moolenaar --recursive;
8431e677df8dSBram Moolenaar }
8432e677df8dSBram Moolenaar # endif
8433e677df8dSBram Moolenaar }
8434e677df8dSBram Moolenaar
8435e677df8dSBram Moolenaar /*
8436e677df8dSBram Moolenaar * "setloclist()" function
8437e677df8dSBram Moolenaar */
8438e677df8dSBram Moolenaar void
f_setloclist(typval_T * argvars,typval_T * rettv)8439e677df8dSBram Moolenaar f_setloclist(typval_T *argvars, typval_T *rettv)
8440e677df8dSBram Moolenaar {
8441e677df8dSBram Moolenaar win_T *win;
8442e677df8dSBram Moolenaar
8443e677df8dSBram Moolenaar rettv->vval.v_number = -1;
8444e677df8dSBram Moolenaar
844583494b4aSYegappan Lakshmanan if (in_vim9script()
844683494b4aSYegappan Lakshmanan && (check_for_number_arg(argvars, 0) == FAIL
844783494b4aSYegappan Lakshmanan || check_for_list_arg(argvars, 1) == FAIL
844883494b4aSYegappan Lakshmanan || check_for_opt_string_arg(argvars, 2) == FAIL
844983494b4aSYegappan Lakshmanan || (argvars[2].v_type != VAR_UNKNOWN
845083494b4aSYegappan Lakshmanan && check_for_opt_dict_arg(argvars, 3) == FAIL)))
845183494b4aSYegappan Lakshmanan return;
845283494b4aSYegappan Lakshmanan
8453e677df8dSBram Moolenaar win = find_win_by_nr_or_id(&argvars[0]);
8454e677df8dSBram Moolenaar if (win != NULL)
8455e677df8dSBram Moolenaar set_qf_ll_list(win, &argvars[1], &argvars[2], &argvars[3], rettv);
8456e677df8dSBram Moolenaar }
8457e677df8dSBram Moolenaar
8458e677df8dSBram Moolenaar /*
8459e677df8dSBram Moolenaar * "setqflist()" function
8460e677df8dSBram Moolenaar */
8461e677df8dSBram Moolenaar void
f_setqflist(typval_T * argvars,typval_T * rettv)8462e677df8dSBram Moolenaar f_setqflist(typval_T *argvars, typval_T *rettv)
8463e677df8dSBram Moolenaar {
846483494b4aSYegappan Lakshmanan if (in_vim9script()
846583494b4aSYegappan Lakshmanan && (check_for_list_arg(argvars, 0) == FAIL
846683494b4aSYegappan Lakshmanan || check_for_opt_string_arg(argvars, 1) == FAIL
846783494b4aSYegappan Lakshmanan || (argvars[1].v_type != VAR_UNKNOWN
846883494b4aSYegappan Lakshmanan && check_for_opt_dict_arg(argvars, 2) == FAIL)))
846983494b4aSYegappan Lakshmanan return;
847083494b4aSYegappan Lakshmanan
8471e677df8dSBram Moolenaar set_qf_ll_list(NULL, &argvars[0], &argvars[1], &argvars[2], rettv);
8472e677df8dSBram Moolenaar }
8473e677df8dSBram Moolenaar #endif
8474