0
0
mirror of https://github.com/vim/vim.git synced 2025-10-02 05:04:20 -04:00

patch 8.1.0519: cannot save and restore the tag stack

Problem:    Cannot save and restore the tag stack.
Solution:   Add gettagstack() and settagstack(). (Yegappan Lakshmanan,
            closes #3604)
This commit is contained in:
Bram Moolenaar
2018-11-11 15:21:05 +01:00
parent 8617b40159
commit f49cc60aa8
15 changed files with 494 additions and 1 deletions

View File

@@ -2206,6 +2206,7 @@ gettabvar({nr}, {varname} [, {def}])
any variable {varname} in tab {nr} or {def} any variable {varname} in tab {nr} or {def}
gettabwinvar({tabnr}, {winnr}, {name} [, {def}]) gettabwinvar({tabnr}, {winnr}, {name} [, {def}])
any {name} in {winnr} in tab page {tabnr} any {name} in {winnr} in tab page {tabnr}
gettagstack([{nr}]) Dict get the tag stack of window {nr}
getwininfo([{winid}]) List list of info about each window getwininfo([{winid}]) List list of info about each window
getwinpos([{timeout}]) List X and Y coord in pixels of the Vim window getwinpos([{timeout}]) List X and Y coord in pixels of the Vim window
getwinposx() Number X coord in pixels of the Vim window getwinposx() Number X coord in pixels of the Vim window
@@ -2378,6 +2379,8 @@ settabvar({nr}, {varname}, {val}) none set {varname} in tab page {nr} to {val}
settabwinvar({tabnr}, {winnr}, {varname}, {val}) settabwinvar({tabnr}, {winnr}, {varname}, {val})
none set {varname} in window {winnr} in tab none set {varname} in window {winnr} in tab
page {tabnr} to {val} page {tabnr} to {val}
settagstack({nr}, {dict} [, {action}])
Number modify tag stack using {dict}
setwinvar({nr}, {varname}, {val}) none set {varname} in window {nr} to {val} setwinvar({nr}, {varname}, {val}) none set {varname} in window {nr} to {val}
sha256({string}) String SHA256 checksum of {string} sha256({string}) String SHA256 checksum of {string}
shellescape({string} [, {special}]) shellescape({string} [, {special}])
@@ -4971,6 +4974,34 @@ gettabwinvar({tabnr}, {winnr}, {varname} [, {def}]) *gettabwinvar()*
To obtain all window-local variables use: > To obtain all window-local variables use: >
gettabwinvar({tabnr}, {winnr}, '&') gettabwinvar({tabnr}, {winnr}, '&')
gettagstack([{nr}]) *gettagstack()*
The result is a Dict, which is the tag stack of window {nr}.
{nr} can be the window number or the |window-ID|.
When {nr} is not specified, the current window is used.
When window {nr} doesn't exist, an empty Dict is returned.
The returned dictionary contains the following entries:
curidx Current index in the stack. When at
top of the stack, set to (length + 1).
Index of bottom of the stack is 1.
items List of items in the stack. Each item
is a dictionary containing the
entries described below.
length Number of entries in the stack.
Each item in the stack is a dictionary with the following
entries:
bufnr buffer number of the current jump
from cursor position before the tag jump.
See |getpos()| for the format of the
returned list.
matchnr current matching tag number. Used when
multiple matching tags are found for a
name.
tagname name of the tag
See |tagstack| for more information about the tag stack.
getwininfo([{winid}]) *getwininfo()* getwininfo([{winid}]) *getwininfo()*
Returns information about windows as a List with Dictionaries. Returns information about windows as a List with Dictionaries.
@@ -7535,6 +7566,37 @@ settabwinvar({tabnr}, {winnr}, {varname}, {val}) *settabwinvar()*
:call settabwinvar(3, 2, "myvar", "foobar") :call settabwinvar(3, 2, "myvar", "foobar")
< This function is not available in the |sandbox|. < This function is not available in the |sandbox|.
settagstack({nr}, {dict} [, {action}]) *settagstack()*
Modify the tag stack of the window {nr} using {dict}.
{nr} can be the window number or the |window-ID|.
For a list of supported items in {dict}, refer to
|gettagstack()|
*E962*
If {action} is not present or is set to 'r', then the tag
stack is replaced. If {action} is set to 'a', then new entries
from {dict} are pushed onto the tag stack.
Returns zero for success, -1 for failure.
Examples:
Set current index of the tag stack to 4: >
call settagstack(1005, {'curidx' : 4})
< Empty the tag stack of window 3: >
call settagstack(3, {'items' : []})
< Push a new item onto the tag stack: >
let pos = [bufnr('myfile.txt'), 10, 1, 0]
let newtag = [{'tagname' : 'mytag', 'from' : pos}]
call settagstack(2, {'items' : newtag}, 'a')
< Save and restore the tag stack: >
let stack = gettagstack(1003)
" do something else
call settagstack(1003, stack)
unlet stack
<
setwinvar({nr}, {varname}, {val}) *setwinvar()* setwinvar({nr}, {varname}, {val}) *setwinvar()*
Like |settabwinvar()| for the current tab page. Like |settabwinvar()| for the current tab page.
Examples: > Examples: >

View File

@@ -179,6 +179,9 @@ commands explained above the tag stack will look like this:
1 1 main 1 harddisk2:text/vim/test 1 1 main 1 harddisk2:text/vim/test
2 1 FuncB 59 harddisk2:text/vim/src/main.c 2 1 FuncB 59 harddisk2:text/vim/src/main.c
The gettagstack() function returns the tag stack of a specified window. The
settagstack() function modifies the tag stack of a window.
*E73* *E73*
When you try to use the tag stack while it doesn't contain anything you will When you try to use the tag stack while it doesn't contain anything you will
get an error message. get an error message.

View File

@@ -1028,6 +1028,8 @@ Various: *various-functions*
taglist() get list of matching tags taglist() get list of matching tags
tagfiles() get a list of tags files tagfiles() get a list of tags files
gettagstack() get the tag stack
settagstack() modify the tag stack
luaeval() evaluate Lua expression luaeval() evaluate Lua expression
mzeval() evaluate |MzScheme| expression mzeval() evaluate |MzScheme| expression

View File

@@ -18,5 +18,8 @@ typedef enum {
aid_qf_module, aid_qf_module,
aid_qf_errmsg, aid_qf_errmsg,
aid_qf_pattern, aid_qf_pattern,
aid_tagstack_items,
aid_tagstack_from,
aid_tagstack_details,
aid_last aid_last
} alloc_id_T; } alloc_id_T;

