summaryrefslogtreecommitdiff
path: root/src/quickfix.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/quickfix.c')
-rw-r--r--src/quickfix.c242
1 files changed, 230 insertions, 12 deletions
diff --git a/src/quickfix.c b/src/quickfix.c
index 0cb9c6956..dbde1550f 100644
--- a/src/quickfix.c
+++ b/src/quickfix.c
@@ -86,6 +86,7 @@ struct eformat
/* '-' do not include this line */
};
+static int qf_init_ext __ARGS((char_u *efile, buf_T *buf, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast));
static void qf_new_list __ARGS((void));
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));
static void qf_msg __ARGS((void));
@@ -106,7 +107,8 @@ static void qf_fill_buffer __ARGS((void));
static char_u *get_mef_name __ARGS((void));
/*
- * Read the errorfile into memory, line by line, building the error list.
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
* Return -1 for error, number of errors for success.
*/
int
@@ -115,6 +117,29 @@ qf_init(efile, errorformat, newlist)
char_u *errorformat;
int newlist; /* TRUE: start a new error list */
{
+ if (efile == NULL)
+ return FAIL;
+ return qf_init_ext(efile, curbuf, errorformat, newlist,
+ (linenr_T)0, (linenr_T)0);
+}
+
+/*
+ * Read the errorfile "efile" into memory, line by line, building the error
+ * list.
+ * Alternative: when "efile" is null read errors from buffer "buf".
+ * Always use 'errorformat' from "buf" if there is a local value.
+ * Then lnumfirst and lnumlast specify the range of lines to use.
+ * Return -1 for error, number of errors for success.
+ */
+ static int
+qf_init_ext(efile, buf, errorformat, newlist, lnumfirst, lnumlast)
+ char_u *efile;
+ buf_T *buf;
+ char_u *errorformat;
+ int newlist; /* TRUE: start a new error list */
+ linenr_T lnumfirst; /* first line number to use */
+ linenr_T lnumlast; /* last line number to use */
+{
char_u *namebuf;
char_u *errmsg;
char_u *fmtstr = NULL;
@@ -122,9 +147,10 @@ qf_init(efile, errorformat, newlist)
char_u use_virt_col = FALSE;
int type = 0;
int valid;
+ linenr_T buflnum = lnumfirst;
long lnum = 0L;
int enr = 0;
- FILE *fd;
+ FILE *fd = NULL;
struct qf_line *qfprev = NULL; /* init to make SASC shut up */
char_u *efmp;
struct eformat *fmt_first = NULL;
@@ -163,15 +189,12 @@ qf_init(efile, errorformat, newlist)
{'v', "\\d\\+"}
};
- if (efile == NULL)
- return FAIL;
-
namebuf = alloc(CMDBUFFSIZE + 1);
errmsg = alloc(CMDBUFFSIZE + 1);
if (namebuf == NULL || errmsg == NULL)
goto qf_init_end;
- if ((fd = mch_fopen((char *)efile, "r")) == NULL)
+ if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL)
{
EMSG2(_(e_openerrf), efile);
goto qf_init_end;
@@ -191,8 +214,8 @@ qf_init(efile, errorformat, newlist)
* regex prog. Only a few % characters are allowed.
*/
/* Use the local value of 'errorformat' if it's set. */
- if (errorformat == p_efm && *curbuf->b_p_efm != NUL)
- efm = curbuf->b_p_efm;
+ if (errorformat == p_efm && *buf->b_p_efm != NUL)
+ efm = buf->b_p_efm;
else
efm = errorformat;
/*
@@ -405,8 +428,18 @@ qf_init(efile, errorformat, newlist)
* Read the lines in the error file one by one.
* Try to recognize one of the error formats in each line.
*/
- while (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) != NULL && !got_int)
+ while (!got_int)
{
+ /* Get the next line. */
+ if (fd == NULL)
+ {
+ if (buflnum > lnumlast)
+ break;
+ STRNCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE), CMDBUFFSIZE - 2);
+ }
+ else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL)
+ break;
+
IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */
if ((efmp = vim_strrchr(IObuff, '\n')) != NULL)
*efmp = NUL;
@@ -594,7 +627,7 @@ restofline:
goto error2;
line_breakcheck();
}
- if (!ferror(fd))
+ if (fd == NULL || !ferror(fd))
{
if (qf_lists[qf_curlist].qf_index == 0) /* no valid entry found */
{
@@ -618,7 +651,8 @@ error2:
if (qf_curlist > 0)
--qf_curlist;
qf_init_ok:
- fclose(fd);
+ if (fd != NULL)
+ fclose(fd);
for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first)
{
fmt_first = fmt_ptr->next;
@@ -2026,6 +2060,18 @@ buf_hide(buf)
}
/*
+ * Return TRUE when using ":vimgrep" for ":grep".
+ */
+ int
+grep_internal(eap)
+ exarg_T *eap;
+{
+ return ((eap->cmdidx == CMD_grep || eap->cmdidx == CMD_grepadd)
+ && STRCMP("internal",
+ *curbuf->b_p_gp == NUL ? p_gp : curbuf->b_p_gp) == 0);
+}
+
+/*
* Used for ":make", ":grep" and ":grepadd".
*/
void
@@ -2036,6 +2082,13 @@ ex_make(eap)
char_u *cmd;
unsigned len;
+ /* Redirect ":grep" to ":vimgrep" if 'grepprg' is "internal". */
+ if (grep_internal(eap))
+ {
+ ex_vimgrep(eap);
+ return;
+ }
+
autowrite_all();
name = get_mef_name();
if (name == NULL)
@@ -2075,7 +2128,7 @@ ex_make(eap)
#endif
if (qf_init(name, eap->cmdidx != CMD_make ? p_gefm : p_efm,
- eap->cmdidx != CMD_grepadd) > 0
+ eap->cmdidx != CMD_grepadd) > 0
&& !eap->forceit)
qf_jump(0, 0, FALSE); /* display first error */
@@ -2190,6 +2243,171 @@ ex_cfile(eap)
}
/*
+ * ":vimgrep {pattern} file(s)"
+ */
+ void
+ex_vimgrep(eap)
+ exarg_T *eap;
+{
+ regmatch_T regmatch;
+ char_u *save_cpo;
+ int fcount;
+ char_u **fnames;
+ char_u *p;
+ int i;
+ FILE *fd;
+ int fi;
+ struct qf_line *prevp = NULL;
+ long lnum;
+ garray_T ga;
+
+ /* Make 'cpoptions' empty, the 'l' flag should not be used here. */
+ save_cpo = p_cpo;
+ p_cpo = empty_option;
+
+ /* Get the search pattern */
+ regmatch.regprog = NULL;
+ p = skip_regexp(eap->arg + 1, *eap->arg, TRUE, NULL);
+ if (*p != *eap->arg)
+ {
+ EMSG(_("E682: Invalid search pattern or delimiter"));
+ goto theend;
+ }
+ *p++ = NUL;
+ regmatch.regprog = vim_regcomp(eap->arg + 1, RE_MAGIC);
+ if (regmatch.regprog == NULL)
+ goto theend;
+ regmatch.rm_ic = FALSE;
+
+ p = skipwhite(p);
+ if (*p == NUL)
+ {
+ EMSG(_("E683: File name missing or invalid pattern"));
+ goto theend;
+ }
+
+ if ((eap->cmdidx != CMD_grepadd && eap->cmdidx != CMD_vimgrepadd)
+ || qf_curlist == qf_listcount)
+ /* make place for a new list */
+ qf_new_list();
+ else if (qf_lists[qf_curlist].qf_count > 0)
+ /* Adding to existing list, find last entry. */
+ for (prevp = qf_lists[qf_curlist].qf_start;
+ prevp->qf_next != prevp; prevp = prevp->qf_next)
+ ;
+
+ /* parse the list of arguments */
+ if (get_arglist(&ga, p) == FAIL)
+ goto theend;
+ i = gen_expand_wildcards(ga.ga_len, (char_u **)ga.ga_data,
+ &fcount, &fnames, EW_FILE|EW_NOTFOUND);
+ ga_clear(&ga);
+ if (i == FAIL)
+ goto theend;
+ if (fcount == 0)
+ {
+ EMSG(_(e_nomatch));
+ goto theend;
+ }
+
+ for (fi = 0; fi < fcount && !got_int; ++fi)
+ {
+ fd = fopen((char *)fnames[fi], "r");
+ if (fd == NULL)
+ smsg((char_u *)_("Cannot open file \"%s\""), fnames[fi]);
+ else
+ {
+ lnum = 1;
+ while (!vim_fgets(IObuff, IOSIZE, fd) && !got_int)
+ {
+ if (vim_regexec(&regmatch, IObuff, (colnr_T)0))
+ {
+ int l = STRLEN(IObuff);
+
+ /* remove trailing CR, LF, spaces, etc. */
+ while (l > 0 && IObuff[l - 1] <= ' ')
+ IObuff[--l] = NUL;
+
+ if (qf_add_entry(&prevp,
+ NULL, /* dir */
+ fnames[fi],
+ IObuff,
+ lnum,
+ (int)(regmatch.startp[0] - IObuff) + 1,/* col */
+ FALSE, /* virt_col */
+ 0, /* nr */
+ 0, /* type */
+ TRUE /* valid */
+ ) == FAIL)
+ {
+ got_int = TRUE;
+ break;
+ }
+ }
+ ++lnum;
+ line_breakcheck();
+ }
+ fclose(fd);
+ }
+ }
+
+ FreeWild(fcount, fnames);
+
+ qf_lists[qf_curlist].qf_nonevalid = FALSE;
+ qf_lists[qf_curlist].qf_ptr = qf_lists[qf_curlist].qf_start;
+ qf_lists[qf_curlist].qf_index = 1;
+
+#ifdef FEAT_WINDOWS
+ qf_update_buffer();
+#endif
+
+ /* Jump to first match. */
+ if (qf_lists[qf_curlist].qf_count > 0)
+ qf_jump(0, 0, FALSE);
+
+theend:
+ vim_free(regmatch.regprog);
+
+ /* Only resture 'cpo' when it wasn't set in the mean time. */
+ if (p_cpo == empty_option)
+ p_cpo = save_cpo;
+ else
+ free_string_option(save_cpo);
+}
+
+/*
+ * ":[range]cbuffer [bufnr]" command.
+ */
+ void
+ex_cbuffer(eap)
+ exarg_T *eap;
+{
+ buf_T *buf = NULL;
+
+ if (*eap->arg == NUL)
+ buf = curbuf;
+ else if (*skipwhite(skipdigits(eap->arg)) == NUL)
+ buf = buflist_findnr(atoi((char *)eap->arg));
+ if (buf == NULL)
+ EMSG(_(e_invarg));
+ else if (buf->b_ml.ml_mfp == NULL)
+ EMSG(_("E681: Buffer is not loaded"));
+ else
+ {
+ if (eap->addr_count == 0)
+ {
+ eap->line1 = 1;
+ eap->line2 = buf->b_ml.ml_line_count;
+ }
+ if (eap->line1 < 1 || eap->line1 > buf->b_ml.ml_line_count
+ || eap->line2 < 1 || eap->line2 > buf->b_ml.ml_line_count)
+ EMSG(_(e_invrange));
+ else
+ qf_init_ext(NULL, buf, p_efm, TRUE, eap->line1, eap->line2);
+ }
+}
+
+/*
* ":helpgrep {pattern}"
*/
void