aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/doc/quickfix.txt6
-rw-r--r--src/nvim/quickfix.c51
-rw-r--r--test/old/testdir/test_quickfix.vim49
3 files changed, 90 insertions, 16 deletions
diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt
index 0bf04034ec..4428ff2f65 100644
--- a/runtime/doc/quickfix.txt
+++ b/runtime/doc/quickfix.txt
@@ -1381,6 +1381,7 @@ rest is ignored. Items can only be 1023 bytes long.
Basic items
%f file name (finds a string)
+ %b buffer number (finds a number)
%o module name (finds a string)
%l line number (finds a number)
%e end line number (finds a number)
@@ -1420,6 +1421,11 @@ On Windows a leading "C:" will be included in "%f", even when using "%f:".
This means that a file name which is a single alphabetical letter will not be
detected.
+The "%b" conversion is used to parse a buffer number. This is useful for
+referring to lines in a scratch buffer or a buffer with no name. If a buffer
+with the matching number doesn't exist, then that line is used as a non-error
+line.
+
The "%p" conversion is normally followed by a "^". It's used for compilers
that output a line like: >
^
diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c
index be2681e765..eae357ebf0 100644
--- a/src/nvim/quickfix.c
+++ b/src/nvim/quickfix.c
@@ -152,7 +152,7 @@ struct qf_info_S {
static qf_info_T ql_info; // global quickfix list
static unsigned last_qf_id = 0; // Last Used quickfix list id
-#define FMT_PATTERNS 13 // maximum number of % recognized
+#define FMT_PATTERNS 14 // maximum number of % recognized
// Structure used to hold the info of one part of 'errorformat'
typedef struct efm_S efm_T;
@@ -217,6 +217,7 @@ typedef struct {
typedef struct {
char *namebuf;
+ int bnr;
char *module;
char *errmsg;
size_t errmsglen;
@@ -344,7 +345,7 @@ static int qf_init_process_nextline(qf_list_T *qfl, efm_T *fmt_first, qfstate_T
: ((qfl->qf_currfile != NULL && fields->valid)
? qfl->qf_currfile : NULL),
fields->module,
- 0,
+ fields->bnr,
fields->errmsg,
fields->lnum,
fields->end_lnum,
@@ -391,20 +392,21 @@ static struct fmtpattern {
char *pattern;
} fmt_pat[FMT_PATTERNS] = {
{ 'f', ".\\+" }, // only used when at end
- { 'n', "\\d\\+" }, // 1
- { 'l', "\\d\\+" }, // 2
- { 'e', "\\d\\+" }, // 3
- { 'c', "\\d\\+" }, // 4
- { 'k', "\\d\\+" }, // 5
- { 't', "." }, // 6
-#define FMT_PATTERN_M 7
- { 'm', ".\\+" }, // 7
-#define FMT_PATTERN_R 8
- { 'r', ".*" }, // 8
- { 'p', "[- \t.]*" }, // 9
- { 'v', "\\d\\+" }, // 10
- { 's', ".\\+" }, // 11
- { 'o', ".\\+" } // 12
+ { 'b', "\\d\\+" }, // 1
+ { 'n', "\\d\\+" }, // 2
+ { 'l', "\\d\\+" }, // 3
+ { 'e', "\\d\\+" }, // 4
+ { 'c', "\\d\\+" }, // 5
+ { 'k', "\\d\\+" }, // 6
+ { 't', "." }, // 7
+#define FMT_PATTERN_M 8
+ { 'm', ".\\+" }, // 8
+#define FMT_PATTERN_R 9
+ { 'r', ".*" }, // 9
+ { 'p', "[-\t .]*" }, // 10
+ { 'v', "\\d\\+" }, // 11
+ { 's', ".\\+" }, // 12
+ { 'o', ".\\+" } // 13
};
/// Convert an errorformat pattern to a regular expression pattern.
@@ -1312,6 +1314,21 @@ static int qf_parse_fmt_f(regmatch_T *rmp, int midx, qffields_T *fields, int pre
return QF_OK;
}
+/// Parse the match for buffer number ('%b') pattern in regmatch.
+/// Return the matched value in "fields->bnr".
+static int qf_parse_fmt_b(regmatch_T *rmp, int midx, qffields_T *fields)
+{
+ if (rmp->startp[midx] == NULL) {
+ return QF_FAIL;
+ }
+ int bnr = (int)atol(rmp->startp[midx]);
+ if (buflist_findnr(bnr) == NULL) {
+ return QF_FAIL;
+ }
+ fields->bnr = bnr;
+ return QF_OK;
+}
+
/// Parse the match for error number ('%n') pattern in regmatch.
/// Return the matched value in "fields->enr".
static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
@@ -1496,6 +1513,7 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
/// Keep in sync with fmt_pat[].
static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = {
NULL, // %f
+ qf_parse_fmt_b,
qf_parse_fmt_n,
qf_parse_fmt_l,
qf_parse_fmt_e,
@@ -1568,6 +1586,7 @@ static int qf_parse_get_fields(char *linebuf, size_t linelen, efm_T *fmt_ptr, qf
}
fields->namebuf[0] = NUL;
+ fields->bnr = 0;
fields->module[0] = NUL;
fields->pattern[0] = NUL;
if (!qf_multiscan) {
diff --git a/test/old/testdir/test_quickfix.vim b/test/old/testdir/test_quickfix.vim
index ebf1bfdc64..b5abb08ed8 100644
--- a/test/old/testdir/test_quickfix.vim
+++ b/test/old/testdir/test_quickfix.vim
@@ -6320,4 +6320,53 @@ func Test_quickfix_buffer_contents()
call setqflist([], 'f')
endfunc
+" Test for "%b" in "errorformat"
+func Test_efm_format_b()
+ call setqflist([], 'f')
+ new
+ call setline(1, ['1: abc', '1: def', '1: ghi'])
+ let b1 = bufnr()
+ new
+ call setline(1, ['2: abc', '2: def', '2: ghi'])
+ let b2 = bufnr()
+ new
+ call setline(1, ['3: abc', '3: def', '3: ghi'])
+ let b3 = bufnr()
+ new
+ let lines =<< trim eval END
+ {b1}:1:1
+ {b2}:2:2
+ {b3}:3:3
+ END
+ call setqflist([], ' ', #{lines: lines, efm: '%b:%l:%c'})
+ cfirst
+ call assert_equal([b1, 1, 1], [bufnr(), line('.'), col('.')])
+ cnext
+ call assert_equal([b2, 2, 2], [bufnr(), line('.'), col('.')])
+ cnext
+ call assert_equal([b3, 3, 3], [bufnr(), line('.'), col('.')])
+ enew!
+
+ " Use a non-existing buffer
+ let lines =<< trim eval END
+ 9991:1:1:m1
+ 9992:2:2:m2
+ {b3}:3:3:m3
+ END
+ call setqflist([], ' ', #{lines: lines, efm: '%b:%l:%c:%m'})
+ cfirst | cnext
+ call assert_equal([b3, 3, 3], [bufnr(), line('.'), col('.')])
+ " Lines with non-existing buffer numbers should be used as non-error lines
+ call assert_equal([
+ \ #{lnum: 0, bufnr: 0, end_lnum: 0, pattern: '', valid: 0, vcol: 0, nr: -1,
+ \ module: '', type: '', end_col: 0, col: 0, text: '9991:1:1:m1'},
+ \ #{lnum: 0, bufnr: 0, end_lnum: 0, pattern: '', valid: 0, vcol: 0, nr: -1,
+ \ module: '', type: '', end_col: 0, col: 0, text: '9992:2:2:m2'},
+ \ #{lnum: 3, bufnr: b3, end_lnum: 0, pattern: '', valid: 1, vcol: 0,
+ \ nr: -1, module: '', type: '', end_col: 0, col: 3, text: 'm3'}],
+ \ getqflist())
+ %bw!
+ call setqflist([], 'f')
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab