vim-patch:9.2.0812: :argdelete with pattern leads to wrong argidx() (#40876)

Problem:  :argdelete with pattern leads to wrong argidx().
Solution: Correct argidx() in both branches of ex_argdelete().  Also use
          ARGCOUNT macro in two more places (zeertzjq).

related: patch 7.4.1119
related: neovim/neovim#40564
closes:  vim/vim#20697

https://github.com/vim/vim/commit/3b40a14a46c2e4f2a29dbf0b2fe48260ce2166ab
This commit is contained in:
zeertzjq authored and GitHub committed 2026-07-21 07:01:52 +08:00
1 parent 16c145d240
commit 60b643a815
2 files changed
+50 -20

No files matched your search

+24 -19
View File
@@ -375,7 +375,7 @@ static void arglist_del_files(garray_T *alist_ga)
xfree(ARGLIST[match].ae_fname);
memmove(ARGLIST + match, ARGLIST + match + 1,
(size_t)(ARGCOUNT - match - 1) * sizeof(aentry_T));
ALIST(curwin)->al_ga.ga_len--;
ARGCOUNT--;
if (curwin->w_arg_idx > match) {
curwin->w_arg_idx--;
}
@@ -780,32 +780,37 @@ void ex_argdelete(exarg_T *eap)
if (*eap->arg != NUL) {
// Can't have both a range and an argument.
emsg(_(e_invarg));
} else if (n <= 0) {
return;
}
if (n <= 0) {
// Don't give an error for ":%argdel" if the list is empty.
if (eap->line1 != 1 || eap->line2 != 0) {
emsg(_(e_invrange));
}
} else {
for (linenr_T i = eap->line1; i <= eap->line2; i++) {
xfree(ARGLIST[i - 1].ae_fname);
}
memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
(size_t)(ARGCOUNT - eap->line2) * sizeof(aentry_T));
ALIST(curwin)->al_ga.ga_len -= (int)n;
if (curwin->w_arg_idx >= eap->line2) {
curwin->w_arg_idx -= (int)n;
} else if (curwin->w_arg_idx > eap->line1) {
curwin->w_arg_idx = (int)eap->line1;
}
if (ARGCOUNT == 0) {
curwin->w_arg_idx = 0;
} else if (curwin->w_arg_idx >= ARGCOUNT) {
curwin->w_arg_idx = ARGCOUNT - 1;
}
return;
}
for (linenr_T i = eap->line1; i <= eap->line2; i++) {
xfree(ARGLIST[i - 1].ae_fname);
}
memmove(ARGLIST + eap->line1 - 1, ARGLIST + eap->line2,
(size_t)(ARGCOUNT - eap->line2) * sizeof(aentry_T));
ARGCOUNT -= n;
if (curwin->w_arg_idx >= eap->line2) {
curwin->w_arg_idx -= n;
} else if (curwin->w_arg_idx > eap->line1) {
curwin->w_arg_idx = eap->line1;
}
} else {
do_arglist(eap->arg, AL_DEL, 0, false);
}
if (ARGCOUNT == 0) {
curwin->w_arg_idx = 0;
} else if (curwin->w_arg_idx >= ARGCOUNT) {
curwin->w_arg_idx = ARGCOUNT - 1;
}
maketitle();
}
+26 -1
View File
@@ -462,15 +462,40 @@ func Test_argdelete()
args aa a aaa b bb
argdelete a*
call assert_equal(['b', 'bb'], argv())
call assert_equal(0, argidx())
call assert_equal('aa', expand('%:t'))
last
call assert_equal(1, argidx())
call assert_equal('bb', expand('%:t'))
argdelete %
call assert_equal(['b'], argv())
call assert_fails('argdelete', 'E610:')
call assert_equal(0, argidx())
call assert_equal('bb', expand('%:t'))
call assert_fails('1,100argdelete', 'E16:')
call assert_fails('argdel /\)/', 'E55:')
call assert_fails('1argdel 1', 'E474:')
call Reset_arglist()
args aa a aaa b bb
4argument
call assert_equal(3, argidx())
call assert_equal('b', expand('%:t'))
argdelete aa*
call assert_equal(['a', 'b', 'bb'], argv())
call assert_equal(1, argidx())
call assert_equal('b', expand('%:t'))
2argdelete
call assert_equal(['a', 'bb'], argv())
call assert_equal(1, argidx())
call assert_equal('b', expand('%:t'))
%argdelete
call assert_equal([], argv())
call assert_equal(0, argidx())
call assert_equal('b', expand('%:t'))
" :%argdelete when the arglist is already empty should not error
%argdelete
call Reset_arglist()
args a b c d
next