# HG changeset patch # User Bram Moolenaar # Date 1577970905 -3600 # Node ID f0312cf3c792a07ee66fcb99faa312b289de85c4 # Parent 02dcaab775478b9205546c050034cc7c00a2f9d2 patch 8.2.0077: settagstack() cannot truncate at current index Commit: https://github.com/vim/vim/commit/271fa08a35b8d320d3a40db4ddae83b698fdd4fb Author: Bram Moolenaar Date: Thu Jan 2 14:02:16 2020 +0100 patch 8.2.0077: settagstack() cannot truncate at current index Problem: settagstack() cannot truncate at current index. Solution: Add the "t" action. (Yegappan Lakshmanan, closes https://github.com/vim/vim/issues/5417) diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -8774,11 +8774,21 @@ settagstack({nr}, {dict} [, {action}]) {nr} can be the window number or the |window-ID|. For a list of supported items in {dict}, refer to - |gettagstack()| + |gettagstack()|. "curidx" takes effect before changing the tag + stack. *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. + How the tag stack is modified depends on the {action} + argument: + - 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 (added) onto the tag stack. + - If {action} is set to 't', then all the entries from the + current entry in the tag stack or "curidx" in {dict} are + removed and then new entries are pushed to the stack. + + The current index is set to one after the length of the tag + stack after the modification. Returns zero for success, -1 for failure. diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -6776,7 +6776,8 @@ f_settagstack(typval_T *argvars, typval_ actstr = tv_get_string_chk(&argvars[2]); if (actstr == NULL) return; - if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL) + if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't') + && actstr[1] == NUL) action = *actstr; else { diff --git a/src/tag.c b/src/tag.c --- a/src/tag.c +++ b/src/tag.c @@ -4224,13 +4224,16 @@ tagstack_set_curidx(win_T *wp, int curid /* * Set the tag stack entries of the specified window. - * 'action' is set to either 'a' for append or 'r' for replace. + * 'action' is set to one of: + * 'a' for append + * 'r' for replace + * 't' for truncate */ int set_tagstack(win_T *wp, dict_T *d, int action) { dictitem_T *di; - list_T *l; + list_T *l = NULL; #ifdef FEAT_EVAL // not allowed to alter the tag stack entries from inside tagfunc @@ -4249,16 +4252,32 @@ set_tagstack(win_T *wp, dict_T *d, int a 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)tv_get_number(&di->di_tv) - 1); + if (action == 't') // truncate the stack + { + taggy_T *tagstack = wp->w_tagstack; + int tagstackidx = wp->w_tagstackidx; + int tagstacklen = wp->w_tagstacklen; + // delete all the tag stack entries above the current entry + while (tagstackidx < tagstacklen) + tagstack_clear_entry(&tagstack[--tagstacklen]); + wp->w_tagstacklen = tagstacklen; + } + + if (l != NULL) + { + if (action == 'r') // replace the stack + tagstack_clear(wp); + + tagstack_push_items(wp, l); + // set the current index after the last entry + wp->w_tagstackidx = wp->w_tagstacklen; + } + return OK; } #endif diff --git a/src/testdir/test_tagjump.vim b/src/testdir/test_tagjump.vim --- a/src/testdir/test_tagjump.vim +++ b/src/testdir/test_tagjump.vim @@ -348,6 +348,28 @@ func Test_getsettagstack() \ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 'a') call assert_equal('abc', gettagstack().items[19].tagname) + " truncate the tag stack + call settagstack(1, + \ {'curidx' : 9, + \ 'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 't') + let t = gettagstack() + call assert_equal(9, t.length) + call assert_equal(10, t.curidx) + + " truncate the tag stack without pushing any new items + call settagstack(1, {'curidx' : 5}, 't') + let t = gettagstack() + call assert_equal(4, t.length) + call assert_equal(5, t.curidx) + + " truncate an empty tag stack and push new items + call settagstack(1, {'items' : []}) + call settagstack(1, + \ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 't') + let t = gettagstack() + call assert_equal(1, t.length) + call assert_equal(2, t.curidx) + " Tag with multiple matches call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", \ "two\tXfile1\t1", diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -743,6 +743,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 77, +/**/ 76, /**/ 75,