Merge #5918 'vim-patch: 7.4.2006, 7.4.2075, 7.4.2077, 7.4.2117, 7.4.2300, 7.4.2313, 7.4.2314'.

This commit is contained in:
Justin M. Keyes 2017-01-16 00:59:50 +01:00
commit 3ba5e43d2e
8 changed files with 224 additions and 47 deletions

View File

@ -294,6 +294,7 @@ Name triggered by ~
|CursorMoved| the cursor was moved in Normal mode
|CursorMovedI| the cursor was moved in Insert mode
|WinNew| after creating a new window
|WinEnter| after entering another window
|WinLeave| before leaving a window
|TabEnter| after entering another tab page
@ -992,6 +993,11 @@ WinLeave Before leaving a window. If the window to be
WinLeave autocommands (but not for ":new").
Not used for ":qa" or ":q" when exiting Vim.
*WinNew*
WinNew When a new window was created. Not done for
the fist window, when Vim has just started.
Before a WinEnter event.
==============================================================================
6. Patterns *autocmd-patterns* *{pat}*

View File

@ -89,6 +89,7 @@ return {
'VimLeave', -- before exiting Vim
'VimLeavePre', -- before exiting Vim and writing ShaDa file
'VimResized', -- after Vim window was resized
'WinNew', -- when entering a new window
'WinEnter', -- after entering a window
'WinLeave', -- before leaving a window
},

View File

@ -409,9 +409,6 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
buf->b_nwindows = nwindows;
buf_freeall(buf, (del_buf ? BFA_DEL : 0) + (wipe_buf ? BFA_WIPE : 0));
if (win_valid_any_tab(win) && win->w_buffer == buf) {
win->w_buffer = NULL; // make sure we don't use the buffer now
}
/* Autocommands may have deleted the buffer. */
if (!buf_valid(buf))
@ -419,11 +416,6 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
if (aborting()) /* autocmds may abort script processing */
return;
/* Autocommands may have opened or closed windows for this buffer.
* Decrement the count for the close we do here. */
if (buf->b_nwindows > 0)
--buf->b_nwindows;
/*
* It's possible that autocommands change curbuf to the one being deleted.
* This might cause the previous curbuf to be deleted unexpectedly. But
@ -434,6 +426,16 @@ void close_buffer(win_T *win, buf_T *buf, int action, int abort_if_last)
if (buf == curbuf && !is_curbuf)
return;
if (win_valid_any_tab(win) && win->w_buffer == buf) {
win->w_buffer = NULL; // make sure we don't use the buffer now
}
// Autocommands may have opened or closed windows for this buffer.
// Decrement the count for the close we do here.
if (buf->b_nwindows > 0) {
buf->b_nwindows--;
}
/* Change directories when the 'acd' option is set. */
do_autochdir();

View File

