-
-
Save BoltsJ/5942ecac7f0b0e9811749ef6e19d2176 to your computer and use it in GitHub Desktop.
| if exists('g:loaded_qfsign') | |
| finish | |
| endif | |
| let g:loaded_qfsign=1 | |
| sign define QFErr texthl=QFErrMarker text=E | |
| sign define QFWarn texthl=QFWarnMarker text=W | |
| sign define QFInfo texthl=QFInfoMarker text=I | |
| augroup qfsign | |
| autocmd! | |
| autocmd QuickFixCmdPre [^l]* call s:clear_signs() | |
| autocmd QuickFixCmdPost [^l]* call s:place_signs() | |
| augroup END | |
| nnoremap <Plug>(QfSignPlace) :silent call <SID>place_signs()<CR> | |
| nnoremap <Plug>(QfSignClear) :silent call <SID>clear_signs()<CR> | |
| let s:sign_count = 0 | |
| function! s:place_signs() abort | |
| let l:errors = getqflist() | |
| for l:error in l:errors | |
| if l:error.bufnr < 0 | |
| continue | |
| endif | |
| let s:sign_count = s:sign_count + 1 | |
| if l:error.type ==# 'E' | |
| let l:err_sign = 'sign place ' . s:sign_count | |
| \ . ' line=' . l:error.lnum | |
| \ . ' name=QFErr' | |
| \ . ' buffer=' . l:error.bufnr | |
| elseif l:error.type ==# 'W' | |
| let l:err_sign = 'sign place ' . s:sign_count | |
| \ . ' line=' . l:error.lnum | |
| \ . ' name=QFWarn' | |
| \ . ' buffer=' . l:error.bufnr | |
| else | |
| let l:err_sign = 'sign place ' . s:sign_count | |
| \ . ' line=' . l:error.lnum | |
| \ . ' name=QFInfo' | |
| \ . ' buffer=' . l:error.bufnr | |
| endif | |
| silent! execute l:err_sign | |
| endfor | |
| endfunction | |
| function! s:clear_signs() abort | |
| while s:sign_count > 0 | |
| execute 'sign unplace ' . s:sign_count | |
| let s:sign_count = s:sign_count - 1 | |
| endwhile | |
| redraw! | |
| endfunction |
I added some <Plug> mappings that can be mapped, but this gist is mostly just a minimal example of working with signs.
This is really neat! Thank you for sharing.
A few improvements I've made that I would like to share:
Filter out text unmatched by errorformat
In cases where linter/compiler output doesn't match errorformat exactly, getqflist() still reports it, causing the unmatched output to be calculated/reported in the final else control flow.
For example, consider the following tflint.vim compiler configuration:
CompilerSet makeprg=tflint\ --format=compact\ $*
CompilerSet errorformat=%f:%l:%c:\ %trror\ -\ %m,%f:%l:%c:\ %tarning\ -\ %m,%f:%l:%c:\ -\ %totice\ %mAnd the following terraform file:
data "" "" {}Running :make % produces:
2 issue(s) found:
data.tf:1:1: Warning - Missing version constraint for provider "" in "required_providers" (terraform_required_providers)
data.tf:1:1: Warning - data "" "" is declared but not used (terraform_unused_declarations)Running :echo getqflist() in vim produces (note the first 2 elements in the array):
[
{
"lnum": 0,
"bufnr": 0,
"end_lnum": 0,
"pattern": "",
"valid": 0,
"vcol": 0,
"nr": -1,
"module": "",
"type": "",
"end_col": 0,
"col": 0,
"text": "2 issue(s) found:"
},
{
"lnum": 0,
"bufnr": 0,
"end_lnum": 0,
"pattern": "",
"valid": 0,
"vcol": 0,
"nr": -1,
"module": "",
"type": "",
"end_col": 0,
"col": 0,
"text": ""
},
{
"lnum": 1,
"bufnr": 1,
"end_lnum": 0,
"pattern": "",
"valid": 1,
"vcol": 0,
"nr": -1,
"module": "",
"type": "W",
"end_col": 0,
"col": 1,
"text": "Missing version constraint for provider \"\" in \"required_providers\" (terraform_required_providers)"
},
{
"lnum": 1,
"bufnr": 1,
"end_lnum": 0,
"pattern": "",
"valid": 1,
"vcol": 0,
"nr": -1,
"module": "",
"type": "W",
"end_col": 0,
"col": 1,
"text": "data \"\" \"\" is declared but not used (terraform_unused_declarations)"
}
]A simple fix is to check if bufnr <= 0 (is buffer number of 0 even possible?), like:
if l:error.bufnr <= 0
continue
endifAlternative, you can check if lnum is 0 (because why/how would you show signs for something with no line number?), like:
if l:error.bufnr < 0 || l:error.lnum == 0
continue
endifSign Priority
Signs were not showing up in my signcolumn. This was because Vim assigns a default priority of 10 for signs (:h sign-place). Priority helps Vim determine which sign to show when multiple signs are placed on the same line. This scenario happes easily & frequently with plugins like vim-signify or vim-gitgutter.
I fixed this by assigning a priority of 99 to errors, 98 to warnings, and 97 to info, because I much rather see issues with code than git status indicators in my signcolumn, like this:
if l:error.type ==# 'E'
let l:qf_sign = 'sign place ' . s:sign_count
\ . ' priority=99'
" ...
elseif l:error.type ==# 'W'
let l:qf_sign = 'sign place ' . s:sign_count
\ . ' priority=98'
" ...
else
let l:qf_sign = 'sign place ' . s:sign_count
\ . ' priority=97'
" ...Note: priority must be specified/assigned before file= or buffer=.
" this works
:sign place priority=99 line=1 name=QFErr buffer=1
" this does not ¯\_(ツ)_/¯
:sign place line=1 name=QFErr buffer=1 priority=99Support location lists
" ...
autocmd QuickFixCmdPre * call s:clear_signs()
autocmd QuickFixCmdPost [^l]* call s:place_signs('qf')
autocmd QuickFixCmdPost l* call s:place_signs('ll')
" ...
function! s:place_signs(list_type) abort
if a:list_type == 'qf'
let l:errors = getqflist()
elseif a:list_type == 'll'
let l:errors = getloclist(winnr())
endif
" ...Surface counts to vimrc
I placed this script in my ~/.vim/plugin/ directory and wanted to surface the count of errors/warnings/infos to show in my statusline.
" ...
let s:sign_count = 0
" Surface counts to .vimrc
let g:qfsigns_error = 0
let g:qfsigns_warn = 0
let g:qfsigns_info = 0
" ...
function! s:place_signs(list_type) abort
let l:qfsigns_error = 0
let l:qfsigns_warn = 0
let l:qfsigns_info = 0
for l:error in l:errors
" ...
if l:error.type ==# 'E'
let l:qfsigns_error = l:qfsigns_error + 1
" ...
elseif l:error.type ==# 'W'
let l:qfsigns_warn = l:qfsigns_warn + 1
" ...
else
let l:qfsigns_info = l:qfsigns_info + 1
" ...
endfor
let g:qfsigns_error = l:qfsigns_error
let g:qfsigns_warn = l:qfsigns_warn
let g:qfsigns_info = l:qfsigns_info
endfunctionThen in my vimrc:
set statusline+=%#QFErrMarker#%{(g:qfsigns_error>0)?'[E:'.g:qfsigns_error.']':''}%*
set statusline+=%#QFWarnMarker#%{(g:qfsigns_warn>0)?'[W:'.g:qfsigns_warn.']':''}%*
set statusline+=%#QFInfoMarker#%{(g:qfsigns_info>0)?'[I:'.g:qfsigns_info.']':''}%*Everything put together: https://gist.github.com/pbnj/dc19a2d0f579933daef7f0fd9604dc0c
Hi @BoltsJ , thanks for the script and for the youtube channel!
question: is it possible to do so that the signs would be hidden/shown by a combination of keys?