# HG changeset patch # User Bram Moolenaar # Date 1640377803 -3600 # Node ID 2bdcce61a4e403d3fcf40a73e5ceaa922bd0d9a6 # Parent 8c929924dc1553529d4c33b78b026e320297dac4 patch 8.2.3888: the argument list may contain duplicates Commit: https://github.com/vim/vim/commit/73a024209cbfbd5b39a2e974084d807c6131e2ed Author: Nir Lichtman 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) diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt --- 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, diff --git a/runtime/doc/index.txt b/runtime/doc/index.txt --- 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 diff --git a/src/arglist.c b/src/arglist.c --- 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 diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h --- 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; diff --git a/src/ex_cmds.h b/src/ex_cmds.h --- 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), diff --git a/src/proto/arglist.pro b/src/proto/arglist.pro --- 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); diff --git a/src/testdir/test_arglist.vim b/src/testdir/test_arglist.vim --- 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() diff --git a/src/version.c b/src/version.c --- 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,