changeset 19033:f0312cf3c792 v8.2.0077

patch 8.2.0077: settagstack() cannot truncate at current index Commit: https://github.com/vim/vim/commit/271fa08a35b8d320d3a40db4ddae83b698fdd4fb Author: Bram Moolenaar <Bram@vim.org> 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)
author Bram Moolenaar <Bram@vim.org>
date Thu, 02 Jan 2020 14:15:05 +0100
parents 02dcaab77547
children a26574e0c267
files runtime/doc/eval.txt src/evalfunc.c src/tag.c src/testdir/test_tagjump.vim src/version.c
diffstat 5 files changed, 66 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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.
 
--- 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
 	{
--- 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
--- 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",
--- 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,