vim-patch:8.2.0869: it is not possible to customize the quickfix window contents

Problem:    It is not possible to customize the quickfix window contents.
Solution:   Add 'quickfixtextfunc'. (Yegappan Lakshmanan, closes vim/vim#5465)
858ba06d5f
This commit is contained in:
kevinhwang91
2021-05-04 00:05:45 +08:00
parent 52ca7f1a26
commit ebe1a08366
8 changed files with 354 additions and 71 deletions

View File

@@ -100,6 +100,7 @@ typedef struct qf_list_S {
char_u *qf_title; ///< title derived from the command that created
///< the error list or set by setqflist
typval_T *qf_ctx; ///< context set by setqflist/setloclist
char_u *qf_qftf; ///< 'quickfixtextfunc' setting for this list
struct dir_stack_T *qf_dir_stack;
char_u *qf_directory;
@@ -1999,6 +2000,11 @@ static int copy_loclist(const qf_list_T *from_qfl, qf_list_T *to_qfl)
} else {
to_qfl->qf_ctx = NULL;
}
if (from_qfl->qf_qftf != NULL) {
to_qfl->qf_qftf = vim_strsave(from_qfl->qf_qftf);
} else {
to_qfl->qf_qftf = NULL;
}
if (from_qfl->qf_count) {
if (copy_loclist_entries(from_qfl, to_qfl) == FAIL) {
@@ -3382,6 +3388,7 @@ static void qf_free(qf_list_T *qfl)
XFREE_CLEAR(qfl->qf_title);
tv_free(qfl->qf_ctx);
qfl->qf_ctx = NULL;
XFREE_CLEAR(qfl->qf_qftf);
qfl->qf_id = 0;
qfl->qf_changedtick = 0L;
}
@@ -3911,70 +3918,103 @@ static void qf_update_buffer(qf_info_T *qi, qfline_T *old_last)
}
// Add an error line to the quickfix buffer.
static int qf_buf_add_line(buf_T *buf, linenr_T lnum, const qfline_T *qfp,
static int qf_buf_add_line(qf_list_T *qfl, buf_T *buf, linenr_T lnum,
const qfline_T *qfp,
char_u *dirname, bool first_bufline)
FUNC_ATTR_NONNULL_ALL
{
int len;
buf_T *errbuf;
char_u *qftf;
if (qfp->qf_module != NULL) {
STRLCPY(IObuff, qfp->qf_module, IOSIZE - 1);
len = (int)STRLEN(IObuff);
} else if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
if (qfp->qf_type == 1) { // :helpgrep
STRLCPY(IObuff, path_tail(errbuf->b_fname), IOSIZE - 1);
} else {
// Shorten the file name if not done already.
// For optimization, do this only for the first entry in a
// buffer.
if (first_bufline
&& (errbuf->b_sfname == NULL
|| path_is_absolute(errbuf->b_sfname))) {
if (*dirname == NUL) {
os_dirname(dirname, MAXPATHL);
}
shorten_buf_fname(errbuf, dirname, false);
}
STRLCPY(IObuff, errbuf->b_fname, IOSIZE - 1);
// If 'quickfixtextfunc' is set, then use the user-supplied function to get
// the text to display
qftf = p_qftf;
// Use the local value of 'quickfixtextfunc' if it is set.
if (qfl->qf_qftf != NULL) {
qftf = qfl->qf_qftf;
}
if (qftf != NULL && *qftf != NUL) {
char_u *qfbuf_text;
typval_T args[1];
// create 'info' dict argument
dict_T *const dict = tv_dict_alloc_lock(VAR_FIXED);
tv_dict_add_nr(dict, S_LEN("quickfix"), IS_QF_LIST(qfl));
tv_dict_add_nr(dict, S_LEN("id"), qfl->qf_id);
tv_dict_add_nr(dict, S_LEN("idx"), lnum + 1);
dict->dv_refcount++;
args[0].v_type = VAR_DICT;
args[0].vval.v_dict = dict;
qfbuf_text = (char_u *)call_func_retstr((const char *const)qftf, 1, args);
dict->dv_refcount--;
if (qfbuf_text == NULL) {
return FAIL;
}
len = (int)STRLEN(IObuff);
STRLCPY(IObuff, qfbuf_text, IOSIZE - 1);
xfree(qfbuf_text);
} else {
len = 0;
}
if (len < IOSIZE - 1) {
IObuff[len++] = '|';
}
if (qfp->qf_lnum > 0) {
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%" PRId64,
(int64_t)qfp->qf_lnum);
len += (int)STRLEN(IObuff + len);
if (qfp->qf_module != NULL) {
STRLCPY(IObuff, qfp->qf_module, IOSIZE - 1);
len = (int)STRLEN(IObuff);
} else if (qfp->qf_fnum != 0
&& (errbuf = buflist_findnr(qfp->qf_fnum)) != NULL
&& errbuf->b_fname != NULL) {
if (qfp->qf_type == 1) { // :helpgrep
STRLCPY(IObuff, path_tail(errbuf->b_fname), IOSIZE - 1);
} else {
// Shorten the file name if not done already.
// For optimization, do this only for the first entry in a
// buffer.
if (first_bufline
&& (errbuf->b_sfname == NULL
|| path_is_absolute(errbuf->b_sfname))) {
if (*dirname == NUL) {
os_dirname(dirname, MAXPATHL);
}
shorten_buf_fname(errbuf, dirname, false);
}
STRLCPY(IObuff, errbuf->b_fname, IOSIZE - 1);
}
len = (int)STRLEN(IObuff);
} else {
len = 0;
}
if (len < IOSIZE - 1) {
IObuff[len++] = '|';
}
if (qfp->qf_lnum > 0) {
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%" PRId64,
(int64_t)qfp->qf_lnum);
len += (int)STRLEN(IObuff + len);
if (qfp->qf_col > 0) {
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), " col %d",
qfp->qf_col);
if (qfp->qf_col > 0) {
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), " col %d",
qfp->qf_col);
len += (int)STRLEN(IObuff + len);
}
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
len += (int)STRLEN(IObuff + len);
} else if (qfp->qf_pattern != NULL) {
qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
len += (int)STRLEN(IObuff + len);
}
if (len < IOSIZE - 2) {
IObuff[len++] = '|';
IObuff[len++] = ' ';
}
snprintf((char *)IObuff + len, (size_t)(IOSIZE - len), "%s",
(char *)qf_types(qfp->qf_type, qfp->qf_nr));
len += (int)STRLEN(IObuff + len);
} else if (qfp->qf_pattern != NULL) {
qf_fmt_text(qfp->qf_pattern, IObuff + len, IOSIZE - len);
len += (int)STRLEN(IObuff + len);
// Remove newlines and leading whitespace from the text.
// For an unrecognized line keep the indent, the compiler may
// mark a word with ^^^^.
qf_fmt_text(len > 3 ? skipwhite(qfp->qf_text) : qfp->qf_text,
IObuff + len, IOSIZE - len);
}
if (len < IOSIZE - 2) {
IObuff[len++] = '|';
IObuff[len++] = ' ';
}
// Remove newlines and leading whitespace from the text.
// For an unrecognized line keep the indent, the compiler may
// mark a word with ^^^^.
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) {
@@ -4027,7 +4067,7 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last)
lnum = buf->b_ml.ml_line_count;
}
while (lnum < qfl->qf_count) {
if (qf_buf_add_line(buf, lnum, qfp, dirname,
if (qf_buf_add_line(qfl, buf, lnum, qfp, dirname,
prev_bufnr != qfp->qf_fnum) == FAIL) {
break;
}
@@ -5665,7 +5705,10 @@ static int get_qfline_items(qfline_T *qfp, list_T *list)
/// 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(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
/// If eidx is not 0, then return only the specified entry. Otherwise return
/// all the entries.
int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, int eidx,
list_T *list)
{
qf_info_T *qi = qi_arg;
qf_list_T *qfl;
@@ -5682,6 +5725,10 @@ int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
}
}
if (eidx < 0) {
return OK;
}
if (qf_idx == INVALID_QFIDX) {
qf_idx = qi->qf_curlist;
}
@@ -5696,7 +5743,13 @@ int get_errorlist(qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
}
FOR_ALL_QFL_ITEMS(qfl, qfp, i) {
get_qfline_items(qfp, list);
if (eidx > 0) {
if (eidx == i) {
return get_qfline_items(qfp, list);
}
} else if (get_qfline_items(qfp, list) == FAIL) {
return FAIL;
}
}
return OK;
@@ -5743,7 +5796,7 @@ static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
if (qf_init_ext(qi, 0, NULL, NULL, &di->di_tv, errorformat,
true, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
(void)get_errorlist(qi, NULL, 0, l);
(void)get_errorlist(qi, NULL, 0, 0, l);
qf_free(&qi->qf_lists[0]);
}
xfree(qi);
@@ -5934,11 +5987,13 @@ static int qf_getprop_filewinid(const win_T *wp, const qf_info_T *qi,
return tv_dict_add_nr(retdict, S_LEN("filewinid"), winid);
}
/// Return the quickfix list items/entries as 'items' in retdict
static int qf_getprop_items(qf_info_T *qi, int qf_idx, dict_T *retdict)
/// Return the quickfix list items/entries as 'items' in retdict.
/// If eidx is not 0, then return the item at the specified index.
static int qf_getprop_items(qf_info_T *qi, int qf_idx, int eidx,
dict_T *retdict)
{
list_T *l = tv_list_alloc(kListLenMayKnow);
get_errorlist(qi, NULL, qf_idx, l);
get_errorlist(qi, NULL, qf_idx, eidx, l);
tv_dict_add_list(retdict, S_LEN("items"), l);
return OK;
@@ -5963,15 +6018,18 @@ static int qf_getprop_ctx(qf_list_T *qfl, dict_T *retdict)
return status;
}
/// Return the current quickfix list index as 'idx' in retdict
static int qf_getprop_idx(qf_list_T *qfl, dict_T *retdict)
/// Return the current quickfix list index as 'idx' in retdict.
/// If a specific entry index (eidx) is supplied, then use that.
static int qf_getprop_idx(qf_list_T *qfl, int eidx, dict_T *retdict)
{
int curidx = qfl->qf_index;
if (qf_list_empty(qfl)) {
// For empty lists, current index is set to 0
curidx = 0;
if (eidx == 0) {
eidx = qfl->qf_index;
if (qf_list_empty(qfl)) {
// For empty lists, current index is set to 0
eidx = 0;
}
}
return tv_dict_add_nr(retdict, S_LEN("idx"), curidx);
return tv_dict_add_nr(retdict, S_LEN("idx"), eidx);
}
/// Return quickfix/location list details (title) as a dictionary.
@@ -5984,6 +6042,7 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
dictitem_T *di = NULL;
int status = OK;
int qf_idx = INVALID_QFIDX;
int eidx = 0;
if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
return qf_get_list_from_lines(what, di, retdict);
@@ -6006,6 +6065,14 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
qfl = qf_get_list(qi, qf_idx);
// If an entry index is specified, use that
if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
if (di->di_tv.v_type != VAR_NUMBER) {
return FAIL;
}
eidx = (int)di->di_tv.vval.v_number;
}
if (flags & QF_GETLIST_TITLE) {
status = qf_getprop_title(qfl, retdict);
}
@@ -6016,7 +6083,7 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
status = tv_dict_add_nr(retdict, S_LEN("winid"), qf_winid(qi));
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
status = qf_getprop_items(qi, qf_idx, retdict);
status = qf_getprop_items(qi, qf_idx, eidx, retdict);
}
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
status = qf_getprop_ctx(qfl, retdict);
@@ -6025,7 +6092,7 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
status = tv_dict_add_nr(retdict, S_LEN("id"), qfl->qf_id);
}
if ((status == OK) && (flags & QF_GETLIST_IDX)) {
status = qf_getprop_idx(qfl, retdict);
status = qf_getprop_idx(qfl, eidx, retdict);
}
if ((status == OK) && (flags & QF_GETLIST_SIZE)) {
status = tv_dict_add_nr(retdict, S_LEN("size"),
@@ -6042,6 +6109,17 @@ int qf_get_properties(win_T *wp, dict_T *what, dict_T *retdict)
return status;
}
/// Set the current index in the specified quickfix list
static int qf_setprop_qftf(qf_info_T *qi, qf_list_T *qfl,
dictitem_T *di)
{
XFREE_CLEAR(qfl->qf_qftf);
if (di->di_tv.v_type == VAR_STRING && di->di_tv.vval.v_string != NULL) {
qfl->qf_qftf = vim_strsave(di->di_tv.vval.v_string);
}
return OK;
}
/// Add a new quickfix entry to list at 'qf_idx' in the stack 'qi' from the
/// items in the dict 'd'. If it is a valid error entry, then set 'valid_entry'
/// to true.
@@ -6407,6 +6485,9 @@ static int qf_set_properties(qf_info_T *qi, const dict_T *what, int action,
if ((di = tv_dict_find(what, S_LEN("idx"))) != NULL) {
retval = qf_setprop_curidx(qi, qfl, di);
}
if ((di = tv_dict_find(what, S_LEN("quickfixtextfunc"))) != NULL) {
retval = qf_setprop_qftf(qi, qfl, di);
}
if (newlist || retval == OK) {
qf_list_changed(qfl);