Wikia

Vim Tips Wiki

Talk:Highlight multiple words

1,612pages on
this wiki

Back to page

Revision as of 08:42, July 6, 2009 by Inkarkat (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

This page discusses some different approaches to the Highlight multiple words tip.

We normally put comments about a tip in the Comments section at the bottom of the tip. However this case needs something more substantial and long lasting. To make tracking the changes easier, I initially copied the entire current tip to this discussion page, and then edited the copy to rearrange and remove superfluous material (use 'history' to view changes). --JohnBeckett 08:16, 26 October 2008 (UTC)

Method 1Edit

To highlight all occurrences of the word under the cursor type \ma. To highlight another word without removing the highlighting of the first word move the cursor to the second word and type 2\ma. As many words as desired can be highlighted by giving each a different count. To remove the highlighting from a word, type <count>\md where <count> is the count given to the \ma command when highlighting the word.

Adding highlighting to a word will remove any previous highlighting with that count. For example, if the cursor is over the word 'Bob', \ma will highlight all Bobs. Moving the cursor to 'Fred' and typing \ma will remove the highlighting from Bob and apply it to Fred. Then moving the cursor to 'Bill' and typing 2\ma will add highlighting to Bill without removing it from Fred.

The script below is setup with colours defined for counts 1, 2 and 3. To add colours for more counts, or to change the existing colours, type <count>\mc and follow the prompt. See :help gui-colors for a list of likely supported colours.

Add the following to your vimrc or a plugin file:

" matchadd() priority -1 means 'hlsearch' will override the match.
function! DoHighlight(hlnum, search_term)
  call UndoHighlight(a:hlnum)
  if len(a:search_term) > 0
    let id = matchadd("hl".a:hlnum, a:search_term, -1)
    let g:matchadd_ids[a:hlnum] = id
  endif
endfunction

function! UndoHighlight(hlnum)
  silent! call matchdelete(g:matchadd_ids[a:hlnum])
endfunction

function! SetHighlight(hlnum, colour)
  if len(a:colour) > 0
    exe "highlight hl".a:hlnum." term=bold ctermfg=".a:colour." guifg=".a:colour
  endif
endfunction

let g:matchadd_ids = {}
call SetHighlight(1, 'blue')
call SetHighlight(2, 'green')
call SetHighlight(3, 'red')
nnoremap <Leader>ma :<C-u>call DoHighlight(v:count1, expand("<cword>"))<CR>
nnoremap <Leader>md :<C-u>call UndoHighlight(v:count1)<CR>
nnoremap <Leader>mc :<C-u>call SetHighlight(v:count1, input("Enter colour: "))<CR>

The above script was created by BenArmston and slightly modified by me:

  • No need for has_key() to check if we think a match exists, since silent! hides error.
  • Don't try to highlight if search_term is empty (can use \ma on a blank line to clear highlight).
  • Don't try to SetHighlight if no colour (can press Esc or Enter at input prompt to cancel).

I only got involved in this project because of the impressive result BenArmston achieved. --JohnBeckett 10:04, 6 September 2008 (UTC)

Method 2Edit

While testing, I noticed a problem. Say you split the screen and show two windows. It turns out that each window has its own set of matches, while the tip uses a single global dictionary.

Apart from any inelegancy, this gives a bug: If you use \ma to match word "one" in the first window, and then use \ma to match "two" in the second window, then you cannot remove the match of "one" (the global dictionary holds only the last id, whereas there is actually an id for the match in the first window, and an unrelated id for the match in the second.

While wondering whether there was any simple fix, I realised that we don't need a dictionary at all, because Vim maintains that info. That led to the version below. --JohnBeckett 10:04, 6 September 2008 (UTC)

" Use getmatches() rather than dictionary (works in multiple windows).
function! DoHighlight(hlnum, search_term)
  call UndoHighlight(a:hlnum)
  if len(a:search_term) > 0
    let id = matchadd('hl'.a:hlnum, a:search_term, -1)
  endif
endfunction

function! UndoHighlight(hlnum)
  silent! call matchdelete(GetId(a:hlnum))
endfunction

function! GetId(hlnum)
  for m in getmatches()
    if m['group'] == 'hl'.a:hlnum
      return m['id']
    endif
  endfor
  return 0
endfunction

function! SetHighlight(hlnum, colour)
  if len(a:colour) > 0
    exe "highlight hl".a:hlnum." term=bold ctermfg=".a:colour." guifg=".a:colour
  endif
endfunction

call SetHighlight(1, 'blue')
call SetHighlight(2, 'green')
call SetHighlight(3, 'red')
nnoremap <Leader>ma :<C-u>call DoHighlight(v:count1, expand("<cword>"))<CR>
nnoremap <Leader>md :<C-u>call UndoHighlight(v:count1)<CR>
nnoremap <Leader>mc :<C-u>call SetHighlight(v:count1, input("Enter colour: "))<CR>

Method in tipEdit

The current tip uses a script that is a little longer than we normally have on the Vim Tips wiki. However, it has some very useful features and code that I think make it worthwhile. I developed the new version because I have sometimes needed to use highlighting, yet have always found it too cumbersome to bother with in practice. When I need to highlight, it's because I'm dealing with some complex text and I can't spare the mental effort required to enter highlight groups, or press clumsy keys to invoke the highlighting. So, I have removed the cleverness of the previous scripts which use the count value to specify the required highlight. Instead, I'm using the keys on the numeric keypad. Of course that won't work on all systems, but it works extremely well on a lot of computers.

I built nine highlight groups into the script (three subtle highlights for when you don't want intrusive colors, plus six that are more prominent). A user can tweak them as required. The script could fairly easily be extended to deal with more than nine highlight groups, using the :Highlight command for larger numbers. --JohnBeckett 08:16, 26 October 2008 (UTC)

Around Wikia's network

Random Wiki