5

Is it possible to show every n relative line numbers? So for example, I can see a a (+/-) 10, 20, 30... instead of a value on every line.

If there's no current way to do it, is it possible to create? i.e. can a plugin programmically change the line numbers shown?

  • 1
    I don't think you can do it without a little bit of scripting. You can look at :h sign to know how to place a sign in the singbar and use it as the number bar – nobe4 Aug 12 '15 at 14:39
4

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 :

  1. Remove all previous signs from the sign bar
  2. Build a list of the lines you want to show in the sign bar
  3. For each line, create a new sign with a unique id (based on current buffer and line number)
  4. 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 :

  1. Create the list from the beginning (as the file lenght will not change a lot very quickly) and reload the list only when needed.
  2. Create 10 lists with all signs created. The cursor move will only change the current list displayed.
  3. Call refresh only on row change (not on every cursor change)
  4. 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.

3

You can use my DynamicSigns plugin.

First Define a function like this:

fu! CustomSignExpression(lnum, div)
    if a:lnum < line('w0') || a:lnum > line ('w$')
        return 0
    endif
    if !exists("#SignExpression#CursorMoved")
        augroup SignExpression
            au!
            au CursorMoved * :Signs
        augroup end
    endif
    let part=abs(a:lnum - line('.'))
    if part % a:div == 0
        return part > 99 ? 99 : part
    else
        return 0
    endif
endfu

Now you simply call :SignExpression CustomSignExpression(v:lnum, 5) if you want to have every fifth line a relative number.

The autocommand is there to make sure, the signs are redrawn on cursor movement (which by default only happens on text changes to not impact performance negatively). This means, that it might affect redraw performance of your Vim especially for larger Files and screen sizes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.