View File

@@ -47,6 +47,19 @@ dict_alloc(void)
return d; return d;
} }
/*
* dict_alloc() with an ID for alloc_fail().
*/
dict_T *
dict_alloc_id(alloc_id_T id UNUSED)
{
#ifdef FEAT_EVAL
if (alloc_fail_id == id && alloc_does_fail((long_u)sizeof(list_T)))
return NULL;
#endif
return (dict_alloc());
}
dict_T * dict_T *
dict_alloc_lock(int lock) dict_alloc_lock(int lock)
{ {

View File

@@ -201,6 +201,7 @@ static void f_getregtype(typval_T *argvars, typval_T *rettv);
static void f_gettabinfo(typval_T *argvars, typval_T *rettv); static void f_gettabinfo(typval_T *argvars, typval_T *rettv);
static void f_gettabvar(typval_T *argvars, typval_T *rettv); static void f_gettabvar(typval_T *argvars, typval_T *rettv);
static void f_gettabwinvar(typval_T *argvars, typval_T *rettv); static void f_gettabwinvar(typval_T *argvars, typval_T *rettv);
static void f_gettagstack(typval_T *argvars, typval_T *rettv);
static void f_getwininfo(typval_T *argvars, typval_T *rettv); static void f_getwininfo(typval_T *argvars, typval_T *rettv);
static void f_getwinpos(typval_T *argvars, typval_T *rettv); static void f_getwinpos(typval_T *argvars, typval_T *rettv);
static void f_getwinposx(typval_T *argvars, typval_T *rettv); static void f_getwinposx(typval_T *argvars, typval_T *rettv);
@@ -361,6 +362,7 @@ static void f_setqflist(typval_T *argvars, typval_T *rettv);
static void f_setreg(typval_T *argvars, typval_T *rettv); static void f_setreg(typval_T *argvars, typval_T *rettv);
static void f_settabvar(typval_T *argvars, typval_T *rettv); static void f_settabvar(typval_T *argvars, typval_T *rettv);
static void f_settabwinvar(typval_T *argvars, typval_T *rettv); static void f_settabwinvar(typval_T *argvars, typval_T *rettv);
static void f_settagstack(typval_T *argvars, typval_T *rettv);
static void f_setwinvar(typval_T *argvars, typval_T *rettv); static void f_setwinvar(typval_T *argvars, typval_T *rettv);
#ifdef FEAT_CRYPT #ifdef FEAT_CRYPT
static void f_sha256(typval_T *argvars, typval_T *rettv); static void f_sha256(typval_T *argvars, typval_T *rettv);
@@ -666,6 +668,7 @@ static struct fst
{"gettabinfo", 0, 1, f_gettabinfo}, {"gettabinfo", 0, 1, f_gettabinfo},
{"gettabvar", 2, 3, f_gettabvar}, {"gettabvar", 2, 3, f_gettabvar},
{"gettabwinvar", 3, 4, f_gettabwinvar}, {"gettabwinvar", 3, 4, f_gettabwinvar},
{"gettagstack", 0, 1, f_gettagstack},
{"getwininfo", 0, 1, f_getwininfo}, {"getwininfo", 0, 1, f_getwininfo},
{"getwinpos", 0, 1, f_getwinpos}, {"getwinpos", 0, 1, f_getwinpos},
{"getwinposx", 0, 0, f_getwinposx}, {"getwinposx", 0, 0, f_getwinposx},
@@ -828,6 +831,7 @@ static struct fst
{"setreg", 2, 3, f_setreg}, {"setreg", 2, 3, f_setreg},
{"settabvar", 3, 3, f_settabvar}, {"settabvar", 3, 3, f_settabvar},
{"settabwinvar", 4, 4, f_settabwinvar}, {"settabwinvar", 4, 4, f_settabwinvar},
{"settagstack", 2, 3, f_settagstack},
{"setwinvar", 3, 3, f_setwinvar}, {"setwinvar", 3, 3, f_setwinvar},
#ifdef FEAT_CRYPT #ifdef FEAT_CRYPT
{"sha256", 1, 1, f_sha256}, {"sha256", 1, 1, f_sha256},
@@ -5656,6 +5660,27 @@ f_gettabwinvar(typval_T *argvars, typval_T *rettv)
getwinvar(argvars, rettv, 1); getwinvar(argvars, rettv, 1);
} }
/*
* "gettagstack()" function
*/
static void
f_gettagstack(typval_T *argvars, typval_T *rettv)
{
win_T *wp = curwin; // default is current window
if (rettv_dict_alloc(rettv) != OK)
return;
if (argvars[0].v_type != VAR_UNKNOWN)
{
wp = find_win_by_nr_or_id(&argvars[0]);
if (wp == NULL)
return;
}
get_tagstack(wp, rettv->vval.v_dict);
}
/* /*
* Returns information about a window as a dictionary. * Returns information about a window as a dictionary.
*/ */
@@ -11118,6 +11143,62 @@ f_settabwinvar(typval_T *argvars, typval_T *rettv)
setwinvar(argvars, rettv, 1); setwinvar(argvars, rettv, 1);
} }
/*
* "settagstack()" function
*/
static void
f_settagstack(typval_T *argvars, typval_T *rettv)
{
static char *e_invact2 = N_("E962: Invalid action: '%s'");
win_T *wp;
dict_T *d;
int action = 'r';
rettv->vval.v_number = -1;
// first argument: window number or id
wp = find_win_by_nr_or_id(&argvars[0]);
if (wp == NULL)
return;
// second argument: dict with items to set in the tag stack
if (argvars[1].v_type != VAR_DICT)
{
EMSG(_(e_dictreq));
return;
}
d = argvars[1].vval.v_dict;
if (d == NULL)
return;
// third argument: action - 'a' for append and 'r' for replace.
// default is to replace the stack.
if (argvars[2].v_type == VAR_UNKNOWN)
action = 'r';
else if (argvars[2].v_type == VAR_STRING)
{
char_u *actstr;
actstr = get_tv_string_chk(&argvars[2]);
if (actstr == NULL)
return;
if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL)
action = *actstr;
else
{
EMSG2(_(e_invact2), actstr);
return;
}
}
else
{
EMSG(_(e_stringreq));
return;
}
if (set_tagstack(wp, d, action) == OK)
rettv->vval.v_number = 0;
}
/* /*
* "setwinvar()" function * "setwinvar()" function
*/ */

