mirror of
https://github.com/neovim/neovim.git
synced 2024-12-24 05:05:00 -07:00
Merge pull request #20497 from zeertzjq/vim-8.2.2413
vim-patch:8.2.{2413,2421,2463,3884,3885,3886},9.0.0388: arglist patches
This commit is contained in:
commit
28e228d60d
@ -27,19 +27,57 @@
|
||||
#include "nvim/vim.h"
|
||||
#include "nvim/window.h"
|
||||
|
||||
/// State used by the :all command to open all the files in the argument list in
|
||||
/// separate windows.
|
||||
typedef struct {
|
||||
alist_T *alist; ///< argument list to be used
|
||||
int had_tab;
|
||||
bool keep_tabs;
|
||||
bool forceit;
|
||||
|
||||
bool use_firstwin; ///< use first window for arglist
|
||||
uint8_t *opened; ///< Array of weight for which args are open:
|
||||
///< 0: not opened
|
||||
///< 1: opened in other tab
|
||||
///< 2: opened in curtab
|
||||
///< 3: opened in curtab and curwin
|
||||
int opened_len; ///< length of opened[]
|
||||
win_T *new_curwin;
|
||||
tabpage_T *new_curtab;
|
||||
} arg_all_state_T;
|
||||
|
||||
#ifdef INCLUDE_GENERATED_DECLARATIONS
|
||||
# include "arglist.c.generated.h"
|
||||
#endif
|
||||
|
||||
static char e_cannot_change_arglist_recursively[]
|
||||
= N_("E1156: Cannot change the argument list recursively");
|
||||
|
||||
enum {
|
||||
AL_SET = 1,
|
||||
AL_ADD = 2,
|
||||
AL_DEL = 3,
|
||||
};
|
||||
|
||||
/// This flag is set whenever the argument list is being changed and calling a
|
||||
/// function that might trigger an autocommand.
|
||||
static bool arglist_locked = false;
|
||||
|
||||
static int check_arglist_locked(void)
|
||||
{
|
||||
if (arglist_locked) {
|
||||
emsg(_(e_cannot_change_arglist_recursively));
|
||||
return FAIL;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
/// Clear an argument list: free all file names and reset it to zero entries.
|
||||
void alist_clear(alist_T *al)
|
||||
{
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
#define FREE_AENTRY_FNAME(arg) xfree((arg)->ae_fname)
|
||||
GA_DEEP_CLEAR(&al->al_ga, aentry_T, FREE_AENTRY_FNAME);
|
||||
}
|
||||
@ -107,13 +145,9 @@ void alist_expand(int *fnum_list, int fnum_len)
|
||||
/// Takes over the allocated files[] and the allocated fnames in it.
|
||||
void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_list, int fnum_len)
|
||||
{
|
||||
static int recursive = 0;
|
||||
|
||||
if (recursive) {
|
||||
emsg(_(e_au_recursive));
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
recursive++;
|
||||
|
||||
alist_clear(al);
|
||||
ga_grow(&al->al_ga, count);
|
||||
@ -131,7 +165,9 @@ void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_l
|
||||
// May set buffer name of a buffer previously used for the
|
||||
// argument list, so that it's re-used by alist_add.
|
||||
if (fnum_list != NULL && i < fnum_len) {
|
||||
arglist_locked = true;
|
||||
buf_set_name(fnum_list[i], files[i]);
|
||||
arglist_locked = false;
|
||||
}
|
||||
|
||||
alist_add(al, files[i], use_curbuf ? 2 : 1);
|
||||
@ -143,7 +179,6 @@ void alist_set(alist_T *al, int count, char **files, int use_curbuf, int *fnum_l
|
||||
if (al == &global_alist) {
|
||||
arg_had_last = false;
|
||||
}
|
||||
recursive--;
|
||||
}
|
||||
|
||||
/// Add file "fname" to argument list "al".
|
||||
@ -155,6 +190,11 @@ void alist_add(alist_T *al, char *fname, int set_fnum)
|
||||
if (fname == NULL) { // don't add NULL file names
|
||||
return;
|
||||
}
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
arglist_locked = true;
|
||||
|
||||
#ifdef BACKSLASH_IN_FILENAME
|
||||
slash_adjust(fname);
|
||||
#endif
|
||||
@ -164,6 +204,8 @@ void alist_add(alist_T *al, char *fname, int set_fnum)
|
||||
buflist_add(fname, BLN_LISTED | (set_fnum == 2 ? BLN_CURBUF : 0));
|
||||
}
|
||||
al->al_ga.ga_len++;
|
||||
|
||||
arglist_locked = false;
|
||||
}
|
||||
|
||||
#if defined(BACKSLASH_IN_FILENAME)
|
||||
@ -285,7 +327,7 @@ static void alist_add_list(int count, char **files, int after, bool will_edit)
|
||||
{
|
||||
int old_argcount = ARGCOUNT;
|
||||
ga_grow(&ALIST(curwin)->al_ga, count);
|
||||
{
|
||||
if (check_arglist_locked() != FAIL) {
|
||||
if (after < 0) {
|
||||
after = 0;
|
||||
}
|
||||
@ -296,11 +338,13 @@ static void alist_add_list(int count, char **files, int after, bool will_edit)
|
||||
memmove(&(ARGLIST[after + count]), &(ARGLIST[after]),
|
||||
(size_t)(ARGCOUNT - after) * sizeof(aentry_T));
|
||||
}
|
||||
arglist_locked = true;
|
||||
for (int i = 0; i < count; i++) {
|
||||
const int flags = BLN_LISTED | (will_edit ? BLN_CURBUF : 0);
|
||||
ARGLIST[after + i].ae_fname = files[i];
|
||||
ARGLIST[after + i].ae_fnum = buflist_add(files[i], flags);
|
||||
}
|
||||
arglist_locked = false;
|
||||
ALIST(curwin)->al_ga.ga_len += count;
|
||||
if (old_argcount > 0 && curwin->w_arg_idx >= after) {
|
||||
curwin->w_arg_idx += count;
|
||||
@ -371,6 +415,10 @@ static int do_arglist(char *str, int what, int after, bool will_edit)
|
||||
char **exp_files;
|
||||
int arg_escaped = true;
|
||||
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
// Set default argument for ":argadd" command.
|
||||
if (what == AL_ADD && *str == NUL) {
|
||||
if (curbuf->b_ffname == NULL) {
|
||||
@ -461,6 +509,9 @@ void check_arg_idx(win_T *win)
|
||||
void ex_args(exarg_T *eap)
|
||||
{
|
||||
if (eap->cmdidx != CMD_args) {
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
alist_unlink(ALIST(curwin));
|
||||
if (eap->cmdidx == CMD_argglobal) {
|
||||
ALIST(curwin) = &global_alist;
|
||||
@ -469,15 +520,21 @@ void ex_args(exarg_T *eap)
|
||||
}
|
||||
}
|
||||
|
||||
// ":args file ..": define new argument list, handle like ":next"
|
||||
// Also for ":argslocal file .." and ":argsglobal file ..".
|
||||
if (*eap->arg != NUL) {
|
||||
// ":args file ..": define new argument list, handle like ":next"
|
||||
// Also for ":argslocal file .." and ":argsglobal file ..".
|
||||
ex_next(eap);
|
||||
} else if (eap->cmdidx == CMD_args) {
|
||||
// ":args": list arguments.
|
||||
if (ARGCOUNT <= 0) {
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
ex_next(eap);
|
||||
return;
|
||||
}
|
||||
|
||||
// ":args": list arguments.
|
||||
if (eap->cmdidx == CMD_args) {
|
||||
if (ARGCOUNT <= 0) {
|
||||
return; // empty argument list
|
||||
}
|
||||
|
||||
char **items = xmalloc(sizeof(char *) * (size_t)ARGCOUNT);
|
||||
|
||||
@ -490,10 +547,14 @@ void ex_args(exarg_T *eap)
|
||||
}
|
||||
list_in_columns(items, ARGCOUNT, curwin->w_arg_idx);
|
||||
xfree(items);
|
||||
} else if (eap->cmdidx == CMD_arglocal) {
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// ":argslocal": make a local copy of the global argument list.
|
||||
if (eap->cmdidx == CMD_arglocal) {
|
||||
garray_T *gap = &curwin->w_alist->al_ga;
|
||||
|
||||
// ":argslocal": make a local copy of the global argument list.
|
||||
ga_grow(gap, GARGCOUNT);
|
||||
|
||||
for (int i = 0; i < GARGCOUNT; i++) {
|
||||
@ -686,6 +747,10 @@ void ex_argadd(exarg_T *eap)
|
||||
/// ":argdelete"
|
||||
void ex_argdelete(exarg_T *eap)
|
||||
{
|
||||
if (check_arglist_locked() == FAIL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (eap->addr_count > 0 || *eap->arg == NUL) {
|
||||
// ":argdel" works like ":.argdel"
|
||||
if (eap->addr_count == 0) {
|
||||
@ -754,76 +819,32 @@ char *alist_name(aentry_T *aep)
|
||||
return bp->b_fname;
|
||||
}
|
||||
|
||||
/// do_arg_all(): Open up to 'count' windows, one for each argument.
|
||||
///
|
||||
/// @param forceit hide buffers in current windows
|
||||
/// @param keep_tabs keep current tabs, for ":tab drop file"
|
||||
static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
/// Close all the windows containing files which are not in the argument list.
|
||||
/// Used by the ":all" command.
|
||||
static void arg_all_close_unused_windows(arg_all_state_T *aall)
|
||||
{
|
||||
uint8_t *opened; // Array of weight for which args are open:
|
||||
// 0: not opened
|
||||
// 1: opened in other tab
|
||||
// 2: opened in curtab
|
||||
// 3: opened in curtab and curwin
|
||||
win_T *old_curwin = curwin;
|
||||
tabpage_T *old_curtab = curtab;
|
||||
|
||||
int opened_len; // length of opened[]
|
||||
int use_firstwin = false; // use first window for arglist
|
||||
bool tab_drop_empty_window = false;
|
||||
int split_ret = OK;
|
||||
bool p_ea_save;
|
||||
alist_T *alist; // argument list to be used
|
||||
buf_T *buf;
|
||||
tabpage_T *tpnext;
|
||||
int had_tab = cmdmod.cmod_tab;
|
||||
win_T *old_curwin, *last_curwin;
|
||||
tabpage_T *old_curtab, *last_curtab;
|
||||
win_T *new_curwin = NULL;
|
||||
tabpage_T *new_curtab = NULL;
|
||||
|
||||
assert(firstwin != NULL); // satisfy coverity
|
||||
|
||||
if (ARGCOUNT <= 0) {
|
||||
// Don't give an error message. We don't want it when the ":all" command is in the .vimrc.
|
||||
return;
|
||||
}
|
||||
setpcmark();
|
||||
|
||||
opened_len = ARGCOUNT;
|
||||
opened = xcalloc((size_t)opened_len, 1);
|
||||
|
||||
// Autocommands may do anything to the argument list. Make sure it's not
|
||||
// freed while we are working here by "locking" it. We still have to
|
||||
// watch out for its size to be changed.
|
||||
alist = curwin->w_alist;
|
||||
alist->al_refcount++;
|
||||
|
||||
old_curwin = curwin;
|
||||
old_curtab = curtab;
|
||||
|
||||
// Try closing all windows that are not in the argument list.
|
||||
// Also close windows that are not full width;
|
||||
// When 'hidden' or "forceit" set the buffer becomes hidden.
|
||||
// Windows that have a changed buffer and can't be hidden won't be closed.
|
||||
// When the ":tab" modifier was used do this for all tab pages.
|
||||
if (had_tab > 0) {
|
||||
if (aall->had_tab > 0) {
|
||||
goto_tabpage_tp(first_tabpage, true, true);
|
||||
}
|
||||
for (;;) {
|
||||
win_T *wpnext = NULL;
|
||||
tpnext = curtab->tp_next;
|
||||
tabpage_T *tpnext = curtab->tp_next;
|
||||
for (win_T *wp = firstwin; wp != NULL; wp = wpnext) {
|
||||
int i;
|
||||
wpnext = wp->w_next;
|
||||
buf = wp->w_buffer;
|
||||
buf_T *buf = wp->w_buffer;
|
||||
if (buf->b_ffname == NULL
|
||||
|| (!keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) {
|
||||
i = opened_len;
|
||||
|| (!aall->keep_tabs && (buf->b_nwindows > 1 || wp->w_width != Columns))) {
|
||||
i = aall->opened_len;
|
||||
} else {
|
||||
// check if the buffer in this window is in the arglist
|
||||
for (i = 0; i < opened_len; i++) {
|
||||
if (i < alist->al_ga.ga_len
|
||||
&& (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
|
||||
|| path_full_compare(alist_name(&AARGLIST(alist)[i]),
|
||||
for (i = 0; i < aall->opened_len; i++) {
|
||||
if (i < aall->alist->al_ga.ga_len
|
||||
&& (AARGLIST(aall->alist)[i].ae_fnum == buf->b_fnum
|
||||
|| path_full_compare(alist_name(&AARGLIST(aall->alist)[i]),
|
||||
buf->b_ffname,
|
||||
true, true) & kEqualFiles)) {
|
||||
int weight = 1;
|
||||
@ -835,23 +856,24 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
}
|
||||
|
||||
if (weight > (int)opened[i]) {
|
||||
opened[i] = (uint8_t)weight;
|
||||
if (weight > (int)aall->opened[i]) {
|
||||
aall->opened[i] = (uint8_t)weight;
|
||||
if (i == 0) {
|
||||
if (new_curwin != NULL) {
|
||||
new_curwin->w_arg_idx = opened_len;
|
||||
if (aall->new_curwin != NULL) {
|
||||
aall->new_curwin->w_arg_idx = aall->opened_len;
|
||||
}
|
||||
new_curwin = wp;
|
||||
new_curtab = curtab;
|
||||
aall->new_curwin = wp;
|
||||
aall->new_curtab = curtab;
|
||||
}
|
||||
} else if (keep_tabs) {
|
||||
i = opened_len;
|
||||
} else if (aall->keep_tabs) {
|
||||
i = aall->opened_len;
|
||||
}
|
||||
|
||||
if (wp->w_alist != alist) {
|
||||
// Use the current argument list for all windows containing a file from it.
|
||||
if (wp->w_alist != aall->alist) {
|
||||
// Use the current argument list for all windows
|
||||
// containing a file from it.
|
||||
alist_unlink(wp->w_alist);
|
||||
wp->w_alist = alist;
|
||||
wp->w_alist = aall->alist;
|
||||
wp->w_alist->al_refcount++;
|
||||
}
|
||||
break;
|
||||
@ -860,8 +882,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
wp->w_arg_idx = i;
|
||||
|
||||
if (i == opened_len && !keep_tabs) { // close this window
|
||||
if (buf_hide(buf) || forceit || buf->b_nwindows > 1
|
||||
if (i == aall->opened_len && !aall->keep_tabs) { // close this window
|
||||
if (buf_hide(buf) || aall->forceit || buf->b_nwindows > 1
|
||||
|| !bufIsChanged(buf)) {
|
||||
// If the buffer was changed, and we would like to hide it, try autowriting.
|
||||
if (!buf_hide(buf) && buf->b_nwindows <= 1 && bufIsChanged(buf)) {
|
||||
@ -876,8 +898,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
// don't close last window
|
||||
if (ONE_WINDOW
|
||||
&& (first_tabpage->tp_next == NULL || !had_tab)) {
|
||||
use_firstwin = true;
|
||||
&& (first_tabpage->tp_next == NULL || !aall->had_tab)) {
|
||||
aall->use_firstwin = true;
|
||||
} else {
|
||||
win_close(wp, !buf_hide(buf) && !bufIsChanged(buf), false);
|
||||
// check if autocommands removed the next window
|
||||
@ -891,7 +913,7 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
|
||||
// Without the ":tab" modifier only do the current tab page.
|
||||
if (had_tab == 0 || tpnext == NULL) {
|
||||
if (aall->had_tab == 0 || tpnext == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
@ -901,39 +923,35 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
goto_tabpage_tp(tpnext, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
// Open a window for files in the argument list that don't have one.
|
||||
// ARGCOUNT may change while doing this, because of autocommands.
|
||||
if (count > opened_len || count <= 0) {
|
||||
count = opened_len;
|
||||
}
|
||||
/// Open up to "count" windows for the files in the argument list "aall->alist".
|
||||
static void arg_all_open_windows(arg_all_state_T *aall, int count)
|
||||
{
|
||||
bool tab_drop_empty_window = false;
|
||||
|
||||
// Don't execute Win/Buf Enter/Leave autocommands here.
|
||||
autocmd_no_enter++;
|
||||
autocmd_no_leave++;
|
||||
last_curwin = curwin;
|
||||
last_curtab = curtab;
|
||||
win_enter(lastwin, false);
|
||||
// ":tab drop file" should re-use an empty window to avoid "--remote-tab"
|
||||
// leaving an empty tab page when executed locally.
|
||||
if (keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1
|
||||
if (aall->keep_tabs && buf_is_empty(curbuf) && curbuf->b_nwindows == 1
|
||||
&& curbuf->b_ffname == NULL && !curbuf->b_changed) {
|
||||
use_firstwin = true;
|
||||
aall->use_firstwin = true;
|
||||
tab_drop_empty_window = true;
|
||||
}
|
||||
|
||||
int split_ret = OK;
|
||||
|
||||
for (int i = 0; i < count && !got_int; i++) {
|
||||
if (alist == &global_alist && i == global_alist.al_ga.ga_len - 1) {
|
||||
if (aall->alist == &global_alist && i == global_alist.al_ga.ga_len - 1) {
|
||||
arg_had_last = true;
|
||||
}
|
||||
if (opened[i] > 0) {
|
||||
if (aall->opened[i] > 0) {
|
||||
// Move the already present window to below the current window
|
||||
if (curwin->w_arg_idx != i) {
|
||||
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
|
||||
if (wp->w_arg_idx == i) {
|
||||
if (keep_tabs) {
|
||||
new_curwin = wp;
|
||||
new_curtab = curtab;
|
||||
if (aall->keep_tabs) {
|
||||
aall->new_curwin = wp;
|
||||
aall->new_curtab = curtab;
|
||||
} else if (wp->w_frame->fr_parent != curwin->w_frame->fr_parent) {
|
||||
emsg(_("E249: window layout changed unexpectedly"));
|
||||
i = count;
|
||||
@ -950,8 +968,8 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
if (tab_drop_empty_window && i == count - 1) {
|
||||
autocmd_no_enter--;
|
||||
}
|
||||
if (!use_firstwin) { // split current window
|
||||
p_ea_save = p_ea;
|
||||
if (!aall->use_firstwin) { // split current window
|
||||
bool p_ea_save = p_ea;
|
||||
p_ea = true; // use space from all windows
|
||||
split_ret = win_split(0, WSP_ROOM | WSP_BELOW);
|
||||
p_ea = p_ea_save;
|
||||
@ -965,36 +983,101 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
// edit file "i"
|
||||
curwin->w_arg_idx = i;
|
||||
if (i == 0) {
|
||||
new_curwin = curwin;
|
||||
new_curtab = curtab;
|
||||
aall->new_curwin = curwin;
|
||||
aall->new_curtab = curtab;
|
||||
}
|
||||
(void)do_ecmd(0, alist_name(&AARGLIST(alist)[i]), NULL, NULL, ECMD_ONE,
|
||||
(void)do_ecmd(0, alist_name(&AARGLIST(aall->alist)[i]), NULL, NULL, ECMD_ONE,
|
||||
((buf_hide(curwin->w_buffer)
|
||||
|| bufIsChanged(curwin->w_buffer))
|
||||
? ECMD_HIDE : 0) + ECMD_OLDBUF,
|
||||
|| bufIsChanged(curwin->w_buffer)) ? ECMD_HIDE : 0) + ECMD_OLDBUF,
|
||||
curwin);
|
||||
if (tab_drop_empty_window && i == count - 1) {
|
||||
autocmd_no_enter++;
|
||||
}
|
||||
if (use_firstwin) {
|
||||
if (aall->use_firstwin) {
|
||||
autocmd_no_leave++;
|
||||
}
|
||||
use_firstwin = false;
|
||||
aall->use_firstwin = false;
|
||||
}
|
||||
os_breakcheck();
|
||||
|
||||
// When ":tab" was used open a new tab for a new window repeatedly.
|
||||
if (had_tab > 0 && tabpage_index(NULL) <= p_tpm) {
|
||||
if (aall->had_tab > 0 && tabpage_index(NULL) <= p_tpm) {
|
||||
cmdmod.cmod_tab = 9999;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// do_arg_all(): Open up to 'count' windows, one for each argument.
|
||||
///
|
||||
/// @param forceit hide buffers in current windows
|
||||
/// @param keep_tabs keep current tabs, for ":tab drop file"
|
||||
static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
{
|
||||
win_T *last_curwin;
|
||||
tabpage_T *last_curtab;
|
||||
bool prev_arglist_locked = arglist_locked;
|
||||
|
||||
assert(firstwin != NULL); // satisfy coverity
|
||||
|
||||
if (cmdwin_type != 0) {
|
||||
emsg(_(e_cmdwin));
|
||||
return;
|
||||
}
|
||||
if (ARGCOUNT <= 0) {
|
||||
// Don't give an error message. We don't want it when the ":all" command is in the .vimrc.
|
||||
return;
|
||||
}
|
||||
setpcmark();
|
||||
|
||||
arg_all_state_T aall = {
|
||||
.use_firstwin = false,
|
||||
.had_tab = cmdmod.cmod_tab,
|
||||
.new_curwin = NULL,
|
||||
.new_curtab = NULL,
|
||||
.forceit = forceit,
|
||||
.keep_tabs = keep_tabs,
|
||||
.opened_len = ARGCOUNT,
|
||||
.opened = xcalloc((size_t)ARGCOUNT, 1),
|
||||
};
|
||||
|
||||
// Autocommands may do anything to the argument list. Make sure it's not
|
||||
// freed while we are working here by "locking" it. We still have to
|
||||
// watch out for its size to be changed.
|
||||
aall.alist = curwin->w_alist;
|
||||
aall.alist->al_refcount++;
|
||||
arglist_locked = true;
|
||||
|
||||
// Try closing all windows that are not in the argument list.
|
||||
// Also close windows that are not full width;
|
||||
// When 'hidden' or "forceit" set the buffer becomes hidden.
|
||||
// Windows that have a changed buffer and can't be hidden won't be closed.
|
||||
// When the ":tab" modifier was used do this for all tab pages.
|
||||
arg_all_close_unused_windows(&aall);
|
||||
|
||||
// Open a window for files in the argument list that don't have one.
|
||||
// ARGCOUNT may change while doing this, because of autocommands.
|
||||
if (count > aall.opened_len || count <= 0) {
|
||||
count = aall.opened_len;
|
||||
}
|
||||
|
||||
// Don't execute Win/Buf Enter/Leave autocommands here.
|
||||
autocmd_no_enter++;
|
||||
autocmd_no_leave++;
|
||||
last_curwin = curwin;
|
||||
last_curtab = curtab;
|
||||
win_enter(lastwin, false);
|
||||
|
||||
// Open upto "count" windows.
|
||||
arg_all_open_windows(&aall, count);
|
||||
|
||||
// Remove the "lock" on the argument list.
|
||||
alist_unlink(alist);
|
||||
alist_unlink(aall.alist);
|
||||
arglist_locked = prev_arglist_locked;
|
||||
|
||||
autocmd_no_enter--;
|
||||
|
||||
// restore last referenced tabpage's curwin
|
||||
if (last_curtab != new_curtab) {
|
||||
if (last_curtab != aall.new_curtab) {
|
||||
if (valid_tabpage(last_curtab)) {
|
||||
goto_tabpage_tp(last_curtab, true, true);
|
||||
}
|
||||
@ -1003,15 +1086,15 @@ static void do_arg_all(int count, int forceit, int keep_tabs)
|
||||
}
|
||||
}
|
||||
// to window with first arg
|
||||
if (valid_tabpage(new_curtab)) {
|
||||
goto_tabpage_tp(new_curtab, true, true);
|
||||
if (valid_tabpage(aall.new_curtab)) {
|
||||
goto_tabpage_tp(aall.new_curtab, true, true);
|
||||
}
|
||||
if (win_valid(new_curwin)) {
|
||||
win_enter(new_curwin, false);
|
||||
if (win_valid(aall.new_curwin)) {
|
||||
win_enter(aall.new_curwin, false);
|
||||
}
|
||||
|
||||
autocmd_no_leave--;
|
||||
xfree(opened);
|
||||
xfree(aall.opened);
|
||||
}
|
||||
|
||||
/// ":all" and ":sall".
|
||||
|
@ -881,7 +881,7 @@ void do_autocmd(char *arg_in, int forceit)
|
||||
}
|
||||
} else {
|
||||
if (*arg == '*' || *arg == NUL || *arg == '|') {
|
||||
if (!forceit && *cmd != NUL) {
|
||||
if (*cmd != NUL) {
|
||||
emsg(_(e_cannot_define_autocommands_for_all_events));
|
||||
} else {
|
||||
do_all_autocmd_events(pat, once, nested, cmd, forceit, group);
|
||||
|
@ -509,18 +509,14 @@ func Test_arglist_autocmd()
|
||||
new
|
||||
" redefine arglist; go to Xxx1
|
||||
next! Xxx1 Xxx2 Xxx3
|
||||
" open window for all args; Reading Xxx2 will change the arglist and the
|
||||
" third window will get Xxx1:
|
||||
" win 1: Xxx1
|
||||
" win 2: Xxx2
|
||||
" win 3: Xxx1
|
||||
all
|
||||
" open window for all args; Reading Xxx2 will try to change the arglist and
|
||||
" that will fail
|
||||
call assert_fails("all", "E1156:")
|
||||
call assert_equal('test file Xxx1', getline(1))
|
||||
wincmd w
|
||||
wincmd w
|
||||
call assert_equal('test file Xxx1', getline(1))
|
||||
rewind
|
||||
call assert_equal('test file Xxx2', getline(1))
|
||||
wincmd w
|
||||
call assert_equal('test file Xxx3', getline(1))
|
||||
|
||||
autocmd! BufReadPost Xxx2
|
||||
enew! | only
|
||||
@ -591,4 +587,27 @@ func Test_quit_with_arglist()
|
||||
call delete('.c.swp')
|
||||
endfunc
|
||||
|
||||
" Test for ":all" not working when in the cmdline window
|
||||
func Test_all_not_allowed_from_cmdwin()
|
||||
au BufEnter * all
|
||||
next x
|
||||
" Use try/catch here, somehow assert_fails() doesn't work on MS-Windows
|
||||
" console.
|
||||
let caught = 'no'
|
||||
try
|
||||
exe ":norm! 7q?apat\<CR>"
|
||||
catch /E11:/
|
||||
let caught = 'yes'
|
||||
endtry
|
||||
call assert_equal('yes', caught)
|
||||
au! BufEnter
|
||||
endfunc
|
||||
|
||||
func Test_clear_arglist_in_all()
|
||||
n 0 00 000 0000 00000 000000
|
||||
au WinNew 0 n 0
|
||||
call assert_fails("all", "E1156")
|
||||
au! *
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
@ -148,6 +148,12 @@ func Test_autocmd_bufunload_with_tabnext()
|
||||
quit
|
||||
endfunc
|
||||
|
||||
func Test_argdelete_in_next()
|
||||
au BufNew,BufEnter,BufLeave,BufWinEnter * argdel
|
||||
call assert_fails('next a b', 'E1156:')
|
||||
au! BufNew,BufEnter,BufLeave,BufWinEnter *
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_bufwinleave_with_tabfirst()
|
||||
tabedit
|
||||
augroup sample
|
||||
@ -2048,6 +2054,7 @@ endfunc
|
||||
func Test_autocommand_all_events()
|
||||
call assert_fails('au * * bwipe', 'E1155:')
|
||||
call assert_fails('au * x bwipe', 'E1155:')
|
||||
call assert_fails('au! * x bwipe', 'E1155:')
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_user()
|
||||
@ -3004,6 +3011,15 @@ func Test_Visual_doautoall_redraw()
|
||||
%bwipe!
|
||||
endfunc
|
||||
|
||||
" This was using freed memory.
|
||||
func Test_BufNew_arglocal()
|
||||
arglocal
|
||||
au BufNew * arglocal
|
||||
call assert_fails('drop xx', 'E1156:')
|
||||
|
||||
au! BufNew
|
||||
endfunc
|
||||
|
||||
func Test_autocmd_closes_window()
|
||||
au BufNew,BufWinLeave * e %e
|
||||
file yyy
|
||||
|
@ -1,85 +0,0 @@
|
||||
-- Test for autocommand that redefines the argument list, when doing ":all".
|
||||
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local clear, feed, insert = helpers.clear, helpers.feed, helpers.insert
|
||||
local command, dedent, eq = helpers.command, helpers.dedent, helpers.eq
|
||||
local curbuf_contents = helpers.curbuf_contents
|
||||
local poke_eventloop = helpers.poke_eventloop
|
||||
|
||||
describe('argument list', function()
|
||||
setup(clear)
|
||||
|
||||
it('is working', function()
|
||||
insert([[
|
||||
start of test file Xxx
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
end of test file Xxx]])
|
||||
poke_eventloop()
|
||||
|
||||
command('au BufReadPost Xxx2 next Xxx2 Xxx1')
|
||||
command('/^start of')
|
||||
|
||||
-- Write test file Xxx1
|
||||
feed('A1<Esc>:.,/end of/w! Xxx1<cr>')
|
||||
|
||||
-- Write test file Xxx2
|
||||
feed('$r2:.,/end of/w! Xxx2<cr>')
|
||||
|
||||
-- Write test file Xxx3
|
||||
feed('$r3:.,/end of/w! Xxx3<cr>')
|
||||
poke_eventloop()
|
||||
|
||||
-- Redefine arglist; go to Xxx1
|
||||
command('next! Xxx1 Xxx2 Xxx3')
|
||||
|
||||
-- Open window for all args
|
||||
command('all')
|
||||
|
||||
-- Write contents of Xxx1
|
||||
command('%yank A')
|
||||
|
||||
-- Append contents of last window (Xxx1)
|
||||
feed('')
|
||||
poke_eventloop()
|
||||
command('%yank A')
|
||||
|
||||
-- should now be in Xxx2
|
||||
command('rew')
|
||||
|
||||
-- Append contents of Xxx2
|
||||
command('%yank A')
|
||||
|
||||
command('%d')
|
||||
command('0put=@a')
|
||||
command('$d')
|
||||
|
||||
eq(dedent([[
|
||||
start of test file Xxx1
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
end of test file Xxx
|
||||
start of test file Xxx1
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
end of test file Xxx
|
||||
start of test file Xxx2
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
this is a test
|
||||
end of test file Xxx]]), curbuf_contents())
|
||||
end)
|
||||
|
||||
teardown(function()
|
||||
os.remove('Xxx1')
|
||||
os.remove('Xxx2')
|
||||
os.remove('Xxx3')
|
||||
end)
|
||||
end)
|
@ -3,7 +3,6 @@
|
||||
local helpers = require('test.functional.helpers')(after_each)
|
||||
local Screen = require('test.functional.ui.screen')
|
||||
local clear, command, eq = helpers.clear, helpers.command, helpers.eq
|
||||
local eval, exc_exec, neq = helpers.eval, helpers.exc_exec, helpers.neq
|
||||
local expect_exit = helpers.expect_exit
|
||||
local feed = helpers.feed
|
||||
local pcall_err = helpers.pcall_err
|
||||
@ -11,233 +10,6 @@ local pcall_err = helpers.pcall_err
|
||||
describe('argument list commands', function()
|
||||
before_each(clear)
|
||||
|
||||
local function init_abc()
|
||||
command('args a b c')
|
||||
command('next')
|
||||
end
|
||||
|
||||
local function reset_arglist()
|
||||
command('arga a | %argd')
|
||||
end
|
||||
|
||||
local function assert_fails(cmd, err)
|
||||
neq(nil, exc_exec(cmd):find(err))
|
||||
end
|
||||
|
||||
it('test that argidx() works', function()
|
||||
command('args a b c')
|
||||
command('last')
|
||||
eq(2, eval('argidx()'))
|
||||
command('%argdelete')
|
||||
eq(0, eval('argidx()'))
|
||||
|
||||
command('args a b c')
|
||||
eq(0, eval('argidx()'))
|
||||
command('next')
|
||||
eq(1, eval('argidx()'))
|
||||
command('next')
|
||||
eq(2, eval('argidx()'))
|
||||
command('1argdelete')
|
||||
eq(1, eval('argidx()'))
|
||||
command('1argdelete')
|
||||
eq(0, eval('argidx()'))
|
||||
command('1argdelete')
|
||||
eq(0, eval('argidx()'))
|
||||
end)
|
||||
|
||||
it('test that argadd() works', function()
|
||||
command('%argdelete')
|
||||
command('argadd a b c')
|
||||
eq(0, eval('argidx()'))
|
||||
|
||||
command('%argdelete')
|
||||
command('argadd a')
|
||||
eq(0, eval('argidx()'))
|
||||
command('argadd b c d')
|
||||
eq(0, eval('argidx()'))
|
||||
|
||||
init_abc()
|
||||
command('argadd x')
|
||||
eq({'a', 'b', 'x', 'c'}, eval('argv()'))
|
||||
eq(1, eval('argidx()'))
|
||||
|
||||
init_abc()
|
||||
command('0argadd x')
|
||||
eq({'x', 'a', 'b', 'c'}, eval('argv()'))
|
||||
eq(2, eval('argidx()'))
|
||||
|
||||
init_abc()
|
||||
command('1argadd x')
|
||||
eq({'a', 'x', 'b', 'c'}, eval('argv()'))
|
||||
eq(2, eval('argidx()'))
|
||||
|
||||
init_abc()
|
||||
command('$argadd x')
|
||||
eq({'a', 'b', 'c', 'x'}, eval('argv()'))
|
||||
eq(1, eval('argidx()'))
|
||||
|
||||
init_abc()
|
||||
command('$argadd x')
|
||||
command('+2argadd y')
|
||||
eq({'a', 'b', 'c', 'x', 'y'}, eval('argv()'))
|
||||
eq(1, eval('argidx()'))
|
||||
|
||||
command('%argd')
|
||||
command('edit d')
|
||||
command('arga')
|
||||
eq(1, eval('len(argv())'))
|
||||
eq('d', eval('get(argv(), 0, "")'))
|
||||
|
||||
command('%argd')
|
||||
command('new')
|
||||
command('arga')
|
||||
eq(0, eval('len(argv())'))
|
||||
end)
|
||||
|
||||
it('test for 0argadd and 0argedit', function()
|
||||
reset_arglist()
|
||||
|
||||
command('arga a b c d')
|
||||
command('2argu')
|
||||
command('0arga added')
|
||||
eq({'added', 'a', 'b', 'c', 'd'}, eval('argv()'))
|
||||
|
||||
command('%argd')
|
||||
command('arga a b c d')
|
||||
command('2argu')
|
||||
command('0arge edited')
|
||||
eq({'edited', 'a', 'b', 'c', 'd'}, eval('argv()'))
|
||||
|
||||
command('2argu')
|
||||
command('arga third')
|
||||
eq({'edited', 'a', 'third', 'b', 'c', 'd'}, eval('argv()'))
|
||||
end)
|
||||
|
||||
it('test for argc()', function()
|
||||
reset_arglist()
|
||||
eq(0, eval('argc()'))
|
||||
command('argadd a b')
|
||||
eq(2, eval('argc()'))
|
||||
end)
|
||||
|
||||
it('test for arglistid()', function()
|
||||
reset_arglist()
|
||||
command('arga a b')
|
||||
eq(0, eval('arglistid()'))
|
||||
command('split')
|
||||
command('arglocal')
|
||||
eq(1, eval('arglistid()'))
|
||||
command('tabnew | tabfirst')
|
||||
eq(0, eval('arglistid(2)'))
|
||||
eq(1, eval('arglistid(1, 1)'))
|
||||
eq(0, eval('arglistid(2, 1)'))
|
||||
eq(1, eval('arglistid(1, 2)'))
|
||||
command('tabonly | only | enew!')
|
||||
command('argglobal')
|
||||
eq(0, eval('arglistid()'))
|
||||
end)
|
||||
|
||||
it('test for argv()', function()
|
||||
reset_arglist()
|
||||
eq({}, eval('argv()'))
|
||||
eq('', eval('argv(2)'))
|
||||
command('argadd a b c d')
|
||||
eq('c', eval('argv(2)'))
|
||||
end)
|
||||
|
||||
it('test for :argedit command', function()
|
||||
reset_arglist()
|
||||
command('argedit a')
|
||||
eq({'a'}, eval('argv()'))
|
||||
eq('a', eval('expand("%:t")'))
|
||||
command('argedit b')
|
||||
eq({'a', 'b'}, eval('argv()'))
|
||||
eq('b', eval('expand("%:t")'))
|
||||
command('argedit a')
|
||||
eq({'a', 'b', 'a'}, eval('argv()'))
|
||||
eq('a', eval('expand("%:t")'))
|
||||
command('argedit c')
|
||||
eq({'a', 'b', 'a', 'c'}, eval('argv()'))
|
||||
command('0argedit x')
|
||||
eq({'x', 'a', 'b', 'a', 'c'}, eval('argv()'))
|
||||
command('set nohidden')
|
||||
command('enew! | set modified')
|
||||
assert_fails('argedit y', 'E37:')
|
||||
command('argedit! y')
|
||||
eq({'x', 'y', 'y', 'a', 'b', 'a', 'c'}, eval('argv()'))
|
||||
command('set hidden')
|
||||
command('%argd')
|
||||
command('argedit a b')
|
||||
eq({'a', 'b'}, eval('argv()'))
|
||||
end)
|
||||
|
||||
it('test for :argdelete command', function()
|
||||
reset_arglist()
|
||||
command('args aa a aaa b bb')
|
||||
command('argdelete a*')
|
||||
eq({'b', 'bb'}, eval('argv()'))
|
||||
eq('aa', eval('expand("%:t")'))
|
||||
command('last')
|
||||
command('argdelete %')
|
||||
eq({'b'}, eval('argv()'))
|
||||
assert_fails('argdelete', 'E610:')
|
||||
assert_fails('1,100argdelete', 'E16:')
|
||||
reset_arglist()
|
||||
command('args a b c d')
|
||||
command('next')
|
||||
command('argdel')
|
||||
eq({'a', 'c', 'd'}, eval('argv()'))
|
||||
command('%argdel')
|
||||
end)
|
||||
|
||||
it('test for the :next, :prev, :first, :last, :rewind commands', function()
|
||||
reset_arglist()
|
||||
command('args a b c d')
|
||||
command('last')
|
||||
eq(3, eval('argidx()'))
|
||||
assert_fails('next', 'E165:')
|
||||
command('prev')
|
||||
eq(2, eval('argidx()'))
|
||||
command('Next')
|
||||
eq(1, eval('argidx()'))
|
||||
command('first')
|
||||
eq(0, eval('argidx()'))
|
||||
assert_fails('prev', 'E164:')
|
||||
command('3next')
|
||||
eq(3, eval('argidx()'))
|
||||
command('rewind')
|
||||
eq(0, eval('argidx()'))
|
||||
command('%argd')
|
||||
end)
|
||||
|
||||
it('test for autocommand that redefines the argument list, when doing ":all"', function()
|
||||
command('autocmd BufReadPost Xxx2 next Xxx2 Xxx1')
|
||||
command("call writefile(['test file Xxx1'], 'Xxx1')")
|
||||
command("call writefile(['test file Xxx2'], 'Xxx2')")
|
||||
command("call writefile(['test file Xxx3'], 'Xxx3')")
|
||||
|
||||
command('new')
|
||||
-- redefine arglist; go to Xxx1
|
||||
command('next! Xxx1 Xxx2 Xxx3')
|
||||
-- open window for all args
|
||||
command('all')
|
||||
eq('test file Xxx1', eval('getline(1)'))
|
||||
command('wincmd w')
|
||||
command('wincmd w')
|
||||
eq('test file Xxx1', eval('getline(1)'))
|
||||
-- should now be in Xxx2
|
||||
command('rewind')
|
||||
eq('test file Xxx2', eval('getline(1)'))
|
||||
|
||||
command('autocmd! BufReadPost Xxx2')
|
||||
command('enew! | only')
|
||||
command("call delete('Xxx1')")
|
||||
command("call delete('Xxx2')")
|
||||
command("call delete('Xxx3')")
|
||||
command('argdelete Xxx*')
|
||||
command('bwipe! Xxx1 Xxx2 Xxx3')
|
||||
end)
|
||||
|
||||
it('quitting Vim with unedited files in the argument list throws E173', function()
|
||||
command('set nomore')
|
||||
command('args a b c')
|
||||
|
Loading…
Reference in New Issue
Block a user