From dd3abf1ad954af30f101eb6f20276283e8b56784 Mon Sep 17 00:00:00 2001 From: w0rp Date: Fri, 8 Sep 2023 18:42:45 +0100 Subject: Close #4605 - Emulate InsertLeave mode Use a repeating timer to emulate InsertLeave mode for users who have not rebound to , like many experienced Vim users do. This allows ALE to start linting when you finish typing by default without having to know about this quirk in Vim or Neovim. --- autoload/ale/events.vim | 84 +++++++++++++++++++++++++++++++++------- test/test_autocmd_commands.vader | 33 ++++++++++++++-- 2 files changed, 100 insertions(+), 17 deletions(-) diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim index eec24f46..c8262b4e 100644 --- a/autoload/ale/events.vim +++ b/autoload/ale/events.vim @@ -92,6 +92,55 @@ function! ale#events#FileChangedEvent(buffer) abort endif endfunction +function! ale#events#EmulateInsertLeave(timer) abort + if mode() is# 'n' + call timer_stop(a:timer) + call ale#Queue(0) + endif +endfunction + +function! ale#events#InsertEnterEvent(buffer) abort + if g:ale_close_preview_on_insert && exists('*ale#preview#CloseIfTypeMatches') + call ale#preview#CloseIfTypeMatches('ale-preview') + endif + + " Start a repeating timer if the use might not trigger InsertLeave, so we + " can emulate its behavior. + if ale#Var(a:buffer, 'lint_on_insert_leave') + \&& maparg("\", 'i') isnot# '' + call timer_stop(getbufvar(a:buffer, 'ale_insert_leave_timer', -1)) + let l:timer = timer_start( + \ 100, + \ function('ale#events#EmulateInsertLeave'), + \ {'repeat': -1} + \) + call setbufvar(a:buffer, 'ale_insert_leave_timer', l:timer) + endif +endfunction + +function! ale#events#InsertLeaveEvent(buffer) abort + if ale#Var(a:buffer, 'lint_on_insert_leave') + " Kill the InsertLeave emulation if the event fired. + call timer_stop(getbufvar(a:buffer, 'ale_insert_leave_timer', -1)) + call ale#Queue(0) + endif + + " Look for a warning to echo as soon as we leave Insert mode. + " The script's position variable used when moving the cursor will + " not be changed here. + " + " We don't echo this message in emulated insert leave mode, as the user + " may want less work to happen on pressing versus + if exists('*ale#engine#Cleanup') + call ale#cursor#EchoCursorWarning() + + if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1' + " Show a virtualtext message if enabled. + call ale#virtualtext#ShowCursorWarning() + endif + endif +endfunction + function! ale#events#Init() abort " This value used to be a Boolean as a Number, and is now a String. let l:text_changed = '' . g:ale_lint_on_text_changed @@ -127,32 +176,39 @@ function! ale#events#Init() abort \) endif - if g:ale_lint_on_insert_leave - autocmd InsertLeave * if ale#Var(str2nr(expand('')), 'lint_on_insert_leave') | call ale#Queue(0) | endif + " Add an InsertEnter event if we need to close the preview window + " on entering insert mode, or if we want to run ALE on leaving + " insert mode and is not the same as . + " + " We will emulate leaving insert mode for users that might not + " trigger InsertLeave. + if g:ale_close_preview_on_insert + \|| (g:ale_lint_on_insert_leave && maparg("\", 'i') isnot# '') + autocmd InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''))) endif + let l:add_insert_leave_event = g:ale_lint_on_insert_leave + if g:ale_echo_cursor || g:ale_cursor_detail + " We need to make the message display on InsertLeave + let l:add_insert_leave_event = 1 + autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarningWithDelay() | endif - " Look for a warning to echo as soon as we leave Insert mode. - " The script's position variable used when moving the cursor will - " not be changed here. - autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif endif if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1' + " We need to make the message display on InsertLeave + let l:add_insert_leave_event = 1 + autocmd CursorMoved,CursorHold * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarningWithDelay() | endif - " Look for a warning to echo as soon as we leave Insert mode. - " The script's position variable used when moving the cursor will - " not be changed here. - autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif endif - if g:ale_hover_cursor - autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif + if l:add_insert_leave_event + autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''))) endif - if g:ale_close_preview_on_insert - autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif + if g:ale_hover_cursor + autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif endif endif augroup END diff --git a/test/test_autocmd_commands.vader b/test/test_autocmd_commands.vader index 9f42eff1..61b1f87d 100644 --- a/test/test_autocmd_commands.vader +++ b/test/test_autocmd_commands.vader @@ -50,6 +50,7 @@ Before: Save g:ale_lint_on_text_changed Save g:ale_pattern_options_enabled Save g:ale_hover_cursor + Save g:ale_close_preview_on_insert " Turn everything on by default for these tests. let g:ale_completion_enabled = 1 @@ -63,6 +64,7 @@ Before: let g:ale_lint_on_text_changed = 1 let g:ale_pattern_options_enabled = 1 let g:ale_hover_cursor = 1 + let g:ale_close_preview_on_insert = 0 After: delfunction CheckAutocmd @@ -79,6 +81,7 @@ After: Execute (All events should be set up when everything is on): let g:ale_echo_cursor = 1 + " The InsertEnter event is only added when a mapping is not set. AssertEqual \ [ \ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand('''')))', @@ -90,8 +93,12 @@ Execute (All events should be set up when everything is on): \ 'CursorMoved * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif', \ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand('''')))', \ 'FileType * call ale#events#FileTypeEvent( str2nr(expand('''')), expand(''''))', - \ 'InsertLeave * if ale#Var(str2nr(expand('''')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif', - \ 'InsertLeave if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarning() | endif', + \ ] + ( + \ maparg("\", 'i') isnot# '' + \ ? ['InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))'] + \ : [] + \ ) + [ + \ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('''')))', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand('''')), ''lint_delay''))', \ ], @@ -182,9 +189,19 @@ Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave): let g:ale_lint_on_insert_leave = 1 let g:ale_echo_cursor = 0 + " CI at least should run this check. + " There isn't an easy way to save an restore a mapping during running the test. + if maparg("\", 'i') isnot# '' + AssertEqual + \ [ + \ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''') + endif + AssertEqual \ [ - \ 'InsertLeave * if ale#Var(str2nr(expand('''')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif', + \ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('''')))', \ ], \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''') @@ -236,3 +253,13 @@ Execute(Disabling completion should remove autocmd events correctly): AssertEqual [], CheckAutocmd('ALECompletionGroup') AssertEqual 0, g:ale_completion_enabled + +Execute(ALE should try to close the preview window on InsertEnter): + let g:ale_lint_on_insert_leave = 0 + let g:ale_close_preview_on_insert = 1 + + AssertEqual + \ [ + \ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('''')))', + \ ], + \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''') -- cgit v1.2.3