I made a little script that does nearly what you do.
Explanations
The core concept behind it comes directly from the vim-signature plugin. Here is a step-by-step walkthrough :
- Remove all previous signs from the sign bar
- Build a list of the lines you want to show in the sign bar
- For each line, create a new sign with a unique id (based on current buffer and line number)
- For each line, display the sign (the text of the sign will be the current line)
The code below works as a proof of concept, but I wouldn't use is. You will see if you try it that it gets all flickering when you move quickly. I think the reason behind it is that the sign bar is not intended to quickly change over time.
Improvements
There are also many optimisations I though of but didn't have the time to write :
- Create the list from the beginning (as the file lenght will not change a lot very quickly) and reload the list only when needed.
- Create 10 lists with all signs created. The cursor move will only change the current list displayed.
- Call refresh only on row change (not on every cursor change)
- Obviously it display only numbers (not relative), but you cannot display more than two characters into the sign bar ...
Show me the code !
There you go :
" List of all displayed lines
let b:lines = []
" Add a line to the signbar
function! AddLine(lnum)
" create a unique id to the current sign
let l:id = a:lnum * 1000 + bufnr('%')
" Create a new sign and place it
execute 'sign define Signature_' . l:id . ' text=' . a:lnum
execute 'sign place ' . l:id . ' line=' . a:lnum . ' name=Signature_' . l:id . ' buffer=' . bufnr('%')
endfunction
function! Remove(lnum)
" Find the sign based on it's id and remove it
let l:id = a:lnum * 1000 + bufnr('%')
silent! execute 'sign unplace ' . l:id
endfunction
" Create a list of all lines on the document to display
function! GetLines(currentLine) abort
let l:c = a:currentLine % 10
while l:c <= line('$')
call add(b:lines, l:c)
let l:c += 10
endwhile
endfunction
" Get called on every cursor move, reload the signs
function! Refresh()
for j in b:lines
call Remove (j)
endfor
let b:lines = []
call GetLines(line('.'))
for j in b:lines
call AddLine(j)
endfor
endfunction
" Call the refresh method once on every cursor move
augroup CursorMove
autocmd!
autocmd CursorMoved * call Refresh()
augroup END
I made a git repo for it if you want to contribute.
:h sign
to know how to place a sign in the singbar and use it as the number bar