changeset 26719:2bdcce61a4e4 v8.2.3888

patch 8.2.3888: the argument list may contain duplicates Commit: https://github.com/vim/vim/commit/73a024209cbfbd5b39a2e974084d807c6131e2ed Author: Nir Lichtman <nir_lichtman@hotmail.com> Date: Fri Dec 24 20:28:03 2021 +0000 patch 8.2.3888: the argument list may contain duplicates Problem: The argument list may contain duplicates. Solution: Add the :argdedeupe command. (Nir Lichtman, closes https://github.com/vim/vim/issues/6235)
author Bram Moolenaar <Bram@vim.org>
date Fri, 24 Dec 2021 21:30:03 +0100
parents 8c929924dc15
children 7d4b0da6a26b
files runtime/doc/editing.txt runtime/doc/index.txt src/arglist.c src/ex_cmdidxs.h src/ex_cmds.h src/proto/arglist.pro src/testdir/test_arglist.vim src/version.c
diffstat 8 files changed, 99 insertions(+), 29 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -650,12 +650,19 @@ list of the current window.
 			And after the last one:
 				:+2argadd y	a b c x y
 			There is no check for duplicates, it is possible to
-			add a file to the argument list twice.
-			The currently edited file is not changed.
+			add a file to the argument list twice.  You can use
+			|:argdedupe| to fix it afterwards: >
+				:argadd *.txt | argdedupe
+<			The currently edited file is not changed.
 			Note: you can also use this method: >
 				:args ## x
 <			This will add the "x" item and sort the new list.
 
+:argded[upe]					*:argded* *:argdedupe*
+			Remove duplicate filenames from the argument list.
+			If your current file is a duplicate, your current file
+			will change to the original file index.
+
 :argd[elete] {pattern} ..		*:argd* *:argdelete* *E480* *E610*
 			Delete files from the argument list that match the
 			{pattern}s.  {pattern} is used like a file pattern,
--- a/runtime/doc/index.txt
+++ b/runtime/doc/index.txt
@@ -1166,6 +1166,7 @@ tag		command		action ~
 				be remapped
 |:args|		:ar[gs]		print the argument list
 |:argadd|	:arga[dd]	add items to the argument list
+:argdedupe	:argdedupe	remove duplicates from the argument list
 |:argdelete|	:argd[elete]	delete items from the argument list
 |:argedit|	:arge[dit]	add item to the argument list and edit it
 |:argdo|	:argdo		do a command on all items in the argument list
