0

Is it possible to do more complex coloring than using regexes in Vim? I'm interested in implementing a feature in vim-flog where a commit and all its ancestors would be colored. That means the exact same regex could match two different lines, where only the commit hash on each line goes through a custom function to determine what its color should be. Is that possible in Vim?

If not using syntax highlighting, what would be some ways that would allow us to easy visualize whether each commit passes the given predicate? Is it possible to bold lines, or set the background color for specific lines through a predicate function?

2
  • Text properties or other things (match?) might get you there. Strictly speaking, syntax highlighting in vim is more powerful than just re because it can be recursive, but it is hard to get right (and if is regex based, as you note)
    – D. Ben Knoble
    Feb 7, 2021 at 15:07
  • You can maybe use \%l to match a specific line number (see :help \%l)? Not entirely sure if that will work in your case. Feb 8, 2021 at 0:39

1 Answer 1

2

There's no built in way to do what you want to do, but you can build your way there with some vimscript.

Here's an example:

function! Tester(line)
    if match(a:line, '(.*)') >= 0
        return '(.*)'
    endif
    if match(a:line, '\.') >= 0
        return '\.\S*'
    endif
    return ''
endfunction

function! Recolor()
    call clearmatches()

    let linecnt = 0
    while linecnt < line('$')
        let linecnt += 1
        let expr = Tester(getline(linecnt))
        if len(expr) > 0
            call matchadd('Comment', '\%'.linecnt.'l'.expr)
        endif
    endwhile
endfunction

I have 2 functions:

  • Tester - It will be called for each line, and should return the coloration regex for this line
  • Recolor - This is the main function, in charge of recoloring

So here, in my Tester function, for example, I say:

  • If my line contains braces ((.*)): highlight the braces
  • Else, if my line contains a dot (\.): highlight the dot and everything after, until I meet a blank character
  • Else, don't highlight anything

Here's what the result looks like for a small Typescript example: Example


You should keep in mind that this solution is bound to the window, so if the window changes, it will disappear. Also, if the content of the buffer changes, it might mess up the coloration, since everything is based on line numbers.

What you could do to avoid those problems would be to add a few autocmd, like:

autocmd BufWinEnter,WinEnter,WinNew,TextChanged,TextChangedI * call Recolor()

It might be pretty heavy to do that though, you might want to add some caching!

1
  • 1
    If the autocmd causes lag, then before implementing caching, it might be worth trying adding CursorMoved to the list of autocommand triggers and only running the code for the lines that are visible in the window: if you're updating whenever the visible content changes, there's no point updating the colours for parts of the buffer that are not currently visible on screen.
    – Rich
    Feb 10, 2021 at 13:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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