Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible fix for issue #4642: use ModeChanged events instead of InsertLeave emulation #4738

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 28 additions & 5 deletions autoload/ale/events.vim
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ if !exists('s:insert_leave_timer')
let s:insert_leave_timer = -1
endif

" True if the ModeChanged event exists.
" In this case, ModeChanged will be used instead of InsertLeave emulation.
let s:mode_changed_exists = exists('##ModeChanged')

function! ale#events#EmulateInsertLeave(buffer) abort
if mode() is# 'n'
call timer_stop(s:insert_leave_timer)
Expand All @@ -114,8 +118,12 @@ function! ale#events#InsertEnterEvent(buffer) abort

" Start a repeating timer if the use might not trigger InsertLeave, so we
" can emulate its behavior.
" If the ModeChanged autocmd exists, it will be used instead of this
" timer; as ModeChanged will be sent regardless of how the insert mode is
" exited, including <Esc>, <C-c> and <C-]>.
if ale#Var(a:buffer, 'lint_on_insert_leave')
\&& maparg("\<C-c>", 'i') isnot# '<Esc>'
\&& !s:mode_changed_exists
call timer_stop(s:insert_leave_timer)
let s:insert_leave_timer = timer_start(
\ 100,
Expand All @@ -126,10 +134,15 @@ function! ale#events#InsertEnterEvent(buffer) abort
endfunction

function! ale#events#InsertLeaveEvent(buffer) abort
if ale#Var(a:buffer, 'lint_on_insert_leave')
" Kill the InsertLeave emulation if the event fired.
" Kill the InsertLeave emulation if the event fired.
" If the ModeChanged event is available, it will be used instead of
" a timer.
if !s:mode_changed_exists
call timer_stop(s:insert_leave_timer)
call ale#Queue(0)
endif

if ale#Var(a:buffer, 'lint_on_insert_leave')
call ale#Queue(0, '', a:buffer)
endif

" Look for a warning to echo as soon as we leave Insert mode.
Expand Down Expand Up @@ -189,8 +202,11 @@ function! ale#events#Init() abort
"
" We will emulate leaving insert mode for users that might not
" trigger InsertLeave.
"
" If the ModeChanged event is available, this timer will not
" be used.
if g:ale_close_preview_on_insert
\|| (g:ale_lint_on_insert_leave && maparg("\<C-c>", 'i') isnot# '<Esc>')
\|| (g:ale_lint_on_insert_leave && maparg("\<C-c>", 'i') isnot# '<Esc>' && !s:mode_changed_exists)
autocmd InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand('<abuf>')))
endif

Expand All @@ -211,7 +227,14 @@ function! ale#events#Init() abort
endif

if l:add_insert_leave_event
autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
if s:mode_changed_exists
" If the ModeChanged event is available, handle any
" transition from the Insert mode to any other mode.
autocmd ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
else
" If ModeChanged is not available, handle InsertLeave events.
autocmd InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand('<abuf>')))
endif
endif

if g:ale_hover_cursor
Expand Down
41 changes: 31 additions & 10 deletions test/test_autocmd_commands.vader
Original file line number Diff line number Diff line change
Expand Up @@ -94,11 +94,17 @@ Execute (All events should be set up when everything is on):
\ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))',
\ 'FileType * call ale#events#FileTypeEvent( str2nr(expand(''<abuf>'')), expand(''<amatch>''))',
\ ] + (
\ maparg("\<C-c>", 'i') isnot# '<Esc>'
\ ? ['InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))']
\ maparg("\<C-c>", 'i') isnot# '<Esc>' && !exists('##ModeChanged')
\ ? [
\ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
\ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ ]
\ : []
\ ) + (
\ exists('##ModeChanged')
\ ? ['ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))']
\ : []
\ ) + [
\ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ 'TextChanged * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ 'TextChangedI * call ale#Queue(ale#Var(str2nr(expand(''<abuf>'')), ''lint_delay''))',
\ ],
Expand Down Expand Up @@ -185,25 +191,40 @@ Execute (g:ale_lint_on_text_changed = 'insert' should bind only TextChangedI):
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^TextChanged''')

Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave):
Execute (g:ale_lint_on_insert_leave = 1 should bind InsertLeave or ModeChanged if available):
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("\<C-c>", 'i') isnot# '<Esc>'
if maparg("\<C-c>", 'i') isnot# '<Esc>' && !exists('##ModeChanged')
AssertEqual
\ [
\ 'InsertEnter * call ale#events#InsertEnterEvent(str2nr(expand(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
else
" If the ModeChanged event is available, starting the timer in InsertEnter is not necessary.
AssertEqual
\ [
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')
endif

AssertEqual
\ [
\ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''')
if !exists('##ModeChanged')
" If the ModeChanged event is not available, bind InsertLeave.
AssertEqual
\ [
\ 'InsertLeave * call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertLeave''')
else
AssertEqual
\ [
\ 'ModeChanged i*:* call ale#events#InsertLeaveEvent(str2nr(expand(''<abuf>'')))',
\ ],
\ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^ModeChanged''')
endif

Execute (g:ale_lint_on_filetype_changed = 1 should bind the FileType event):
let g:ale_lint_on_filetype_changed = 1
Expand Down
4 changes: 2 additions & 2 deletions test/test_cursor_warnings.vader
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ Execute(The message at the cursor should be shown when linting ends):

AssertEqual 'semi: Missing semicolon.', g:last_message

Execute(The message at the cursor should be shown on InsertLeave):
Execute(The message at the cursor should be shown when leaving insert mode):
call cursor(2, 9)
doautocmd InsertLeave
call feedkeys("i\<Esc>", 'tnix')

AssertEqual 'space-infix-ops: Infix operators must be spaced.', g:last_message

Expand Down