user11810714
user11810714

Reputation:

How to change a specific line number color in Vim

I've been wanted to do this for a while, sometimes when I have a file open I want to be able to highlight certain line numbers to a different color. For example, say my LineNr is blue, and my Current LineNr is red. Say I'm on line 25, is there anyway I can change the LineNr color of lines 28-30 to green WITHOUT leaving my current line?

Upvotes: 2

Views: 1197

Answers (1)

perelo
perelo

Reputation: 495

As a quick answer, if you don't mind highlighting only by groups of at most 8 lignes at once, you can use the matchaddpos({group}, {pos}) function and create a command to apply a highlight group to a range of lines.

command! -range -nargs=1 -complete=highlight HiLine call matchaddpos(<f-args>, range(<line1>,<line2>))

Which you can use, for example to highlight as 'cursorline' :

:28,30HiLine CursorLine

Note that completion applies on the argument for highlight groups.

To remove the group(s) of previously highlighted lines you could remove thoses that contains a particular line. I can't find a simpler way than to go through all getmatches() dicts and matchdelete({id}) the ones that contains the line on one of their 'posX' key :

function! s:RemoveMatchOnLine(line) abort
  for l:match in getmatches()
    let l:matchlines = values(filter(copy(l:match), 'v:key =~# ''pos\d\+'''))
    if index(l:matchlines, [a:line]) >= 0
      call matchdelete(l:match['id'])
    endif
  endfor
endfunction
command! -nargs=? LoLine call <SID>RemoveMatchOnLine(<q-args> ? <q-args> : line('.'))

Now, you can :LoLine to undo the highlighting on lines near the current line, or you can give it an argument to specify another line, so you don't have to move your cursor there : :LoLine 28.

Finally, you can set mappings :

nnoremap <leader>hi :HiLine CursorLine<CR>
xnoremap <leader>hi :HiLine CursorLine<CR>
nnoremap <leader>hc :<c-u>execute 'LoLine ' . v:count<CR>

Typing [count]<leader>hi in normal mode will highlight count lines from the cursor. And [count]<leader>hc will remove the highlighting on the group of line count.

Addendum

We could work on larger ranges using matchadd({group}, {pattern}), using \%xl to match line x. Replace call matchaddpos(... by

execute 'call matchadd(<f-args>, ''\%'.<line1>.'l\(.*\n\)\+\%'.(<line2>+1).'l'')'

and line 2 and 3 of the function by

let l:a = matchlist(get(l:match,'pattern',''), '^\\%\(\d\+\)l.*\\%\(\d\+\)l$')
if !empty(l:a) && l:a[1] <= a:line && a:line <= l:a[2]

But for me it breaks on large ranges, I would prefer to have the first solution which seems more robust.

Upvotes: 2

Related Questions