1

I am using a function in my vimrc to detect contents similar to those of a modeline and use that to highlight specific words in the file contents.

The function I'm using is from the answer to my previous question on the topic:

function! s:confhighlight()
    let l:matches = matchlist(getline('$'), '^# highlight: \(.*\)$')
    if len(l:matches)
        let s:matchid = matchadd('Todo', l:matches[1])
    endif
endfunction

How can I modify this function to highlight multiple words instead of just one expression?

You can see that here, we're trying to match \(.*\)$') but that would match only all characters till the end of the line.

I want to match words separated by spaces as below:

# highlight: first second

I expect that all matches of first and second will be highligted in the current buffer.

Thanks in advance.

  • as mentioned in your other question, this is not possible from a modeline. You need to create a custom plugin for that. – Christian Brabandt Apr 21 at 13:15
  • In link it worked for a word only, how to have it works for multiple words separated by spaces? I just need a simple script for the case, I have no power to write a vimL script/plugin. – Tuyen Pham Apr 21 at 13:17
  • 1
    read the answer again. It should work with any keyword, not just one, you just need to add several lines for every keyword you like to have highlighted – Christian Brabandt Apr 21 at 13:19
  • Does “(.*)$” only match for one word till the end of line? As I wrote in “expected” but I’ll test it again, I want all matchs contain “first” or “second” highlighted. – Tuyen Pham Apr 21 at 13:22
  • 2
    Yes and the easy solution from your other question is to add several lines. The script can be improved to allow several alternative keywords per line, but that needs some vimscript knowledge – Christian Brabandt Apr 21 at 13:26
1

As @filbranden suggested, there's a simple solution using split and a for loop, here it is:

function! ClearConfHilights()
    for id in getwinvar(win_getid(), 'confHiIds', [])
        call matchdelete(id)
    endfor
    let w:confHiIds = []
endfunction
function! Confhighlight()
    call ClearConfHilights()
    let l:raw_matches = matchlist(getline('$'), '^# highlight: \(\S.*\)$')
    if len(l:raw_matches) >= 1
        let l:matches = split(l:raw_matches[1])
        for match in l:matches
            call add(w:confHiIds, matchadd('Todo', match))
        endfor
    endif
endfunction

autocmd BufWinEnter *.conf call Confhighlight()

" To auto update highlights:
autocmd TextChanged,InsertLeave *.conf if line('.') == line('.') | call Confhighlight() | endif

" To update the highlights when you hit `<F2>`:
nnoremap <F2> :<C-u>call Confhighlight()<CR>

There are 2 functions here:

  • ClearConfHighlights
    Its role is to delete all the present conf highlights, and initialize the highlights list to an empty array.

  • Confhighlight
    Looks at the last line of the file to find (or not) the pattern # highlight: ..., and highlights the words one by one, adding them to the highlight list at the same time.

The autocmd is here to reset the highlight on buffer change


Note

As you can see, the highlight list is local to windows, and not buffers. That's because the matches created by matchadd are themselves local to windows.

| improve this answer | |
  • Looks great, thanks for taking the time to write an answer and test it! A couple of minor nitpicks: 1) You don't need to pass a pattern since split() defaults to splitting on whitespace already, so split(l:matches[1]) is enough. 2) I'd avoid reassigning it and just use it in the for directly: for match in split(l:matches[1]). Hmmm I just noticed that s:matchid now might need to be a list and you might need to clear them appropriately too? (See linked original question for that...) Cheers! – filbranden Apr 21 at 18:22
  • Thank you for your comment @filbranden, I updated my answer! – Zorzi Apr 21 at 19:13
  • Awesome, thanks! I think you're missing clearing the list if it had any elements, right? You might want to include the function that clears them later, since that one will also need to be updated. (In fact, it's just the beginning of this one, right?) (I "like" how these always snowball into something much larger than it seemed initially...) – filbranden Apr 21 at 19:34
  • 1
    Haha, as you said, the snowball effect! :) – Zorzi Apr 22 at 8:43
  • 1
    I just updated my answer to include that. – Zorzi Apr 26 at 15:02

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.