vim-patch:8.0.0657: cannot get and set quickfix list items

Problem:    Cannot get and set quickfix list items.
Solution:   Add the "items" argument to getqflist() and setqflist(). (Yegappan
            Lakshmanan)

6a8958db25
This commit is contained in:
James McCoy
2017-12-31 00:36:35 -05:00
parent 3efc50d1d4
commit d0c4bd23f7
3 changed files with 134 additions and 18 deletions

View File

@@ -4328,6 +4328,7 @@ getqflist([{what}]) *getqflist()*
returns only the items listed in {what} as a dictionary. The
following string items are supported in {what}:
context get the context stored with |setqflist()|
items quickfix list entries
nr get information for this quickfix list; zero
means the current quickfix list and '$' means
the last quickfix list
@@ -4344,6 +4345,7 @@ getqflist([{what}]) *getqflist()*
The returned dictionary contains the following entries:
context context information stored with |setqflist()|
items quickfix list entries
nr quickfix list number
title quickfix list title text
winid quickfix |window-ID| (if opened)
@@ -6892,6 +6894,8 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
argument is ignored. The following items can be specified in
{what}:
context any Vim type can be stored as a context
items list of quickfix entries. Same as the {list}
argument.
nr list number in the quickfix stack; zero
means the current quickfix list and '$' means
the last quickfix list

View File