View File

@@ -85,6 +85,19 @@ list_alloc(void)
return l; return l;
} }
/*
* list_alloc() with an ID for alloc_fail().
*/
list_T *
list_alloc_id(alloc_id_T id UNUSED)
{
#ifdef FEAT_EVAL
if (alloc_fail_id == id && alloc_does_fail((long_u)sizeof(list_T)))
return NULL;
#endif
return (list_alloc());
}
/* /*
* Allocate an empty list for a return value, with reference count set. * Allocate an empty list for a return value, with reference count set.
* Returns OK or FAIL. * Returns OK or FAIL.

View File

@@ -835,7 +835,7 @@ vim_mem_profile_dump(void)
#endif /* MEM_PROFILE */ #endif /* MEM_PROFILE */
#ifdef FEAT_EVAL #ifdef FEAT_EVAL
static int int
alloc_does_fail(long_u size) alloc_does_fail(long_u size)
{ {
if (alloc_fail_countdown == 0) if (alloc_fail_countdown == 0)

View File

@@ -1,5 +1,6 @@
/* dict.c */ /* dict.c */
dict_T *dict_alloc(void); dict_T *dict_alloc(void);
dict_T *dict_alloc_id(alloc_id_T id);
dict_T *dict_alloc_lock(int lock); dict_T *dict_alloc_lock(int lock);
int rettv_dict_alloc(typval_T *rettv); int rettv_dict_alloc(typval_T *rettv);
void rettv_dict_set(typval_T *rettv, dict_T *d); void rettv_dict_set(typval_T *rettv, dict_T *d);

View File

@@ -3,6 +3,7 @@ void list_add_watch(list_T *l, listwatch_T *lw);
void list_rem_watch(list_T *l, listwatch_T *lwrem); void list_rem_watch(list_T *l, listwatch_T *lwrem);
void list_fix_watch(list_T *l, listitem_T *item); void list_fix_watch(list_T *l, listitem_T *item);
list_T *list_alloc(void); list_T *list_alloc(void);
list_T *list_alloc_id(alloc_id_T id);
int rettv_list_alloc(typval_T *rettv); int rettv_list_alloc(typval_T *rettv);
void rettv_list_set(typval_T *rettv, list_T *l); void rettv_list_set(typval_T *rettv, list_T *l);
void list_unref(list_T *l); void list_unref(list_T *l);

View File

@@ -21,6 +21,7 @@ void adjust_cursor_col(void);
int leftcol_changed(void); int leftcol_changed(void);
void vim_mem_profile_dump(void); void vim_mem_profile_dump(void);
char_u *alloc(unsigned size); char_u *alloc(unsigned size);
int alloc_does_fail(long_u size);
char_u *alloc_id(unsigned size, alloc_id_T id); char_u *alloc_id(unsigned size, alloc_id_T id);
char_u *alloc_clear(unsigned size); char_u *alloc_clear(unsigned size);
char_u *alloc_check(unsigned size); char_u *alloc_check(unsigned size);

View File

@@ -9,4 +9,6 @@ void tagname_free(tagname_T *tnp);
void simplify_filename(char_u *filename); void simplify_filename(char_u *filename);
int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file); int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file);
int get_tags(list_T *list, char_u *pat, char_u *buf_fname); int get_tags(list_T *list, char_u *pat, char_u *buf_fname);
void get_tagstack(win_T *wp, dict_T *retdict);
int set_tagstack(win_T *wp, dict_T *d, int action);
/* vim: set ft=c : */ /* vim: set ft=c : */

