Merge #8969 from janlazo/vim-8.0.1006

This commit is contained in:
Justin M. Keyes 2018-09-09 11:29:18 +02:00 committed by GitHub
commit a8bd4de28a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 276 additions and 82 deletions

View File

@ -4335,23 +4335,39 @@ 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()|
efm errorformat to use when parsing "lines". If
not present, then the 'erroformat' option
value is used.
id get information for the quickfix list with
|quickfix-ID|; zero means the id for the
current list or the list specifed by "nr"
items quickfix list entries
lines use 'errorformat' to extract items from a list
of lines and return the resulting entries.
Only a |List| type is accepted. The current
quickfix list is not modified.
nr get information for this quickfix list; zero
means the current quickfix list and '$' means
means the current quickfix list and "$" means
the last quickfix list
title get the list title
winid get the |window-ID| (if opened)
all all of the above quickfix properties
Non-string items in {what} are ignored.
If "nr" is not present then the current quickfix list is used.
If both "nr" and a non-zero "id" are specified, then the list
specified by "id" is used.
To get the number of lists in the quickfix stack, set 'nr' to
'$' in {what}. The 'nr' value in the returned dictionary
contains the quickfix stack size.
When 'text' is specified, all the other items are ignored. The
returned dictionary contains the entry 'items' with the list
of entries.
In case of error processing {what}, an empty dictionary is
returned.
The returned dictionary contains the following entries:
context context information stored with |setqflist()|
id quickfix list ID |quickfix-ID|
items quickfix list entries
nr quickfix list number
title quickfix list title text
@ -4360,6 +4376,7 @@ getqflist([{what}]) *getqflist()*
Examples: >
:echo getqflist({'all': 1})
:echo getqflist({'nr': 2, 'title': 1})
:echo getqflist({'lines' : ["F1:10:L10"]})
<
getreg([{regname} [, 1 [, {list}]]]) *getreg()*
@ -6904,7 +6921,7 @@ setqflist({list} [, {action}[, {what}]]) *setqflist()*
is created. The new quickfix list is added after the current
quickfix list in the stack and all the following lists are
freed. To add a new quickfix list at the end of the stack,
set "nr" in {what} to '$'.
set "nr" in {what} to "$".
If {title} is given, it will be used to set |w:quickfix_title|
after opening the quickfix window.
@ -6914,24 +6931,31 @@ 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
text use 'errorformat' to extract items from the
text and add the resulting entries to the
quickfix list {nr}. The value can be a string
with one line or a list with multiple lines.
efm errorformat to use when parsing text from
"lines". If this is not present, then the
'errorformat' option value is used.
id quickfix list identifier |quickfix-ID|
items list of quickfix entries. Same as the {list}
argument.
lines use 'errorformat' to parse a list of lines and
add the resulting entries to the quickfix list
{nr} or {id}. Only a |List| value is supported.
nr list number in the quickfix stack; zero
means the current quickfix list and '$' means
means the current quickfix list and "$" means
the last quickfix list
title quickfix list title text
Unsupported keys in {what} are ignored.
If the "nr" item is not present, then the current quickfix list
is modified. When creating a new quickfix list, "nr" can be
set to a value one greater than the quickfix stack size.
When modifying a quickfix list, to guarantee that the correct
list is modified, "id" should be used instead of "nr" to
specify the list.
Examples: >
:call setqflist([], 'r', {'title': 'My search'})
:call setqflist([], 'r', {'nr': 2, 'title': 'Errors'})
:call setqflist([], 'r', {'title': 'My search'})
:call setqflist([], 'r', {'nr': 2, 'title': 'Errors'})
:call setqflist([], 'a', {'id':myid, 'lines':["F1:10:L10"]})
<
Returns zero for success, -1 for failure.

View File

