Vim Tips Wiki

Hi,if I have a little time, I will try to clean up this post: generally there is an issue with duplicated color schemes names, I've loaded 150 colo and then i could only view a few because 100 and 110 were the same (but loaded from different path), so there was only short loop between them.

Here some working code:

" Change the color scheme from a list of color scheme names.
" Version 2010-09-12 from
" Press key:
"FIXME: i prefer F2 :P
"   F2                next scheme
"   Shift-F2          previous scheme
"   Alt-F2            random scheme
" Set the list of color schemes used by the above (default is 'all'):
"   :SetColors all              (all $VIMRUNTIME/colors/*.vim)
"   :SetColors my               (names built into script)
"   :SetColors blue slate ron   (these schemes)
"   :SetColors                  (display current scheme names)
" Set the current color scheme based on time of day:
"   :SetColors now
if v:version < 700 || exists('loaded_setcolors') || &cp

let loaded_setcolors = 1
let s:mycolors = ['slate', 'torte', 'darkblue', 'delek', 'murphy', 'elflord', 'pablo', 'koehler', 'solarized']  " colorscheme names that we use to set color

"FIXME need to use global enumerator
let s:current = -1

" Set list of color scheme names that we will use, except
" argument 'now' actually changes the current color scheme.
function! s:SetColors(args)
  if len(a:args) == 0
    echo 'Current color scheme names:'
    let i = 0
    while i < len(s:mycolors)
      echo '  '.join(map(s:mycolors[i : i+4], 'printf("%-14s", v:val)'))
      let i += 5
  elseif a:args == 'all'
"    let paths = []
    let paths_tofix = split(globpath(&runtimepath, 'colors/*.vim'), "\n")
" FIXME duplicated color schemes - it doesnt - take a look /usr/share/.../murphy.vim and ~/vim/color/murphy.vim
"    for i in range(len(paths_tofix))
"      if index(paths, paths_tofix[i]) == -1
"        call add(paths, paths_tofix[i])
"        echo paths_tofix[i]
"      endif
"    endfor
    let paths = paths_tofix
    let s:mycolors = map(paths, 'fnamemodify(v:val, ":t:r")')
"    echo 'List of colors set from all installed color schemes (added ' . len(paths). ' schemes).'
    let g:colorschemes = len(paths)
  elseif a:args == 'my'
    let c1 = 'default elflord peachpuff desert256 breeze morning'
    let c2 = 'darkblue gothic aqua earth black_angus relaxedgreen'
    let c3 = 'darkblack freya motus impact less chocolateliquor'
    let s:mycolors = split(c1.' '.c2.' '.c3)
"    echo 'List of colors set from built-in names'
  elseif a:args == 'now'
    call s:HourColor()
    let s:mycolors = split(a:args)
"    echo 'List of colors set from argument (space-separated names)'

command! -nargs=* SetColors call <SID>SetColors('<args>')

"FIXME - i have not chosen my prefered set of colour schemes so i add all of them
execute "call <SID>SetColors('all')"

" Set next/previous/random (how = 1/-1/0) color from our list of colors.
" The 'random' index is actually set from the current time in seconds.
" Global (no 's:') so can easily call from command line.
function! NextColor(how)
  call s:NextColor(a:how, 1)

" Helper function for NextColor(), allows echoing of the color name to be
" disabled.
function! s:NextColor(how, echo_color)
  if len(s:mycolors) == 0
    call s:SetColors('all')
  let missing = []
  let how = a:how
  for i in range(len(s:mycolors))
    if how == 0
      let s:current = localtime() % len(s:mycolors)
      let how = 1  " in case random color does not exist
      let s:current += how
"      echoerr current . '/' . len(s:mycolors)
      if !(0 <= s:current && s:current < len(s:mycolors))
        let s:current = (how>0 ? 0 : len(s:mycolors)-1)
      execute 'colorscheme '.s:mycolors[s:current]
    catch /E185:/
      echoerr 'Could not locate colorscheme: ' . s:mycolors[s:current]
      call add(missing, s:mycolors[s:current])
  if len(missing) > 0
    echo 'Error: colorscheme not found:' join(missing)
  if (a:echo_color)
    echo '[' . s:current . '] ' . g:colors_name

"FIXME my mod - useful when you have 150 colour schemes
function! SetColor()
  let s:current = input("Enter number [0," . (len(s:mycolors) - 1) . "]: ")
    execute 'colorscheme '.s:mycolors[s:current]
    call s:NextColor(1,1)
noremap <F7> :call SetColor()<CR>

inoremap <F2> <ESC>:call NextColor(1)<CR>i
inoremap <S-F2> <ESC>:call NextColor(-1)<CR>i
inoremap <A-F2> <ESC>:call NextColor(0)<CR>i

nnoremap <F2> :call NextColor(1)<CR>
nnoremap <S-F2> :call NextColor(-1)<CR>
nnoremap <A-F2> :call NextColor(0)<CR>