200
src/tag.c
View File

@@ -4016,4 +4016,204 @@ get_tags(list_T *list, char_u *pat, char_u *buf_fname)
} }
return ret; return ret;
} }
/*
* Return information about 'tag' in dict 'retdict'.
*/
static void
get_tag_details(taggy_T *tag, dict_T *retdict)
{
list_T *pos;
fmark_T *fmark;
dict_add_string(retdict, "tagname", tag->tagname);
dict_add_number(retdict, "matchnr", tag->cur_match + 1);
dict_add_number(retdict, "bufnr", tag->cur_fnum);
if ((pos = list_alloc_id(aid_tagstack_from)) == NULL)
return;
dict_add_list(retdict, "from", pos);
fmark = &tag->fmark;
list_append_number(pos,
(varnumber_T)(fmark->fnum != -1 ? fmark->fnum : 0));
list_append_number(pos, (varnumber_T)fmark->mark.lnum);
list_append_number(pos, (varnumber_T)(fmark->mark.col == MAXCOL ?
MAXCOL : fmark->mark.col + 1));
list_append_number(pos, (varnumber_T)fmark->mark.coladd);
}
/*
* Return the tag stack entries of the specified window 'wp' in dictionary
* 'retdict'.
*/
void
get_tagstack(win_T *wp, dict_T *retdict)
{
list_T *l;
int i;
dict_T *d;
dict_add_number(retdict, "length", wp->w_tagstacklen);
dict_add_number(retdict, "curidx", wp->w_tagstackidx + 1);
l = list_alloc_id(aid_tagstack_items);
if (l == NULL)
return;
dict_add_list(retdict, "items", l);
for (i = 0; i < wp->w_tagstacklen; i++)
{
if ((d = dict_alloc_id(aid_tagstack_details)) == NULL)
return;
list_append_dict(l, d);
get_tag_details(&wp->w_tagstack[i], d);
}
}
/*
* Free all the entries in the tag stack of the specified window
*/
static void
tagstack_clear(win_T *wp)
{
int i;
// Free the current tag stack
for (i = 0; i < wp->w_tagstacklen; ++i)
vim_free(wp->w_tagstack[i].tagname);
wp->w_tagstacklen = 0;
wp->w_tagstackidx = 0;
}
/*
* Remove the oldest entry from the tag stack and shift the rest of
* the entires to free up the top of the stack.
*/
static void
tagstack_shift(win_T *wp)
{
taggy_T *tagstack = wp->w_tagstack;
int i;
vim_free(tagstack[0].tagname);
for (i = 1; i < wp->w_tagstacklen; ++i)
tagstack[i - 1] = tagstack[i];
wp->w_tagstacklen--;
}
/*
* Push a new item to the tag stack
*/
static void
tagstack_push_item(
win_T *wp,
char_u *tagname,
int cur_fnum,
int cur_match,
pos_T mark,
int fnum)
{
taggy_T *tagstack = wp->w_tagstack;
int idx = wp->w_tagstacklen; // top of the stack
// if the tagstack is full: remove the oldest entry
if (idx >= TAGSTACKSIZE)
{
tagstack_shift(wp);
idx = TAGSTACKSIZE - 1;
}
wp->w_tagstacklen++;
tagstack[idx].tagname = tagname;
tagstack[idx].cur_fnum = cur_fnum;
tagstack[idx].cur_match = cur_match;
if (tagstack[idx].cur_match < 0)
tagstack[idx].cur_match = 0;
tagstack[idx].fmark.mark = mark;
tagstack[idx].fmark.fnum = fnum;
}
/*
* Add a list of items to the tag stack in the specified window
*/
static void
tagstack_push_items(win_T *wp, list_T *l)
{
listitem_T *li;
dictitem_T *di;
dict_T *itemdict;
char_u *tagname;
pos_T mark;
int fnum;
// Add one entry at a time to the tag stack
for (li = l->lv_first; li != NULL; li = li->li_next)
{
if (li->li_tv.v_type != VAR_DICT || li->li_tv.vval.v_dict == NULL)
continue; // Skip non-dict items
itemdict = li->li_tv.vval.v_dict;
// parse 'from' for the cursor position before the tag jump
if ((di = dict_find(itemdict, (char_u *)"from", -1)) == NULL)
continue;
if (list2fpos(&di->di_tv, &mark, &fnum, NULL) != OK)
continue;
if ((tagname =
get_dict_string(itemdict, (char_u *)"tagname", TRUE)) == NULL)
continue;
if (mark.col > 0)
mark.col--;
tagstack_push_item(wp, tagname,
(int)get_dict_number(itemdict, (char_u *)"bufnr"),
(int)get_dict_number(itemdict, (char_u *)"matchnr") - 1,
mark, fnum);
}
}
/*
* Set the current index in the tag stack. Valid values are between 0
* and the stack length (inclusive).
*/
static void
tagstack_set_curidx(win_T *wp, int curidx)
{
wp->w_tagstackidx = curidx;
if (wp->w_tagstackidx < 0) // sanity check
wp->w_tagstackidx = 0;
if (wp->w_tagstackidx > wp->w_tagstacklen)
wp->w_tagstackidx = wp->w_tagstacklen;
}
/*
* Set the tag stack entries of the specified window.
* 'action' is set to either 'a' for append or 'r' for replace.
*/
int
set_tagstack(win_T *wp, dict_T *d, int action)
{
dictitem_T *di;
list_T *l;
if ((di = dict_find(d, (char_u *)"items", -1)) != NULL)
{
if (di->di_tv.v_type != VAR_LIST)
{
EMSG(_(e_listreq));
return FAIL;
}
l = di->di_tv.vval.v_list;
if (action == 'r')
tagstack_clear(wp);
tagstack_push_items(wp, l);
}
if ((di = dict_find(d, (char_u *)"curidx", -1)) != NULL)
tagstack_set_curidx(wp, (int)get_tv_number(&di->di_tv) - 1);
return OK;
}
#endif #endif