@@ -76,18 +76,25 @@ struct qfline_S {
*/
#define LISTCOUNT 10
/// Quickfix/Location list definition
///
/// Usually the list contains one or more entries. But an empty list can be
/// created using setqflist()/setloclist() with a title and/or user context
/// information and entries can be added later using setqflist()/setloclist().
typedef struct qf_list_S {
qfline_T *qf_start; // pointer to the first error
qfline_T *qf_last; // pointer to the last error
qfline_T *qf_ptr; // pointer to the current error
int qf_count; // number of errors (0 means no error list)
int qf_index; // current index in the error list
int qf_nonevalid; // TRUE if not a single valid entry found
char_u *qf_title; // title derived from the command that created
// the error list
typval_T *qf_ctx; // context set by setqflist/setloclist
qfline_T *qf_start; ///< pointer to the first error
qfline_T *qf_last; ///< pointer to the last error
qfline_T *qf_ptr; ///< pointer to the current error
int qf_count; ///< number of errors (0 means empty list)
int qf_index; ///< current index in the error list
int qf_nonevalid; ///< TRUE if not a single valid entry found
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
} qf_list_T;
/// Quickfix/Location list stack definition
/// Contains a list of quickfix/location lists (qf_list_T)
struct qf_info_S {
/*
* Count of references to this list. Used only for location lists.
@@ -1185,6 +1192,9 @@ qf_init_end:
static void qf_store_title(qf_info_T *qi, int qf_idx, char_u *title)
{
xfree(qi->qf_lists[qf_idx].qf_title);
qi->qf_lists[qf_idx].qf_title = NULL;
if (title != NULL) {
size_t len = STRLEN(title) + 1;
char_u *p = xmallocz(len);
@@ -2396,8 +2406,9 @@ void qf_history(exarg_T *eap)
}
}
/// Free all the entries in the error list "idx".
static void qf_free(qf_info_T *qi, int idx)
/// Free all the entries in the error list "idx". Note that other information
/// associated with the list like context and title are not freed.
static void qf_free_items(qf_info_T *qi, int idx)
{
qfline_T *qfp;
qfline_T *qfpnext;
@@ -2421,12 +2432,9 @@ static void qf_free(qf_info_T *qi, int idx)
qi->qf_lists[idx].qf_start = qfpnext;
qi->qf_lists[idx].qf_count--;
}
xfree(qi->qf_lists[idx].qf_title);
qi->qf_lists[idx].qf_start = NULL;
qi->qf_lists[idx].qf_ptr = NULL;
qi->qf_lists[idx].qf_title = NULL;
tv_free(qi->qf_lists[idx].qf_ctx);
qi->qf_lists[idx].qf_ctx = NULL;
qi->qf_lists[idx].qf_index = 0;
qi->qf_lists[idx].qf_start = NULL;
qi->qf_lists[idx].qf_last = NULL;
@@ -2442,6 +2450,18 @@ static void qf_free(qf_info_T *qi, int idx)
qi->qf_multiscan = false;
}
/// Free error list "idx". Frees all the entries in the quickfix list,
/// associated context information and the title.
static void qf_free(qf_info_T *qi, int idx)
{
qf_free_items(qi, idx);
xfree(qi->qf_lists[idx].qf_title);
qi->qf_lists[idx].qf_title = NULL;
tv_free(qi->qf_lists[idx].qf_ctx);
qi->qf_lists[idx].qf_ctx = NULL;
}
/*
* qf_mark_adjust: adjust marks
*/
@@ -4150,6 +4170,10 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (tv_dict_find(what, S_LEN("context")) != NULL) {
flags |= QF_GETLIST_CONTEXT;
}
if (tv_dict_find(what, S_LEN("items")) != NULL) {
flags |= QF_GETLIST_ITEMS;
}
}
if (flags & QF_GETLIST_TITLE) {
@@ -4168,6 +4192,11 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
status = tv_dict_add_nr(retdict, S_LEN("winid"), win->handle);
}
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
list_T *l = tv_list_alloc();
(void)get_errorlist(wp, qf_idx, l);
tv_dict_add_list(retdict, S_LEN("items"), l);
}
if ((status == OK) && (flags & QF_GETLIST_CONTEXT)) {
if (qi->qf_lists[qf_idx].qf_ctx != NULL) {
@@ -4204,7 +4233,7 @@ static int qf_add_entries(qf_info_T *qi, int qf_idx, list_T *list,
// Adding to existing list, use last entry.
old_last = qi->qf_lists[qf_idx].qf_last;
} else if (action == 'r') {
qf_free(qi, qf_idx);
qf_free_items(qi, qf_idx);
qf_store_title(qi, qf_idx, title);
}
@@ -4312,17 +4341,24 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
if (di->di_tv.vval.v_number != 0) {
qf_idx = (int)di->di_tv.vval.v_number - 1;
}
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
if ((action == ' ' || action == 'a') && qf_idx == qi->qf_listcount) {
// When creating a new list, accept qf_idx pointing to the next
// non-available list
newlist = true;
} else if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
} else {
newlist = false; // use the specified list
}
} else if (di->di_tv.v_type == VAR_STRING
&& strequal((const char *)di->di_tv.vval.v_string, "$")
&& qi->qf_listcount > 0) {
qf_idx = qi->qf_listcount - 1;
newlist = false;
} else {
return FAIL;
}
newlist = false; // use the specified list
}
if (newlist) {
@@ -4341,6 +4377,15 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action)
retval = OK;
}
}
if ((di = tv_dict_find(what, S_LEN("items"))) != NULL) {
if (di->di_tv.v_type == VAR_LIST) {
char_u *title_save = vim_strsave(qi->qf_lists[qf_idx].qf_title);
retval = qf_add_entries(qi, qf_idx, di->di_tv.vval.v_list,
title_save, action == ' ' ? 'a' : action);
xfree(title_save);
}
}
if ((di = tv_dict_find(what, S_LEN("context"))) != NULL) {
tv_free(qi->qf_lists[qf_idx].qf_ctx);

View File

@@ -1817,6 +1817,73 @@ func Xproperty_tests(cchar)
call test_garbagecollect_now()
let m = g:Xgetlist({'context' : 1})
call assert_equal(["red", "blue", "green"], m.context)
" Test for setting/getting items
Xexpr ""
let qfprev = g:Xgetlist({'nr':0})
call g:Xsetlist([], ' ', {'title':'Green',
\ 'items' : [{'filename':'F1', 'lnum':10}]})
let qfcur = g:Xgetlist({'nr':0})
call assert_true(qfcur.nr == qfprev.nr + 1)
let l = g:Xgetlist({'items':1})
call assert_equal('F1', bufname(l.items[0].bufnr))
call assert_equal(10, l.items[0].lnum)
call g:Xsetlist([], 'a', {'items' : [{'filename':'F2', 'lnum':20},
\ {'filename':'F2', 'lnum':30}]})
let l = g:Xgetlist({'items':1})
call assert_equal('F2', bufname(l.items[2].bufnr))
call assert_equal(30, l.items[2].lnum)
call g:Xsetlist([], 'r', {'items' : [{'filename':'F3', 'lnum':40}]})
let l = g:Xgetlist({'items':1})
call assert_equal('F3', bufname(l.items[0].bufnr))
call assert_equal(40, l.items[0].lnum)
call g:Xsetlist([], 'r', {'items' : []})
let l = g:Xgetlist({'items':1})
call assert_equal(0, len(l.items))
" Save and restore the quickfix stack
call g:Xsetlist([], 'f')
call assert_equal(0, g:Xgetlist({'nr':'$'}).nr)
Xexpr "File1:10:Line1"
Xexpr "File2:20:Line2"
Xexpr "File3:30:Line3"
let last_qf = g:Xgetlist({'nr':'$'}).nr
call assert_equal(3, last_qf)
let qstack = []
for i in range(1, last_qf)
let qstack = add(qstack, g:Xgetlist({'nr':i, 'all':1}))
endfor
call g:Xsetlist([], 'f')
for i in range(len(qstack))
call g:Xsetlist([], ' ', qstack[i])
endfor
call assert_equal(3, g:Xgetlist({'nr':'$'}).nr)
call assert_equal(10, g:Xgetlist({'nr':1, 'items':1}).items[0].lnum)
call assert_equal(20, g:Xgetlist({'nr':2, 'items':1}).items[0].lnum)
call assert_equal(30, g:Xgetlist({'nr':3, 'items':1}).items[0].lnum)
call g:Xsetlist([], 'f')
" Swap two quickfix lists
Xexpr "File1:10:Line10"
Xexpr "File2:20:Line20"
Xexpr "File3:30:Line30"
call g:Xsetlist([], 'r', {'nr':1,'title':'Colors','context':['Colors']})
call g:Xsetlist([], 'r', {'nr':2,'title':'Fruits','context':['Fruits']})
let l1=g:Xgetlist({'nr':1,'all':1})
let l2=g:Xgetlist({'nr':2,'all':1})
let l1.nr=2
let l2.nr=1
call g:Xsetlist([], 'r', l1)
call g:Xsetlist([], 'r', l2)
let newl1=g:Xgetlist({'nr':1,'all':1})
let newl2=g:Xgetlist({'nr':2,'all':1})
call assert_equal(':Fruits', newl1.title)
call assert_equal(['Fruits'], newl1.context)
call assert_equal('Line20', newl1.items[0].text)
call assert_equal(':Colors', newl2.title)
call assert_equal(['Colors'], newl2.context)
call assert_equal('Line10', newl2.items[0].text)
call g:Xsetlist([], 'f')
endfunc
func Test_qf_property()