From a8cfdf43bc6226e32679ec59769ea3e48ca26193 Mon Sep 17 00:00:00 2001 From: zeertzjq Date: Sun, 23 Jul 2023 07:16:41 +0800 Subject: [PATCH] fix(events): trigger VimResume on next UI request (#24426) --- src/nvim/api/ui.c | 6 +++ src/nvim/api/vim.c | 3 ++ src/nvim/autocmd.c | 25 ++++++++++ src/nvim/ex_docmd.c | 5 +- test/functional/api/ui_spec.lua | 59 ++++++++++++++++++++++++ test/functional/ui/screen_basic_spec.lua | 29 ------------ 6 files changed, 94 insertions(+), 33 deletions(-) diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 861ce100cd..9fa5a89407 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -215,6 +215,8 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona pmap_put(uint64_t)(&connected_uis, channel_id, ui); ui_attach_impl(ui, channel_id); + + may_trigger_vim_suspend_resume(false); } /// @deprecated @@ -237,6 +239,10 @@ void nvim_ui_set_focus(uint64_t channel_id, Boolean gained, Error *error) return; } + if (gained) { + may_trigger_vim_suspend_resume(false); + } + do_autocmd_focusgained((bool)gained); } diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index b1e472aa8c..8738b3e38e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -305,6 +305,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) Integer nvim_input(String keys) FUNC_API_SINCE(1) FUNC_API_FAST { + may_trigger_vim_suspend_resume(false); return (Integer)input_enqueue(keys); } @@ -334,6 +335,8 @@ void nvim_input_mouse(String button, String action, String modifier, Integer gri Integer col, Error *err) FUNC_API_SINCE(6) FUNC_API_FAST { + may_trigger_vim_suspend_resume(false); + if (button.data == NULL || action.data == NULL) { goto error; } diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 4aa2ec56a4..a8c5d00383 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -46,6 +46,7 @@ #include "nvim/search.h" #include "nvim/state.h" #include "nvim/strings.h" +#include "nvim/types.h" #include "nvim/ui.h" #include "nvim/ui_compositor.h" #include "nvim/vim.h" @@ -2521,6 +2522,30 @@ static bool arg_autocmd_flag_get(bool *flag, char **cmd_ptr, char *pattern, int return false; } +/// When kFalse: VimSuspend should be triggered next. +/// When kTrue: VimResume should be triggerd next. +/// When kNone: Currently triggering VimSuspend or VimResume. +static TriState pending_vimresume = kFalse; + +static void vimresume_event(void **argv) +{ + apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL); + pending_vimresume = kFalse; +} + +/// Trigger VimSuspend or VimResume autocommand. +void may_trigger_vim_suspend_resume(bool suspend) +{ + if (suspend && pending_vimresume == kFalse) { + pending_vimresume = kNone; + apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL); + pending_vimresume = kTrue; + } else if (!suspend && pending_vimresume == kTrue) { + pending_vimresume = kNone; + multiqueue_put(main_loop.events, vimresume_event, 0); + } +} + // UI Enter void do_autocmd_uienter(uint64_t chanid, bool attached) { diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 7aea2cda53..f154b5b77f 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -4874,12 +4874,9 @@ static void ex_stop(exarg_T *eap) if (!eap->forceit) { autowrite_all(); } - apply_autocmds(EVENT_VIMSUSPEND, NULL, NULL, false, NULL); - + may_trigger_vim_suspend_resume(true); ui_call_suspend(); ui_flush(); - - apply_autocmds(EVENT_VIMRESUME, NULL, NULL, false, NULL); } /// ":exit", ":xit" and ":wq": Write file and quit the current window. diff --git a/test/functional/api/ui_spec.lua b/test/functional/api/ui_spec.lua index b616f51d10..60d115c6f1 100644 --- a/test/functional/api/ui_spec.lua +++ b/test/functional/api/ui_spec.lua @@ -1,8 +1,11 @@ local helpers = require('test.functional.helpers')(after_each) local Screen = require('test.functional.ui.screen') local clear = helpers.clear +local command = helpers.command local eq = helpers.eq local eval = helpers.eval +local exec = helpers.exec +local feed = helpers.feed local meths = helpers.meths local request = helpers.request local pcall_err = helpers.pcall_err @@ -76,3 +79,59 @@ it('autocmds UIEnter/UILeave', function() 'UILeave', }, eval('g:evs')) end) + +it('autocmds VimSuspend/VimResume #22041', function() + clear() + local screen = Screen.new() + screen:attach() + exec([[ + let g:ev = [] + autocmd VimResume * :call add(g:ev, 'r') + autocmd VimSuspend * :call add(g:ev, 's') + ]]) + + eq(false, screen.suspended) + feed('') + screen:expect(function() eq (true, screen.suspended) end) + eq({ 's' }, eval('g:ev')) + screen.suspended = false + feed('') + eq({ 's', 'r' }, eval('g:ev')) + + command('suspend') + screen:expect(function() eq (true, screen.suspended) end) + eq({ 's', 'r', 's' }, eval('g:ev')) + screen.suspended = false + meths.input_mouse('move', '', '', 0, 0, 0) + eq({ 's', 'r', 's', 'r' }, eval('g:ev')) + + feed('') + screen:expect(function() eq (true, screen.suspended) end) + meths.ui_set_focus(false) + eq({ 's', 'r', 's', 'r', 's' }, eval('g:ev')) + screen.suspended = false + meths.ui_set_focus(true) + eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) + + command('suspend') + screen:expect(function() eq (true, screen.suspended) end) + screen:detach() + eq({ 's', 'r', 's', 'r', 's', 'r', 's' }, eval('g:ev')) + screen.suspended = false + screen:attach() + eq({ 's', 'r', 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) + + eq(false, screen.suspended) + feed('') + screen:expect(function() eq (true, screen.suspended) end) + eq({ 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's' }, eval('g:ev')) + screen.suspended = false + feed('') + eq({ 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's' }, eval('g:ev')) + screen:expect(function() eq (true, screen.suspended) end) + screen.suspended = false + feed('i=g:ev') + eq({ 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) + eq({ 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's', 'r', 's', 'r', '' }, + meths.buf_get_lines(0, 0, -1, true)) +end) diff --git a/test/functional/ui/screen_basic_spec.lua b/test/functional/ui/screen_basic_spec.lua index 5d5be2e807..bc9517aa60 100644 --- a/test/functional/ui/screen_basic_spec.lua +++ b/test/functional/ui/screen_basic_spec.lua @@ -4,7 +4,6 @@ local spawn, set_session, clear = helpers.spawn, helpers.set_session, helpers.cl local feed, command = helpers.feed, helpers.command local insert = helpers.insert local eq = helpers.eq -local eval = helpers.eval local funcs, meths = helpers.funcs, helpers.meths describe('screen', function() @@ -64,34 +63,6 @@ local function screen_tests(linegrid) } ) end) - describe(':suspend', function() - it('is forwarded to the UI', function() - local function check() - eq(true, screen.suspended) - end - - command('let g:ev = []') - command('autocmd VimResume * :call add(g:ev, "r")') - command('autocmd VimSuspend * :call add(g:ev, "s")') - - eq(false, screen.suspended) - command('suspend') - eq({ 's', 'r' }, eval('g:ev')) - - screen:expect(check) - screen.suspended = false - - feed('') - eq({ 's', 'r', 's', 'r' }, eval('g:ev')) - - screen:expect(check) - screen.suspended = false - - command('suspend') - eq({ 's', 'r', 's', 'r', 's', 'r' }, eval('g:ev')) - end) - end) - describe('bell/visual bell', function() it('is forwarded to the UI', function() feed('')