1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-03-13 18:25:42 +08:00
2020-06-13 14:06:35 +08:00

378 lines
12 KiB
VimL
Vendored

" vim: ts=4 sw=4 et
scriptencoding utf-8
let s:is_enabled = 0
let s:match_base_priority = 10
" args: a:1: force enabling? (used in tests and for VimEnter callback)
function! neomake#quickfix#enable(...) abort
if has('vim_starting') && !(a:0 && a:1)
" Delay enabling for our FileType autocommand to happen as late as
" possible, since placing signs triggers a redraw, and together with
" vim-qf_resize this causes flicker.
" https://github.com/vim/vim/issues/2763
augroup neomake_qf
autocmd!
autocmd VimEnter * call neomake#quickfix#enable(1)
augroup END
return
endif
call neomake#log#debug('enabling custom quickfix list handling.')
let s:is_enabled = 1
augroup neomake_qf
autocmd!
autocmd FileType qf if get(b:, 'current_syntax', '') !=# 'neomake_qf'
\ | call neomake#quickfix#FormatQuickfix()
\ | endif
augroup END
if &filetype ==# 'qf'
call neomake#quickfix#FormatQuickfix()
endif
endfunction
function! neomake#quickfix#disable() abort
call neomake#log#debug('disabling custom quickfix list handling.')
let s:is_enabled = 0
if &filetype ==# 'qf'
call neomake#quickfix#FormatQuickfix()
endif
if exists('#neomake_qf')
autocmd! neomake_qf
augroup! neomake_qf
endif
endfunction
function! neomake#quickfix#is_enabled() abort
return s:is_enabled
endfunction
function! s:highlight_cursor_listnr() abort
if col('.') <= b:neomake_start_col + 1
call cursor(line('.'), b:neomake_start_col + 2)
endif
" Update neomakeCursorListNr, but not with :syntax-off.
if empty(get(b:, 'current_syntax', ''))
return
endif
if exists('w:_neomake_cursor_match_id')
silent! call matchdelete(w:_neomake_cursor_match_id)
endif
if exists('*matchaddpos')
let w:_neomake_cursor_match_id = matchaddpos('neomakeCursorListNr',
\ [[line('.'), (b:neomake_start_col - b:neomake_number_len) + 2, b:neomake_number_len]],
\ s:match_base_priority+3)
else
let w:_neomake_cursor_match_id = matchadd('neomakeCursorListNr',
\ '\%' . line('.') . 'c'
\. '\%' . ((b:neomake_start_col - b:neomake_number_len) + 2) . 'c'
\. '.\{' . b:neomake_number_len . '}',
\ s:match_base_priority+3)
endif
endfunction
function! s:set_qf_lines(lines) abort
let ul = &l:undolevels
setlocal modifiable nonumber undolevels=-1
call setline(1, a:lines)
let &l:undolevels = ul
setlocal nomodifiable nomodified
endfunction
function! s:clean_qf_annotations() abort
call neomake#log#debug('cleaning qf annotations.', {'bufnr': bufnr('%')})
if exists('b:_neomake_qf_orig_lines')
call s:set_qf_lines(b:_neomake_qf_orig_lines)
unlet b:_neomake_qf_orig_lines
endif
unlet b:neomake_qf
augroup neomake_qf
autocmd! * <buffer>
augroup END
call s:clean_matches()
endfunction
function! s:clean_matches() abort
if exists('w:_neomake_maker_match_id')
silent! call matchdelete(w:_neomake_maker_match_id)
endif
if exists('w:_neomake_gutter_match_id')
silent! call matchdelete(w:_neomake_gutter_match_id)
endif
if exists('w:_neomake_bufname_match_id')
silent! call matchdelete(w:_neomake_bufname_match_id)
endif
if exists('w:_neomake_cursor_match_id')
silent! call matchdelete(w:_neomake_cursor_match_id)
endif
call neomake#signs#ResetFile(bufnr('%'))
endfunction
function! neomake#quickfix#_get_list() abort
if has('patch-7.4.2215')
let is_loclist = getwininfo(win_getid())[0].loclist
if is_loclist
let qflist = getloclist(0)
else
let qflist = getqflist()
endif
else
let is_loclist = 1
let qflist = getloclist(0)
if empty(qflist)
let is_loclist = 0
let qflist = getqflist()
endif
endif
return [is_loclist, qflist]
endfunction
function! neomake#quickfix#FormatQuickfix() abort
if !s:is_enabled || &filetype !=# 'qf'
if exists('b:neomake_qf')
call s:clean_qf_annotations()
endif
return
endif
let [is_loclist, qflist] = neomake#quickfix#_get_list()
if empty(qflist) || qflist[0].text !~# ' nmcfg:{.\{-}}$'
if exists('b:neomake_qf')
call neomake#log#debug('Resetting custom qf for non-Neomake change.')
call s:clean_qf_annotations()
endif
return
endif
if is_loclist
let b:neomake_qf = 'file'
let src_buf = qflist[0].bufnr
else
let b:neomake_qf = 'project'
let src_buf = 0
endif
let lines = []
let signs = []
let i = 0
let lnum_width = 0
let col_width = 0
let maker_width = 0
let nmcfg = {}
let makers = {}
for item in qflist
" Look for marker at end of entry.
if item.text[-1:] ==# '}'
let idx = strridx(item.text, ' nmcfg:{')
if idx != -1
let config = item.text[idx+7:]
try
let nmcfg = eval(config)
if !has_key(makers, nmcfg.name)
let makers[nmcfg.name] = 0
endif
let item.text = idx == 0 ? '' : item.text[:(idx-1)]
catch
call neomake#log#exception(printf(
\ 'Error when evaluating nmcfg (%s): %s.',
\ config, v:exception))
endtry
endif
endif
" Count entries.
if !empty(nmcfg)
let makers[nmcfg.name] += 1
endif
let item.maker_name = get(nmcfg, 'short', '????')
let maker_width = max([len(item.maker_name), maker_width])
if item.lnum
let lnum_width = max([len(item.lnum), lnum_width])
let col_width = max([len(item.col), col_width])
endif
let i += 1
endfor
let syntax = keys(makers)
if src_buf
for ft in split(neomake#compat#getbufvar(src_buf, '&filetype', ''), '\.')
if !empty(ft) && index(syntax, ft) == -1
call add(syntax, ft)
endif
endfor
endif
let current_syntax = get(b:, 'current_syntax', '')
if !empty(current_syntax) " not with :syntax-off.
runtime! syntax/neomake/qf.vim
for name in syntax
execute 'runtime! syntax/neomake/'.name.'.vim '
\ . 'syntax/neomake/'.name.'/*.vim'
endfor
endif
if maker_width + lnum_width + col_width > 0
let b:neomake_start_col = maker_width + lnum_width + col_width + 2
let b:neomake_number_len = lnum_width + col_width + 2
let blank_col = repeat(' ', lnum_width + col_width + 1)
else
let b:neomake_start_col = 0
let b:neomake_number_len = 0
let blank_col = ''
endif
" Count number of different buffers and cache their names.
let buffers = neomake#compat#uniq(sort(
\ filter(map(copy(qflist), 'v:val.bufnr'), 'v:val != 0')))
let buffer_names = {}
if len(buffers) > 1
for b in buffers
let bufname = bufname(b)
if empty(bufname)
let bufname = 'buf:'.b
else
let bufname = fnamemodify(bufname, ':t')
if len(bufname) > 15
let bufname = bufname[0:13].'…'
endif
endif
let buffer_names[b] = bufname
endfor
endif
let i = 1
let buf = bufnr('%')
let last_bufnr = -1
for item in qflist
if item.lnum
call add(signs, {'lnum': i, 'bufnr': buf, 'type': item.type})
endif
let i += 1
let text = item.text
if item.bufnr != 0 && !empty(buffer_names)
if last_bufnr != item.bufnr
let text = printf('[%s] %s', buffer_names[item.bufnr], text)
let last_bufnr = item.bufnr
endif
endif
if !item.lnum
call add(lines, printf('%*s %s %s',
\ maker_width, item.maker_name,
\ blank_col, text))
else
call add(lines, printf('%*s %*s:%*s %s',
\ maker_width, item.maker_name,
\ lnum_width, item.lnum,
\ col_width, item.col ? item.col : '-',
\ text))
endif
endfor
if !exists('b:_neomake_qf_orig_lines')
let b:_neomake_qf_orig_lines = getbufline('%', 1, '$')
endif
call s:set_qf_lines(lines)
if exists('+breakindent')
" Keeps the text aligned with the fake gutter.
setlocal breakindent linebreak
let &breakindentopt = 'shift:'.(b:neomake_start_col + 1)
endif
call neomake#signs#Reset(buf, 'file')
call neomake#signs#PlaceSigns(buf, signs, 'file')
augroup neomake_qf
autocmd! * <buffer>
autocmd CursorMoved <buffer> call s:highlight_cursor_listnr()
if !empty(current_syntax) " not with :syntax-off.
call s:add_window_matches(maker_width)
" Annotate in new window, e.g. with "tab sp".
" It keeps the syntax there, so should also have the rest.
" This happens on Neovim already through CursorMoved being invoked
" always then.
if exists('##WinNew')
exe 'autocmd WinNew <buffer> call s:add_window_matches('.maker_width.')'
endif
" Clear matches when opening another buffer in the same window, with
" the original window/buffer still being visible (e.g. in another
" tab).
autocmd BufLeave <buffer> call s:on_bufleave()
endif
augroup END
" Set title.
" Fallback without patch-7.4.2200, fix for without 8.0.1831.
if !has('patch-7.4.2200') || !exists('w:quickfix_title') || w:quickfix_title[0] ==# ':'
let maker_info = []
for [maker, c] in items(makers)
call add(maker_info, maker.'('.c.')')
endfor
let maker_info_str = join(maker_info, ', ')
if is_loclist
let prefix = 'file'
else
let prefix = 'project'
endif
let w:quickfix_title = neomake#list#get_title(prefix, src_buf, maker_info_str)
endif
endfunction
function! s:on_bufleave() abort
let s:left_winnr = winnr()
augroup neomake_qf
autocmd BufEnter * call s:on_bufenter_after_bufleave()
augroup END
endfunction
function! s:on_bufenter_after_bufleave() abort
if winnr() == s:left_winnr
call s:clean_matches()
endif
unlet s:left_winnr
augroup neomake_qf
autocmd! BufEnter
augroup END
endfunction
function! s:add_window_matches(maker_width) abort
if !b:neomake_start_col
return
endif
if exists('w:_neomake_maker_match_id')
silent! call matchdelete(w:_neomake_maker_match_id)
endif
let w:_neomake_maker_match_id = matchadd('neomakeMakerName',
\ '.*\%<'.(a:maker_width + 1).'c',
\ s:match_base_priority+1)
if exists('w:_neomake_gutter_match_id')
silent! call matchdelete(w:_neomake_gutter_match_id)
endif
let w:_neomake_gutter_match_id = matchadd('neomakeListNr',
\ '\%>'.(a:maker_width).'c'
\ .'.*\%<'.(b:neomake_start_col + 2).'c',
\ s:match_base_priority+2)
if exists('w:_neomake_bufname_match_id')
silent! call matchdelete(w:_neomake_bufname_match_id)
endif
let w:_neomake_bufname_match_id = matchadd('neomakeBufferName',
\ '.*\%<'.(a:maker_width + 1).'c',
\ s:match_base_priority+3)
call s:highlight_cursor_listnr()
endfunction