From c41dbe2ba9862037122b98fa2bb55fd72d277b74 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Mon, 5 Nov 2018 22:45:40 -0800 Subject: Add support for nvim's virtualtext on cursor - Add g:ale_virtualtext_cursor boolean to enable/disable it - Add g:ale_virtualtext_prefix to configure what prefix to use (default: '> ') - Requires neovim 0.3.2's unreleased API `nvim_buf_set_virtual_text` --- autoload/ale/cursor.vim | 45 +++++++++++++++++++++++++++++++++++++++++++-- autoload/ale/debugging.vim | 6 ++++-- autoload/ale/engine.vim | 2 +- autoload/ale/events.vim | 2 +- doc/ale.txt | 24 ++++++++++++++++++++++++ plugin/ale.vim | 3 +++ 6 files changed, 76 insertions(+), 6 deletions(-) diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index 32ce8c84..9b4b9c1a 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -52,6 +52,29 @@ function! ale#cursor#TruncatedEcho(original_message) abort endtry endfunction +function! ale#cursor#ClearVirtualText() abort + if !has('nvim-0.3.2') + return + endif + + let l:buffer = bufnr('') + + call nvim_buf_clear_highlight(l:buffer, 1000, 0, -1) +endfunction + +function! ale#cursor#ShowVirtualText(message, hl_group) abort + if !has('nvim-0.3.2') + return + endif + + let l:cursor_position = getcurpos() + let l:line = line('.') + let l:buffer = bufnr('') + let l:prefix = get(g:, 'ale_virtualtext_prefix', '> ') + + call nvim_buf_set_virtual_text(l:buffer, 1000, l:line-1, [[l:prefix.a:message, a:hl_group]], {}) +endfunction + function! s:FindItemAtCursor(buffer) abort let l:info = get(g:ale_buffer_info, a:buffer, {}) let l:loclist = get(l:info, 'loclist', []) @@ -72,7 +95,7 @@ endfunction function! ale#cursor#EchoCursorWarning(...) abort let l:buffer = bufnr('') - if !g:ale_echo_cursor && !g:ale_cursor_detail + if !g:ale_echo_cursor && !g:ale_cursor_detail && !g:ale_virtualtext_cursor return endif @@ -108,12 +131,30 @@ function! ale#cursor#EchoCursorWarning(...) abort call ale#preview#CloseIfTypeMatches('ale-preview') endif endif + + if g:ale_virtualtext_cursor + call ale#cursor#ClearVirtualText() + + if !empty(l:loc) + let l:msg = get(l:loc, 'detail', l:loc.text) + let l:hl_group = 'ALEInfo' + let l:type = get(l:loc, 'type', 'E') + + if l:type is# 'E' + let l:hl_group = 'ALEError' + elseif l:type is# 'I' + let l:hl_group = 'ALEWarning' + endif + + call ale#cursor#ShowVirtualText(l:msg, l:hl_group) + endif + endif endfunction function! ale#cursor#EchoCursorWarningWithDelay() abort let l:buffer = bufnr('') - if !g:ale_echo_cursor && !g:ale_cursor_detail + if !g:ale_echo_cursor && !g:ale_cursor_detail && !g:ale_virtualtext_cursor return endif diff --git a/autoload/ale/debugging.vim b/autoload/ale/debugging.vim index 34c13770..ac7e02e3 100644 --- a/autoload/ale/debugging.vim +++ b/autoload/ale/debugging.vim @@ -22,14 +22,14 @@ let s:global_variable_list = [ \ 'ale_lint_delay', \ 'ale_lint_on_enter', \ 'ale_lint_on_filetype_changed', +\ 'ale_lint_on_insert_leave', \ 'ale_lint_on_save', \ 'ale_lint_on_text_changed', -\ 'ale_lint_on_insert_leave', \ 'ale_linter_aliases', \ 'ale_linters', \ 'ale_linters_explicit', -\ 'ale_list_window_size', \ 'ale_list_vertical', +\ 'ale_list_window_size', \ 'ale_loclist_msg_format', \ 'ale_max_buffer_history_size', \ 'ale_max_signs', @@ -52,6 +52,8 @@ let s:global_variable_list = [ \ 'ale_statusline_format', \ 'ale_type_map', \ 'ale_use_global_executables', +\ 'ale_virtualtext_cursor', +\ 'ale_virtualtext_prefix', \ 'ale_warn_about_trailing_blank_lines', \ 'ale_warn_about_trailing_whitespace', \] diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index e85e4d66..f49d607b 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -298,7 +298,7 @@ function! ale#engine#SetResults(buffer, loclist) abort endif if l:linting_is_done - if g:ale_echo_cursor + if g:ale_echo_cursor || g:ale_virtualtext_cursor " Try and echo the warning now. " This will only do something meaningful if we're in normal mode. call ale#cursor#EchoCursorWarning() diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim index e48ad488..4efb42e3 100644 --- a/autoload/ale/events.vim +++ b/autoload/ale/events.vim @@ -131,7 +131,7 @@ function! ale#events#Init() abort autocmd InsertLeave * call ale#Queue(0) endif - if g:ale_echo_cursor || g:ale_cursor_detail + if g:ale_echo_cursor || g:ale_cursor_detail || g:ale_virtualtext_cursor 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 diff --git a/doc/ale.txt b/doc/ale.txt index d4223f84..1e114c72 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -557,6 +557,7 @@ their relevant options. * By setting error highlights. - |g:ale_set_highlights| * By creating signs in the sign column. - |g:ale_set_signs| * By echoing messages based on your cursor. - |g:ale_echo_cursor| +* By inline text based on your cursor. - |g:ale_virtualtext_cursor| * By displaying the preview based on your cursor. - |g:ale_cursor_detail| * By showing balloons for your mouse cursor - |g:ale_set_balloons| @@ -1868,6 +1869,29 @@ g:ale_use_global_executables *g:ale_use_global_executables* options. +g:ale_virtualtext_cursor *g:ale_virtualtext_cursor* + + Type: |Number| + Default: `0` + + When this option is set to `1`, a message will be shown when a cursor is + near a warning or error. ALE will attempt to find the warning or error at a + column nearest to the cursor when the cursor is resting on a line which + contains a warning or error. This option can be set to `0` to disable this + behavior. + + Messages are only displayed after a short delay. See |g:ale_echo_delay|. + + Messages can be prefixed prefixed with a string. See |g:ale_virtualtext_prefix|. + + +g:ale_virtualtext_prefix *g:ale_virtualtext_prefix* + + Type: |String| + Default: `'> '` + + Prefix to be used with |g:ale_virtualtext_cursor|. + g:ale_virtualenv_dir_names *g:ale_virtualenv_dir_names* b:ale_virtualenv_dir_names *b:ale_virtualenv_dir_names* diff --git a/plugin/ale.vim b/plugin/ale.vim index 7ef19775..f1735b42 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -109,6 +109,9 @@ let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax')) " This flag can be set to 0 to disable echoing when the cursor moves. let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1) +" This flag can be set to 1 to enable virtual text when the cursor moves. +let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 0) + " This flag can be set to 1 to automatically show errors in the preview window. let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', 0) -- cgit v1.2.3 From 25068de91d1ff61cba02da4ad19f45d35c634eb9 Mon Sep 17 00:00:00 2001 From: w0rp Date: Tue, 6 Nov 2018 11:31:17 -0800 Subject: Fix incorrect warning match Co-Authored-By: luan --- autoload/ale/cursor.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index 9b4b9c1a..090a3553 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -142,7 +142,7 @@ function! ale#cursor#EchoCursorWarning(...) abort if l:type is# 'E' let l:hl_group = 'ALEError' - elseif l:type is# 'I' + elseif l:type is# 'W' let l:hl_group = 'ALEWarning' endif -- cgit v1.2.3 From f58a5cba0583231f77bd5e7cd5ab7a246fb00cd1 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Tue, 6 Nov 2018 22:31:35 -0800 Subject: Move virtualtext handling to own file This allows cursor and virtualtext to be independently autoloaded. --- autoload/ale/cursor.vim | 59 ++---------------------- autoload/ale/engine.vim | 8 +++- autoload/ale/events.vim | 10 ++++- autoload/ale/util.vim | 11 +++++ autoload/ale/virtualtext.vim | 104 +++++++++++++++++++++++++++++++++++++++++++ plugin/ale.vim | 6 +-- 6 files changed, 138 insertions(+), 60 deletions(-) create mode 100644 autoload/ale/virtualtext.vim diff --git a/autoload/ale/cursor.vim b/autoload/ale/cursor.vim index 090a3553..6672c349 100644 --- a/autoload/ale/cursor.vim +++ b/autoload/ale/cursor.vim @@ -52,39 +52,6 @@ function! ale#cursor#TruncatedEcho(original_message) abort endtry endfunction -function! ale#cursor#ClearVirtualText() abort - if !has('nvim-0.3.2') - return - endif - - let l:buffer = bufnr('') - - call nvim_buf_clear_highlight(l:buffer, 1000, 0, -1) -endfunction - -function! ale#cursor#ShowVirtualText(message, hl_group) abort - if !has('nvim-0.3.2') - return - endif - - let l:cursor_position = getcurpos() - let l:line = line('.') - let l:buffer = bufnr('') - let l:prefix = get(g:, 'ale_virtualtext_prefix', '> ') - - call nvim_buf_set_virtual_text(l:buffer, 1000, l:line-1, [[l:prefix.a:message, a:hl_group]], {}) -endfunction - -function! s:FindItemAtCursor(buffer) abort - let l:info = get(g:ale_buffer_info, a:buffer, {}) - let l:loclist = get(l:info, 'loclist', []) - let l:pos = getcurpos() - let l:index = ale#util#BinarySearch(l:loclist, a:buffer, l:pos[1], l:pos[2]) - let l:loc = l:index >= 0 ? l:loclist[l:index] : {} - - return [l:info, l:loc] -endfunction - function! s:StopCursorTimer() abort if s:cursor_timer != -1 call timer_stop(s:cursor_timer) @@ -95,7 +62,7 @@ endfunction function! ale#cursor#EchoCursorWarning(...) abort let l:buffer = bufnr('') - if !g:ale_echo_cursor && !g:ale_cursor_detail && !g:ale_virtualtext_cursor + if !g:ale_echo_cursor && !g:ale_cursor_detail return endif @@ -108,7 +75,7 @@ function! ale#cursor#EchoCursorWarning(...) abort return endif - let [l:info, l:loc] = s:FindItemAtCursor(l:buffer) + let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) if g:ale_echo_cursor if !empty(l:loc) @@ -131,30 +98,12 @@ function! ale#cursor#EchoCursorWarning(...) abort call ale#preview#CloseIfTypeMatches('ale-preview') endif endif - - if g:ale_virtualtext_cursor - call ale#cursor#ClearVirtualText() - - if !empty(l:loc) - let l:msg = get(l:loc, 'detail', l:loc.text) - let l:hl_group = 'ALEInfo' - let l:type = get(l:loc, 'type', 'E') - - if l:type is# 'E' - let l:hl_group = 'ALEError' - elseif l:type is# 'W' - let l:hl_group = 'ALEWarning' - endif - - call ale#cursor#ShowVirtualText(l:msg, l:hl_group) - endif - endif endfunction function! ale#cursor#EchoCursorWarningWithDelay() abort let l:buffer = bufnr('') - if !g:ale_echo_cursor && !g:ale_cursor_detail && !g:ale_virtualtext_cursor + if !g:ale_echo_cursor && !g:ale_cursor_detail return endif @@ -210,7 +159,7 @@ function! ale#cursor#ShowCursorDetail() abort call s:StopCursorTimer() - let [l:info, l:loc] = s:FindItemAtCursor(l:buffer) + let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) if !empty(l:loc) call s:ShowCursorDetailForItem(l:loc, {'stay_here': 0}) diff --git a/autoload/ale/engine.vim b/autoload/ale/engine.vim index f49d607b..b44be73c 100644 --- a/autoload/ale/engine.vim +++ b/autoload/ale/engine.vim @@ -298,12 +298,18 @@ function! ale#engine#SetResults(buffer, loclist) abort endif if l:linting_is_done - if g:ale_echo_cursor || g:ale_virtualtext_cursor + if g:ale_echo_cursor " Try and echo the warning now. " This will only do something meaningful if we're in normal mode. call ale#cursor#EchoCursorWarning() endif + if g:ale_virtualtext_cursor + " Try and show the warning now. + " This will only do something meaningful if we're in normal mode. + call ale#virtualtext#ShowCursorWarning() + endif + " Reset the save event marker, used for opening windows, etc. call setbufvar(a:buffer, 'ale_save_event_fired', 0) " Set a marker showing how many times a buffer has been checked. diff --git a/autoload/ale/events.vim b/autoload/ale/events.vim index 4efb42e3..55e0a6cc 100644 --- a/autoload/ale/events.vim +++ b/autoload/ale/events.vim @@ -131,7 +131,7 @@ function! ale#events#Init() abort autocmd InsertLeave * call ale#Queue(0) endif - if g:ale_echo_cursor || g:ale_cursor_detail || g:ale_virtualtext_cursor + if g:ale_echo_cursor || g:ale_cursor_detail 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 @@ -139,6 +139,14 @@ function! ale#events#Init() abort autocmd InsertLeave * if exists('*ale#engine#Cleanup') | call ale#cursor#EchoCursorWarning() | endif endif + if g:ale_virtualtext_cursor + 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_close_preview_on_insert autocmd InsertEnter * if exists('*ale#preview#CloseIfTypeMatches') | call ale#preview#CloseIfTypeMatches('ale-preview') | endif endif diff --git a/autoload/ale/util.vim b/autoload/ale/util.vim index e0491653..bb478957 100644 --- a/autoload/ale/util.vim +++ b/autoload/ale/util.vim @@ -452,3 +452,14 @@ function! ale#util#Col(str, chr) abort return strlen(join(split(a:str, '\zs')[0:a:chr - 2], '')) + 1 endfunction + +function! ale#util#FindItemAtCursor(buffer) abort + let l:info = get(g:ale_buffer_info, a:buffer, {}) + let l:loclist = get(l:info, 'loclist', []) + let l:pos = getcurpos() + let l:index = ale#util#BinarySearch(l:loclist, a:buffer, l:pos[1], l:pos[2]) + let l:loc = l:index >= 0 ? l:loclist[l:index] : {} + + return [l:info, l:loc] +endfunction + diff --git a/autoload/ale/virtualtext.vim b/autoload/ale/virtualtext.vim new file mode 100644 index 00000000..85a12de6 --- /dev/null +++ b/autoload/ale/virtualtext.vim @@ -0,0 +1,104 @@ +scriptencoding utf-8 +" Author: w0rp +" Author: Luan Santos +" Description: Shows lint message for the current line as virtualtext, if any + +" Controls the milliseconds delay before showing a message. +let g:ale_virtualtext_delay = get(g:, 'ale_virtualtext_delay', 10) +let s:cursor_timer = -1 +let s:last_pos = [0, 0, 0] + +function! ale#virtualtext#Clear() abort + if !has('nvim-0.3.2') + return + endif + + let l:buffer = bufnr('') + + call nvim_buf_clear_highlight(l:buffer, 1000, 0, -1) +endfunction + +function! ale#virtualtext#ShowMessage(message, hl_group) abort + if !has('nvim-0.3.2') + return + endif + + let l:cursor_position = getcurpos() + let l:line = line('.') + let l:buffer = bufnr('') + let l:prefix = get(g:, 'ale_virtualtext_prefix', '> ') + + call nvim_buf_set_virtual_text(l:buffer, 1000, l:line-1, [[l:prefix.a:message, a:hl_group]], {}) +endfunction + +function! s:StopCursorTimer() abort + if s:cursor_timer != -1 + call timer_stop(s:cursor_timer) + let s:cursor_timer = -1 + endif +endfunction + +function! ale#virtualtext#ShowCursorWarning(...) abort + if !g:ale_virtualtext_cursor + return + endif + + let l:buffer = bufnr('') + + if mode(1) isnot# 'n' + return + endif + + if ale#ShouldDoNothing(l:buffer) + return + endif + + let [l:info, l:loc] = ale#util#FindItemAtCursor(l:buffer) + + call ale#virtualtext#Clear() + + if !empty(l:loc) + let l:msg = get(l:loc, 'detail', l:loc.text) + let l:hl_group = 'ALEInfo' + let l:type = get(l:loc, 'type', 'E') + + if l:type is# 'E' + let l:hl_group = 'ALEError' + elseif l:type is# 'W' + let l:hl_group = 'ALEWarning' + endif + + call ale#virtualtext#ShowMessage(l:msg, l:hl_group) + endif +endfunction + +function! ale#virtualtext#ShowCursorWarningWithDelay() abort + let l:buffer = bufnr('') + + if !g:ale_virtualtext_cursor + return + endif + + if mode(1) isnot# 'n' + return + endif + + call s:StopCursorTimer() + + let l:pos = getcurpos()[0:2] + + " Check the current buffer, line, and column number against the last + " recorded position. If the position has actually changed, *then* + " we should show something. Otherwise we can end up doing processing + " the show message far too frequently. + if l:pos != s:last_pos + let l:delay = ale#Var(l:buffer, 'virtualtext_delay') + + let s:last_pos = l:pos + let s:cursor_timer = timer_start( + \ l:delay, + \ function('ale#virtualtext#ShowCursorWarning') + \) + endif +endfunction + diff --git a/plugin/ale.vim b/plugin/ale.vim index f1735b42..7231d1bd 100644 --- a/plugin/ale.vim +++ b/plugin/ale.vim @@ -109,12 +109,12 @@ let g:ale_set_highlights = get(g:, 'ale_set_highlights', has('syntax')) " This flag can be set to 0 to disable echoing when the cursor moves. let g:ale_echo_cursor = get(g:, 'ale_echo_cursor', 1) -" This flag can be set to 1 to enable virtual text when the cursor moves. -let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 0) - " This flag can be set to 1 to automatically show errors in the preview window. let g:ale_cursor_detail = get(g:, 'ale_cursor_detail', 0) +" This flag can be set to 1 to enable virtual text when the cursor moves. +let g:ale_virtualtext_cursor = get(g:, 'ale_virtualtext_cursor', 0) + " This flag can be set to 1 to automatically close the preview window upon " entering Insert Mode. let g:ale_close_preview_on_insert = get(g:, 'ale_close_preview_on_insert', 0) -- cgit v1.2.3 From 3ec09f7826a6799aa4186542e0f802991b36ddc3 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Tue, 6 Nov 2018 22:36:37 -0800 Subject: Document ale_virtualtext_delay --- doc/ale.txt | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/ale.txt b/doc/ale.txt index 1e114c72..d260b40e 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -1880,11 +1880,23 @@ g:ale_virtualtext_cursor *g:ale_virtua contains a warning or error. This option can be set to `0` to disable this behavior. - Messages are only displayed after a short delay. See |g:ale_echo_delay|. + Messages are only displayed after a short delay. See |g:ale_virtualtext_delay|. Messages can be prefixed prefixed with a string. See |g:ale_virtualtext_prefix|. +g:ale_virtualtext_delay *g:ale_virtualtext_delay* + *b:ale_virtualtext_delay* + Type: |Number| + Default: `10` + + Given any integer, this option controls the number of milliseconds before + ALE will show a message for a problem near the cursor. + + The value can be increased to decrease the amount of processing ALE will do + for files displaying a large number of problems. + + g:ale_virtualtext_prefix *g:ale_virtualtext_prefix* Type: |String| -- cgit v1.2.3 From ba9b056a57a605e1253b9f50e94074499bf808b4 Mon Sep 17 00:00:00 2001 From: Luan Santos Date: Tue, 6 Nov 2018 22:38:47 -0800 Subject: Fix info text Removed ale_virualtext_prefix from debugging since it's not requried for the functionality to work. Sorted debugging info to make the list easier to navigate/diff. --- autoload/ale/debugging.vim | 1 - test/test_ale_info.vader | 5 +++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/autoload/ale/debugging.vim b/autoload/ale/debugging.vim index ac7e02e3..6c2bfbee 100644 --- a/autoload/ale/debugging.vim +++ b/autoload/ale/debugging.vim @@ -53,7 +53,6 @@ let s:global_variable_list = [ \ 'ale_type_map', \ 'ale_use_global_executables', \ 'ale_virtualtext_cursor', -\ 'ale_virtualtext_prefix', \ 'ale_warn_about_trailing_blank_lines', \ 'ale_warn_about_trailing_whitespace', \] diff --git a/test/test_ale_info.vader b/test/test_ale_info.vader index 39a2a85a..325c2aa8 100644 --- a/test/test_ale_info.vader +++ b/test/test_ale_info.vader @@ -88,14 +88,14 @@ Before: \ 'let g:ale_lint_delay = 200', \ 'let g:ale_lint_on_enter = 1', \ 'let g:ale_lint_on_filetype_changed = 1', + \ 'let g:ale_lint_on_insert_leave = 0', \ 'let g:ale_lint_on_save = 1', \ 'let g:ale_lint_on_text_changed = ''always''', - \ 'let g:ale_lint_on_insert_leave = 0', \ 'let g:ale_linter_aliases = {}', \ 'let g:ale_linters = {}', \ 'let g:ale_linters_explicit = 0', - \ 'let g:ale_list_window_size = 10', \ 'let g:ale_list_vertical = 0', + \ 'let g:ale_list_window_size = 10', \ 'let g:ale_loclist_msg_format = ''%code: %%s''', \ 'let g:ale_max_buffer_history_size = 20', \ 'let g:ale_max_signs = -1', @@ -118,6 +118,7 @@ Before: \ 'let g:ale_statusline_format = [''%d error(s)'', ''%d warning(s)'', ''OK'']', \ 'let g:ale_type_map = {}', \ 'let g:ale_use_global_executables = v:null', + \ 'let g:ale_virtualtext_cursor = 0', \ 'let g:ale_warn_about_trailing_blank_lines = 1', \ 'let g:ale_warn_about_trailing_whitespace = 1', \] -- cgit v1.2.3