Reputation:
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
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
.
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