Rainbow
[my-vim-dotfolder.git] / plugin / ScrollColor.vim
blob7c4960c7af994b29d3730098ddcbd0dea05f3ad2
1 " ScrollColors.vim - Colorsheme Scroller, Chooser, and Browser
3 "     Author and maintainer: Yakov Lerner <iler_ml@fastmail.fm>
4 "     Last Change: 2006-07-18
6 " SYNOPSIS:
7 "   This is colorscheme Scroller/Chooser/Browser.
8 "   With this plugin, you walk through installed 
9 "   colorschemes using arrow keys.
11 " SHORT USAGE DESCRIPTION:
12 "   Drop ScrollColors.vim into your plugin directory. 
13 "   Type :SCROLL    
14 "   Use arrow keys to walk through colorschemes, ? for help, Esc to exit.
16 " DETAILED DESCRIPTION:
17 "   1. source ScrollColors.vim  " or drop ScrollColors.vim into
18 "                          " your ~/.vim/plugins directory
19 "   2. Type :SCROLL
20 "   3. Use arrows to scroll thgough colorschemes.
21 "   4. When done, press Esc to exit. You will be prompted
22 "      wether to 
24 "   You can download 140 colorschemes pack from:
25 "        http://www.vim.org/scripts/script.php?script_id=625
26 "   Having 140 installed colorschemes is in no way prerequisite for
27 "   ScrollColors. But with ScrollColors you can preview 140 colorschemes
28 "   in couple of minutes.
30 " CUSTOM KEY MAPPINGS:
31 "   You can map two keys of your choice to NextColor and PrevColor actions.
32 "   Choose pair of shortcut keys (for example <F2> and <f3>, or \n and \p)
33 "   and map them as follows:
34 "      map <silent><F3> :NEXTCOLOR<cr>
35 "      map <silent><F2> :PREVCOLOR<cr>
38 if exists("g:scroll_colors") | finish | endif
39 let g:scroll_colors = 1
41 command! COLORSCROLL :call s:ColorScroller()
42 command! SCROLLCOLOR :call s:ColorScroller()
43 command! NEXTCOLOR   :call s:NextColorscheme()
44 command! PREVCOLOR   :call s:PrevColorscheme()
46 " Example of convenience mappings:
47 "map <silent><F3> :NEXTCOLOR<cr>
48 "map <silent><F2> :PREVCOLOR<cr>
49 "map <silent><F4> :SCROLLCOLOR<cr>
51 function! s:ScrollerHelp()
52     echo " "
53     echohl Title
54     echo "Color Scroller Help:"
55     echo "--------------------"
56     echohl NONE
57     echo "Arrows       - change colorscheme"
58     echo "Esc,q,Enter  - exit"
59     echo "h,j,k,l      - change colorscheme"
60     echo "0,g          - go to first colorscheme"
61     echo "$,G          - go to last colorscheme"
62     echo "L            - list colorschemes"
63     echo "PgUp,PgDown  - jump by 10 colorschemes"
64     echo "#            - go to colorscheme by index (1-N)"
65     echo "R            - refresh colorscheme list"
66     echo "?            - this help text"
67     echohl MoreMsg
68     echo "Press any key to continue"
69     echohl NONE
70     call getchar()
71 endfu
73 function! s:Align(s, width)
74     if strlen(a:s) >= a:width
75         return a:s." "
76     else
77         let pad="                       "
78         let res=a:s
79         while strlen(res) < a:width
80             let chunk = (a:width - strlen(res) > strlen(pad) ? strlen(pad) : a:width - strlen(res))
81             let res = res . strpart(pad,0,chunk)
82         endw
83         return res
84     endif
85 endfu
87 function! s:ListColors()
88     echo " "
89     let list=s:GetColorschemesList()
90     let width=18
91     let pos=0
92     while list != ''
93         let str=substitute(list,"\n.*","","")
94         let list=substitute(list,"[^\n]*\n", "", "")
95         let aligned = s:Align(str, width)
96         if( pos+strlen(aligned)+1 >= &columns)
97             echo " "
98             let pos=0
99         endif
100         echon aligned
101         let pos = pos + strlen(aligned)
102     endw
103     echo "Press any key to continue"
104     call getchar()
105 endfu
107 function! s:CurrentColor()
108     return exists("g:colors_name") ? g:colors_name : ""
109 endfu
111 function! s:SetColor(name)
112     exe "color ".a:name
113     " if we do not assign a:colors_name, then
114     " bad things happen if file colors/name.vim conmtains wrong assignment inside.
115     " Wrong assignment inside happens when file was copied but
116     " assignment inside not fixed.
117     " Such wrong assignment cause up erratic switches unless
118     " we do our own assignment to g:colors_name
119     let g:colors_name=a:name
120 endfu
122 function! s:JumpByIndex(list,total)
123     let ans = input("Enter colorscheme number (1-".a:total.") : ")
124     let index = (ans<=0? 1 : 1+(ans-1)%a:total )
125     let name = s:EntryByIndex(a:list, index )
126     call s:SetColor(name)
127 endfu
129 function! s:JumpByIndex2(list,total, index)
130     let mod = (a:index <= 0? 1 : 1+(a:index-1)%a:total )
131     let name = s:EntryByIndex(a:list, mod )
132     call s:SetColor(name)
133 endfu
135 function! s:ExitDialog(old, action)
136     let ans = 0
138     if a:old == s:CurrentColor()
139         let ans=1
140     elseif a:action == ''
141         let ans = confirm("Keep this colorscheme ?", "&Yes\n&No\n&Cancel")
142     elseif action == 'keep'
143         ans = 1
144     elseif action == 'revert'
145         ans = 2
146     endif
148     if ans == 1 || ans==0
149     " exit, keep colorscheme
150         let msg = (a:old == s:CurrentColor() ? '' : "(original: '".a:old."')")
151         call s:FinalEcho( msg )
152     elseif ans == 2 
153     " exit, revert colorscheme
154         call s:SetColor(a:old)
155         call s:FinalEcho('original color restored')
156     elseif ans == 3
157     " do not exit, continue browsing
158         return -1
159     endif
160 endfu
162 function! s:ColorScroller()
163     let old = s:CurrentColor()
164     let list = s:GetColorschemesList()
165     let total = s:CountEntries(list)
166     let loop=0
168     if line("$") == 1 && getline(1) == "" && bufnr('$')==1
169     " if buffer is empty, open something
170         echo "We will open sample text with syntax highlighting."
171         echo "Watch for the guiding prompt in the bottom line."
172         echo "When the text will open, use Arrow keys to switch colorschemes, ? for help."
173         echo " "
174         echo "Press any key to continue"
175         call getchar()
176         :e $VIMRUNTIME/syntax/abc.vim
177         :setlocal ro
178         syntax on
179         redraw
180     endif
182     if !exists("g:syntax_on")
183         syntax on
184         redraw
185     endif
187     while 1
188         redraw
189         let index = s:FindIndex(list, s:CurrentColor())
190         echo "["
191         echohl Search
192         echon s:CurrentColor()
193         echohl NONE
194         if loop == 0
195             echon "] ColorScroller: "
196             echohl MoreMsg | echon "Arrows" | echohl NONE | echon "-next/prev; "
197             echohl MoreMsg | echon "Esc" | echohl NONE | echon "-exit; "
198             echohl MoreMsg | echon "?" | echohl NONE | echon "-help > "
199         else
200             echon "] "
201             echon " " . index . "/" . total . " "
202             echon s:Align("", 12-strlen(s:CurrentColor()))
203             echon "> ColorScroll > "
204             echon "Arrows,Esc,? > "
205         endif
206         let key = getchar()
207         let c = nr2char(key)
209         if     key == "\<Left>" || key == "\<Up>" || c ==# 'h' || c ==# 'j'
210             call s:PrevSilent()
211         elseif key == "\<Down>" || key == "\<Right>" || c ==# 'l' || c==# 'k' || c==# ' '
212             call s:NextSilent()
213         elseif c==# 'g' || c=='0' || c=='1'
214             call s:SetColor( s:GetFirstColors() )
215         elseif c=='$' || c==# 'G'
216             call s:SetColor( s:GetLastColors() )
217         elseif c ==# 'L'
218         " command 'L' list colors
219             call s:ListColors()
220         elseif c=='Z' || c=='z' || key == 13 || c=='q' || c=='Q' || c==':' || key == 27
221             if s:ExitDialog(old, '') != -1
222                 break
223             endif
224         elseif key == 12 " c=="\<C-L>"
225             redraw
226         elseif c == '#'
227             call s:JumpByIndex(list,total)
228         elseif key == "\<PageDown>"
229             call s:JumpByIndex2(list,total, (index-10>=1 ? index-10 : index-10+total))
230         elseif key == "\<PageUp>"
231             call s:JumpByIndex2(list,total, index+10)
232         elseif c == '?'
233             call s:ScrollerHelp()
234         elseif c == 'R'
235             call s:RefreshColorschemesList()
236             echo "Colorscheme list refreshed. Press any key to continue."
237             call getchar()
238         else
239             call s:ScrollerHelp()
240         endif
241         let loop = loop + 1
242     endw
243 endfu
245 " Get 1-based index of 'entry' in \n-separated 'list'
246 function! s:FindIndex(list,entry)
247      " we assume entry has no special chars or we could escape() it
248      let str = substitute("\n" . a:list . "\n", "\n" . a:entry . "\n.*$", "", "")
249      return 1 + s:CountEntries(str)
250 endfu
252 " Get list element by 1-based index
253 function! s:EntryByIndex(list,index)
254     let k=1
255     let tail=a:list 
256     while tail != '' && k < a:index
257         let tail=substitute(tail, "^[^\n]*\n", "", "")
258         let k = k + 1
259     endw
260     let tail = substitute(tail, "\n.*$", "", "")
261     return tail
262 endfu
264 function! s:MakeWellFormedList(list) 
266     " make sure last \n is present
267     let str=a:list."\n"
268     " make sure leading \n are not present
269     let str=substitute(str, "^\n*", "", "")
270     " make sure entries are separated by exactly one \n
271     let str=substitute(str, "\n\\+", "\n", "g")
273     return str
274 endfu
276 function! s:CountEntries(list)
277     let str = s:MakeWellFormedList(a:list)
279     let str=substitute(str, "[^\n]\\+\n", ".", "g")
281     return strlen(str)
282 endfu
284 function! s:RemoveDuplicates(list)
285     let sep = "\n"
286     let res = s:MakeWellFormedList(a:list . "\n")
287     let beg = 0
288     while beg < strlen(res)
289         let end = matchend(res, sep, beg)
290         let str1 = strpart( res, beg, end - beg)
291         let res = strpart(res,0,end) . substitute("\n".strpart(res,end), "\n".str1,"\n","g") 
292         let res = substitute(res, "\n\\+", "\n", "g")
293         let beg = end
294     endw
295     return res
296 endfu
298 if v:version >= 700
300 " s:SortVar(): sort components of string @var separated
301 " by delimiter @sep, and returns the sorted string.
302 " For example, s:SortVar("c\nb\na", "\n") returns "a\nb\nc\n"
303 function! s:SortVar(list, sep)
304     let list = split( a:list, a:sep )
305     let sorted = sort(list)
306     let result = join( sorted, "\n" )
307     return result . "\n"
308 endfun
310 endif
312 if v:version < 700
313 " s:SortVar(): sort components of string @var separated
314 " by delimiter @sep, and returns the sorted string.
315 " For example, s:SortVar("c\nb\na", "\n") returns "a\nb\nc\n"
316 function! s:SortVar(list, sep)
318    let res=s:MakeWellFormedList(a:list . "\n")
319    while 1
320       let disorder=0
321       let index1=0
323       let len=strlen(res)
324       while 1
325          let index2=matchend(res, a:sep, index1)
326          if index2 == -1 || index2>=len
327             break
328          endif
329          let index3=matchend(res, a:sep, index2)
330          if index3 == -1
331             let index3=len
332          endif
333          let str1=strpart(res, index1, index2-index1)
334          let str2=strpart(res, index2, index3-index2)
335          if str1 > str2
336             let disorder=1
337             " swap str1 and str2 in res
338             let res=strpart(res,0,index1).str2.str1.strpart(res,index3)
339              let index1=index1 + strlen(str2)
340          else
341             let index1=index1 + strlen(str1)
342          endif
343       endw
345       if !disorder
346         break
347       endif
348    endw
349    return res
350 endfu
351 endif " v:version < 700
353 let s:list = ""
355 function! s:GetColorschemesList()
356    if s:list == ""
357        let s:list = s:RefreshColorschemesList()
358    endif
359    return s:list
360 endfunction
363 function! s:RefreshColorschemesList() 
364     let x=globpath(&rtp, "colors/*.vim")
365     let y=substitute(x."\n","\\(^\\|\n\\)[^\n]*[/\\\\]", "\n", "g")
366     let z=substitute(y,"\\.vim\n", "\n", "g")
367     let sorted = s:SortVar(z, "\n")
368     let s:list = s:RemoveDuplicates(sorted)
369     return s:list
370 endfun
372 function! s:GetFirstColors() 
373     let list=s:GetColorschemesList()
374     let trim=substitute(list, "^\n\\+", "", "")
375     return substitute(trim, "\n.*", "", "")
376 endfu
378 function! s:GetLastColors()
379     let list=s:GetColorschemesList()
380     let trim=substitute(list, "\n\\+$", "", "")
381     return substitute(trim, "^.*\n", "", "")
382 endfu
384 function! s:FinalEcho(suffix)
385     let list = s:GetColorschemesList()
386     let total = s:CountEntries(list)
387     let index = s:FindIndex(list, s:CurrentColor())
389     redraw
390     echon "["
391     echohl Search
392     echon  s:CurrentColor()
393     echohl NONE
394     echon "] colorscheme #".index ." of " . total.". "
395     echon  a:suffix
396 endfu
398 function! s:GetNextColor(color)
399     let list=s:GetColorschemesList()
400     if ("\n".list) =~ ("\n".s:CurrentColor()."\n")
401         let next=substitute("\n".list."\n", ".*\n".a:color."\n", "", "")
402         let next = substitute(next, "\n.*", "", "")
403         return next=='' ? s:GetFirstColors() : next
404     else
405         return s:GetFirstColors()
406     endif
407 endfu
409 function! s:GetPrevColor(color)
410     let list=s:GetColorschemesList()
411     if ("\n".list) =~ ("\n".a:color."\n")
412         let prev=substitute("\n".list."\n", "\n".a:color."\n.*", "", "")
413         let prev=substitute(prev, "^.*\n", "", "")
414         return prev=='' ? s:GetLastColors() : prev
415     else
416         return s:GetLastColors()
417     endif
418 endfu
420 function! s:NextSilent()
421     let old = s:CurrentColor()
422     let next = s:GetNextColor(s:CurrentColor())
423     call s:SetColor( next )
424 endfu
426 function! s:PrevSilent()
427     let old = s:CurrentColor()
428     let prev = s:GetPrevColor(s:CurrentColor())
429     call s:SetColor( prev )
430 endfu
432 function! s:NextColorscheme()
433     let old = s:CurrentColor()
434     let next = s:GetNextColor(s:CurrentColor())
435     call s:SetColor( next )
436     redraw
437     call s:FinalEcho('previous: '.old)
438 endfun
440 function! s:PrevColorscheme()
441     let old = s:CurrentColor()
442     let prev = s:GetPrevColor(s:CurrentColor())
443     call s:SetColor( prev )
444     redraw
445     call s:FinalEcho('previous: '.old)
446 endfun
448 command! CN :call s:NextColorscheme()
449 command! CP :call s:PrevColorscheme()
450 map \n :CN<cr>
451 map \p :CP<cr>
452 map \c :echo g:colors_name<cr>
454 " 2006-07-18 fixed bug with Align() -> s:Align() (affected L command)
455 " 2006-07-18 added colorlist cache (s:list)
456 " 2006-07-18 added R key to refresh colorlist
457 " 2006-07-19 for vim7, sort using builtin sort() (bubblesort is slow)