View File

@@ -257,4 +257,113 @@ func Test_tagjump_etags()
bwipe! bwipe!
endfunc endfunc
" Test for getting and modifying the tag stack
func Test_getsettagstack()
call writefile(['line1', 'line2', 'line3'], 'Xfile1')
call writefile(['line1', 'line2', 'line3'], 'Xfile2')
call writefile(['line1', 'line2', 'line3'], 'Xfile3')
enew | only
call settagstack(1, {'items' : []})
call assert_equal(0, gettagstack(1).length)
call assert_equal([], gettagstack(1).items)
" Error cases
call assert_equal({}, gettagstack(100))
call assert_equal(-1, settagstack(100, {'items' : []}))
call assert_fails('call settagstack(1, [1, 10])', 'E715')
call assert_fails("call settagstack(1, {'items' : 10})", 'E714')
call assert_fails("call settagstack(1, {'items' : []}, 10)", 'E928')
call assert_fails("call settagstack(1, {'items' : []}, 'b')", 'E962')
set tags=Xtags
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "one\tXfile1\t1",
\ "three\tXfile3\t3",
\ "two\tXfile2\t2"],
\ 'Xtags')
let stk = []
call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'one',
\ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
tag one
call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'two',
\ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
tag two
call add(stk, {'bufnr' : bufnr('%'), 'tagname' : 'three',
\ 'from' : [bufnr('%'), line('.'), col('.'), 0], 'matchnr' : 1})
tag three
call assert_equal(3, gettagstack(1).length)
call assert_equal(stk, gettagstack(1).items)
" Check for default - current window
call assert_equal(3, gettagstack().length)
call assert_equal(stk, gettagstack().items)
" Try to set current index to invalid values
call settagstack(1, {'curidx' : -1})
call assert_equal(1, gettagstack().curidx)
call settagstack(1, {'curidx' : 50})
call assert_equal(4, gettagstack().curidx)
" Try pushing invalid items onto the stack
call settagstack(1, {'items' : []})
call settagstack(1, {'items' : ["plate"]}, 'a')
call assert_equal(0, gettagstack().length)
call assert_equal([], gettagstack().items)
call settagstack(1, {'items' : [{"tagname" : "abc"}]}, 'a')
call assert_equal(0, gettagstack().length)
call assert_equal([], gettagstack().items)
call settagstack(1, {'items' : [{"from" : 100}]}, 'a')
call assert_equal(0, gettagstack().length)
call assert_equal([], gettagstack().items)
call settagstack(1, {'items' : [{"from" : [2, 1, 0, 0]}]}, 'a')
call assert_equal(0, gettagstack().length)
call assert_equal([], gettagstack().items)
" Push one item at a time to the stack
call settagstack(1, {'items' : []})
call settagstack(1, {'items' : [stk[0]]}, 'a')
call settagstack(1, {'items' : [stk[1]]}, 'a')
call settagstack(1, {'items' : [stk[2]]}, 'a')
call settagstack(1, {'curidx' : 4})
call assert_equal({'length' : 3, 'curidx' : 4, 'items' : stk},
\ gettagstack(1))
" Try pushing items onto a full stack
for i in range(7)
call settagstack(1, {'items' : stk}, 'a')
endfor
call assert_equal(20, gettagstack().length)
call settagstack(1,
\ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 'a')
call assert_equal('abc', gettagstack().items[19].tagname)
" Tag with multiple matches
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "two\tXfile1\t1",
\ "two\tXfile2\t3",
\ "two\tXfile3\t2"],
\ 'Xtags')
call settagstack(1, {'items' : []})
tag two
tnext
tnext
call assert_equal(1, gettagstack().length)
call assert_equal(3, gettagstack().items[0].matchnr)
" Memory allocation failures
call test_alloc_fail(GetAllocId('tagstack_items'), 0, 0)
call assert_fails('call gettagstack()', 'E342:')
call test_alloc_fail(GetAllocId('tagstack_from'), 0, 0)
call assert_fails('call gettagstack()', 'E342:')
call test_alloc_fail(GetAllocId('tagstack_details'), 0, 0)
call assert_fails('call gettagstack()', 'E342:')
call settagstack(1, {'items' : []})
call delete('Xfile1')
call delete('Xfile2')
call delete('Xfile3')
call delete('Xtags')
set tags&
endfunc
" vim: shiftwidth=2 sts=2 expandtab " vim: shiftwidth=2 sts=2 expandtab

View File

@@ -792,6 +792,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
519,
/**/ /**/
518, 518,
/**/ /**/