2

Is it possible to automatically create a highlight which is the reverse of an existing highlight? Example highlight Search guifg=Black guibg=Yellow, becomes highlight CustomHighlight guifg=Yellow guibg=Black.

I would want to use this to highlight certain text so that it would look like the inverse of whatever the user has set as their search highlight color. Could vimscript be used to achieve this effect?

3 Answers 3

2

This is certainly possible, but it requires a bit of VimScript. The following function does the basic thing:

func SwapHiGroup(group)
    let id = synIDtrans(hlID(a:group))
    for mode in ['cterm', 'gui']
        for g in ['fg', 'bg']
            exe 'let '. mode.g. "=  synIDattr(id, '".
                        \ g."#', '". mode. "')"
            exe "let ". mode.g. " = empty(". mode.g. ") ? 'NONE' : ". mode.g
        endfor
    endfor
    exe printf('hi %s ctermfg=%s ctermbg=%s guifg=%s guibg=%s', a:group, ctermbg, ctermfg, guibg, guifg)
endfunc

The idea is, to query the syntax attributes using the function synIDattr(). However you need to query each attribute (like 'fg', 'bg', etc) separately. In addition you need to do this separately for the different modes (like 'term', 'cterm', 'gui'), etc. So the whole function is a bit tedious to write. Therefore I made the function dynamically assign the different variables 'ctermfg', 'ctermbg', 'guifg' and 'guibg'. However this makes quoting a bit nasty :(

Note also, the use of querying the attributes with a # (e.g. fg# instead of fg) will translate color names into the RGB color specification. But that shouldn't be a problem in practice.

In an ideal world, you also would need to query the basic terminal mode term (which I left out here) and the additional attributes like 'strike', 'underline', 'undercurl', 'bold', 'italic', etc. This becomes additional fun if you find the attribute 'inverse' or 'reverse' :) In addition, you'd need to add some error handling as well.

Note, I would not recommend the use of execute(), since this depends on parsing the output of the command, which might wrap (on small screen sizes) or add newlines or might even be translated.

And finally, one remark I learned from my work as the vim-airline maintainer. A function that queries all the syntax attributes of a highlighting group several times and executes a new :hi statement, might slow down Vim considerably, if this happens often. vim-airline does this e.g. when evaluating the statusline and dynamically changes the colors of several highlighting groups and this has been the cause of many performance issues. So be careful with this.

4
  • which might wrap (on small screen sizes) or add newlines or might even be translated I admit that execute() is a bit lazy, but Vim adds newlines only at WORDs' ends, so they can't break matchstr(), at least for a carefully written pattern. And I can't even imagine that guifg= and such will get ever translated in the output.
    – Matt
    Commented Oct 18, 2019 at 7:29
  • 1
    yeah, your example should be fine, but it is a bit hacky by parsing the screen output. But it was more meant as a general note, that execute() might have unexpected results. Commented Oct 18, 2019 at 7:37
  • 1
    Therefore I made the function dynamically assign the different variables 'ctermfg', 'ctermbg', 'guifg' and 'guibg'. However this makes quoting a bit nasty :( It makes sense to use :h curly-braces-names: let {mode}{g} = empty({mode}{g}) ? 'NONE' : {mode}{g} and so on.
    – Matt
    Commented Oct 18, 2019 at 9:49
  • oh yes, I always forgot about those Commented Oct 18, 2019 at 10:04
1

Not sure if it's a good idea at all, but it's certainly possible:

function! HiliteSwap(group)
    let l:hi = execute('hi ' . a:group)
    let l:ctermfg = matchstr(l:hi, 'ctermfg=\zs\S*')
    let l:ctermbg = matchstr(l:hi, 'ctermbg=\zs\S*')
    let l:guifg = matchstr(l:hi, 'guifg=\zs\S*')
    let l:guibg = matchstr(l:hi, 'guibg=\zs\S*')
    call execute(printf("hi %s ctermfg=%s ctermbg=%s guifg=%s guibg=%s", a:group, l:ctermbg, l:ctermfg, l:guibg, l:guifg))
endfunction
1
  • I'm curious why your answer here doesn't include your advice on @Christian-Brabandt's answer above? "empty({mode}{g}) ? 'NONE' : {mode}{g}". Seems to me that it needs it, esp for groups that don't define all attributes. Commented Aug 1, 2021 at 22:10
0

Referencing: Is it possible to automatically invert the cursor color or current line color color in gvim, just use one of these two.

highlight Search gui=reverse
highlight Search gui=inverse

Reference to the help: :help inverse

Your Answer

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

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