Merge pull request #9985 from bfredl/shenanigans

Fix aucmd_win issues: crashes and redrawing errors.
This commit is contained in:
Björn Linse 2019-05-13 23:24:14 +02:00 committed by GitHub
commit 9e0982a1a2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 129 additions and 2 deletions

View File

@ -11,6 +11,7 @@
#include <fcntl.h> #include <fcntl.h>
#include "nvim/vim.h" #include "nvim/vim.h"
#include "nvim/api/private/handle.h"
#include "nvim/ascii.h" #include "nvim/ascii.h"
#include "nvim/fileio.h" #include "nvim/fileio.h"
#include "nvim/buffer.h" #include "nvim/buffer.h"
@ -47,6 +48,7 @@
#include "nvim/state.h" #include "nvim/state.h"
#include "nvim/strings.h" #include "nvim/strings.h"
#include "nvim/ui.h" #include "nvim/ui.h"
#include "nvim/ui_compositor.h"
#include "nvim/types.h" #include "nvim/types.h"
#include "nvim/undo.h" #include "nvim/undo.h"
#include "nvim/window.h" #include "nvim/window.h"
@ -6586,6 +6588,8 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf)
block_autocmds(); // We don't want BufEnter/WinEnter autocommands. block_autocmds(); // We don't want BufEnter/WinEnter autocommands.
if (need_append) { if (need_append) {
win_append(lastwin, aucmd_win); win_append(lastwin, aucmd_win);
handle_register_window(aucmd_win);
win_config_float(aucmd_win, aucmd_win->w_float_config);
} }
// Prevent chdir() call in win_enter_ext(), through do_autochdir() // Prevent chdir() call in win_enter_ext(), through do_autochdir()
int save_acd = p_acd; int save_acd = p_acd;
@ -6625,6 +6629,13 @@ void aucmd_restbuf(aco_save_T *aco)
win_found: win_found:
win_remove(curwin, NULL); win_remove(curwin, NULL);
handle_unregister_window(curwin);
if (curwin->w_grid.chars != NULL) {
ui_comp_remove_grid(&curwin->w_grid);
ui_call_win_hide(curwin->w_grid.handle);
grid_free(&curwin->w_grid);
}
aucmd_win_used = false; aucmd_win_used = false;
last_status(false); // may need to remove last status line last_status(false); // may need to remove last status line

View File

@ -3418,8 +3418,8 @@ void win_alloc_aucmd_win(void)
{ {
Error err = ERROR_INIT; Error err = ERROR_INIT;
FloatConfig fconfig = FLOAT_CONFIG_INIT; FloatConfig fconfig = FLOAT_CONFIG_INIT;
fconfig.width = 20; fconfig.width = Columns;
fconfig.height = 20; fconfig.height = 5;
fconfig.focusable = false; fconfig.focusable = false;
aucmd_win = win_new_float(NULL, fconfig, &err); aucmd_win = win_new_float(NULL, fconfig, &err);
aucmd_win->w_buffer->b_nwindows--; aucmd_win->w_buffer->b_nwindows--;

View File

@ -1,4 +1,5 @@
local helpers = require('test.functional.helpers')(after_each) local helpers = require('test.functional.helpers')(after_each)
local Screen = require('test.functional.ui.screen')
local dedent = helpers.dedent local dedent = helpers.dedent
local eq = helpers.eq local eq = helpers.eq
@ -6,11 +7,13 @@ local eval = helpers.eval
local feed = helpers.feed local feed = helpers.feed
local clear = helpers.clear local clear = helpers.clear
local meths = helpers.meths local meths = helpers.meths
local meth_pcall = helpers.meth_pcall
local funcs = helpers.funcs local funcs = helpers.funcs
local expect = helpers.expect local expect = helpers.expect
local command = helpers.command local command = helpers.command
local exc_exec = helpers.exc_exec local exc_exec = helpers.exc_exec
local curbufmeths = helpers.curbufmeths local curbufmeths = helpers.curbufmeths
local source = helpers.source
describe('autocmd', function() describe('autocmd', function()
before_each(clear) before_each(clear)
@ -144,4 +147,117 @@ describe('autocmd', function()
--- Autocommands ---]]), --- Autocommands ---]]),
funcs.execute('autocmd Tabnew')) funcs.execute('autocmd Tabnew'))
end) end)
it('window works', function()
-- Nvim uses a special window to execute certain actions for an invisible buffer,
-- internally called autcmd_win and mentioned in the docs at :help E813
-- Do some safety checks for redrawing and api accesses to this window.
local screen = Screen.new(50, 10)
screen:attach()
screen:set_default_attr_ids({
[1] = {bold = true, foreground = Screen.colors.Blue1},
[2] = {background = Screen.colors.LightMagenta},
[3] = {background = Screen.colors.LightMagenta, bold = true, foreground = Screen.colors.Blue1},
})
source([[
function! Doit()
let g:winid = nvim_get_current_win()
redraw!
echo getchar()
" API functions work when aucmd_win is in scope
let g:had_value = has_key(w:, "testvar")
call nvim_win_set_var(g:winid, "testvar", 7)
let g:test = w:testvar
endfunction
set hidden
" add dummy text to not discard the buffer
call setline(1,"bb")
autocmd User <buffer> call Doit()
]])
screen:expect([[
^bb |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
|
]])
feed(":enew | doautoall User<cr>")
screen:expect([[
{2:bb }|
{3:~ }|
{3:~ }|
{3:~ }|
{3:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
^:enew | doautoall User |
]])
feed('<cr>')
screen:expect([[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
13 |
]])
eq(7, eval('g:test'))
-- API calls are blocked when aucmd_win is not in scope
eq({false, 'Vim(call):Invalid window id'},
meth_pcall(command, "call nvim_set_current_win(g:winid)"))
-- second time aucmd_win is needed, a different code path is invoked
-- to reuse the same window, so check again
command("let g:test = v:null")
command("let g:had_value = v:null")
feed(":doautoall User<cr>")
screen:expect([[
{2:bb }|
{3:~ }|
{3:~ }|
{3:~ }|
{3:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
^:doautoall User |
]])
feed('<cr>')
screen:expect([[
^ |
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
{1:~ }|
13 |
]])
-- win vars in aucmd_win should have been reset
eq(0, eval('g:had_value'))
eq(7, eval('g:test'))
eq({false, 'Vim(call):Invalid window id'},
meth_pcall(command, "call nvim_set_current_win(g:winid)"))
end)
end) end)