ale/autoload/ale/list.vim

275 lines
8.9 KiB
VimL
Raw Normal View History

" Author: Bjorn Neergaard <bjorn@neersighted.com>, modified by Yann fery <yann@fery.me>
" Description: Manages the loclist and quickfix lists
" This flag dictates if ale open the configured loclist
let g:ale_open_list = get(g:, 'ale_open_list', 0)
" This flag dictates if ale keeps open loclist even if there is no error in loclist
let g:ale_keep_list_window_open = get(g:, 'ale_keep_list_window_open', 0)
" This flag dictates that quickfix windows should be opened vertically
let g:ale_list_vertical = get(g:, 'ale_list_vertical', 0)
" The window size to set for the quickfix and loclist windows
let g:ale_list_window_size = get(g:, 'ale_list_window_size', 10)
" A string format for the loclist messages.
let g:ale_loclist_msg_format = get(g:, 'ale_loclist_msg_format',
\ get(g:, 'ale_echo_msg_format', '%code: %%s')
\)
if !exists('s:timer_args')
let s:timer_args = {}
endif
" Return 1 if there is a buffer with buftype == 'quickfix' in bufffer list
function! ale#list#IsQuickfixOpen() abort
3560 add vim 8.2 and nvim 0.4 to ci tests (#3561) * Add vim82 and neovim04 to CI tests. * Fix test_sign_column_hightlighting test. In vim82 with verbose=1 the output of highlight command changes breaking the ale#sign#SetUpDefaultColumnWithoutErrorsHighlight(). This commit forces verbose=0 when the method starts and restores the previous value before exiting. * No return values in vim82 returns a numeric value instead of a empty string. * Fix test_reek_handler test The FuzzyJSONDecode() method catches E474 when it fails to parse the input as JSON but Vim8.2 throws E491 instead. This commit modifies the function to catch both E474 or E491. * Fix perl6 handler test. Perl6 handler catches json parse errors using the E474 error but in Vim82 it changed to E491. This commit modifies the handler so both errors are considered. * Fix list opening tests. In Vim 8.2 the call `range(1, bufnr('$'))` always returns quickfix buffers no matter if they are closed or not. Using `ls` does not show them but the above range will always include them. This new behavior breaks the ale#list#IsQuickfixOpen() method that in turn breaks many other things. This commit fixes this by using the getqflist() and getloclist() methods instead. * Fix test updates loclist test. For some reason in Vim 8.2 the sign offset seems to not reset between tests causing the sign_id to not match in the Assert. When the test is run individually it passes but when run as part of the whole suite the sign_id is off by one. Forcing the offset in the test setup seems to fix the issue. * Fix omnifunc completion test. For unknown reasons the SetCompletionResponse tests fail in Neovim 0.2 and 0.4. Unfortunatelly the only solution I found is to disable them for neovim. * Fix linter warnings * Fix smoker test. Add vim 8.2 to the list of versions that need some retires due to randomly failing tests. * Add docker image build job. Trying some clever trick to build the docker image if not available locally or in Docker hub. It uses the Dockerfile md5 checksum as tag so only when changes on that file occur will the image be downloaded or build. * Add labels to Docker image * Remove tests for middle versions 8.1 and 0.3.5 * Use same vader commit as appveyor * Implement image push to Docker Hub Co-authored-by: Horacio Sanson <horacio@allm.inc>
2021-01-27 19:52:24 +00:00
let l:res = getqflist({ 'winid' : winnr() })
if has_key(l:res, 'winid') && l:res.winid > 0
return 1
endif
let l:res = getloclist(0, { 'winid' : winnr() })
if has_key(l:res, 'winid') && l:res.winid > 0
return 1
endif
return 0
endfunction
" Check if we should open the list, based on the save event being fired, and
" that setting being on, or that the error count is at least as high as the
" setting when set to an integer value.
function! s:ShouldOpen(buffer, loclist_len) abort
let l:val = ale#Var(a:buffer, 'open_list')
let l:saved = getbufvar(a:buffer, 'ale_save_event_fired', 0)
return l:val > 0 ? a:loclist_len >= l:val : l:val is# 'on_save' && l:saved
endfunction
" Check if we should close the list, based on the save event being fired, and
" that setting being on, or the setting just being set to an integer value.
function! s:ShouldClose(buffer) abort
let l:val = ale#Var(a:buffer, 'open_list')
let l:saved = getbufvar(a:buffer, 'ale_save_event_fired', 0)
return !((l:val >= 1) || (l:val is# 'on_save' && l:saved))
endfunction
function! s:Deduplicate(list) abort
let l:list = a:list
call sort(l:list, function('ale#util#LocItemCompareWithText'))
call uniq(l:list, function('ale#util#LocItemCompareWithText'))
return l:list
endfunction
function! ale#list#GetCombinedList() abort
let l:list = []
for l:info in values(g:ale_buffer_info)
call extend(l:list, l:info.loclist)
endfor
return s:Deduplicate(l:list)
endfunction
function! s:FixList(buffer, list) abort
let l:format = ale#Var(a:buffer, 'loclist_msg_format')
let l:new_list = []
for l:item in a:list
let l:fixed_item = copy(l:item)
let l:fixed_item.text = ale#GetLocItemMessage(l:item, l:format)
if l:item.bufnr == -1
" If the buffer number is invalid, remove it.
call remove(l:fixed_item, 'bufnr')
endif
call add(l:new_list, l:fixed_item)
endfor
return l:new_list
endfunction
function! s:WinFindBuf(buffer) abort
return exists('*win_findbuf') ? win_findbuf(str2nr(a:buffer)) : [0]
endfunction
function! s:SetListsImpl(timer_id, buffer, loclist) abort
let l:title = expand('#' . a:buffer . ':p')
if g:ale_set_quickfix
let l:quickfix_list = ale#list#GetCombinedList()
if has('nvim')
call setqflist(s:FixList(a:buffer, l:quickfix_list), ' ', l:title)
else
call setqflist(s:FixList(a:buffer, l:quickfix_list))
call setqflist([], 'r', {'title': l:title})
endif
elseif g:ale_set_loclist
" If windows support is off, win_findbuf() may not exist.
" We'll set result in the current window, which might not be correct,
" but it's better than nothing.
let l:ids = s:WinFindBuf(a:buffer)
let l:loclist = s:Deduplicate(a:loclist)
for l:id in l:ids
if has('nvim')
call setloclist(l:id, s:FixList(a:buffer, l:loclist), ' ', l:title)
else
call setloclist(l:id, s:FixList(a:buffer, l:loclist))
call setloclist(l:id, [], 'r', {'title': l:title})
endif
endfor
endif
" Save the current view before opening/closing any window
call setbufvar(a:buffer, 'ale_winview', winsaveview())
" Open a window to show the problems if we need to.
"
" ShouldOpen() checks if the current buffer has enough problems to be
" opened.
if s:ShouldOpen(a:buffer, len(a:loclist))
let l:winnr = winnr()
let l:mode = mode()
" open windows vertically instead of default horizontally
let l:open_type = ''
if ale#Var(a:buffer, 'list_vertical') == 1
let l:open_type = 'vert rightbelow '
endif
if g:ale_set_quickfix
if !ale#list#IsQuickfixOpen()
silent! execute l:open_type . 'copen ' . str2nr(ale#Var(a:buffer, 'list_window_size'))
endif
elseif g:ale_set_loclist
silent! execute l:open_type . 'lopen ' . str2nr(ale#Var(a:buffer, 'list_window_size'))
endif
" If focus changed, restore it (jump to the last window).
2017-08-10 23:31:42 +00:00
if l:winnr isnot# winnr()
wincmd p
endif
" Return to original mode when applicable
if mode() != l:mode
if l:mode is? 'v' || l:mode is# "\<c-v>"
" Reset our last visual selection
normal! gv
elseif l:mode is? 's' || l:mode is# "\<c-s>"
" Reset our last character selection
normal! "\<c-g>"
endif
endif
call s:RestoreViewIfNeeded(a:buffer)
endif
" If ALE isn't currently checking for more problems, close the window if
" needed now. This check happens inside of this timer function, so
" the window can be closed reliably.
if !ale#engine#IsCheckingBuffer(a:buffer)
call s:CloseWindowIfNeeded(a:buffer)
endif
endfunction
" Try to restore the window view after closing any of the lists to avoid making
" the it moving around, especially useful when on insert mode
function! s:RestoreViewIfNeeded(buffer) abort
let l:saved_view = getbufvar(a:buffer, 'ale_winview', {})
" Saved view is empty, can't do anything
if empty(l:saved_view)
return
endif
" Check wether the cursor has moved since linting was actually requested. If
" the user has indeed moved lines, do nothing
let l:current_view = winsaveview()
if l:current_view['lnum'] != l:saved_view['lnum']
return
endif
" Anchor view by topline if the list is set to open horizontally
if ale#Var(a:buffer, 'list_vertical') == 0
call winrestview({'topline': l:saved_view['topline']})
endif
endfunction
function! ale#list#SetLists(buffer, loclist) abort
if get(g:, 'ale_set_lists_synchronously') == 1
\|| getbufvar(a:buffer, 'ale_save_event_fired', 0)
" Update lists immediately if running a test synchronously, or if the
" buffer was saved.
"
" The lists need to be updated immediately when saving a buffer so
" that we can reliably close window automatically, if so configured.
call s:SetListsImpl(-1, a:buffer, a:loclist)
else
call ale#util#StartPartialTimer(
\ 0,
\ function('s:SetListsImpl'),
\ [a:buffer, a:loclist],
\)
endif
endfunction
function! ale#list#ForcePopulateErrorList(populate_quickfix) abort
let l:quickfix_bak = g:ale_set_quickfix
let g:ale_set_quickfix = a:populate_quickfix
let l:loclist_bak = g:ale_set_loclist
let g:ale_set_loclist = !a:populate_quickfix
let l:open_list_bak = g:ale_open_list
let g:ale_open_list = 1
let l:buffer = bufnr('')
let l:loclist = get(g:ale_buffer_info, l:buffer, {'loclist': []}).loclist
call s:SetListsImpl(-1, l:buffer, l:loclist)
let g:ale_open_list = l:open_list_bak
let g:ale_set_loclist = l:loclist_bak
let g:ale_set_quickfix = l:quickfix_bak
endfunction
function! s:CloseWindowIfNeeded(buffer) abort
if ale#Var(a:buffer, 'keep_list_window_open') || s:ShouldClose(a:buffer)
return
endif
let l:did_close_any_list = 0
try
" Only close windows if the quickfix list or loclist is completely empty,
" including errors set through other means.
if g:ale_set_quickfix
if empty(getqflist())
cclose
let l:did_close_any_list = 1
endif
else
let l:win_ids = s:WinFindBuf(a:buffer)
for l:win_id in l:win_ids
if g:ale_set_loclist && empty(getloclist(l:win_id))
lclose
let l:did_close_any_list = 1
endif
endfor
endif
" Ignore 'Cannot close last window' errors.
catch /E444/
endtry
if l:did_close_any_list
call s:RestoreViewIfNeeded(a:buffer)
endif
endfunction