Mercurial > vim
comparison src/quickfix.c @ 7:3fc0f57ecb91 v7.0001
updated for version 7.0001
author | vimboss |
---|---|
date | Sun, 13 Jun 2004 20:20:40 +0000 |
parents | |
children | 4102fb4ea781 |
comparison
equal
deleted
inserted
replaced
6:c2daee826b8f | 7:3fc0f57ecb91 |
---|---|
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 /* | |
27 * for each error the next struct is allocated and linked in a list | |
28 */ | |
29 struct qf_line | |
30 { | |
31 struct qf_line *qf_next; /* pointer to next error in the list */ | |
32 struct qf_line *qf_prev; /* pointer to previous error in the list */ | |
33 linenr_T qf_lnum; /* line number where the error occurred */ | |
34 int qf_fnum; /* file number for the line */ | |
35 int qf_col; /* column where the error occurred */ | |
36 int qf_nr; /* error number */ | |
37 char_u *qf_text; /* description of the error */ | |
38 char_u qf_virt_col; /* set to TRUE if qf_col is screen column */ | |
39 char_u qf_cleared;/* set to TRUE if line has been deleted */ | |
40 char_u qf_type; /* type of the error (mostly 'E'); 1 for | |
41 :helpgrep */ | |
42 char_u qf_valid; /* valid error message detected */ | |
43 }; | |
44 | |
45 /* | |
46 * There is a stack of error lists. | |
47 */ | |
48 #define LISTCOUNT 10 | |
49 | |
50 struct qf_list | |
51 { | |
52 struct qf_line *qf_start; /* pointer to the first error */ | |
53 struct qf_line *qf_ptr; /* pointer to the current error */ | |
54 int qf_count; /* number of errors (0 means no error list) */ | |
55 int qf_index; /* current index in the error list */ | |
56 int qf_nonevalid; /* TRUE if not a single valid entry found */ | |
57 } qf_lists[LISTCOUNT]; | |
58 | |
59 static int qf_curlist = 0; /* current error list */ | |
60 static int qf_listcount = 0; /* current number of lists */ | |
61 | |
62 #define FMT_PATTERNS 9 /* maximum number of % recognized */ | |
63 | |
64 /* | |
65 * Structure used to hold the info of one part of 'errorformat' | |
66 */ | |
67 struct eformat | |
68 { | |
69 regprog_T *prog; /* pre-formatted part of 'errorformat' */ | |
70 struct eformat *next; /* pointer to next (NULL if last) */ | |
71 char_u addr[FMT_PATTERNS]; /* indices of used % patterns */ | |
72 char_u prefix; /* prefix of this format line: */ | |
73 /* 'D' enter directory */ | |
74 /* 'X' leave directory */ | |
75 /* 'A' start of multi-line message */ | |
76 /* 'E' error message */ | |
77 /* 'W' warning message */ | |
78 /* 'I' informational message */ | |
79 /* 'C' continuation line */ | |
80 /* 'Z' end of multi-line message */ | |
81 /* 'G' general, unspecific message */ | |
82 /* 'P' push file (partial) message */ | |
83 /* 'Q' pop/quit file (partial) message */ | |
84 /* 'O' overread (partial) message */ | |
85 char_u flags; /* additional flags given in prefix */ | |
86 /* '-' do not include this line */ | |
87 }; | |
88 | |
89 static void qf_new_list __ARGS((void)); | |
90 static int qf_add_entry __ARGS((struct qf_line **prevp, char_u *dir, char_u *fname, char_u *mesg, long lnum, int col, int virt_col, int nr, int type, int valid)); | |
91 static void qf_msg __ARGS((void)); | |
92 static void qf_free __ARGS((int idx)); | |
93 static char_u *qf_types __ARGS((int, int)); | |
94 static int qf_get_fnum __ARGS((char_u *, char_u *)); | |
95 static char_u *qf_push_dir __ARGS((char_u *, struct dir_stack_T **)); | |
96 static char_u *qf_pop_dir __ARGS((struct dir_stack_T **)); | |
97 static char_u *qf_guess_filepath __ARGS((char_u *)); | |
98 static void qf_fmt_text __ARGS((char_u *text, char_u *buf, int bufsize)); | |
99 static void qf_clean_dir_stack __ARGS((struct dir_stack_T **)); | |
100 #ifdef FEAT_WINDOWS | |
101 static int qf_win_pos_update __ARGS((int old_qf_index)); | |
102 static buf_T *qf_find_buf __ARGS((void)); | |
103 static void qf_update_buffer __ARGS((void)); | |
104 static void qf_fill_buffer __ARGS((void)); | |
105 #endif | |
106 static char_u *get_mef_name __ARGS((void)); | |
107 | |
108 /* | |
109 * Read the errorfile into memory, line by line, building the error list. | |
110 * Return -1 for error, number of errors for success. | |
111 */ | |
112 int | |
113 qf_init(efile, errorformat, newlist) | |
114 char_u *efile; | |
115 char_u *errorformat; | |
116 int newlist; /* TRUE: start a new error list */ | |
117 { | |
118 char_u *namebuf; | |
119 char_u *errmsg; | |
120 char_u *fmtstr = NULL; | |
121 int col = 0; | |
122 char_u use_virt_col = FALSE; | |
123 int type = 0; | |
124 int valid; | |
125 long lnum = 0L; | |
126 int enr = 0; | |
127 FILE *fd; | |
128 struct qf_line *qfprev = NULL; /* init to make SASC shut up */ | |
129 char_u *efmp; | |
130 struct eformat *fmt_first = NULL; | |
131 struct eformat *fmt_last = NULL; | |
132 struct eformat *fmt_ptr; | |
133 char_u *efm; | |
134 char_u *ptr; | |
135 char_u *srcptr; | |
136 int len; | |
137 int i; | |
138 int round; | |
139 int idx = 0; | |
140 int multiline = FALSE; | |
141 int multiignore = FALSE; | |
142 int multiscan = FALSE; | |
143 int retval = -1; /* default: return error flag */ | |
144 char_u *directory = NULL; | |
145 char_u *currfile = NULL; | |
146 char_u *tail = NULL; | |
147 struct dir_stack_T *file_stack = NULL; | |
148 regmatch_T regmatch; | |
149 static struct fmtpattern | |
150 { | |
151 char_u convchar; | |
152 char *pattern; | |
153 } fmt_pat[FMT_PATTERNS] = | |
154 { | |
155 {'f', "\\f\\+"}, | |
156 {'n', "\\d\\+"}, | |
157 {'l', "\\d\\+"}, | |
158 {'c', "\\d\\+"}, | |
159 {'t', "."}, | |
160 {'m', ".\\+"}, | |
161 {'r', ".*"}, | |
162 {'p', "[- .]*"}, | |
163 {'v', "\\d\\+"} | |
164 }; | |
165 | |
166 if (efile == NULL) | |
167 return FAIL; | |
168 | |
169 namebuf = alloc(CMDBUFFSIZE + 1); | |
170 errmsg = alloc(CMDBUFFSIZE + 1); | |
171 if (namebuf == NULL || errmsg == NULL) | |
172 goto qf_init_end; | |
173 | |
174 if ((fd = mch_fopen((char *)efile, "r")) == NULL) | |
175 { | |
176 EMSG2(_(e_openerrf), efile); | |
177 goto qf_init_end; | |
178 } | |
179 | |
180 if (newlist || qf_curlist == qf_listcount) | |
181 /* make place for a new list */ | |
182 qf_new_list(); | |
183 else if (qf_lists[qf_curlist].qf_count > 0) | |
184 /* Adding to existing list, find last entry. */ | |
185 for (qfprev = qf_lists[qf_curlist].qf_start; | |
186 qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) | |
187 ; | |
188 | |
189 /* | |
190 * Each part of the format string is copied and modified from errorformat to | |
191 * regex prog. Only a few % characters are allowed. | |
192 */ | |
193 /* Use the local value of 'errorformat' if it's set. */ | |
194 if (errorformat == p_efm && *curbuf->b_p_efm != NUL) | |
195 efm = curbuf->b_p_efm; | |
196 else | |
197 efm = errorformat; | |
198 /* | |
199 * Get some space to modify the format string into. | |
200 */ | |
201 i = (FMT_PATTERNS * 3) + ((int)STRLEN(efm) << 2); | |
202 for (round = FMT_PATTERNS; round > 0; ) | |
203 i += (int)STRLEN(fmt_pat[--round].pattern); | |
204 #ifdef COLON_IN_FILENAME | |
205 i += 12; /* "%f" can become twelve chars longer */ | |
206 #else | |
207 i += 2; /* "%f" can become two chars longer */ | |
208 #endif | |
209 if ((fmtstr = alloc(i)) == NULL) | |
210 goto error2; | |
211 | |
212 while (efm[0]) | |
213 { | |
214 /* | |
215 * Allocate a new eformat structure and put it at the end of the list | |
216 */ | |
217 fmt_ptr = (struct eformat *)alloc((unsigned)sizeof(struct eformat)); | |
218 if (fmt_ptr == NULL) | |
219 goto error2; | |
220 if (fmt_first == NULL) /* first one */ | |
221 fmt_first = fmt_ptr; | |
222 else | |
223 fmt_last->next = fmt_ptr; | |
224 fmt_last = fmt_ptr; | |
225 fmt_ptr->prefix = NUL; | |
226 fmt_ptr->flags = NUL; | |
227 fmt_ptr->next = NULL; | |
228 fmt_ptr->prog = NULL; | |
229 for (round = FMT_PATTERNS; round > 0; ) | |
230 fmt_ptr->addr[--round] = NUL; | |
231 /* round is 0 now */ | |
232 | |
233 /* | |
234 * Isolate one part in the 'errorformat' option | |
235 */ | |
236 for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) | |
237 if (efm[len] == '\\' && efm[len + 1] != NUL) | |
238 ++len; | |
239 | |
240 /* | |
241 * Build regexp pattern from current 'errorformat' option | |
242 */ | |
243 ptr = fmtstr; | |
244 *ptr++ = '^'; | |
245 for (efmp = efm; efmp < efm + len; ++efmp) | |
246 { | |
247 if (*efmp == '%') | |
248 { | |
249 ++efmp; | |
250 for (idx = 0; idx < FMT_PATTERNS; ++idx) | |
251 if (fmt_pat[idx].convchar == *efmp) | |
252 break; | |
253 if (idx < FMT_PATTERNS) | |
254 { | |
255 if (fmt_ptr->addr[idx]) | |
256 { | |
257 sprintf((char *)errmsg, | |
258 _("E372: Too many %%%c in format string"), *efmp); | |
259 EMSG(errmsg); | |
260 goto error2; | |
261 } | |
262 if ((idx | |
263 && idx < 6 | |
264 && vim_strchr((char_u *)"DXOPQ", | |
265 fmt_ptr->prefix) != NULL) | |
266 || (idx == 6 | |
267 && vim_strchr((char_u *)"OPQ", | |
268 fmt_ptr->prefix) == NULL)) | |
269 { | |
270 sprintf((char *)errmsg, | |
271 _("E373: Unexpected %%%c in format string"), *efmp); | |
272 EMSG(errmsg); | |
273 goto error2; | |
274 } | |
275 fmt_ptr->addr[idx] = (char_u)++round; | |
276 *ptr++ = '\\'; | |
277 *ptr++ = '('; | |
278 #ifdef BACKSLASH_IN_FILENAME | |
279 if (*efmp == 'f') | |
280 { | |
281 /* Also match "c:" in the file name, even when | |
282 * checking for a colon next: "%f:". | |
283 * "\%(\a:\)\=" */ | |
284 STRCPY(ptr, "\\%(\\a:\\)\\="); | |
285 ptr += 10; | |
286 } | |
287 #endif | |
288 if (*efmp == 'f' && efmp[1] != NUL | |
289 && efmp[1] != '\\' && efmp[1] != '%') | |
290 { | |
291 /* A file name may contain spaces, but this isn't in | |
292 * "\f". use "[^x]\+" instead (x is next character) */ | |
293 *ptr++ = '['; | |
294 *ptr++ = '^'; | |
295 *ptr++ = efmp[1]; | |
296 *ptr++ = ']'; | |
297 *ptr++ = '\\'; | |
298 *ptr++ = '+'; | |
299 } | |
300 else | |
301 { | |
302 srcptr = (char_u *)fmt_pat[idx].pattern; | |
303 while ((*ptr = *srcptr++) != NUL) | |
304 ++ptr; | |
305 } | |
306 *ptr++ = '\\'; | |
307 *ptr++ = ')'; | |
308 } | |
309 else if (*efmp == '*') | |
310 { | |
311 if (*++efmp == '[' || *efmp == '\\') | |
312 { | |
313 if ((*ptr++ = *efmp) == '[') /* %*[^a-z0-9] etc. */ | |
314 { | |
315 if (efmp[1] == '^') | |
316 *ptr++ = *++efmp; | |
317 if (efmp < efm + len) | |
318 { | |
319 *ptr++ = *++efmp; /* could be ']' */ | |
320 while (efmp < efm + len | |
321 && (*ptr++ = *++efmp) != ']') | |
322 /* skip */; | |
323 if (efmp == efm + len) | |
324 { | |
325 EMSG(_("E374: Missing ] in format string")); | |
326 goto error2; | |
327 } | |
328 } | |
329 } | |
330 else if (efmp < efm + len) /* %*\D, %*\s etc. */ | |
331 *ptr++ = *++efmp; | |
332 *ptr++ = '\\'; | |
333 *ptr++ = '+'; | |
334 } | |
335 else | |
336 { | |
337 /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ | |
338 sprintf((char *)errmsg, | |
339 _("E375: Unsupported %%%c in format string"), *efmp); | |
340 EMSG(errmsg); | |
341 goto error2; | |
342 } | |
343 } | |
344 else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) | |
345 *ptr++ = *efmp; /* regexp magic characters */ | |
346 else if (*efmp == '#') | |
347 *ptr++ = '*'; | |
348 else if (efmp == efm + 1) /* analyse prefix */ | |
349 { | |
350 if (vim_strchr((char_u *)"+-", *efmp) != NULL) | |
351 fmt_ptr->flags = *efmp++; | |
352 if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) | |
353 fmt_ptr->prefix = *efmp; | |
354 else | |
355 { | |
356 sprintf((char *)errmsg, | |
357 _("E376: Invalid %%%c in format string prefix"), *efmp); | |
358 EMSG(errmsg); | |
359 goto error2; | |
360 } | |
361 } | |
362 else | |
363 { | |
364 sprintf((char *)errmsg, | |
365 _("E377: Invalid %%%c in format string"), *efmp); | |
366 EMSG(errmsg); | |
367 goto error2; | |
368 } | |
369 } | |
370 else /* copy normal character */ | |
371 { | |
372 if (*efmp == '\\' && efmp + 1 < efm + len) | |
373 ++efmp; | |
374 else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) | |
375 *ptr++ = '\\'; /* escape regexp atoms */ | |
376 if (*efmp) | |
377 *ptr++ = *efmp; | |
378 } | |
379 } | |
380 *ptr++ = '$'; | |
381 *ptr = NUL; | |
382 if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) | |
383 goto error2; | |
384 /* | |
385 * Advance to next part | |
386 */ | |
387 efm = skip_to_option_part(efm + len); /* skip comma and spaces */ | |
388 } | |
389 if (fmt_first == NULL) /* nothing found */ | |
390 { | |
391 EMSG(_("E378: 'errorformat' contains no pattern")); | |
392 goto error2; | |
393 } | |
394 | |
395 /* | |
396 * got_int is reset here, because it was probably set when killing the | |
397 * ":make" command, but we still want to read the errorfile then. | |
398 */ | |
399 got_int = FALSE; | |
400 | |
401 /* Always ignore case when looking for a matching error. */ | |
402 regmatch.rm_ic = TRUE; | |
403 | |
404 /* | |
405 * Read the lines in the error file one by one. | |
406 * Try to recognize one of the error formats in each line. | |
407 */ | |
408 while (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) != NULL && !got_int) | |
409 { | |
410 IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ | |
411 if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) | |
412 *efmp = NUL; | |
413 #ifdef USE_CRNL | |
414 if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) | |
415 *efmp = NUL; | |
416 #endif | |
417 | |
418 /* | |
419 * Try to match each part of 'errorformat' until we find a complete | |
420 * match or no match. | |
421 */ | |
422 valid = TRUE; | |
423 restofline: | |
424 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) | |
425 { | |
426 idx = fmt_ptr->prefix; | |
427 if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) | |
428 continue; | |
429 namebuf[0] = NUL; | |
430 if (!multiscan) | |
431 errmsg[0] = NUL; | |
432 lnum = 0; | |
433 col = 0; | |
434 use_virt_col = FALSE; | |
435 enr = -1; | |
436 type = 0; | |
437 tail = NULL; | |
438 | |
439 regmatch.regprog = fmt_ptr->prog; | |
440 if (vim_regexec(®match, IObuff, (colnr_T)0)) | |
441 { | |
442 if ((idx == 'C' || idx == 'Z') && !multiline) | |
443 continue; | |
444 if (vim_strchr((char_u *)"EWI", idx) != NULL) | |
445 type = idx; | |
446 else | |
447 type = 0; | |
448 /* | |
449 * Extract error message data from matched line | |
450 */ | |
451 if ((i = (int)fmt_ptr->addr[0]) > 0) /* %f */ | |
452 { | |
453 len = (int)(regmatch.endp[i] - regmatch.startp[i]); | |
454 STRNCPY(namebuf, regmatch.startp[i], len); | |
455 namebuf[len] = NUL; | |
456 if (vim_strchr((char_u *)"OPQ", idx) != NULL | |
457 && mch_getperm(namebuf) == -1) | |
458 continue; | |
459 } | |
460 if ((i = (int)fmt_ptr->addr[1]) > 0) /* %n */ | |
461 enr = (int)atol((char *)regmatch.startp[i]); | |
462 if ((i = (int)fmt_ptr->addr[2]) > 0) /* %l */ | |
463 lnum = atol((char *)regmatch.startp[i]); | |
464 if ((i = (int)fmt_ptr->addr[3]) > 0) /* %c */ | |
465 col = (int)atol((char *)regmatch.startp[i]); | |
466 if ((i = (int)fmt_ptr->addr[4]) > 0) /* %t */ | |
467 type = *regmatch.startp[i]; | |
468 if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ | |
469 STRCPY(errmsg, IObuff); | |
470 else if ((i = (int)fmt_ptr->addr[5]) > 0) /* %m */ | |
471 { | |
472 len = (int)(regmatch.endp[i] - regmatch.startp[i]); | |
473 STRNCPY(errmsg, regmatch.startp[i], len); | |
474 errmsg[len] = NUL; | |
475 } | |
476 if ((i = (int)fmt_ptr->addr[6]) > 0) /* %r */ | |
477 tail = regmatch.startp[i]; | |
478 if ((i = (int)fmt_ptr->addr[7]) > 0) /* %p */ | |
479 { | |
480 col = (int)(regmatch.endp[i] - regmatch.startp[i] + 1); | |
481 if (*((char_u *)regmatch.startp[i]) != TAB) | |
482 use_virt_col = TRUE; | |
483 } | |
484 if ((i = (int)fmt_ptr->addr[8]) > 0) /* %v */ | |
485 { | |
486 col = (int)atol((char *)regmatch.startp[i]); | |
487 use_virt_col = TRUE; | |
488 } | |
489 break; | |
490 } | |
491 } | |
492 multiscan = FALSE; | |
493 if (!fmt_ptr || idx == 'D' || idx == 'X') | |
494 { | |
495 if (fmt_ptr) | |
496 { | |
497 if (idx == 'D') /* enter directory */ | |
498 { | |
499 if (*namebuf == NUL) | |
500 { | |
501 EMSG(_("E379: Missing or empty directory name")); | |
502 goto error2; | |
503 } | |
504 if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) | |
505 goto error2; | |
506 } | |
507 else if (idx == 'X') /* leave directory */ | |
508 directory = qf_pop_dir(&dir_stack); | |
509 } | |
510 namebuf[0] = NUL; /* no match found, remove file name */ | |
511 lnum = 0; /* don't jump to this line */ | |
512 valid = FALSE; | |
513 STRCPY(errmsg, IObuff); /* copy whole line to error message */ | |
514 if (!fmt_ptr) | |
515 multiline = multiignore = FALSE; | |
516 } | |
517 else if (fmt_ptr) | |
518 { | |
519 if (vim_strchr((char_u *)"AEWI", idx) != NULL) | |
520 multiline = TRUE; /* start of a multi-line message */ | |
521 else if (vim_strchr((char_u *)"CZ", idx) != NULL) | |
522 { /* continuation of multi-line msg */ | |
523 if (qfprev == NULL) | |
524 goto error2; | |
525 if (*errmsg && !multiignore) | |
526 { | |
527 len = (int)STRLEN(qfprev->qf_text); | |
528 if ((ptr = alloc((unsigned)(len + STRLEN(errmsg) + 2))) | |
529 == NULL) | |
530 goto error2; | |
531 STRCPY(ptr, qfprev->qf_text); | |
532 vim_free(qfprev->qf_text); | |
533 qfprev->qf_text = ptr; | |
534 *(ptr += len) = '\n'; | |
535 STRCPY(++ptr, errmsg); | |
536 } | |
537 if (qfprev->qf_nr == -1) | |
538 qfprev->qf_nr = enr; | |
539 if (vim_isprintc(type) && !qfprev->qf_type) | |
540 qfprev->qf_type = type; /* only printable chars allowed */ | |
541 if (!qfprev->qf_lnum) | |
542 qfprev->qf_lnum = lnum; | |
543 if (!qfprev->qf_col) | |
544 qfprev->qf_col = col; | |
545 qfprev->qf_virt_col = use_virt_col; | |
546 if (!qfprev->qf_fnum) | |
547 qfprev->qf_fnum = qf_get_fnum(directory, | |
548 *namebuf || directory ? namebuf | |
549 : currfile && valid ? currfile : 0); | |
550 if (idx == 'Z') | |
551 multiline = multiignore = FALSE; | |
552 line_breakcheck(); | |
553 continue; | |
554 } | |
555 else if (vim_strchr((char_u *)"OPQ", idx) != NULL) | |
556 { | |
557 /* global file names */ | |
558 valid = FALSE; | |
559 if (*namebuf == NUL || mch_getperm(namebuf) >= 0) | |
560 { | |
561 if (*namebuf && idx == 'P') | |
562 currfile = qf_push_dir(namebuf, &file_stack); | |
563 else if (idx == 'Q') | |
564 currfile = qf_pop_dir(&file_stack); | |
565 *namebuf = NUL; | |
566 if (tail && *tail) | |
567 { | |
568 STRCPY(IObuff, skipwhite(tail)); | |
569 multiscan = TRUE; | |
570 goto restofline; | |
571 } | |
572 } | |
573 } | |
574 if (fmt_ptr->flags == '-') /* generally exclude this line */ | |
575 { | |
576 if (multiline) | |
577 multiignore = TRUE; /* also exclude continuation lines */ | |
578 continue; | |
579 } | |
580 } | |
581 | |
582 if (qf_add_entry(&qfprev, | |
583 directory, | |
584 *namebuf || directory | |
585 ? namebuf | |
586 : currfile && valid ? currfile : NULL, | |
587 errmsg, | |
588 lnum, | |
589 col, | |
590 use_virt_col, | |
591 enr, | |
592 type, | |
593 valid) == FAIL) | |
594 goto error2; | |
595 line_breakcheck(); | |
596 } | |
597 if (!ferror(fd)) | |
598 { | |
599 if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */ | |
600 { | |
601 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; | |
602 qf_lists[qf_curlist].qf_index = 1; | |
603 qf_lists[qf_curlist].qf_nonevalid = TRUE; | |
604 } | |
605 else | |
606 { | |
607 qf_lists[qf_curlist].qf_nonevalid = FALSE; | |
608 if (qf_lists[qf_curlist].qf_ptr == NULL) | |
609 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; | |
610 } | |
611 retval = qf_lists[qf_curlist].qf_count; /* return number of matches */ | |
612 goto qf_init_ok; | |
613 } | |
614 EMSG(_(e_readerrf)); | |
615 error2: | |
616 qf_free(qf_curlist); | |
617 qf_listcount--; | |
618 if (qf_curlist > 0) | |
619 --qf_curlist; | |
620 qf_init_ok: | |
621 fclose(fd); | |
622 for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) | |
623 { | |
624 fmt_first = fmt_ptr->next; | |
625 vim_free(fmt_ptr->prog); | |
626 vim_free(fmt_ptr); | |
627 } | |
628 qf_clean_dir_stack(&dir_stack); | |
629 qf_clean_dir_stack(&file_stack); | |
630 qf_init_end: | |
631 vim_free(namebuf); | |
632 vim_free(errmsg); | |
633 vim_free(fmtstr); | |
634 | |
635 #ifdef FEAT_WINDOWS | |
636 qf_update_buffer(); | |
637 #endif | |
638 | |
639 return retval; | |
640 } | |
641 | |
642 /* | |
643 * Prepare for adding a new quickfix list. | |
644 */ | |
645 static void | |
646 qf_new_list() | |
647 { | |
648 int i; | |
649 | |
650 /* | |
651 * If the current entry is not the last entry, delete entries below | |
652 * the current entry. This makes it possible to browse in a tree-like | |
653 * way with ":grep'. | |
654 */ | |
655 while (qf_listcount > qf_curlist + 1) | |
656 qf_free(--qf_listcount); | |
657 | |
658 /* | |
659 * When the stack is full, remove to oldest entry | |
660 * Otherwise, add a new entry. | |
661 */ | |
662 if (qf_listcount == LISTCOUNT) | |
663 { | |
664 qf_free(0); | |
665 for (i = 1; i < LISTCOUNT; ++i) | |
666 qf_lists[i - 1] = qf_lists[i]; | |
667 qf_curlist = LISTCOUNT - 1; | |
668 } | |
669 else | |
670 qf_curlist = qf_listcount++; | |
671 qf_lists[qf_curlist].qf_index = 0; | |
672 qf_lists[qf_curlist].qf_count = 0; | |
673 } | |
674 | |
675 /* | |
676 * Add an entry to the end of the list of errors. | |
677 * Returns OK or FAIL. | |
678 */ | |
679 static int | |
680 qf_add_entry(prevp, dir, fname, mesg, lnum, col, virt_col, nr, type, valid) | |
681 struct qf_line **prevp; /* pointer to previously added entry or NULL */ | |
682 char_u *dir; /* optional directory name */ | |
683 char_u *fname; /* file name or NULL */ | |
684 char_u *mesg; /* message */ | |
685 long lnum; /* line number */ | |
686 int col; /* column */ | |
687 int virt_col; /* using virtual column */ | |
688 int nr; /* error number */ | |
689 int type; /* type character */ | |
690 int valid; /* valid entry */ | |
691 { | |
692 struct qf_line *qfp; | |
693 | |
694 if ((qfp = (struct qf_line *)alloc((unsigned)sizeof(struct qf_line))) | |
695 == NULL) | |
696 return FAIL; | |
697 qfp->qf_fnum = qf_get_fnum(dir, fname); | |
698 if ((qfp->qf_text = vim_strsave(mesg)) == NULL) | |
699 { | |
700 vim_free(qfp); | |
701 return FAIL; | |
702 } | |
703 qfp->qf_lnum = lnum; | |
704 qfp->qf_col = col; | |
705 qfp->qf_virt_col = virt_col; | |
706 qfp->qf_nr = nr; | |
707 if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ | |
708 type = 0; | |
709 qfp->qf_type = type; | |
710 qfp->qf_valid = valid; | |
711 | |
712 if (qf_lists[qf_curlist].qf_count == 0) /* first element in the list */ | |
713 { | |
714 qf_lists[qf_curlist].qf_start = qfp; | |
715 qfp->qf_prev = qfp; /* first element points to itself */ | |
716 } | |
717 else | |
718 { | |
719 qfp->qf_prev = *prevp; | |
720 (*prevp)->qf_next = qfp; | |
721 } | |
722 qfp->qf_next = qfp; /* last element points to itself */ | |
723 qfp->qf_cleared = FALSE; | |
724 *prevp = qfp; | |
725 ++qf_lists[qf_curlist].qf_count; | |
726 if (qf_lists[qf_curlist].qf_index == 0 && qfp->qf_valid) | |
727 /* first valid entry */ | |
728 { | |
729 qf_lists[qf_curlist].qf_index = qf_lists[qf_curlist].qf_count; | |
730 qf_lists[qf_curlist].qf_ptr = qfp; | |
731 } | |
732 | |
733 return OK; | |
734 } | |
735 | |
736 /* | |
737 * get buffer number for file "dir.name" | |
738 */ | |
739 static int | |
740 qf_get_fnum(directory, fname) | |
741 char_u *directory; | |
742 char_u *fname; | |
743 { | |
744 if (fname == NULL || *fname == NUL) /* no file name */ | |
745 return 0; | |
746 { | |
747 #ifdef RISCOS | |
748 /* Name is reported as `main.c', but file is `c.main' */ | |
749 return ro_buflist_add(fname); | |
750 #else | |
751 char_u *ptr; | |
752 int fnum; | |
753 | |
754 # ifdef VMS | |
755 vms_remove_version(fname); | |
756 # endif | |
757 # ifdef BACKSLASH_IN_FILENAME | |
758 if (directory != NULL) | |
759 slash_adjust(directory); | |
760 slash_adjust(fname); | |
761 # endif | |
762 if (directory != NULL && !vim_isAbsName(fname) | |
763 && (ptr = concat_fnames(directory, fname, TRUE)) != NULL) | |
764 { | |
765 /* | |
766 * Here we check if the file really exists. | |
767 * This should normally be true, but if make works without | |
768 * "leaving directory"-messages we might have missed a | |
769 * directory change. | |
770 */ | |
771 if (mch_getperm(ptr) < 0) | |
772 { | |
773 vim_free(ptr); | |
774 directory = qf_guess_filepath(fname); | |
775 if (directory) | |
776 ptr = concat_fnames(directory, fname, TRUE); | |
777 else | |
778 ptr = vim_strsave(fname); | |
779 } | |
780 /* Use concatenated directory name and file name */ | |
781 fnum = buflist_add(ptr, 0); | |
782 vim_free(ptr); | |
783 return fnum; | |
784 } | |
785 return buflist_add(fname, 0); | |
786 #endif | |
787 } | |
788 } | |
789 | |
790 /* | |
791 * push dirbuf onto the directory stack and return pointer to actual dir or | |
792 * NULL on error | |
793 */ | |
794 static char_u * | |
795 qf_push_dir(dirbuf, stackptr) | |
796 char_u *dirbuf; | |
797 struct dir_stack_T **stackptr; | |
798 { | |
799 struct dir_stack_T *ds_new; | |
800 struct dir_stack_T *ds_ptr; | |
801 | |
802 /* allocate new stack element and hook it in */ | |
803 ds_new = (struct dir_stack_T *)alloc((unsigned)sizeof(struct dir_stack_T)); | |
804 if (ds_new == NULL) | |
805 return NULL; | |
806 | |
807 ds_new->next = *stackptr; | |
808 *stackptr = ds_new; | |
809 | |
810 /* store directory on the stack */ | |
811 if (vim_isAbsName(dirbuf) | |
812 || (*stackptr)->next == NULL | |
813 || (*stackptr && dir_stack != *stackptr)) | |
814 (*stackptr)->dirname = vim_strsave(dirbuf); | |
815 else | |
816 { | |
817 /* Okay we don't have an absolute path. | |
818 * dirbuf must be a subdir of one of the directories on the stack. | |
819 * Let's search... | |
820 */ | |
821 ds_new = (*stackptr)->next; | |
822 (*stackptr)->dirname = NULL; | |
823 while (ds_new) | |
824 { | |
825 vim_free((*stackptr)->dirname); | |
826 (*stackptr)->dirname = concat_fnames(ds_new->dirname, dirbuf, | |
827 TRUE); | |
828 if (mch_isdir((*stackptr)->dirname) == TRUE) | |
829 break; | |
830 | |
831 ds_new = ds_new->next; | |
832 } | |
833 | |
834 /* clean up all dirs we already left */ | |
835 while ((*stackptr)->next != ds_new) | |
836 { | |
837 ds_ptr = (*stackptr)->next; | |
838 (*stackptr)->next = (*stackptr)->next->next; | |
839 vim_free(ds_ptr->dirname); | |
840 vim_free(ds_ptr); | |
841 } | |
842 | |
843 /* Nothing found -> it must be on top level */ | |
844 if (ds_new == NULL) | |
845 { | |
846 vim_free((*stackptr)->dirname); | |
847 (*stackptr)->dirname = vim_strsave(dirbuf); | |
848 } | |
849 } | |
850 | |
851 if ((*stackptr)->dirname != NULL) | |
852 return (*stackptr)->dirname; | |
853 else | |
854 { | |
855 ds_ptr = *stackptr; | |
856 *stackptr = (*stackptr)->next; | |
857 vim_free(ds_ptr); | |
858 return NULL; | |
859 } | |
860 } | |
861 | |
862 | |
863 /* | |
864 * pop dirbuf from the directory stack and return previous directory or NULL if | |
865 * stack is empty | |
866 */ | |
867 static char_u * | |
868 qf_pop_dir(stackptr) | |
869 struct dir_stack_T **stackptr; | |
870 { | |
871 struct dir_stack_T *ds_ptr; | |
872 | |
873 /* TODO: Should we check if dirbuf is the directory on top of the stack? | |
874 * What to do if it isn't? */ | |
875 | |
876 /* pop top element and free it */ | |
877 if (*stackptr != NULL) | |
878 { | |
879 ds_ptr = *stackptr; | |
880 *stackptr = (*stackptr)->next; | |
881 vim_free(ds_ptr->dirname); | |
882 vim_free(ds_ptr); | |
883 } | |
884 | |
885 /* return NEW top element as current dir or NULL if stack is empty*/ | |
886 return *stackptr ? (*stackptr)->dirname : NULL; | |
887 } | |
888 | |
889 /* | |
890 * clean up directory stack | |
891 */ | |
892 static void | |
893 qf_clean_dir_stack(stackptr) | |
894 struct dir_stack_T **stackptr; | |
895 { | |
896 struct dir_stack_T *ds_ptr; | |
897 | |
898 while ((ds_ptr = *stackptr) != NULL) | |
899 { | |
900 *stackptr = (*stackptr)->next; | |
901 vim_free(ds_ptr->dirname); | |
902 vim_free(ds_ptr); | |
903 } | |
904 } | |
905 | |
906 /* | |
907 * Check in which directory of the directory stack the given file can be | |
908 * found. | |
909 * Returns a pointer to the directory name or NULL if not found | |
910 * Cleans up intermediate directory entries. | |
911 * | |
912 * TODO: How to solve the following problem? | |
913 * If we have the this directory tree: | |
914 * ./ | |
915 * ./aa | |
916 * ./aa/bb | |
917 * ./bb | |
918 * ./bb/x.c | |
919 * and make says: | |
920 * making all in aa | |
921 * making all in bb | |
922 * x.c:9: Error | |
923 * Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. | |
924 * qf_guess_filepath will return NULL. | |
925 */ | |
926 static char_u * | |
927 qf_guess_filepath(filename) | |
928 char_u *filename; | |
929 { | |
930 struct dir_stack_T *ds_ptr; | |
931 struct dir_stack_T *ds_tmp; | |
932 char_u *fullname; | |
933 | |
934 /* no dirs on the stack - there's nothing we can do */ | |
935 if (dir_stack == NULL) | |
936 return NULL; | |
937 | |
938 ds_ptr = dir_stack->next; | |
939 fullname = NULL; | |
940 while (ds_ptr) | |
941 { | |
942 vim_free(fullname); | |
943 fullname = concat_fnames(ds_ptr->dirname, filename, TRUE); | |
944 | |
945 /* If concat_fnames failed, just go on. The worst thing that can happen | |
946 * is that we delete the entire stack. | |
947 */ | |
948 if ((fullname != NULL) && (mch_getperm(fullname) >= 0)) | |
949 break; | |
950 | |
951 ds_ptr = ds_ptr->next; | |
952 } | |
953 | |
954 vim_free(fullname); | |
955 | |
956 /* clean up all dirs we already left */ | |
957 while (dir_stack->next != ds_ptr) | |
958 { | |
959 ds_tmp = dir_stack->next; | |
960 dir_stack->next = dir_stack->next->next; | |
961 vim_free(ds_tmp->dirname); | |
962 vim_free(ds_tmp); | |
963 } | |
964 | |
965 return ds_ptr==NULL? NULL: ds_ptr->dirname; | |
966 | |
967 } | |
968 | |
969 /* | |
970 * jump to a quickfix line | |
971 * if dir == FORWARD go "errornr" valid entries forward | |
972 * if dir == BACKWARD go "errornr" valid entries backward | |
973 * if dir == FORWARD_FILE go "errornr" valid entries files backward | |
974 * if dir == BACKWARD_FILE go "errornr" valid entries files backward | |
975 * else if "errornr" is zero, redisplay the same line | |
976 * else go to entry "errornr" | |
977 */ | |
978 void | |
979 qf_jump(dir, errornr, forceit) | |
980 int dir; | |
981 int errornr; | |
982 int forceit; | |
983 { | |
984 struct qf_line *qf_ptr; | |
985 struct qf_line *old_qf_ptr; | |
986 int qf_index; | |
987 int old_qf_fnum; | |
988 int old_qf_index; | |
989 int prev_index; | |
990 static char_u *e_no_more_items = (char_u *)N_("E553: No more items"); | |
991 char_u *err = e_no_more_items; | |
992 linenr_T i; | |
993 buf_T *old_curbuf; | |
994 linenr_T old_lnum; | |
995 char_u *old_swb = p_swb; | |
996 colnr_T screen_col; | |
997 colnr_T char_col; | |
998 char_u *line; | |
999 #ifdef FEAT_WINDOWS | |
1000 int opened_window = FALSE; | |
1001 win_T *win; | |
1002 win_T *altwin; | |
1003 #endif | |
1004 int print_message = TRUE; | |
1005 int len; | |
1006 #ifdef FEAT_FOLDING | |
1007 int old_KeyTyped = KeyTyped; /* getting file may reset it */ | |
1008 #endif | |
1009 | |
1010 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0) | |
1011 { | |
1012 EMSG(_(e_quickfix)); | |
1013 return; | |
1014 } | |
1015 | |
1016 qf_ptr = qf_lists[qf_curlist].qf_ptr; | |
1017 old_qf_ptr = qf_ptr; | |
1018 qf_index = qf_lists[qf_curlist].qf_index; | |
1019 old_qf_index = qf_index; | |
1020 if (dir == FORWARD || dir == FORWARD_FILE) /* next valid entry */ | |
1021 { | |
1022 while (errornr--) | |
1023 { | |
1024 old_qf_ptr = qf_ptr; | |
1025 prev_index = qf_index; | |
1026 old_qf_fnum = qf_ptr->qf_fnum; | |
1027 do | |
1028 { | |
1029 if (qf_index == qf_lists[qf_curlist].qf_count | |
1030 || qf_ptr->qf_next == NULL) | |
1031 { | |
1032 qf_ptr = old_qf_ptr; | |
1033 qf_index = prev_index; | |
1034 if (err != NULL) | |
1035 { | |
1036 EMSG(_(err)); | |
1037 goto theend; | |
1038 } | |
1039 errornr = 0; | |
1040 break; | |
1041 } | |
1042 ++qf_index; | |
1043 qf_ptr = qf_ptr->qf_next; | |
1044 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) | |
1045 || (dir == FORWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); | |
1046 err = NULL; | |
1047 } | |
1048 } | |
1049 else if (dir == BACKWARD || dir == BACKWARD_FILE) /* prev. valid entry */ | |
1050 { | |
1051 while (errornr--) | |
1052 { | |
1053 old_qf_ptr = qf_ptr; | |
1054 prev_index = qf_index; | |
1055 old_qf_fnum = qf_ptr->qf_fnum; | |
1056 do | |
1057 { | |
1058 if (qf_index == 1 || qf_ptr->qf_prev == NULL) | |
1059 { | |
1060 qf_ptr = old_qf_ptr; | |
1061 qf_index = prev_index; | |
1062 if (err != NULL) | |
1063 { | |
1064 EMSG(_(err)); | |
1065 goto theend; | |
1066 } | |
1067 errornr = 0; | |
1068 break; | |
1069 } | |
1070 --qf_index; | |
1071 qf_ptr = qf_ptr->qf_prev; | |
1072 } while ((!qf_lists[qf_curlist].qf_nonevalid && !qf_ptr->qf_valid) | |
1073 || (dir == BACKWARD_FILE && qf_ptr->qf_fnum == old_qf_fnum)); | |
1074 err = NULL; | |
1075 } | |
1076 } | |
1077 else if (errornr != 0) /* go to specified number */ | |
1078 { | |
1079 while (errornr < qf_index && qf_index > 1 && qf_ptr->qf_prev != NULL) | |
1080 { | |
1081 --qf_index; | |
1082 qf_ptr = qf_ptr->qf_prev; | |
1083 } | |
1084 while (errornr > qf_index && qf_index < qf_lists[qf_curlist].qf_count | |
1085 && qf_ptr->qf_next != NULL) | |
1086 { | |
1087 ++qf_index; | |
1088 qf_ptr = qf_ptr->qf_next; | |
1089 } | |
1090 } | |
1091 | |
1092 #ifdef FEAT_WINDOWS | |
1093 qf_lists[qf_curlist].qf_index = qf_index; | |
1094 if (qf_win_pos_update(old_qf_index)) | |
1095 /* No need to print the error message if it's visible in the error | |
1096 * window */ | |
1097 print_message = FALSE; | |
1098 | |
1099 /* | |
1100 * If currently in the quickfix window, find another window to show the | |
1101 * file in. | |
1102 */ | |
1103 if (bt_quickfix(curbuf)) | |
1104 { | |
1105 /* | |
1106 * If there is no file specified, we don't know where to go. | |
1107 * But do advance, otherwise ":cn" gets stuck. | |
1108 */ | |
1109 if (qf_ptr->qf_fnum == 0) | |
1110 goto theend; | |
1111 | |
1112 /* | |
1113 * If there is only one window, create a new one above the quickfix | |
1114 * window. | |
1115 */ | |
1116 if (firstwin == lastwin) | |
1117 { | |
1118 if (win_split(0, WSP_ABOVE) == FAIL) | |
1119 goto failed; /* not enough room for window */ | |
1120 opened_window = TRUE; /* close it when fail */ | |
1121 p_swb = empty_option; /* don't split again */ | |
1122 # ifdef FEAT_SCROLLBIND | |
1123 curwin->w_p_scb = FALSE; | |
1124 # endif | |
1125 } | |
1126 else | |
1127 { | |
1128 /* | |
1129 * Try to find a window that shows the right buffer. | |
1130 * Default to the window just above the quickfix buffer. | |
1131 */ | |
1132 win = curwin; | |
1133 altwin = NULL; | |
1134 for (;;) | |
1135 { | |
1136 if (win->w_buffer->b_fnum == qf_ptr->qf_fnum) | |
1137 break; | |
1138 if (win->w_prev == NULL) | |
1139 win = lastwin; /* wrap around the top */ | |
1140 else | |
1141 win = win->w_prev; /* go to previous window */ | |
1142 | |
1143 if (bt_quickfix(win->w_buffer)) | |
1144 { | |
1145 /* Didn't find it, go to the window before the quickfix | |
1146 * window. */ | |
1147 if (altwin != NULL) | |
1148 win = altwin; | |
1149 else if (curwin->w_prev != NULL) | |
1150 win = curwin->w_prev; | |
1151 else | |
1152 win = curwin->w_next; | |
1153 break; | |
1154 } | |
1155 | |
1156 /* Remember a usable window. */ | |
1157 if (altwin == NULL && !win->w_p_pvw | |
1158 && win->w_buffer->b_p_bt[0] == NUL) | |
1159 altwin = win; | |
1160 } | |
1161 | |
1162 win_goto(win); | |
1163 } | |
1164 } | |
1165 #endif | |
1166 | |
1167 /* | |
1168 * If there is a file name, | |
1169 * read the wanted file if needed, and check autowrite etc. | |
1170 */ | |
1171 old_curbuf = curbuf; | |
1172 old_lnum = curwin->w_cursor.lnum; | |
1173 if (qf_ptr->qf_fnum == 0 || buflist_getfile(qf_ptr->qf_fnum, | |
1174 (linenr_T)1, GETF_SETMARK | GETF_SWITCH, forceit) == OK) | |
1175 { | |
1176 /* When not switched to another buffer, still need to set pc mark */ | |
1177 if (curbuf == old_curbuf) | |
1178 setpcmark(); | |
1179 | |
1180 /* | |
1181 * Go to line with error, unless qf_lnum is 0. | |
1182 */ | |
1183 i = qf_ptr->qf_lnum; | |
1184 if (i > 0) | |
1185 { | |
1186 if (i > curbuf->b_ml.ml_line_count) | |
1187 i = curbuf->b_ml.ml_line_count; | |
1188 curwin->w_cursor.lnum = i; | |
1189 } | |
1190 if (qf_ptr->qf_col > 0) | |
1191 { | |
1192 curwin->w_cursor.col = qf_ptr->qf_col - 1; | |
1193 if (qf_ptr->qf_virt_col == TRUE) | |
1194 { | |
1195 /* | |
1196 * Check each character from the beginning of the error | |
1197 * line up to the error column. For each tab character | |
1198 * found, reduce the error column value by the length of | |
1199 * a tab character. | |
1200 */ | |
1201 line = ml_get_curline(); | |
1202 screen_col = 0; | |
1203 for (char_col = 0; char_col < curwin->w_cursor.col; ++char_col) | |
1204 { | |
1205 if (*line == NUL) | |
1206 break; | |
1207 if (*line++ == '\t') | |
1208 { | |
1209 curwin->w_cursor.col -= 7 - (screen_col % 8); | |
1210 screen_col += 8 - (screen_col % 8); | |
1211 } | |
1212 else | |
1213 ++screen_col; | |
1214 } | |
1215 } | |
1216 check_cursor(); | |
1217 } | |
1218 else | |
1219 beginline(BL_WHITE | BL_FIX); | |
1220 | |
1221 #ifdef FEAT_FOLDING | |
1222 if ((fdo_flags & FDO_QUICKFIX) && old_KeyTyped) | |
1223 foldOpenCursor(); | |
1224 #endif | |
1225 if (print_message) | |
1226 { | |
1227 /* Update the screen before showing the message */ | |
1228 update_topline_redraw(); | |
1229 sprintf((char *)IObuff, _("(%d of %d)%s%s: "), qf_index, | |
1230 qf_lists[qf_curlist].qf_count, | |
1231 qf_ptr->qf_cleared ? _(" (line deleted)") : "", | |
1232 (char *)qf_types(qf_ptr->qf_type, qf_ptr->qf_nr)); | |
1233 /* Add the message, skipping leading whitespace and newlines. */ | |
1234 len = (int)STRLEN(IObuff); | |
1235 qf_fmt_text(skipwhite(qf_ptr->qf_text), IObuff + len, IOSIZE - len); | |
1236 | |
1237 /* Output the message. Overwrite to avoid scrolling when the 'O' | |
1238 * flag is present in 'shortmess'; But when not jumping, print the | |
1239 * whole message. */ | |
1240 i = msg_scroll; | |
1241 if (curbuf == old_curbuf && curwin->w_cursor.lnum == old_lnum) | |
1242 msg_scroll = TRUE; | |
1243 else if (!msg_scrolled && shortmess(SHM_OVERALL)) | |
1244 msg_scroll = FALSE; | |
1245 msg_attr_keep(IObuff, 0, TRUE); | |
1246 msg_scroll = i; | |
1247 } | |
1248 } | |
1249 else | |
1250 { | |
1251 #ifdef FEAT_WINDOWS | |
1252 if (opened_window) | |
1253 win_close(curwin, TRUE); /* Close opened window */ | |
1254 #endif | |
1255 if (qf_ptr->qf_fnum != 0) | |
1256 { | |
1257 /* | |
1258 * Couldn't open file, so put index back where it was. This could | |
1259 * happen if the file was readonly and we changed something. | |
1260 */ | |
1261 #ifdef FEAT_WINDOWS | |
1262 failed: | |
1263 #endif | |
1264 qf_ptr = old_qf_ptr; | |
1265 qf_index = old_qf_index; | |
1266 } | |
1267 } | |
1268 theend: | |
1269 qf_lists[qf_curlist].qf_ptr = qf_ptr; | |
1270 qf_lists[qf_curlist].qf_index = qf_index; | |
1271 #ifdef FEAT_WINDOWS | |
1272 if (p_swb != old_swb && opened_window) | |
1273 { | |
1274 /* Restore old 'switchbuf' value, but not when an autocommand or | |
1275 * modeline has changed the value. */ | |
1276 if (p_swb == empty_option) | |
1277 p_swb = old_swb; | |
1278 else | |
1279 free_string_option(old_swb); | |
1280 } | |
1281 #endif | |
1282 } | |
1283 | |
1284 /* | |
1285 * ":clist": list all errors | |
1286 */ | |
1287 void | |
1288 qf_list(eap) | |
1289 exarg_T *eap; | |
1290 { | |
1291 buf_T *buf; | |
1292 char_u *fname; | |
1293 struct qf_line *qfp; | |
1294 int i; | |
1295 int idx1 = 1; | |
1296 int idx2 = -1; | |
1297 int need_return = TRUE; | |
1298 int last_printed = 1; | |
1299 char_u *arg = eap->arg; | |
1300 int all = eap->forceit; /* if not :cl!, only show | |
1301 recognised errors */ | |
1302 | |
1303 if (qf_curlist >= qf_listcount || qf_lists[qf_curlist].qf_count == 0) | |
1304 { | |
1305 EMSG(_(e_quickfix)); | |
1306 return; | |
1307 } | |
1308 if (!get_list_range(&arg, &idx1, &idx2) || *arg != NUL) | |
1309 { | |
1310 EMSG(_(e_trailing)); | |
1311 return; | |
1312 } | |
1313 i = qf_lists[qf_curlist].qf_count; | |
1314 if (idx1 < 0) | |
1315 idx1 = (-idx1 > i) ? 0 : idx1 + i + 1; | |
1316 if (idx2 < 0) | |
1317 idx2 = (-idx2 > i) ? 0 : idx2 + i + 1; | |
1318 | |
1319 more_back_used = TRUE; | |
1320 if (qf_lists[qf_curlist].qf_nonevalid) | |
1321 all = TRUE; | |
1322 qfp = qf_lists[qf_curlist].qf_start; | |
1323 for (i = 1; !got_int && i <= qf_lists[qf_curlist].qf_count; ) | |
1324 { | |
1325 if ((qfp->qf_valid || all) && idx1 <= i && i <= idx2) | |
1326 { | |
1327 if (need_return) | |
1328 { | |
1329 msg_putchar('\n'); | |
1330 need_return = FALSE; | |
1331 } | |
1332 if (more_back == 0) | |
1333 { | |
1334 fname = NULL; | |
1335 if (qfp->qf_fnum != 0 | |
1336 && (buf = buflist_findnr(qfp->qf_fnum)) != NULL) | |
1337 { | |
1338 fname = buf->b_fname; | |
1339 if (qfp->qf_type == 1) /* :helpgrep */ | |
1340 fname = gettail(fname); | |
1341 } | |
1342 if (fname == NULL) | |
1343 sprintf((char *)IObuff, "%2d", i); | |
1344 else | |
1345 sprintf((char *)IObuff, "%2d %s", i, (char *)fname); | |
1346 msg_outtrans_attr(IObuff, i == qf_lists[qf_curlist].qf_index | |
1347 ? hl_attr(HLF_L) : hl_attr(HLF_D)); | |
1348 if (qfp->qf_lnum == 0) | |
1349 IObuff[0] = NUL; | |
1350 else if (qfp->qf_col == 0) | |
1351 sprintf((char *)IObuff, ":%ld", qfp->qf_lnum); | |
1352 else | |
1353 sprintf((char *)IObuff, ":%ld col %d", | |
1354 qfp->qf_lnum, qfp->qf_col); | |
1355 sprintf((char *)IObuff + STRLEN(IObuff), "%s: ", | |
1356 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); | |
1357 msg_puts_attr(IObuff, hl_attr(HLF_N)); | |
1358 /* Remove newlines and leading whitespace from the text. | |
1359 * For an unrecognized line keep the indent, the compiler may | |
1360 * mark a word with ^^^^. */ | |
1361 qf_fmt_text((fname != NULL || qfp->qf_lnum != 0) | |
1362 ? skipwhite(qfp->qf_text) : qfp->qf_text, | |
1363 IObuff, IOSIZE); | |
1364 msg_prt_line(IObuff); | |
1365 out_flush(); /* show one line at a time */ | |
1366 need_return = TRUE; | |
1367 last_printed = i; | |
1368 } | |
1369 } | |
1370 if (more_back) | |
1371 { | |
1372 /* scrolling backwards from the more-prompt */ | |
1373 /* TODO: compute the number of items from the screen lines */ | |
1374 more_back = more_back * 2 - 1; | |
1375 while (i > last_printed - more_back && i > idx1) | |
1376 { | |
1377 do | |
1378 { | |
1379 qfp = qfp->qf_prev; | |
1380 --i; | |
1381 } | |
1382 while (i > idx1 && !qfp->qf_valid && !all); | |
1383 } | |
1384 more_back = 0; | |
1385 } | |
1386 else | |
1387 { | |
1388 qfp = qfp->qf_next; | |
1389 ++i; | |
1390 } | |
1391 ui_breakcheck(); | |
1392 } | |
1393 more_back_used = FALSE; | |
1394 } | |
1395 | |
1396 /* | |
1397 * Remove newlines and leading whitespace from an error message. | |
1398 * Put the result in "buf[bufsize]". | |
1399 */ | |
1400 static void | |
1401 qf_fmt_text(text, buf, bufsize) | |
1402 char_u *text; | |
1403 char_u *buf; | |
1404 int bufsize; | |
1405 { | |
1406 int i; | |
1407 char_u *p = text; | |
1408 | |
1409 for (i = 0; *p != NUL && i < bufsize - 1; ++i) | |
1410 { | |
1411 if (*p == '\n') | |
1412 { | |
1413 buf[i] = ' '; | |
1414 while (*++p != NUL) | |
1415 if (!vim_iswhite(*p) && *p != '\n') | |
1416 break; | |
1417 } | |
1418 else | |
1419 buf[i] = *p++; | |
1420 } | |
1421 buf[i] = NUL; | |
1422 } | |
1423 | |
1424 /* | |
1425 * ":colder [count]": Up in the quickfix stack. | |
1426 * ":cnewer [count]": Down in the quickfix stack. | |
1427 */ | |
1428 void | |
1429 qf_age(eap) | |
1430 exarg_T *eap; | |
1431 { | |
1432 int count; | |
1433 | |
1434 if (eap->addr_count != 0) | |
1435 count = eap->line2; | |
1436 else | |
1437 count = 1; | |
1438 while (count--) | |
1439 { | |
1440 if (eap->cmdidx == CMD_colder) | |
1441 { | |
1442 if (qf_curlist == 0) | |
1443 { | |
1444 EMSG(_("E380: At bottom of quickfix stack")); | |
1445 return; | |
1446 } | |
1447 --qf_curlist; | |
1448 } | |
1449 else | |
1450 { | |
1451 if (qf_curlist >= qf_listcount - 1) | |
1452 { | |
1453 EMSG(_("E381: At top of quickfix stack")); | |
1454 return; | |
1455 } | |
1456 ++qf_curlist; | |
1457 } | |
1458 } | |
1459 qf_msg(); | |
1460 } | |
1461 | |
1462 static void | |
1463 qf_msg() | |
1464 { | |
1465 smsg((char_u *)_("error list %d of %d; %d errors"), | |
1466 qf_curlist + 1, qf_listcount, qf_lists[qf_curlist].qf_count); | |
1467 #ifdef FEAT_WINDOWS | |
1468 qf_update_buffer(); | |
1469 #endif | |
1470 } | |
1471 | |
1472 /* | |
1473 * free the error list | |
1474 */ | |
1475 static void | |
1476 qf_free(idx) | |
1477 int idx; | |
1478 { | |
1479 struct qf_line *qfp; | |
1480 | |
1481 while (qf_lists[idx].qf_count) | |
1482 { | |
1483 qfp = qf_lists[idx].qf_start->qf_next; | |
1484 vim_free(qf_lists[idx].qf_start->qf_text); | |
1485 vim_free(qf_lists[idx].qf_start); | |
1486 qf_lists[idx].qf_start = qfp; | |
1487 --qf_lists[idx].qf_count; | |
1488 } | |
1489 } | |
1490 | |
1491 /* | |
1492 * qf_mark_adjust: adjust marks | |
1493 */ | |
1494 void | |
1495 qf_mark_adjust(line1, line2, amount, amount_after) | |
1496 linenr_T line1; | |
1497 linenr_T line2; | |
1498 long amount; | |
1499 long amount_after; | |
1500 { | |
1501 int i; | |
1502 struct qf_line *qfp; | |
1503 int idx; | |
1504 | |
1505 for (idx = 0; idx < qf_listcount; ++idx) | |
1506 if (qf_lists[idx].qf_count) | |
1507 for (i = 0, qfp = qf_lists[idx].qf_start; | |
1508 i < qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) | |
1509 if (qfp->qf_fnum == curbuf->b_fnum) | |
1510 { | |
1511 if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) | |
1512 { | |
1513 if (amount == MAXLNUM) | |
1514 qfp->qf_cleared = TRUE; | |
1515 else | |
1516 qfp->qf_lnum += amount; | |
1517 } | |
1518 else if (amount_after && qfp->qf_lnum > line2) | |
1519 qfp->qf_lnum += amount_after; | |
1520 } | |
1521 } | |
1522 | |
1523 /* | |
1524 * Make a nice message out of the error character and the error number: | |
1525 * char number message | |
1526 * e or E 0 " error" | |
1527 * w or W 0 " warning" | |
1528 * i or I 0 " info" | |
1529 * 0 0 "" | |
1530 * other 0 " c" | |
1531 * e or E n " error n" | |
1532 * w or W n " warning n" | |
1533 * i or I n " info n" | |
1534 * 0 n " error n" | |
1535 * other n " c n" | |
1536 * 1 x "" :helpgrep | |
1537 */ | |
1538 static char_u * | |
1539 qf_types(c, nr) | |
1540 int c, nr; | |
1541 { | |
1542 static char_u buf[20]; | |
1543 static char_u cc[3]; | |
1544 char_u *p; | |
1545 | |
1546 if (c == 'W' || c == 'w') | |
1547 p = (char_u *)" warning"; | |
1548 else if (c == 'I' || c == 'i') | |
1549 p = (char_u *)" info"; | |
1550 else if (c == 'E' || c == 'e' || (c == 0 && nr > 0)) | |
1551 p = (char_u *)" error"; | |
1552 else if (c == 0 || c == 1) | |
1553 p = (char_u *)""; | |
1554 else | |
1555 { | |
1556 cc[0] = ' '; | |
1557 cc[1] = c; | |
1558 cc[2] = NUL; | |
1559 p = cc; | |
1560 } | |
1561 | |
1562 if (nr <= 0) | |
1563 return p; | |
1564 | |
1565 sprintf((char *)buf, "%s %3d", (char *)p, nr); | |
1566 return buf; | |
1567 } | |
1568 | |
1569 #if defined(FEAT_WINDOWS) || defined(PROTO) | |
1570 /* | |
1571 * ":cwindow": open the quickfix window if we have errors to display, | |
1572 * close it if not. | |
1573 */ | |
1574 void | |
1575 ex_cwindow(eap) | |
1576 exarg_T *eap; | |
1577 { | |
1578 win_T *win; | |
1579 | |
1580 /* | |
1581 * Look for an existing quickfix window. | |
1582 */ | |
1583 for (win = firstwin; win != NULL; win = win->w_next) | |
1584 if (bt_quickfix(win->w_buffer)) | |
1585 break; | |
1586 | |
1587 /* | |
1588 * If a quickfix window is open but we have no errors to display, | |
1589 * close the window. If a quickfix window is not open, then open | |
1590 * it if we have errors; otherwise, leave it closed. | |
1591 */ | |
1592 if (qf_lists[qf_curlist].qf_nonevalid || qf_curlist >= qf_listcount) | |
1593 { | |
1594 if (win != NULL) | |
1595 ex_cclose(eap); | |
1596 } | |
1597 else if (win == NULL) | |
1598 ex_copen(eap); | |
1599 } | |
1600 | |
1601 /* | |
1602 * ":cclose": close the window showing the list of errors. | |
1603 */ | |
1604 /*ARGSUSED*/ | |
1605 void | |
1606 ex_cclose(eap) | |
1607 exarg_T *eap; | |
1608 { | |
1609 win_T *win; | |
1610 | |
1611 /* | |
1612 * Find existing quickfix window and close it. | |
1613 */ | |
1614 for (win = firstwin; win != NULL; win = win->w_next) | |
1615 if (bt_quickfix(win->w_buffer)) | |
1616 break; | |
1617 | |
1618 if (win != NULL) | |
1619 win_close(win, FALSE); | |
1620 } | |
1621 | |
1622 /* | |
1623 * ":copen": open a window that shows the list of errors. | |
1624 */ | |
1625 void | |
1626 ex_copen(eap) | |
1627 exarg_T *eap; | |
1628 { | |
1629 int height; | |
1630 buf_T *buf; | |
1631 win_T *win; | |
1632 | |
1633 if (eap->addr_count != 0) | |
1634 height = eap->line2; | |
1635 else | |
1636 height = QF_WINHEIGHT; | |
1637 | |
1638 #ifdef FEAT_VISUAL | |
1639 reset_VIsual_and_resel(); /* stop Visual mode */ | |
1640 #endif | |
1641 #ifdef FEAT_GUI | |
1642 need_mouse_correct = TRUE; | |
1643 #endif | |
1644 | |
1645 /* | |
1646 * Find existing quickfix window, or open a new one. | |
1647 */ | |
1648 for (win = firstwin; win != NULL; win = win->w_next) | |
1649 if (bt_quickfix(win->w_buffer)) | |
1650 break; | |
1651 if (win != NULL) | |
1652 win_goto(win); | |
1653 else | |
1654 { | |
1655 /* The current window becomes the previous window afterwards. */ | |
1656 win = curwin; | |
1657 | |
1658 /* Create the new window at the very bottom. */ | |
1659 win_goto(lastwin); | |
1660 if (win_split(height, WSP_BELOW) == FAIL) | |
1661 return; /* not enough room for window */ | |
1662 #ifdef FEAT_SCROLLBIND | |
1663 curwin->w_p_scb = FALSE; | |
1664 #endif | |
1665 | |
1666 /* | |
1667 * Find existing quickfix buffer, or create a new one. | |
1668 */ | |
1669 buf = qf_find_buf(); | |
1670 if (buf == NULL) | |
1671 { | |
1672 (void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE); | |
1673 /* switch off 'swapfile' */ | |
1674 set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); | |
1675 set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", | |
1676 OPT_LOCAL); | |
1677 set_option_value((char_u *)"bh", 0L, (char_u *)"delete", OPT_LOCAL); | |
1678 set_option_value((char_u *)"diff", 0L, (char_u *)"", OPT_LOCAL); | |
1679 } | |
1680 else if (buf != curbuf) | |
1681 set_curbuf(buf, DOBUF_GOTO); | |
1682 | |
1683 /* Only set the height when there is no window to the side. */ | |
1684 if (curwin->w_width == Columns) | |
1685 win_setheight(height); | |
1686 curwin->w_p_wfh = TRUE; /* set 'winfixheight' */ | |
1687 if (win_valid(win)) | |
1688 prevwin = win; | |
1689 } | |
1690 | |
1691 /* | |
1692 * Fill the buffer with the quickfix list. | |
1693 */ | |
1694 qf_fill_buffer(); | |
1695 | |
1696 curwin->w_cursor.lnum = qf_lists[qf_curlist].qf_index; | |
1697 curwin->w_cursor.col = 0; | |
1698 check_cursor(); | |
1699 update_topline(); /* scroll to show the line */ | |
1700 } | |
1701 | |
1702 /* | |
1703 * Return the number of the current entry (line number in the quickfix | |
1704 * window). | |
1705 */ | |
1706 linenr_T | |
1707 qf_current_entry() | |
1708 { | |
1709 return qf_lists[qf_curlist].qf_index; | |
1710 } | |
1711 | |
1712 /* | |
1713 * Update the cursor position in the quickfix window to the current error. | |
1714 * Return TRUE if there is a quickfix window. | |
1715 */ | |
1716 static int | |
1717 qf_win_pos_update(old_qf_index) | |
1718 int old_qf_index; /* previous qf_index or zero */ | |
1719 { | |
1720 win_T *win; | |
1721 int qf_index = qf_lists[qf_curlist].qf_index; | |
1722 | |
1723 /* | |
1724 * Put the cursor on the current error in the quickfix window, so that | |
1725 * it's viewable. | |
1726 */ | |
1727 for (win = firstwin; win != NULL; win = win->w_next) | |
1728 if (bt_quickfix(win->w_buffer)) | |
1729 break; | |
1730 if (win != NULL | |
1731 && qf_index <= win->w_buffer->b_ml.ml_line_count | |
1732 && old_qf_index != qf_index) | |
1733 { | |
1734 win_T *old_curwin = curwin; | |
1735 | |
1736 curwin = win; | |
1737 curbuf = win->w_buffer; | |
1738 if (qf_index > old_qf_index) | |
1739 { | |
1740 curwin->w_redraw_top = old_qf_index; | |
1741 curwin->w_redraw_bot = qf_index; | |
1742 } | |
1743 else | |
1744 { | |
1745 curwin->w_redraw_top = qf_index; | |
1746 curwin->w_redraw_bot = old_qf_index; | |
1747 } | |
1748 curwin->w_cursor.lnum = qf_index; | |
1749 curwin->w_cursor.col = 0; | |
1750 update_topline(); /* scroll to show the line */ | |
1751 redraw_later(VALID); | |
1752 curwin->w_redr_status = TRUE; /* update ruler */ | |
1753 curwin = old_curwin; | |
1754 curbuf = curwin->w_buffer; | |
1755 } | |
1756 return win != NULL; | |
1757 } | |
1758 | |
1759 /* | |
1760 * Find quickfix buffer. | |
1761 */ | |
1762 static buf_T * | |
1763 qf_find_buf() | |
1764 { | |
1765 buf_T *buf; | |
1766 | |
1767 for (buf = firstbuf; buf != NULL; buf = buf->b_next) | |
1768 if (bt_quickfix(buf)) | |
1769 break; | |
1770 return buf; | |
1771 } | |
1772 | |
1773 /* | |
1774 * Find the quickfix buffer. If it exists, update the contents. | |
1775 */ | |
1776 static void | |
1777 qf_update_buffer() | |
1778 { | |
1779 buf_T *buf; | |
1780 #ifdef FEAT_AUTOCMD | |
1781 aco_save_T aco; | |
1782 #else | |
1783 buf_T *save_curbuf; | |
1784 #endif | |
1785 | |
1786 /* Check if a buffer for the quickfix list exists. Update it. */ | |
1787 buf = qf_find_buf(); | |
1788 if (buf != NULL) | |
1789 { | |
1790 #ifdef FEAT_AUTOCMD | |
1791 /* set curwin/curbuf to buf and save a few things */ | |
1792 aucmd_prepbuf(&aco, buf); | |
1793 #else | |
1794 save_curbuf = curbuf; | |
1795 curbuf = buf; | |
1796 #endif | |
1797 | |
1798 qf_fill_buffer(); | |
1799 | |
1800 #ifdef FEAT_AUTOCMD | |
1801 /* restore curwin/curbuf and a few other things */ | |
1802 aucmd_restbuf(&aco); | |
1803 #else | |
1804 curbuf = save_curbuf; | |
1805 #endif | |
1806 | |
1807 (void)qf_win_pos_update(0); | |
1808 } | |
1809 } | |
1810 | |
1811 /* | |
1812 * Fill current buffer with quickfix errors, replacing any previous contents. | |
1813 * curbuf must be the quickfix buffer! | |
1814 */ | |
1815 static void | |
1816 qf_fill_buffer() | |
1817 { | |
1818 linenr_T lnum; | |
1819 struct qf_line *qfp; | |
1820 buf_T *errbuf; | |
1821 int len; | |
1822 int old_KeyTyped = KeyTyped; | |
1823 | |
1824 /* delete all existing lines */ | |
1825 while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) | |
1826 (void)ml_delete((linenr_T)1, FALSE); | |
1827 | |
1828 /* Check if there is anything to display */ | |
1829 if (qf_curlist < qf_listcount) | |
1830 { | |
1831 /* Add one line for each error */ | |
1832 qfp = qf_lists[qf_curlist].qf_start; | |
1833 for (lnum = 0; lnum < qf_lists[qf_curlist].qf_count; ++lnum) | |
1834 { | |
1835 if (qfp->qf_fnum != 0 | |
1836 && (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL | |
1837 && errbuf->b_fname != NULL) | |
1838 { | |
1839 if (qfp->qf_type == 1) /* :helpgrep */ | |
1840 STRCPY(IObuff, gettail(errbuf->b_fname)); | |
1841 else | |
1842 STRCPY(IObuff, errbuf->b_fname); | |
1843 len = (int)STRLEN(IObuff); | |
1844 } | |
1845 else | |
1846 len = 0; | |
1847 IObuff[len++] = '|'; | |
1848 | |
1849 if (qfp->qf_lnum > 0) | |
1850 { | |
1851 sprintf((char *)IObuff + len, "%ld", qfp->qf_lnum); | |
1852 len += (int)STRLEN(IObuff + len); | |
1853 | |
1854 if (qfp->qf_col > 0) | |
1855 { | |
1856 sprintf((char *)IObuff + len, " col %d", qfp->qf_col); | |
1857 len += (int)STRLEN(IObuff + len); | |
1858 } | |
1859 | |
1860 sprintf((char *)IObuff + len, "%s", | |
1861 (char *)qf_types(qfp->qf_type, qfp->qf_nr)); | |
1862 len += (int)STRLEN(IObuff + len); | |
1863 } | |
1864 IObuff[len++] = '|'; | |
1865 IObuff[len++] = ' '; | |
1866 | |
1867 /* Remove newlines and leading whitespace from the text. | |
1868 * For an unrecognized line keep the indent, the compiler may | |
1869 * mark a word with ^^^^. */ | |
1870 qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, | |
1871 IObuff + len, IOSIZE - len); | |
1872 | |
1873 if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) | |
1874 == FAIL) | |
1875 break; | |
1876 qfp = qfp->qf_next; | |
1877 } | |
1878 /* Delete the empty line which is now at the end */ | |
1879 (void)ml_delete(lnum + 1, FALSE); | |
1880 } | |
1881 | |
1882 /* correct cursor position */ | |
1883 check_lnums(TRUE); | |
1884 | |
1885 /* Set the 'filetype' to "qf" each time after filling the buffer. This | |
1886 * resembles reading a file into a buffer, it's more logical when using | |
1887 * autocommands. */ | |
1888 set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); | |
1889 curbuf->b_p_ma = FALSE; | |
1890 | |
1891 #ifdef FEAT_AUTOCMD | |
1892 apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, | |
1893 FALSE, curbuf); | |
1894 apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, | |
1895 FALSE, curbuf); | |
1896 #endif | |
1897 | |
1898 /* make sure it will be redrawn */ | |
1899 redraw_curbuf_later(NOT_VALID); | |
1900 | |
1901 /* Restore KeyTyped, setting 'filetype' may reset it. */ | |
1902 KeyTyped = old_KeyTyped; | |
1903 } | |
1904 | |
1905 #endif /* FEAT_WINDOWS */ | |
1906 | |
1907 /* | |
1908 * Return TRUE if "buf" is the quickfix buffer. | |
1909 */ | |
1910 int | |
1911 bt_quickfix(buf) | |
1912 buf_T *buf; | |
1913 { | |
1914 return (buf->b_p_bt[0] == 'q'); | |
1915 } | |
1916 | |
1917 /* | |
1918 * Return TRUE if "buf" is a "nofile" buffer. | |
1919 */ | |
1920 int | |
1921 bt_nofile(buf) | |
1922 buf_T *buf; | |
1923 { | |
1924 return (buf->b_p_bt[0] == 'n' && buf->b_p_bt[2] == 'f'); | |
1925 } | |
1926 | |
1927 /* | |
1928 * Return TRUE if "buf" is a "nowrite" or "nofile" buffer. | |
1929 */ | |
1930 int | |
1931 bt_dontwrite(buf) | |
1932 buf_T *buf; | |
1933 { | |
1934 return (buf->b_p_bt[0] == 'n'); | |
1935 } | |
1936 | |
1937 int | |
1938 bt_dontwrite_msg(buf) | |
1939 buf_T *buf; | |
1940 { | |
1941 if (bt_dontwrite(buf)) | |
1942 { | |
1943 EMSG(_("E382: Cannot write, 'buftype' option is set")); | |
1944 return TRUE; | |
1945 } | |
1946 return FALSE; | |
1947 } | |
1948 | |
1949 /* | |
1950 * Return TRUE if the buffer should be hidden, according to 'hidden', ":hide" | |
1951 * and 'bufhidden'. | |
1952 */ | |
1953 int | |
1954 buf_hide(buf) | |
1955 buf_T *buf; | |
1956 { | |
1957 /* 'bufhidden' overrules 'hidden' and ":hide", check it first */ | |
1958 switch (buf->b_p_bh[0]) | |
1959 { | |
1960 case 'u': /* "unload" */ | |
1961 case 'w': /* "wipe" */ | |
1962 case 'd': return FALSE; /* "delete" */ | |
1963 case 'h': return TRUE; /* "hide" */ | |
1964 } | |
1965 return (p_hid || cmdmod.hide); | |
1966 } | |
1967 | |
1968 /* | |
1969 * Used for ":make", ":grep" and ":grepadd". | |
1970 */ | |
1971 void | |
1972 ex_make(eap) | |
1973 exarg_T *eap; | |
1974 { | |
1975 char_u *name; | |
1976 char_u *cmd; | |
1977 unsigned len; | |
1978 | |
1979 autowrite_all(); | |
1980 name = get_mef_name(); | |
1981 if (name == NULL) | |
1982 return; | |
1983 mch_remove(name); /* in case it's not unique */ | |
1984 | |
1985 /* | |
1986 * If 'shellpipe' empty: don't redirect to 'errorfile'. | |
1987 */ | |
1988 len = (unsigned)STRLEN(p_shq) * 2 + (unsigned)STRLEN(eap->arg) + 1; | |
1989 if (*p_sp != NUL) | |
1990 len += (unsigned)STRLEN(p_sp) + (unsigned)STRLEN(name) + 3; | |
1991 cmd = alloc(len); | |
1992 if (cmd == NULL) | |
1993 return; | |
1994 sprintf((char *)cmd, "%s%s%s", (char *)p_shq, (char *)eap->arg, | |
1995 (char *)p_shq); | |
1996 if (*p_sp != NUL) | |
1997 append_redir(cmd, p_sp, name); | |
1998 /* | |
1999 * Output a newline if there's something else than the :make command that | |
2000 * was typed (in which case the cursor is in column 0). | |
2001 */ | |
2002 if (msg_col == 0) | |
2003 msg_didout = FALSE; | |
2004 msg_start(); | |
2005 MSG_PUTS(":!"); | |
2006 msg_outtrans(cmd); /* show what we are doing */ | |
2007 | |
2008 /* let the shell know if we are redirecting output or not */ | |
2009 do_shell(cmd, *p_sp != NUL ? SHELL_DOOUT : 0); | |
2010 | |
2011 #ifdef AMIGA | |
2012 out_flush(); | |
2013 /* read window status report and redraw before message */ | |
2014 (void)char_avail(); | |
2015 #endif | |
2016 | |
2017 if (qf_init(name, eap->cmdidx != CMD_make ? p_gefm : p_efm, | |
2018 eap->cmdidx != CMD_grepadd) > 0 | |
2019 && !eap->forceit) | |
2020 qf_jump(0, 0, FALSE); /* display first error */ | |
2021 | |
2022 mch_remove(name); | |
2023 vim_free(name); | |
2024 vim_free(cmd); | |
2025 } | |
2026 | |
2027 /* | |
2028 * Return the name for the errorfile, in allocated memory. | |
2029 * Find a new unique name when 'makeef' contains "##". | |
2030 * Returns NULL for error. | |
2031 */ | |
2032 static char_u * | |
2033 get_mef_name() | |
2034 { | |
2035 char_u *p; | |
2036 char_u *name; | |
2037 static int start = -1; | |
2038 static int off = 0; | |
2039 #ifdef HAVE_LSTAT | |
2040 struct stat sb; | |
2041 #endif | |
2042 | |
2043 if (*p_mef == NUL) | |
2044 { | |
2045 name = vim_tempname('e'); | |
2046 if (name == NULL) | |
2047 EMSG(_(e_notmp)); | |
2048 return name; | |
2049 } | |
2050 | |
2051 for (p = p_mef; *p; ++p) | |
2052 if (p[0] == '#' && p[1] == '#') | |
2053 break; | |
2054 | |
2055 if (*p == NUL) | |
2056 return vim_strsave(p_mef); | |
2057 | |
2058 /* Keep trying until the name doesn't exist yet. */ | |
2059 for (;;) | |
2060 { | |
2061 if (start == -1) | |
2062 start = mch_get_pid(); | |
2063 else | |
2064 off += 19; | |
2065 | |
2066 name = alloc((unsigned)STRLEN(p_mef) + 30); | |
2067 if (name == NULL) | |
2068 break; | |
2069 STRCPY(name, p_mef); | |
2070 sprintf((char *)name + (p - p_mef), "%d%d", start, off); | |
2071 STRCAT(name, p + 2); | |
2072 if (mch_getperm(name) < 0 | |
2073 #ifdef HAVE_LSTAT | |
2074 /* Don't accept a symbolic link, its a security risk. */ | |
2075 && mch_lstat((char *)name, &sb) < 0 | |
2076 #endif | |
2077 ) | |
2078 break; | |
2079 vim_free(name); | |
2080 } | |
2081 return name; | |
2082 } | |
2083 | |
2084 /* | |
2085 * ":cc", ":crewind", ":cfirst" and ":clast". | |
2086 */ | |
2087 void | |
2088 ex_cc(eap) | |
2089 exarg_T *eap; | |
2090 { | |
2091 qf_jump(0, | |
2092 eap->addr_count > 0 | |
2093 ? (int)eap->line2 | |
2094 : eap->cmdidx == CMD_cc | |
2095 ? 0 | |
2096 : (eap->cmdidx == CMD_crewind || eap->cmdidx == CMD_cfirst) | |
2097 ? 1 | |
2098 : 32767, | |
2099 eap->forceit); | |
2100 } | |
2101 | |
2102 /* | |
2103 * ":cnext", ":cnfile", ":cNext" and ":cprevious". | |
2104 */ | |
2105 void | |
2106 ex_cnext(eap) | |
2107 exarg_T *eap; | |
2108 { | |
2109 qf_jump(eap->cmdidx == CMD_cnext | |
2110 ? FORWARD | |
2111 : eap->cmdidx == CMD_cnfile | |
2112 ? FORWARD_FILE | |
2113 : (eap->cmdidx == CMD_cpfile || eap->cmdidx == CMD_cNfile) | |
2114 ? BACKWARD_FILE | |
2115 : BACKWARD, | |
2116 eap->addr_count > 0 ? (int)eap->line2 : 1, eap->forceit); | |
2117 } | |
2118 | |
2119 /* | |
2120 * ":cfile" command. | |
2121 */ | |
2122 void | |
2123 ex_cfile(eap) | |
2124 exarg_T *eap; | |
2125 { | |
2126 if (*eap->arg != NUL) | |
2127 set_string_option_direct((char_u *)"ef", -1, eap->arg, OPT_FREE); | |
2128 if (qf_init(p_ef, p_efm, TRUE) > 0 && eap->cmdidx == CMD_cfile) | |
2129 qf_jump(0, 0, eap->forceit); /* display first error */ | |
2130 } | |
2131 | |
2132 /* | |
2133 * ":helpgrep {pattern}" | |
2134 */ | |
2135 void | |
2136 ex_helpgrep(eap) | |
2137 exarg_T *eap; | |
2138 { | |
2139 regmatch_T regmatch; | |
2140 char_u *save_cpo; | |
2141 char_u *p; | |
2142 int fcount; | |
2143 char_u **fnames; | |
2144 FILE *fd; | |
2145 int fi; | |
2146 struct qf_line *prevp = NULL; | |
2147 long lnum; | |
2148 | |
2149 /* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
2150 save_cpo = p_cpo; | |
2151 p_cpo = (char_u *)""; | |
2152 | |
2153 regmatch.regprog = vim_regcomp(eap->arg, RE_MAGIC + RE_STRING); | |
2154 regmatch.rm_ic = FALSE; | |
2155 if (regmatch.regprog != NULL) | |
2156 { | |
2157 /* create a new quickfix list */ | |
2158 qf_new_list(); | |
2159 | |
2160 /* Go through all directories in 'runtimepath' */ | |
2161 p = p_rtp; | |
2162 while (*p != NUL && !got_int) | |
2163 { | |
2164 copy_option_part(&p, NameBuff, MAXPATHL, ","); | |
2165 | |
2166 /* Find all "*.txt" and "*.??x" files in the "doc" directory. */ | |
2167 add_pathsep(NameBuff); | |
2168 STRCAT(NameBuff, "doc/*.\\(txt\\|??x\\)"); | |
2169 if (gen_expand_wildcards(1, &NameBuff, &fcount, | |
2170 &fnames, EW_FILE|EW_SILENT) == OK | |
2171 && fcount > 0) | |
2172 { | |
2173 for (fi = 0; fi < fcount && !got_int; ++fi) | |
2174 { | |
2175 fd = fopen((char *)fnames[fi], "r"); | |
2176 if (fd != NULL) | |
2177 { | |
2178 lnum = 1; | |
2179 while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int) | |
2180 { | |
2181 if (vim_regexec(®match, IObuff, (colnr_T)0)) | |
2182 { | |
2183 int l = STRLEN(IObuff); | |
2184 | |
2185 /* remove trailing CR, LF, spaces, etc. */ | |
2186 while (l > 0 && IObuff[l - 1] <= ' ') | |
2187 IObuff[--l] = NUL; | |
2188 | |
2189 if (qf_add_entry(&prevp, | |
2190 NULL, /* dir */ | |
2191 fnames[fi], | |
2192 IObuff, | |
2193 lnum, | |
2194 0, /* col */ | |
2195 FALSE, /* virt_col */ | |
2196 0, /* nr */ | |
2197 1, /* type */ | |
2198 TRUE /* valid */ | |
2199 ) == FAIL) | |
2200 { | |
2201 got_int = TRUE; | |
2202 break; | |
2203 } | |
2204 } | |
2205 ++lnum; | |
2206 line_breakcheck(); | |
2207 } | |
2208 fclose(fd); | |
2209 } | |
2210 } | |
2211 FreeWild(fcount, fnames); | |
2212 } | |
2213 } | |
2214 vim_free(regmatch.regprog); | |
2215 | |
2216 qf_lists[qf_curlist].qf_nonevalid = FALSE; | |
2217 qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start; | |
2218 qf_lists[qf_curlist].qf_index = 1; | |
2219 } | |
2220 | |
2221 p_cpo = save_cpo; | |
2222 | |
2223 #ifdef FEAT_WINDOWS | |
2224 qf_update_buffer(); | |
2225 #endif | |
2226 | |
2227 /* Jump to first match. */ | |
2228 if (qf_lists[qf_curlist].qf_count > 0) | |
2229 qf_jump(0, 0, FALSE); | |
2230 } | |
2231 | |
2232 #endif /* FEAT_QUICKFIX */ |