@ -5373,6 +5373,8 @@ static AutoPatCmd *active_apc_list = NULL; /* stack of active autocommands */
*/
static garray_T augroups = {0, 0, sizeof(char_u *), 10, NULL};
#define AUGROUP_NAME(i) (((char_u **)augroups.ga_data)[i])
// use get_deleted_augroup() to get this
static char_u *deleted_augroup = NULL;
/*
* The ID of the current group. Group 0 is the default one.
@ -5387,6 +5389,14 @@ static event_T last_event;
static int last_group;
static int autocmd_blocked = 0; /* block all autocmds */
static char_u *get_deleted_augroup(void)
{
if (deleted_augroup == NULL) {
deleted_augroup = (char_u *)_("--Deleted--");
}
return deleted_augroup;
}
/*
* Show the autocommands for one AutoPat.
*/
@ -5406,10 +5416,11 @@ static void show_autocmd(AutoPat *ap, event_T event)
return;
if (event != last_event || ap->group != last_group) {
if (ap->group != AUGROUP_DEFAULT) {
if (AUGROUP_NAME(ap->group) == NULL)
msg_puts_attr((char_u *)_("--Deleted--"), hl_attr(HLF_E));
else
if (AUGROUP_NAME(ap->group) == NULL) {
msg_puts_attr(get_deleted_augroup(), hl_attr(HLF_E));
} else {
msg_puts_attr(AUGROUP_NAME(ap->group), hl_attr(HLF_T));
}
msg_puts((char_u *)" ");
}
msg_puts_attr(event_nr2name(event), hl_attr(HLF_T));
@ -5575,11 +5586,33 @@ static void au_del_group(char_u *name)
int i;
i = au_find_group(name);
if (i == AUGROUP_ERROR) /* the group doesn't exist */
if (i == AUGROUP_ERROR) { // the group doesn't exist
EMSG2(_("E367: No such group: \"%s\""), name);
else {
} else if (i == current_augroup) {
EMSG(_("E936: Cannot delete the current group"));
} else {
event_T event;
AutoPat *ap;
int in_use = false;
for (event = (event_T)0; (int)event < (int)NUM_EVENTS;
event = (event_T)((int)event + 1)) {
for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) {
if (ap->group == i && ap->pat != NULL) {
give_warning((char_u *)
_("W19: Deleting augroup that is still in use"), true);
in_use = true;
event = NUM_EVENTS;
break;
}
}
}
xfree(AUGROUP_NAME(i));
AUGROUP_NAME(i) = NULL;
if (in_use) {
AUGROUP_NAME(i) = get_deleted_augroup();
} else {
AUGROUP_NAME(i) = NULL;
}
}
}
@ -5591,8 +5624,9 @@ static void au_del_group(char_u *name)
static int au_find_group(const char_u *name)
FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
{
for (int i = 0; i < augroups.ga_len; ++i) {
if (AUGROUP_NAME(i) != NULL && STRCMP(AUGROUP_NAME(i), name) == 0) {
for (int i = 0; i < augroups.ga_len; i++) {
if (AUGROUP_NAME(i) != NULL && AUGROUP_NAME(i) != get_deleted_augroup()
&& STRCMP(AUGROUP_NAME(i), name) == 0) {
return i;
}
}
@ -5640,10 +5674,21 @@ void do_augroup(char_u *arg, int del_group)
#if defined(EXITFREE)
void free_all_autocmds(void)
{
int i;
char_u *s;
for (current_augroup = -1; current_augroup < augroups.ga_len;
++current_augroup)
do_autocmd((char_u *)"", TRUE);
ga_clear_strings(&augroups);
current_augroup++) {
do_autocmd((char_u *)"", true);
}
for (i = 0; i < augroups.ga_len; i++) {
s = ((char_u **)(augroups.ga_data))[i];
if (s != get_deleted_augroup()) {
xfree(s);
}
}
ga_clear(&augroups);
}
#endif
@ -7105,9 +7150,11 @@ char_u *get_augroup_name(expand_T *xp, int idx)
return (char_u *)"END";
if (idx >= augroups.ga_len) /* end of list */
return NULL;
if (AUGROUP_NAME(idx) == NULL) /* skip deleted entries */
if (AUGROUP_NAME(idx) == NULL || AUGROUP_NAME(idx) == get_deleted_augroup()) {
// skip deleted entries
return (char_u *)"";
return AUGROUP_NAME(idx); /* return a name */
}
return AUGROUP_NAME(idx); // return a name
}
static int include_groups = FALSE;
@ -7164,10 +7211,12 @@ set_context_in_autocmd (
*/
char_u *get_event_name(expand_T *xp, int idx)
{
if (idx < augroups.ga_len) { /* First list group names, if wanted */
if (!include_groups || AUGROUP_NAME(idx) == NULL)
return (char_u *)""; /* skip deleted entries */
return AUGROUP_NAME(idx); /* return a name */
if (idx < augroups.ga_len) { // First list group names, if wanted
if (!include_groups || AUGROUP_NAME(idx) == NULL
|| AUGROUP_NAME(idx) == get_deleted_augroup()) {
return (char_u *)""; // skip deleted entries
}
return AUGROUP_NAME(idx); // return a name
}
return (char_u *)event_names[idx - augroups.ga_len].name;
}

View File

@ -64,6 +64,66 @@ function Test_bufunload()
augroup! test_bufunload_group
endfunc
" SEGV occurs in older versions. (At least 7.4.2005 or older)
function Test_autocmd_bufunload_with_tabnext()
tabedit
tabfirst
augroup test_autocmd_bufunload_with_tabnext_group
autocmd!
autocmd BufUnload <buffer> tabnext
augroup END
quit
call assert_equal(2, tabpagenr('$'))
augroup! test_autocmd_bufunload_with_tabnext_group
tablast
quit
endfunc
func Test_win_tab_autocmd()
let g:record = []
augroup testing
au WinNew * call add(g:record, 'WinNew')
au WinEnter * call add(g:record, 'WinEnter')
au WinLeave * call add(g:record, 'WinLeave')
au TabNew * call add(g:record, 'TabNew')
au TabClosed * call add(g:record, 'TabClosed')
au TabEnter * call add(g:record, 'TabEnter')
au TabLeave * call add(g:record, 'TabLeave')
augroup END
split
tabnew
close
close
call assert_equal([
\ 'WinLeave', 'WinNew', 'WinEnter',
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'TabClosed', 'WinEnter', 'TabEnter',
\ 'WinLeave', 'WinEnter'
\ ], g:record)
let g:record = []
tabnew somefile
tabnext
bwipe somefile
call assert_equal([
\ 'WinLeave', 'TabLeave', 'WinNew', 'WinEnter', 'TabNew', 'TabEnter',
\ 'WinLeave', 'TabLeave', 'WinEnter', 'TabEnter',
\ 'TabClosed'
\ ], g:record)
augroup testing
au!
augroup END
unlet g:record
endfunc
func s:AddAnAutocmd()
augroup vimBarTest
au BufReadCmd * echo 'hello'
@ -91,3 +151,48 @@ func Test_early_bar()
au! vimBarTest|echo 'hello'
call assert_equal(1, len(split(execute('au vimBarTest'), "\n")))
endfunc
func RemoveGroup()
autocmd! StartOK
augroup! StartOK
endfunc
func Test_augroup_warning()
augroup TheWarning
au VimEnter * echo 'entering'
augroup END
call assert_true(match(execute('au VimEnter'), "TheWarning.*VimEnter") >= 0)
redir => res
augroup! TheWarning
redir END
call assert_true(match(res, "W19:") >= 0)
call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
" check "Another" does not take the pace of the deleted entry
augroup Another
augroup END
call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
" no warning for postpone aucmd delete
augroup StartOK
au VimEnter * call RemoveGroup()
augroup END
call assert_true(match(execute('au VimEnter'), "StartOK.*VimEnter") >= 0)
redir => res
doautocmd VimEnter
redir END
call assert_true(match(res, "W19:") < 0)
au! VimEnter
endfunc
func Test_augroup_deleted()
" This caused a crash before E936 was introduced
augroup x
call assert_fails('augroup! x', 'E936:')
au VimEnter * echo
augroup end
augroup! x
call assert_true(match(execute('au VimEnter'), "-Deleted-.*VimEnter") >= 0)
au! VimEnter
endfunc

View File

@ -126,8 +126,8 @@ static int included_patches[] = {
// 2317,
// 2316 NA
// 2315,
// 2314,
// 2313,
2314,
2313,
2312,
// 2311 NA
// 2310 NA
@ -140,7 +140,7 @@ static int included_patches[] = {
// 2303,
// 2302 NA
// 2301 NA
// 2300,
2300,
// 2299,
// 2298 NA
// 2297 NA
@ -323,7 +323,7 @@ static int included_patches[] = {
// 2120,
// 2119,
// 2118 NA
// 2117,
2117,
// 2116 NA
// 2115 NA
// 2114 NA
@ -363,9 +363,9 @@ static int included_patches[] = {
// 2080,
// 2079 NA
// 2078 NA
// 2077,
2077,
// 2076,
// 2075,
2075,
// 2074,
// 2073 NA
// 2072,
@ -434,7 +434,7 @@ static int included_patches[] = {
2009,
2008,
2007,
// 2006,
2006,
2005,
// 2004 NA
// 2003 NA

View File

@ -973,11 +973,12 @@ int win_split_ins(int size, int flags, win_T *new_wp, int dir)
/*
* make the new window the current window
*/
win_enter(wp, false);
if (flags & WSP_VERT)
win_enter_ext(wp, false, false, true, true, true);
if (flags & WSP_VERT) {
p_wiw = i;
else
} else {
p_wh = i;
}
return OK;
}
@ -1718,6 +1719,7 @@ close_windows (
{
tabpage_T *tp, *nexttp;
int h = tabline_height();
int count = tabpage_index(NULL);
++RedrawingDisabled;
@ -1754,9 +1756,14 @@ close_windows (
--RedrawingDisabled;
redraw_tabline = TRUE;
if (h != tabline_height())
if (count != tabpage_index(NULL)) {
apply_autocmds(EVENT_TABCLOSED, NULL, NULL, false, curbuf);
}
redraw_tabline = true;
if (h != tabline_height()) {
shell_new_rows();
}
}
/// Check that current window is the last one.
@ -2014,10 +2021,11 @@ int win_close(win_T *win, int free_buf)
}
if (close_curwin) {
win_enter_ext(wp, false, TRUE, TRUE, TRUE);
if (other_buffer)
/* careful: after this wp and win may be invalid! */
apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
win_enter_ext(wp, false, true, false, true, true);
if (other_buffer) {
// careful: after this wp and win may be invalid!
apply_autocmds(EVENT_BUFENTER, NULL, NULL, false, curbuf);
}
}
/*
@ -3045,8 +3053,9 @@ int win_new_tabpage(int after, char_u *filename)
redraw_all_later(CLEAR);
apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_WINENTER, NULL, NULL, false, curbuf);
apply_autocmds(EVENT_TABNEW, filename, filename, false, curbuf);
apply_autocmds(EVENT_TABENTER, NULL, NULL, false, curbuf);
return OK;
@ -3204,8 +3213,8 @@ static void enter_tabpage(tabpage_T *tp, buf_T *old_curbuf, int trigger_enter_au
/* We would like doing the TabEnter event first, but we don't have a
* valid current window yet, which may break some commands.
* This triggers autocommands, thus may make "tp" invalid. */
win_enter_ext(tp->tp_curwin, false, TRUE,
trigger_enter_autocmds, trigger_leave_autocmds);
win_enter_ext(tp->tp_curwin, false, true, false,
trigger_enter_autocmds, trigger_leave_autocmds);
prevwin = next_prevwin;
last_status(FALSE); /* status line may appear or disappear */
@ -3546,7 +3555,7 @@ end:
*/
void win_enter(win_T *wp, bool undo_sync)
{
win_enter_ext(wp, undo_sync, FALSE, TRUE, TRUE);
win_enter_ext(wp, undo_sync, false, false, true, true);
}
/*
@ -3554,7 +3563,9 @@ void win_enter(win_T *wp, bool undo_sync)
* Can be called with "curwin_invalid" TRUE, which means that curwin has just
* been closed and isn't valid.
*/
static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int trigger_enter_autocmds, int trigger_leave_autocmds)
static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid,
int trigger_new_autocmds, int trigger_enter_autocmds,
int trigger_leave_autocmds)
{
int other_buffer = FALSE;
@ -3630,6 +3641,9 @@ static void win_enter_ext(win_T *wp, bool undo_sync, int curwin_invalid, int tri
shorten_fnames(TRUE);
}
if (trigger_new_autocmds) {
apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf);
}
if (trigger_enter_autocmds) {
apply_autocmds(EVENT_WINENTER, NULL, NULL, FALSE, curbuf);
if (other_buffer)

View File

@ -12,8 +12,8 @@ describe('autocmds:', function()
local expected = {
'WinLeave',
'TabLeave',
'TabNew',
'WinEnter',
'TabNew',
'TabEnter',
'BufLeave',
'BufEnter'