Mercurial > vim
annotate src/quickfix.c @ 2247:c40cd9aad546 vim73
Add patch to improve support of z/OS (OS/390). (Ralf Schandl)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Thu, 03 Jun 2010 21:17:25 +0200 |
parents | c17a42da3920 |
children | eb7be7b075a6 |
rev | line source |
---|---|
7 | 1 /* vi:set ts=8 sts=4 sw=4: |
2 * | |
3 * VIM - Vi IMproved by Bram Moolenaar | |
4 * | |
5 * Do ":help uganda" in Vim to read copying and usage conditions. | |
6 * Do ":help credits" in Vim to see a list of people who contributed. | |
7 * See README.txt for an overview of the Vim source code. | |
8 */ | |
9 | |
10 /* | |
11 * quickfix.c: functions for quickfix mode, using a file with error messages | |
12 */ | |
13 | |
14 #include "vim.h" | |
15 | |
16 #if defined(FEAT_QUICKFIX) || defined(PROTO) | |
17 | |
18 struct dir_stack_T | |
19 { | |
20 struct dir_stack_T *next; | |
21 char_u *dirname; | |
22 }; | |
23 | |
24 static struct dir_stack_T *dir_stack = NULL; | |
25 | |
26 /* | |
230 | 27 * For each error the next struct is allocated and linked in a list. |
7 | 28 */ |
230 | 29 typedef struct qfline_S qfline_T; |
30 struct qfline_S | |
7 | 31 { |
230 | 32 qfline_T *qf_next; /* pointer to next error in the list */ |
33 qfline_T *qf_prev; /* pointer to previous error in the list */ | |
34 linenr_T qf_lnum; /* line number where the error occurred */ | |
35 int qf_fnum; /* file number for the line */ | |
36 int qf_col; /* column where the error occurred */ | |
37 int qf_nr; /* error number */ | |
38 char_u *qf_pattern; /* search pattern for the error */ | |
39 char_u *qf_text; /* description of the error */ | |
40 char_u qf_viscol; /* set to TRUE if qf_col is screen column */ | |
41 char_u qf_cleared; /* set to TRUE if line has been deleted */ | |
42 char_u qf_type; /* type of the error (mostly 'E'); 1 for | |
7 | 43 :helpgrep */ |
230 | 44 char_u qf_valid; /* valid error message detected */ |
7 | 45 }; |
46 | |
47 /* | |
48 * There is a stack of error lists. | |
49 */ | |
50 #define LISTCOUNT 10 | |
51 | |
644 | 52 typedef struct qf_list_S |
7 | 53 { |
230 | 54 qfline_T *qf_start; /* pointer to the first error */ |
55 qfline_T *qf_ptr; /* pointer to the current error */ | |
56 int qf_count; /* number of errors (0 means no error list) */ | |
57 int qf_index; /* current index in the error list */ | |
58 int qf_nonevalid; /* TRUE if not a single valid entry found */ | |
644 | 59 } qf_list_T; |
60 | |
61 struct qf_info_S | |
62 { | |
63 /* | |
64 * Count of references to this list. Used only for location lists. | |
65 * When a location list window reference this list, qf_refcount | |
66 * will be 2. Otherwise, qf_refcount will be 1. When qf_refcount | |
67 * reaches 0, the list is freed. | |
68 */ | |
69 int qf_refcount; | |
70 int qf_listcount; /* current number of lists */ | |
71 int qf_curlist; /* current error list */ | |
72 qf_list_T qf_lists[LISTCOUNT]; | |
73 }; | |
74 | |
75 static qf_info_T ql_info; /* global quickfix list */ | |
7 | 76 |
230 | 77 #define FMT_PATTERNS 10 /* maximum number of % recognized */ |
7 | 78 |
79 /* | |
80 * Structure used to hold the info of one part of 'errorformat' | |
81 */ | |
789 | 82 typedef struct efm_S efm_T; |
83 struct efm_S | |
7 | 84 { |
85 regprog_T *prog; /* pre-formatted part of 'errorformat' */ | |
789 | 86 efm_T *next; /* pointer to next (NULL if last) */ |
7 | 87 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */ |
88 char_u prefix; /* prefix of this format line: */ | |
89 /* 'D' enter directory */ | |
90 /* 'X' leave directory */ | |
91 /* 'A' start of multi-line message */ | |
92 /* 'E' error message */ | |
93 /* 'W' warning message */ | |
94 /* 'I' informational message */ | |
95 /* 'C' continuation line */ | |
96 /* 'Z' end of multi-line message */ | |
97 /* 'G' general, unspecific message */ | |
98 /* 'P' push file (partial) message */ | |
99 /* 'Q' pop/quit file (partial) message */ | |
100 /* 'O' overread (partial) message */ | |
101 char_u flags; /* additional flags given in prefix */ | |
102 /* '-' do not include this line */ | |
625 | 103 /* '+' include whole line in message */ |
789 | 104 int conthere; /* %> used */ |
7 | 105 }; |
106 | |
644 | 107 static int qf_init_ext __ARGS((qf_info_T *qi, char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast)); |
108 static void qf_new_list __ARGS((qf_info_T *qi)); | |
1571 | 109 static void ll_free_all __ARGS((qf_info_T **pqi)); |
1065 | 110 static int qf_add_entry __ARGS((qf_info_T *qi, qfline_T **prevp, char_u *dir, char_u *fname, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid)); |
1571 | 111 static qf_info_T *ll_new_list __ARGS((void)); |
644 | 112 static void qf_msg __ARGS((qf_info_T *qi)); |
113 static void qf_free __ARGS((qf_info_T *qi, int idx)); | |
7 | 114 static char_u *qf_types __ARGS((int, int)); |
115 static int qf_get_fnum __ARGS((char_u *, char_u *)); | |
116 static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); | |
117 static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); | |
118 static char_u *qf_guess_filepath __ARGS((char_u *)); | |
119 static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); | |
120 static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); | |
121 #ifdef FEAT_WINDOWS | |
644 | 122 static int qf_win_pos_update __ARGS((qf_info_T *qi, int old_qf_index)); |
859 | 123 static int is_qf_win __ARGS((win_T *win, qf_info_T *qi)); |
644 | 124 static win_T *qf_find_win __ARGS((qf_info_T *qi)); |
125 static buf_T *qf_find_buf __ARGS((qf_info_T *qi)); | |
126 static void qf_update_buffer __ARGS((qf_info_T *qi)); | |
127 static void qf_fill_buffer __ARGS((qf_info_T *qi)); | |
7 | 128 #endif |
129 static char_u *get_mef_name __ARGS((void)); | |
42 | 130 static buf_T *load_dummy_buffer __ARGS((char_u *fname)); |
131 static void wipe_dummy_buffer __ARGS((buf_T *buf)); | |
132 static void unload_dummy_buffer __ARGS((buf_T *buf)); | |
665 | 133 static qf_info_T *ll_get_or_alloc_list __ARGS((win_T *)); |
7 | 134 |
644 | 135 /* Quickfix window check helper macro */ |
136 #define IS_QF_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref == NULL) | |
137 /* Location list window check helper macro */ | |
138 #define IS_LL_WINDOW(wp) (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) | |
139 /* | |
140 * Return location list for window 'wp' | |
141 * For location list window, return the referenced location list | |
142 */ | |
143 #define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist) | |
144 | |
7 | 145 /* |
41 | 146 * Read the errorfile "efile" into memory, line by line, building the error |
147 * list. | |
7 | 148 * Return -1 for error, number of errors for success. |
149 */ | |
150 int | |
644 | 151 qf_init(wp, efile, errorformat, newlist) |
152 win_T *wp; | |
7 | 153 char_u *efile; |
154 char_u *errorformat; | |
155 int newlist; /* TRUE: start a new error list */ | |
156 { | |
644 | 157 qf_info_T *qi = &ql_info; |
158 | |
41 | 159 if (efile == NULL) |
160 return FAIL; | |
644 | 161 |
162 if (wp != NULL) | |
665 | 163 { |
164 qi = ll_get_or_alloc_list(wp); | |
165 if (qi == NULL) | |
166 return FAIL; | |
167 } | |
644 | 168 |
169 return qf_init_ext(qi, efile, curbuf, NULL, errorformat, newlist, | |
41 | 170 (linenr_T)0, (linenr_T)0); |
171 } | |
172 | |
173 /* | |
174 * Read the errorfile "efile" into memory, line by line, building the error | |
175 * list. | |
176 * Alternative: when "efile" is null read errors from buffer "buf". | |
177 * Always use 'errorformat' from "buf" if there is a local value. | |
178 * Then lnumfirst and lnumlast specify the range of lines to use. | |
179 * Return -1 for error, number of errors for success. | |
180 */ | |
181 static int | |
644 | 182 qf_init_ext(qi, efile, buf, tv, errorformat, newlist, lnumfirst, lnumlast) |
183 qf_info_T *qi; | |
41 | 184 char_u *efile; |
185 buf_T *buf; | |
446 | 186 typval_T *tv; |
41 | 187 char_u *errorformat; |
188 int newlist; /* TRUE: start a new error list */ | |
189 linenr_T lnumfirst; /* first line number to use */ | |
190 linenr_T lnumlast; /* last line number to use */ | |
191 { | |
7 | 192 char_u *namebuf; |
193 char_u *errmsg; | |
230 | 194 char_u *pattern; |
7 | 195 char_u *fmtstr = NULL; |
196 int col = 0; | |
170 | 197 char_u use_viscol = FALSE; |
7 | 198 int type = 0; |
199 int valid; | |
41 | 200 linenr_T buflnum = lnumfirst; |
7 | 201 long lnum = 0L; |
202 int enr = 0; | |
41 | 203 FILE *fd = NULL; |
230 | 204 qfline_T *qfprev = NULL; /* init to make SASC shut up */ |
7 | 205 char_u *efmp; |
789 | 206 efm_T *fmt_first = NULL; |
207 efm_T *fmt_last = NULL; | |
208 efm_T *fmt_ptr; | |
209 efm_T *fmt_start = NULL; | |
7 | 210 char_u *efm; |
211 char_u *ptr; | |
212 char_u *srcptr; | |
213 int len; | |
214 int i; | |
215 int round; | |
216 int idx = 0; | |
217 int multiline = FALSE; | |
218 int multiignore = FALSE; | |
219 int multiscan = FALSE; | |
220 int retval = -1; /* default: return error flag */ | |
221 char_u *directory = NULL; | |
222 char_u *currfile = NULL; | |
223 char_u *tail = NULL; | |
446 | 224 char_u *p_str = NULL; |
225 listitem_T *p_li = NULL; | |
7 | 226 struct dir_stack_T *file_stack = NULL; |
227 regmatch_T regmatch; | |
228 static struct fmtpattern | |
229 { | |
230 char_u convchar; | |
231 char *pattern; | |
232 } fmt_pat[FMT_PATTERNS] = | |
233 { | |
502 | 234 {'f', ".\\+"}, /* only used when at end */ |
7 | 235 {'n', "\\d\\+"}, |
236 {'l', "\\d\\+"}, | |
237 {'c', "\\d\\+"}, | |
238 {'t', "."}, | |
239 {'m', ".\\+"}, | |
240 {'r', ".*"}, | |
241 {'p', "[- .]*"}, | |
230 | 242 {'v', "\\d\\+"}, |
243 {'s', ".\\+"} | |
7 | 244 }; |
245 | |
246 namebuf = alloc(CMDBUFFSIZE + 1); | |
247 errmsg = alloc(CMDBUFFSIZE + 1); | |
230 | 248 pattern = alloc(CMDBUFFSIZE + 1); |
249 if (namebuf == NULL || errmsg == NULL || pattern == NULL) | |
7 | 250 goto qf_init_end; |
251 | |
41 | 252 if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) |
7 | 253 { |
254 EMSG2(_(e_openerrf), efile); | |
255 goto qf_init_end; | |
256 } | |
257 | |
644 | 258 if (newlist || qi->qf_curlist == qi->qf_listcount) |
7 | 259 /* make place for a new list */ |
644 | 260 qf_new_list(qi); |
261 else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) | |
7 | 262 /* Adding to existing list, find last entry. */ |
644 | 263 for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start; |
7 | 264 qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) |
265 ; | |
266 | |
267 /* | |
268 * Each part of the format string is copied and modified from errorformat to | |
269 * regex prog. Only a few % characters are allowed. | |
270 */ | |
271 /* Use the local value of 'errorformat' if it's set. */ | |
446 | 272 if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL) |
41 | 273 efm = buf->b_p_efm; |
7 | 274 else |
275 efm = errorformat; | |
276 /* | |
277 * Get some space to modify the format string into. | |
278 */ | |
279 i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); | |
280 for (round = FMT_PATTERNS; round > 0; ) | |
281 i += (int)STRLEN(fmt_pat[--round].pattern); | |
282 #ifdef COLON_IN_FILENAME | |
283 i += 12; /* "%f" can become twelve chars longer */ | |
284 #else | |
285 i += 2; /* "%f" can become two chars longer */ | |
286 #endif | |
287 if ((fmtstr = alloc(i)) == NULL) | |
288 goto error2; | |
289 | |
789 | 290 while (efm[0] != NUL) |
7 | 291 { |
292 /* | |
293 * Allocate a new eformat structure and put it at the end of the list | |
294 */ | |
789 | 295 fmt_ptr = (efm_T *)alloc_clear((unsigned)sizeof(efm_T)); |
7 | 296 if (fmt_ptr == NULL) |
297 goto error2; | |
298 if (fmt_first == NULL) /* first one */ | |
299 fmt_first = fmt_ptr; | |
300 else | |
301 fmt_last->next = fmt_ptr; | |
302 fmt_last = fmt_ptr; | |
303 | |
304 /* | |
305 * Isolate one part in the 'errorformat' option | |
306 */ | |
307 for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) | |
308 if (efm[len] == '\\' && efm[len + 1] != NUL) | |
309 ++len; | |
310 | |
311 /* | |
312 * Build regexp pattern from current 'errorformat' option | |
313 */ | |
314 ptr = fmtstr; | |
315 *ptr++ = '^'; | |
789 | 316 round = 0; |
7 | 317 for (efmp = efm; efmp < efm + len; ++efmp) |
318 { | |
319 if (*efmp == '%') | |
320 { | |
321 ++efmp; | |
322 for (idx = 0; idx < FMT_PATTERNS; ++idx) | |
323 if (fmt_pat[idx].convchar == *efmp) | |
324 break; | |
325 if (idx < FMT_PATTERNS) | |
326 { | |
327 if (fmt_ptr->addr[idx]) | |
328 { | |
329 sprintf((char *)errmsg, | |
330 _("E372: Too many %%%c in format string"), *efmp); | |
331 EMSG(errmsg); | |
332 goto error2; | |
333 } | |
334 if ((idx | |
335 && idx < 6 | |
336 && vim_strchr((char_u *)"DXOPQ", | |
337 fmt_ptr->prefix) != NULL) | |
338 || (idx == 6 | |
339 && vim_strchr((char_u *)"OPQ", | |
340 fmt_ptr->prefix) == NULL)) | |
341 { | |
342 sprintf((char *)errmsg, | |
343 _("E373: Unexpected %%%c in format string"), *efmp); | |
344 EMSG(errmsg); | |
345 goto error2; | |
346 } | |
347 fmt_ptr->addr[idx] = (char_u)++round; | |
348 *ptr++ = '\\'; | |
349 *ptr++ = '('; | |
350 #ifdef BACKSLASH_IN_FILENAME | |
351 if (*efmp == 'f') | |
352 { | |
353 /* Also match "c:" in the file name, even when | |
354 * checking for a colon next: "%f:". | |
355 * "\%(\a:\)\=" */ | |
356 STRCPY(ptr, "\\%(\\a:\\)\\="); | |
357 ptr += 10; | |
358 } | |
359 #endif | |
502 | 360 if (*efmp == 'f' && efmp[1] != NUL) |
7 | 361 { |
502 | 362 if (efmp[1] != '\\' && efmp[1] != '%') |
363 { | |
364 /* A file name may contain spaces, but this isn't | |
365 * in "\f". For "%f:%l:%m" there may be a ":" in | |
366 * the file name. Use ".\{-1,}x" instead (x is | |
367 * the next character), the requirement that :999: | |
368 * follows should work. */ | |
369 STRCPY(ptr, ".\\{-1,}"); | |
370 ptr += 7; | |
371 } | |
372 else | |
373 { | |
374 /* File name followed by '\\' or '%': include as | |
375 * many file name chars as possible. */ | |
376 STRCPY(ptr, "\\f\\+"); | |
377 ptr += 4; | |
378 } | |
7 | 379 } |
380 else | |
381 { | |
382 srcptr = (char_u *)fmt_pat[idx].pattern; | |
383 while ((*ptr = *srcptr++) != NUL) | |
384 ++ptr; | |
385 } | |
386 *ptr++ = '\\'; | |
387 *ptr++ = ')'; | |
388 } | |
389 else if (*efmp == '*') | |
390 { | |
391 if (*++efmp == '[' || *efmp == '\\') | |
392 { | |
393 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ | |
394 { | |
395 if (efmp[1] == '^') | |
396 *ptr++ = *++efmp; | |
397 if (efmp < efm + len) | |
398 { | |
399 *ptr++ = *++efmp; /* could be ']' */ | |
400 while (efmp < efm + len | |
401 && (*ptr++ = *++efmp) != ']') | |
402 /* skip */; | |
403 if (efmp == efm + len) | |
404 { | |
405 EMSG(_("E374: Missing ] in format string")); | |
406 goto error2; | |
407 } | |
408 } | |
409 } | |
410 else if (efmp < efm + len) /* %*\D, %*\s etc. */ | |
411 *ptr++ = *++efmp; | |
412 *ptr++ = '\\'; | |
413 *ptr++ = '+'; | |
414 } | |
415 else | |
416 { | |
417 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ | |
418 sprintf((char *)errmsg, | |
419 _("E375: Unsupported %%%c in format string"), *efmp); | |
420 EMSG(errmsg); | |
421 goto error2; | |
422 } | |
423 } | |
424 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) | |
425 *ptr++ = *efmp; /* regexp magic characters */ | |
426 else if (*efmp == '#') | |
427 *ptr++ = '*'; | |
789 | 428 else if (*efmp == '>') |
429 fmt_ptr->conthere = TRUE; | |
7 | 430 else if (efmp == efm + 1) /* analyse prefix */ |
431 { | |
432 if (vim_strchr((char_u *)"+-", *efmp) != NULL) | |
433 fmt_ptr->flags = *efmp++; | |
434 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) | |
435 fmt_ptr->prefix = *efmp; | |
436 else | |
437 { | |
438 sprintf((char *)errmsg, | |
439 _("E376: Invalid %%%c in format string prefix"), *efmp); | |
440 EMSG(errmsg); | |
441 goto error2; | |
442 } | |
443 } | |
444 else | |
445 { | |
446 sprintf((char *)errmsg, | |
447 _("E377: Invalid %%%c in format string"), *efmp); | |
448 EMSG(errmsg); | |
449 goto error2; | |
450 } | |
451 } | |
452 else /* copy normal character */ | |
453 { | |
454 if (*efmp == '\\' && efmp + 1 < efm + len) | |
455 ++efmp; | |
456 else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) | |
457 *ptr++ = '\\'; /* escape regexp atoms */ | |
458 if (*efmp) | |
459 *ptr++ = *efmp; | |
460 } | |
461 } | |
462 *ptr++ = '$'; | |
463 *ptr = NUL; | |
464 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) | |
465 goto error2; | |
466 /* | |
467 * Advance to next part | |
468 */ | |
469 efm = skip_to_option_part(efm + len); /* skip comma and spaces */ | |
470 } | |
471 if (fmt_first == NULL) /* nothing found */ | |
472 { | |
473 EMSG(_("E378: 'errorformat' contains no pattern")); | |
474 goto error2; | |
475 } | |
476 | |
477 /* | |
478 * got_int is reset here, because it was probably set when killing the | |
479 * ":make" command, but we still want to read the errorfile then. | |
480 */ | |
481 got_int = FALSE; | |
482 | |
483 /* Always ignore case when looking for a matching error. */ | |
484 regmatch.rm_ic = TRUE; | |
485 | |
446 | 486 if (tv != NULL) |
487 { | |
488 if (tv->v_type == VAR_STRING) | |
489 p_str = tv->vval.v_string; | |
490 else if (tv->v_type == VAR_LIST) | |
491 p_li = tv->vval.v_list->lv_first; | |
492 } | |
493 | |
7 | 494 /* |
495 * Read the lines in the error file one by one. | |
496 * Try to recognize one of the error formats in each line. | |
497 */ | |
41 | 498 while (!got_int) |
7 | 499 { |
41 | 500 /* Get the next line. */ |
501 if (fd == NULL) | |
502 { | |
446 | 503 if (tv != NULL) |
504 { | |
505 if (tv->v_type == VAR_STRING) | |
506 { | |
507 /* Get the next line from the supplied string */ | |
508 char_u *p; | |
509 | |
510 if (!*p_str) /* Reached the end of the string */ | |
511 break; | |
512 | |
513 p = vim_strchr(p_str, '\n'); | |
514 if (p) | |
835 | 515 len = (int)(p - p_str + 1); |
446 | 516 else |
835 | 517 len = (int)STRLEN(p_str); |
446 | 518 |
519 if (len > CMDBUFFSIZE - 2) | |
520 vim_strncpy(IObuff, p_str, CMDBUFFSIZE - 2); | |
521 else | |
522 vim_strncpy(IObuff, p_str, len); | |
523 | |
524 p_str += len; | |
525 } | |
526 else if (tv->v_type == VAR_LIST) | |
527 { | |
528 /* Get the next line from the supplied list */ | |
529 while (p_li && p_li->li_tv.v_type != VAR_STRING) | |
530 p_li = p_li->li_next; /* Skip non-string items */ | |
531 | |
532 if (!p_li) /* End of the list */ | |
533 break; | |
534 | |
835 | 535 len = (int)STRLEN(p_li->li_tv.vval.v_string); |
446 | 536 if (len > CMDBUFFSIZE - 2) |
537 len = CMDBUFFSIZE - 2; | |
538 | |
539 vim_strncpy(IObuff, p_li->li_tv.vval.v_string, len); | |
540 | |
541 p_li = p_li->li_next; /* next item */ | |
542 } | |
543 } | |
544 else | |
545 { | |
546 /* Get the next line from the supplied buffer */ | |
547 if (buflnum > lnumlast) | |
548 break; | |
549 vim_strncpy(IObuff, ml_get_buf(buf, buflnum++, FALSE), | |
550 CMDBUFFSIZE - 2); | |
551 } | |
41 | 552 } |
553 else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) | |
554 break; | |
555 | |
7 | 556 IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ |
557 if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) | |
558 *efmp = NUL; | |
559 #ifdef USE_CRNL | |
560 if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) | |
561 *efmp = NUL; | |
562 #endif | |
563 | |
789 | 564 /* If there was no %> item start at the first pattern */ |
565 if (fmt_start == NULL) | |
566 fmt_ptr = fmt_first; | |
567 else | |
568 { | |
569 fmt_ptr = fmt_start; | |
570 fmt_start = NULL; | |
571 } | |
572 | |
7 | 573 /* |
574 * Try to match each part of 'errorformat' until we find a complete | |
575 * match or no match. | |
576 */ | |
577 valid = TRUE; | |
578 restofline: | |
789 | 579 for ( ; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) |
7 | 580 { |
581 idx = fmt_ptr->prefix; | |
582 if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) | |
583 continue; | |
584 namebuf[0] = NUL; | |
230 | 585 pattern[0] = NUL; |
7 | 586 if (!multiscan) |
587 errmsg[0] = NUL; | |
588 lnum = 0; | |
589 col = 0; | |
170 | 590 use_viscol = FALSE; |
7 | 591 enr = -1; |
592 type = 0; | |
593 tail = NULL; | |
594 | |
595 regmatch.regprog = fmt_ptr->prog; | |
596 if (vim_regexec(®match, IObuff, (colnr_T)0)) | |
597 { | |
598 if ((idx == 'C' || idx == 'Z') && !multiline) | |
599 continue; | |
600 if (vim_strchr((char_u *)"EWI", idx) != NULL) | |
601 type = idx; | |
602 else | |
603 type = 0; | |
604 /* | |
895 | 605 * Extract error message data from matched line. |
606 * We check for an actual submatch, because "\[" and "\]" in | |
607 * the 'errorformat' may cause the wrong submatch to be used. | |
7 | 608 */ |
609 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */ | |
610 { | |
895 | 611 int c; |
612 | |
613 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) | |
614 continue; | |
277 | 615 |
616 /* Expand ~/file and $HOME/file to full path. */ | |
895 | 617 c = *regmatch.endp[i]; |
277 | 618 *regmatch.endp[i] = NUL; |
619 expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE); | |
620 *regmatch.endp[i] = c; | |
621 | |
7 | 622 if (vim_strchr((char_u *)"OPQ", idx) != NULL |
277 | 623 && mch_getperm(namebuf) == -1) |
7 | 624 continue; |
625 } | |
626 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */ | |
895 | 627 { |
628 if (regmatch.startp[i] == NULL) | |
629 continue; | |
7 | 630 enr = (int)atol((char *)regmatch.startp[i]); |
895 | 631 } |
7 | 632 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */ |
895 | 633 { |
634 if (regmatch.startp[i] == NULL) | |
635 continue; | |
7 | 636 lnum = atol((char *)regmatch.startp[i]); |
895 | 637 } |
7 | 638 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */ |
895 | 639 { |
640 if (regmatch.startp[i] == NULL) | |
641 continue; | |
7 | 642 col = (int)atol((char *)regmatch.startp[i]); |
895 | 643 } |
7 | 644 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */ |
895 | 645 { |
646 if (regmatch.startp[i] == NULL) | |
647 continue; | |
7 | 648 type = *regmatch.startp[i]; |
895 | 649 } |
625 | 650 if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ |
7 | 651 STRCPY(errmsg, IObuff); |
652 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ | |
653 { | |
895 | 654 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) |
655 continue; | |
7 | 656 len = (int)(regmatch.endp[i] - regmatch.startp[i]); |
418 | 657 vim_strncpy(errmsg, regmatch.startp[i], len); |
7 | 658 } |
659 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */ | |
895 | 660 { |
661 if (regmatch.startp[i] == NULL) | |
662 continue; | |
7 | 663 tail = regmatch.startp[i]; |
895 | 664 } |
7 | 665 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */ |
666 { | |
895 | 667 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) |
668 continue; | |
7 | 669 col = (int)(regmatch.endp[i] - regmatch.startp[i] + 1); |
670 if (*((char_u *)regmatch.startp[i]) != TAB) | |
170 | 671 use_viscol = TRUE; |
7 | 672 } |
673 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */ | |
674 { | |
895 | 675 if (regmatch.startp[i] == NULL) |
676 continue; | |
7 | 677 col = (int)atol((char *)regmatch.startp[i]); |
170 | 678 use_viscol = TRUE; |
7 | 679 } |
230 | 680 if ((i = (int)fmt_ptr->addr[9]) > 0) /* %s */ |
681 { | |
895 | 682 if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) |
683 continue; | |
230 | 684 len = (int)(regmatch.endp[i] - regmatch.startp[i]); |
685 if (len > CMDBUFFSIZE - 5) | |
686 len = CMDBUFFSIZE - 5; | |
687 STRCPY(pattern, "^\\V"); | |
688 STRNCAT(pattern, regmatch.startp[i], len); | |
689 pattern[len + 3] = '\\'; | |
690 pattern[len + 4] = '$'; | |
691 pattern[len + 5] = NUL; | |
692 } | |
7 | 693 break; |
694 } | |
695 } | |
696 multiscan = FALSE; | |
789 | 697 |
625 | 698 if (fmt_ptr == NULL || idx == 'D' || idx == 'X') |
7 | 699 { |
625 | 700 if (fmt_ptr != NULL) |
7 | 701 { |
702 if (idx == 'D') /* enter directory */ | |
703 { | |
704 if (*namebuf == NUL) | |
705 { | |
706 EMSG(_("E379: Missing or empty directory name")); | |
707 goto error2; | |
708 } | |
709 if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) | |
710 goto error2; | |
711 } | |
712 else if (idx == 'X') /* leave directory */ | |
713 directory = qf_pop_dir(&dir_stack); | |
714 } | |
715 namebuf[0] = NUL; /* no match found, remove file name */ | |
716 lnum = 0; /* don't jump to this line */ | |
717 valid = FALSE; | |
718 STRCPY(errmsg, IObuff); /* copy whole line to error message */ | |
625 | 719 if (fmt_ptr == NULL) |
7 | 720 multiline = multiignore = FALSE; |
721 } | |
625 | 722 else if (fmt_ptr != NULL) |
7 | 723 { |
789 | 724 /* honor %> item */ |
725 if (fmt_ptr->conthere) | |
726 fmt_start = fmt_ptr; | |
727 | |
7 | 728 if (vim_strchr((char_u *)"AEWI", idx) != NULL) |
729 multiline = TRUE; /* start of a multi-line message */ | |
730 else if (vim_strchr((char_u *)"CZ", idx) != NULL) | |
731 { /* continuation of multi-line msg */ | |
732 if (qfprev == NULL) | |
733 goto error2; | |
734 if (*errmsg && !multiignore) | |
735 { | |
736 len = (int)STRLEN(qfprev->qf_text); | |
737 if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) | |
738 == NULL) | |
739 goto error2; | |
740 STRCPY(ptr, qfprev->qf_text); | |
741 vim_free(qfprev->qf_text); | |
742 qfprev->qf_text = ptr; | |
743 *(ptr += len) = '\n'; | |
744 STRCPY(++ptr, errmsg); | |
745 } | |
746 if (qfprev->qf_nr == -1) | |
747 qfprev->qf_nr = enr; | |
748 if (vim_isprintc(type) && !qfprev->qf_type) | |
749 qfprev->qf_type = type; /* only printable chars allowed */ | |
750 if (!qfprev->qf_lnum) | |
751 qfprev->qf_lnum = lnum; | |
752 if (!qfprev->qf_col) | |
753 qfprev->qf_col = col; | |
170 | 754 qfprev->qf_viscol = use_viscol; |
7 | 755 if (!qfprev->qf_fnum) |
756 qfprev->qf_fnum = qf_get_fnum(directory, | |
757 *namebuf || directory ? namebuf | |
758 : currfile && valid ? currfile : 0); | |
759 if (idx == 'Z') | |
760 multiline = multiignore = FALSE; | |
761 line_breakcheck(); | |
762 continue; | |
763 } | |
764 else if (vim_strchr((char_u *)"OPQ", idx) != NULL) | |
765 { | |
766 /* global file names */ | |
767 valid = FALSE; | |
768 if (*namebuf == NUL || mch_getperm(namebuf) >= 0) | |
769 { | |
770 if (*namebuf && idx == 'P') | |
771 currfile = qf_push_dir(namebuf, &file_stack); | |
772 else if (idx == 'Q') | |
773 currfile = qf_pop_dir(&file_stack); | |
774 *namebuf = NUL; | |
775 if (tail && *tail) | |
776 { | |
1668 | 777 STRMOVE(IObuff, skipwhite(tail)); |
7 | 778 multiscan = TRUE; |
779 goto restofline; | |
780 } | |
781 } | |
782 } | |
783 if (fmt_ptr->flags == '-') /* generally exclude this line */ | |
784 { | |
785 if (multiline) | |
786 multiignore = TRUE; /* also exclude continuation lines */ | |
787 continue; | |
788 } | |
789 } | |
790 | |
644 | 791 if (qf_add_entry(qi, &qfprev, |
7 | 792 directory, |
129 | 793 (*namebuf || directory) |
7 | 794 ? namebuf |
129 | 795 : ((currfile && valid) ? currfile : (char_u *)NULL), |
1065 | 796 0, |
7 | 797 errmsg, |
798 lnum, | |
799 col, | |
170 | 800 use_viscol, |
230 | 801 pattern, |
7 | 802 enr, |
803 type, | |
804 valid) == FAIL) | |
805 goto error2; | |
806 line_breakcheck(); | |
807 } | |
41 | 808 if (fd == NULL || !ferror(fd)) |
7 | 809 { |
644 | 810 if (qi->qf_lists[qi->qf_curlist].qf_index == 0) |
7 | 811 { |
644 | 812 /* no valid entry found */ |
813 qi->qf_lists[qi->qf_curlist].qf_ptr = | |
814 qi->qf_lists[qi->qf_curlist].qf_start; | |
815 qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
816 qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; | |
7 | 817 } |
818 else | |
819 { | |
644 | 820 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; |
821 if (qi->qf_lists[qi->qf_curlist].qf_ptr == NULL) | |
822 qi->qf_lists[qi->qf_curlist].qf_ptr = | |
823 qi->qf_lists[qi->qf_curlist].qf_start; | |
7 | 824 } |
644 | 825 /* return number of matches */ |
826 retval = qi->qf_lists[qi->qf_curlist].qf_count; | |
7 | 827 goto qf_init_ok; |
828 } | |
829 EMSG(_(e_readerrf)); | |
830 error2: | |
644 | 831 qf_free(qi, qi->qf_curlist); |
832 qi->qf_listcount--; | |
833 if (qi->qf_curlist > 0) | |
834 --qi->qf_curlist; | |
7 | 835 qf_init_ok: |
41 | 836 if (fd != NULL) |
837 fclose(fd); | |
7 | 838 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) |
839 { | |
840 fmt_first = fmt_ptr->next; | |
841 vim_free(fmt_ptr->prog); | |
842 vim_free(fmt_ptr); | |
843 } | |
844 qf_clean_dir_stack(&dir_stack); | |
845 qf_clean_dir_stack(&file_stack); | |
846 qf_init_end: | |
847 vim_free(namebuf); | |
848 vim_free(errmsg); | |
230 | 849 vim_free(pattern); |
7 | 850 vim_free(fmtstr); |
851 | |
852 #ifdef FEAT_WINDOWS | |
644 | 853 qf_update_buffer(qi); |
7 | 854 #endif |
855 | |
856 return retval; | |
857 } | |
858 | |
859 /* | |
860 * Prepare for adding a new quickfix list. | |
861 */ | |
862 static void | |
644 | 863 qf_new_list(qi) |
864 qf_info_T *qi; | |
7 | 865 { |
866 int i; | |
867 | |
868 /* | |
869 * If the current entry is not the last entry, delete entries below | |
870 * the current entry. This makes it possible to browse in a tree-like | |
871 * way with ":grep'. | |
872 */ | |
644 | 873 while (qi->qf_listcount > qi->qf_curlist + 1) |
874 qf_free(qi, --qi->qf_listcount); | |
7 | 875 |
876 /* | |
877 * When the stack is full, remove to oldest entry | |
878 * Otherwise, add a new entry. | |
879 */ | |
644 | 880 if (qi->qf_listcount == LISTCOUNT) |
7 | 881 { |
644 | 882 qf_free(qi, 0); |
7 | 883 for (i = 1; i < LISTCOUNT; ++i) |
644 | 884 qi->qf_lists[i - 1] = qi->qf_lists[i]; |
885 qi->qf_curlist = LISTCOUNT - 1; | |
7 | 886 } |
887 else | |
644 | 888 qi->qf_curlist = qi->qf_listcount++; |
889 qi->qf_lists[qi->qf_curlist].qf_index = 0; | |
890 qi->qf_lists[qi->qf_curlist].qf_count = 0; | |
7 | 891 } |
892 | |
644 | 893 /* |
894 * Free a location list | |
895 */ | |
896 static void | |
897 ll_free_all(pqi) | |
898 qf_info_T **pqi; | |
359 | 899 { |
900 int i; | |
644 | 901 qf_info_T *qi; |
902 | |
903 qi = *pqi; | |
904 if (qi == NULL) | |
905 return; | |
906 *pqi = NULL; /* Remove reference to this list */ | |
907 | |
908 qi->qf_refcount--; | |
909 if (qi->qf_refcount < 1) | |
910 { | |
911 /* No references to this location list */ | |
912 for (i = 0; i < qi->qf_listcount; ++i) | |
913 qf_free(qi, i); | |
914 vim_free(qi); | |
915 } | |
359 | 916 } |
644 | 917 |
918 void | |
919 qf_free_all(wp) | |
920 win_T *wp; | |
921 { | |
922 int i; | |
923 qf_info_T *qi = &ql_info; | |
924 | |
925 if (wp != NULL) | |
926 { | |
927 /* location list */ | |
928 ll_free_all(&wp->w_llist); | |
929 ll_free_all(&wp->w_llist_ref); | |
930 } | |
931 else | |
932 /* quickfix list */ | |
933 for (i = 0; i < qi->qf_listcount; ++i) | |
934 qf_free(qi, i); | |
935 } | |
359 | 936 |
7 | 937 /* |
938 * Add an entry to the end of the list of errors. | |
939 * Returns OK or FAIL. | |
940 */ | |
941 static int | |
1065 | 942 qf_add_entry(qi, prevp, dir, fname, bufnum, mesg, lnum, col, vis_col, pattern, |
943 nr, type, valid) | |
644 | 944 qf_info_T *qi; /* quickfix list */ |
230 | 945 qfline_T **prevp; /* pointer to previously added entry or NULL */ |
7 | 946 char_u *dir; /* optional directory name */ |
947 char_u *fname; /* file name or NULL */ | |
1065 | 948 int bufnum; /* buffer number or zero */ |
7 | 949 char_u *mesg; /* message */ |
950 long lnum; /* line number */ | |
951 int col; /* column */ | |
170 | 952 int vis_col; /* using visual column */ |
230 | 953 char_u *pattern; /* search pattern */ |
7 | 954 int nr; /* error number */ |
955 int type; /* type character */ | |
956 int valid; /* valid entry */ | |
957 { | |
230 | 958 qfline_T *qfp; |
7 | 959 |
230 | 960 if ((qfp = (qfline_T *)alloc((unsigned)sizeof(qfline_T))) == NULL) |
7 | 961 return FAIL; |
1065 | 962 if (bufnum != 0) |
963 qfp->qf_fnum = bufnum; | |
964 else | |
965 qfp->qf_fnum = qf_get_fnum(dir, fname); | |
7 | 966 if ((qfp->qf_text = vim_strsave(mesg)) == NULL) |
967 { | |
968 vim_free(qfp); | |
969 return FAIL; | |
970 } | |
971 qfp->qf_lnum = lnum; | |
972 qfp->qf_col = col; | |
170 | 973 qfp->qf_viscol = vis_col; |
230 | 974 if (pattern == NULL || *pattern == NUL) |
975 qfp->qf_pattern = NULL; | |
976 else if ((qfp->qf_pattern = vim_strsave(pattern)) == NULL) | |
977 { | |
978 vim_free(qfp->qf_text); | |
979 vim_free(qfp); | |
980 return FAIL; | |
981 } | |
7 | 982 qfp->qf_nr = nr; |
983 if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ | |
984 type = 0; | |
985 qfp->qf_type = type; | |
986 qfp->qf_valid = valid; | |
987 | |
644 | 988 if (qi->qf_lists[qi->qf_curlist].qf_count == 0) |
989 /* first element in the list */ | |
7 | 990 { |
644 | 991 qi->qf_lists[qi->qf_curlist].qf_start = qfp; |
7 | 992 qfp->qf_prev = qfp; /* first element points to itself */ |
993 } | |
994 else | |
995 { | |
996 qfp->qf_prev = *prevp; | |
997 (*prevp)->qf_next = qfp; | |
998 } | |
999 qfp->qf_next = qfp; /* last element points to itself */ | |
1000 qfp->qf_cleared = FALSE; | |
1001 *prevp = qfp; | |
644 | 1002 ++qi->qf_lists[qi->qf_curlist].qf_count; |
1003 if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) | |
1004 /* first valid entry */ | |
7 | 1005 { |
644 | 1006 qi->qf_lists[qi->qf_curlist].qf_index = |
1007 qi->qf_lists[qi->qf_curlist].qf_count; | |
1008 qi->qf_lists[qi->qf_curlist].qf_ptr = qfp; | |
7 | 1009 } |
1010 | |
1011 return OK; | |
1012 } | |
1013 | |
1014 /* | |
659 | 1015 * Allocate a new location list |
644 | 1016 */ |
659 | 1017 static qf_info_T * |
1018 ll_new_list() | |
644 | 1019 { |
659 | 1020 qf_info_T *qi; |
1021 | |
1022 qi = (qf_info_T *)alloc((unsigned)sizeof(qf_info_T)); | |
1023 if (qi != NULL) | |
1024 { | |
1025 vim_memset(qi, 0, (size_t)(sizeof(qf_info_T))); | |
1026 qi->qf_refcount++; | |
1027 } | |
1028 | |
1029 return qi; | |
644 | 1030 } |
1031 | |
1032 /* | |
1033 * Return the location list for window 'wp'. | |
1034 * If not present, allocate a location list | |
1035 */ | |
1036 static qf_info_T * | |
1037 ll_get_or_alloc_list(wp) | |
1038 win_T *wp; | |
1039 { | |
1040 if (IS_LL_WINDOW(wp)) | |
1041 /* For a location list window, use the referenced location list */ | |
1042 return wp->w_llist_ref; | |
1043 | |
1044 /* | |
1045 * For a non-location list window, w_llist_ref should not point to a | |
1046 * location list. | |
1047 */ | |
1048 ll_free_all(&wp->w_llist_ref); | |
1049 | |
1050 if (wp->w_llist == NULL) | |
659 | 1051 wp->w_llist = ll_new_list(); /* new location list */ |
644 | 1052 return wp->w_llist; |
1053 } | |
1054 | |
1055 /* | |
1056 * Copy the location list from window "from" to window "to". | |
1057 */ | |
1058 void | |
1059 copy_loclist(from, to) | |
1060 win_T *from; | |
1061 win_T *to; | |
1062 { | |
1063 qf_info_T *qi; | |
1064 int idx; | |
1065 int i; | |
1066 | |
1067 /* | |
1068 * When copying from a location list window, copy the referenced | |
1069 * location list. For other windows, copy the location list for | |
1070 * that window. | |
1071 */ | |
1072 if (IS_LL_WINDOW(from)) | |
1073 qi = from->w_llist_ref; | |
1074 else | |
1075 qi = from->w_llist; | |
1076 | |
1077 if (qi == NULL) /* no location list to copy */ | |
1078 return; | |
1079 | |
659 | 1080 /* allocate a new location list */ |
1081 if ((to->w_llist = ll_new_list()) == NULL) | |
644 | 1082 return; |
1083 | |
1084 to->w_llist->qf_listcount = qi->qf_listcount; | |
1085 | |
1086 /* Copy the location lists one at a time */ | |
1087 for (idx = 0; idx < qi->qf_listcount; idx++) | |
1088 { | |
1089 qf_list_T *from_qfl; | |
1090 qf_list_T *to_qfl; | |
1091 | |
1092 to->w_llist->qf_curlist = idx; | |
1093 | |
1094 from_qfl = &qi->qf_lists[idx]; | |
1095 to_qfl = &to->w_llist->qf_lists[idx]; | |
1096 | |
1097 /* Some of the fields are populated by qf_add_entry() */ | |
1098 to_qfl->qf_nonevalid = from_qfl->qf_nonevalid; | |
1099 to_qfl->qf_count = 0; | |
1100 to_qfl->qf_index = 0; | |
1101 to_qfl->qf_start = NULL; | |
1102 to_qfl->qf_ptr = NULL; | |
1103 | |
1104 if (from_qfl->qf_count) | |
1105 { | |
1106 qfline_T *from_qfp; | |
1107 qfline_T *prevp = NULL; | |
1108 | |
1109 /* copy all the location entries in this list */ | |
1110 for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count; | |
1111 ++i, from_qfp = from_qfp->qf_next) | |
1112 { | |
1113 if (qf_add_entry(to->w_llist, &prevp, | |
1114 NULL, | |
1115 NULL, | |
1065 | 1116 0, |
644 | 1117 from_qfp->qf_text, |
1118 from_qfp->qf_lnum, | |
1119 from_qfp->qf_col, | |
1120 from_qfp->qf_viscol, | |
1121 from_qfp->qf_pattern, | |
1122 from_qfp->qf_nr, | |
1123 0, | |
1124 from_qfp->qf_valid) == FAIL) | |
1125 { | |
1126 qf_free_all(to); | |
1127 return; | |
1128 } | |
1129 /* | |
1130 * qf_add_entry() will not set the qf_num field, as the | |
1131 * directory and file names are not supplied. So the qf_fnum | |
1132 * field is copied here. | |
1133 */ | |
1134 prevp->qf_fnum = from_qfp->qf_fnum; /* file number */ | |
1135 prevp->qf_type = from_qfp->qf_type; /* error type */ | |
1136 if (from_qfl->qf_ptr == from_qfp) | |
1137 to_qfl->qf_ptr = prevp; /* current location */ | |
1138 } | |
1139 } | |
1140 | |
1141 to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */ | |
1142 | |
1143 /* When no valid entries are present in the list, qf_ptr points to | |
1144 * the first item in the list */ | |
1145 if (to_qfl->qf_nonevalid == TRUE) | |
1146 to_qfl->qf_ptr = to_qfl->qf_start; | |
1147 } | |
1148 | |
1149 to->w_llist->qf_curlist = qi->qf_curlist; /* current list */ | |
1150 } | |
1151 | |
1152 /* | |
7 | 1153 * get buffer number for file "dir.name" |
1154 */ | |
1155 static int | |
1156 qf_get_fnum(directory, fname) | |
1157 char_u *directory; | |
1158 char_u *fname; | |
1159 { | |
1160 if (fname == NULL || *fname == NUL) /* no file name */ | |
1161 return 0; | |
1162 { | |
1163 #ifdef RISCOS | |
1164 /* Name is reported as `main.c', but file is `c.main' */ | |
1165 return ro_buflist_add(fname); | |
1166 #else | |
1167 char_u *ptr; | |
1168 int fnum; | |
1169 | |
1170 # ifdef VMS | |
1171 vms_remove_version(fname); | |
1172 # endif | |
1173 # ifdef BACKSLASH_IN_FILENAME | |
1174 if (directory != NULL) | |
1175 slash_adjust(directory); | |
1176 slash_adjust(fname); | |
1177 # endif | |
1178 if (directory != NULL && !vim_isAbsName(fname) | |
1179 && (ptr = concat_fnames(directory, fname, TRUE)) != NULL) | |
1180 { | |
1181 /* | |
1182 * Here we check if the file really exists. | |
1183 * This should normally be true, but if make works without | |
1184 * "leaving directory"-messages we might have missed a | |
1185 * directory change. | |
1186 */ | |
1187 if (mch_getperm(ptr) < 0) | |
1188 { | |
1189 vim_free(ptr); | |
1190 directory = qf_guess_filepath(fname); | |
1191 if (directory) | |
1192 ptr = concat_fnames(directory, fname, TRUE); | |
1193 else | |
1194 ptr = vim_strsave(fname); | |
1195 } | |
1196 /* Use concatenated directory name and file name */ | |
1197 fnum = buflist_add(ptr, 0); | |
1198 vim_free(ptr); | |
1199 return fnum; | |
1200 } | |
1201 return buflist_add(fname, 0); | |
1202 #endif | |
1203 } | |
1204 } | |
1205 | |
1206 /* | |
1207 * push dirbuf onto the directory stack and return pointer to actual dir or | |
1208 * NULL on error | |
1209 */ | |
1210 static char_u * | |
1211 qf_push_dir(dirbuf, stackptr) | |
1212 char_u *dirbuf; | |
1213 struct dir_stack_T **stackptr; | |
1214 { | |
1215 struct dir_stack_T *ds_new; | |
1216 struct dir_stack_T *ds_ptr; | |
1217 | |
1218 /* allocate new stack element and hook it in */ | |
1219 ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T)); | |
1220 if (ds_new == NULL) | |
1221 return NULL; | |
1222 | |
1223 ds_new->next = *stackptr; | |
1224 *stackptr = ds_new; | |
1225 | |
1226 /* store directory on the stack */ | |
1227 if (vim_isAbsName(dirbuf) | |
1228 || (*stackptr)->next == NULL | |
1229 || (*stackptr && dir_stack != *stackptr)) | |
1230 (*stackptr)->dirname = vim_strsave(dirbuf); | |
1231 else | |
1232 { | |
1233 /* Okay we don't have an absolute path. | |
1234 * dirbuf must be a subdir of one of the directories on the stack. | |
1235 * Let's search... | |
1236 */ | |
1237 ds_new = (*stackptr)->next; | |
1238 (*stackptr)->dirname = NULL; | |
1239 while (ds_new) | |
1240 { | |
1241 vim_free((*stackptr)->dirname); | |
1242 (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, | |
1243 TRUE); | |
1244 if (mch_isdir((*stackptr)->dirname) == TRUE) | |
1245 break; | |
1246 | |
1247 ds_new = ds_new->next; | |
1248 } | |
1249 | |
1250 /* clean up all dirs we already left */ | |
1251 while ((*stackptr)->next != ds_new) | |
1252 { | |
1253 ds_ptr = (*stackptr)->next; | |
1254 (*stackptr)->next = (*stackptr)->next->next; | |
1255 vim_free(ds_ptr->dirname); | |
1256 vim_free(ds_ptr); | |
1257 } | |
1258 | |
1259 /* Nothing found -> it must be on top level */ | |
1260 if (ds_new == NULL) | |
1261 { | |
1262 vim_free((*stackptr)->dirname); | |
1263 (*stackptr)->dirname = vim_strsave(dirbuf); | |
1264 } | |
1265 } | |
1266 | |
1267 if ((*stackptr)->dirname != NULL) | |
1268 return (*stackptr)->dirname; | |
1269 else | |
1270 { | |
1271 ds_ptr = *stackptr; | |
1272 *stackptr = (*stackptr)->next; | |
1273 vim_free(ds_ptr); | |
1274 return NULL; | |
1275 } | |
1276 } | |
1277 | |
1278 | |
1279 /* | |
1280 * pop dirbuf from the directory stack and return previous directory or NULL if | |
1281 * stack is empty | |
1282 */ | |
1283 static char_u * | |
1284 qf_pop_dir(stackptr) | |
1285 struct dir_stack_T **stackptr; | |
1286 { | |
1287 struct dir_stack_T *ds_ptr; | |
1288 | |
1289 /* TODO: Should we check if dirbuf is the directory on top of the stack? | |
1290 * What to do if it isn't? */ | |
1291 | |
1292 /* pop top element and free it */ | |
1293 if (*stackptr != NULL) | |
1294 { | |
1295 ds_ptr = *stackptr; | |
1296 *stackptr = (*stackptr)->next; | |
1297 vim_free(ds_ptr->dirname); | |
1298 vim_free(ds_ptr); | |
1299 } | |
1300 | |
1301 /* return NEW top element as current dir or NULL if stack is empty*/ | |
1302 return *stackptr ? (*stackptr)->dirname : NULL; | |
1303 } | |
1304 | |
1305 /* | |
1306 * clean up directory stack | |
1307 */ | |
1308 static void | |
1309 qf_clean_dir_stack(stackptr) | |
1310 struct dir_stack_T **stackptr; | |
1311 { | |
1312 struct dir_stack_T *ds_ptr; | |
1313 | |
1314 while ((ds_ptr = *stackptr) != NULL) | |
1315 { | |
1316 *stackptr = (*stackptr)->next; | |
1317 vim_free(ds_ptr->dirname); | |
1318 vim_free(ds_ptr); | |
1319 } | |
1320 } | |
1321 | |
1322 /* | |
1323 * Check in which directory of the directory stack the given file can be | |
1324 * found. | |
1325 * Returns a pointer to the directory name or NULL if not found | |
1326 * Cleans up intermediate directory entries. | |
1327 * | |
1328 * TODO: How to solve the following problem? | |
1329 * If we have the this directory tree: | |
1330 * ./ | |
1331 * ./aa | |
1332 * ./aa/bb | |
1333 * ./bb | |
1334 * ./bb/x.c | |
1335 * and make says: | |
1336 * making all in aa | |
1337 * making all in bb | |
1338 * x.c:9: Error | |
1339 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. | |
1340 * qf_guess_filepath will return NULL. | |
1341 */ | |
1342 static char_u * | |
1343 qf_guess_filepath(filename) | |
1344 char_u *filename; | |
1345 { | |
1346 struct dir_stack_T *ds_ptr; | |
1347 struct dir_stack_T *ds_tmp; | |
1348 char_u *fullname; | |
1349 | |
1350 /* no dirs on the stack - there's nothing we can do */ | |
1351 if (dir_stack == NULL) | |
1352 return NULL; | |
1353 | |
1354 ds_ptr = dir_stack->next; | |
1355 fullname = NULL; | |
1356 while (ds_ptr) | |
1357 { | |
1358 vim_free(fullname); | |
1359 fullname = concat_fnames(ds_ptr->dirname, filename, TRUE); | |
1360 | |
1361 /* If concat_fnames failed, just go on. The worst thing that can happen | |
1362 * is that we delete the entire stack. | |
1363 */ | |
1364 if ((fullname != NULL) && (mch_getperm(fullname) >= 0)) | |
1365 break; | |
1366 | |
1367 ds_ptr = ds_ptr->next; | |
1368 } | |
1369 | |
1370 vim_free(fullname); | |
1371 | |
1372 /* clean up all dirs we already left */ | |
1373 while (dir_stack->next != ds_ptr) | |
1374 { | |
1375 ds_tmp = dir_stack->next; | |
1376 dir_stack->next = dir_stack->next->next; | |
1377 vim_free(ds_tmp->dirname); | |
1378 vim_free(ds_tmp); | |
1379 } | |
1380 | |
1381 return ds_ptr==NULL? NULL: ds_ptr->dirname; | |
1382 | |
1383 } | |
1384 | |
1385 /* | |
1386 * jump to a quickfix line | |
1387 * if dir == FORWARD go "errornr" valid entries forward | |
1388 * if dir == BACKWARD go "errornr" valid entries backward | |
1389 * if dir == FORWARD_FILE go "errornr" valid entries files backward | |
1390 * if dir == BACKWARD_FILE go "errornr" valid entries files backward | |
1391 * else if "errornr" is zero, redisplay the same line | |
1392 * else go to entry "errornr" | |
1393 */ | |
1394 void | |
659 | 1395 qf_jump(qi, dir, errornr, forceit) |
1396 qf_info_T *qi; | |
7 | 1397 int dir; |
1398 int errornr; | |
1399 int forceit; | |
1400 { | |
644 | 1401 qf_info_T *ll_ref; |
230 | 1402 qfline_T *qf_ptr; |
1403 qfline_T *old_qf_ptr; | |
7 | 1404 int qf_index; |
1405 int old_qf_fnum; | |
1406 int old_qf_index; | |
1407 int prev_index; | |
1408 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); | |
1409 char_u *err = e_no_more_items; | |
1410 linenr_T i; | |
1411 buf_T *old_curbuf; | |
1412 linenr_T old_lnum; | |
1413 colnr_T screen_col; | |
1414 colnr_T char_col; | |
1415 char_u *line; | |
1416 #ifdef FEAT_WINDOWS | |
639 | 1417 char_u *old_swb = p_swb; |
1621 | 1418 unsigned old_swb_flags = swb_flags; |
7 | 1419 int opened_window = FALSE; |
1420 win_T *win; | |
1421 win_T *altwin; | |
1822 | 1422 int flags; |
7 | 1423 #endif |
1743 | 1424 win_T *oldwin = curwin; |
7 | 1425 int print_message = TRUE; |
1426 int len; | |
1427 #ifdef FEAT_FOLDING | |
1428 int old_KeyTyped = KeyTyped; /* getting file may reset it */ | |
1429 #endif | |
9 | 1430 int ok = OK; |
644 | 1431 int usable_win; |
1432 | |
659 | 1433 if (qi == NULL) |
1434 qi = &ql_info; | |
644 | 1435 |
1436 if (qi->qf_curlist >= qi->qf_listcount | |
1437 || qi->qf_lists[qi->qf_curlist].qf_count == 0) | |
7 | 1438 { |
1439 EMSG(_(e_quickfix)); | |
1440 return; | |
1441 } | |
1442 | |
644 | 1443 qf_ptr = qi->qf_lists[qi->qf_curlist].qf_ptr; |
7 | 1444 old_qf_ptr = qf_ptr; |
644 | 1445 qf_index = qi->qf_lists[qi->qf_curlist].qf_index; |
7 | 1446 old_qf_index = qf_index; |
1447 if (dir == FORWARD || dir == FORWARD_FILE) /* next valid entry */ | |
1448 { | |
1449 while (errornr--) | |
1450 { | |
1451 old_qf_ptr = qf_ptr; | |
1452 prev_index = qf_index; | |
1453 old_qf_fnum = qf_ptr->qf_fnum; | |
1454 do | |
1455 { | |
644 | 1456 if (qf_index == qi->qf_lists[qi->qf_curlist].qf_count |
7 | 1457 || qf_ptr->qf_next == NULL) |
1458 { | |
1459 qf_ptr = old_qf_ptr; | |
1460 qf_index = prev_index; | |
1461 if (err != NULL) | |
1462 { | |
1463 EMSG(_(err)); | |
1464 goto theend; | |
1465 } | |
1466 errornr = 0; | |
1467 break; | |
1468 } | |
1469 ++qf_index; | |
1470 qf_ptr = qf_ptr->qf_next; | |
644 | 1471 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid |
1472 && !qf_ptr->qf_valid) | |
7 | 1473 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); |
1474 err = NULL; | |
1475 } | |
1476 } | |
1477 else if (dir == BACKWARD || dir == BACKWARD_FILE) /* prev. valid entry */ | |
1478 { | |
1479 while (errornr--) | |
1480 { | |
1481 old_qf_ptr = qf_ptr; | |
1482 prev_index = qf_index; | |
1483 old_qf_fnum = qf_ptr->qf_fnum; | |
1484 do | |
1485 { | |
1486 if (qf_index == 1 || qf_ptr->qf_prev == NULL) | |
1487 { | |
1488 qf_ptr = old_qf_ptr; | |
1489 qf_index = prev_index; | |
1490 if (err != NULL) | |
1491 { | |
1492 EMSG(_(err)); | |
1493 goto theend; | |
1494 } | |
1495 errornr = 0; | |
1496 break; | |
1497 } | |
1498 --qf_index; | |
1499 qf_ptr = qf_ptr->qf_prev; | |
644 | 1500 } while ((!qi->qf_lists[qi->qf_curlist].qf_nonevalid |
1501 && !qf_ptr->qf_valid) | |
7 | 1502 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); |
1503 err = NULL; | |
1504 } | |
1505 } | |
1506 else if (errornr != 0) /* go to specified number */ | |
1507 { | |
1508 while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL) | |
1509 { | |
1510 --qf_index; | |
1511 qf_ptr = qf_ptr->qf_prev; | |
1512 } | |
644 | 1513 while (errornr > qf_index && qf_index < |
1514 qi->qf_lists[qi->qf_curlist].qf_count | |
7 | 1515 && qf_ptr->qf_next != NULL) |
1516 { | |
1517 ++qf_index; | |
1518 qf_ptr = qf_ptr->qf_next; | |
1519 } | |
1520 } | |
1521 | |
1522 #ifdef FEAT_WINDOWS | |
644 | 1523 qi->qf_lists[qi->qf_curlist].qf_index = qf_index; |
1524 if (qf_win_pos_update(qi, old_qf_index)) | |
7 | 1525 /* No need to print the error message if it's visible in the error |
1526 * window */ | |
1527 print_message = FALSE; | |
1528 | |
1529 /* | |
9 | 1530 * For ":helpgrep" find a help window or open one. |
1531 */ | |
682 | 1532 if (qf_ptr->qf_type == 1 && (!curwin->w_buffer->b_help || cmdmod.tab != 0)) |
9 | 1533 { |
1534 win_T *wp; | |
1535 | |
682 | 1536 if (cmdmod.tab != 0) |
1537 wp = NULL; | |
1538 else | |
1539 for (wp = firstwin; wp != NULL; wp = wp->w_next) | |
1540 if (wp->w_buffer != NULL && wp->w_buffer->b_help) | |
1541 break; | |
9 | 1542 if (wp != NULL && wp->w_buffer->b_nwindows > 0) |
1543 win_enter(wp, TRUE); | |
1544 else | |
1545 { | |
1546 /* | |
1547 * Split off help window; put it at far top if no position | |
1548 * specified, the current window is vertically split and narrow. | |
1549 */ | |
1822 | 1550 flags = WSP_HELP; |
9 | 1551 # ifdef FEAT_VERTSPLIT |
1552 if (cmdmod.split == 0 && curwin->w_width != Columns | |
1553 && curwin->w_width < 80) | |
1822 | 1554 flags |= WSP_TOP; |
9 | 1555 # endif |
1822 | 1556 if (qi != &ql_info) |
1557 flags |= WSP_NEWLOC; /* don't copy the location list */ | |
1558 | |
1559 if (win_split(0, flags) == FAIL) | |
9 | 1560 goto theend; |
26 | 1561 opened_window = TRUE; /* close it when fail */ |
9 | 1562 |
1563 if (curwin->w_height < p_hh) | |
1564 win_setheight((int)p_hh); | |
659 | 1565 |
1566 if (qi != &ql_info) /* not a quickfix list */ | |
1567 { | |
1568 /* The new window should use the supplied location list */ | |
1569 curwin->w_llist = qi; | |
1570 qi->qf_refcount++; | |
1571 } | |
9 | 1572 } |
1573 | |
1574 if (!p_im) | |
1575 restart_edit = 0; /* don't want insert mode in help file */ | |
1576 } | |
1577 | |
1578 /* | |
7 | 1579 * If currently in the quickfix window, find another window to show the |
1580 * file in. | |
1581 */ | |
26 | 1582 if (bt_quickfix(curbuf) && !opened_window) |
7 | 1583 { |
1584 /* | |
1585 * If there is no file specified, we don't know where to go. | |
1586 * But do advance, otherwise ":cn" gets stuck. | |
1587 */ | |
1588 if (qf_ptr->qf_fnum == 0) | |
1589 goto theend; | |
1590 | |
644 | 1591 /* Locate a window showing a normal buffer */ |
1592 usable_win = 0; | |
1593 FOR_ALL_WINDOWS(win) | |
1594 if (win->w_buffer->b_p_bt[0] == NUL) | |
1595 { | |
1596 usable_win = 1; | |
1597 break; | |
1598 } | |
1599 | |
7 | 1600 /* |
1621 | 1601 * If no usable window is found and 'switchbuf' contains "usetab" |
1020 | 1602 * then search in other tabs. |
7 | 1603 */ |
1621 | 1604 if (!usable_win && (swb_flags & SWB_USETAB)) |
1020 | 1605 { |
1606 tabpage_T *tp; | |
1607 win_T *wp; | |
1608 | |
1609 FOR_ALL_TAB_WINDOWS(tp, wp) | |
1610 { | |
1611 if (wp->w_buffer->b_fnum == qf_ptr->qf_fnum) | |
1612 { | |
1613 goto_tabpage_win(tp, wp); | |
1614 usable_win = 1; | |
1819 | 1615 goto win_found; |
1020 | 1616 } |
1617 } | |
1618 } | |
1819 | 1619 win_found: |
1020 | 1620 |
1621 /* | |
1396 | 1622 * If there is only one window and it is the quickfix window, create a |
1623 * new one above the quickfix window. | |
1020 | 1624 */ |
1625 if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win) | |
7 | 1626 { |
644 | 1627 ll_ref = curwin->w_llist_ref; |
1628 | |
1822 | 1629 flags = WSP_ABOVE; |
1630 if (ll_ref != NULL) | |
1631 flags |= WSP_NEWLOC; | |
1632 if (win_split(0, flags) == FAIL) | |
7 | 1633 goto failed; /* not enough room for window */ |
1634 opened_window = TRUE; /* close it when fail */ | |
1635 p_swb = empty_option; /* don't split again */ | |
1621 | 1636 swb_flags = 0; |
7 | 1637 # ifdef FEAT_SCROLLBIND |
1638 curwin->w_p_scb = FALSE; | |
1639 # endif | |
644 | 1640 if (ll_ref != NULL) |
1641 { | |
1642 /* The new window should use the location list from the | |
1643 * location list window */ | |
1644 curwin->w_llist = ll_ref; | |
1645 ll_ref->qf_refcount++; | |
1646 } | |
7 | 1647 } |
1648 else | |
1649 { | |
644 | 1650 if (curwin->w_llist_ref != NULL) |
1651 { | |
1652 /* In a location window */ | |
1653 ll_ref = curwin->w_llist_ref; | |
1654 | |
1655 /* Find the window with the same location list */ | |
1656 FOR_ALL_WINDOWS(win) | |
1657 if (win->w_llist == ll_ref) | |
1658 break; | |
1659 if (win == NULL) | |
1660 { | |
1661 /* Find the window showing the selected file */ | |
1662 FOR_ALL_WINDOWS(win) | |
1663 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) | |
1664 break; | |
1665 if (win == NULL) | |
1666 { | |
1667 /* Find a previous usable window */ | |
1668 win = curwin; | |
1669 do | |
1670 { | |
1671 if (win->w_buffer->b_p_bt[0] == NUL) | |
1672 break; | |
1673 if (win->w_prev == NULL) | |
1674 win = lastwin; /* wrap around the top */ | |
1675 else | |
1676 win = win->w_prev; /* go to previous window */ | |
1677 } while (win != curwin); | |
1678 } | |
1679 } | |
1680 win_goto(win); | |
1681 | |
1682 /* If the location list for the window is not set, then set it | |
1683 * to the location list from the location window */ | |
1684 if (win->w_llist == NULL) | |
1685 { | |
1686 win->w_llist = ll_ref; | |
1687 ll_ref->qf_refcount++; | |
1688 } | |
1689 } | |
1690 else | |
1691 { | |
1692 | |
7 | 1693 /* |
1694 * Try to find a window that shows the right buffer. | |
1695 * Default to the window just above the quickfix buffer. | |
1696 */ | |
1697 win = curwin; | |
1698 altwin = NULL; | |
1699 for (;;) | |
1700 { | |
1701 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) | |
1702 break; | |
1703 if (win->w_prev == NULL) | |
1704 win = lastwin; /* wrap around the top */ | |
1705 else | |
1706 win = win->w_prev; /* go to previous window */ | |
1707 | |
644 | 1708 if (IS_QF_WINDOW(win)) |
7 | 1709 { |
1710 /* Didn't find it, go to the window before the quickfix | |
1711 * window. */ | |
1712 if (altwin != NULL) | |
1713 win = altwin; | |
1714 else if (curwin->w_prev != NULL) | |
1715 win = curwin->w_prev; | |
1716 else | |
1717 win = curwin->w_next; | |
1718 break; | |
1719 } | |
1720 | |
1721 /* Remember a usable window. */ | |
1722 if (altwin == NULL && !win->w_p_pvw | |
1723 && win->w_buffer->b_p_bt[0] == NUL) | |
1724 altwin = win; | |
1725 } | |
1726 | |
1727 win_goto(win); | |
644 | 1728 } |
7 | 1729 } |
1730 } | |
1731 #endif | |
1732 | |
1733 /* | |
1734 * If there is a file name, | |
1735 * read the wanted file if needed, and check autowrite etc. | |
1736 */ | |
1737 old_curbuf = curbuf; | |
1738 old_lnum = curwin->w_cursor.lnum; | |
9 | 1739 |
1740 if (qf_ptr->qf_fnum != 0) | |
1741 { | |
1742 if (qf_ptr->qf_type == 1) | |
1743 { | |
1744 /* Open help file (do_ecmd() will set b_help flag, readfile() will | |
1745 * set b_p_ro flag). */ | |
1746 if (!can_abandon(curbuf, forceit)) | |
1747 { | |
1748 EMSG(_(e_nowrtmsg)); | |
1749 ok = FALSE; | |
1750 } | |
1751 else | |
1752 ok = do_ecmd(qf_ptr->qf_fnum, NULL, NULL, NULL, (linenr_T)1, | |
1743 | 1753 ECMD_HIDE + ECMD_SET_HELP, |
1754 oldwin == curwin ? curwin : NULL); | |
9 | 1755 } |
1756 else | |
1757 ok = buflist_getfile(qf_ptr->qf_fnum, | |
1758 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit); | |
1759 } | |
1760 | |
1761 if (ok == OK) | |
7 | 1762 { |
1763 /* When not switched to another buffer, still need to set pc mark */ | |
1764 if (curbuf == old_curbuf) | |
1765 setpcmark(); | |
1766 | |
230 | 1767 if (qf_ptr->qf_pattern == NULL) |
7 | 1768 { |
230 | 1769 /* |
1770 * Go to line with error, unless qf_lnum is 0. | |
1771 */ | |
1772 i = qf_ptr->qf_lnum; | |
1773 if (i > 0) | |
1774 { | |
1775 if (i > curbuf->b_ml.ml_line_count) | |
1776 i = curbuf->b_ml.ml_line_count; | |
1777 curwin->w_cursor.lnum = i; | |
1778 } | |
1779 if (qf_ptr->qf_col > 0) | |
7 | 1780 { |
230 | 1781 curwin->w_cursor.col = qf_ptr->qf_col - 1; |
1782 if (qf_ptr->qf_viscol == TRUE) | |
7 | 1783 { |
230 | 1784 /* |
1785 * Check each character from the beginning of the error | |
1786 * line up to the error column. For each tab character | |
1787 * found, reduce the error column value by the length of | |
1788 * a tab character. | |
1789 */ | |
1790 line = ml_get_curline(); | |
1791 screen_col = 0; | |
1792 for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) | |
7 | 1793 { |
230 | 1794 if (*line == NUL) |
1795 break; | |
1796 if (*line++ == '\t') | |
1797 { | |
1798 curwin->w_cursor.col -= 7 - (screen_col % 8); | |
1799 screen_col += 8 - (screen_col % 8); | |
1800 } | |
1801 else | |
1802 ++screen_col; | |
7 | 1803 } |
1804 } | |
230 | 1805 check_cursor(); |
7 | 1806 } |
230 | 1807 else |
1808 beginline(BL_WHITE | BL_FIX); | |
7 | 1809 } |
1810 else | |
230 | 1811 { |
1812 pos_T save_cursor; | |
1813 | |
1814 /* Move the cursor to the first line in the buffer */ | |
1815 save_cursor = curwin->w_cursor; | |
1816 curwin->w_cursor.lnum = 0; | |
1521 | 1817 if (!do_search(NULL, '/', qf_ptr->qf_pattern, (long)1, |
1818 SEARCH_KEEP, NULL)) | |
230 | 1819 curwin->w_cursor = save_cursor; |
1820 } | |
7 | 1821 |
1822 #ifdef FEAT_FOLDING | |
1823 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped) | |
1824 foldOpenCursor(); | |
1825 #endif | |
1826 if (print_message) | |
1827 { | |
1828 /* Update the screen before showing the message */ | |
1829 update_topline_redraw(); | |
1830 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, | |
644 | 1831 qi->qf_lists[qi->qf_curlist].qf_count, |
7 | 1832 qf_ptr->qf_cleared ? _(" (line deleted)") : "", |
1833 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); | |
1834 /* Add the message, skipping leading whitespace and newlines. */ | |
1835 len = (int)STRLEN(IObuff); | |
1836 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); | |
1837 | |
1838 /* Output the message. Overwrite to avoid scrolling when the 'O' | |
1839 * flag is present in 'shortmess'; But when not jumping, print the | |
1840 * whole message. */ | |
1841 i = msg_scroll; | |
1842 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) | |
1843 msg_scroll = TRUE; | |
1844 else if (!msg_scrolled && shortmess(SHM_OVERALL)) | |
1845 msg_scroll = FALSE; | |
1846 msg_attr_keep(IObuff, 0, TRUE); | |
1847 msg_scroll = i; | |
1848 } | |
1849 } | |
1850 else | |
1851 { | |
1852 #ifdef FEAT_WINDOWS | |
1853 if (opened_window) | |
1854 win_close(curwin, TRUE); /* Close opened window */ | |
1855 #endif | |
1856 if (qf_ptr->qf_fnum != 0) | |
1857 { | |
1858 /* | |
1859 * Couldn't open file, so put index back where it was. This could | |
1860 * happen if the file was readonly and we changed something. | |
1861 */ | |
1862 #ifdef FEAT_WINDOWS | |
1863 failed: | |
1864 #endif | |
1865 qf_ptr = old_qf_ptr; | |
1866 qf_index = old_qf_index; | |
1867 } | |
1868 } | |
1869 theend: | |
644 | 1870 qi->qf_lists[qi->qf_curlist].qf_ptr = qf_ptr; |
1871 qi->qf_lists[qi->qf_curlist].qf_index = qf_index; | |
7 | 1872 #ifdef FEAT_WINDOWS |
1873 if (p_swb != old_swb && opened_window) | |
1874 { | |
1875 /* Restore old 'switchbuf' value, but not when an autocommand or | |
1876 * modeline has changed the value. */ | |
1877 if (p_swb == empty_option) | |
1621 | 1878 { |
7 | 1879 p_swb = old_swb; |
1621 | 1880 swb_flags = old_swb_flags; |
1881 } | |
7 | 1882 else |
1883 free_string_option(old_swb); | |
1884 } | |
1885 #endif | |
1886 } | |
1887 | |
1888 /* | |
1889 * ":clist": list all errors | |
644 | 1890 * ":llist": list all locations |
7 | 1891 */ |
1892 void | |
1893 qf_list(eap) | |
1894 exarg_T *eap; | |
1895 { | |
230 | 1896 buf_T *buf; |
1897 char_u *fname; | |
1898 qfline_T *qfp; | |
1899 int i; | |
1900 int idx1 = 1; | |
1901 int idx2 = -1; | |
1902 char_u *arg = eap->arg; | |
1903 int all = eap->forceit; /* if not :cl!, only show | |
7 | 1904 recognised errors */ |
644 | 1905 qf_info_T *qi = &ql_info; |
1906 | |
1907 if (eap->cmdidx == CMD_llist) | |
1908 { | |
1909 qi = GET_LOC_LIST(curwin); | |
1910 if (qi == NULL) | |
1911 { | |
1912 EMSG(_(e_loclist)); | |
1913 return; | |
1914 } | |
1915 } | |
1916 | |
1917 if (qi->qf_curlist >= qi->qf_listcount | |
1918 || qi->qf_lists[qi->qf_curlist].qf_count == 0) | |
7 | 1919 { |
1920 EMSG(_(e_quickfix)); | |
1921 return; | |
1922 } | |
1923 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) | |
1924 { | |
1925 EMSG(_(e_trailing)); | |
1926 return; | |
1927 } | |
644 | 1928 i = qi->qf_lists[qi->qf_curlist].qf_count; |
7 | 1929 if (idx1 < 0) |
1930 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1; | |
1931 if (idx2 < 0) | |
1932 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1; | |
1933 | |
644 | 1934 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid) |
7 | 1935 all = TRUE; |
644 | 1936 qfp = qi->qf_lists[qi->qf_curlist].qf_start; |
1937 for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ) | |
7 | 1938 { |
1939 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) | |
1940 { | |
2047
85da03763130
updated for version 7.2.333
Bram Moolenaar <bram@zimbu.org>
parents:
1918
diff
changeset
|
1941 msg_putchar('\n'); |
85da03763130
updated for version 7.2.333
Bram Moolenaar <bram@zimbu.org>
parents:
1918
diff
changeset
|
1942 if (got_int) |
85da03763130
updated for version 7.2.333
Bram Moolenaar <bram@zimbu.org>
parents:
1918
diff
changeset
|
1943 break; |
446 | 1944 |
1945 fname = NULL; | |
1946 if (qfp->qf_fnum != 0 | |
7 | 1947 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) |
446 | 1948 { |
1949 fname = buf->b_fname; | |
1950 if (qfp->qf_type == 1) /* :helpgrep */ | |
1951 fname = gettail(fname); | |
1952 } | |
1953 if (fname == NULL) | |
1954 sprintf((char *)IObuff, "%2d", i); | |
1955 else | |
1956 vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", | |
273 | 1957 i, (char *)fname); |
644 | 1958 msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index |
446 | 1959 ? hl_attr(HLF_L) : hl_attr(HLF_D)); |
1960 if (qfp->qf_lnum == 0) | |
1961 IObuff[0] = NUL; | |
1962 else if (qfp->qf_col == 0) | |
1963 sprintf((char *)IObuff, ":%ld", qfp->qf_lnum); | |
1964 else | |
1965 sprintf((char *)IObuff, ":%ld col %d", | |
7 | 1966 qfp->qf_lnum, qfp->qf_col); |
446 | 1967 sprintf((char *)IObuff + STRLEN(IObuff), "%s:", |
7 | 1968 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); |
446 | 1969 msg_puts_attr(IObuff, hl_attr(HLF_N)); |
1970 if (qfp->qf_pattern != NULL) | |
1971 { | |
1972 qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); | |
1973 STRCAT(IObuff, ":"); | |
1974 msg_puts(IObuff); | |
1975 } | |
1976 msg_puts((char_u *)" "); | |
230 | 1977 |
446 | 1978 /* Remove newlines and leading whitespace from the text. For an |
1979 * unrecognized line keep the indent, the compiler may mark a word | |
1980 * with ^^^^. */ | |
1981 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) | |
7 | 1982 ? skipwhite(qfp->qf_text) : qfp->qf_text, |
1983 IObuff, IOSIZE); | |
446 | 1984 msg_prt_line(IObuff, FALSE); |
1985 out_flush(); /* show one line at a time */ | |
7 | 1986 } |
446 | 1987 |
1988 qfp = qfp->qf_next; | |
1989 ++i; | |
7 | 1990 ui_breakcheck(); |
1991 } | |
1992 } | |
1993 | |
1994 /* | |
1995 * Remove newlines and leading whitespace from an error message. | |
1996 * Put the result in "buf[bufsize]". | |
1997 */ | |
1998 static void | |
1999 qf_fmt_text(text, buf, bufsize) | |
2000 char_u *text; | |
2001 char_u *buf; | |
2002 int bufsize; | |
2003 { | |
2004 int i; | |
2005 char_u *p = text; | |
2006 | |
2007 for (i = 0; *p != NUL && i < bufsize - 1; ++i) | |
2008 { | |
2009 if (*p == '\n') | |
2010 { | |
2011 buf[i] = ' '; | |
2012 while (*++p != NUL) | |
2013 if (!vim_iswhite(*p) && *p != '\n') | |
2014 break; | |
2015 } | |
2016 else | |
2017 buf[i] = *p++; | |
2018 } | |
2019 buf[i] = NUL; | |
2020 } | |
2021 | |
2022 /* | |
2023 * ":colder [count]": Up in the quickfix stack. | |
2024 * ":cnewer [count]": Down in the quickfix stack. | |
644 | 2025 * ":lolder [count]": Up in the location list stack. |
2026 * ":lnewer [count]": Down in the location list stack. | |
7 | 2027 */ |
2028 void | |
2029 qf_age(eap) | |
2030 exarg_T *eap; | |
2031 { | |
644 | 2032 qf_info_T *qi = &ql_info; |
7 | 2033 int count; |
2034 | |
644 | 2035 if (eap->cmdidx == CMD_lolder || eap->cmdidx == CMD_lnewer) |
2036 { | |
2037 qi = GET_LOC_LIST(curwin); | |
2038 if (qi == NULL) | |
2039 { | |
2040 EMSG(_(e_loclist)); | |
2041 return; | |
2042 } | |
2043 } | |
2044 | |
7 | 2045 if (eap->addr_count != 0) |
2046 count = eap->line2; | |
2047 else | |
2048 count = 1; | |
2049 while (count--) | |
2050 { | |
644 | 2051 if (eap->cmdidx == CMD_colder || eap->cmdidx == CMD_lolder) |
7 | 2052 { |
644 | 2053 if (qi->qf_curlist == 0) |
7 | 2054 { |
2055 EMSG(_("E380: At bottom of quickfix stack")); | |
2056 return; | |
2057 } | |
644 | 2058 --qi->qf_curlist; |
7 | 2059 } |
2060 else | |
2061 { | |
644 | 2062 if (qi->qf_curlist >= qi->qf_listcount - 1) |
7 | 2063 { |
2064 EMSG(_("E381: At top of quickfix stack")); | |
2065 return; | |
2066 } | |
644 | 2067 ++qi->qf_curlist; |
7 | 2068 } |
2069 } | |
644 | 2070 qf_msg(qi); |
2071 | |
7 | 2072 } |
2073 | |
2074 static void | |
644 | 2075 qf_msg(qi) |
2076 qf_info_T *qi; | |
7 | 2077 { |
2078 smsg((char_u *)_("error list %d of %d; %d errors"), | |
644 | 2079 qi->qf_curlist + 1, qi->qf_listcount, |
2080 qi->qf_lists[qi->qf_curlist].qf_count); | |
7 | 2081 #ifdef FEAT_WINDOWS |
644 | 2082 qf_update_buffer(qi); |
7 | 2083 #endif |
2084 } | |
2085 | |
2086 /* | |
581 | 2087 * Free error list "idx". |
7 | 2088 */ |
2089 static void | |
644 | 2090 qf_free(qi, idx) |
2091 qf_info_T *qi; | |
7 | 2092 int idx; |
2093 { | |
230 | 2094 qfline_T *qfp; |
7 | 2095 |
644 | 2096 while (qi->qf_lists[idx].qf_count) |
7 | 2097 { |
644 | 2098 qfp = qi->qf_lists[idx].qf_start->qf_next; |
2099 vim_free(qi->qf_lists[idx].qf_start->qf_text); | |
2100 vim_free(qi->qf_lists[idx].qf_start->qf_pattern); | |
2101 vim_free(qi->qf_lists[idx].qf_start); | |
2102 qi->qf_lists[idx].qf_start = qfp; | |
2103 --qi->qf_lists[idx].qf_count; | |
7 | 2104 } |
2105 } | |
2106 | |
2107 /* | |
2108 * qf_mark_adjust: adjust marks | |
2109 */ | |
2110 void | |
644 | 2111 qf_mark_adjust(wp, line1, line2, amount, amount_after) |
2112 win_T *wp; | |
7 | 2113 linenr_T line1; |
2114 linenr_T line2; | |
2115 long amount; | |
2116 long amount_after; | |
2117 { | |
230 | 2118 int i; |
2119 qfline_T *qfp; | |
2120 int idx; | |
644 | 2121 qf_info_T *qi = &ql_info; |
2122 | |
2123 if (wp != NULL) | |
2124 { | |
2125 if (wp->w_llist == NULL) | |
2126 return; | |
2127 qi = wp->w_llist; | |
2128 } | |
2129 | |
2130 for (idx = 0; idx < qi->qf_listcount; ++idx) | |
2131 if (qi->qf_lists[idx].qf_count) | |
2132 for (i = 0, qfp = qi->qf_lists[idx].qf_start; | |
2133 i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) | |
7 | 2134 if (qfp->qf_fnum == curbuf->b_fnum) |
2135 { | |
2136 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) | |
2137 { | |
2138 if (amount == MAXLNUM) | |
2139 qfp->qf_cleared = TRUE; | |
2140 else | |
2141 qfp->qf_lnum += amount; | |
2142 } | |
2143 else if (amount_after && qfp->qf_lnum > line2) | |
2144 qfp->qf_lnum += amount_after; | |
2145 } | |
2146 } | |
2147 | |
2148 /* | |
2149 * Make a nice message out of the error character and the error number: | |
2150 * char number message | |
2151 * e or E 0 " error" | |
2152 * w or W 0 " warning" | |
2153 * i or I 0 " info" | |
2154 * 0 0 "" | |
2155 * other 0 " c" | |
2156 * e or E n " error n" | |
2157 * w or W n " warning n" | |
2158 * i or I n " info n" | |
2159 * 0 n " error n" | |
2160 * other n " c n" | |
2161 * 1 x "" :helpgrep | |
2162 */ | |
2163 static char_u * | |
2164 qf_types(c, nr) | |
2165 int c, nr; | |
2166 { | |
2167 static char_u buf[20]; | |
2168 static char_u cc[3]; | |
2169 char_u *p; | |
2170 | |
2171 if (c == 'W' || c == 'w') | |
2172 p = (char_u *)" warning"; | |
2173 else if (c == 'I' || c == 'i') | |
2174 p = (char_u *)" info"; | |
2175 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) | |
2176 p = (char_u *)" error"; | |
2177 else if (c == 0 || c == 1) | |
2178 p = (char_u *)""; | |
2179 else | |
2180 { | |
2181 cc[0] = ' '; | |
2182 cc[1] = c; | |
2183 cc[2] = NUL; | |
2184 p = cc; | |
2185 } | |
2186 | |
2187 if (nr <= 0) | |
2188 return p; | |
2189 | |
2190 sprintf((char *)buf, "%s %3d", (char *)p, nr); | |
2191 return buf; | |
2192 } | |
2193 | |
2194 #if defined(FEAT_WINDOWS) || defined(PROTO) | |
2195 /* | |
2196 * ":cwindow": open the quickfix window if we have errors to display, | |
2197 * close it if not. | |
644 | 2198 * ":lwindow": open the location list window if we have locations to display, |
2199 * close it if not. | |
7 | 2200 */ |
2201 void | |
2202 ex_cwindow(eap) | |
2203 exarg_T *eap; | |
2204 { | |
644 | 2205 qf_info_T *qi = &ql_info; |
7 | 2206 win_T *win; |
2207 | |
644 | 2208 if (eap->cmdidx == CMD_lwindow) |
2209 { | |
2210 qi = GET_LOC_LIST(curwin); | |
2211 if (qi == NULL) | |
2212 return; | |
2213 } | |
2214 | |
2215 /* Look for an existing quickfix window. */ | |
2216 win = qf_find_win(qi); | |
7 | 2217 |
2218 /* | |
2219 * If a quickfix window is open but we have no errors to display, | |
2220 * close the window. If a quickfix window is not open, then open | |
2221 * it if we have errors; otherwise, leave it closed. | |
2222 */ | |
644 | 2223 if (qi->qf_lists[qi->qf_curlist].qf_nonevalid |
857 | 2224 || qi->qf_curlist >= qi->qf_listcount) |
7 | 2225 { |
2226 if (win != NULL) | |
2227 ex_cclose(eap); | |
2228 } | |
2229 else if (win == NULL) | |
2230 ex_copen(eap); | |
2231 } | |
2232 | |
2233 /* | |
2234 * ":cclose": close the window showing the list of errors. | |
644 | 2235 * ":lclose": close the window showing the location list |
7 | 2236 */ |
2237 void | |
2238 ex_cclose(eap) | |
2239 exarg_T *eap; | |
2240 { | |
644 | 2241 win_T *win = NULL; |
2242 qf_info_T *qi = &ql_info; | |
2243 | |
2244 if (eap->cmdidx == CMD_lclose || eap->cmdidx == CMD_lwindow) | |
2245 { | |
2246 qi = GET_LOC_LIST(curwin); | |
2247 if (qi == NULL) | |
2248 return; | |
2249 } | |
2250 | |
2251 /* Find existing quickfix window and close it. */ | |
2252 win = qf_find_win(qi); | |
7 | 2253 if (win != NULL) |
2254 win_close(win, FALSE); | |
2255 } | |
2256 | |
2257 /* | |
2258 * ":copen": open a window that shows the list of errors. | |
644 | 2259 * ":lopen": open a window that shows the location list. |
7 | 2260 */ |
2261 void | |
2262 ex_copen(eap) | |
2263 exarg_T *eap; | |
2264 { | |
644 | 2265 qf_info_T *qi = &ql_info; |
7 | 2266 int height; |
2267 win_T *win; | |
682 | 2268 tabpage_T *prevtab = curtab; |
859 | 2269 buf_T *qf_buf; |
1743 | 2270 win_T *oldwin = curwin; |
7 | 2271 |
644 | 2272 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) |
2273 { | |
2274 qi = GET_LOC_LIST(curwin); | |
2275 if (qi == NULL) | |
2276 { | |
2277 EMSG(_(e_loclist)); | |
2278 return; | |
2279 } | |
2280 } | |
2281 | |
7 | 2282 if (eap->addr_count != 0) |
2283 height = eap->line2; | |
2284 else | |
2285 height = QF_WINHEIGHT; | |
2286 | |
2287 #ifdef FEAT_VISUAL | |
2288 reset_VIsual_and_resel(); /* stop Visual mode */ | |
2289 #endif | |
2290 #ifdef FEAT_GUI | |
2291 need_mouse_correct = TRUE; | |
2292 #endif | |
2293 | |
2294 /* | |
2295 * Find existing quickfix window, or open a new one. | |
2296 */ | |
644 | 2297 win = qf_find_win(qi); |
2298 | |
682 | 2299 if (win != NULL && cmdmod.tab == 0) |
7 | 2300 win_goto(win); |
2301 else | |
2302 { | |
859 | 2303 qf_buf = qf_find_buf(qi); |
2304 | |
7 | 2305 /* The current window becomes the previous window afterwards. */ |
2306 win = curwin; | |
2307 | |
644 | 2308 if (eap->cmdidx == CMD_copen || eap->cmdidx == CMD_cwindow) |
2309 /* Create the new window at the very bottom. */ | |
2310 win_goto(lastwin); | |
1822 | 2311 if (win_split(height, WSP_BELOW | WSP_NEWLOC) == FAIL) |
7 | 2312 return; /* not enough room for window */ |
2313 #ifdef FEAT_SCROLLBIND | |
2314 curwin->w_p_scb = FALSE; | |
2315 #endif | |
2316 | |
644 | 2317 if (eap->cmdidx == CMD_lopen || eap->cmdidx == CMD_lwindow) |
7 | 2318 { |
644 | 2319 /* |
2320 * For the location list window, create a reference to the | |
2321 * location list from the window 'win'. | |
2322 */ | |
2323 curwin->w_llist_ref = win->w_llist; | |
2324 win->w_llist->qf_refcount++; | |
7 | 2325 } |
644 | 2326 |
1743 | 2327 if (oldwin != curwin) |
2328 oldwin = NULL; /* don't store info when in another window */ | |
859 | 2329 if (qf_buf != NULL) |
2330 /* Use the existing quickfix buffer */ | |
2331 (void)do_ecmd(qf_buf->b_fnum, NULL, NULL, NULL, ECMD_ONE, | |
1743 | 2332 ECMD_HIDE + ECMD_OLDBUF, oldwin); |
859 | 2333 else |
2334 { | |
2335 /* Create a new quickfix buffer */ | |
1743 | 2336 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin); |
859 | 2337 /* switch off 'swapfile' */ |
2338 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); | |
2339 set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", | |
729 | 2340 OPT_LOCAL); |
859 | 2341 set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); |
1864 | 2342 #ifdef FEAT_DIFF |
2343 curwin->w_p_diff = FALSE; | |
2344 #endif | |
2345 #ifdef FEAT_FOLDING | |
2346 set_option_value((char_u *)"fdm", 0L, (char_u *)"manual", | |
2347 OPT_LOCAL); | |
2348 #endif | |
859 | 2349 } |
7 | 2350 |
682 | 2351 /* Only set the height when still in the same tab page and there is no |
2352 * window to the side. */ | |
2353 if (curtab == prevtab | |
119 | 2354 #ifdef FEAT_VERTSPLIT |
682 | 2355 && curwin->w_width == Columns |
119 | 2356 #endif |
682 | 2357 ) |
7 | 2358 win_setheight(height); |
2359 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */ | |
2360 if (win_valid(win)) | |
2361 prevwin = win; | |
2362 } | |
2363 | |
2364 /* | |
2365 * Fill the buffer with the quickfix list. | |
2366 */ | |
644 | 2367 qf_fill_buffer(qi); |
2368 | |
2369 curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index; | |
7 | 2370 curwin->w_cursor.col = 0; |
2371 check_cursor(); | |
2372 update_topline(); /* scroll to show the line */ | |
2373 } | |
2374 | |
2375 /* | |
2376 * Return the number of the current entry (line number in the quickfix | |
2377 * window). | |
2378 */ | |
2379 linenr_T | |
644 | 2380 qf_current_entry(wp) |
2381 win_T *wp; | |
7 | 2382 { |
644 | 2383 qf_info_T *qi = &ql_info; |
2384 | |
2385 if (IS_LL_WINDOW(wp)) | |
2386 /* In the location list window, use the referenced location list */ | |
2387 qi = wp->w_llist_ref; | |
2388 | |
2389 return qi->qf_lists[qi->qf_curlist].qf_index; | |
7 | 2390 } |
2391 | |
2392 /* | |
2393 * Update the cursor position in the quickfix window to the current error. | |
2394 * Return TRUE if there is a quickfix window. | |
2395 */ | |
2396 static int | |
644 | 2397 qf_win_pos_update(qi, old_qf_index) |
2398 qf_info_T *qi; | |
7 | 2399 int old_qf_index; /* previous qf_index or zero */ |
2400 { | |
2401 win_T *win; | |
644 | 2402 int qf_index = qi->qf_lists[qi->qf_curlist].qf_index; |
7 | 2403 |
2404 /* | |
2405 * Put the cursor on the current error in the quickfix window, so that | |
2406 * it's viewable. | |
2407 */ | |
644 | 2408 win = qf_find_win(qi); |
7 | 2409 if (win != NULL |
2410 && qf_index <= win->w_buffer->b_ml.ml_line_count | |
2411 && old_qf_index != qf_index) | |
2412 { | |
2413 win_T *old_curwin = curwin; | |
2414 | |
2415 curwin = win; | |
2416 curbuf = win->w_buffer; | |
2417 if (qf_index > old_qf_index) | |
2418 { | |
2419 curwin->w_redraw_top = old_qf_index; | |
2420 curwin->w_redraw_bot = qf_index; | |
2421 } | |
2422 else | |
2423 { | |
2424 curwin->w_redraw_top = qf_index; | |
2425 curwin->w_redraw_bot = old_qf_index; | |
2426 } | |
2427 curwin->w_cursor.lnum = qf_index; | |
2428 curwin->w_cursor.col = 0; | |
2429 update_topline(); /* scroll to show the line */ | |
2430 redraw_later(VALID); | |
2431 curwin->w_redr_status = TRUE; /* update ruler */ | |
2432 curwin = old_curwin; | |
2433 curbuf = curwin->w_buffer; | |
2434 } | |
2435 return win != NULL; | |
2436 } | |
2437 | |
2438 /* | |
859 | 2439 * Check whether the given window is displaying the specified quickfix/location |
2440 * list buffer | |
2441 */ | |
2442 static int | |
2443 is_qf_win(win, qi) | |
2444 win_T *win; | |
2445 qf_info_T *qi; | |
2446 { | |
2447 /* | |
2448 * A window displaying the quickfix buffer will have the w_llist_ref field | |
2449 * set to NULL. | |
2450 * A window displaying a location list buffer will have the w_llist_ref | |
2451 * pointing to the location list. | |
2452 */ | |
2453 if (bt_quickfix(win->w_buffer)) | |
2454 if ((qi == &ql_info && win->w_llist_ref == NULL) | |
2455 || (qi != &ql_info && win->w_llist_ref == qi)) | |
2456 return TRUE; | |
2457 | |
2458 return FALSE; | |
2459 } | |
2460 | |
2461 /* | |
644 | 2462 * Find a window displaying the quickfix/location list 'qi' |
859 | 2463 * Searches in only the windows opened in the current tab. |
644 | 2464 */ |
2465 static win_T * | |
2466 qf_find_win(qi) | |
2467 qf_info_T *qi; | |
2468 { | |
2469 win_T *win; | |
2470 | |
2471 FOR_ALL_WINDOWS(win) | |
859 | 2472 if (is_qf_win(win, qi)) |
2473 break; | |
644 | 2474 |
2475 return win; | |
2476 } | |
2477 | |
2478 /* | |
859 | 2479 * Find a quickfix buffer. |
2480 * Searches in windows opened in all the tabs. | |
7 | 2481 */ |
2482 static buf_T * | |
644 | 2483 qf_find_buf(qi) |
2484 qf_info_T *qi; | |
7 | 2485 { |
859 | 2486 tabpage_T *tp; |
644 | 2487 win_T *win; |
2488 | |
859 | 2489 FOR_ALL_TAB_WINDOWS(tp, win) |
2490 if (is_qf_win(win, qi)) | |
2491 return win->w_buffer; | |
2492 | |
2493 return NULL; | |
7 | 2494 } |
2495 | |
2496 /* | |
2497 * Find the quickfix buffer. If it exists, update the contents. | |
2498 */ | |
2499 static void | |
644 | 2500 qf_update_buffer(qi) |
2501 qf_info_T *qi; | |
7 | 2502 { |
2503 buf_T *buf; | |
2504 aco_save_T aco; | |
2505 | |
2506 /* Check if a buffer for the quickfix list exists. Update it. */ | |
644 | 2507 buf = qf_find_buf(qi); |
7 | 2508 if (buf != NULL) |
2509 { | |
2510 /* set curwin/curbuf to buf and save a few things */ | |
2511 aucmd_prepbuf(&aco, buf); | |
2512 | |
644 | 2513 qf_fill_buffer(qi); |
7 | 2514 |
2515 /* restore curwin/curbuf and a few other things */ | |
2516 aucmd_restbuf(&aco); | |
2517 | |
644 | 2518 (void)qf_win_pos_update(qi, 0); |
7 | 2519 } |
2520 } | |
2521 | |
2522 /* | |
2523 * Fill current buffer with quickfix errors, replacing any previous contents. | |
2524 * curbuf must be the quickfix buffer! | |
2525 */ | |
2526 static void | |
644 | 2527 qf_fill_buffer(qi) |
2528 qf_info_T *qi; | |
7 | 2529 { |
230 | 2530 linenr_T lnum; |
2531 qfline_T *qfp; | |
2532 buf_T *errbuf; | |
2533 int len; | |
2534 int old_KeyTyped = KeyTyped; | |
7 | 2535 |
2536 /* delete all existing lines */ | |
2537 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) | |
2538 (void)ml_delete((linenr_T)1, FALSE); | |
2539 | |
2540 /* Check if there is anything to display */ | |
644 | 2541 if (qi->qf_curlist < qi->qf_listcount) |
7 | 2542 { |
2543 /* Add one line for each error */ | |
644 | 2544 qfp = qi->qf_lists[qi->qf_curlist].qf_start; |
2545 for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum) | |
7 | 2546 { |
2547 if (qfp->qf_fnum != 0 | |
2548 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL | |
2549 && errbuf->b_fname != NULL) | |
2550 { | |
2551 if (qfp->qf_type == 1) /* :helpgrep */ | |
2552 STRCPY(IObuff, gettail(errbuf->b_fname)); | |
2553 else | |
2554 STRCPY(IObuff, errbuf->b_fname); | |
2555 len = (int)STRLEN(IObuff); | |
2556 } | |
2557 else | |
2558 len = 0; | |
2559 IObuff[len++] = '|'; | |
2560 | |
2561 if (qfp->qf_lnum > 0) | |
2562 { | |
2563 sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum); | |
2564 len += (int)STRLEN(IObuff + len); | |
2565 | |
2566 if (qfp->qf_col > 0) | |
2567 { | |
2568 sprintf((char *)IObuff + len, " col %d", qfp->qf_col); | |
2569 len += (int)STRLEN(IObuff + len); | |
2570 } | |
2571 | |
2572 sprintf((char *)IObuff + len, "%s", | |
2573 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); | |
2574 len += (int)STRLEN(IObuff + len); | |
2575 } | |
230 | 2576 else if (qfp->qf_pattern != NULL) |
2577 { | |
2578 qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len); | |
2579 len += (int)STRLEN(IObuff + len); | |
2580 } | |
7 | 2581 IObuff[len++] = '|'; |
2582 IObuff[len++] = ' '; | |
2583 | |
2584 /* Remove newlines and leading whitespace from the text. | |
2585 * For an unrecognized line keep the indent, the compiler may | |
2586 * mark a word with ^^^^. */ | |
2587 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, | |
2588 IObuff + len, IOSIZE - len); | |
2589 | |
2590 if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) | |
2591 == FAIL) | |
2592 break; | |
2593 qfp = qfp->qf_next; | |
2594 } | |
2595 /* Delete the empty line which is now at the end */ | |
2596 (void)ml_delete(lnum + 1, FALSE); | |
2597 } | |
2598 | |
2599 /* correct cursor position */ | |
2600 check_lnums(TRUE); | |
2601 | |
2602 /* Set the 'filetype' to "qf" each time after filling the buffer. This | |
2603 * resembles reading a file into a buffer, it's more logical when using | |
2604 * autocommands. */ | |
2605 set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); | |
2606 curbuf->b_p_ma = FALSE; | |
2607 | |
2608 #ifdef FEAT_AUTOCMD | |
1864 | 2609 keep_filetype = TRUE; /* don't detect 'filetype' */ |
7 | 2610 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, |
2611 FALSE, curbuf); | |
2612 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, | |
2613 FALSE, curbuf); | |
1864 | 2614 keep_filetype = FALSE; |
7 | 2615 #endif |
2616 | |
2617 /* make sure it will be redrawn */ | |
2618 redraw_curbuf_later(NOT_VALID); | |
2619 | |
2620 /* Restore KeyTyped, setting 'filetype' may reset it. */ | |
2621 KeyTyped = old_KeyTyped; | |
2622 } | |
2623 | |
2624 #endif /* FEAT_WINDOWS */ | |
2625 | |
2626 /* | |
2627 * Return TRUE if "buf" is the quickfix buffer. | |
2628 */ | |
2629 int | |
2630 bt_quickfix(buf) | |
2631 buf_T *buf; | |
2632 { | |
2633 return (buf->b_p_bt[0] == 'q'); | |
2634 } | |
2635 | |
2636 /* | |
17 | 2637 * Return TRUE if "buf" is a "nofile" or "acwrite" buffer. |
2638 * This means the buffer name is not a file name. | |
7 | 2639 */ |
2640 int | |
2641 bt_nofile(buf) | |
2642 buf_T *buf; | |
2643 { | |
17 | 2644 return (buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f') |
2645 || buf->b_p_bt[0] == 'a'; | |
7 | 2646 } |
2647 | |
2648 /* | |
2649 * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. | |
2650 */ | |
2651 int | |
2652 bt_dontwrite(buf) | |
2653 buf_T *buf; | |
2654 { | |
2655 return (buf->b_p_bt[0] == 'n'); | |
2656 } | |
2657 | |
2658 int | |
2659 bt_dontwrite_msg(buf) | |
2660 buf_T *buf; | |
2661 { | |
2662 if (bt_dontwrite(buf)) | |
2663 { | |
2664 EMSG(_("E382: Cannot write, 'buftype' option is set")); | |
2665 return TRUE; | |
2666 } | |
2667 return FALSE; | |
2668 } | |
2669 | |
2670 /* | |
2671 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" | |
2672 * and 'bufhidden'. | |
2673 */ | |
2674 int | |
2675 buf_hide(buf) | |
2676 buf_T *buf; | |
2677 { | |
2678 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ | |
2679 switch (buf->b_p_bh[0]) | |
2680 { | |
2681 case 'u': /* "unload" */ | |
2682 case 'w': /* "wipe" */ | |
2683 case 'd': return FALSE; /* "delete" */ | |
2684 case 'h': return TRUE; /* "hide" */ | |
2685 } | |
2686 return (p_hid || cmdmod.hide); | |
2687 } | |
2688 | |
2689 /* | |
41 | 2690 * Return TRUE when using ":vimgrep" for ":grep". |
2691 */ | |
2692 int | |
42 | 2693 grep_internal(cmdidx) |
2694 cmdidx_T cmdidx; | |
41 | 2695 { |
661 | 2696 return ((cmdidx == CMD_grep |
2697 || cmdidx == CMD_lgrep | |
2698 || cmdidx == CMD_grepadd | |
2699 || cmdidx == CMD_lgrepadd) | |
41 | 2700 && STRCMP("internal", |
2701 *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0); | |
2702 } | |
2703 | |
2704 /* | |
657 | 2705 * Used for ":make", ":lmake", ":grep", ":lgrep", ":grepadd", and ":lgrepadd" |
7 | 2706 */ |
2707 void | |
2708 ex_make(eap) | |
2709 exarg_T *eap; | |
2710 { | |
161 | 2711 char_u *fname; |
7 | 2712 char_u *cmd; |
2713 unsigned len; | |
657 | 2714 win_T *wp = NULL; |
659 | 2715 qf_info_T *qi = &ql_info; |
842 | 2716 int res; |
161 | 2717 #ifdef FEAT_AUTOCMD |
2718 char_u *au_name = NULL; | |
2719 | |
2720 switch (eap->cmdidx) | |
2721 { | |
661 | 2722 case CMD_make: au_name = (char_u *)"make"; break; |
2723 case CMD_lmake: au_name = (char_u *)"lmake"; break; | |
2724 case CMD_grep: au_name = (char_u *)"grep"; break; | |
2725 case CMD_lgrep: au_name = (char_u *)"lgrep"; break; | |
2726 case CMD_grepadd: au_name = (char_u *)"grepadd"; break; | |
2727 case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break; | |
161 | 2728 default: break; |
2729 } | |
2730 if (au_name != NULL) | |
2731 { | |
2732 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
2733 curbuf->b_fname, TRUE, curbuf); | |
532 | 2734 # ifdef FEAT_EVAL |
161 | 2735 if (did_throw || force_abort) |
2736 return; | |
532 | 2737 # endif |
161 | 2738 } |
2739 #endif | |
7 | 2740 |
41 | 2741 /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */ |
42 | 2742 if (grep_internal(eap->cmdidx)) |
41 | 2743 { |
2744 ex_vimgrep(eap); | |
2745 return; | |
2746 } | |
2747 | |
657 | 2748 if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep |
2749 || eap->cmdidx == CMD_lgrepadd) | |
2750 wp = curwin; | |
2751 | |
7 | 2752 autowrite_all(); |
161 | 2753 fname = get_mef_name(); |
2754 if (fname == NULL) | |
7 | 2755 return; |
161 | 2756 mch_remove(fname); /* in case it's not unique */ |
7 | 2757 |
2758 /* | |
2759 * If 'shellpipe' empty: don't redirect to 'errorfile'. | |
2760 */ | |
2761 len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1; | |
2762 if (*p_sp != NUL) | |
161 | 2763 len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(fname) + 3; |
7 | 2764 cmd = alloc(len); |
2765 if (cmd == NULL) | |
2766 return; | |
2767 sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg, | |
2768 (char *)p_shq); | |
2769 if (*p_sp != NUL) | |
1872 | 2770 append_redir(cmd, len, p_sp, fname); |
7 | 2771 /* |
2772 * Output a newline if there's something else than the :make command that | |
2773 * was typed (in which case the cursor is in column 0). | |
2774 */ | |
2775 if (msg_col == 0) | |
2776 msg_didout = FALSE; | |
2777 msg_start(); | |
2778 MSG_PUTS(":!"); | |
2779 msg_outtrans(cmd); /* show what we are doing */ | |
2780 | |
2781 /* let the shell know if we are redirecting output or not */ | |
2782 do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0); | |
2783 | |
2784 #ifdef AMIGA | |
2785 out_flush(); | |
2786 /* read window status report and redraw before message */ | |
2787 (void)char_avail(); | |
2788 #endif | |
2789 | |
842 | 2790 res = qf_init(wp, fname, (eap->cmdidx != CMD_make |
657 | 2791 && eap->cmdidx != CMD_lmake) ? p_gefm : p_efm, |
2792 (eap->cmdidx != CMD_grepadd | |
842 | 2793 && eap->cmdidx != CMD_lgrepadd)); |
2794 #ifdef FEAT_AUTOCMD | |
2795 if (au_name != NULL) | |
2796 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, | |
2797 curbuf->b_fname, TRUE, curbuf); | |
2798 #endif | |
2799 if (res > 0 && !eap->forceit) | |
665 | 2800 { |
2801 if (wp != NULL) | |
2802 qi = GET_LOC_LIST(wp); | |
659 | 2803 qf_jump(qi, 0, 0, FALSE); /* display first error */ |
665 | 2804 } |
7 | 2805 |
161 | 2806 mch_remove(fname); |
2807 vim_free(fname); | |
7 | 2808 vim_free(cmd); |
2809 } | |
2810 | |
2811 /* | |
2812 * Return the name for the errorfile, in allocated memory. | |
2813 * Find a new unique name when 'makeef' contains "##". | |
2814 * Returns NULL for error. | |
2815 */ | |
2816 static char_u * | |
2817 get_mef_name() | |
2818 { | |
2819 char_u *p; | |
2820 char_u *name; | |
2821 static int start = -1; | |
2822 static int off = 0; | |
2823 #ifdef HAVE_LSTAT | |
2824 struct stat sb; | |
2825 #endif | |
2826 | |
2827 if (*p_mef == NUL) | |
2828 { | |
2829 name = vim_tempname('e'); | |
2830 if (name == NULL) | |
2831 EMSG(_(e_notmp)); | |
2832 return name; | |
2833 } | |
2834 | |
2835 for (p = p_mef; *p; ++p) | |
2836 if (p[0] == '#' && p[1] == '#') | |
2837 break; | |
2838 | |
2839 if (*p == NUL) | |
2840 return vim_strsave(p_mef); | |
2841 | |
2842 /* Keep trying until the name doesn't exist yet. */ | |
2843 for (;;) | |
2844 { | |
2845 if (start == -1) | |
2846 start = mch_get_pid(); | |
2847 else | |
2848 off += 19; | |
2849 | |
2850 name = alloc((unsigned)STRLEN(p_mef) + 30); | |
2851 if (name == NULL) | |
2852 break; | |
2853 STRCPY(name, p_mef); | |
2854 sprintf((char *)name + (p - p_mef), "%d%d", start, off); | |
2855 STRCAT(name, p + 2); | |
2856 if (mch_getperm(name) < 0 | |
2857 #ifdef HAVE_LSTAT | |
2858 /* Don't accept a symbolic link, its a security risk. */ | |
2859 && mch_lstat((char *)name, &sb) < 0 | |
2860 #endif | |
2861 ) | |
2862 break; | |
2863 vim_free(name); | |
2864 } | |
2865 return name; | |
2866 } | |
2867 | |
2868 /* | |
2869 * ":cc", ":crewind", ":cfirst" and ":clast". | |
644 | 2870 * ":ll", ":lrewind", ":lfirst" and ":llast". |
7 | 2871 */ |
2872 void | |
2873 ex_cc(eap) | |
2874 exarg_T *eap; | |
2875 { | |
659 | 2876 qf_info_T *qi = &ql_info; |
2877 | |
2878 if (eap->cmdidx == CMD_ll | |
2879 || eap->cmdidx == CMD_lrewind | |
2880 || eap->cmdidx == CMD_lfirst | |
2881 || eap->cmdidx == CMD_llast) | |
644 | 2882 { |
2883 qi = GET_LOC_LIST(curwin); | |
2884 if (qi == NULL) | |
2885 { | |
2886 EMSG(_(e_loclist)); | |
2887 return; | |
2888 } | |
2889 } | |
2890 | |
659 | 2891 qf_jump(qi, 0, |
7 | 2892 eap->addr_count > 0 |
2893 ? (int)eap->line2 | |
644 | 2894 : (eap->cmdidx == CMD_cc || eap->cmdidx == CMD_ll) |
7 | 2895 ? 0 |
644 | 2896 : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_lrewind |
2897 || eap->cmdidx == CMD_cfirst || eap->cmdidx == CMD_lfirst) | |
7 | 2898 ? 1 |
2899 : 32767, | |
2900 eap->forceit); | |
2901 } | |
2902 | |
2903 /* | |
2904 * ":cnext", ":cnfile", ":cNext" and ":cprevious". | |
644 | 2905 * ":lnext", ":lNext", ":lprevious", ":lnfile", ":lNfile" and ":lpfile". |
7 | 2906 */ |
2907 void | |
2908 ex_cnext(eap) | |
2909 exarg_T *eap; | |
2910 { | |
659 | 2911 qf_info_T *qi = &ql_info; |
2912 | |
2913 if (eap->cmdidx == CMD_lnext | |
2914 || eap->cmdidx == CMD_lNext | |
2915 || eap->cmdidx == CMD_lprevious | |
2916 || eap->cmdidx == CMD_lnfile | |
2917 || eap->cmdidx == CMD_lNfile | |
2918 || eap->cmdidx == CMD_lpfile) | |
644 | 2919 { |
2920 qi = GET_LOC_LIST(curwin); | |
2921 if (qi == NULL) | |
2922 { | |
2923 EMSG(_(e_loclist)); | |
2924 return; | |
2925 } | |
2926 } | |
2927 | |
659 | 2928 qf_jump(qi, (eap->cmdidx == CMD_cnext || eap->cmdidx == CMD_lnext) |
7 | 2929 ? FORWARD |
644 | 2930 : (eap->cmdidx == CMD_cnfile || eap->cmdidx == CMD_lnfile) |
7 | 2931 ? FORWARD_FILE |
644 | 2932 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_lpfile |
2933 || eap->cmdidx == CMD_cNfile || eap->cmdidx == CMD_lNfile) | |
7 | 2934 ? BACKWARD_FILE |
2935 : BACKWARD, | |
2936 eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); | |
2937 } | |
2938 | |
2939 /* | |
446 | 2940 * ":cfile"/":cgetfile"/":caddfile" commands. |
644 | 2941 * ":lfile"/":lgetfile"/":laddfile" commands. |
7 | 2942 */ |
2943 void | |
2944 ex_cfile(eap) | |
2945 exarg_T *eap; | |
2946 { | |
644 | 2947 win_T *wp = NULL; |
659 | 2948 qf_info_T *qi = &ql_info; |
644 | 2949 |
2950 if (eap->cmdidx == CMD_lfile || eap->cmdidx == CMD_lgetfile | |
2951 || eap->cmdidx == CMD_laddfile) | |
2952 wp = curwin; | |
2953 | |
7 | 2954 if (*eap->arg != NUL) |
694 | 2955 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE, 0); |
446 | 2956 |
2957 /* | |
2958 * This function is used by the :cfile, :cgetfile and :caddfile | |
2959 * commands. | |
2960 * :cfile always creates a new quickfix list and jumps to the | |
2961 * first error. | |
2962 * :cgetfile creates a new quickfix list but doesn't jump to the | |
2963 * first error. | |
2964 * :caddfile adds to an existing quickfix list. If there is no | |
2965 * quickfix list then a new list is created. | |
2966 */ | |
644 | 2967 if (qf_init(wp, p_ef, p_efm, (eap->cmdidx != CMD_caddfile |
2968 && eap->cmdidx != CMD_laddfile)) > 0 | |
2969 && (eap->cmdidx == CMD_cfile | |
2970 || eap->cmdidx == CMD_lfile)) | |
665 | 2971 { |
2972 if (wp != NULL) | |
2973 qi = GET_LOC_LIST(wp); | |
659 | 2974 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ |
665 | 2975 } |
7 | 2976 } |
2977 | |
2978 /* | |
41 | 2979 * ":vimgrep {pattern} file(s)" |
657 | 2980 * ":vimgrepadd {pattern} file(s)" |
2981 * ":lvimgrep {pattern} file(s)" | |
2982 * ":lvimgrepadd {pattern} file(s)" | |
41 | 2983 */ |
2984 void | |
2985 ex_vimgrep(eap) | |
2986 exarg_T *eap; | |
2987 { | |
42 | 2988 regmmatch_T regmatch; |
153 | 2989 int fcount; |
41 | 2990 char_u **fnames; |
1411 | 2991 char_u *fname; |
153 | 2992 char_u *s; |
2993 char_u *p; | |
2994 int fi; | |
657 | 2995 qf_info_T *qi = &ql_info; |
230 | 2996 qfline_T *prevp = NULL; |
41 | 2997 long lnum; |
42 | 2998 buf_T *buf; |
2999 int duplicate_name = FALSE; | |
3000 int using_dummy; | |
1396 | 3001 int redraw_for_dummy = FALSE; |
42 | 3002 int found_match; |
123 | 3003 buf_T *first_match_buf = NULL; |
3004 time_t seconds = 0; | |
677 | 3005 int save_mls; |
123 | 3006 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) |
3007 char_u *save_ei = NULL; | |
677 | 3008 #endif |
123 | 3009 aco_save_T aco; |
170 | 3010 int flags = 0; |
3011 colnr_T col; | |
716 | 3012 long tomatch; |
1411 | 3013 char_u dirname_start[MAXPATHL]; |
3014 char_u dirname_now[MAXPATHL]; | |
3015 char_u *target_dir = NULL; | |
1683 | 3016 #ifdef FEAT_AUTOCMD |
3017 char_u *au_name = NULL; | |
161 | 3018 |
3019 switch (eap->cmdidx) | |
3020 { | |
3021 case CMD_vimgrep: au_name = (char_u *)"vimgrep"; break; | |
657 | 3022 case CMD_lvimgrep: au_name = (char_u *)"lvimgrep"; break; |
161 | 3023 case CMD_vimgrepadd: au_name = (char_u *)"vimgrepadd"; break; |
657 | 3024 case CMD_lvimgrepadd: au_name = (char_u *)"lvimgrepadd"; break; |
161 | 3025 default: break; |
3026 } | |
3027 if (au_name != NULL) | |
3028 { | |
3029 apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
3030 curbuf->b_fname, TRUE, curbuf); | |
3031 if (did_throw || force_abort) | |
3032 return; | |
3033 } | |
3034 #endif | |
41 | 3035 |
661 | 3036 if (eap->cmdidx == CMD_lgrep |
659 | 3037 || eap->cmdidx == CMD_lvimgrep |
3038 || eap->cmdidx == CMD_lgrepadd | |
3039 || eap->cmdidx == CMD_lvimgrepadd) | |
657 | 3040 { |
3041 qi = ll_get_or_alloc_list(curwin); | |
3042 if (qi == NULL) | |
3043 return; | |
3044 } | |
3045 | |
716 | 3046 if (eap->addr_count > 0) |
3047 tomatch = eap->line2; | |
3048 else | |
3049 tomatch = MAXLNUM; | |
3050 | |
42 | 3051 /* Get the search pattern: either white-separated or enclosed in // */ |
41 | 3052 regmatch.regprog = NULL; |
170 | 3053 p = skip_vimgrep_pat(eap->arg, &s, &flags); |
153 | 3054 if (p == NULL) |
41 | 3055 { |
282 | 3056 EMSG(_(e_invalpat)); |
153 | 3057 goto theend; |
41 | 3058 } |
42 | 3059 regmatch.regprog = vim_regcomp(s, RE_MAGIC); |
41 | 3060 if (regmatch.regprog == NULL) |
3061 goto theend; | |
95 | 3062 regmatch.rmm_ic = p_ic; |
410 | 3063 regmatch.rmm_maxcol = 0; |
41 | 3064 |
3065 p = skipwhite(p); | |
3066 if (*p == NUL) | |
3067 { | |
3068 EMSG(_("E683: File name missing or invalid pattern")); | |
3069 goto theend; | |
3070 } | |
3071 | |
661 | 3072 if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_lgrepadd && |
657 | 3073 eap->cmdidx != CMD_vimgrepadd && eap->cmdidx != CMD_lvimgrepadd) |
644 | 3074 || qi->qf_curlist == qi->qf_listcount) |
41 | 3075 /* make place for a new list */ |
644 | 3076 qf_new_list(qi); |
3077 else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) | |
41 | 3078 /* Adding to existing list, find last entry. */ |
644 | 3079 for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; |
41 | 3080 prevp->qf_next != prevp; prevp = prevp->qf_next) |
3081 ; | |
3082 | |
3083 /* parse the list of arguments */ | |
236 | 3084 if (get_arglist_exp(p, &fcount, &fnames) == FAIL) |
41 | 3085 goto theend; |
3086 if (fcount == 0) | |
3087 { | |
3088 EMSG(_(e_nomatch)); | |
3089 goto theend; | |
3090 } | |
3091 | |
1411 | 3092 /* Remember the current directory, because a BufRead autocommand that does |
3093 * ":lcd %:p:h" changes the meaning of short path names. */ | |
3094 mch_dirname(dirname_start, MAXPATHL); | |
3095 | |
123 | 3096 seconds = (time_t)0; |
716 | 3097 for (fi = 0; fi < fcount && !got_int && tomatch > 0; ++fi) |
41 | 3098 { |
1411 | 3099 fname = shorten_fname1(fnames[fi]); |
123 | 3100 if (time(NULL) > seconds) |
3101 { | |
1411 | 3102 /* Display the file name every second or so, show the user we are |
3103 * working on it. */ | |
123 | 3104 seconds = time(NULL); |
3105 msg_start(); | |
1411 | 3106 p = msg_strtrunc(fname, TRUE); |
123 | 3107 if (p == NULL) |
1411 | 3108 msg_outtrans(fname); |
123 | 3109 else |
3110 { | |
3111 msg_outtrans(p); | |
3112 vim_free(p); | |
3113 } | |
3114 msg_clr_eos(); | |
3115 msg_didout = FALSE; /* overwrite this message */ | |
3116 msg_nowait = TRUE; /* don't wait for this message */ | |
3117 msg_col = 0; | |
3118 out_flush(); | |
3119 } | |
3120 | |
42 | 3121 buf = buflist_findname_exp(fnames[fi]); |
3122 if (buf == NULL || buf->b_ml.ml_mfp == NULL) | |
3123 { | |
3124 /* Remember that a buffer with this name already exists. */ | |
3125 duplicate_name = (buf != NULL); | |
123 | 3126 using_dummy = TRUE; |
1396 | 3127 redraw_for_dummy = TRUE; |
123 | 3128 |
3129 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) | |
3130 /* Don't do Filetype autocommands to avoid loading syntax and | |
3131 * indent scripts, a great speed improvement. */ | |
3132 save_ei = au_event_disable(",Filetype"); | |
3133 #endif | |
677 | 3134 /* Don't use modelines here, it's useless. */ |
3135 save_mls = p_mls; | |
3136 p_mls = 0; | |
42 | 3137 |
3138 /* Load file into a buffer, so that 'fileencoding' is detected, | |
3139 * autocommands applied, etc. */ | |
1411 | 3140 buf = load_dummy_buffer(fname); |
3141 | |
3142 /* When autocommands changed directory: go back. We assume it was | |
3143 * ":lcd %:p:h". */ | |
3144 mch_dirname(dirname_now, MAXPATHL); | |
3145 if (STRCMP(dirname_start, dirname_now) != 0) | |
3146 { | |
3147 exarg_T ea; | |
3148 | |
3149 ea.arg = dirname_start; | |
3150 ea.cmdidx = CMD_lcd; | |
3151 ex_cd(&ea); | |
3152 } | |
123 | 3153 |
677 | 3154 p_mls = save_mls; |
123 | 3155 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) |
3156 au_event_restore(save_ei); | |
3157 #endif | |
42 | 3158 } |
3159 else | |
3160 /* Use existing, loaded buffer. */ | |
3161 using_dummy = FALSE; | |
123 | 3162 |
42 | 3163 if (buf == NULL) |
123 | 3164 { |
3165 if (!got_int) | |
1411 | 3166 smsg((char_u *)_("Cannot open file \"%s\""), fname); |
123 | 3167 } |
41 | 3168 else |
3169 { | |
717 | 3170 /* Try for a match in all lines of the buffer. |
3171 * For ":1vimgrep" look for first match only. */ | |
42 | 3172 found_match = FALSE; |
716 | 3173 for (lnum = 1; lnum <= buf->b_ml.ml_line_count && tomatch > 0; |
3174 ++lnum) | |
41 | 3175 { |
170 | 3176 col = 0; |
3177 while (vim_regexec_multi(®match, curwin, buf, lnum, | |
1521 | 3178 col, NULL) > 0) |
41 | 3179 { |
1411 | 3180 ; |
644 | 3181 if (qf_add_entry(qi, &prevp, |
41 | 3182 NULL, /* dir */ |
1411 | 3183 fname, |
1065 | 3184 0, |
42 | 3185 ml_get_buf(buf, |
3186 regmatch.startpos[0].lnum + lnum, FALSE), | |
3187 regmatch.startpos[0].lnum + lnum, | |
3188 regmatch.startpos[0].col + 1, | |
170 | 3189 FALSE, /* vis_col */ |
230 | 3190 NULL, /* search pattern */ |
856 | 3191 0, /* nr */ |
3192 0, /* type */ | |
3193 TRUE /* valid */ | |
41 | 3194 ) == FAIL) |
3195 { | |
3196 got_int = TRUE; | |
3197 break; | |
3198 } | |
716 | 3199 found_match = TRUE; |
3200 if (--tomatch == 0) | |
3201 break; | |
170 | 3202 if ((flags & VGR_GLOBAL) == 0 |
3203 || regmatch.endpos[0].lnum > 0) | |
3204 break; | |
3205 col = regmatch.endpos[0].col | |
3206 + (col == regmatch.endpos[0].col); | |
1883 | 3207 if (col > (colnr_T)STRLEN(ml_get_buf(buf, lnum, FALSE))) |
170 | 3208 break; |
41 | 3209 } |
3210 line_breakcheck(); | |
42 | 3211 if (got_int) |
3212 break; | |
41 | 3213 } |
42 | 3214 |
3215 if (using_dummy) | |
3216 { | |
123 | 3217 if (found_match && first_match_buf == NULL) |
3218 first_match_buf = buf; | |
42 | 3219 if (duplicate_name) |
123 | 3220 { |
42 | 3221 /* Never keep a dummy buffer if there is another buffer |
3222 * with the same name. */ | |
3223 wipe_dummy_buffer(buf); | |
123 | 3224 buf = NULL; |
3225 } | |
717 | 3226 else if (!cmdmod.hide |
3227 || buf->b_p_bh[0] == 'u' /* "unload" */ | |
3228 || buf->b_p_bh[0] == 'w' /* "wipe" */ | |
3229 || buf->b_p_bh[0] == 'd') /* "delete" */ | |
42 | 3230 { |
717 | 3231 /* When no match was found we don't need to remember the |
3232 * buffer, wipe it out. If there was a match and it | |
3233 * wasn't the first one or we won't jump there: only | |
3234 * unload the buffer. | |
3235 * Ignore 'hidden' here, because it may lead to having too | |
3236 * many swap files. */ | |
42 | 3237 if (!found_match) |
123 | 3238 { |
42 | 3239 wipe_dummy_buffer(buf); |
123 | 3240 buf = NULL; |
3241 } | |
170 | 3242 else if (buf != first_match_buf || (flags & VGR_NOJUMP)) |
123 | 3243 { |
42 | 3244 unload_dummy_buffer(buf); |
123 | 3245 buf = NULL; |
3246 } | |
42 | 3247 } |
123 | 3248 |
3249 if (buf != NULL) | |
3250 { | |
1411 | 3251 /* If the buffer is still loaded we need to use the |
3252 * directory we jumped to below. */ | |
3253 if (buf == first_match_buf | |
3254 && target_dir == NULL | |
3255 && STRCMP(dirname_start, dirname_now) != 0) | |
3256 target_dir = vim_strsave(dirname_now); | |
3257 | |
123 | 3258 /* The buffer is still loaded, the Filetype autocommands |
677 | 3259 * need to be done now, in that buffer. And the modelines |
717 | 3260 * need to be done (again). But not the window-local |
3261 * options! */ | |
123 | 3262 aucmd_prepbuf(&aco, buf); |
677 | 3263 #if defined(FEAT_AUTOCMD) && defined(FEAT_SYN_HL) |
123 | 3264 apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, |
3265 buf->b_fname, TRUE, buf); | |
677 | 3266 #endif |
717 | 3267 do_modelines(OPT_NOWIN); |
123 | 3268 aucmd_restbuf(&aco); |
3269 } | |
42 | 3270 } |
41 | 3271 } |
3272 } | |
3273 | |
3274 FreeWild(fcount, fnames); | |
3275 | |
644 | 3276 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; |
3277 qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; | |
3278 qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
41 | 3279 |
3280 #ifdef FEAT_WINDOWS | |
644 | 3281 qf_update_buffer(qi); |
41 | 3282 #endif |
3283 | |
842 | 3284 #ifdef FEAT_AUTOCMD |
3285 if (au_name != NULL) | |
3286 apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, | |
3287 curbuf->b_fname, TRUE, curbuf); | |
3288 #endif | |
3289 | |
41 | 3290 /* Jump to first match. */ |
644 | 3291 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) |
170 | 3292 { |
3293 if ((flags & VGR_NOJUMP) == 0) | |
1396 | 3294 { |
3295 buf = curbuf; | |
659 | 3296 qf_jump(qi, 0, 0, eap->forceit); |
1396 | 3297 if (buf != curbuf) |
3298 /* If we jumped to another buffer redrawing will already be | |
3299 * taken care of. */ | |
3300 redraw_for_dummy = FALSE; | |
1411 | 3301 |
3302 /* Jump to the directory used after loading the buffer. */ | |
3303 if (curbuf == first_match_buf && target_dir != NULL) | |
3304 { | |
3305 exarg_T ea; | |
3306 | |
3307 ea.arg = target_dir; | |
3308 ea.cmdidx = CMD_lcd; | |
3309 ex_cd(&ea); | |
3310 } | |
1396 | 3311 } |
170 | 3312 } |
42 | 3313 else |
3314 EMSG2(_(e_nomatch2), s); | |
41 | 3315 |
1396 | 3316 /* If we loaded a dummy buffer into the current window, the autocommands |
3317 * may have messed up things, need to redraw and recompute folds. */ | |
3318 if (redraw_for_dummy) | |
3319 { | |
3320 #ifdef FEAT_FOLDING | |
3321 foldUpdateAll(curwin); | |
3322 #else | |
3323 redraw_later(NOT_VALID); | |
3324 #endif | |
3325 } | |
3326 | |
41 | 3327 theend: |
1411 | 3328 vim_free(target_dir); |
41 | 3329 vim_free(regmatch.regprog); |
3330 } | |
3331 | |
3332 /* | |
170 | 3333 * Skip over the pattern argument of ":vimgrep /pat/[g][j]". |
153 | 3334 * Put the start of the pattern in "*s", unless "s" is NULL. |
170 | 3335 * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. |
3336 * If "s" is not NULL terminate the pattern with a NUL. | |
3337 * Return a pointer to the char just past the pattern plus flags. | |
153 | 3338 */ |
3339 char_u * | |
170 | 3340 skip_vimgrep_pat(p, s, flags) |
3341 char_u *p; | |
3342 char_u **s; | |
3343 int *flags; | |
153 | 3344 { |
3345 int c; | |
3346 | |
3347 if (vim_isIDc(*p)) | |
3348 { | |
170 | 3349 /* ":vimgrep pattern fname" */ |
153 | 3350 if (s != NULL) |
3351 *s = p; | |
170 | 3352 p = skiptowhite(p); |
3353 if (s != NULL && *p != NUL) | |
3354 *p++ = NUL; | |
153 | 3355 } |
170 | 3356 else |
3357 { | |
3358 /* ":vimgrep /pattern/[g][j] fname" */ | |
3359 if (s != NULL) | |
3360 *s = p + 1; | |
3361 c = *p; | |
3362 p = skip_regexp(p + 1, c, TRUE, NULL); | |
3363 if (*p != c) | |
3364 return NULL; | |
3365 | |
3366 /* Truncate the pattern. */ | |
3367 if (s != NULL) | |
3368 *p = NUL; | |
3369 ++p; | |
3370 | |
3371 /* Find the flags */ | |
3372 while (*p == 'g' || *p == 'j') | |
3373 { | |
3374 if (flags != NULL) | |
3375 { | |
3376 if (*p == 'g') | |
3377 *flags |= VGR_GLOBAL; | |
3378 else | |
3379 *flags |= VGR_NOJUMP; | |
3380 } | |
3381 ++p; | |
3382 } | |
3383 } | |
153 | 3384 return p; |
3385 } | |
3386 | |
3387 /* | |
42 | 3388 * Load file "fname" into a dummy buffer and return the buffer pointer. |
3389 * Returns NULL if it fails. | |
3390 * Must call unload_dummy_buffer() or wipe_dummy_buffer() later! | |
3391 */ | |
3392 static buf_T * | |
3393 load_dummy_buffer(fname) | |
3394 char_u *fname; | |
3395 { | |
3396 buf_T *newbuf; | |
3397 int failed = TRUE; | |
3398 aco_save_T aco; | |
3399 | |
3400 /* Allocate a buffer without putting it in the buffer list. */ | |
3401 newbuf = buflist_new(NULL, NULL, (linenr_T)1, BLN_DUMMY); | |
3402 if (newbuf == NULL) | |
3403 return NULL; | |
3404 | |
177 | 3405 /* Init the options. */ |
3406 buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP); | |
3407 | |
1918 | 3408 /* need to open the memfile before putting the buffer in a window */ |
3409 if (ml_open(newbuf) == OK) | |
42 | 3410 { |
1918 | 3411 /* set curwin/curbuf to buf and save a few things */ |
3412 aucmd_prepbuf(&aco, newbuf); | |
3413 | |
3414 /* Need to set the filename for autocommands. */ | |
3415 (void)setfname(curbuf, fname, NULL, FALSE); | |
3416 | |
42 | 3417 /* Create swap file now to avoid the ATTENTION message. */ |
3418 check_need_swap(TRUE); | |
3419 | |
3420 /* Remove the "dummy" flag, otherwise autocommands may not | |
3421 * work. */ | |
3422 curbuf->b_flags &= ~BF_DUMMY; | |
3423 | |
3424 if (readfile(fname, NULL, | |
3425 (linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, | |
3426 NULL, READ_NEW | READ_DUMMY) == OK | |
857 | 3427 && !got_int |
42 | 3428 && !(curbuf->b_flags & BF_NEW)) |
3429 { | |
3430 failed = FALSE; | |
3431 if (curbuf != newbuf) | |
3432 { | |
3433 /* Bloody autocommands changed the buffer! */ | |
3434 if (buf_valid(newbuf)) | |
3435 wipe_buffer(newbuf, FALSE); | |
3436 newbuf = curbuf; | |
3437 } | |
3438 } | |
1918 | 3439 |
3440 /* restore curwin/curbuf and a few other things */ | |
3441 aucmd_restbuf(&aco); | |
42 | 3442 } |
3443 | |
3444 if (!buf_valid(newbuf)) | |
3445 return NULL; | |
3446 if (failed) | |
3447 { | |
3448 wipe_dummy_buffer(newbuf); | |
3449 return NULL; | |
3450 } | |
3451 return newbuf; | |
3452 } | |
3453 | |
3454 /* | |
3455 * Wipe out the dummy buffer that load_dummy_buffer() created. | |
3456 */ | |
3457 static void | |
3458 wipe_dummy_buffer(buf) | |
3459 buf_T *buf; | |
3460 { | |
3461 if (curbuf != buf) /* safety check */ | |
857 | 3462 { |
3463 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) | |
3464 cleanup_T cs; | |
3465 | |
3466 /* Reset the error/interrupt/exception state here so that aborting() | |
3467 * returns FALSE when wiping out the buffer. Otherwise it doesn't | |
3468 * work when got_int is set. */ | |
3469 enter_cleanup(&cs); | |
3470 #endif | |
3471 | |
42 | 3472 wipe_buffer(buf, FALSE); |
857 | 3473 |
3474 #if defined(FEAT_AUTOCMD) && defined(FEAT_EVAL) | |
3475 /* Restore the error/interrupt/exception state if not discarded by a | |
3476 * new aborting error, interrupt, or uncaught exception. */ | |
3477 leave_cleanup(&cs); | |
3478 #endif | |
3479 } | |
42 | 3480 } |
3481 | |
3482 /* | |
3483 * Unload the dummy buffer that load_dummy_buffer() created. | |
3484 */ | |
3485 static void | |
3486 unload_dummy_buffer(buf) | |
3487 buf_T *buf; | |
3488 { | |
3489 if (curbuf != buf) /* safety check */ | |
3490 close_buffer(NULL, buf, DOBUF_UNLOAD); | |
3491 } | |
3492 | |
170 | 3493 #if defined(FEAT_EVAL) || defined(PROTO) |
3494 /* | |
3495 * Add each quickfix error to list "list" as a dictionary. | |
3496 */ | |
3497 int | |
647 | 3498 get_errorlist(wp, list) |
3499 win_T *wp; | |
170 | 3500 list_T *list; |
3501 { | |
644 | 3502 qf_info_T *qi = &ql_info; |
230 | 3503 dict_T *dict; |
3504 char_u buf[2]; | |
3505 qfline_T *qfp; | |
3506 int i; | |
1065 | 3507 int bufnum; |
170 | 3508 |
647 | 3509 if (wp != NULL) |
3510 { | |
3511 qi = GET_LOC_LIST(wp); | |
3512 if (qi == NULL) | |
3513 return FAIL; | |
3514 } | |
3515 | |
644 | 3516 if (qi->qf_curlist >= qi->qf_listcount |
712 | 3517 || qi->qf_lists[qi->qf_curlist].qf_count == 0) |
170 | 3518 return FAIL; |
3519 | |
644 | 3520 qfp = qi->qf_lists[qi->qf_curlist].qf_start; |
3521 for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ++i) | |
170 | 3522 { |
1065 | 3523 /* Handle entries with a non-existing buffer number. */ |
3524 bufnum = qfp->qf_fnum; | |
3525 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) | |
3526 bufnum = 0; | |
3527 | |
170 | 3528 if ((dict = dict_alloc()) == NULL) |
3529 return FAIL; | |
3530 if (list_append_dict(list, dict) == FAIL) | |
3531 return FAIL; | |
3532 | |
3533 buf[0] = qfp->qf_type; | |
3534 buf[1] = NUL; | |
1065 | 3535 if ( dict_add_nr_str(dict, "bufnr", (long)bufnum, NULL) == FAIL |
170 | 3536 || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL |
3537 || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL | |
3538 || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL | |
3539 || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL | |
960 | 3540 || dict_add_nr_str(dict, "pattern", 0L, |
3541 qfp->qf_pattern == NULL ? (char_u *)"" : qfp->qf_pattern) == FAIL | |
3542 || dict_add_nr_str(dict, "text", 0L, | |
3543 qfp->qf_text == NULL ? (char_u *)"" : qfp->qf_text) == FAIL | |
170 | 3544 || dict_add_nr_str(dict, "type", 0L, buf) == FAIL |
3545 || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL) | |
3546 return FAIL; | |
3547 | |
3548 qfp = qfp->qf_next; | |
3549 } | |
3550 return OK; | |
3551 } | |
230 | 3552 |
3553 /* | |
3554 * Populate the quickfix list with the items supplied in the list | |
3555 * of dictionaries. | |
3556 */ | |
3557 int | |
647 | 3558 set_errorlist(wp, list, action) |
3559 win_T *wp; | |
230 | 3560 list_T *list; |
277 | 3561 int action; |
230 | 3562 { |
3563 listitem_T *li; | |
3564 dict_T *d; | |
3565 char_u *filename, *pattern, *text, *type; | |
1065 | 3566 int bufnum; |
230 | 3567 long lnum; |
3568 int col, nr; | |
3569 int vcol; | |
3570 qfline_T *prevp = NULL; | |
3571 int valid, status; | |
3572 int retval = OK; | |
644 | 3573 qf_info_T *qi = &ql_info; |
1065 | 3574 int did_bufnr_emsg = FALSE; |
644 | 3575 |
647 | 3576 if (wp != NULL) |
3577 { | |
648 | 3578 qi = ll_get_or_alloc_list(wp); |
647 | 3579 if (qi == NULL) |
3580 return FAIL; | |
3581 } | |
3582 | |
644 | 3583 if (action == ' ' || qi->qf_curlist == qi->qf_listcount) |
277 | 3584 /* make place for a new list */ |
644 | 3585 qf_new_list(qi); |
3586 else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) | |
277 | 3587 /* Adding to existing list, find last entry. */ |
644 | 3588 for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; |
277 | 3589 prevp->qf_next != prevp; prevp = prevp->qf_next) |
3590 ; | |
3591 else if (action == 'r') | |
644 | 3592 qf_free(qi, qi->qf_curlist); |
230 | 3593 |
3594 for (li = list->lv_first; li != NULL; li = li->li_next) | |
3595 { | |
3596 if (li->li_tv.v_type != VAR_DICT) | |
3597 continue; /* Skip non-dict items */ | |
3598 | |
3599 d = li->li_tv.vval.v_dict; | |
3600 if (d == NULL) | |
3601 continue; | |
3602 | |
659 | 3603 filename = get_dict_string(d, (char_u *)"filename", TRUE); |
1065 | 3604 bufnum = get_dict_number(d, (char_u *)"bufnr"); |
230 | 3605 lnum = get_dict_number(d, (char_u *)"lnum"); |
3606 col = get_dict_number(d, (char_u *)"col"); | |
3607 vcol = get_dict_number(d, (char_u *)"vcol"); | |
3608 nr = get_dict_number(d, (char_u *)"nr"); | |
659 | 3609 type = get_dict_string(d, (char_u *)"type", TRUE); |
3610 pattern = get_dict_string(d, (char_u *)"pattern", TRUE); | |
3611 text = get_dict_string(d, (char_u *)"text", TRUE); | |
230 | 3612 if (text == NULL) |
3613 text = vim_strsave((char_u *)""); | |
3614 | |
3615 valid = TRUE; | |
1065 | 3616 if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) |
230 | 3617 valid = FALSE; |
3618 | |
1065 | 3619 /* Mark entries with non-existing buffer number as not valid. Give the |
3620 * error message only once. */ | |
3621 if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) | |
3622 { | |
3623 if (!did_bufnr_emsg) | |
3624 { | |
3625 did_bufnr_emsg = TRUE; | |
3626 EMSGN(_("E92: Buffer %ld not found"), bufnum); | |
3627 } | |
3628 valid = FALSE; | |
3629 bufnum = 0; | |
3630 } | |
3631 | |
644 | 3632 status = qf_add_entry(qi, &prevp, |
230 | 3633 NULL, /* dir */ |
3634 filename, | |
1065 | 3635 bufnum, |
230 | 3636 text, |
3637 lnum, | |
3638 col, | |
3639 vcol, /* vis_col */ | |
3640 pattern, /* search pattern */ | |
3641 nr, | |
3642 type == NULL ? NUL : *type, | |
3643 valid); | |
3644 | |
3645 vim_free(filename); | |
3646 vim_free(pattern); | |
3647 vim_free(text); | |
3648 vim_free(type); | |
3649 | |
3650 if (status == FAIL) | |
3651 { | |
3652 retval = FAIL; | |
3653 break; | |
3654 } | |
3655 } | |
3656 | |
2146
c17a42da3920
updated for version 7.2.428
Bram Moolenaar <bram@zimbu.org>
parents:
2047
diff
changeset
|
3657 if (qi->qf_lists[qi->qf_curlist].qf_index == 0) |
c17a42da3920
updated for version 7.2.428
Bram Moolenaar <bram@zimbu.org>
parents:
2047
diff
changeset
|
3658 /* empty list or no valid entry */ |
c17a42da3920
updated for version 7.2.428
Bram Moolenaar <bram@zimbu.org>
parents:
2047
diff
changeset
|
3659 qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; |
c17a42da3920
updated for version 7.2.428
Bram Moolenaar <bram@zimbu.org>
parents:
2047
diff
changeset
|
3660 else |
c17a42da3920
updated for version 7.2.428
Bram Moolenaar <bram@zimbu.org>
parents:
2047
diff
changeset
|
3661 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; |
644 | 3662 qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; |
3663 qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
230 | 3664 |
3665 #ifdef FEAT_WINDOWS | |
644 | 3666 qf_update_buffer(qi); |
230 | 3667 #endif |
3668 | |
3669 return retval; | |
3670 } | |
170 | 3671 #endif |
3672 | |
42 | 3673 /* |
41 | 3674 * ":[range]cbuffer [bufnr]" command. |
657 | 3675 * ":[range]caddbuffer [bufnr]" command. |
798 | 3676 * ":[range]cgetbuffer [bufnr]" command. |
644 | 3677 * ":[range]lbuffer [bufnr]" command. |
657 | 3678 * ":[range]laddbuffer [bufnr]" command. |
798 | 3679 * ":[range]lgetbuffer [bufnr]" command. |
41 | 3680 */ |
3681 void | |
3682 ex_cbuffer(eap) | |
3683 exarg_T *eap; | |
3684 { | |
3685 buf_T *buf = NULL; | |
644 | 3686 qf_info_T *qi = &ql_info; |
3687 | |
798 | 3688 if (eap->cmdidx == CMD_lbuffer || eap->cmdidx == CMD_lgetbuffer |
3689 || eap->cmdidx == CMD_laddbuffer) | |
644 | 3690 { |
3691 qi = ll_get_or_alloc_list(curwin); | |
3692 if (qi == NULL) | |
3693 return; | |
3694 } | |
41 | 3695 |
3696 if (*eap->arg == NUL) | |
3697 buf = curbuf; | |
3698 else if (*skipwhite(skipdigits(eap->arg)) == NUL) | |
3699 buf = buflist_findnr(atoi((char *)eap->arg)); | |
3700 if (buf == NULL) | |
3701 EMSG(_(e_invarg)); | |
3702 else if (buf->b_ml.ml_mfp == NULL) | |
3703 EMSG(_("E681: Buffer is not loaded")); | |
3704 else | |
3705 { | |
3706 if (eap->addr_count == 0) | |
3707 { | |
3708 eap->line1 = 1; | |
3709 eap->line2 = buf->b_ml.ml_line_count; | |
3710 } | |
3711 if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count | |
3712 || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count) | |
3713 EMSG(_(e_invrange)); | |
3714 else | |
661 | 3715 { |
798 | 3716 if (qf_init_ext(qi, NULL, buf, NULL, p_efm, |
3717 (eap->cmdidx != CMD_caddbuffer | |
3718 && eap->cmdidx != CMD_laddbuffer), | |
661 | 3719 eap->line1, eap->line2) > 0 |
798 | 3720 && (eap->cmdidx == CMD_cbuffer |
3721 || eap->cmdidx == CMD_lbuffer)) | |
661 | 3722 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ |
3723 } | |
41 | 3724 } |
3725 } | |
3726 | |
532 | 3727 #if defined(FEAT_EVAL) || defined(PROTO) |
41 | 3728 /* |
798 | 3729 * ":cexpr {expr}", ":cgetexpr {expr}", ":caddexpr {expr}" command. |
3730 * ":lexpr {expr}", ":lgetexpr {expr}", ":laddexpr {expr}" command. | |
446 | 3731 */ |
3732 void | |
3733 ex_cexpr(eap) | |
3734 exarg_T *eap; | |
3735 { | |
3736 typval_T *tv; | |
644 | 3737 qf_info_T *qi = &ql_info; |
3738 | |
798 | 3739 if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_lgetexpr |
3740 || eap->cmdidx == CMD_laddexpr) | |
644 | 3741 { |
3742 qi = ll_get_or_alloc_list(curwin); | |
3743 if (qi == NULL) | |
3744 return; | |
3745 } | |
446 | 3746 |
625 | 3747 /* Evaluate the expression. When the result is a string or a list we can |
3748 * use it to fill the errorlist. */ | |
446 | 3749 tv = eval_expr(eap->arg, NULL); |
625 | 3750 if (tv != NULL) |
3751 { | |
3752 if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) | |
3753 || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL)) | |
3754 { | |
798 | 3755 if (qf_init_ext(qi, NULL, NULL, tv, p_efm, |
3756 (eap->cmdidx != CMD_caddexpr | |
3757 && eap->cmdidx != CMD_laddexpr), | |
625 | 3758 (linenr_T)0, (linenr_T)0) > 0 |
798 | 3759 && (eap->cmdidx == CMD_cexpr |
3760 || eap->cmdidx == CMD_lexpr)) | |
659 | 3761 qf_jump(qi, 0, 0, eap->forceit); /* display first error */ |
625 | 3762 } |
3763 else | |
626 | 3764 EMSG(_("E777: String or List expected")); |
625 | 3765 free_tv(tv); |
3766 } | |
446 | 3767 } |
532 | 3768 #endif |
446 | 3769 |
3770 /* | |
7 | 3771 * ":helpgrep {pattern}" |
3772 */ | |
3773 void | |
3774 ex_helpgrep(eap) | |
3775 exarg_T *eap; | |
3776 { | |
3777 regmatch_T regmatch; | |
3778 char_u *save_cpo; | |
3779 char_u *p; | |
3780 int fcount; | |
3781 char_u **fnames; | |
3782 FILE *fd; | |
3783 int fi; | |
230 | 3784 qfline_T *prevp = NULL; |
7 | 3785 long lnum; |
9 | 3786 #ifdef FEAT_MULTI_LANG |
3787 char_u *lang; | |
3788 #endif | |
644 | 3789 qf_info_T *qi = &ql_info; |
659 | 3790 int new_qi = FALSE; |
3791 win_T *wp; | |
7 | 3792 |
3793 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
3794 save_cpo = p_cpo; | |
1672 | 3795 p_cpo = empty_option; |
7 | 3796 |
9 | 3797 #ifdef FEAT_MULTI_LANG |
3798 /* Check for a specified language */ | |
3799 lang = check_help_lang(eap->arg); | |
3800 #endif | |
3801 | |
659 | 3802 if (eap->cmdidx == CMD_lhelpgrep) |
3803 { | |
3804 /* Find an existing help window */ | |
3805 FOR_ALL_WINDOWS(wp) | |
3806 if (wp->w_buffer != NULL && wp->w_buffer->b_help) | |
3807 break; | |
3808 | |
3809 if (wp == NULL) /* Help window not found */ | |
3810 qi = NULL; | |
3811 else | |
3812 qi = wp->w_llist; | |
3813 | |
3814 if (qi == NULL) | |
3815 { | |
3816 /* Allocate a new location list for help text matches */ | |
3817 if ((qi = ll_new_list()) == NULL) | |
3818 return; | |
3819 new_qi = TRUE; | |
3820 } | |
3821 } | |
3822 | |
7 | 3823 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); |
3824 regmatch.rm_ic = FALSE; | |
3825 if (regmatch.regprog != NULL) | |
3826 { | |
3827 /* create a new quickfix list */ | |
644 | 3828 qf_new_list(qi); |
7 | 3829 |
3830 /* Go through all directories in 'runtimepath' */ | |
3831 p = p_rtp; | |
3832 while (*p != NUL && !got_int) | |
3833 { | |
3834 copy_option_part(&p, NameBuff, MAXPATHL, ","); | |
3835 | |
3836 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */ | |
3837 add_pathsep(NameBuff); | |
3838 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)"); | |
3839 if (gen_expand_wildcards(1, &NameBuff, &fcount, | |
3840 &fnames, EW_FILE|EW_SILENT) == OK | |
3841 && fcount > 0) | |
3842 { | |
3843 for (fi = 0; fi < fcount && !got_int; ++fi) | |
3844 { | |
9 | 3845 #ifdef FEAT_MULTI_LANG |
3846 /* Skip files for a different language. */ | |
3847 if (lang != NULL | |
3848 && STRNICMP(lang, fnames[fi] | |
3849 + STRLEN(fnames[fi]) - 3, 2) != 0 | |
3850 && !(STRNICMP(lang, "en", 2) == 0 | |
3851 && STRNICMP("txt", fnames[fi] | |
3852 + STRLEN(fnames[fi]) - 3, 3) == 0)) | |
3853 continue; | |
3854 #endif | |
531 | 3855 fd = mch_fopen((char *)fnames[fi], "r"); |
7 | 3856 if (fd != NULL) |
3857 { | |
3858 lnum = 1; | |
3859 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) | |
3860 { | |
3861 if (vim_regexec(®match, IObuff, (colnr_T)0)) | |
3862 { | |
835 | 3863 int l = (int)STRLEN(IObuff); |
7 | 3864 |
3865 /* remove trailing CR, LF, spaces, etc. */ | |
3866 while (l > 0 && IObuff[l - 1] <= ' ') | |
3867 IObuff[--l] = NUL; | |
3868 | |
644 | 3869 if (qf_add_entry(qi, &prevp, |
7 | 3870 NULL, /* dir */ |
3871 fnames[fi], | |
1065 | 3872 0, |
7 | 3873 IObuff, |
3874 lnum, | |
42 | 3875 (int)(regmatch.startp[0] - IObuff) |
3876 + 1, /* col */ | |
170 | 3877 FALSE, /* vis_col */ |
230 | 3878 NULL, /* search pattern */ |
7 | 3879 0, /* nr */ |
3880 1, /* type */ | |
3881 TRUE /* valid */ | |
3882 ) == FAIL) | |
3883 { | |
3884 got_int = TRUE; | |
3885 break; | |
3886 } | |
3887 } | |
3888 ++lnum; | |
3889 line_breakcheck(); | |
3890 } | |
3891 fclose(fd); | |
3892 } | |
3893 } | |
3894 FreeWild(fcount, fnames); | |
3895 } | |
3896 } | |
3897 vim_free(regmatch.regprog); | |
3898 | |
644 | 3899 qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; |
3900 qi->qf_lists[qi->qf_curlist].qf_ptr = | |
3901 qi->qf_lists[qi->qf_curlist].qf_start; | |
3902 qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
7 | 3903 } |
3904 | |
1672 | 3905 if (p_cpo == empty_option) |
3906 p_cpo = save_cpo; | |
3907 else | |
3908 /* Darn, some plugin changed the value. */ | |
3909 free_string_option(save_cpo); | |
7 | 3910 |
3911 #ifdef FEAT_WINDOWS | |
644 | 3912 qf_update_buffer(qi); |
7 | 3913 #endif |
3914 | |
3915 /* Jump to first match. */ | |
644 | 3916 if (qi->qf_lists[qi->qf_curlist].qf_count > 0) |
659 | 3917 qf_jump(qi, 0, 0, FALSE); |
9 | 3918 else |
3919 EMSG2(_(e_nomatch2), eap->arg); | |
659 | 3920 |
3921 if (eap->cmdidx == CMD_lhelpgrep) | |
3922 { | |
3923 /* If the help window is not opened or if it already points to the | |
661 | 3924 * correct location list, then free the new location list. */ |
659 | 3925 if (!curwin->w_buffer->b_help || curwin->w_llist == qi) |
3926 { | |
3927 if (new_qi) | |
3928 ll_free_all(&qi); | |
3929 } | |
3930 else if (curwin->w_llist == NULL) | |
3931 curwin->w_llist = qi; | |
3932 } | |
7 | 3933 } |
3934 | |
3935 #endif /* FEAT_QUICKFIX */ |