Permalink
Browse files

patch 8.0.1782: no simple way to label quickfix entries

Problem:    No simple way to label quickfix entries.
Solution:   Add the "module" item, to be used instead of the file name for
            display purposes. (Martin Szamotulski, closes #1757)
  • Loading branch information...
brammool committed May 1, 2018
1 parent a796d46 commit d76ce852668635d81778cedacc2d3f021ed4e475
Showing with 101 additions and 19 deletions.
  1. +3 −0 runtime/doc/eval.txt
  2. +6 −0 runtime/doc/quickfix.txt
  3. +1 −0 src/alloc.h
  4. +64 −19 src/quickfix.c
  5. +25 −0 src/testdir/test_quickfix.vim
  6. +2 −0 src/version.c
@@ -4737,6 +4737,7 @@ getqflist([{what}]) *getqflist()*
list item is a dictionary with these entries:
bufnr number of buffer that has the file name, use
bufname() to get the name
module module name
lnum line number in the buffer (first line is 1)
col column number (first column is 1)
vcol |TRUE|: "col" is visual column
@@ -7221,6 +7222,8 @@ setqflist({list} [, {action} [, {what}]]) *setqflist()*
buffer
filename name of a file; only used when "bufnr" is not
present or it is invalid.
module name of a module; if given it will be used in
quickfix error window instead of the filename.
lnum line number in the file
pattern search pattern used to locate the error
col column number
@@ -1220,6 +1220,7 @@ you want to match case, add "\C" to the pattern |/\C|.
Basic items
%f file name (finds a string)
%o module name (finds a string)
%l line number (finds a number)
%c column number (finds a number representing character
column of the error, (1 <tab> == 1 character column))
@@ -1264,6 +1265,11 @@ conversion can be used to locate lines without a line number in the error
output. Like the output of the "grep" shell command.
When the pattern is present the line number will not be used.
The "%o" conversion specifies the module name in quickfix entry. If present
it will be used in quickfix error window instead of the filename. The module
name is used only for displaying purposes, the file name is used when jumping
to the file.
Changing directory
The following uppercase conversion characters specify the type of special
@@ -15,6 +15,7 @@ typedef enum {
aid_qf_dirname_start,
aid_qf_dirname_now,
aid_qf_namebuf,
aid_qf_module,
aid_qf_errmsg,
aid_qf_pattern,
aid_last
@@ -33,6 +33,7 @@ struct qfline_S
int qf_fnum; /* file number for the line */
int qf_col; /* column where the error occurred */
int qf_nr; /* error number */
char_u *qf_module; /* module name for this error */
char_u *qf_pattern; /* search pattern for the error */
char_u *qf_text; /* description of the error */
char_u qf_viscol; /* set to TRUE if qf_col is screen column */
@@ -101,7 +102,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 10 /* maximum number of % recognized */
#define FMT_PATTERNS 11 /* maximum number of % recognized */
/*
* Structure used to hold the info of one part of 'errorformat'
@@ -135,7 +136,8 @@ static efm_T *fmt_start = NULL; /* cached across qf_parse_line() calls */
static int qf_init_ext(qf_info_T *qi, int qf_idx, char_u *efile, buf_T *buf, typval_T *tv, char_u *errorformat, int newlist, linenr_T lnumfirst, linenr_T lnumlast, char_u *qf_title, char_u *enc);
static void qf_new_list(qf_info_T *qi, char_u *qf_title);
static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid);
static int qf_add_entry(qf_info_T *qi, int qf_idx, char_u *dir, char_u *fname, char_u *module, int bufnum, char_u *mesg, long lnum, int col, int vis_col, char_u *pattern, int nr, int type, int valid);
static qf_info_T *ll_new_list(void);
static void qf_free(qf_info_T *qi, int idx);
static char_u *qf_types(int, int);
static int qf_get_fnum(qf_info_T *qi, int qf_idx, char_u *, char_u *);
@@ -221,7 +223,8 @@ static struct fmtpattern
{'r', ".*"},
{'p', "[- .]*"},
{'v', "\\d\\+"},
{'s', ".\\+"}
{'s', ".\\+"},
{'o', ".\\+"}
};
/*
@@ -809,6 +812,7 @@ qf_get_nextline(qfstate_T *state)
typedef struct {
char_u *namebuf;
char_u *module;
char_u *errmsg;
int errmsglen;
long lnum;
@@ -868,6 +872,7 @@ qf_parse_line(
if (qfl->qf_multiscan && vim_strchr((char_u *)"OPQ", idx) == NULL)
continue;
fields->namebuf[0] = NUL;
fields->module[0] = NUL;
fields->pattern[0] = NUL;
if (!qfl->qf_multiscan)
fields->errmsg[0] = NUL;
@@ -1008,6 +1013,15 @@ qf_parse_line(
fields->pattern[len + 4] = '$';
fields->pattern[len + 5] = NUL;
}
if ((i = (int)fmt_ptr->addr[10]) > 0) /* %o */
{
if (regmatch.startp[i] == NULL)
continue;
len = (int)(regmatch.endp[i] - regmatch.startp[i]);
if (len > CMDBUFFSIZE)
len = CMDBUFFSIZE;
STRNCAT(fields->module, regmatch.startp[i], len);
}
break;
}
}
@@ -1181,11 +1195,12 @@ qf_init_ext(
convert_setup(&state.vc, enc, p_enc);
#endif
fields.namebuf = alloc_id(CMDBUFFSIZE + 1, aid_qf_namebuf);
fields.module = alloc_id(CMDBUFFSIZE + 1, aid_qf_module);
fields.errmsglen = CMDBUFFSIZE + 1;
fields.errmsg = alloc_id(fields.errmsglen, aid_qf_errmsg);
fields.pattern = alloc_id(CMDBUFFSIZE + 1, aid_qf_pattern);
if (fields.namebuf == NULL || fields.errmsg == NULL
|| fields.pattern == NULL)
|| fields.pattern == NULL || fields.module == NULL)
goto qf_init_end;
if (efile != NULL && (state.fd = mch_fopen((char *)efile, "r")) == NULL)
@@ -1282,6 +1297,7 @@ qf_init_ext(
? fields.namebuf
: ((qfl->qf_currfile != NULL && fields.valid)
? qfl->qf_currfile : (char_u *)NULL),
fields.module,
0,
fields.errmsg,
fields.lnum,
@@ -1327,6 +1343,7 @@ qf_init_ext(
if (state.fd != NULL)
fclose(state.fd);
vim_free(fields.namebuf);
vim_free(fields.module);
vim_free(fields.errmsg);
vim_free(fields.pattern);
vim_free(state.growbuf);
@@ -1444,6 +1461,7 @@ qf_add_entry(
int qf_idx, /* list index */
char_u *dir, /* optional directory name */
char_u *fname, /* file name or NULL */
char_u *module, /* module name or NULL */
int bufnum, /* buffer number or zero */
char_u *mesg, /* message */
long lnum, /* line number */
@@ -1486,6 +1504,15 @@ qf_add_entry(
vim_free(qfp);
return FAIL;
}
if (module == NULL || *module == NUL)
qfp->qf_module = NULL;
else if ((qfp->qf_module = vim_strsave(module)) == NULL)
{
vim_free(qfp->qf_text);
vim_free(qfp->qf_pattern);
vim_free(qfp);
return FAIL;
}
qfp->qf_nr = nr;
if (type != 1 && !vim_isprintc(type)) /* only printable chars allowed */
type = 0;
@@ -1635,6 +1662,7 @@ copy_loclist(win_T *from, win_T *to)
to->w_llist->qf_curlist,
NULL,
NULL,
from_qfp->qf_module,
0,
from_qfp->qf_text,
from_qfp->qf_lnum,
@@ -2765,18 +2793,22 @@ qf_list(exarg_T *eap)
break;
fname = NULL;
if (qfp->qf_fnum != 0
&& (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
{
fname = buf->b_fname;
if (qfp->qf_type == 1) /* :helpgrep */
fname = gettail(fname);
if (qfp->qf_module != NULL && *qfp->qf_module != NUL)
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s", i, (char *)qfp->qf_module);
else {
if (qfp->qf_fnum != 0
&& (buf = buflist_findnr(qfp->qf_fnum)) != NULL)
{
fname = buf->b_fname;
if (qfp->qf_type == 1) /* :helpgrep */
fname = gettail(fname);
}
if (fname == NULL)
sprintf((char *)IObuff, "%2d", i);
else
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
i, (char *)fname);
}
if (fname == NULL)
sprintf((char *)IObuff, "%2d", i);
else
vim_snprintf((char *)IObuff, IOSIZE, "%2d %s",
i, (char *)fname);
msg_outtrans_attr(IObuff, i == qi->qf_lists[qi->qf_curlist].qf_index
? HL_ATTR(HLF_QFL) : qfFileAttr);
@@ -2957,9 +2989,10 @@ qf_free_items(qf_info_T *qi, int idx)
qfpnext = qfp->qf_next;
if (!stop)
{
vim_free(qfp->qf_module);
vim_free(qfp->qf_text);
stop = (qfp == qfpnext);
vim_free(qfp->qf_pattern);
stop = (qfp == qfpnext);
vim_free(qfp);
if (stop)
/* Somehow qf_count may have an incorrect value, set it to 1
@@ -3562,7 +3595,12 @@ qf_fill_buffer(qf_info_T *qi, buf_T *buf, qfline_T *old_last)
}
while (lnum < qi->qf_lists[qi->qf_curlist].qf_count)
{
if (qfp->qf_fnum != 0
if (qfp->qf_module != NULL)
{
STRCPY(IObuff, qfp->qf_module);
len = (int)STRLEN(IObuff);
}
else if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL)
{
@@ -4367,6 +4405,7 @@ vgr_match_buflines(
qi->qf_curlist,
NULL, /* dir */
fname,
NULL,
duplicate_name ? 0 : buf->b_fnum,
ml_get_buf(buf,
regmatch->startpos[0].lnum + lnum, FALSE),
@@ -4934,6 +4973,8 @@ get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
|| 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, "module", 0L,
qfp->qf_module == NULL ? (char_u *)"" : qfp->qf_module) == 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,
@@ -5312,7 +5353,7 @@ qf_add_entries(
{
listitem_T *li;
dict_T *d;
char_u *filename, *pattern, *text, *type;
char_u *filename, *module, *pattern, *text, *type;
int bufnum;
long lnum;
int col, nr;
@@ -5347,6 +5388,7 @@ qf_add_entries(
continue;
filename = get_dict_string(d, (char_u *)"filename", TRUE);
module = get_dict_string(d, (char_u *)"module", TRUE);
bufnum = (int)get_dict_number(d, (char_u *)"bufnr");
lnum = (int)get_dict_number(d, (char_u *)"lnum");
col = (int)get_dict_number(d, (char_u *)"col");
@@ -5383,6 +5425,7 @@ qf_add_entries(
qf_idx,
NULL, /* dir */
filename,
module,
bufnum,
text,
lnum,
@@ -5394,6 +5437,7 @@ qf_add_entries(
valid);
vim_free(filename);
vim_free(module);
vim_free(pattern);
vim_free(text);
vim_free(type);
@@ -6040,6 +6084,7 @@ hgr_search_file(
qi->qf_curlist,
NULL, /* dir */
fname,
NULL,
0,
line,
lnum,
@@ -6104,7 +6149,7 @@ hgr_search_files_in_dir(
/* Skip files for a different language. */
if (lang != NULL
&& STRNICMP(lang, fnames[fi]
+ STRLEN(fnames[fi]) - 3, 2) != 0
+ STRLEN(fnames[fi]) - 3, 2) != 0
&& !(STRNICMP(lang, "en", 2) == 0
&& STRNICMP("txt", fnames[fi]
+ STRLEN(fnames[fi]) - 3, 3) == 0))
@@ -138,6 +138,16 @@ func XlistTests(cchar)
\ ' 4:40 col 20 x 44: Other',
\ ' 5:50 col 25 55: one'], l)
" Test for module names, one needs to explicitly set `'valid':v:true` so
call g:Xsetlist([
\ {'lnum':10,'col':5,'type':'W','module':'Data.Text','text':'ModuleWarning','nr':11,'valid':v:true},
\ {'lnum':20,'col':10,'type':'W','module':'Data.Text','filename':'Data/Text.hs','text':'ModuleWarning','nr':22,'valid':v:true},
\ {'lnum':30,'col':15,'type':'W','filename':'Data/Text.hs','text':'FileWarning','nr':33,'valid':v:true}])
let l = split(execute('Xlist', ""), "\n")
call assert_equal([' 1 Data.Text:10 col 5 warning 11: ModuleWarning',
\ ' 2 Data.Text:20 col 10 warning 22: ModuleWarning',
\ ' 3 Data/Text.hs:30 col 15 warning 33: FileWarning'], l)
" Error cases
call assert_fails('Xlist abc', 'E488:')
endfunc
@@ -1142,6 +1152,21 @@ func Test_efm2()
call assert_equal(1, l[4].valid)
call assert_equal('unittests/dbfacadeTest.py', bufname(l[4].bufnr))
" Test for %o
set efm=%f(%o):%l\ %m
cgetexpr ['Xtestfile(Language.PureScript.Types):20 Error']
call writefile(['Line1'], 'Xtestfile')
let l = getqflist()
call assert_equal(1, len(l), string(l))
call assert_equal('Language.PureScript.Types', l[0].module)
copen
call assert_equal('Language.PureScript.Types|20| Error', getline(1))
call feedkeys("\<CR>", 'xn')
call assert_equal('Xtestfile', expand('%:t'))
cclose
bd
call delete("Xtestfile")
" The following sequence of commands used to crash Vim
set efm=%W%m
cgetexpr ['msg1']
@@ -761,6 +761,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
1782,
/**/
1781,
/**/

0 comments on commit d76ce85

Please sign in to comment.