Close #4605 - Emulate InsertLeave mode

Use a repeating timer to emulate InsertLeave mode for users who have not
rebound <C-c> to <Esc>, 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.
This commit is contained in:
w0rp 2023-09-08 18:42:45 +01:00
parent bf55175b69
commit dd3abf1ad9
No known key found for this signature in database
GPG Key ID: 0FC1ECAA8C81CD83
2 changed files with 100 additions and 17 deletions

View File

@ -92,6 +92,55 @@ function! ale#events#FileChangedEvent(buffer) abort
endif endif
endfunction 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("\<C-c>", 'i') isnot# '<Esc>'
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 <C-c> versus <Esc>
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 function! ale#events#Init() abort
" This value used to be a Boolean as a Number, and is now a String. " 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 let l:text_changed = '' . g:ale_lint_on_text_changed
@ -127,33 +176,40 @@ function! ale#events#Init() abort
\) \)
endif endif
if g:ale_lint_on_insert_leave " Add an InsertEnter event if we need to close the preview window
autocmd InsertLeave * if ale#Var(str2nr(expand('<abuf>')), 'lint_on_insert_leave') | call ale#Queue(0) | endif " on entering insert mode, or if we want to run ALE on leaving
" insert mode and <C-c> is not the same as <Esc>.
"
" 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("\<C-c>", 'i') isnot# '<Esc>')
autocmd InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('<abuf>')))
endif endif
let l:add_insert_leave_event = g:ale_lint_on_insert_leave
if g:ale_echo_cursor || g:ale_cursor_detail 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 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 endif
if g:ale_virtualtext_cursor is# 'current' || g:ale_virtualtext_cursor is# 1 || g:ale_virtualtext_cursor is# '1' 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 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. endif
" The script's position variable used when moving the cursor will
" not be changed here. if l:add_insert_leave_event
autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#virtualtext#ShowCursorWarning() | endif autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
endif endif
if g:ale_hover_cursor if g:ale_hover_cursor
autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif autocmd CursorHold * if exists('*ale#lsp#Send') | call ale#hover#ShowTruncatedMessageAtCursor() | endif
endif endif
if g:ale_close_preview_on_insert
autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif
endif
endif endif
augroup END augroup END

View File

@ -50,6 +50,7 @@ Before:
Save g:ale_lint_on_text_changed Save g:ale_lint_on_text_changed
Save g:ale_pattern_options_enabled Save g:ale_pattern_options_enabled
Save g:ale_hover_cursor Save g:ale_hover_cursor
Save g:ale_close_preview_on_insert
" Turn everything on by default for these tests. " Turn everything on by default for these tests.
let g:ale_completion_enabled = 1 let g:ale_completion_enabled = 1
@ -63,6 +64,7 @@ Before:
let g:ale_lint_on_text_changed = 1 let g:ale_lint_on_text_changed = 1
let g:ale_pattern_options_enabled = 1 let g:ale_pattern_options_enabled = 1
let g:ale_hover_cursor = 1 let g:ale_hover_cursor = 1
let g:ale_close_preview_on_insert = 0
After: After:
delfunction CheckAutocmd delfunction CheckAutocmd
@ -79,6 +81,7 @@ After:
Execute (All events should be set up when everything is on): Execute (All events should be set up when everything is on):
let g:ale_echo_cursor = 1 let g:ale_echo_cursor = 1
" The InsertEnter event is only added when a mapping is not set.
AssertEqual AssertEqual
\ [ \ [
\ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))', \ 'BufEnter * call ale#events#ReadOrEnterEvent(str2nr(expand(''<abuf>'')))',
@ -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', \ 'CursorMoved * if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarningWithDelay() | endif',
\ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))', \ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))',
\ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))', \ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))',
\ 'InsertLeave * if ale#Var(str2nr(expand(''<abuf>'')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif', \ ] + (
\ 'InsertLeave if exists(''*ale#engine#Cleanup'') | call ale#cursor#EchoCursorWarning() | endif', \ maparg("\<C-c>", 'i') isnot# '<Esc>'
\ ? ['InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))']
\ : []
\ ) + [
\ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))', \ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))', \ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''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_lint_on_insert_leave = 1
let g:ale_echo_cursor = 0 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("\<C-c>", 'i') isnot# '<Esc>'
AssertEqual
\ [
\ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
endif
AssertEqual AssertEqual
\ [ \ [
\ 'InsertLeave * if ale#Var(str2nr(expand(''<abuf>'')), ''lint_on_insert_leave'') | call ale#Queue(0) | endif', \ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ ], \ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''') \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''')
@ -236,3 +253,13 @@ Execute(Disabling completion should remove autocmd events correctly):
AssertEqual [], CheckAutocmd('ALECompletionGroup') AssertEqual [], CheckAutocmd('ALECompletionGroup')
AssertEqual 0, g:ale_completion_enabled 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(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')