0

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?

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.

| improve this answer | |
  • 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 Oct 18 '19 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. – Christian Brabandt Oct 18 '19 at 7:37
  • 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 Oct 18 '19 at 9:49
  • oh yes, I always forgot about those – Christian Brabandt Oct 18 '19 at 10:04
0

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
| improve this answer | |

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.