summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorw0rp <devw0rp@gmail.com>2023-09-08 18:42:45 +0100
committerw0rp <devw0rp@gmail.com>2023-09-08 18:42:45 +0100
commitdd3abf1ad954af30f101eb6f20276283e8b56784 (patch)
tree680212725141006d9683fd62e6d54784cca2d516
parentbf55175b6971a9a706dfb73ddd00b71750aaee80 (diff)
downloadale-dd3abf1ad954af30f101eb6f20276283e8b56784.zip
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.
-rw-r--r--autoload/ale/events.vim84
-rw-r--r--test/test_autocmd_commands.vader33
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("\<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
" 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('<abuf>')), '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 <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
+ 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('<abuf>')))
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(''<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',
\ 'FileChangedShellPost * call ale#events#FileChangedEvent(str2nr(expand(''<abuf>'')))',
\ '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''))',
\ '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_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
\ [
- \ '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''')
@@ -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(''<abuf>'')))',
+ \ ],
+ \ filter(CheckAutocmd('ALEEvents'), 'v:val =~ ''^InsertEnter''')