@ -9943,7 +9943,7 @@ static void get_qf_loc_list(int is_qf, win_T *wp, typval_T *what_arg,
if (what_arg->v_type == VAR_UNKNOWN) {
tv_list_alloc_ret(rettv, kListLenMayKnow);
if (is_qf || wp != NULL) {
(void)get_errorlist(wp, -1, rettv->vval.v_list);
(void)get_errorlist(NULL, wp, -1, rettv->vval.v_list);
}
} else {
tv_dict_alloc_ret(rettv);

View File

@ -82,6 +82,7 @@ struct qfline_S {
/// 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 {
unsigned qf_id; ///< Unique identifier for this list
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
@ -116,7 +117,8 @@ struct qf_info_S {
qf_list_T qf_lists[LISTCOUNT];
};
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
#define FMT_PATTERNS 10 /* maximum number of % recognized */
@ -1224,6 +1226,7 @@ static void qf_new_list(qf_info_T *qi, char_u *qf_title)
qi->qf_curlist = qi->qf_listcount++;
memset(&qi->qf_lists[qi->qf_curlist], 0, (size_t)(sizeof(qf_list_T)));
qf_store_title(qi, qi->qf_curlist, qf_title);
qi->qf_lists[qi->qf_curlist].qf_id = ++last_qf_id;
}
/*
@ -1467,6 +1470,9 @@ void copy_loclist(win_T *from, win_T *to)
to_qfl->qf_index = from_qfl->qf_index; /* current index in the list */
// Assign a new ID for the location list
to_qfl->qf_id = ++last_qf_id;
/* When no valid entries are present in the list, qf_ptr points to
* the first item in the list */
if (to_qfl->qf_nonevalid) {
@ -2414,7 +2420,7 @@ static void qf_free_items(qf_info_T *qi, int idx)
while (qfl->qf_count && qfl->qf_start != NULL) {
qfp = qfl->qf_start;
qfpnext = qfp->qf_next;
if (qfl->qf_title != NULL && !stop) {
if (!stop) {
xfree(qfp->qf_text);
stop = (qfp == qfpnext);
xfree(qfp->qf_pattern);
@ -2458,6 +2464,7 @@ static void qf_free(qf_info_T *qi, int idx)
qfl->qf_title = NULL;
tv_free(qfl->qf_ctx);
qfl->qf_ctx = NULL;
qfl->qf_id = 0;
}
/*
@ -4031,18 +4038,22 @@ static void unload_dummy_buffer(buf_T *buf, char_u *dirname_start)
/// 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(win_T *wp, int qf_idx, list_T *list)
int get_errorlist(const qf_info_T *qi_arg, win_T *wp, int qf_idx, list_T *list)
{
qf_info_T *qi = &ql_info;
const qf_info_T *qi = qi_arg;
char_u buf[2];
qfline_T *qfp;
int i;
int bufnum;
if (wp != NULL) {
qi = GET_LOC_LIST(wp);
if (qi == NULL)
return FAIL;
if (qi == NULL) {
qi = &ql_info;
if (wp != NULL) {
qi = GET_LOC_LIST(wp);
if (qi == NULL) {
return FAIL;
}
}
}
if (qf_idx == -1) {
@ -4106,9 +4117,48 @@ enum {
QF_GETLIST_NR = 0x4,
QF_GETLIST_WINID = 0x8,
QF_GETLIST_CONTEXT = 0x10,
QF_GETLIST_ID = 0x20,
QF_GETLIST_ALL = 0xFF
};
// Parse text from 'di' and return the quickfix list items
static int qf_get_list_from_lines(dict_T *what, dictitem_T *di, dict_T *retdict)
{
int status = FAIL;
char_u *errorformat = p_efm;
dictitem_T *efm_di;
// Only a List value is supported
if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
// If errorformat is supplied then use it, otherwise use the 'efm'
// option setting
if ((efm_di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
if (efm_di->di_tv.v_type != VAR_STRING
|| efm_di->di_tv.vval.v_string == NULL) {
return FAIL;
}
errorformat = efm_di->di_tv.vval.v_string;
}
list_T *l = tv_list_alloc(kListLenMayKnow);
qf_info_T *qi = xmalloc(sizeof(*qi));
memset(qi, 0, sizeof(*qi));
qi->qf_refcount++;
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);
qf_free(qi, 0);
}
xfree(qi);
tv_dict_add_list(retdict, S_LEN("items"), l);
status = OK;
}
return status;
}
/// Return quickfix/location list details (title) as a
/// dictionary. 'what' contains the details to return. If 'list_idx' is -1,
/// then current list is used. Otherwise the specified list is used.
@ -4117,17 +4167,22 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
qf_info_T *qi = &ql_info;
dictitem_T *di;
if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
return qf_get_list_from_lines(what, di, retdict);
}
if (wp != NULL) {
qi = GET_LOC_LIST(wp);
if (qi == NULL) {
// If querying for the size of the location list, return 0
if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL)
&& (di->di_tv.v_type == VAR_STRING)
&& strequal((const char *)di->di_tv.vval.v_string, "$")) {
return tv_dict_add_nr(retdict, S_LEN("nr"), 0);
}
return FAIL;
}
// List is not present or is empty
if (qi == NULL || qi->qf_listcount == 0) {
// If querying for the size of the list, return 0
if (((di = tv_dict_find(what, S_LEN("nr"))) != NULL)
&& (di->di_tv.v_type == VAR_STRING)
&& (STRCMP(di->di_tv.vval.v_string, "$") == 0)) {
return tv_dict_add_nr(retdict, S_LEN("nr"), 0);
}
return FAIL;
}
int status = OK;
@ -4143,44 +4198,51 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
if (qf_idx < 0 || qf_idx >= qi->qf_listcount) {
return FAIL;
}
} else if (qi->qf_listcount == 0) { // stack is empty
return FAIL;
}
flags |= QF_GETLIST_NR;
} else if (di->di_tv.v_type == VAR_STRING
&& strequal((const char *)di->di_tv.vval.v_string, "$")) {
// Get the last quickfix list number
if (qi->qf_listcount > 0) {
qf_idx = qi->qf_listcount - 1;
} else {
qf_idx = -1; // Quickfix stack is empty
qf_idx = qi->qf_listcount - 1;
} else {
return FAIL;
}
flags |= QF_GETLIST_NR;
}
if ((di = tv_dict_find(what, S_LEN("id"))) != NULL) {
// Look for a list with the specified id
if (di->di_tv.v_type == VAR_NUMBER) {
// For zero, use the current list or the list specifed by 'nr'
if (di->di_tv.vval.v_number != 0) {
for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) {
if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) {
break;
}
}
if (qf_idx == qi->qf_listcount) {
return FAIL; // List not found
}
}
flags |= QF_GETLIST_NR;
flags |= QF_GETLIST_ID;
} else {
return FAIL;
}
}
if (qf_idx != -1) {
if (tv_dict_find(what, S_LEN("all")) != NULL) {
flags |= QF_GETLIST_ALL;
}
if (tv_dict_find(what, S_LEN("title")) != NULL) {
flags |= QF_GETLIST_TITLE;
}
if (tv_dict_find(what, S_LEN("winid")) != NULL) {
flags |= QF_GETLIST_WINID;
}
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 (tv_dict_find(what, S_LEN("all")) != NULL) {
flags |= QF_GETLIST_ALL;
}
if (tv_dict_find(what, S_LEN("title")) != NULL) {
flags |= QF_GETLIST_TITLE;
}
if (tv_dict_find(what, S_LEN("winid")) != NULL) {
flags |= QF_GETLIST_WINID;
}
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) {
@ -4201,7 +4263,7 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
if ((status == OK) && (flags & QF_GETLIST_ITEMS)) {
list_T *l = tv_list_alloc(kListLenMayKnow);
(void)get_errorlist(wp, qf_idx, l);
(void)get_errorlist(qi, NULL, qf_idx, l);
tv_dict_add_list(retdict, S_LEN("items"), l);
}
@ -4218,6 +4280,10 @@ int get_errorlist_properties(win_T *wp, dict_T *what, dict_T *retdict)
}
}
if ((status == OK) && (flags & QF_GETLIST_ID)) {
status = tv_dict_add_nr(retdict, S_LEN("id"), qi->qf_lists[qf_idx].qf_id);
}
return status;
}
@ -4336,6 +4402,7 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
dictitem_T *di;
int retval = FAIL;
int newlist = false;
char_u *errorformat = p_efm;
if (action == ' ' || qi->qf_curlist == qi->qf_listcount) {
newlist = true;
@ -4374,6 +4441,22 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
}
}
if (!newlist && (di = tv_dict_find(what, S_LEN("id"))) != NULL) {
// Use the quickfix/location list with the specified id
if (di->di_tv.v_type == VAR_NUMBER) {
for (qf_idx = 0; qf_idx < qi->qf_listcount; qf_idx++) {
if (qi->qf_lists[qf_idx].qf_id == di->di_tv.vval.v_number) {
break;
}
}
if (qf_idx == qi->qf_listcount) {
return FAIL; // List not found
}
} else {
return FAIL;
}
}
if (newlist) {
qi->qf_curlist = qf_idx;
qf_new_list(qi, title);
@ -4401,16 +4484,20 @@ static int qf_set_properties(qf_info_T *qi, dict_T *what, int action,
}
}
if ((di = tv_dict_find(what, S_LEN("text"))) != NULL) {
// Only string and list values are supported
if ((di->di_tv.v_type == VAR_STRING
&& di->di_tv.vval.v_string != NULL)
|| (di->di_tv.v_type == VAR_LIST
&& di->di_tv.vval.v_list != NULL)) {
if ((di = tv_dict_find(what, S_LEN("efm"))) != NULL) {
if (di->di_tv.v_type != VAR_STRING || di->di_tv.vval.v_string == NULL) {
return FAIL;
}
errorformat = di->di_tv.vval.v_string;
}
if ((di = tv_dict_find(what, S_LEN("lines"))) != NULL) {
// Only a List value is supported
if (di->di_tv.v_type == VAR_LIST && di->di_tv.vval.v_list != NULL) {
if (action == 'r') {
qf_free_items(qi, qf_idx);
}
if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, p_efm,
if (qf_init_ext(qi, qf_idx, NULL, NULL, &di->di_tv, errorformat,
false, (linenr_T)0, (linenr_T)0, NULL, NULL) > 0) {
retval = OK;
}

View File

@ -1879,8 +1879,9 @@ func Xproperty_tests(cchar)
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
let save_id = l1.id
let l1.id=l2.id
let l2.id=save_id
call g:Xsetlist([], 'r', l1)
call g:Xsetlist([], 'r', l2)
let newl1=g:Xgetlist({'nr':1,'all':1})
@ -2280,27 +2281,39 @@ func Xsetexpr_tests(cchar)
call s:setup_commands(a:cchar)
let t = ["File1:10:Line10", "File1:20:Line20"]
call g:Xsetlist([], ' ', {'text' : t})
call g:Xsetlist([], 'a', {'text' : "File1:30:Line30"})
call g:Xsetlist([], ' ', {'lines' : t})
call g:Xsetlist([], 'a', {'lines' : ["File1:30:Line30"]})
let l = g:Xgetlist()
call assert_equal(3, len(l))
call assert_equal(20, l[1].lnum)
call assert_equal('Line30', l[2].text)
call g:Xsetlist([], 'r', {'text' : "File2:5:Line5"})
call g:Xsetlist([], 'r', {'lines' : ["File2:5:Line5"]})
let l = g:Xgetlist()
call assert_equal(1, len(l))
call assert_equal('Line5', l[0].text)
call assert_equal(-1, g:Xsetlist([], 'a', {'text' : 10}))
call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : 10}))
call assert_equal(-1, g:Xsetlist([], 'a', {'lines' : "F1:10:L10"}))
call g:Xsetlist([], 'f')
" Add entries to multiple lists
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : ["File2:25:Line25"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:10:Line10"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:20:Line20"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["File1:15:Line15"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["File2:25:Line25"]})
call assert_equal('Line15', g:Xgetlist({'nr':1, 'items':1}).items[1].text)
call assert_equal('Line25', g:Xgetlist({'nr':2, 'items':1}).items[1].text)
" Adding entries using a custom efm
set efm&
call g:Xsetlist([], ' ', {'efm' : '%f#%l#%m',
\ 'lines' : ["F1#10#L10", "F2#20#L20"]})
call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
call g:Xsetlist([], 'a', {'efm' : '%f#%l#%m', 'lines' : ["F3:30:L30"]})
call assert_equal('F3:30:L30', g:Xgetlist({'items':1}).items[2].text)
call assert_equal(20, g:Xgetlist({'items':1}).items[1].lnum)
call assert_equal(-1, g:Xsetlist([], 'a', {'efm' : [],
\ 'lines' : ['F1:10:L10']}))
endfunc
func Test_setexpr()
@ -2315,16 +2328,16 @@ func Xmultidirstack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "Entering dir 'Xone/a'"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "Entering dir 'Xtwo/a'"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "one.txt:3:one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "two.txt:5:two two two"})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["Entering dir 'Xone/a'"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["Entering dir 'Xtwo/a'"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["one.txt:3:one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["two.txt:5:two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
call assert_equal('Xone/a/one.txt', bufname(l1.items[1].bufnr))
call assert_equal(expand('Xone/a/one.txt'), bufname(l1.items[1].bufnr))
call assert_equal(3, l1.items[1].lnum)
call assert_equal('Xtwo/a/two.txt', bufname(l2.items[1].bufnr))
call assert_equal(expand('Xtwo/a/two.txt'), bufname(l2.items[1].bufnr))
call assert_equal(5, l2.items[1].lnum)
endfunc
@ -2352,10 +2365,10 @@ func Xmultifilestack_tests(cchar)
call g:Xsetlist([], 'f')
Xexpr "" | Xexpr ""
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "[one.txt]"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "[two.txt]"})
call g:Xsetlist([], 'a', {'nr' : 1, 'text' : "(3,5) one one one"})
call g:Xsetlist([], 'a', {'nr' : 2, 'text' : "(5,9) two two two"})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["[one.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["[two.txt]"]})
call g:Xsetlist([], 'a', {'nr' : 1, 'lines' : ["(3,5) one one one"]})
call g:Xsetlist([], 'a', {'nr' : 2, 'lines' : ["(5,9) two two two"]})
let l1 = g:Xgetlist({'nr':1, 'items':1})
let l2 = g:Xgetlist({'nr':2, 'items':1})
@ -2501,3 +2514,73 @@ func Test_add_qf()
call XaddQf_tests('c')
call XaddQf_tests('l')
endfunc
" Test for getting the quickfix list items from some text without modifying
" the quickfix stack
func XgetListFromLines(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
let l = g:Xgetlist({'lines' : ["File2:20:Line20", "File2:30:Line30"]}).items
call assert_equal(2, len(l))
call assert_equal(30, l[1].lnum)
call assert_equal({}, g:Xgetlist({'lines' : 10}))
call assert_equal({}, g:Xgetlist({'lines' : 'File1:10:Line10'}))
call assert_equal([], g:Xgetlist({'lines' : []}).items)
call assert_equal([], g:Xgetlist({'lines' : [10, 20]}).items)
" Parse text using a custom efm
set efm&
let l = g:Xgetlist({'lines':['File3#30#Line30'], 'efm' : '%f#%l#%m'}).items
call assert_equal('Line30', l[0].text)
let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : '%f-%l-%m'}).items
call assert_equal('File3:30:Line30', l[0].text)
let l = g:Xgetlist({'lines':['File3:30:Line30'], 'efm' : [1,2]})
call assert_equal({}, l)
call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':'%2'})", 'E376:')
call assert_fails("call g:Xgetlist({'lines':['abc'], 'efm':''})", 'E378:')
" Make sure that the quickfix stack is not modified
call assert_equal(0, g:Xgetlist({'nr' : '$'}).nr)
endfunc
func Test_get_list_from_lines()
call XgetListFromLines('c')
call XgetListFromLines('l')
endfunc
" Tests for the quickfix list id
func Xqfid_tests(cchar)
call s:setup_commands(a:cchar)
call g:Xsetlist([], 'f')
call assert_equal({}, g:Xgetlist({'id':0}))
Xexpr ''
let start_id = g:Xgetlist({'id' : 0}).id
Xexpr '' | Xexpr ''
Xolder
call assert_equal(start_id, g:Xgetlist({'id':0, 'nr':1}).id)
call assert_equal(start_id + 1, g:Xgetlist({'id':0, 'nr':0}).id)
call assert_equal(start_id + 2, g:Xgetlist({'id':0, 'nr':'$'}).id)
call assert_equal({}, g:Xgetlist({'id':0, 'nr':99}))
call assert_equal(2, g:Xgetlist({'id':start_id + 1, 'nr':0}).nr)
call assert_equal({}, g:Xgetlist({'id':99, 'nr':0}))
call assert_equal({}, g:Xgetlist({'id':"abc", 'nr':0}))
call g:Xsetlist([], 'a', {'id':start_id, 'context':[1,2]})
call assert_equal([1,2], g:Xgetlist({'nr':1, 'context':1}).context)
call g:Xsetlist([], 'a', {'id':start_id+1, 'lines':['F1:10:L10']})
call assert_equal('L10', g:Xgetlist({'nr':2, 'items':1}).items[0].text)
call assert_equal(-1, g:Xsetlist([], 'a', {'id':999, 'title':'Vim'}))
call assert_equal(-1, g:Xsetlist([], 'a', {'id':'abc', 'title':'Vim'}))
let qfid = g:Xgetlist({'id':0, 'nr':0})
call g:Xsetlist([], 'f')
call assert_equal({}, g:Xgetlist({'id':qfid, 'nr':0}))
endfunc
func Test_qf_id()
call Xqfid_tests('c')
call Xqfid_tests('l')
endfunc