# HG changeset patch # User Bram Moolenaar # Date 1644344103 -3600 # Node ID bf540a32439a07527267fb3490aeeb2229da7544 # Parent 4f782c34c224b517457a4fd087736e82be843e83 patch 8.2.4329: no support for end line number and column in 'errorformat' Commit: https://github.com/vim/vim/commit/e023d499378942a6c3a3855cbe461ec2cb570f63 Author: haya14busa Date: Tue Feb 8 18:09:29 2022 +0000 patch 8.2.4329: no support for end line number and column in 'errorformat' Problem: No support for end line number and column in 'errorformat'. Solution: Add %e and %k. (closes https://github.com/vim/vim/issues/9624) diff --git a/runtime/doc/quickfix.txt b/runtime/doc/quickfix.txt --- a/runtime/doc/quickfix.txt +++ b/runtime/doc/quickfix.txt @@ -1385,12 +1385,17 @@ Basic items %f file name (finds a string) %o module name (finds a string) %l line number (finds a number) + %e end line number (finds a number) %c column number (finds a number representing character column of the error, byte index, a is 1 character column) %v virtual column number (finds a number representing screen column of the error (1 == 8 screen columns)) + %k end column number (finds a number representing + the character column of the error, byte index, or a + number representing screen end column of the error if + it's used with %v) %t error type (finds a single character): e - error message w - warning message diff --git a/src/quickfix.c b/src/quickfix.c --- a/src/quickfix.c +++ b/src/quickfix.c @@ -118,7 +118,7 @@ struct qf_info_S static qf_info_T ql_info; // global quickfix list static int_u last_qf_id = 0; // Last used quickfix list id -#define FMT_PATTERNS 11 // maximum number of % recognized +#define FMT_PATTERNS 13 // maximum number of % recognized /* * Structure used to hold the info of one part of 'errorformat' @@ -224,6 +224,9 @@ static bufref_T qf_last_bufref = {NULL, */ #define LINE_MAXLEN 4096 +/* + * Patterns used. Keep in sync with qf_parse_fmt[]. + */ static struct fmtpattern { char_u convchar; @@ -231,16 +234,20 @@ static struct fmtpattern } fmt_pat[FMT_PATTERNS] = { {'f', ".\\+"}, // only used when at end - {'n', "\\d\\+"}, - {'l', "\\d\\+"}, - {'c', "\\d\\+"}, - {'t', "."}, - {'m', ".\\+"}, - {'r', ".*"}, - {'p', "[- .]*"}, - {'v', "\\d\\+"}, - {'s', ".\\+"}, - {'o', ".\\+"} + {'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', "[- .]*"}, // 9 + {'v', "\\d\\+"}, // 10 + {'s', ".\\+"}, // 11 + {'o', ".\\+"} // 12 }; /* @@ -265,9 +272,9 @@ efmpat_to_regpat( semsg(_(e_too_many_chr_in_format_string), *efmpat); return NULL; } - if ((idx && idx < 6 + if ((idx && idx < FMT_PATTERN_R && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL) - || (idx == 6 + || (idx == FMT_PATTERN_R && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) { semsg(_(e_unexpected_chr_in_format_str), *efmpat); @@ -948,7 +955,7 @@ qf_parse_fmt_n(regmatch_T *rmp, int midx } /* - * Parse the match for line number (%l') pattern in regmatch. + * Parse the match for line number ('%l') pattern in regmatch. * Return the matched value in "fields->lnum". */ static int @@ -961,6 +968,19 @@ qf_parse_fmt_l(regmatch_T *rmp, int midx } /* + * Parse the match for end line number ('%e') pattern in regmatch. + * Return the matched value in "fields->end_lnum". + */ + static int +qf_parse_fmt_e(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->end_lnum = atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/* * Parse the match for column number ('%c') pattern in regmatch. * Return the matched value in "fields->col". */ @@ -974,6 +994,19 @@ qf_parse_fmt_c(regmatch_T *rmp, int midx } /* + * Parse the match for end column number ('%k') pattern in regmatch. + * Return the matched value in "fields->end_col". + */ + static int +qf_parse_fmt_k(regmatch_T *rmp, int midx, qffields_T *fields) +{ + if (rmp->startp[midx] == NULL) + return QF_FAIL; + fields->end_col = (int)atol((char *)rmp->startp[midx]); + return QF_OK; +} + +/* * Parse the match for error type ('%t') pattern in regmatch. * Return the matched value in "fields->type". */ @@ -1132,16 +1165,19 @@ qf_parse_fmt_o(regmatch_T *rmp, int midx * 'errorformat' format pattern parser functions. * The '%f' and '%r' formats are parsed differently from other formats. * See qf_parse_match() for details. + * Keep in sync with fmt_pat[]. */ static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = { - NULL, + NULL, // %f qf_parse_fmt_n, qf_parse_fmt_l, + qf_parse_fmt_e, qf_parse_fmt_c, + qf_parse_fmt_k, qf_parse_fmt_t, qf_parse_fmt_m, - NULL, + NULL, // %r qf_parse_fmt_p, qf_parse_fmt_v, qf_parse_fmt_s, @@ -1186,14 +1222,14 @@ qf_parse_match( midx = (int)fmt_ptr->addr[i]; if (i == 0 && midx > 0) // %f status = qf_parse_fmt_f(regmatch, midx, fields, idx); - else if (i == 5) + else if (i == FMT_PATTERN_M) { if (fmt_ptr->flags == '+' && !qf_multiscan) // %+ status = copy_nonerror_line(linebuf, linelen, fields); else if (midx > 0) // %m status = qf_parse_fmt_m(regmatch, midx, fields); } - else if (i == 6 && midx > 0) // %r + else if (i == FMT_PATTERN_R && midx > 0) // %r status = qf_parse_fmt_r(regmatch, midx, tail); else if (midx > 0) // others status = (qf_parse_fmt[i])(regmatch, midx, fields); @@ -1363,11 +1399,15 @@ qf_parse_multiline_pfx( if (!qfprev->qf_lnum) qfprev->qf_lnum = fields->lnum; + if (!qfprev->qf_end_lnum) + qfprev->qf_end_lnum = fields->end_lnum; if (!qfprev->qf_col) { qfprev->qf_col = fields->col; qfprev->qf_viscol = fields->use_viscol; } + if (!qfprev->qf_end_col) + qfprev->qf_end_col = fields->end_col; if (!qfprev->qf_fnum) qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory, diff --git a/src/testdir/test_quickfix.vim b/src/testdir/test_quickfix.vim --- a/src/testdir/test_quickfix.vim +++ b/src/testdir/test_quickfix.vim @@ -1469,6 +1469,29 @@ func Test_efm_error_type() let &efm = save_efm endfunc +" Test for end_lnum ('%e') and end_col ('%k') fields in 'efm' +func Test_efm_end_lnum_col() + let save_efm = &efm + + " single line + set efm=%f:%l-%e:%c-%k:%t:%m + cexpr ["Xfile1:10-20:1-2:E:msg1", "Xfile1:20-30:2-3:W:msg2",] + let output = split(execute('clist'), "\n") + call assert_equal([ + \ ' 1 Xfile1:10-20 col 1-2 error: msg1', + \ ' 2 Xfile1:20-30 col 2-3 warning: msg2'], output) + + " multiple lines + set efm=%A%n)%m,%Z%f:%l-%e:%c-%k + cexpr ["1)msg1", "Xfile1:14-24:1-2", + \ "2)msg2", "Xfile1:24-34:3-4"] + let output = split(execute('clist'), "\n") + call assert_equal([ + \ ' 1 Xfile1:14-24 col 1-2 error 1: msg1', + \ ' 2 Xfile1:24-34 col 3-4 error 2: msg2'], output) + let &efm = save_efm +endfunc + func XquickfixChangedByAutocmd(cchar) call s:setup_commands(a:cchar) if a:cchar == 'c' diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -747,6 +747,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 4329, +/**/ 4328, /**/ 4327,