Created
December 14, 2017 20:29
-
-
Save brailsmt/e218b170158d6ac9730027c36daeeded to your computer and use it in GitHub Desktop.
diff of the changes in src/nvim/quickfix.c between master (6ff13d78b) and v0.1.7 tag.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c | |
index 1fc585f0c..f0d77f9e2 100644 | |
--- a/src/nvim/quickfix.c | |
+++ b/src/nvim/quickfix.c | |
@@ -1,6 +1,3 @@ | |
-// This is an open source non-commercial project. Dear PVS-Studio, please check | |
-// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com | |
- | |
/* | |
* quickfix.c: functions for quickfix mode, using a file with error messages | |
*/ | |
@@ -51,6 +48,8 @@ struct dir_stack_T { | |
char_u *dirname; | |
}; | |
+static struct dir_stack_T *dir_stack = NULL; | |
+ | |
/* | |
* For each error the next struct is allocated and linked in a list. | |
*/ | |
@@ -77,14 +76,13 @@ struct qfline_S { | |
#define LISTCOUNT 10 | |
typedef struct qf_list_S { | |
- qfline_T *qf_start; // pointer to the first error | |
- qfline_T *qf_last; // pointer to the last error | |
- qfline_T *qf_ptr; // pointer to the current error | |
- int qf_count; // number of errors (0 means no error list) | |
- int qf_index; // current index in the error list | |
- int qf_nonevalid; // TRUE if not a single valid entry found | |
- char_u *qf_title; // title derived from the command that created | |
- // the error list | |
+ qfline_T *qf_start; /* pointer to the first error */ | |
+ qfline_T *qf_ptr; /* pointer to the current error */ | |
+ int qf_count; /* number of errors (0 means no error list) */ | |
+ int qf_index; /* current index in the error list */ | |
+ int qf_nonevalid; /* TRUE if not a single valid entry found */ | |
+ char_u *qf_title; /* title derived from the command that created | |
+ * the error list */ | |
} qf_list_T; | |
struct qf_info_S { | |
@@ -98,15 +96,6 @@ struct qf_info_S { | |
int qf_listcount; /* current number of lists */ | |
int qf_curlist; /* current error list */ | |
qf_list_T qf_lists[LISTCOUNT]; | |
- | |
- int qf_dir_curlist; ///< error list for qf_dir_stack | |
- struct dir_stack_T *qf_dir_stack; | |
- char_u *qf_directory; | |
- struct dir_stack_T *qf_file_stack; | |
- char_u *qf_currfile; | |
- bool qf_multiline; | |
- bool qf_multiignore; | |
- bool qf_multiscan; | |
}; | |
static qf_info_T ql_info; /* global quickfix list */ | |
@@ -140,40 +129,6 @@ struct efm_S { | |
int conthere; /* %> used */ | |
}; | |
-enum { | |
- QF_FAIL = 0, | |
- QF_OK = 1, | |
- QF_END_OF_INPUT = 2, | |
- QF_NOMEM = 3, | |
- QF_IGNORE_LINE = 4 | |
-}; | |
- | |
-typedef struct { | |
- char_u *linebuf; | |
- size_t linelen; | |
- char_u *growbuf; | |
- size_t growbufsiz; | |
- FILE *fd; | |
- typval_T *tv; | |
- char_u *p_str; | |
- listitem_T *p_li; | |
- buf_T *buf; | |
- linenr_T buflnum; | |
- linenr_T lnumlast; | |
-} qfstate_T; | |
- | |
-typedef struct { | |
- char_u *namebuf; | |
- char_u *errmsg; | |
- size_t errmsglen; | |
- long lnum; | |
- int col; | |
- bool use_viscol; | |
- char_u *pattern; | |
- int enr; | |
- char_u type; | |
- bool valid; | |
-} qffields_T; | |
#ifdef INCLUDE_GENERATED_DECLARATIONS | |
# include "quickfix.c.generated.h" | |
@@ -188,11 +143,6 @@ typedef struct { | |
*/ | |
#define GET_LOC_LIST(wp) (IS_LL_WINDOW(wp) ? wp->w_llist_ref : wp->w_llist) | |
-// Looking up a buffer can be slow if there are many. Remember the last one | |
-// to make this a lot faster if there are multiple matches in the same file. | |
-static char_u *qf_last_bufname = NULL; | |
-static bufref_T qf_last_bufref = { NULL, 0, 0 }; | |
- | |
/* | |
* Read the errorfile "efile" into memory, line by line, building the error | |
* list. Set the error list's title to qf_title. | |
@@ -218,899 +168,586 @@ qf_init ( | |
qf_title); | |
} | |
-// Maximum number of bytes allowed per line while reading an errorfile. | |
-static const size_t LINE_MAXLEN = 4096; | |
- | |
-static struct fmtpattern | |
-{ | |
- char_u convchar; | |
- char *pattern; | |
-} fmt_pat[FMT_PATTERNS] = | |
+/* | |
+ * 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. | |
+ * Set the title of the list to "qf_title". | |
+ * Return -1 for error, number of errors for success. | |
+ */ | |
+static int | |
+qf_init_ext ( | |
+ qf_info_T *qi, | |
+ char_u *efile, | |
+ buf_T *buf, | |
+ typval_T *tv, | |
+ 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 *qf_title | |
+) | |
{ | |
- { 'f', ".\\+" }, // only used when at end | |
- { 'n', "\\d\\+" }, | |
- { 'l', "\\d\\+" }, | |
- { 'c', "\\d\\+" }, | |
- { 't', "." }, | |
- { 'm', ".\\+" }, | |
- { 'r', ".*" }, | |
- { 'p', "[- .]*" }, // NOLINT(whitespace/tab) | |
- { 'v', "\\d\\+" }, | |
- { 's', ".\\+" } | |
-}; | |
+ char_u *namebuf; | |
+ char_u *errmsg; | |
+ char_u *pattern; | |
+ char_u *fmtstr = NULL; | |
+ int col = 0; | |
+ bool use_viscol = false; | |
+ char_u type = 0; | |
+ linenr_T buflnum = lnumfirst; | |
+ long lnum = 0L; | |
+ int enr = 0; | |
+ FILE *fd = NULL; | |
+ qfline_T *qfprev = NULL; /* init to make SASC shut up */ | |
+ char_u *efmp; | |
+ efm_T *fmt_first = NULL; | |
+ efm_T *fmt_last = NULL; | |
+ efm_T *fmt_ptr; | |
+ efm_T *fmt_start = NULL; | |
+ char_u *efm; | |
+ char_u *ptr; | |
+ char_u *srcptr; | |
+ int len; | |
+ int i; | |
+ int round; | |
+ int idx = 0; | |
+ bool multiline = false; | |
+ bool multiignore = false; | |
+ bool multiscan = false; | |
+ int retval = -1; // default: return error flag | |
+ char_u *directory = NULL; | |
+ char_u *currfile = NULL; | |
+ char_u *tail = NULL; | |
+ char_u *p_str = NULL; | |
+ listitem_T *p_li = NULL; | |
+ struct dir_stack_T *file_stack = NULL; | |
+ regmatch_T regmatch; | |
+ static struct fmtpattern { | |
+ char_u convchar; | |
+ char *pattern; | |
+ } fmt_pat[FMT_PATTERNS] = | |
+ { | |
+ {'f', ".\\+"}, /* only used when at end */ | |
+ {'n', "\\d\\+"}, | |
+ {'l', "\\d\\+"}, | |
+ {'c', "\\d\\+"}, | |
+ {'t', "."}, | |
+ {'m', ".\\+"}, | |
+ {'r', ".*"}, | |
+ {'p', "[- .]*"}, | |
+ {'v', "\\d\\+"}, | |
+ {'s', ".\\+"} | |
+ }; | |
+ | |
+ namebuf = xmalloc(CMDBUFFSIZE + 1); | |
+ errmsg = xmalloc(CMDBUFFSIZE + 1); | |
+ pattern = xmalloc(CMDBUFFSIZE + 1); | |
+ | |
+ if (efile != NULL && (fd = mch_fopen((char *)efile, "r")) == NULL) { | |
+ EMSG2(_(e_openerrf), efile); | |
+ goto qf_init_end; | |
+ } | |
-// Converts a 'errorformat' string to regular expression pattern | |
-static int efm_to_regpat(char_u *efm, int len, efm_T *fmt_ptr, | |
- char_u *regpat, char_u *errmsg) | |
-{ | |
- // Build regexp pattern from current 'errorformat' option | |
- char_u *ptr = regpat; | |
- *ptr++ = '^'; | |
- int round = 0; | |
- for (char_u *efmp = efm; efmp < efm + len; efmp++) { | |
- if (*efmp == '%') { | |
- efmp++; | |
- int idx; | |
- for (idx = 0; idx < FMT_PATTERNS; idx++) { | |
- if (fmt_pat[idx].convchar == *efmp) { | |
- break; | |
- } | |
- } | |
- if (idx < FMT_PATTERNS) { | |
- if (fmt_ptr->addr[idx]) { | |
- snprintf((char *)errmsg, CMDBUFFSIZE + 1, | |
- _("E372: Too many %%%c in format string"), *efmp); | |
- EMSG(errmsg); | |
- return -1; | |
- } | |
- if ((idx | |
- && idx < 6 | |
- && vim_strchr((char_u *)"DXOPQ", fmt_ptr->prefix) != NULL) | |
- || (idx == 6 | |
- && vim_strchr((char_u *)"OPQ", fmt_ptr->prefix) == NULL)) { | |
- snprintf((char *)errmsg, CMDBUFFSIZE + 1, | |
- _("E373: Unexpected %%%c in format string"), *efmp); | |
- EMSG(errmsg); | |
- return -1; | |
- } | |
- round++; | |
- fmt_ptr->addr[idx] = (char_u)round; | |
- *ptr++ = '\\'; | |
- *ptr++ = '('; | |
-#ifdef BACKSLASH_IN_FILENAME | |
- if (*efmp == 'f') { | |
- // Also match "c:" in the file name, even when | |
- // checking for a colon next: "%f:". | |
- // "\%(\a:\)\=" | |
- STRCPY(ptr, "\\%(\\a:\\)\\="); | |
- ptr += 10; | |
- } | |
+ if (newlist || qi->qf_curlist == qi->qf_listcount) | |
+ /* make place for a new list */ | |
+ qf_new_list(qi, qf_title); | |
+ else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) | |
+ /* Adding to existing list, find last entry. */ | |
+ for (qfprev = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ qfprev->qf_next != qfprev; qfprev = qfprev->qf_next) | |
+ ; | |
+ | |
+ /* | |
+ * Each part of the format string is copied and modified from errorformat to | |
+ * regex prog. Only a few % characters are allowed. | |
+ */ | |
+ /* Use the local value of 'errorformat' if it's set. */ | |
+ if (errorformat == p_efm && tv == NULL && *buf->b_p_efm != NUL) | |
+ efm = buf->b_p_efm; | |
+ else | |
+ efm = errorformat; | |
+ /* | |
+ * Get some space to modify the format string into. | |
+ */ | |
+ size_t fmtstr_size = 3 * FMT_PATTERNS + 4 * STRLEN(efm); | |
+ for (round = FMT_PATTERNS; round > 0; ) { | |
+ fmtstr_size += STRLEN(fmt_pat[--round].pattern); | |
+ } | |
+#ifdef COLON_IN_FILENAME | |
+ fmtstr_size += 12; // "%f" can become twelve chars longer | |
+#else | |
+ fmtstr_size += 2; // "%f" can become two chars longer | |
#endif | |
- if (*efmp == 'f' && efmp[1] != NUL) { | |
- if (efmp[1] != '\\' && efmp[1] != '%') { | |
- // A file name may contain spaces, but this isn't | |
- // in "\f". For "%f:%l:%m" there may be a ":" in | |
- // the file name. Use ".\{-1,}x" instead (x is | |
- // the next character), the requirement that :999: | |
- // follows should work. | |
- STRCPY(ptr, ".\\{-1,}"); | |
- ptr += 7; | |
- } else { | |
- // File name followed by '\\' or '%': include as | |
- // many file name chars as possible. | |
- STRCPY(ptr, "\\f\\+"); | |
- ptr += 4; | |
+ fmtstr = xmalloc(fmtstr_size); | |
+ | |
+ while (efm[0] != NUL) { | |
+ /* | |
+ * Allocate a new eformat structure and put it at the end of the list | |
+ */ | |
+ fmt_ptr = xcalloc(1, sizeof(efm_T)); | |
+ if (fmt_first == NULL) /* first one */ | |
+ fmt_first = fmt_ptr; | |
+ else | |
+ fmt_last->next = fmt_ptr; | |
+ fmt_last = fmt_ptr; | |
+ | |
+ /* | |
+ * Isolate one part in the 'errorformat' option | |
+ */ | |
+ for (len = 0; efm[len] != NUL && efm[len] != ','; ++len) | |
+ if (efm[len] == '\\' && efm[len + 1] != NUL) | |
+ ++len; | |
+ | |
+ /* | |
+ * Build regexp pattern from current 'errorformat' option | |
+ */ | |
+ ptr = fmtstr; | |
+ *ptr++ = '^'; | |
+ round = 0; | |
+ for (efmp = efm; efmp < efm + len; ++efmp) { | |
+ if (*efmp == '%') { | |
+ ++efmp; | |
+ for (idx = 0; idx < FMT_PATTERNS; ++idx) | |
+ if (fmt_pat[idx].convchar == *efmp) | |
+ break; | |
+ if (idx < FMT_PATTERNS) { | |
+ if (fmt_ptr->addr[idx]) { | |
+ sprintf((char *)errmsg, | |
+ _("E372: Too many %%%c in format string"), *efmp); | |
+ EMSG(errmsg); | |
+ goto error2; | |
} | |
- } else { | |
- char_u *srcptr = (char_u *)fmt_pat[idx].pattern; | |
- while ((*ptr = *srcptr++) != NUL) { | |
- ptr++; | |
+ if ((idx | |
+ && idx < 6 | |
+ && vim_strchr((char_u *)"DXOPQ", | |
+ fmt_ptr->prefix) != NULL) | |
+ || (idx == 6 | |
+ && vim_strchr((char_u *)"OPQ", | |
+ fmt_ptr->prefix) == NULL)) { | |
+ sprintf((char *)errmsg, | |
+ _("E373: Unexpected %%%c in format string"), *efmp); | |
+ EMSG(errmsg); | |
+ goto error2; | |
} | |
- } | |
- *ptr++ = '\\'; | |
- *ptr++ = ')'; | |
- } else if (*efmp == '*') { | |
- if (*++efmp == '[' || *efmp == '\\') { | |
- if ((*ptr++ = *efmp) == '[') { // %*[^a-z0-9] etc. | |
- if (efmp[1] == '^') { | |
- *ptr++ = *++efmp; | |
+ fmt_ptr->addr[idx] = (char_u)++ round; | |
+ *ptr++ = '\\'; | |
+ *ptr++ = '('; | |
+#ifdef BACKSLASH_IN_FILENAME | |
+ if (*efmp == 'f') { | |
+ /* Also match "c:" in the file name, even when | |
+ * checking for a colon next: "%f:". | |
+ * "\%(\a:\)\=" */ | |
+ STRCPY(ptr, "\\%(\\a:\\)\\="); | |
+ ptr += 10; | |
+ } | |
+#endif | |
+ if (*efmp == 'f' && efmp[1] != NUL) { | |
+ if (efmp[1] != '\\' && efmp[1] != '%') { | |
+ /* A file name may contain spaces, but this isn't | |
+ * in "\f". For "%f:%l:%m" there may be a ":" in | |
+ * the file name. Use ".\{-1,}x" instead (x is | |
+ * the next character), the requirement that :999: | |
+ * follows should work. */ | |
+ STRCPY(ptr, ".\\{-1,}"); | |
+ ptr += 7; | |
+ } else { | |
+ /* File name followed by '\\' or '%': include as | |
+ * many file name chars as possible. */ | |
+ STRCPY(ptr, "\\f\\+"); | |
+ ptr += 4; | |
} | |
- if (efmp < efm + len) { | |
- efmp++; | |
- *ptr++ = *efmp; // could be ']' | |
- while (efmp < efm + len) { | |
- efmp++; | |
- if ((*ptr++ = *efmp) == ']') { | |
- break; | |
+ } else { | |
+ srcptr = (char_u *)fmt_pat[idx].pattern; | |
+ while ((*ptr = *srcptr++) != NUL) | |
+ ++ptr; | |
+ } | |
+ *ptr++ = '\\'; | |
+ *ptr++ = ')'; | |
+ } else if (*efmp == '*') { | |
+ if (*++efmp == '[' || *efmp == '\\') { | |
+ if ((*ptr++ = *efmp) == '[') { /* %*[^a-z0-9] etc. */ | |
+ if (efmp[1] == '^') | |
+ *ptr++ = *++efmp; | |
+ if (efmp < efm + len) { | |
+ *ptr++ = *++efmp; /* could be ']' */ | |
+ while (efmp < efm + len | |
+ && (*ptr++ = *++efmp) != ']') | |
+ /* skip */; | |
+ if (efmp == efm + len) { | |
+ EMSG(_("E374: Missing ] in format string")); | |
+ goto error2; | |
} | |
} | |
- if (efmp == efm + len) { | |
- EMSG(_("E374: Missing ] in format string")); | |
- return -1; | |
- } | |
- } | |
- } else if (efmp < efm + len) { // %*\D, %*\s etc. | |
- efmp++; | |
- *ptr++ = *efmp; | |
+ } else if (efmp < efm + len) /* %*\D, %*\s etc. */ | |
+ *ptr++ = *++efmp; | |
+ *ptr++ = '\\'; | |
+ *ptr++ = '+'; | |
+ } else { | |
+ /* TODO: scanf()-like: %*ud, %*3c, %*f, ... ? */ | |
+ sprintf((char *)errmsg, | |
+ _("E375: Unsupported %%%c in format string"), *efmp); | |
+ EMSG(errmsg); | |
+ goto error2; | |
+ } | |
+ } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) | |
+ *ptr++ = *efmp; /* regexp magic characters */ | |
+ else if (*efmp == '#') | |
+ *ptr++ = '*'; | |
+ else if (*efmp == '>') | |
+ fmt_ptr->conthere = TRUE; | |
+ else if (efmp == efm + 1) { /* analyse prefix */ | |
+ if (vim_strchr((char_u *)"+-", *efmp) != NULL) | |
+ fmt_ptr->flags = *efmp++; | |
+ if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) | |
+ fmt_ptr->prefix = *efmp; | |
+ else { | |
+ sprintf((char *)errmsg, | |
+ _("E376: Invalid %%%c in format string prefix"), *efmp); | |
+ EMSG(errmsg); | |
+ goto error2; | |
} | |
- *ptr++ = '\\'; | |
- *ptr++ = '+'; | |
- } else { | |
- // TODO(vim): scanf()-like: %*ud, %*3c, %*f, ... ? | |
- snprintf((char *)errmsg, CMDBUFFSIZE + 1, | |
- _("E375: Unsupported %%%c in format string"), *efmp); | |
- EMSG(errmsg); | |
- return -1; | |
- } | |
- } else if (vim_strchr((char_u *)"%\\.^$~[", *efmp) != NULL) { | |
- *ptr++ = *efmp; // regexp magic characters | |
- } else if (*efmp == '#') { | |
- *ptr++ = '*'; | |
- } else if (*efmp == '>') { | |
- fmt_ptr->conthere = true; | |
- } else if (efmp == efm + 1) { // analyse prefix | |
- if (vim_strchr((char_u *)"+-", *efmp) != NULL) { | |
- fmt_ptr->flags = *efmp++; | |
- } | |
- if (vim_strchr((char_u *)"DXAEWICZGOPQ", *efmp) != NULL) { | |
- fmt_ptr->prefix = *efmp; | |
} else { | |
- snprintf((char *)errmsg, CMDBUFFSIZE + 1, | |
- _("E376: Invalid %%%c in format string prefix"), *efmp); | |
+ sprintf((char *)errmsg, | |
+ _("E377: Invalid %%%c in format string"), *efmp); | |
EMSG(errmsg); | |
- return -1; | |
+ goto error2; | |
} | |
- } else { | |
- snprintf((char *)errmsg, CMDBUFFSIZE + 1, | |
- _("E377: Invalid %%%c in format string"), *efmp); | |
- EMSG(errmsg); | |
- return -1; | |
- } | |
- } else { // copy normal character | |
- if (*efmp == '\\' && efmp + 1 < efm + len) { | |
- efmp++; | |
- } else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) { | |
- *ptr++ = '\\'; // escape regexp atoms | |
- } | |
- if (*efmp) { | |
- *ptr++ = *efmp; | |
+ } else { /* copy normal character */ | |
+ if (*efmp == '\\' && efmp + 1 < efm + len) | |
+ ++efmp; | |
+ else if (vim_strchr((char_u *)".*^$~[", *efmp) != NULL) | |
+ *ptr++ = '\\'; /* escape regexp atoms */ | |
+ if (*efmp) | |
+ *ptr++ = *efmp; | |
} | |
} | |
+ *ptr++ = '$'; | |
+ *ptr = NUL; | |
+ if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) | |
+ goto error2; | |
+ /* | |
+ * Advance to next part | |
+ */ | |
+ efm = skip_to_option_part(efm + len); /* skip comma and spaces */ | |
} | |
- *ptr++ = '$'; | |
- *ptr = NUL; | |
- | |
- return 0; | |
-} | |
- | |
-static efm_T *fmt_start = NULL; // cached across qf_parse_line() calls | |
- | |
-static void free_efm_list(efm_T **efm_first) | |
-{ | |
- for (efm_T *efm_ptr = *efm_first; efm_ptr != NULL; efm_ptr = *efm_first) { | |
- *efm_first = efm_ptr->next; | |
- vim_regfree(efm_ptr->prog); | |
- xfree(efm_ptr); | |
- } | |
- | |
- fmt_start = NULL; | |
-} | |
- | |
-// Parse 'errorformat' option | |
-static efm_T * parse_efm_option(char_u *efm) | |
-{ | |
- efm_T *fmt_ptr = NULL; | |
- efm_T *fmt_first = NULL; | |
- efm_T *fmt_last = NULL; | |
- int len; | |
- | |
- size_t errmsglen = CMDBUFFSIZE + 1; | |
- char_u *errmsg = xmalloc(errmsglen); | |
- | |
- // Get some space to modify the format string into. | |
- size_t i = (FMT_PATTERNS * 3) + (STRLEN(efm) << 2); | |
- for (int round = FMT_PATTERNS - 1; round >= 0; ) { | |
- i += STRLEN(fmt_pat[round--].pattern); | |
- } | |
- i += 2; // "%f" can become two chars longer | |
- char_u *fmtstr = xmalloc(i); | |
- | |
- while (efm[0] != NUL) { | |
- // Allocate a new eformat structure and put it at the end of the list | |
- fmt_ptr = (efm_T *)xcalloc(1, sizeof(efm_T)); | |
- if (fmt_first == NULL) { // first one | |
- fmt_first = fmt_ptr; | |
- } else { | |
- fmt_last->next = fmt_ptr; | |
- } | |
- fmt_last = fmt_ptr; | |
- | |
- // Isolate one part in the 'errorformat' option | |
- for (len = 0; efm[len] != NUL && efm[len] != ','; len++) { | |
- if (efm[len] == '\\' && efm[len + 1] != NUL) { | |
- len++; | |
- } | |
- } | |
- | |
- if (efm_to_regpat(efm, len, fmt_ptr, fmtstr, errmsg) == -1) { | |
- goto parse_efm_error; | |
- } | |
- if ((fmt_ptr->prog = vim_regcomp(fmtstr, RE_MAGIC + RE_STRING)) == NULL) { | |
- goto parse_efm_error; | |
- } | |
- // Advance to next part | |
- efm = skip_to_option_part(efm + len); // skip comma and spaces | |
- } | |
- | |
- if (fmt_first == NULL) { // nothing found | |
+ if (fmt_first == NULL) { /* nothing found */ | |
EMSG(_("E378: 'errorformat' contains no pattern")); | |
+ goto error2; | |
} | |
- goto parse_efm_end; | |
- | |
-parse_efm_error: | |
- free_efm_list(&fmt_first); | |
- | |
-parse_efm_end: | |
- xfree(fmtstr); | |
- xfree(errmsg); | |
- | |
- return fmt_first; | |
-} | |
- | |
-static char_u *qf_grow_linebuf(qfstate_T *state, size_t newsz) | |
-{ | |
- // If the line exceeds LINE_MAXLEN exclude the last | |
- // byte since it's not a NL character. | |
- state->linelen = newsz > LINE_MAXLEN ? LINE_MAXLEN - 1 : newsz; | |
- if (state->growbuf == NULL) { | |
- state->growbuf = xmalloc(state->linelen + 1); | |
- state->growbufsiz = state->linelen; | |
- } else if (state->linelen > state->growbufsiz) { | |
- state->growbuf = xrealloc(state->growbuf, state->linelen + 1); | |
- state->growbufsiz = state->linelen; | |
- } | |
- return state->growbuf; | |
-} | |
- | |
-/// Get the next string (separated by newline) from state->p_str. | |
-static int qf_get_next_str_line(qfstate_T *state) | |
-{ | |
- // Get the next line from the supplied string | |
- char_u *p_str = state->p_str; | |
- char_u *p; | |
- size_t len; | |
- | |
- if (*p_str == NUL) { // Reached the end of the string | |
- return QF_END_OF_INPUT; | |
- } | |
- | |
- p = vim_strchr(p_str, '\n'); | |
- if (p != NULL) { | |
- len = (size_t)(p - p_str) + 1; | |
- } else { | |
- len = STRLEN(p_str); | |
- } | |
- | |
- if (len > IOSIZE - 2) { | |
- state->linebuf = qf_grow_linebuf(state, len); | |
- } else { | |
- state->linebuf = IObuff; | |
- state->linelen = len; | |
- } | |
- STRLCPY(state->linebuf, p_str, state->linelen + 1); | |
- | |
- // Increment using len in order to discard the rest of the line if it | |
- // exceeds LINE_MAXLEN. | |
- p_str += len; | |
- state->p_str = p_str; | |
- | |
- return QF_OK; | |
-} | |
- | |
-/// Get the next string from state->p_Li. | |
-static int qf_get_next_list_line(qfstate_T *state) | |
-{ | |
- listitem_T *p_li = state->p_li; | |
- size_t len; | |
- | |
- // Get the next line from the supplied list | |
- while (p_li != NULL | |
- && (p_li->li_tv.v_type != VAR_STRING | |
- || p_li->li_tv.vval.v_string == NULL)) { | |
- p_li = p_li->li_next; // Skip non-string items | |
- } | |
- | |
- if (p_li == NULL) { // End of the list | |
- state->p_li = NULL; | |
- return QF_END_OF_INPUT; | |
- } | |
- | |
- len = STRLEN(p_li->li_tv.vval.v_string); | |
- if (len > IOSIZE - 2) { | |
- state->linebuf = qf_grow_linebuf(state, len); | |
- } else { | |
- state->linebuf = IObuff; | |
- state->linelen = len; | |
- } | |
- | |
- STRLCPY(state->linebuf, p_li->li_tv.vval.v_string, state->linelen + 1); | |
- | |
- state->p_li = p_li->li_next; // next item | |
- return QF_OK; | |
-} | |
- | |
-/// Get the next string from state->buf. | |
-static int qf_get_next_buf_line(qfstate_T *state) | |
-{ | |
- char_u *p_buf = NULL; | |
- size_t len; | |
+ /* | |
+ * got_int is reset here, because it was probably set when killing the | |
+ * ":make" command, but we still want to read the errorfile then. | |
+ */ | |
+ got_int = FALSE; | |
- // Get the next line from the supplied buffer | |
- if (state->buflnum > state->lnumlast) { | |
- return QF_END_OF_INPUT; | |
- } | |
- p_buf = ml_get_buf(state->buf, state->buflnum, false); | |
- state->buflnum += 1; | |
+ /* Always ignore case when looking for a matching error. */ | |
+ regmatch.rm_ic = TRUE; | |
- len = STRLEN(p_buf); | |
- if (len > IOSIZE - 2) { | |
- state->linebuf = qf_grow_linebuf(state, len); | |
- } else { | |
- state->linebuf = IObuff; | |
- state->linelen = len; | |
+ if (tv != NULL) { | |
+ if (tv->v_type == VAR_STRING) | |
+ p_str = tv->vval.v_string; | |
+ else if (tv->v_type == VAR_LIST) | |
+ p_li = tv->vval.v_list->lv_first; | |
} | |
- STRLCPY(state->linebuf, p_buf, state->linelen + 1); | |
- | |
- return QF_OK; | |
-} | |
-/// Get the next string from file state->fd. | |
-static int qf_get_next_file_line(qfstate_T *state) | |
-{ | |
- size_t growbuflen; | |
+ /* | |
+ * Read the lines in the error file one by one. | |
+ * Try to recognize one of the error formats in each line. | |
+ */ | |
+ while (!got_int) { | |
+ /* Get the next line. */ | |
+ if (fd == NULL) { | |
+ if (tv != NULL) { | |
+ if (tv->v_type == VAR_STRING) { | |
+ /* Get the next line from the supplied string */ | |
+ char_u *p; | |
+ | |
+ if (!*p_str) /* Reached the end of the string */ | |
+ break; | |
-retry: | |
- errno = 0; | |
- if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { | |
- if (errno == EINTR) { | |
- goto retry; | |
- } | |
- return QF_END_OF_INPUT; | |
- } | |
+ p = vim_strchr(p_str, '\n'); | |
+ if (p) | |
+ len = (int)(p - p_str + 1); | |
+ else | |
+ len = (int)STRLEN(p_str); | |
- bool discard = false; | |
- state->linelen = STRLEN(IObuff); | |
- if (state->linelen == IOSIZE - 1 | |
- && !(IObuff[state->linelen - 1] == '\n')) { | |
- // The current line exceeds IObuff, continue reading using growbuf | |
- // until EOL or LINE_MAXLEN bytes is read. | |
- if (state->growbuf == NULL) { | |
- state->growbufsiz = 2 * (IOSIZE - 1); | |
- state->growbuf = xmalloc(state->growbufsiz); | |
- } | |
+ if (len > CMDBUFFSIZE - 2) | |
+ STRLCPY(IObuff, p_str, CMDBUFFSIZE - 1); | |
+ else | |
+ STRLCPY(IObuff, p_str, len + 1); | |
+ | |
+ p_str += len; | |
+ } else if (tv->v_type == VAR_LIST) { | |
+ // Get the next line from the supplied list | |
+ while (p_li && (p_li->li_tv.v_type != VAR_STRING | |
+ || p_li->li_tv.vval.v_string == NULL)) { | |
+ p_li = p_li->li_next; // Skip non-string items | |
+ } | |
- // Copy the read part of the line, excluding null-terminator | |
- memcpy(state->growbuf, IObuff, IOSIZE - 1); | |
- growbuflen = state->linelen; | |
+ if (!p_li) /* End of the list */ | |
+ break; | |
- for (;;) { | |
- errno = 0; | |
- if (fgets((char *)state->growbuf + growbuflen, | |
- (int)(state->growbufsiz - growbuflen), state->fd) == NULL) { | |
- if (errno == EINTR) { | |
- continue; | |
- } | |
- break; | |
- } | |
- state->linelen = STRLEN(state->growbuf + growbuflen); | |
- growbuflen += state->linelen; | |
- if (state->growbuf[growbuflen - 1] == '\n') { | |
- break; | |
- } | |
- if (state->growbufsiz == LINE_MAXLEN) { | |
- discard = true; | |
- break; | |
- } | |
+ len = (int)STRLEN(p_li->li_tv.vval.v_string); | |
+ if (len > CMDBUFFSIZE - 2) | |
+ len = CMDBUFFSIZE - 2; | |
- state->growbufsiz = (2 * state->growbufsiz < LINE_MAXLEN) | |
- ? 2 * state->growbufsiz : LINE_MAXLEN; | |
- state->growbuf = xrealloc(state->growbuf, state->growbufsiz); | |
- } | |
+ STRLCPY(IObuff, p_li->li_tv.vval.v_string, len + 1); | |
- while (discard) { | |
- // The current line is longer than LINE_MAXLEN, continue reading but | |
- // discard everything until EOL or EOF is reached. | |
- errno = 0; | |
- if (fgets((char *)IObuff, IOSIZE, state->fd) == NULL) { | |
- if (errno == EINTR) { | |
- continue; | |
+ p_li = p_li->li_next; /* next item */ | |
} | |
- break; | |
- } | |
- if (STRLEN(IObuff) < IOSIZE - 1 || IObuff[IOSIZE - 1] == '\n') { | |
- break; | |
- } | |
- } | |
- | |
- state->linebuf = state->growbuf; | |
- state->linelen = growbuflen; | |
- } else { | |
- state->linebuf = IObuff; | |
- } | |
- return QF_OK; | |
-} | |
- | |
-/// Get the next string from a file/buffer/list/string. | |
-static int qf_get_nextline(qfstate_T *state) | |
-{ | |
- int status = QF_FAIL; | |
- | |
- if (state->fd == NULL) { | |
- if (state->tv != NULL) { | |
- if (state->tv->v_type == VAR_STRING) { | |
- // Get the next line from the supplied string | |
- status = qf_get_next_str_line(state); | |
- } else if (state->tv->v_type == VAR_LIST) { | |
- // Get the next line from the supplied list | |
- status = qf_get_next_list_line(state); | |
+ } else { | |
+ /* Get the next line from the supplied buffer */ | |
+ if (buflnum > lnumlast) | |
+ break; | |
+ STRLCPY(IObuff, ml_get_buf(buf, buflnum++, FALSE), | |
+ CMDBUFFSIZE - 1); | |
} | |
- } else { | |
- // Get the next line from the supplied buffer | |
- status = qf_get_next_buf_line(state); | |
- } | |
- } else { | |
- // Get the next line from the supplied file | |
- status = qf_get_next_file_line(state); | |
- } | |
+ } else if (fgets((char *)IObuff, CMDBUFFSIZE - 2, fd) == NULL) | |
+ break; | |
- if (status != QF_OK) { | |
- return status; | |
- } | |
+ IObuff[CMDBUFFSIZE - 2] = NUL; /* for very long lines */ | |
+ remove_bom(IObuff); | |
- if (state->linelen > 0 && state->linebuf[state->linelen - 1] == '\n') { | |
- state->linebuf[state->linelen - 1] = NUL; | |
+ if ((efmp = vim_strrchr(IObuff, '\n')) != NULL) | |
+ *efmp = NUL; | |
#ifdef USE_CRNL | |
- if (state->linelen > 1 && state->linebuf[state->linelen - 2] == '\r') { | |
- state->linebuf[state->linelen - 2] = NUL; | |
- } | |
+ if ((efmp = vim_strrchr(IObuff, '\r')) != NULL) | |
+ *efmp = NUL; | |
#endif | |
- } | |
- | |
- remove_bom(state->linebuf); | |
- | |
- return QF_OK; | |
-} | |
- | |
- | |
-/// Parse a line and get the quickfix fields. | |
-/// Return the QF_ status. | |
-static int qf_parse_line(qf_info_T *qi, char_u *linebuf, size_t linelen, | |
- efm_T *fmt_first, qffields_T *fields) | |
-{ | |
- efm_T *fmt_ptr; | |
- size_t len; | |
- int i; | |
- int idx = 0; | |
- char_u *tail = NULL; | |
- regmatch_T regmatch; | |
- | |
- // Always ignore case when looking for a matching error. | |
- regmatch.rm_ic = true; | |
- | |
- // If there was no %> item start at the first pattern | |
- if (fmt_start == NULL) { | |
- fmt_ptr = fmt_first; | |
- } else { | |
- fmt_ptr = fmt_start; | |
- fmt_start = NULL; | |
- } | |
+ /* If there was no %> item start at the first pattern */ | |
+ if (fmt_start == NULL) | |
+ fmt_ptr = fmt_first; | |
+ else { | |
+ fmt_ptr = fmt_start; | |
+ fmt_start = NULL; | |
+ } | |
- // Try to match each part of 'errorformat' until we find a complete | |
- // match or no match. | |
- fields->valid = true; | |
+ // Try to match each part of 'errorformat' until we find a complete | |
+ // match or no match. | |
+ bool valid = true; | |
restofline: | |
- for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { | |
- idx = fmt_ptr->prefix; | |
- if (qi->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) { | |
- continue; | |
- } | |
- fields->namebuf[0] = NUL; | |
- fields->pattern[0] = NUL; | |
- if (!qi->qf_multiscan) { | |
- fields->errmsg[0] = NUL; | |
- } | |
- fields->lnum = 0; | |
- fields->col = 0; | |
- fields->use_viscol = false; | |
- fields->enr = -1; | |
- fields->type = 0; | |
- tail = NULL; | |
- | |
- regmatch.regprog = fmt_ptr->prog; | |
- int r = vim_regexec(®match, linebuf, (colnr_T)0); | |
- fmt_ptr->prog = regmatch.regprog; | |
- if (r) { | |
- if ((idx == 'C' || idx == 'Z') && !qi->qf_multiline) { | |
+ for (; fmt_ptr != NULL; fmt_ptr = fmt_ptr->next) { | |
+ idx = fmt_ptr->prefix; | |
+ if (multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL) | |
continue; | |
- } | |
- if (vim_strchr((char_u *)"EWI", idx) != NULL) { | |
- fields->type = (char_u)idx; | |
- } else { | |
- fields->type = 0; | |
- } | |
- // Extract error message data from matched line. | |
- // We check for an actual submatch, because "\[" and "\]" in | |
- // the 'errorformat' may cause the wrong submatch to be used. | |
- if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f | |
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { | |
- continue; | |
- } | |
- // Expand ~/file and $HOME/file to full path. | |
- char_u c = *regmatch.endp[i]; | |
- *regmatch.endp[i] = NUL; | |
- expand_env(regmatch.startp[i], fields->namebuf, CMDBUFFSIZE); | |
- *regmatch.endp[i] = c; | |
- | |
- if (vim_strchr((char_u *)"OPQ", idx) != NULL | |
- && !os_path_exists(fields->namebuf)) { | |
+ namebuf[0] = NUL; | |
+ pattern[0] = NUL; | |
+ if (!multiscan) | |
+ errmsg[0] = NUL; | |
+ lnum = 0; | |
+ col = 0; | |
+ use_viscol = false; | |
+ enr = -1; | |
+ type = 0; | |
+ tail = NULL; | |
+ | |
+ regmatch.regprog = fmt_ptr->prog; | |
+ int r = vim_regexec(®match, IObuff, (colnr_T)0); | |
+ fmt_ptr->prog = regmatch.regprog; | |
+ if (r) { | |
+ if ((idx == 'C' || idx == 'Z') && !multiline) { | |
continue; | |
} | |
- } | |
- if ((i = (int)fmt_ptr->addr[1]) > 0) { // %n | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
+ if (vim_strchr((char_u *)"EWI", idx) != NULL) { | |
+ type = (char_u)idx; | |
+ } else { | |
+ type = 0; | |
} | |
- fields->enr = (int)atol((char *)regmatch.startp[i]); | |
- } | |
- if ((i = (int)fmt_ptr->addr[2]) > 0) { // %l | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
+ // Extract error message data from matched line. | |
+ // We check for an actual submatch, because "\[" and "\]" in | |
+ // the 'errorformat' may cause the wrong submatch to be used. | |
+ if ((i = (int)fmt_ptr->addr[0]) > 0) { // %f | |
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { | |
+ continue; | |
+ } | |
+ // Expand ~/file and $HOME/file to full path. | |
+ char_u c = *regmatch.endp[i]; | |
+ *regmatch.endp[i] = NUL; | |
+ expand_env(regmatch.startp[i], namebuf, CMDBUFFSIZE); | |
+ *regmatch.endp[i] = c; | |
+ | |
+ if (vim_strchr((char_u *)"OPQ", idx) != NULL | |
+ && !os_path_exists(namebuf)) { | |
+ continue; | |
+ } | |
} | |
- fields->lnum = atol((char *)regmatch.startp[i]); | |
- } | |
- if ((i = (int)fmt_ptr->addr[3]) > 0) { // %c | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
+ if ((i = (int)fmt_ptr->addr[1]) > 0) { /* %n */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ enr = (int)atol((char *)regmatch.startp[i]); | |
} | |
- fields->col = (int)atol((char *)regmatch.startp[i]); | |
- } | |
- if ((i = (int)fmt_ptr->addr[4]) > 0) { // %t | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
+ if ((i = (int)fmt_ptr->addr[2]) > 0) { /* %l */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ lnum = atol((char *)regmatch.startp[i]); | |
} | |
- fields->type = *regmatch.startp[i]; | |
- } | |
- if (fmt_ptr->flags == '+' && !qi->qf_multiscan) { // %+ | |
- if (linelen > fields->errmsglen) { | |
- // linelen + null terminator | |
- fields->errmsg = xrealloc(fields->errmsg, linelen + 1); | |
- fields->errmsglen = linelen + 1; | |
+ if ((i = (int)fmt_ptr->addr[3]) > 0) { /* %c */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ col = (int)atol((char *)regmatch.startp[i]); | |
} | |
- STRLCPY(fields->errmsg, linebuf, linelen + 1); | |
- } else if ((i = (int)fmt_ptr->addr[5]) > 0) { // %m | |
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { | |
- continue; | |
+ if ((i = (int)fmt_ptr->addr[4]) > 0) { /* %t */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ type = *regmatch.startp[i]; | |
} | |
- len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); | |
- if (len > fields->errmsglen) { | |
- // len + null terminator | |
- fields->errmsg = xrealloc(fields->errmsg, len + 1); | |
- fields->errmsglen = len + 1; | |
+ if (fmt_ptr->flags == '+' && !multiscan) /* %+ */ | |
+ STRCPY(errmsg, IObuff); | |
+ else if ((i = (int)fmt_ptr->addr[5]) > 0) { /* %m */ | |
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) | |
+ continue; | |
+ len = (int)(regmatch.endp[i] - regmatch.startp[i]); | |
+ STRLCPY(errmsg, regmatch.startp[i], len + 1); | |
} | |
- STRLCPY(fields->errmsg, regmatch.startp[i], len + 1); | |
- } | |
- if ((i = (int)fmt_ptr->addr[6]) > 0) { // %r | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
+ if ((i = (int)fmt_ptr->addr[6]) > 0) { /* %r */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ tail = regmatch.startp[i]; | |
} | |
- tail = regmatch.startp[i]; | |
- } | |
- if ((i = (int)fmt_ptr->addr[7]) > 0) { // %p | |
- char_u *match_ptr; | |
+ if ((i = (int)fmt_ptr->addr[7]) > 0) { /* %p */ | |
+ char_u *match_ptr; | |
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { | |
- continue; | |
- } | |
- fields->col = 0; | |
- for (match_ptr = regmatch.startp[i]; | |
- match_ptr != regmatch.endp[i]; match_ptr++) { | |
- fields->col++; | |
- if (*match_ptr == TAB) { | |
- fields->col += 7; | |
- fields->col -= fields->col % 8; | |
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) | |
+ continue; | |
+ col = 0; | |
+ for (match_ptr = regmatch.startp[i]; | |
+ match_ptr != regmatch.endp[i]; ++match_ptr) { | |
+ ++col; | |
+ if (*match_ptr == TAB) { | |
+ col += 7; | |
+ col -= col % 8; | |
+ } | |
} | |
+ col++; | |
+ use_viscol = true; | |
} | |
- fields->col++; | |
- fields->use_viscol = true; | |
- } | |
- if ((i = (int)fmt_ptr->addr[8]) > 0) { // %v | |
- if (regmatch.startp[i] == NULL) { | |
- continue; | |
- } | |
- fields->col = (int)atol((char *)regmatch.startp[i]); | |
- fields->use_viscol = true; | |
- } | |
- if ((i = (int)fmt_ptr->addr[9]) > 0) { // %s | |
- if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) { | |
- continue; | |
- } | |
- len = (size_t)(regmatch.endp[i] - regmatch.startp[i]); | |
- if (len > CMDBUFFSIZE - 5) { | |
- len = CMDBUFFSIZE - 5; | |
- } | |
- STRCPY(fields->pattern, "^\\V"); | |
- xstrlcat((char *)fields->pattern, (char *)regmatch.startp[i], | |
- CMDBUFFSIZE+1); | |
- fields->pattern[len + 3] = '\\'; | |
- fields->pattern[len + 4] = '$'; | |
- fields->pattern[len + 5] = NUL; | |
- } | |
- break; | |
- } | |
- } | |
- qi->qf_multiscan = false; | |
- | |
- if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { | |
- if (fmt_ptr != NULL) { | |
- if (idx == 'D') { // enter directory | |
- if (*fields->namebuf == NUL) { | |
- EMSG(_("E379: Missing or empty directory name")); | |
- return QF_FAIL; | |
+ if ((i = (int)fmt_ptr->addr[8]) > 0) { /* %v */ | |
+ if (regmatch.startp[i] == NULL) | |
+ continue; | |
+ col = (int)atol((char *)regmatch.startp[i]); | |
+ use_viscol = true; | |
} | |
- qi->qf_directory = qf_push_dir(fields->namebuf, &qi->qf_dir_stack, | |
- false); | |
- if (qi->qf_directory == NULL) { | |
- return QF_FAIL; | |
+ if ((i = (int)fmt_ptr->addr[9]) > 0) { /* %s */ | |
+ if (regmatch.startp[i] == NULL || regmatch.endp[i] == NULL) | |
+ continue; | |
+ len = (int)(regmatch.endp[i] - regmatch.startp[i]); | |
+ if (len > CMDBUFFSIZE - 5) | |
+ len = CMDBUFFSIZE - 5; | |
+ STRCPY(pattern, "^\\V"); | |
+ STRNCAT(pattern, regmatch.startp[i], len); | |
+ pattern[len + 3] = '\\'; | |
+ pattern[len + 4] = '$'; | |
+ pattern[len + 5] = NUL; | |
} | |
- } else if (idx == 'X') { // leave directory | |
- qi->qf_directory = qf_pop_dir(&qi->qf_dir_stack); | |
+ break; | |
} | |
} | |
- fields->namebuf[0] = NUL; // no match found, remove file name | |
- fields->lnum = 0; // don't jump to this line | |
- fields->valid = false; | |
- if (linelen > fields->errmsglen) { | |
- // linelen + null terminator | |
- fields->errmsg = xrealloc(fields->errmsg, linelen + 1); | |
- fields->errmsglen = linelen + 1; | |
- } | |
- // copy whole line to error message | |
- STRLCPY(fields->errmsg, linebuf, linelen + 1); | |
- if (fmt_ptr == NULL) { | |
- qi->qf_multiline = qi->qf_multiignore = false; | |
- } | |
- } else { | |
- // honor %> item | |
- if (fmt_ptr->conthere) { | |
- fmt_start = fmt_ptr; | |
- } | |
+ multiscan = false; | |
- if (vim_strchr((char_u *)"AEWI", idx) != NULL) { | |
- qi->qf_multiline = true; // start of a multi-line message | |
- qi->qf_multiignore = false; // reset continuation | |
- } else if (vim_strchr((char_u *)"CZ", idx) | |
- != NULL) { // continuation of multi-line msg | |
- if (!qi->qf_multiignore) { | |
- qfline_T *qfprev = qi->qf_lists[qi->qf_curlist].qf_last; | |
- if (qfprev == NULL) { | |
- return QF_FAIL; | |
- } | |
- if (*fields->errmsg && !qi->qf_multiignore) { | |
+ if (fmt_ptr == NULL || idx == 'D' || idx == 'X') { | |
+ if (fmt_ptr != NULL) { | |
+ if (idx == 'D') { /* enter directory */ | |
+ if (*namebuf == NUL) { | |
+ EMSG(_("E379: Missing or empty directory name")); | |
+ goto error2; | |
+ } | |
+ if ((directory = qf_push_dir(namebuf, &dir_stack)) == NULL) | |
+ goto error2; | |
+ } else if (idx == 'X') /* leave directory */ | |
+ directory = qf_pop_dir(&dir_stack); | |
+ } | |
+ namebuf[0] = NUL; // no match found, remove file name | |
+ lnum = 0; // don't jump to this line | |
+ valid = false; | |
+ STRCPY(errmsg, IObuff); // copy whole line to error message | |
+ if (fmt_ptr == NULL) { | |
+ multiline = multiignore = false; | |
+ } | |
+ } else if (fmt_ptr != NULL) { | |
+ /* honor %> item */ | |
+ if (fmt_ptr->conthere) | |
+ fmt_start = fmt_ptr; | |
+ | |
+ if (vim_strchr((char_u *)"AEWI", idx) != NULL) { | |
+ multiline = true; // start of a multi-line message | |
+ multiignore = false; // reset continuation | |
+ } else if (vim_strchr((char_u *)"CZ", idx) | |
+ != NULL) { /* continuation of multi-line msg */ | |
+ if (qfprev == NULL) | |
+ goto error2; | |
+ if (*errmsg && !multiignore) { | |
size_t len = STRLEN(qfprev->qf_text); | |
- qfprev->qf_text = xrealloc(qfprev->qf_text, | |
- len + STRLEN(fields->errmsg) + 2); | |
+ qfprev->qf_text = xrealloc(qfprev->qf_text, len + STRLEN(errmsg) + 2); | |
qfprev->qf_text[len] = '\n'; | |
- STRCPY(qfprev->qf_text + len + 1, fields->errmsg); | |
- } | |
- if (qfprev->qf_nr == -1) { | |
- qfprev->qf_nr = fields->enr; | |
- } | |
- if (vim_isprintc(fields->type) && !qfprev->qf_type) { | |
- qfprev->qf_type = fields->type; // only printable chars allowed | |
- } | |
- if (!qfprev->qf_lnum) { | |
- qfprev->qf_lnum = fields->lnum; | |
- } | |
- if (!qfprev->qf_col) { | |
- qfprev->qf_col = fields->col; | |
+ STRCPY(qfprev->qf_text + len + 1, errmsg); | |
+ } | |
+ if (qfprev->qf_nr == -1) | |
+ qfprev->qf_nr = enr; | |
+ if (vim_isprintc(type) && !qfprev->qf_type) | |
+ qfprev->qf_type = type; /* only printable chars allowed */ | |
+ if (!qfprev->qf_lnum) | |
+ qfprev->qf_lnum = lnum; | |
+ if (!qfprev->qf_col) | |
+ qfprev->qf_col = col; | |
+ qfprev->qf_viscol = use_viscol; | |
+ if (!qfprev->qf_fnum) | |
+ qfprev->qf_fnum = qf_get_fnum(directory, | |
+ *namebuf | |
+ || directory ? namebuf : currfile | |
+ && valid ? currfile : 0); | |
+ if (idx == 'Z') { | |
+ multiline = multiignore = false; | |
} | |
- qfprev->qf_viscol = fields->use_viscol; | |
- if (!qfprev->qf_fnum) { | |
- qfprev->qf_fnum = qf_get_fnum(qi, qi->qf_directory, | |
- *fields->namebuf || qi->qf_directory | |
- ? fields->namebuf | |
- : qi->qf_currfile && fields->valid | |
- ? qi->qf_currfile : 0); | |
+ line_breakcheck(); | |
+ continue; | |
+ } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) { | |
+ // global file names | |
+ valid = false; | |
+ if (*namebuf == NUL || os_path_exists(namebuf)) { | |
+ if (*namebuf && idx == 'P') { | |
+ currfile = qf_push_dir(namebuf, &file_stack); | |
+ } else if (idx == 'Q') { | |
+ currfile = qf_pop_dir(&file_stack); | |
+ } | |
+ *namebuf = NUL; | |
+ if (tail && *tail) { | |
+ STRMOVE(IObuff, skipwhite(tail)); | |
+ multiscan = true; | |
+ goto restofline; | |
+ } | |
} | |
} | |
- if (idx == 'Z') { | |
- qi->qf_multiline = qi->qf_multiignore = false; | |
- } | |
- | |
- line_breakcheck(); | |
- return QF_IGNORE_LINE; | |
- } else if (vim_strchr((char_u *)"OPQ", idx) != NULL) { | |
- // global file names | |
- fields->valid = false; | |
- if (*fields->namebuf == NUL || os_path_exists(fields->namebuf)) { | |
- if (*fields->namebuf && idx == 'P') { | |
- qi->qf_currfile = qf_push_dir(fields->namebuf, &qi->qf_file_stack, | |
- true); | |
- } else if (idx == 'Q') { | |
- qi->qf_currfile = qf_pop_dir(&qi->qf_file_stack); | |
+ if (fmt_ptr->flags == '-') { // generally exclude this line | |
+ if (multiline) { | |
+ multiignore = true; // also exclude continuation lines | |
} | |
- *fields->namebuf = NUL; | |
- if (tail && *tail) { | |
- STRMOVE(IObuff, skipwhite(tail)); | |
- qi->qf_multiscan = true; | |
- goto restofline; | |
- } | |
- } | |
- } | |
- if (fmt_ptr->flags == '-') { // generally exclude this line | |
- if (qi->qf_multiline) { | |
- // also exclude continuation lines | |
- qi->qf_multiignore = true; | |
+ continue; | |
} | |
- return QF_IGNORE_LINE; | |
- } | |
- } | |
- | |
- return QF_OK; | |
-} | |
- | |
-// Read the errorfile "efile" into memory, line by line, building the error | |
-// list. | |
-// Alternative: when "efile" is NULL read errors from buffer "buf". | |
-// Alternative: when "tv" is not NULL get errors from the string or list. | |
-// Always use 'errorformat' from "buf" if there is a local value. | |
-// Then "lnumfirst" and "lnumlast" specify the range of lines to use. | |
-// Set the title of the list to "qf_title". | |
-// Return -1 for error, number of errors for success. | |
-static int | |
-qf_init_ext( | |
- qf_info_T *qi, | |
- char_u *efile, | |
- buf_T *buf, | |
- typval_T *tv, | |
- 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 *qf_title | |
-) | |
-{ | |
- qfstate_T state = { NULL, 0, NULL, 0, NULL, NULL, NULL, NULL, | |
- NULL, 0, 0 }; | |
- qffields_T fields = { NULL, NULL, 0, 0L, 0, false, NULL, 0, 0, 0 }; | |
- qfline_T *old_last = NULL; | |
- bool adding = false; | |
- static efm_T *fmt_first = NULL; | |
- char_u *efm; | |
- static char_u *last_efm = NULL; | |
- int retval = -1; // default: return error flag | |
- int status; | |
- | |
- // Do not used the cached buffer, it may have been wiped out. | |
- xfree(qf_last_bufname); | |
- qf_last_bufname = NULL; | |
- | |
- fields.namebuf = xmalloc(CMDBUFFSIZE + 1); | |
- fields.errmsglen = CMDBUFFSIZE + 1; | |
- fields.errmsg = xmalloc(fields.errmsglen); | |
- fields.pattern = xmalloc(CMDBUFFSIZE + 1); | |
- | |
- if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL) { | |
- EMSG2(_(e_openerrf), efile); | |
- goto qf_init_end; | |
- } | |
- | |
- if (newlist || qi->qf_curlist == qi->qf_listcount) { | |
- // make place for a new list | |
- qf_new_list(qi, qf_title); | |
- } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { | |
- // Adding to existing list, use last entry. | |
- adding = true; | |
- old_last = qi->qf_lists[qi->qf_curlist].qf_last; | |
- } | |
- | |
- // Use the local value of 'errorformat' if it's set. | |
- if (errorformat == p_efm && tv == NULL && buf && *buf->b_p_efm != NUL) { | |
- efm = buf->b_p_efm; | |
- } else { | |
- efm = errorformat; | |
- } | |
- | |
- // If we are not adding or adding to another list: clear the state. | |
- if (newlist || qi->qf_curlist != qi->qf_dir_curlist) { | |
- qi->qf_dir_curlist = qi->qf_curlist; | |
- qf_clean_dir_stack(&qi->qf_dir_stack); | |
- qi->qf_directory = NULL; | |
- qf_clean_dir_stack(&qi->qf_file_stack); | |
- qi->qf_currfile = NULL; | |
- qi->qf_multiline = false; | |
- qi->qf_multiignore = false; | |
- qi->qf_multiscan = false; | |
- } | |
- | |
- // If the errorformat didn't change between calls, then reuse the previously | |
- // parsed values. | |
- if (last_efm == NULL || (STRCMP(last_efm, efm) != 0)) { | |
- // free the previously parsed data | |
- xfree(last_efm); | |
- last_efm = NULL; | |
- free_efm_list(&fmt_first); | |
- | |
- // parse the current 'efm' | |
- fmt_first = parse_efm_option(efm); | |
- if (fmt_first != NULL) { | |
- last_efm = vim_strsave(efm); | |
- } | |
- } | |
- | |
- if (fmt_first == NULL) { // nothing found | |
- goto error2; | |
- } | |
- | |
- /* | |
- * got_int is reset here, because it was probably set when killing the | |
- * ":make" command, but we still want to read the errorfile then. | |
- */ | |
- got_int = FALSE; | |
- | |
- if (tv != NULL) { | |
- if (tv->v_type == VAR_STRING) { | |
- state.p_str = tv->vval.v_string; | |
- } else if (tv->v_type == VAR_LIST) { | |
- state.p_li = tv->vval.v_list->lv_first; | |
- } | |
- state.tv = tv; | |
- } | |
- state.buf = buf; | |
- state.buflnum = lnumfirst; | |
- state.lnumlast = lnumlast; | |
- | |
- /* | |
- * Read the lines in the error file one by one. | |
- * Try to recognize one of the error formats in each line. | |
- */ | |
- while (!got_int) { | |
- // Get the next line from a file/buffer/list/string | |
- status = qf_get_nextline(&state); | |
- if (status == QF_END_OF_INPUT) { // end of input | |
- break; | |
} | |
- status = qf_parse_line(qi, state.linebuf, state.linelen, fmt_first, | |
- &fields); | |
- if (status == QF_FAIL) { | |
+ if (qf_add_entry(qi, &qfprev, | |
+ directory, | |
+ (*namebuf || directory) | |
+ ? namebuf | |
+ : ((currfile && valid) ? currfile : (char_u *)NULL), | |
+ 0, | |
+ errmsg, | |
+ lnum, | |
+ col, | |
+ use_viscol, | |
+ pattern, | |
+ enr, | |
+ type, | |
+ valid) == FAIL) | |
goto error2; | |
- } | |
- if (status == QF_IGNORE_LINE) { | |
- continue; | |
- } | |
- | |
- if (qf_add_entry(qi, | |
- qi->qf_directory, | |
- (*fields.namebuf || qi->qf_directory) | |
- ? fields.namebuf : ((qi->qf_currfile && fields.valid) | |
- ? qi->qf_currfile : (char_u *)NULL), | |
- 0, | |
- fields.errmsg, | |
- fields.lnum, | |
- fields.col, | |
- fields.use_viscol, | |
- fields.pattern, | |
- fields.enr, | |
- fields.type, | |
- fields.valid) == FAIL) { | |
- goto error2; | |
- } | |
line_breakcheck(); | |
} | |
- if (state.fd == NULL || !ferror(state.fd)) { | |
+ if (fd == NULL || !ferror(fd)) { | |
if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { | |
/* no valid entry found */ | |
qi->qf_lists[qi->qf_curlist].qf_ptr = | |
@@ -1125,27 +762,31 @@ qf_init_ext( | |
} | |
/* return number of matches */ | |
retval = qi->qf_lists[qi->qf_curlist].qf_count; | |
- goto qf_init_end; | |
+ goto qf_init_ok; | |
} | |
EMSG(_(e_readerrf)); | |
error2: | |
- if (!adding) { | |
- qf_free(qi, qi->qf_curlist); | |
- qi->qf_listcount--; | |
- if (qi->qf_curlist > 0) { | |
- qi->qf_curlist--; | |
- } | |
- } | |
+ qf_free(qi, qi->qf_curlist); | |
+ qi->qf_listcount--; | |
+ if (qi->qf_curlist > 0) | |
+ --qi->qf_curlist; | |
+qf_init_ok: | |
+ if (fd != NULL) | |
+ fclose(fd); | |
+ for (fmt_ptr = fmt_first; fmt_ptr != NULL; fmt_ptr = fmt_first) { | |
+ fmt_first = fmt_ptr->next; | |
+ vim_regfree(fmt_ptr->prog); | |
+ xfree(fmt_ptr); | |
+ } | |
+ qf_clean_dir_stack(&dir_stack); | |
+ qf_clean_dir_stack(&file_stack); | |
qf_init_end: | |
- if (state.fd != NULL) { | |
- fclose(state.fd); | |
- } | |
- xfree(fields.namebuf); | |
- xfree(fields.errmsg); | |
- xfree(fields.pattern); | |
- xfree(state.growbuf); | |
+ xfree(namebuf); | |
+ xfree(errmsg); | |
+ xfree(pattern); | |
+ xfree(fmtstr); | |
- qf_update_buffer(qi, old_last); | |
+ qf_update_buffer(qi); | |
return retval; | |
} | |
@@ -1228,6 +869,7 @@ void qf_free_all(win_T *wp) | |
/// Add an entry to the end of the list of errors. | |
/// | |
/// @param qi quickfix list | |
+/// @param prevp nonnull pointer (to previously added entry or NULL) | |
/// @param dir optional directory name | |
/// @param fname file name or NULL | |
/// @param bufnum buffer number or zero | |
@@ -1241,24 +883,17 @@ void qf_free_all(win_T *wp) | |
/// @param valid valid entry | |
/// | |
/// @returns OK or FAIL. | |
-static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, | |
- char_u *mesg, long lnum, int col, char_u vis_col, | |
- char_u *pattern, int nr, char_u type, char_u valid) | |
+static int qf_add_entry(qf_info_T *qi, qfline_T **prevp, char_u *dir, | |
+ char_u *fname, int bufnum, char_u *mesg, long lnum, | |
+ int col, char_u vis_col, char_u *pattern, int nr, | |
+ char_u type, char_u valid) | |
{ | |
qfline_T *qfp = xmalloc(sizeof(qfline_T)); | |
- qfline_T **lastp; // pointer to qf_last or NULL | |
- | |
- if (bufnum != 0) { | |
- buf_T *buf = buflist_findnr(bufnum); | |
+ if (bufnum != 0) | |
qfp->qf_fnum = bufnum; | |
- if (buf != NULL) { | |
- buf->b_has_qf_entry |= | |
- (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; | |
- } | |
- } else { | |
- qfp->qf_fnum = qf_get_fnum(qi, dir, fname); | |
- } | |
+ else | |
+ qfp->qf_fnum = qf_get_fnum(dir, fname); | |
qfp->qf_text = vim_strsave(mesg); | |
qfp->qf_lnum = lnum; | |
qfp->qf_col = col; | |
@@ -1271,25 +906,24 @@ static int qf_add_entry(qf_info_T *qi, char_u *dir, char_u *fname, int bufnum, | |
qfp->qf_nr = nr; | |
if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */ | |
type = 0; | |
- qfp->qf_type = (char_u)type; | |
+ qfp->qf_type = type; | |
qfp->qf_valid = valid; | |
- lastp = &qi->qf_lists[qi->qf_curlist].qf_last; | |
if (qi->qf_lists[qi->qf_curlist].qf_count == 0) { | |
/* first element in the list */ | |
qi->qf_lists[qi->qf_curlist].qf_start = qfp; | |
qi->qf_lists[qi->qf_curlist].qf_ptr = qfp; | |
qi->qf_lists[qi->qf_curlist].qf_index = 0; | |
- qfp->qf_prev = NULL; | |
+ qfp->qf_prev = qfp; // first element points to itself | |
} else { | |
- assert(*lastp); | |
- qfp->qf_prev = *lastp; | |
- (*lastp)->qf_next = qfp; | |
- } | |
- qfp->qf_next = NULL; | |
- qfp->qf_cleared = false; | |
- *lastp = qfp; | |
- qi->qf_lists[qi->qf_curlist].qf_count++; | |
+ assert(*prevp); | |
+ qfp->qf_prev = *prevp; | |
+ (*prevp)->qf_next = qfp; | |
+ } | |
+ qfp->qf_next = qfp; /* last element points to itself */ | |
+ qfp->qf_cleared = FALSE; | |
+ *prevp = qfp; | |
+ ++qi->qf_lists[qi->qf_curlist].qf_count; | |
if (qi->qf_lists[qi->qf_curlist].qf_index == 0 && qfp->qf_valid) { | |
/* first valid entry */ | |
qi->qf_lists[qi->qf_curlist].qf_index = | |
@@ -1374,7 +1008,6 @@ void copy_loclist(win_T *from, win_T *to) | |
to_qfl->qf_count = 0; | |
to_qfl->qf_index = 0; | |
to_qfl->qf_start = NULL; | |
- to_qfl->qf_last = NULL; | |
to_qfl->qf_ptr = NULL; | |
if (from_qfl->qf_title != NULL) | |
to_qfl->qf_title = vim_strsave(from_qfl->qf_title); | |
@@ -1383,24 +1016,23 @@ void copy_loclist(win_T *from, win_T *to) | |
if (from_qfl->qf_count) { | |
qfline_T *from_qfp; | |
- qfline_T *prevp; | |
- | |
- // copy all the location entries in this list | |
- for (i = 0, from_qfp = from_qfl->qf_start; | |
- i < from_qfl->qf_count && from_qfp != NULL; | |
- i++, from_qfp = from_qfp->qf_next) { | |
- if (qf_add_entry(to->w_llist, | |
- NULL, | |
- NULL, | |
- 0, | |
- from_qfp->qf_text, | |
- from_qfp->qf_lnum, | |
- from_qfp->qf_col, | |
- from_qfp->qf_viscol, | |
- from_qfp->qf_pattern, | |
- from_qfp->qf_nr, | |
- 0, | |
- from_qfp->qf_valid) == FAIL) { | |
+ qfline_T *prevp = NULL; | |
+ | |
+ /* copy all the location entries in this list */ | |
+ for (i = 0, from_qfp = from_qfl->qf_start; i < from_qfl->qf_count; | |
+ ++i, from_qfp = from_qfp->qf_next) { | |
+ if (qf_add_entry(to->w_llist, &prevp, | |
+ NULL, | |
+ NULL, | |
+ 0, | |
+ from_qfp->qf_text, | |
+ from_qfp->qf_lnum, | |
+ from_qfp->qf_col, | |
+ from_qfp->qf_viscol, | |
+ from_qfp->qf_pattern, | |
+ from_qfp->qf_nr, | |
+ 0, | |
+ from_qfp->qf_valid) == FAIL) { | |
qf_free_all(to); | |
return; | |
} | |
@@ -1409,12 +1041,10 @@ void copy_loclist(win_T *from, win_T *to) | |
* directory and file names are not supplied. So the qf_fnum | |
* field is copied here. | |
*/ | |
- prevp = to->w_llist->qf_lists[to->w_llist->qf_curlist].qf_last; | |
- prevp->qf_fnum = from_qfp->qf_fnum; // file number | |
- prevp->qf_type = from_qfp->qf_type; // error type | |
- if (from_qfl->qf_ptr == from_qfp) { | |
- to_qfl->qf_ptr = prevp; // current location | |
- } | |
+ prevp->qf_fnum = from_qfp->qf_fnum; /* file number */ | |
+ prevp->qf_type = from_qfp->qf_type; /* error type */ | |
+ if (from_qfl->qf_ptr == from_qfp) | |
+ to_qfl->qf_ptr = prevp; /* current location */ | |
} | |
} | |
@@ -1431,67 +1061,52 @@ void copy_loclist(win_T *from, win_T *to) | |
to->w_llist->qf_curlist = qi->qf_curlist; /* current list */ | |
} | |
-// Get buffer number for file "directory/fname". | |
-// Also sets the b_has_qf_entry flag. | |
-static int qf_get_fnum(qf_info_T *qi, char_u *directory, char_u *fname) | |
+/* | |
+ * get buffer number for file "dir.name" | |
+ */ | |
+static int qf_get_fnum(char_u *directory, char_u *fname) | |
{ | |
- char_u *ptr = NULL; | |
- char_u *bufname; | |
- buf_T *buf; | |
- if (fname == NULL || *fname == NUL) { // no file name | |
- return 0; | |
- } | |
- | |
-#ifdef BACKSLASH_IN_FILENAME | |
- if (directory != NULL) { | |
- slash_adjust(directory); | |
- } | |
- slash_adjust(fname); | |
-#endif | |
- if (directory != NULL && !vim_isAbsName(fname)) { | |
- ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); | |
- // Here we check if the file really exists. | |
- // This should normally be true, but if make works without | |
- // "leaving directory"-messages we might have missed a | |
- // directory change. | |
- if (!os_path_exists(ptr)) { | |
- xfree(ptr); | |
- directory = qf_guess_filepath(qi, fname); | |
- if (directory) { | |
- ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, true); | |
- } else { | |
- ptr = vim_strsave(fname); | |
- } | |
- } | |
- // Use concatenated directory name and file name. | |
- bufname = ptr; | |
- } else { | |
- bufname = fname; | |
- } | |
- | |
- if (qf_last_bufname != NULL | |
- && STRCMP(bufname, qf_last_bufname) == 0 | |
- && bufref_valid(&qf_last_bufref)) { | |
- buf = qf_last_bufref.br_buf; | |
- xfree(ptr); | |
- } else { | |
- xfree(qf_last_bufname); | |
- buf = buflist_new(bufname, NULL, (linenr_T)0, BLN_NOOPT); | |
- qf_last_bufname = (bufname == ptr) ? bufname : vim_strsave(bufname); | |
- set_bufref(&qf_last_bufref, buf); | |
- } | |
- if (buf == NULL) { | |
+ if (fname == NULL || *fname == NUL) /* no file name */ | |
return 0; | |
+ { | |
+ char_u *ptr; | |
+ int fnum; | |
+ | |
+#ifdef BACKSLASH_IN_FILENAME | |
+ if (directory != NULL) | |
+ slash_adjust(directory); | |
+ slash_adjust(fname); | |
+#endif | |
+ if (directory != NULL && !vim_isAbsName(fname)) { | |
+ ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); | |
+ /* | |
+ * Here we check if the file really exists. | |
+ * This should normally be true, but if make works without | |
+ * "leaving directory"-messages we might have missed a | |
+ * directory change. | |
+ */ | |
+ if (!os_path_exists(ptr)) { | |
+ xfree(ptr); | |
+ directory = qf_guess_filepath(fname); | |
+ if (directory) | |
+ ptr = (char_u *)concat_fnames((char *)directory, (char *)fname, TRUE); | |
+ else | |
+ ptr = vim_strsave(fname); | |
+ } | |
+ /* Use concatenated directory name and file name */ | |
+ fnum = buflist_add(ptr, 0); | |
+ xfree(ptr); | |
+ return fnum; | |
+ } | |
+ return buflist_add(fname, 0); | |
} | |
- buf->b_has_qf_entry = | |
- (qi == &ql_info) ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; | |
- return buf->b_fnum; | |
} | |
-// Push dirbuf onto the directory stack and return pointer to actual dir or | |
-// NULL on error. | |
-static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, | |
- bool is_file_stack) | |
+/* | |
+ * push dirbuf onto the directory stack and return pointer to actual dir or | |
+ * NULL on error | |
+ */ | |
+static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr) | |
{ | |
struct dir_stack_T *ds_ptr; | |
@@ -1504,7 +1119,7 @@ static char_u *qf_push_dir(char_u *dirbuf, struct dir_stack_T **stackptr, | |
/* store directory on the stack */ | |
if (vim_isAbsName(dirbuf) | |
|| (*stackptr)->next == NULL | |
- || (*stackptr && is_file_stack)) | |
+ || (*stackptr && dir_stack != *stackptr)) | |
(*stackptr)->dirname = vim_strsave(dirbuf); | |
else { | |
/* Okay we don't have an absolute path. | |
@@ -1606,18 +1221,17 @@ static void qf_clean_dir_stack(struct dir_stack_T **stackptr) | |
* Then qf_push_dir thinks we are in ./aa/bb, but we are in ./bb. | |
* qf_guess_filepath will return NULL. | |
*/ | |
-static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) | |
+static char_u *qf_guess_filepath(char_u *filename) | |
{ | |
struct dir_stack_T *ds_ptr; | |
struct dir_stack_T *ds_tmp; | |
char_u *fullname; | |
- // no dirs on the stack - there's nothing we can do | |
- if (qi->qf_dir_stack == NULL) { | |
+ /* no dirs on the stack - there's nothing we can do */ | |
+ if (dir_stack == NULL) | |
return NULL; | |
- } | |
- ds_ptr = qi->qf_dir_stack->next; | |
+ ds_ptr = dir_stack->next; | |
fullname = NULL; | |
while (ds_ptr) { | |
xfree(fullname); | |
@@ -1632,15 +1246,16 @@ static char_u *qf_guess_filepath(qf_info_T *qi, char_u *filename) | |
xfree(fullname); | |
- // clean up all dirs we already left | |
- while (qi->qf_dir_stack->next != ds_ptr) { | |
- ds_tmp = qi->qf_dir_stack->next; | |
- qi->qf_dir_stack->next = qi->qf_dir_stack->next->next; | |
+ /* clean up all dirs we already left */ | |
+ while (dir_stack->next != ds_ptr) { | |
+ ds_tmp = dir_stack->next; | |
+ dir_stack->next = dir_stack->next->next; | |
xfree(ds_tmp->dirname); | |
xfree(ds_tmp); | |
} | |
- return ds_ptr == NULL ? NULL : ds_ptr->dirname; | |
+ return ds_ptr==NULL ? NULL : ds_ptr->dirname; | |
+ | |
} | |
/// When loading a file from the quickfix, the auto commands may modify it. | |
@@ -1657,7 +1272,7 @@ static bool is_qf_entry_present(qf_info_T *qi, qfline_T *qf_ptr) | |
// Search for the entry in the current list | |
for (i = 0, qfp = qfl->qf_start; i < qfl->qf_count; i++, qfp = qfp->qf_next) { | |
- if (qfp == NULL || qfp == qf_ptr) { | |
+ if (qfp == qf_ptr) { | |
break; | |
} | |
} | |
@@ -1892,7 +1507,7 @@ win_found: | |
* If there is only one window and it is the quickfix window, create a | |
* new one above the quickfix window. | |
*/ | |
- if ((ONE_WINDOW && bt_quickfix(curbuf)) || !usable_win) { | |
+ if (((firstwin == lastwin) && bt_quickfix(curbuf)) || !usable_win) { | |
flags = WSP_ABOVE; | |
if (ll_ref != NULL) | |
flags |= WSP_NEWLOC; | |
@@ -2005,7 +1620,7 @@ win_found: | |
ok = buflist_getfile(qf_ptr->qf_fnum, (linenr_T)1, | |
GETF_SETMARK | GETF_SWITCH, forceit); | |
- if (qi != &ql_info && !win_valid_any_tab(oldwin)) { | |
+ if (qi != &ql_info && !win_valid(oldwin)) { | |
EMSG(_("E924: Current window was closed")); | |
is_abort = true; | |
opened_window = false; | |
@@ -2211,20 +1826,21 @@ void qf_list(exarg_T *eap) | |
if (qfp->qf_lnum == 0) { | |
IObuff[0] = NUL; | |
} else if (qfp->qf_col == 0) { | |
- vim_snprintf((char *)IObuff, IOSIZE, ":%" PRIdLINENR, qfp->qf_lnum); | |
+ vim_snprintf((char *)IObuff, IOSIZE, ":%" PRId64, | |
+ (int64_t)qfp->qf_lnum); | |
} else { | |
- vim_snprintf((char *)IObuff, IOSIZE, ":%" PRIdLINENR " col %d", | |
- qfp->qf_lnum, qfp->qf_col); | |
+ vim_snprintf((char *)IObuff, IOSIZE, ":%" PRId64 " col %d", | |
+ (int64_t)qfp->qf_lnum, qfp->qf_col); | |
} | |
vim_snprintf((char *)IObuff + STRLEN(IObuff), IOSIZE, "%s:", | |
(char *)qf_types(qfp->qf_type, qfp->qf_nr)); | |
- msg_puts_attr((const char *)IObuff, hl_attr(HLF_N)); | |
+ msg_puts_attr(IObuff, hl_attr(HLF_N)); | |
if (qfp->qf_pattern != NULL) { | |
qf_fmt_text(qfp->qf_pattern, IObuff, IOSIZE); | |
- xstrlcat((char *)IObuff, ":", IOSIZE); | |
- msg_puts((const char *)IObuff); | |
+ STRCAT(IObuff, ":"); | |
+ msg_puts(IObuff); | |
} | |
- msg_puts(" "); | |
+ msg_puts((char_u *)" "); | |
/* Remove newlines and leading whitespace from the text. For an | |
* unrecognized line keep the indent, the compiler may mark a word | |
@@ -2237,10 +1853,7 @@ void qf_list(exarg_T *eap) | |
} | |
qfp = qfp->qf_next; | |
- if (qfp == NULL) { | |
- break; | |
- } | |
- i++; | |
+ ++i; | |
os_breakcheck(); | |
} | |
} | |
@@ -2266,31 +1879,6 @@ static void qf_fmt_text(char_u *text, char_u *buf, int bufsize) | |
buf[i] = NUL; | |
} | |
-static void qf_msg(qf_info_T *qi, int which, char *lead) | |
-{ | |
- char *title = (char *)qi->qf_lists[which].qf_title; | |
- int count = qi->qf_lists[which].qf_count; | |
- char_u buf[IOSIZE]; | |
- | |
- vim_snprintf((char *)buf, IOSIZE, _("%serror list %d of %d; %d errors "), | |
- lead, | |
- which + 1, | |
- qi->qf_listcount, | |
- count); | |
- | |
- if (title != NULL) { | |
- size_t len = STRLEN(buf); | |
- | |
- if (len < 34) { | |
- memset(buf + len, ' ', 34 - len); | |
- buf[34] = NUL; | |
- } | |
- xstrlcat((char *)buf, title, IOSIZE); | |
- } | |
- trunc_string(buf, buf, (int)Columns - 1, IOSIZE); | |
- msg(buf); | |
-} | |
- | |
/* | |
* ":colder [count]": Up in the quickfix stack. | |
* ":cnewer [count]": Down in the quickfix stack. | |
@@ -2331,95 +1919,69 @@ void qf_age(exarg_T *eap) | |
++qi->qf_curlist; | |
} | |
} | |
- qf_msg(qi, qi->qf_curlist, ""); | |
- qf_update_buffer(qi, NULL); | |
+ qf_msg(qi); | |
} | |
-void qf_history(exarg_T *eap) | |
+static void qf_msg(qf_info_T *qi) | |
{ | |
- qf_info_T *qi = &ql_info; | |
- int i; | |
- | |
- if (eap->cmdidx == CMD_lhistory) { | |
- qi = GET_LOC_LIST(curwin); | |
- } | |
- if (qi == NULL || (qi->qf_listcount == 0 | |
- && qi->qf_lists[qi->qf_curlist].qf_count == 0)) { | |
- MSG(_("No entries")); | |
- } else { | |
- for (i = 0; i < qi->qf_listcount; i++) { | |
- qf_msg(qi, i, i == qi->qf_curlist ? "> " : " "); | |
- } | |
- } | |
+ smsg(_("error list %d of %d; %d errors"), | |
+ qi->qf_curlist + 1, qi->qf_listcount, | |
+ qi->qf_lists[qi->qf_curlist].qf_count); | |
+ qf_update_buffer(qi); | |
} | |
-/// Free all the entries in the error list "idx". | |
+/* | |
+ * Free error list "idx". | |
+ */ | |
static void qf_free(qf_info_T *qi, int idx) | |
{ | |
qfline_T *qfp; | |
- qfline_T *qfpnext; | |
- bool stop = false; | |
+ int stop = FALSE; | |
- while (qi->qf_lists[idx].qf_count && qi->qf_lists[idx].qf_start != NULL) { | |
- qfp = qi->qf_lists[idx].qf_start; | |
- qfpnext = qfp->qf_next; | |
+ while (qi->qf_lists[idx].qf_count) { | |
+ qfp = qi->qf_lists[idx].qf_start->qf_next; | |
if (qi->qf_lists[idx].qf_title != NULL && !stop) { | |
- xfree(qfp->qf_text); | |
- stop = (qfp == qfpnext); | |
- xfree(qfp->qf_pattern); | |
- xfree(qfp); | |
- if (stop) { | |
- // Somehow qf_count may have an incorrect value, set it to 1 | |
- // to avoid crashing when it's wrong. | |
- // TODO(vim): Avoid qf_count being incorrect. | |
+ xfree(qi->qf_lists[idx].qf_start->qf_text); | |
+ stop = (qi->qf_lists[idx].qf_start == qfp); | |
+ xfree(qi->qf_lists[idx].qf_start->qf_pattern); | |
+ xfree(qi->qf_lists[idx].qf_start); | |
+ if (stop) | |
+ /* Somehow qf_count may have an incorrect value, set it to 1 | |
+ * to avoid crashing when it's wrong. | |
+ * TODO: Avoid qf_count being incorrect. */ | |
qi->qf_lists[idx].qf_count = 1; | |
- } | |
} | |
- qi->qf_lists[idx].qf_start = qfpnext; | |
- qi->qf_lists[idx].qf_count--; | |
+ qi->qf_lists[idx].qf_start = qfp; | |
+ --qi->qf_lists[idx].qf_count; | |
} | |
xfree(qi->qf_lists[idx].qf_title); | |
qi->qf_lists[idx].qf_start = NULL; | |
qi->qf_lists[idx].qf_ptr = NULL; | |
qi->qf_lists[idx].qf_title = NULL; | |
qi->qf_lists[idx].qf_index = 0; | |
- | |
- qf_clean_dir_stack(&qi->qf_dir_stack); | |
- qi->qf_directory = NULL; | |
- qf_clean_dir_stack(&qi->qf_file_stack); | |
- qi->qf_currfile = NULL; | |
} | |
/* | |
* qf_mark_adjust: adjust marks | |
*/ | |
-bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, | |
- long amount_after) | |
+void qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, long amount_after) | |
{ | |
int i; | |
qfline_T *qfp; | |
int idx; | |
qf_info_T *qi = &ql_info; | |
- bool found_one = false; | |
- int buf_has_flag = wp == NULL ? BUF_HAS_QF_ENTRY : BUF_HAS_LL_ENTRY; | |
- if (!(curbuf->b_has_qf_entry & buf_has_flag)) { | |
- return false; | |
- } | |
if (wp != NULL) { | |
- if (wp->w_llist == NULL) { | |
- return false; | |
- } | |
+ if (wp->w_llist == NULL) | |
+ return; | |
qi = wp->w_llist; | |
} | |
for (idx = 0; idx < qi->qf_listcount; ++idx) | |
if (qi->qf_lists[idx].qf_count) | |
for (i = 0, qfp = qi->qf_lists[idx].qf_start; | |
- i < qi->qf_lists[idx].qf_count && qfp != NULL; | |
- i++, qfp = qfp->qf_next) { | |
+ i < qi->qf_lists[idx].qf_count; ++i, qfp = qfp->qf_next) | |
if (qfp->qf_fnum == curbuf->b_fnum) { | |
- found_one = true; | |
if (qfp->qf_lnum >= line1 && qfp->qf_lnum <= line2) { | |
if (amount == MAXLNUM) | |
qfp->qf_cleared = TRUE; | |
@@ -2428,9 +1990,6 @@ bool qf_mark_adjust(win_T *wp, linenr_T line1, linenr_T line2, long amount, | |
} else if (amount_after && qfp->qf_lnum > line2) | |
qfp->qf_lnum += amount_after; | |
} | |
- } | |
- | |
- return found_one; | |
} | |
/* | |
@@ -2611,13 +2170,15 @@ void ex_copen(exarg_T *eap) | |
else { | |
/* Create a new quickfix buffer */ | |
(void)do_ecmd(0, NULL, NULL, NULL, ECMD_ONE, ECMD_HIDE, oldwin); | |
- // Switch off 'swapfile'. | |
- set_option_value("swf", 0L, NULL, OPT_LOCAL); | |
- set_option_value("bt", 0L, "quickfix", OPT_LOCAL); | |
- set_option_value("bh", 0L, "wipe", OPT_LOCAL); | |
+ /* switch off 'swapfile' */ | |
+ set_option_value((char_u *)"swf", 0L, NULL, OPT_LOCAL); | |
+ set_option_value((char_u *)"bt", 0L, (char_u *)"quickfix", | |
+ OPT_LOCAL); | |
+ set_option_value((char_u *)"bh", 0L, (char_u *)"wipe", OPT_LOCAL); | |
RESET_BINDING(curwin); | |
- curwin->w_p_diff = false; | |
- set_option_value("fdm", 0L, "manual", OPT_LOCAL); | |
+ curwin->w_p_diff = FALSE; | |
+ set_option_value((char_u *)"fdm", 0L, (char_u *)"manual", | |
+ OPT_LOCAL); | |
} | |
/* Only set the height when still in the same tab page and there is no | |
@@ -2634,7 +2195,7 @@ void ex_copen(exarg_T *eap) | |
qf_set_title_var(qi); | |
// Fill the buffer with the quickfix list. | |
- qf_fill_buffer(qi, curbuf, NULL); | |
+ qf_fill_buffer(qi); | |
curwin->w_cursor.lnum = qi->qf_lists[qi->qf_curlist].qf_index; | |
curwin->w_cursor.col = 0; | |
@@ -2642,44 +2203,6 @@ void ex_copen(exarg_T *eap) | |
update_topline(); /* scroll to show the line */ | |
} | |
-// Move the cursor in the quickfix window to "lnum". | |
-static void qf_win_goto(win_T *win, linenr_T lnum) | |
-{ | |
- win_T *old_curwin = curwin; | |
- | |
- curwin = win; | |
- curbuf = win->w_buffer; | |
- curwin->w_cursor.lnum = lnum; | |
- curwin->w_cursor.col = 0; | |
- curwin->w_cursor.coladd = 0; | |
- curwin->w_curswant = 0; | |
- update_topline(); // scroll to show the line | |
- redraw_later(VALID); | |
- curwin->w_redr_status = true; // update ruler | |
- curwin = old_curwin; | |
- curbuf = curwin->w_buffer; | |
-} | |
- | |
-// :cbottom/:lbottom command. | |
-void ex_cbottom(exarg_T *eap) | |
-{ | |
- qf_info_T *qi = &ql_info; | |
- | |
- if (eap->cmdidx == CMD_lbottom) { | |
- qi = GET_LOC_LIST(curwin); | |
- if (qi == NULL) { | |
- EMSG(_(e_loclist)); | |
- return; | |
- } | |
- } | |
- | |
- win_T *win = qf_find_win(qi); | |
- | |
- if (win != NULL && win->w_cursor.lnum != win->w_buffer->b_ml.ml_line_count) { | |
- qf_win_goto(win, win->w_buffer->b_ml.ml_line_count); | |
- } | |
-} | |
- | |
/* | |
* Return the number of the current entry (line number in the quickfix | |
* window). | |
@@ -2716,14 +2239,24 @@ qf_win_pos_update ( | |
if (win != NULL | |
&& qf_index <= win->w_buffer->b_ml.ml_line_count | |
&& old_qf_index != qf_index) { | |
+ win_T *old_curwin = curwin; | |
+ | |
+ curwin = win; | |
+ curbuf = win->w_buffer; | |
if (qf_index > old_qf_index) { | |
- win->w_redraw_top = old_qf_index; | |
- win->w_redraw_bot = qf_index; | |
+ curwin->w_redraw_top = old_qf_index; | |
+ curwin->w_redraw_bot = qf_index; | |
} else { | |
- win->w_redraw_top = qf_index; | |
- win->w_redraw_bot = old_qf_index; | |
+ curwin->w_redraw_top = qf_index; | |
+ curwin->w_redraw_bot = old_qf_index; | |
} | |
- qf_win_goto(win, qf_index); | |
+ curwin->w_cursor.lnum = qf_index; | |
+ curwin->w_cursor.col = 0; | |
+ update_topline(); /* scroll to show the line */ | |
+ redraw_later(VALID); | |
+ curwin->w_redr_status = TRUE; /* update ruler */ | |
+ curwin = old_curwin; | |
+ curbuf = curwin->w_buffer; | |
} | |
return win != NULL; | |
} | |
@@ -2778,54 +2311,34 @@ static buf_T *qf_find_buf(qf_info_T *qi) | |
return NULL; | |
} | |
-/// Update the w:quickfix_title variable in the quickfix/location list window | |
-static void qf_update_win_titlevar(qf_info_T *qi) | |
-{ | |
- win_T *win; | |
- | |
- if ((win = qf_find_win(qi)) != NULL) { | |
- win_T *curwin_save = curwin; | |
- curwin = win; | |
- qf_set_title_var(qi); | |
- curwin = curwin_save; | |
- } | |
-} | |
- | |
/* | |
* Find the quickfix buffer. If it exists, update the contents. | |
*/ | |
-static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last) | |
+static void qf_update_buffer(qf_info_T *qi) | |
{ | |
buf_T *buf; | |
win_T *win; | |
+ win_T *curwin_save; | |
aco_save_T aco; | |
/* Check if a buffer for the quickfix list exists. Update it. */ | |
buf = qf_find_buf(qi); | |
if (buf != NULL) { | |
- linenr_T old_line_count = buf->b_ml.ml_line_count; | |
+ /* set curwin/curbuf to buf and save a few things */ | |
+ aucmd_prepbuf(&aco, buf); | |
- if (old_last == NULL) { | |
- // set curwin/curbuf to buf and save a few things | |
- aucmd_prepbuf(&aco, buf); | |
+ if ((win = qf_find_win(qi)) != NULL) { | |
+ curwin_save = curwin; | |
+ curwin = win; | |
+ qf_set_title_var(qi); | |
+ curwin = curwin_save; | |
} | |
+ qf_fill_buffer(qi); | |
- qf_update_win_titlevar(qi); | |
- | |
- qf_fill_buffer(qi, buf, old_last); | |
- | |
- if (old_last == NULL) { | |
- (void)qf_win_pos_update(qi, 0); | |
- | |
- // restore curwin/curbuf and a few other things | |
- aucmd_restbuf(&aco); | |
- } | |
+ /* restore curwin/curbuf and a few other things */ | |
+ aucmd_restbuf(&aco); | |
- // Only redraw when added lines are visible. This avoids flickering when | |
- // the added lines are not visible. | |
- if ((win = qf_find_win(qi)) != NULL && old_line_count < win->w_botline) { | |
- redraw_buf_later(buf, NOT_VALID); | |
- } | |
+ (void)qf_win_pos_update(qi, 0); | |
} | |
} | |
@@ -2838,12 +2351,11 @@ static void qf_set_title_var(qf_info_T *qi) | |
} | |
} | |
-// Fill current buffer with quickfix errors, replacing any previous contents. | |
-// curbuf must be the quickfix buffer! | |
-// If "old_last" is not NULL append the items after this one. | |
-// When "old_last" is NULL then "buf" must equal "curbuf"! Because ml_delete() | |
-// is used and autocommands will be triggered. | |
-static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) | |
+/* | |
+ * Fill current buffer with quickfix errors, replacing any previous contents. | |
+ * curbuf must be the quickfix buffer! | |
+ */ | |
+static void qf_fill_buffer(qf_info_T *qi) | |
{ | |
linenr_T lnum; | |
qfline_T *qfp; | |
@@ -2851,29 +2363,15 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) | |
int len; | |
int old_KeyTyped = KeyTyped; | |
- if (old_last == NULL) { | |
- if (buf != curbuf) { | |
- EMSG2(_(e_intern2), "qf_fill_buffer()"); | |
- return; | |
- } | |
- | |
- // delete all existing lines | |
- while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) { | |
- (void)ml_delete((linenr_T)1, false); | |
- } | |
- } | |
+ /* delete all existing lines */ | |
+ while ((curbuf->b_ml.ml_flags & ML_EMPTY) == 0) | |
+ (void)ml_delete((linenr_T)1, FALSE); | |
/* Check if there is anything to display */ | |
if (qi->qf_curlist < qi->qf_listcount) { | |
- // Add one line for each error | |
- if (old_last == NULL) { | |
- qfp = qi->qf_lists[qi->qf_curlist].qf_start; | |
- lnum = 0; | |
- } else { | |
- qfp = old_last->qf_next; | |
- lnum = buf->b_ml.ml_line_count; | |
- } | |
- while (lnum < qi->qf_lists[qi->qf_curlist].qf_count) { | |
+ /* Add one line for each error */ | |
+ qfp = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ for (lnum = 0; lnum < qi->qf_lists[qi->qf_curlist].qf_count; ++lnum) { | |
if (qfp->qf_fnum != 0 | |
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL | |
&& errbuf->b_fname != NULL) { | |
@@ -2913,42 +2411,33 @@ static void qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last) | |
qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text, | |
IObuff + len, IOSIZE - len); | |
- if (ml_append_buf(buf, lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, false) | |
- == FAIL) { | |
+ if (ml_append(lnum, IObuff, (colnr_T)STRLEN(IObuff) + 1, FALSE) | |
+ == FAIL) | |
break; | |
- } | |
- lnum++; | |
qfp = qfp->qf_next; | |
- if (qfp == NULL) { | |
- break; | |
- } | |
- } | |
- if (old_last == NULL) { | |
- // Delete the empty line which is now at the end | |
- (void)ml_delete(lnum + 1, false); | |
} | |
+ /* Delete the empty line which is now at the end */ | |
+ (void)ml_delete(lnum + 1, FALSE); | |
} | |
- // Correct cursor position. | |
- check_lnums(true); | |
- | |
- if (old_last == NULL) { | |
- // Set the 'filetype' to "qf" each time after filling the buffer. This | |
- // resembles reading a file into a buffer, it's more logical when using | |
- // autocommands. | |
- set_option_value("ft", 0L, "qf", OPT_LOCAL); | |
- curbuf->b_p_ma = false; | |
- | |
- keep_filetype = true; // don't detect 'filetype' | |
- apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, | |
- false, curbuf); | |
- apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, | |
- false, curbuf); | |
- keep_filetype = false; | |
- | |
- // make sure it will be redrawn | |
- redraw_curbuf_later(NOT_VALID); | |
- } | |
+ /* correct cursor position */ | |
+ check_lnums(TRUE); | |
+ | |
+ /* Set the 'filetype' to "qf" each time after filling the buffer. This | |
+ * resembles reading a file into a buffer, it's more logical when using | |
+ * autocommands. */ | |
+ set_option_value((char_u *)"ft", 0L, (char_u *)"qf", OPT_LOCAL); | |
+ curbuf->b_p_ma = FALSE; | |
+ | |
+ keep_filetype = TRUE; /* don't detect 'filetype' */ | |
+ apply_autocmds(EVENT_BUFREADPOST, (char_u *)"quickfix", NULL, | |
+ FALSE, curbuf); | |
+ apply_autocmds(EVENT_BUFWINENTER, (char_u *)"quickfix", NULL, | |
+ FALSE, curbuf); | |
+ keep_filetype = FALSE; | |
+ | |
+ /* make sure it will be redrawn */ | |
+ redraw_curbuf_later(NOT_VALID); | |
/* Restore KeyTyped, setting 'filetype' may reset it. */ | |
KeyTyped = old_KeyTyped; | |
@@ -3040,11 +2529,11 @@ void ex_make(exarg_T *eap) | |
case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break; | |
default: break; | |
} | |
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
- curbuf->b_fname, true, curbuf)) { | |
- if (aborting()) { | |
+ if (au_name != NULL) { | |
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
+ curbuf->b_fname, TRUE, curbuf); | |
+ if (did_throw || force_abort) | |
return; | |
- } | |
} | |
if (eap->cmdidx == CMD_lmake || eap->cmdidx == CMD_lgrep | |
@@ -3141,7 +2630,7 @@ static char_u *get_mef_name(void) | |
STRCPY(name, p_mef); | |
sprintf((char *)name + (p - p_mef), "%d%d", start, off); | |
STRCAT(name, p + 2); | |
- // Don't accept a symbolic link, it's a security risk. | |
+ // Don't accept a symbolic link, its a security risk. | |
FileInfo file_info; | |
bool file_or_link_found = os_fileinfo_link((char *)name, &file_info); | |
if (!file_or_link_found) { | |
@@ -3314,6 +2803,7 @@ void ex_cc(exarg_T *eap) | |
|| eap->cmdidx == CMD_lrewind | |
|| eap->cmdidx == CMD_lfirst | |
|| eap->cmdidx == CMD_llast | |
+ || eap->cmdidx == CMD_llast | |
|| eap->cmdidx == CMD_ldo | |
|| eap->cmdidx == CMD_lfdo) { | |
qi = GET_LOC_LIST(curwin); | |
@@ -3370,6 +2860,7 @@ void ex_cnext(exarg_T *eap) | |
|| eap->cmdidx == CMD_lnfile | |
|| eap->cmdidx == CMD_lNfile | |
|| eap->cmdidx == CMD_lpfile | |
+ || eap->cmdidx == CMD_lpfile | |
|| eap->cmdidx == CMD_ldo | |
|| eap->cmdidx == CMD_lfdo) { | |
qi = GET_LOC_LIST(curwin); | |
@@ -3472,6 +2963,7 @@ void ex_vimgrep(exarg_T *eap) | |
int fi; | |
qf_info_T *qi = &ql_info; | |
qfline_T *cur_qf_start; | |
+ qfline_T *prevp = NULL; | |
long lnum; | |
buf_T *buf; | |
int duplicate_name = FALSE; | |
@@ -3502,11 +2994,11 @@ void ex_vimgrep(exarg_T *eap) | |
case CMD_lgrepadd: au_name = (char_u *)"lgrepadd"; break; | |
default: break; | |
} | |
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
- curbuf->b_fname, true, curbuf)) { | |
- if (aborting()) { | |
+ if (au_name != NULL) { | |
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
+ curbuf->b_fname, TRUE, curbuf); | |
+ if (did_throw || force_abort) | |
return; | |
- } | |
} | |
if (eap->cmdidx == CMD_lgrep | |
@@ -3556,6 +3048,12 @@ void ex_vimgrep(exarg_T *eap) | |
|| qi->qf_curlist == qi->qf_listcount) { | |
// make place for a new list | |
qf_new_list(qi, title != NULL ? title : *eap->cmdlinep); | |
+ } else if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { | |
+ // Adding to existing list, find last entry. | |
+ for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ prevp->qf_next != prevp; | |
+ prevp = prevp->qf_next) { | |
+ } | |
} | |
/* parse the list of arguments */ | |
@@ -3651,25 +3149,23 @@ void ex_vimgrep(exarg_T *eap) | |
++lnum) { | |
col = 0; | |
while (vim_regexec_multi(®match, curwin, buf, lnum, | |
- col, NULL) > 0) { | |
- // Pass the buffer number so that it gets used even for a | |
- // dummy buffer, unless duplicate_name is set, then the | |
- // buffer will be wiped out below. | |
- if (qf_add_entry(qi, | |
- NULL, // dir | |
- fname, | |
- duplicate_name ? 0 : buf->b_fnum, | |
- ml_get_buf(buf, | |
- regmatch.startpos[0].lnum + lnum, false), | |
- regmatch.startpos[0].lnum + lnum, | |
- regmatch.startpos[0].col + 1, | |
- false, // vis_col | |
- NULL, // search pattern | |
- 0, // nr | |
- 0, // type | |
- true) // valid | |
- == FAIL) { | |
- got_int = true; | |
+ col, NULL) > 0) { | |
+ ; | |
+ if (qf_add_entry(qi, &prevp, | |
+ NULL, /* dir */ | |
+ fname, | |
+ 0, | |
+ ml_get_buf(buf, | |
+ regmatch.startpos[0].lnum + lnum, FALSE), | |
+ regmatch.startpos[0].lnum + lnum, | |
+ regmatch.startpos[0].col + 1, | |
+ FALSE, /* vis_col */ | |
+ NULL, /* search pattern */ | |
+ 0, /* nr */ | |
+ 0, /* type */ | |
+ TRUE /* valid */ | |
+ ) == FAIL) { | |
+ got_int = TRUE; | |
break; | |
} | |
found_match = TRUE; | |
@@ -3712,23 +3208,17 @@ void ex_vimgrep(exarg_T *eap) | |
buf = NULL; | |
} else if (buf != first_match_buf || (flags & VGR_NOJUMP)) { | |
unload_dummy_buffer(buf, dirname_start); | |
- // Keeping the buffer, remove the dummy flag. | |
- buf->b_flags &= ~BF_DUMMY; | |
buf = NULL; | |
} | |
} | |
if (buf != NULL) { | |
- // Keeping the buffer, remove the dummy flag. | |
- buf->b_flags &= ~BF_DUMMY; | |
- | |
- // If the buffer is still loaded we need to use the | |
- // directory we jumped to below. | |
+ /* If the buffer is still loaded we need to use the | |
+ * directory we jumped to below. */ | |
if (buf == first_match_buf | |
&& target_dir == NULL | |
- && STRCMP(dirname_start, dirname_now) != 0) { | |
+ && STRCMP(dirname_start, dirname_now) != 0) | |
target_dir = vim_strsave(dirname_now); | |
- } | |
/* The buffer is still loaded, the Filetype autocommands | |
* need to be done now, in that buffer. And the modelines | |
@@ -3750,7 +3240,7 @@ void ex_vimgrep(exarg_T *eap) | |
qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; | |
qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
- qf_update_buffer(qi, NULL); | |
+ qf_update_buffer(qi); | |
if (au_name != NULL) | |
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, | |
@@ -3792,6 +3282,52 @@ theend: | |
vim_regfree(regmatch.regprog); | |
} | |
+/* | |
+ * Skip over the pattern argument of ":vimgrep /pat/[g][j]". | |
+ * Put the start of the pattern in "*s", unless "s" is NULL. | |
+ * If "flags" is not NULL put the flags in it: VGR_GLOBAL, VGR_NOJUMP. | |
+ * If "s" is not NULL terminate the pattern with a NUL. | |
+ * Return a pointer to the char just past the pattern plus flags. | |
+ */ | |
+char_u *skip_vimgrep_pat(char_u *p, char_u **s, int *flags) | |
+{ | |
+ int c; | |
+ | |
+ if (vim_isIDc(*p)) { | |
+ /* ":vimgrep pattern fname" */ | |
+ if (s != NULL) | |
+ *s = p; | |
+ p = skiptowhite(p); | |
+ if (s != NULL && *p != NUL) | |
+ *p++ = NUL; | |
+ } else { | |
+ /* ":vimgrep /pattern/[g][j] fname" */ | |
+ if (s != NULL) | |
+ *s = p + 1; | |
+ c = *p; | |
+ p = skip_regexp(p + 1, c, TRUE, NULL); | |
+ if (*p != c) | |
+ return NULL; | |
+ | |
+ /* Truncate the pattern. */ | |
+ if (s != NULL) | |
+ *p = NUL; | |
+ ++p; | |
+ | |
+ /* Find the flags */ | |
+ while (*p == 'g' || *p == 'j') { | |
+ if (flags != NULL) { | |
+ if (*p == 'g') | |
+ *flags |= VGR_GLOBAL; | |
+ else | |
+ *flags |= VGR_NOJUMP; | |
+ } | |
+ ++p; | |
+ } | |
+ } | |
+ return p; | |
+} | |
+ | |
/* | |
* Restore current working directory to "dirname_start" if they differ, taking | |
* into account whether it is set locally or globally. | |
@@ -3833,9 +3369,8 @@ load_dummy_buffer ( | |
) | |
{ | |
buf_T *newbuf; | |
- bufref_T newbufref; | |
- bufref_T newbuf_to_wipe; | |
- int failed = true; | |
+ buf_T *newbuf_to_wipe = NULL; | |
+ int failed = TRUE; | |
aco_save_T aco; | |
// Allocate a buffer without putting it in the buffer list. | |
@@ -3843,7 +3378,6 @@ load_dummy_buffer ( | |
if (newbuf == NULL) { | |
return NULL; | |
} | |
- set_bufref(&newbufref, newbuf); | |
/* Init the options. */ | |
buf_copy_options(newbuf, BCO_ENTER | BCO_NOHELP); | |
@@ -3863,7 +3397,6 @@ load_dummy_buffer ( | |
* work. */ | |
curbuf->b_flags &= ~BF_DUMMY; | |
- newbuf_to_wipe.br_buf = NULL; | |
if (readfile(fname, NULL, | |
(linenr_T)0, (linenr_T)0, (linenr_T)MAXLNUM, | |
NULL, READ_NEW | READ_DUMMY) == OK | |
@@ -3871,24 +3404,19 @@ load_dummy_buffer ( | |
&& !(curbuf->b_flags & BF_NEW)) { | |
failed = FALSE; | |
if (curbuf != newbuf) { | |
- // Bloody autocommands changed the buffer! Can happen when | |
- // using netrw and editing a remote file. Use the current | |
- // buffer instead, delete the dummy one after restoring the | |
- // window stuff. | |
- set_bufref(&newbuf_to_wipe, newbuf); | |
+ /* Bloody autocommands changed the buffer! Can happen when | |
+ * using netrw and editing a remote file. Use the current | |
+ * buffer instead, delete the dummy one after restoring the | |
+ * window stuff. */ | |
+ newbuf_to_wipe = newbuf; | |
newbuf = curbuf; | |
} | |
} | |
- // Restore curwin/curbuf and a few other things. | |
+ /* restore curwin/curbuf and a few other things */ | |
aucmd_restbuf(&aco); | |
- if (newbuf_to_wipe.br_buf != NULL && bufref_valid(&newbuf_to_wipe)) { | |
- wipe_buffer(newbuf_to_wipe.br_buf, false); | |
- } | |
- | |
- // Add back the "dummy" flag, otherwise buflist_findname_file_id() | |
- // won't skip it. | |
- newbuf->b_flags |= BF_DUMMY; | |
+ if (newbuf_to_wipe != NULL && buf_valid(newbuf_to_wipe)) | |
+ wipe_buffer(newbuf_to_wipe, FALSE); | |
} | |
/* | |
@@ -3899,9 +3427,8 @@ load_dummy_buffer ( | |
os_dirname(resulting_dir, MAXPATHL); | |
restore_start_dir(dirname_start); | |
- if (!bufref_valid(&newbufref)) { | |
+ if (!buf_valid(newbuf)) | |
return NULL; | |
- } | |
if (failed) { | |
wipe_dummy_buffer(newbuf, dirname_start); | |
return NULL; | |
@@ -3949,11 +3476,13 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start) | |
} | |
} | |
-/// Add each quickfix error to list "list" as a dictionary. | |
-/// If qf_idx is -1, use the current list. Otherwise, use the specified list. | |
-int get_errorlist(win_T *wp, int qf_idx, list_T *list) | |
+/* | |
+ * Add each quickfix error to list "list" as a dictionary. | |
+ */ | |
+int get_errorlist(win_T *wp, list_T *list) | |
{ | |
qf_info_T *qi = &ql_info; | |
+ dict_T *dict; | |
char_u buf[2]; | |
qfline_T *qfp; | |
int i; | |
@@ -3965,154 +3494,66 @@ int get_errorlist(win_T *wp, int qf_idx, list_T *list) | |
return FAIL; | |
} | |
- if (qf_idx == -1) { | |
- qf_idx = qi->qf_curlist; | |
- } | |
- | |
- if (qf_idx >= qi->qf_listcount | |
- || qi->qf_lists[qf_idx].qf_count == 0) { | |
+ if (qi->qf_curlist >= qi->qf_listcount | |
+ || qi->qf_lists[qi->qf_curlist].qf_count == 0) | |
return FAIL; | |
- } | |
- qfp = qi->qf_lists[qf_idx].qf_start; | |
- for (i = 1; !got_int && i <= qi->qf_lists[qf_idx].qf_count; i++) { | |
- // Handle entries with a non-existing buffer number. | |
+ qfp = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ for (i = 1; !got_int && i <= qi->qf_lists[qi->qf_curlist].qf_count; ++i) { | |
+ /* Handle entries with a non-existing buffer number. */ | |
bufnum = qfp->qf_fnum; | |
if (bufnum != 0 && (buflist_findnr(bufnum) == NULL)) | |
bufnum = 0; | |
- dict_T *const dict = tv_dict_alloc(); | |
- tv_list_append_dict(list, dict); | |
+ dict = dict_alloc(); | |
+ list_append_dict(list, dict); | |
buf[0] = qfp->qf_type; | |
buf[1] = NUL; | |
- if (tv_dict_add_nr(dict, S_LEN("bufnr"), (varnumber_T)bufnum) == FAIL | |
- || (tv_dict_add_nr(dict, S_LEN("lnum"), (varnumber_T)qfp->qf_lnum) | |
- == FAIL) | |
- || (tv_dict_add_nr(dict, S_LEN("col"), (varnumber_T)qfp->qf_col) | |
- == FAIL) | |
- || (tv_dict_add_nr(dict, S_LEN("vcol"), (varnumber_T)qfp->qf_viscol) | |
- == FAIL) | |
- || (tv_dict_add_nr(dict, S_LEN("nr"), (varnumber_T)qfp->qf_nr) == FAIL) | |
- || tv_dict_add_str(dict, S_LEN("pattern"), | |
- (qfp->qf_pattern == NULL | |
- ? "" | |
- : (const char *)qfp->qf_pattern)) == FAIL | |
- || tv_dict_add_str(dict, S_LEN("text"), | |
- (qfp->qf_text == NULL | |
- ? "" | |
- : (const char *)qfp->qf_text)) == FAIL | |
- || tv_dict_add_str(dict, S_LEN("type"), (const char *)buf) == FAIL | |
- || (tv_dict_add_nr(dict, S_LEN("valid"), (varnumber_T)qfp->qf_valid) | |
- == FAIL)) { | |
- // tv_dict_add* fail only if key already exist, but this is a newly | |
- // allocated dictionary which is thus guaranteed to have no existing keys. | |
- assert(false); | |
- } | |
+ if ( dict_add_nr_str(dict, "bufnr", (long)bufnum, NULL) == FAIL | |
+ || dict_add_nr_str(dict, "lnum", (long)qfp->qf_lnum, NULL) == FAIL | |
+ || dict_add_nr_str(dict, "col", (long)qfp->qf_col, NULL) == FAIL | |
+ || dict_add_nr_str(dict, "vcol", (long)qfp->qf_viscol, NULL) == FAIL | |
+ || dict_add_nr_str(dict, "nr", (long)qfp->qf_nr, NULL) == FAIL | |
+ || dict_add_nr_str(dict, "pattern", 0L, | |
+ qfp->qf_pattern == NULL ? (char_u *)"" : qfp->qf_pattern) == FAIL | |
+ || dict_add_nr_str(dict, "text", 0L, | |
+ qfp->qf_text == NULL ? (char_u *)"" : qfp->qf_text) == FAIL | |
+ || dict_add_nr_str(dict, "type", 0L, buf) == FAIL | |
+ || dict_add_nr_str(dict, "valid", (long)qfp->qf_valid, NULL) == FAIL) | |
+ return FAIL; | |
qfp = qfp->qf_next; | |
- if (qfp == NULL) { | |
- break; | |
- } | |
} | |
return OK; | |
} | |
-/// Flags used by getqflist()/getloclist() to determine which fields to return. | |
-enum { | |
- QF_GETLIST_NONE = 0x0, | |
- QF_GETLIST_TITLE = 0x1, | |
- QF_GETLIST_ITEMS = 0x2, | |
- QF_GETLIST_NR = 0x4, | |
- QF_GETLIST_WINID = 0x8, | |
- QF_GETLIST_ALL = 0xFF | |
-}; | |
- | |
-/// Return quickfix/location list details (title) as a | |
-/// dictionary. 'what' contains the details to return. If 'list_idx' is -1, | |
-/// then current list is used. Otherwise the specified list is used. | |
-int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict) | |
-{ | |
- qf_info_T *qi = &ql_info; | |
- | |
- if (wp != NULL) { | |
- qi = GET_LOC_LIST(wp); | |
- if (qi == NULL) { | |
- return FAIL; | |
- } | |
- } | |
- | |
- int status = OK; | |
- dictitem_T *di; | |
- int flags = QF_GETLIST_NONE; | |
- | |
- int qf_idx = qi->qf_curlist; // default is the current list | |
- if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) { | |
- // Use the specified quickfix/location list | |
- if (di->di_tv.v_type == VAR_NUMBER) { | |
- // for zero use the current list | |
- if (di->di_tv.vval.v_number != 0) { | |
- qf_idx = (int)di->di_tv.vval.v_number - 1; | |
- if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { | |
- return FAIL; | |
- } | |
- } | |
- flags |= QF_GETLIST_NR; | |
- } else { | |
- return FAIL; | |
- } | |
- } | |
- | |
- if (tv_dict_find(what, S_LEN("all")) != NULL) { | |
- flags |= QF_GETLIST_ALL; | |
- } | |
- | |
- if (tv_dict_find(what, S_LEN("title")) != NULL) { | |
- flags |= QF_GETLIST_TITLE; | |
- } | |
- | |
- if (tv_dict_find(what, S_LEN("winid")) != NULL) { | |
- flags |= QF_GETLIST_WINID; | |
- } | |
- | |
- if (flags & QF_GETLIST_TITLE) { | |
- char_u *t = qi->qf_lists[qf_idx].qf_title; | |
- if (t == NULL) { | |
- t = (char_u *)""; | |
- } | |
- status = tv_dict_add_str(retdict, S_LEN("title"), (const char *)t); | |
- } | |
- if ((status == OK) && (flags & QF_GETLIST_NR)) { | |
- status = tv_dict_add_nr(retdict, S_LEN("nr"), qf_idx + 1); | |
- } | |
- if ((status == OK) && (flags & QF_GETLIST_WINID)) { | |
- win_T *win = qf_find_win(qi); | |
- if (win != NULL) { | |
- status = tv_dict_add_nr(retdict, S_LEN("winid"), win->handle); | |
- } | |
- } | |
- | |
- return status; | |
-} | |
- | |
-/// Add list of entries to quickfix/location list. Each list entry is | |
-/// a dictionary with item information. | |
-static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, | |
- int action) | |
+/* | |
+ * Populate the quickfix list with the items supplied in the list | |
+ * of dictionaries. "title" will be copied to w:quickfix_title | |
+ */ | |
+int set_errorlist(win_T *wp, list_T *list, int action, char_u *title) | |
{ | |
listitem_T *li; | |
dict_T *d; | |
- qfline_T *old_last = NULL; | |
+ qfline_T *prevp = NULL; | |
int retval = OK; | |
+ qf_info_T *qi = &ql_info; | |
bool did_bufnr_emsg = false; | |
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) { | |
- // make place for a new list | |
+ if (wp != NULL) { | |
+ qi = ll_get_or_alloc_list(wp); | |
+ } | |
+ | |
+ if (action == ' ' || qi->qf_curlist == qi->qf_listcount) | |
+ /* make place for a new list */ | |
qf_new_list(qi, title); | |
- } else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) { | |
- // Adding to existing list, use last entry. | |
- old_last = qi->qf_lists[qi->qf_curlist].qf_last; | |
- } else if (action == 'r') { | |
+ else if (action == 'a' && qi->qf_lists[qi->qf_curlist].qf_count > 0) | |
+ /* Adding to existing list, find last entry. */ | |
+ for (prevp = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ prevp->qf_next != prevp; prevp = prevp->qf_next) | |
+ ; | |
+ else if (action == 'r') { | |
qf_free(qi, qi->qf_curlist); | |
qf_store_title(qi, title); | |
} | |
@@ -4125,18 +3566,17 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, | |
if (d == NULL) | |
continue; | |
- char *const filename = tv_dict_get_string(d, "filename", true); | |
- int bufnum = (int)tv_dict_get_number(d, "bufnr"); | |
- long lnum = (long)tv_dict_get_number(d, "lnum"); | |
- int col = (int)tv_dict_get_number(d, "col"); | |
- char_u vcol = (char_u)tv_dict_get_number(d, "vcol"); | |
- int nr = (int)tv_dict_get_number(d, "nr"); | |
- const char *type_str = tv_dict_get_string(d, "type", false); | |
- const char_u type = (char_u)(uint8_t)(type_str == NULL ? NUL : *type_str); | |
- char *const pattern = tv_dict_get_string(d, "pattern", true); | |
- char *text = tv_dict_get_string(d, "text", true); | |
+ char_u *filename = get_dict_string(d, "filename", true); | |
+ int bufnum = (int)get_dict_number(d, "bufnr"); | |
+ long lnum = get_dict_number(d, "lnum"); | |
+ int col = (int)get_dict_number(d, "col"); | |
+ char_u vcol = (char_u)get_dict_number(d, "vcol"); | |
+ int nr = (int)get_dict_number(d, "nr"); | |
+ char_u *type = get_dict_string(d, "type", true); | |
+ char_u *pattern = get_dict_string(d, "pattern", true); | |
+ char_u *text = get_dict_string(d, "text", true); | |
if (text == NULL) { | |
- text = xcalloc(1, 1); | |
+ text = vim_strsave((char_u *)""); | |
} | |
bool valid = true; | |
if ((filename == NULL && bufnum == 0) || (lnum == 0 && pattern == NULL)) { | |
@@ -4155,21 +3595,23 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, | |
} | |
int status = qf_add_entry(qi, | |
+ &prevp, | |
NULL, // dir | |
- (char_u *)filename, | |
+ filename, | |
bufnum, | |
- (char_u *)text, | |
+ text, | |
lnum, | |
col, | |
vcol, // vis_col | |
- (char_u *)pattern, // search pattern | |
+ pattern, // search pattern | |
nr, | |
- type, | |
+ (char_u)(type == NULL ? NUL : *type), | |
valid); | |
xfree(filename); | |
xfree(pattern); | |
xfree(text); | |
+ xfree(type); | |
if (status == FAIL) { | |
retval = FAIL; | |
@@ -4177,86 +3619,17 @@ static int qf_add_entries(qf_info_T *qi, list_T *list, char_u *title, | |
} | |
} | |
- if (qi->qf_lists[qi->qf_curlist].qf_index == 0) { | |
- // no valid entry | |
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = true; | |
- } else { | |
- qi->qf_lists[qi->qf_curlist].qf_nonevalid = false; | |
- } | |
- if (action != 'a') { | |
- qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; | |
- if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { | |
- qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
- } | |
- } | |
- | |
- // Don't update the cursor in quickfix window when appending entries | |
- qf_update_buffer(qi, old_last); | |
- | |
- return retval; | |
-} | |
- | |
-static int qf_set_properties(qf_info_T *qi, dict_T *what, int action) | |
-{ | |
- dictitem_T *di; | |
- int retval = FAIL; | |
- int newlist = false; | |
- | |
- if (action == ' ' || qi->qf_curlist == qi->qf_listcount) { | |
- newlist = true; | |
- } | |
- int qf_idx = qi->qf_curlist; // default is the current list | |
- if ((di = tv_dict_find(what, S_LEN("nr"))) != NULL) { | |
- // Use the specified quickfix/location list | |
- if (di->di_tv.v_type == VAR_NUMBER) { | |
- qf_idx = (int)di->di_tv.vval.v_number - 1; | |
- if (qf_idx < 0 || qf_idx >= qi->qf_listcount) { | |
- return FAIL; | |
- } | |
- } else { | |
- return FAIL; | |
- } | |
- newlist = false; // use the specified list | |
- } | |
- | |
- if (newlist) { | |
- qf_new_list(qi, NULL); | |
- qf_idx = qi->qf_curlist; | |
- } | |
- | |
- if ((di = tv_dict_find(what, S_LEN("title"))) != NULL) { | |
- if (di->di_tv.v_type == VAR_STRING) { | |
- xfree(qi->qf_lists[qf_idx].qf_title); | |
- qi->qf_lists[qf_idx].qf_title = (char_u *)tv_dict_get_string( | |
- what, "title", true); | |
- if (qf_idx == qi->qf_curlist) { | |
- qf_update_win_titlevar(qi); | |
- } | |
- retval = OK; | |
- } | |
- } | |
- | |
- return retval; | |
-} | |
- | |
-// Populate the quickfix list with the items supplied in the list | |
-// of dictionaries. "title" will be copied to w:quickfix_title | |
-// "action" is 'a' for add, 'r' for replace. Otherwise create a new list. | |
-int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, | |
- dict_T *what) | |
-{ | |
- qf_info_T *qi = &ql_info; | |
- int retval = OK; | |
- | |
- if (wp != NULL) { | |
- qi = ll_get_or_alloc_list(wp); | |
+ if (qi->qf_lists[qi->qf_curlist].qf_index == 0) | |
+ /* no valid entry */ | |
+ qi->qf_lists[qi->qf_curlist].qf_nonevalid = TRUE; | |
+ else | |
+ qi->qf_lists[qi->qf_curlist].qf_nonevalid = FALSE; | |
+ qi->qf_lists[qi->qf_curlist].qf_ptr = qi->qf_lists[qi->qf_curlist].qf_start; | |
+ if (qi->qf_lists[qi->qf_curlist].qf_count > 0) { | |
+ qi->qf_lists[qi->qf_curlist].qf_index = 1; | |
} | |
- if (what != NULL) { | |
- retval = qf_set_properties(qi, what, action); | |
- } else { | |
- retval = qf_add_entries(qi, list, title, action); | |
- } | |
+ qf_update_buffer(qi); | |
return retval; | |
} | |
@@ -4271,45 +3644,14 @@ int set_errorlist(win_T *wp, list_T *list, int action, char_u *title, | |
*/ | |
void ex_cbuffer(exarg_T *eap) | |
{ | |
- buf_T *buf = NULL; | |
- qf_info_T *qi = &ql_info; | |
- const char *au_name = NULL; | |
+ buf_T *buf = NULL; | |
+ qf_info_T *qi = &ql_info; | |
if (eap->cmdidx == CMD_lbuffer || eap->cmdidx == CMD_lgetbuffer | |
|| eap->cmdidx == CMD_laddbuffer) { | |
qi = ll_get_or_alloc_list(curwin); | |
} | |
- switch (eap->cmdidx) { | |
- case CMD_cbuffer: | |
- au_name = "cbuffer"; | |
- break; | |
- case CMD_cgetbuffer: | |
- au_name = "cgetbuffer"; | |
- break; | |
- case CMD_caddbuffer: | |
- au_name = "caddbuffer"; | |
- break; | |
- case CMD_lbuffer: | |
- au_name = "lbuffer"; | |
- break; | |
- case CMD_lgetbuffer: | |
- au_name = "lgetbuffer"; | |
- break; | |
- case CMD_laddbuffer: | |
- au_name = "laddbuffer"; | |
- break; | |
- default: | |
- break; | |
- } | |
- | |
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name, | |
- curbuf->b_fname, true, curbuf)) { | |
- if (aborting()) { | |
- return; | |
- } | |
- } | |
- | |
if (*eap->arg == NUL) | |
buf = curbuf; | |
else if (*skipwhite(skipdigits(eap->arg)) == NUL) | |
@@ -4336,17 +3678,13 @@ void ex_cbuffer(exarg_T *eap) | |
} | |
if (qf_init_ext(qi, NULL, buf, NULL, p_efm, | |
- (eap->cmdidx != CMD_caddbuffer | |
- && eap->cmdidx != CMD_laddbuffer), | |
- eap->line1, eap->line2, qf_title) > 0) { | |
- if (au_name != NULL) { | |
- apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name, | |
- curbuf->b_fname, true, curbuf); | |
- } | |
- if (eap->cmdidx == CMD_cbuffer || eap->cmdidx == CMD_lbuffer) { | |
- qf_jump(qi, 0, 0, eap->forceit); // display first error | |
- } | |
- } | |
+ (eap->cmdidx != CMD_caddbuffer | |
+ && eap->cmdidx != CMD_laddbuffer), | |
+ eap->line1, eap->line2, | |
+ qf_title) > 0 | |
+ && (eap->cmdidx == CMD_cbuffer | |
+ || eap->cmdidx == CMD_lbuffer)) | |
+ qf_jump(qi, 0, 0, eap->forceit); /* display first error */ | |
} | |
} | |
} | |
@@ -4357,65 +3695,30 @@ void ex_cbuffer(exarg_T *eap) | |
*/ | |
void ex_cexpr(exarg_T *eap) | |
{ | |
- qf_info_T *qi = &ql_info; | |
- const char *au_name = NULL; | |
+ typval_T *tv; | |
+ qf_info_T *qi = &ql_info; | |
if (eap->cmdidx == CMD_lexpr || eap->cmdidx == CMD_lgetexpr | |
|| eap->cmdidx == CMD_laddexpr) { | |
qi = ll_get_or_alloc_list(curwin); | |
} | |
- switch (eap->cmdidx) { | |
- case CMD_cexpr: | |
- au_name = "cexpr"; | |
- break; | |
- case CMD_cgetexpr: | |
- au_name = "cgetexpr"; | |
- break; | |
- case CMD_caddexpr: | |
- au_name = "caddexpr"; | |
- break; | |
- case CMD_lexpr: | |
- au_name = "lexpr"; | |
- break; | |
- case CMD_lgetexpr: | |
- au_name = "lgetexpr"; | |
- break; | |
- case CMD_laddexpr: | |
- au_name = "laddexpr"; | |
- break; | |
- default: | |
- break; | |
- } | |
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, (char_u *)au_name, | |
- curbuf->b_fname, true, curbuf)) { | |
- if (aborting()) { | |
- return; | |
- } | |
- } | |
- | |
/* Evaluate the expression. When the result is a string or a list we can | |
* use it to fill the errorlist. */ | |
- typval_T tv; | |
- if (eval0(eap->arg, &tv, NULL, true) != FAIL) { | |
- if ((tv.v_type == VAR_STRING && tv.vval.v_string != NULL) | |
- || (tv.v_type == VAR_LIST && tv.vval.v_list != NULL)) { | |
- if (qf_init_ext(qi, NULL, NULL, &tv, p_efm, | |
- (eap->cmdidx != CMD_caddexpr | |
- && eap->cmdidx != CMD_laddexpr), | |
- (linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0) { | |
- if (au_name != NULL) { | |
- apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)au_name, | |
- curbuf->b_fname, true, curbuf); | |
- } | |
- if (eap->cmdidx == CMD_cexpr || eap->cmdidx == CMD_lexpr) { | |
- qf_jump(qi, 0, 0, eap->forceit); // display first error | |
- } | |
- } | |
- } else { | |
+ tv = eval_expr(eap->arg, NULL); | |
+ if (tv != NULL) { | |
+ if ((tv->v_type == VAR_STRING && tv->vval.v_string != NULL) | |
+ || (tv->v_type == VAR_LIST && tv->vval.v_list != NULL)) { | |
+ if (qf_init_ext(qi, NULL, NULL, tv, p_efm, | |
+ (eap->cmdidx != CMD_caddexpr | |
+ && eap->cmdidx != CMD_laddexpr), | |
+ (linenr_T)0, (linenr_T)0, *eap->cmdlinep) > 0 | |
+ && (eap->cmdidx == CMD_cexpr | |
+ || eap->cmdidx == CMD_lexpr)) | |
+ qf_jump(qi, 0, 0, eap->forceit); /* display first error */ | |
+ } else | |
EMSG(_("E777: String or List expected")); | |
- } | |
- tv_clear(&tv); | |
+ free_tv(tv); | |
} | |
} | |
@@ -4431,6 +3734,7 @@ void ex_helpgrep(exarg_T *eap) | |
char_u **fnames; | |
FILE *fd; | |
int fi; | |
+ qfline_T *prevp = NULL; | |
long lnum; | |
char_u *lang; | |
qf_info_T *qi = &ql_info; | |
@@ -4445,11 +3749,11 @@ void ex_helpgrep(exarg_T *eap) | |
case CMD_lhelpgrep: au_name = (char_u *)"lhelpgrep"; break; | |
default: break; | |
} | |
- if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
- curbuf->b_fname, true, curbuf)) { | |
- if (aborting()) { | |
+ if (au_name != NULL) { | |
+ apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, | |
+ curbuf->b_fname, TRUE, curbuf); | |
+ if (did_throw || force_abort) | |
return; | |
- } | |
} | |
/* Make 'cpoptions' empty, the 'l' flag should not be used here. */ | |
@@ -4533,24 +3837,23 @@ void ex_helpgrep(exarg_T *eap) | |
while (l > 0 && line[l - 1] <= ' ') | |
line[--l] = NUL; | |
- if (qf_add_entry(qi, | |
- NULL, // dir | |
- fnames[fi], | |
- 0, | |
- line, | |
- lnum, | |
- (int)(regmatch.startp[0] - line) | |
- + 1, // col | |
- false, // vis_col | |
- NULL, // search pattern | |
- 0, // nr | |
- 1, // type | |
- true) // valid | |
- == FAIL) { | |
- got_int = true; | |
- if (line != IObuff) { | |
+ if (qf_add_entry(qi, &prevp, | |
+ NULL, /* dir */ | |
+ fnames[fi], | |
+ 0, | |
+ line, | |
+ lnum, | |
+ (int)(regmatch.startp[0] - line) | |
+ + 1, /* col */ | |
+ FALSE, /* vis_col */ | |
+ NULL, /* search pattern */ | |
+ 0, /* nr */ | |
+ 1, /* type */ | |
+ TRUE /* valid */ | |
+ ) == FAIL) { | |
+ got_int = TRUE; | |
+ if (line != IObuff) | |
xfree(line); | |
- } | |
break; | |
} | |
} | |
@@ -4582,7 +3885,7 @@ void ex_helpgrep(exarg_T *eap) | |
/* Darn, some plugin changed the value. */ | |
free_string_option(save_cpo); | |
- qf_update_buffer(qi, NULL); | |
+ qf_update_buffer(qi); | |
if (au_name != NULL) { | |
apply_autocmds(EVENT_QUICKFIXCMDPOST, au_name, |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment