views:

166

answers:

2

I would like to tidy up my Vim color scheme file, by replacing #ABCDEF colors with variables. For example, I would like to replace this:

highlight String     guifg=#61CE3C
highlight Identifier guifg=#61CE3C
highlight Type       guifg=#84A7C1

with something like this (pseudo-code vimscript):

my_string =#61CE3C
my_type   =#84A7C1

highlight String     guifg=my_string
highlight Identifier guifg=my_string
highlight Type       guifg=my_type

I wasn't sure whether vimscript considers the hex color to be a string, or a hexadecimal number. Apparently it's a string, cause this seems to work:

:highlight Normal guifg='#ffffff'

So I thought I'd try this:

:let my_color='#ffffff'
:highlight Normal guifg=my_color

But this gives the error "E254: Cannot allocate color my_color". Can anyone suggest a way to make this work?

+3  A: 

Since :highlight doesn't accept a variable as an argument, you have to build the command to run as an expression and then evaluate it with the :execute command.

:let my_color='#ffffff'
:exe 'highlight Normal guifg=' . my_color
jamessan
Thanks, your suggestion works for me, but sadly it adds more clutter where I was trying to tidy things up! Perhaps I'll have to give up on this idea.One of the definitions under [:help :highlight](http://vimdoc.sourceforge.net/htmldoc/syntax.html#:highlight) says: `:hi[ghlight] [default] {group-name} {key}={arg} ..`. I thought that the `{key}={arg}` bit would accept a variable in place of `{arg}`. Is there no other way?
nelstrom
+3  A: 

As jamessan has said, you need to use :exe to do this. I found the general syntax for the colour scheme files a bit difficult to manage, so I made my own, which you may be interested in. I find it a lot more maintainable, but you may still find it a bit too verbose, in which case see the alternative at the end of this answer.

Rather than writing the long :hi lines, you create a dictionary along the lines of:

" Unspecified colours default to NONE, EXCEPT cterm(.*) which default to matching gui(.*)
" ctermfg will default to 'Blue' and ctermbg to 'NONE' if gui(.*) are RGB
"
" In most cases, only GUIFG is therefore important unless support for Black and White
" terminals is essential

let ColourAssignment['Normal']          = {"GUIFG": 'White', "GUIBG":  'Black'}
let ColourAssignment['Comment']         = {"GUIFG": '#00ff00'}

As mentioned in the comment, all unspecified parts assume sensible defaults, so you don't have to do the common:

:hi Comment guifg=green ctermfg=green guibg=black ctermfg=black

repetition. You can also (of course) put variables in place of the '#00ff00' bit if you want.

It's currently designed around dark background colour schemes: for light background colour schemes, it automatically chooses an appropriate colour (it makes bright colours darker basically) unless you override it, but if you prefer light background colour schemes, it wouldn't be too hard to change so that the default is light.

The other advantage of it is that it comes with a syntax highlighting file that automatically highlights the "ColourAssignment" bit in the colour that you've selected.

Anyway, if that's any interest to you, you can get it from here.


An alternative you could use would be to create a command like this:

command! -nargs=+ Hi call CustomHighlighter(<f-args>)
function! CustomHighlighter(name, ...)
    let colour_order = ['guifg', 'guibg']
    let command = 'hi ' . a:name
    if (len(a:000) < 1) || (len(a:000) > (len(colour_order)))
        echoerr "No colour or too many colours specified"
    else
        for i in range(0,len(a:000)-1)
            let command .= ' ' . colour_order[i] . '=' . a:000[i]
        endfor
        exe command
    endif
endfunc 

You could then use:

Hi Comment #00ff00
Hi String Yellow
Hi Normal White Black
Al
Alternative approach added.
Al
Thanks. I'm glad to hear that I wasn't the only one who was irritated by Vim's color scheme syntax!
nelstrom