" Set color scheme according to current time of day.
function! s:HourColor()
  let hr = str2nr(strftime('%H'))
  if hr <= 3
    let i = 0
  elseif hr <= 7
    let i = 1
  elseif hr <= 14
    let i = 2
  elseif hr <= 18
    let i = 3
    let i = 4
  let nowcolors = 'elflord morning desert evening pablo'
  execute 'colorscheme '.split(nowcolors)[i]
  echo g:colors_name
endfunction January 29, 2012

We generally don't use talk pages, preferring all comments to be on the tip page where people see them. Also, we do not keep comments indefinitely, but hope to eventually respond to any points raised and integrate them into the tip (and remove the comment). However, the talk page is a good place for something of this length and complexity so let's stay here for now (but there is no commitment to keep this page). I have not yet taken the time to work out what changes there are above, so can't say anything helpful at the moment. JohnBeckett 10:04, January 29, 2012 (UTC)

OK, I'll fix it after my finals (next weekend). Best regards. Aleksander Gajewski <>

I'm a little confused about your comment about having two colorschemes that are the same scheme at a different path. How do you load these schemes? Won't 'colorscheme abc' load the first abc.vim found in the runtimepath and then stop? This does not sound like a very common problem. Or maybe the script finds duplicates in the installed schemes in the runtimepath and adds them both, when really it ought to only add the one that comes earliest in the runtimepath? --Fritzophrenic 15:50, January 30, 2012 (UTC)

This is what I think are the changes when comparing the code in the tip with the code above:

  • Mapped F2 instead of F8.
  • Added insert mode mappings so can change colorschemes while in insert mode.
  • Some preference changes like adding a particular colorscheme to the defaults, and some other tweaks (not sure of purpose).
  • New code (commented out) that a quick look makes me think is intended to omit duplicate colorschemes (those with same file name?).
  • Mapped F7 to call new function SetColor that prompts user to enter number of wanted colorscheme, and makes that number current so next/previous will operate from that number.
  • Made a script variable s:current to support SetColor operation.

We may as well wait for Aleksander to respond before thinking any more, but my first impression is that while code like this could be valuable for an individual, it may be unnecessary for a tip like this. As I see it, this tip provides a good way for people to quickly change between a few color schemes in order to choose what works for them. JohnBeckett 06:54, January 31, 2012 (UTC)

Hi, I'm sorry for this messy post, but I was quite busy and I just wanted to share with you the unexpected behaviour of this plugin (in case I don't have time to take care of it). I'm just trying to master my VIM skills. My mapping is completly unimportant. SetColor function is also not-so-important feature. Unfortunatelly my laptop is broken (I've sent it to the dealer) and I cannot restore my configuration (installed color schemes etc.) to point out the situation which seemed to me uncovered by the current version of plugin.

In general - the problem occured after calling SetColors all, which read all the color schemes but some of them twice (as I wrote in comment: /usr/share/.../murphy.vim and ~/vim/color/murphy.vim) - that's why some of them was duplicated on the list of available colorschemes. But also both of them (let focus on murphy) was setting the variable g:colors_name to "murphy", then switching the color scheme function evaluated line:

let current = index(s:mycolors, g:colors_name)

which (as I thought) caused the strangly short loop. I added the verbose mode:

  if (a:echo_color)
    echo '[' . s:current . '] ' . g:colors_name

and I found something like that:

101 - murphy   (/usr/share/.../murphy.vim)
102 - desert
103 - koehler
110 - murphy   (~/vim/color/murphy.vim)

I hope it explains the problem - and that's why I decided to recognize the current color scheme not by g:colors_name, but by internal script variable, which allowed me to solve the problem. Feel free to correct my spelling/grammar - I'm not native speaker. Thanks for your feedback. It certainly might not be the common problem, but those fixtures can improve the plugin. --Preceding unsigned comment added by Gajewski 01:20, February 4, 2012

OK, thanks for the explanation, and I see the problem. Of course the problem arises because the user has created a color scheme file under ~/.vim/colors that has the same name as one of the color schemes provided with Vim. That should not happen. The advantage of relying on g:colors_name is that that name is set automatically by Vim, for example, if the user uses the :colorscheme command. I'll think about the problem. JohnBeckett 08:49, February 4, 2012 (UTC)
I think it may actually be quite common to have a color scheme file in ~/.vim/colors with the same name as one in $VIMRUNTIME/colors, because the general recommendation for overriding the officially distributed runtime, is to copy them into ~/.vim and edit them there. I used to (when editing colorschemes) not only copy them but also append a _btfritz to the end of the colorscheme name, but I grew tired of that and started just using the original name. I'm not sure what the correct thing to do with this script in that situation would be. Were this a plugin, I'd want an option to tell it to select either the user or runtime files, but I think the tip (not as a fully featured plugin) should focus on just the user files. --Fritzophrenic 15:43, February 6, 2012 (UTC)