--- a/src/arglist.c
+++ b/src/arglist.c
@@ -759,6 +759,33 @@ ex_next(exarg_T *eap)
 }
 
 /*
+ * ":argdedupe"
+ */
+    void
+ex_argdedupe(exarg_T *eap UNUSED)
+{
+    int i;
+    int j;
+
+    for (i = 0; i < ARGCOUNT; ++i)
+	for (j = i + 1; j < ARGCOUNT; ++j)
+	    if (fnamecmp(ARGLIST[i].ae_fname, ARGLIST[j].ae_fname) == 0)
+	    {
+		vim_free(ARGLIST[j].ae_fname);
+		mch_memmove(ARGLIST + j, ARGLIST + j + 1,
+					(ARGCOUNT - j - 1) * sizeof(aentry_T));
+		--ARGCOUNT;
+
+		if (curwin->w_arg_idx == j)
+		    curwin->w_arg_idx = i;
+		else if (curwin->w_arg_idx > j)
+		    --curwin->w_arg_idx;
+
+		--j;
+	    }
+}
+
+/*
  * ":argedit"
  */
     void
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -6,31 +6,31 @@
 static const unsigned short cmdidxs1[26] =
 {
   /* a */ 0,
-  /* b */ 20,
-  /* c */ 44,
-  /* d */ 111,
-  /* e */ 136,
-  /* f */ 164,
-  /* g */ 181,
-  /* h */ 187,
-  /* i */ 196,
-  /* j */ 216,
-  /* k */ 218,
-  /* l */ 223,
-  /* m */ 286,
-  /* n */ 304,
-  /* o */ 324,
-  /* p */ 336,
-  /* q */ 375,
-  /* r */ 378,
-  /* s */ 398,
-  /* t */ 468,
-  /* u */ 514,
-  /* v */ 525,
-  /* w */ 546,
-  /* x */ 560,
-  /* y */ 570,
-  /* z */ 571
+  /* b */ 21,
+  /* c */ 45,
+  /* d */ 112,
+  /* e */ 137,
+  /* f */ 165,
+  /* g */ 182,
+  /* h */ 188,
+  /* i */ 197,
+  /* j */ 217,
+  /* k */ 219,
+  /* l */ 224,
+  /* m */ 287,
+  /* n */ 305,
+  /* o */ 325,
+  /* p */ 337,
+  /* q */ 376,
+  /* r */ 379,
+  /* s */ 399,
+  /* t */ 469,
+  /* u */ 515,
+  /* v */ 526,
+  /* w */ 547,
+  /* x */ 561,
+  /* y */ 571,
+  /* z */ 572
 };
 
 /*
@@ -41,7 +41,7 @@ static const unsigned short cmdidxs1[26]
  */
 static const unsigned char cmdidxs2[26][26] =
 { /*         a   b   c   d   e   f   g   h   i   j   k   l   m   n   o   p   q   r   s   t   u   v   w   x   y   z */
-  /* a */ {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  6,  7,  0,  0,  0,  8, 16,  0, 17,  0,  0,  0,  0,  0 },
+  /* a */ {  0,  1,  0,  0,  0,  0,  0,  0,  0,  0,  0,  5,  6,  7,  0,  0,  0,  8, 17,  0, 18,  0,  0,  0,  0,  0 },
   /* b */ {  2,  0,  0,  5,  6,  8,  0,  0,  0,  0,  0,  9, 10, 11, 12, 13,  0, 14,  0,  0,  0,  0, 23,  0,  0,  0 },
   /* c */ {  3, 12, 16, 18, 20, 22, 25,  0,  0,  0,  0, 33, 38, 41, 47, 57, 59, 60, 61,  0, 63,  0, 66,  0,  0,  0 },
   /* d */ {  0,  0,  0,  0,  0,  0,  0,  0,  8, 18,  0, 19,  0,  0, 20,  0,  0, 22, 23,  0,  0,  0,  0,  0,  0,  0 },
@@ -69,4 +69,4 @@ static const unsigned char cmdidxs2[26][
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 588;
+static const int command_count = 589;
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -148,6 +148,9 @@ EXCMD(CMD_argdelete,	"argdelete",	ex_arg
 EXCMD(CMD_argdo,	"argdo",	ex_listdo,
 	EX_BANG|EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_RANGE|EX_DFLALL|EX_EXPAND,
 	ADDR_ARGUMENTS),
+EXCMD(CMD_argdedupe,	"argdedupe",	ex_argdedupe,
+	EX_TRLBAR,
+	ADDR_NONE),
 EXCMD(CMD_argedit,	"argedit",	ex_argedit,
 	EX_BANG|EX_NEEDARG|EX_RANGE|EX_ZEROR|EX_FILES|EX_CMDARG|EX_ARGOPT|EX_TRLBAR,
 	ADDR_ARGUMENTS),
--- a/src/proto/arglist.pro
+++ b/src/proto/arglist.pro
@@ -18,6 +18,7 @@ void ex_last(exarg_T *eap);
 void ex_argument(exarg_T *eap);
 void do_argfile(exarg_T *eap, int argn);
 void ex_next(exarg_T *eap);
+void ex_argdedupe(exarg_T *eap);
 void ex_argedit(exarg_T *eap);
 void ex_argadd(exarg_T *eap);
 void ex_argdelete(exarg_T *eap);
--- a/src/testdir/test_arglist.vim
+++ b/src/testdir/test_arglist.vim
@@ -416,6 +416,35 @@ func Test_argedit()
   bw! x
 endfunc
 
+" Test for the :argdedupe command
+func Test_argdedupe()
+  call Reset_arglist()
+  argdedupe
+  call assert_equal([], argv())
+  args a a a aa b b a b aa
+  argdedupe
+  call assert_equal(['a', 'aa', 'b'], argv())
+  args a b c
+  argdedupe
+  call assert_equal(['a', 'b', 'c'], argv())
+  args a
+  argdedupe
+  call assert_equal(['a'], argv())
+  args a A b B
+  argdedupe
+  if has('fname_case')
+    call assert_equal(['a', 'A', 'b', 'B'], argv())
+  else
+    call assert_equal(['a', 'b'], argv())
+  endif
+  args a b a c a b
+  last
+  argdedupe
+  next
+  call assert_equal('c', expand('%:t'))
+  %argd
+endfunc
+
 " Test for the :argdelete command
 func Test_argdelete()
   call Reset_arglist()
--- a/src/version.c
+++ b/src/version.c
@@ -750,6 +750,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    3888,
+/**/
     3887,
 /**/
     3886,