vim-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 vim/vim#9624)
e023d49937

Use "\t" to represent a Tab as it looks better.
This commit is contained in:
zeertzjq 2022-02-09 13:18:37 +08:00
parent 07c97fa02d
commit b9732e555b
3 changed files with 83 additions and 19 deletions

View File

@ -1339,12 +1339,17 @@ Basic items
%f file name (finds a string) %f file name (finds a string)
%o module name (finds a string) %o module name (finds a string)
%l line number (finds a number) %l line number (finds a number)
%e end line number (finds a number)
%c column number (finds a number representing character %c column number (finds a number representing character
column of the error, byte index, a <tab> is 1 column of the error, byte index, a <tab> is 1
character column) character column)
%v virtual column number (finds a number representing %v virtual column number (finds a number representing
screen column of the error (1 <tab> == 8 screen screen column of the error (1 <tab> == 8 screen
columns)) 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): %t error type (finds a single character):
e - error message e - error message
w - warning message w - warning message

View File

@ -131,7 +131,7 @@ struct qf_info_S {
static qf_info_T ql_info; // global quickfix list static qf_info_T ql_info; // global quickfix list
static unsigned last_qf_id = 0; // Last Used quickfix list id static unsigned 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' // Structure used to hold the info of one part of 'errorformat'
typedef struct efm_S efm_T; typedef struct efm_S efm_T;
@ -332,22 +332,27 @@ int qf_init(win_T *wp, const char_u *restrict efile, char_u *restrict errorforma
// Maximum number of bytes allowed per line while reading an errorfile. // Maximum number of bytes allowed per line while reading an errorfile.
static const size_t LINE_MAXLEN = 4096; static const size_t LINE_MAXLEN = 4096;
/// Patterns used. Keep in sync with qf_parse_fmt[].
static struct fmtpattern { static struct fmtpattern {
char_u convchar; char_u convchar;
char *pattern; char *pattern;
} fmt_pat[FMT_PATTERNS] = } fmt_pat[FMT_PATTERNS] =
{ {
{ 'f', ".\\+" }, // only used when at end { 'f', ".\\+" }, // only used when at end
{ 'n', "\\d\\+" }, { 'n', "\\d\\+" }, // 1
{ 'l', "\\d\\+" }, { 'l', "\\d\\+" }, // 2
{ 'c', "\\d\\+" }, { 'e', "\\d\\+" }, // 3
{ 't', "." }, { 'c', "\\d\\+" }, // 4
{ 'm', ".\\+" }, { 'k', "\\d\\+" }, // 5
{ 'r', ".*" }, { 't', "." }, // 6
{ 'p', "[- .]*"}, // NOLINT(whitespace/tab) #define FMT_PATTERN_M 7
{ 'v', "\\d\\+" }, { 'm', ".\\+" }, // 7
{ 's', ".\\+" }, #define FMT_PATTERN_R 8
{ 'o', ".\\+" } { 'r', ".*" }, // 8
{ 'p', "[- \t.]*" }, // 9
{ 'v', "\\d\\+" }, // 10
{ 's', ".\\+" }, // 11
{ 'o', ".\\+" } // 12
}; };
/// Convert an errorformat pattern to a regular expression pattern. /// Convert an errorformat pattern to a regular expression pattern.
@ -363,9 +368,9 @@ static char_u *efmpat_to_regpat(const char_u *efmpat, char_u *regpat, efm_T *efm
semsg(_("E372: Too many %%%c in format string"), *efmpat); semsg(_("E372: Too many %%%c in format string"), *efmpat);
return NULL; return NULL;
} }
if ((idx && idx < 6 if ((idx && idx < FMT_PATTERN_R
&& vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL) && vim_strchr((char_u *)"DXOPQ", efminfo->prefix) != NULL)
|| (idx == 6 || (idx == FMT_PATTERN_R
&& vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) { && vim_strchr((char_u *)"OPQ", efminfo->prefix) == NULL)) {
semsg(_("E373: Unexpected %%%c in format string"), *efmpat); semsg(_("E373: Unexpected %%%c in format string"), *efmpat);
return NULL; return NULL;
@ -1288,7 +1293,7 @@ static int qf_parse_fmt_n(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK; return QF_OK;
} }
/// 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". /// Return the matched value in "fields->lnum".
static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields) static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
{ {
@ -1299,6 +1304,17 @@ static int qf_parse_fmt_l(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK; return QF_OK;
} }
/// 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. /// Parse the match for column number ('%c') pattern in regmatch.
/// Return the matched value in "fields->col". /// Return the matched value in "fields->col".
static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields) static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
@ -1310,6 +1326,17 @@ static int qf_parse_fmt_c(regmatch_T *rmp, int midx, qffields_T *fields)
return QF_OK; return QF_OK;
} }
/// Parse the match for end line number ('%e') pattern in regmatch.
/// Return the matched value in "fields->end_lnum".
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. /// Parse the match for error type ('%t') pattern in regmatch.
/// Return the matched value in "fields->type". /// Return the matched value in "fields->type".
static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields) static int qf_parse_fmt_t(regmatch_T *rmp, int midx, qffields_T *fields)
@ -1442,14 +1469,17 @@ static int qf_parse_fmt_o(regmatch_T *rmp, int midx, qffields_T *fields)
/// 'errorformat' format pattern parser functions. /// 'errorformat' format pattern parser functions.
/// The '%f' and '%r' formats are parsed differently from other formats. /// The '%f' and '%r' formats are parsed differently from other formats.
/// See qf_parse_match() for details. /// See qf_parse_match() for details.
/// Keep in sync with fmt_pat[].
static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = { static int (*qf_parse_fmt[FMT_PATTERNS])(regmatch_T *, int, qffields_T *) = {
NULL, NULL, // %f
qf_parse_fmt_n, qf_parse_fmt_n,
qf_parse_fmt_l, qf_parse_fmt_l,
qf_parse_fmt_e,
qf_parse_fmt_c, qf_parse_fmt_c,
qf_parse_fmt_k,
qf_parse_fmt_t, qf_parse_fmt_t,
qf_parse_fmt_m, qf_parse_fmt_m,
NULL, NULL, // %r
qf_parse_fmt_p, qf_parse_fmt_p,
qf_parse_fmt_v, qf_parse_fmt_v,
qf_parse_fmt_s, qf_parse_fmt_s,
@ -1485,13 +1515,13 @@ static int qf_parse_match(char_u *linebuf, size_t linelen, efm_T *fmt_ptr, regma
midx = (int)fmt_ptr->addr[i]; midx = (int)fmt_ptr->addr[i];
if (i == 0 && midx > 0) { // %f if (i == 0 && midx > 0) { // %f
status = qf_parse_fmt_f(regmatch, midx, fields, idx); 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) { // %+ if (fmt_ptr->flags == '+' && !qf_multiscan) { // %+
qf_parse_fmt_plus(linebuf, linelen, fields); qf_parse_fmt_plus(linebuf, linelen, fields);
} else if (midx > 0) { // %m } else if (midx > 0) { // %m
status = qf_parse_fmt_m(regmatch, midx, fields); 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); status = qf_parse_fmt_r(regmatch, midx, tail);
} else if (midx > 0) { // others } else if (midx > 0) { // others
status = (qf_parse_fmt[i])(regmatch, midx, fields); status = (qf_parse_fmt[i])(regmatch, midx, fields);
@ -1636,10 +1666,16 @@ static int qf_parse_multiline_pfx(int idx, qf_list_T *qfl, qffields_T *fields)
if (!qfprev->qf_lnum) { if (!qfprev->qf_lnum) {
qfprev->qf_lnum = fields->lnum; qfprev->qf_lnum = fields->lnum;
} }
if (!qfprev->qf_end_lnum) {
qfprev->qf_end_lnum = fields->end_lnum;
}
if (!qfprev->qf_col) { if (!qfprev->qf_col) {
qfprev->qf_col = fields->col; qfprev->qf_col = fields->col;
qfprev->qf_viscol = fields->use_viscol; qfprev->qf_viscol = fields->use_viscol;
} }
if (!qfprev->qf_end_col) {
qfprev->qf_end_col = fields->end_col;
}
if (!qfprev->qf_fnum) { if (!qfprev->qf_fnum) {
qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory, qfprev->qf_fnum = qf_get_fnum(qfl, qfl->qf_directory,
*fields->namebuf || qfl->qf_directory *fields->namebuf || qfl->qf_directory

View File

@ -1384,6 +1384,29 @@ func Test_efm_error_type()
let &efm = save_efm let &efm = save_efm
endfunc 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) func XquickfixChangedByAutocmd(cchar)
call s:setup_commands(a:cchar) call s:setup_commands(a:cchar)
if a:cchar == 'c' if a:cchar == 'c'