mirror of
https://github.com/SpaceVim/SpaceVim.git
synced 2025-02-14 06:48:00 +08:00
414 lines
12 KiB
VimL
414 lines
12 KiB
VimL
"=============================================================================
|
|
" checkers.vim --- SpaceVim checkers layer
|
|
" Copyright (c) 2016-2022 Wang Shidong & Contributors
|
|
" Author: Wang Shidong < wsdjeg@outlook.com >
|
|
" URL: https://spacevim.org
|
|
" License: GPLv3
|
|
"=============================================================================
|
|
|
|
""
|
|
" @section checkers, layers-checkers
|
|
" @parentsection layers
|
|
" The `checkers` layer provides syntax lint feature. The default lint engine
|
|
" is |neomake|, this can be changed by `lint_engine` option:
|
|
" >
|
|
" [options]
|
|
" lint_engine = 'ale'
|
|
" <
|
|
"
|
|
" @subsection options
|
|
"
|
|
" - `lint_on_the_fly`: Syntax checking on the fly feature, disabled by default.
|
|
" - `lint_on_save`: Run syntax checking when saving a file.
|
|
" - `show_cursor_error`: Enable/Disable displaying error below current line.
|
|
" - `lint_exclude_filetype`: Set the filetypes which does not enable syntax
|
|
" checking.
|
|
|
|
|
|
if exists('s:show_cursor_error')
|
|
finish
|
|
endif
|
|
|
|
if has('timers')
|
|
let s:show_cursor_error = 1
|
|
else
|
|
let s:show_cursor_error = 0
|
|
endif
|
|
|
|
let s:lint_exclude_filetype = []
|
|
|
|
let s:SIG = SpaceVim#api#import('vim#signatures')
|
|
let s:STRING = SpaceVim#api#import('data#string')
|
|
|
|
function! SpaceVim#layers#checkers#plugins() abort
|
|
let plugins = []
|
|
|
|
if exists('g:spacevim_enable_neomake') || exists('g:spacevim_enable_ale')
|
|
call SpaceVim#logger#warn('enable_neomake and enable_ale is duplecated', 0)
|
|
call SpaceVim#logger#warn('please read :h spacevim-options-lint_engine for more info!', 0)
|
|
endif
|
|
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
call add(plugins, [g:_spacevim_root_dir . 'bundle/neomake', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}])
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
call add(plugins, [g:_spacevim_root_dir . 'bundle/ale', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}])
|
|
elseif g:spacevim_lint_engine ==# 'syntastic'
|
|
call add(plugins, [g:_spacevim_root_dir . 'bundle/syntastic', {'merged' : 0, 'loadconf' : 1 , 'loadconf_before' : 1}])
|
|
endif
|
|
|
|
return plugins
|
|
endfunction
|
|
|
|
function! SpaceVim#layers#checkers#set_variable(var) abort
|
|
|
|
let s:show_cursor_error = get(a:var, 'show_cursor_error', 1)
|
|
let s:lint_on_the_fly = get(a:var, 'lint_on_the_fly', 1)
|
|
let s:lint_exclude_filetype = get(a:var, 'lint_exclude_filetype', [])
|
|
|
|
if s:show_cursor_error && !has('timers')
|
|
call SpaceVim#logger#warn('show_cursor_error in checkers layer needs timers feature')
|
|
let s:show_cursor_error = 0
|
|
endif
|
|
endfunction
|
|
|
|
function! SpaceVim#layers#checkers#get_options() abort
|
|
|
|
return ['show_cursor_error']
|
|
|
|
endfunction
|
|
|
|
|
|
function! SpaceVim#layers#checkers#config() abort
|
|
" neomake config
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
let g:neomake_echo_current_error = get(g:, 'neomake_echo_current_error', !s:show_cursor_error)
|
|
let g:neomake_cursormoved_delay = get(g:, 'neomake_cursormoved_delay', 300)
|
|
let g:neomake_virtualtext_current_error = get(g:, 'neomake_virtualtext_current_error', !s:show_cursor_error)
|
|
|
|
" exclude filetypes:
|
|
for ft in s:lint_exclude_filetype
|
|
let g:neomake_{ft}_enabled_makers = []
|
|
endfor
|
|
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
let g:ale_echo_delay = get(g:, 'ale_echo_delay', 300)
|
|
endif
|
|
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'c'], 'call call('
|
|
\ . string(s:_function('s:clear_errors')) . ', [])',
|
|
\ 'clear-all-errors', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'h'], '', 'describe-a-syntax-checker', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'v'], '', 'verify-syntax-checker-setup', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'n'], 'call call('
|
|
\ . string(s:_function('s:jump_to_next_error')) . ', [])',
|
|
\ 'next-error', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'l'], 'call call('
|
|
\ . string(s:_function('s:toggle_show_error')) . ', [0])',
|
|
\ 'toggle-showing-the-error-list', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'L'], 'call call('
|
|
\ . string(s:_function('s:toggle_show_error')) . ', [1])',
|
|
\ 'toggle-showing-the-error-list', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'p'], 'call call('
|
|
\ . string(s:_function('s:jump_to_previous_error')) . ', [])',
|
|
\ 'previous-error', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'N'], 'call call('
|
|
\ . string(s:_function('s:jump_to_previous_error')) . ', [])',
|
|
\ 'previous-error', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'v'], 'call call('
|
|
\ . string(s:_function('s:verify_syntax_setup')) . ', [])',
|
|
\ 'verify-syntax-setup', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', '.'], 'call call('
|
|
\ . string(s:_function('s:error_transient_state')) . ', [])',
|
|
\ 'error-transient-state', 1)
|
|
call SpaceVim#mapping#space#def('nnoremap', ['t', 's'], 'call SpaceVim#layers#core#statusline#toggle_mode("syntax-checking")',
|
|
\ 'toggle-syntax-checker', 1)
|
|
call SpaceVim#layers#core#statusline#register_mode(
|
|
\ {
|
|
\ 'key' : 'syntax-checking',
|
|
\ 'func' : s:_function('s:toggle_syntax_checker'),
|
|
\ }
|
|
\ )
|
|
call SpaceVim#mapping#space#def('nnoremap', ['e', 'e'], 'call call('
|
|
\ . string(s:_function('s:explain_the_error')) . ', [])',
|
|
\ 'explain-the-error', 1)
|
|
augroup SpaceVim_layer_checker
|
|
autocmd!
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
if SpaceVim#layers#isLoaded('core#statusline')
|
|
autocmd User NeomakeFinished nested
|
|
\ let &l:statusline = SpaceVim#layers#core#statusline#get(1)
|
|
endif
|
|
if s:show_cursor_error
|
|
" when move cursor, the error message will be shown below current line
|
|
" after a delay
|
|
autocmd CursorMoved * call <SID>neomake_cursor_move_delay()
|
|
|
|
" when switch to Insert mode, stop timer and clear the signature
|
|
if exists('##CmdLineEnter')
|
|
autocmd InsertEnter,WinLeave *
|
|
\ call <SID>neomake_signatures_clear()
|
|
autocmd CmdLineEnter *
|
|
\ call <SID>neomake_signatures_clear()
|
|
else
|
|
autocmd InsertEnter,WinLeave * call <SID>neomake_signatures_clear()
|
|
endif
|
|
endif
|
|
elseif g:spacevim_lint_engine ==# 'ale' && SpaceVim#layers#isLoaded('core#statusline')
|
|
autocmd User ALELintPost
|
|
\ let &l:statusline = SpaceVim#layers#core#statusline#get(1)
|
|
endif
|
|
augroup END
|
|
endfunction
|
|
|
|
|
|
function! SpaceVim#layers#checkers#health() abort
|
|
|
|
call SpaceVim#layers#checkers#plugins()
|
|
call SpaceVim#layers#checkers#set_variable({})
|
|
call SpaceVim#layers#checkers#get_options()
|
|
call SpaceVim#layers#checkers#config()
|
|
return 1
|
|
|
|
endfunction
|
|
|
|
|
|
function! s:neomake_cursor_move_delay() abort
|
|
call s:neomake_signatures_clear()
|
|
let s:neomake_cursormoved_timer = timer_start(g:neomake_cursormoved_delay,
|
|
\ function('s:neomake_signatures_current_error'))
|
|
endfunction
|
|
|
|
function! s:toggle_show_error(...) abort
|
|
if SpaceVim#lsp#buf_server_ready()
|
|
call SpaceVim#lsp#diagnostic_set_loclist()
|
|
else
|
|
" if buf_server_ready return false, the language server loclist
|
|
" should be cleared.
|
|
if get(getloclist(0, {'title': 0}), 'title', '') ==# 'Language Server'
|
|
call setloclist(0, [], 'r')
|
|
endif
|
|
let llist = getloclist(0, {'size' : 1, 'winid' : 1})
|
|
let qlist = getqflist({'size' : 1, 'winid' : 1})
|
|
if llist.size == 0 && qlist.size == 0
|
|
echohl WarningMsg
|
|
echon 'There is no errors!'
|
|
echohl None
|
|
return
|
|
endif
|
|
if llist.winid > 0
|
|
lclose
|
|
elseif qlist.winid > 0
|
|
cclose
|
|
elseif llist.size > 0
|
|
botright lopen
|
|
elseif qlist.size > 0
|
|
botright copen
|
|
endif
|
|
if a:1 == 1
|
|
wincmd w
|
|
endif
|
|
endif
|
|
endfunction
|
|
|
|
function! s:jump_to_next_error() abort
|
|
if SpaceVim#lsp#buf_server_ready()
|
|
call SpaceVim#lsp#diagnostic_goto_next()
|
|
else
|
|
try
|
|
lnext
|
|
catch
|
|
try
|
|
ll
|
|
catch
|
|
try
|
|
cnext
|
|
catch
|
|
try
|
|
cc
|
|
catch
|
|
echohl WarningMsg
|
|
echon 'There is no errors!'
|
|
echohl None
|
|
endtry
|
|
endtry
|
|
endtry
|
|
endtry
|
|
endif
|
|
endfunction
|
|
|
|
function! s:jump_to_previous_error() abort
|
|
if SpaceVim#lsp#buf_server_ready()
|
|
call SpaceVim#lsp#diagnostic_goto_prev()
|
|
else
|
|
try
|
|
lprevious
|
|
catch
|
|
try
|
|
ll
|
|
catch
|
|
try
|
|
cprevious
|
|
catch
|
|
try
|
|
cc
|
|
catch
|
|
echohl WarningMsg
|
|
echon 'There is no errors!'
|
|
echohl None
|
|
endtry
|
|
endtry
|
|
endtry
|
|
endtry
|
|
endif
|
|
endfunction
|
|
|
|
let s:last_echoed_error = ''
|
|
function! s:neomake_signatures_current_error(...) abort
|
|
call s:neomake_signatures_clear()
|
|
try
|
|
let message = neomake#GetCurrentErrorMsg()
|
|
catch /^Vim\%((\a\+)\)\=:E117/
|
|
let message = ''
|
|
endtry
|
|
if empty(message)
|
|
if exists('s:last_echoed_error')
|
|
unlet s:last_echoed_error
|
|
endif
|
|
return
|
|
endif
|
|
if exists('s:last_echoed_error')
|
|
\ && s:last_echoed_error == message
|
|
return
|
|
endif
|
|
let s:last_echoed_error = message
|
|
if len(line('.') + 1) > len(message)
|
|
let message = s:STRING.fill(message, len(line('.') + 1))
|
|
endif
|
|
call s:SIG.info(line('.') + 1, 1, message)
|
|
endfunction
|
|
|
|
function! s:neomake_signatures_clear() abort
|
|
if exists('s:neomake_cursormoved_timer') && s:neomake_cursormoved_timer != 0
|
|
call timer_stop(s:neomake_cursormoved_timer)
|
|
endif
|
|
let s:last_echoed_error = ''
|
|
call s:SIG.clear()
|
|
endfunction
|
|
|
|
function! s:verify_syntax_setup() abort
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
NeomakeInfo
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
else
|
|
endif
|
|
endfunction
|
|
|
|
function! s:toggle_syntax_checker() abort
|
|
call SpaceVim#layers#core#statusline#toggle_section('syntax checking')
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
verbose NeomakeToggle
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
ALEToggle
|
|
endif
|
|
return 1
|
|
endfunction
|
|
|
|
|
|
function! s:explain_the_error() abort
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
try
|
|
let message = neomake#GetCurrentErrorMsg()
|
|
catch /^Vim\%((\a\+)\)\=:E117/
|
|
let message = ''
|
|
endtry
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
try
|
|
"@bug wrong func to get ale error message
|
|
let message = neomake#GetCurrentErrorMsg()
|
|
catch /^Vim\%((\a\+)\)\=:E117/
|
|
let message = ''
|
|
endtry
|
|
endif
|
|
if !empty(message)
|
|
echo message
|
|
else
|
|
echo 'no error message at this point!'
|
|
endif
|
|
endfunction
|
|
|
|
function! s:error_transient_state() abort
|
|
if g:spacevim_lint_engine ==# 'neomake'
|
|
let num_errors = neomake#statusline#LoclistCounts()
|
|
elseif g:spacevim_lint_engine ==# 'ale'
|
|
let counts = ale#statusline#Count(buffer_name('%'))
|
|
let num_errors = counts.error + counts.warning + counts.style_error
|
|
\ + counts.style_warning
|
|
else
|
|
let num_errors = 0
|
|
endif
|
|
if empty(num_errors)
|
|
echo 'no buffers contain error message locations'
|
|
return
|
|
endif
|
|
let state = SpaceVim#api#import('transient_state')
|
|
call state.set_title('Error Transient State')
|
|
call state.defind_keys(
|
|
\ {
|
|
\ 'layout' : 'vertical split',
|
|
\ 'left' : [
|
|
\ {
|
|
\ 'key' : 'n',
|
|
\ 'desc' : 'next error',
|
|
\ 'func' : '',
|
|
\ 'cmd' : 'try | lnext | catch | endtry',
|
|
\ 'exit' : 0,
|
|
\ },
|
|
\ ],
|
|
\ 'right' : [
|
|
\ {
|
|
\ 'key' : ['p', 'N'],
|
|
\ 'desc' : 'previous error',
|
|
\ 'func' : '',
|
|
\ 'cmd' : 'try | lprevious | catch | endtry',
|
|
\ 'exit' : 0,
|
|
\ },
|
|
\ {
|
|
\ 'key' : 'q',
|
|
\ 'desc' : 'quit',
|
|
\ 'func' : '',
|
|
\ 'cmd' : '',
|
|
\ 'exit' : 1,
|
|
\ },
|
|
\ ],
|
|
\ }
|
|
\ )
|
|
call state.open()
|
|
endfunction
|
|
|
|
" function() wrapper
|
|
if v:version > 703 || v:version == 703 && has('patch1170')
|
|
function! s:_function(fstr) abort
|
|
return function(a:fstr)
|
|
endfunction
|
|
else
|
|
function! s:_SID() abort
|
|
return matchstr(expand('<sfile>'), '<SNR>\zs\d\+\ze__SID$')
|
|
endfunction
|
|
let s:_s = '<SNR>' . s:_SID() . '_'
|
|
function! s:_function(fstr) abort
|
|
return function(substitute(a:fstr, 's:', s:_s, 'g'))
|
|
endfunction
|
|
endif
|
|
|
|
" TODO clear errors
|
|
function! s:clear_errors() abort
|
|
if SpaceVim#lsp#buf_server_ready()
|
|
call SpaceVim#lsp#diagnostic_clear()
|
|
if get(getloclist(0, {'title': 0}), 'title', '') ==# 'Language Server'
|
|
call setloclist(0, [], 'r')
|
|
endif
|
|
else
|
|
sign unplace *
|
|
endif
|
|
endfunction
|