vim-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 vim/vim#5417)
271fa08a35
This commit is contained in:
Jan Edmund Lazo
2020-01-29 20:44:23 -05:00
parent f719b8898b
commit 31f31b40a8
4 changed files with 65 additions and 14 deletions

View File

@@ -7550,11 +7550,21 @@ settagstack({nr}, {dict} [, {action}]) *settagstack()*
{nr} can be the window number or the |window-ID|. {nr} can be the window number or the |window-ID|.
For a list of supported items in {dict}, refer to For a list of supported items in {dict}, refer to
|gettagstack()| |gettagstack()|. "curidx" takes effect before changing the tag
stack.
*E962* *E962*
If {action} is not present or is set to 'r', then the tag How the tag stack is modified depends on the {action}
stack is replaced. If {action} is set to 'a', then new entries argument:
from {dict} are pushed onto the tag stack. - 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. Returns zero for success, -1 for failure.

View File

@@ -16242,7 +16242,8 @@ static void f_settagstack(typval_T *argvars, typval_T *rettv, FunPtr fptr)
if (actstr == NULL) { if (actstr == NULL) {
return; return;
} }
if ((*actstr == 'r' || *actstr == 'a') && actstr[1] == NUL) { if ((*actstr == 'r' || *actstr == 'a' || *actstr == 't')
&& actstr[1] == NUL) {
action = *actstr; action = *actstr;
} else { } else {
EMSG2(_(e_invact2), actstr); EMSG2(_(e_invact2), actstr);

View File

@@ -3378,11 +3378,15 @@ static void tagstack_set_curidx(win_T *wp, int curidx)
} }
// Set the tag stack entries of the specified window. // 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:
int set_tagstack(win_T *wp, dict_T *d, int action) // 'a' for append
// 'r' for replace
// 't' for truncate
int set_tagstack(win_T *wp, const dict_T *d, int action)
FUNC_ATTR_NONNULL_ARG(1)
{ {
dictitem_T *di; dictitem_T *di;
list_T *l; list_T *l = NULL;
// not allowed to alter the tag stack entries from inside tagfunc // not allowed to alter the tag stack entries from inside tagfunc
if (tfu_in_use) { if (tfu_in_use) {
@@ -3395,17 +3399,31 @@ int set_tagstack(win_T *wp, dict_T *d, int action)
return FAIL; return FAIL;
} }
l = di->di_tv.vval.v_list; l = di->di_tv.vval.v_list;
if (action == 'r') {
tagstack_clear(wp);
}
tagstack_push_items(wp, l);
} }
if ((di = tv_dict_find(d, "curidx", -1)) != NULL) { if ((di = tv_dict_find(d, "curidx", -1)) != NULL) {
tagstack_set_curidx(wp, (int)tv_get_number(&di->di_tv) - 1); tagstack_set_curidx(wp, (int)tv_get_number(&di->di_tv) - 1);
} }
if (action == 't') { // truncate the stack
taggy_T *const tagstack = wp->w_tagstack;
const 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; return OK;
} }

View File

@@ -340,6 +340,28 @@ func Test_getsettagstack()
\ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 'a') \ {'items' : [{'tagname' : 'abc', 'from' : [1, 10, 1, 0]}]}, 'a')
call assert_equal('abc', gettagstack().items[19].tagname) 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 " Tag with multiple matches
call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//", call writefile(["!_TAG_FILE_ENCODING\tutf-8\t//",
\ "two\tXfile1\t1", \ "two\tXfile1\t1",