aboutsummaryrefslogtreecommitdiff
path: root/vim/plugin/ScrollColor.vim
blob: 7c4960c7af994b29d3730098ddcbd0dea05f3ad2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
" ScrollColors.vim - Colorsheme Scroller, Chooser, and Browser
"
"     Author and maintainer: Yakov Lerner <iler_ml@fastmail.fm>
"     Last Change: 2006-07-18
"
" SYNOPSIS:
"   This is colorscheme Scroller/Chooser/Browser.
"   With this plugin, you walk through installed 
"   colorschemes using arrow keys.
"
" SHORT USAGE DESCRIPTION:
"   Drop ScrollColors.vim into your plugin directory. 
"   Type :SCROLL    
"   Use arrow keys to walk through colorschemes, ? for help, Esc to exit.
"
" DETAILED DESCRIPTION:
"   1. source ScrollColors.vim  " or drop ScrollColors.vim into
"                          " your ~/.vim/plugins directory
"   2. Type :SCROLL
"   3. Use arrows to scroll thgough colorschemes.
"   4. When done, press Esc to exit. You will be prompted
"      wether to 
"
"   You can download 140 colorschemes pack from:
"        http://www.vim.org/scripts/script.php?script_id=625
"   Having 140 installed colorschemes is in no way prerequisite for
"   ScrollColors. But with ScrollColors you can preview 140 colorschemes
"   in couple of minutes.
"
" CUSTOM KEY MAPPINGS:
"   You can map two keys of your choice to NextColor and PrevColor actions.
"   Choose pair of shortcut keys (for example <F2> and <f3>, or \n and \p)
"   and map them as follows:
"      map <silent><F3> :NEXTCOLOR<cr>
"      map <silent><F2> :PREVCOLOR<cr>


if exists("g:scroll_colors") | finish | endif
let g:scroll_colors = 1

command! COLORSCROLL :call s:ColorScroller()
command! SCROLLCOLOR :call s:ColorScroller()
command! NEXTCOLOR   :call s:NextColorscheme()
command! PREVCOLOR   :call s:PrevColorscheme()

" Example of convenience mappings:
"map <silent><F3> :NEXTCOLOR<cr>
"map <silent><F2> :PREVCOLOR<cr>
"map <silent><F4> :SCROLLCOLOR<cr>

function! s:ScrollerHelp()
    echo " "
    echohl Title
    echo "Color Scroller Help:"
    echo "--------------------"
    echohl NONE
    echo "Arrows       - change colorscheme"
    echo "Esc,q,Enter  - exit"
    echo "h,j,k,l      - change colorscheme"
    echo "0,g          - go to first colorscheme"
    echo "$,G          - go to last colorscheme"
    echo "L            - list colorschemes"
    echo "PgUp,PgDown  - jump by 10 colorschemes"
    echo "#            - go to colorscheme by index (1-N)"
    echo "R            - refresh colorscheme list"
    echo "?            - this help text"
    echohl MoreMsg
    echo "Press any key to continue"
    echohl NONE
    call getchar()
endfu

function! s:Align(s, width)
    if strlen(a:s) >= a:width
        return a:s." "
    else
        let pad="                       "
        let res=a:s
        while strlen(res) < a:width
            let chunk = (a:width - strlen(res) > strlen(pad) ? strlen(pad) : a:width - strlen(res))
            let res = res . strpart(pad,0,chunk)
        endw
        return res
    endif
endfu

function! s:ListColors()
    echo " "
    let list=s:GetColorschemesList()
    let width=18
    let pos=0
    while list != ''
        let str=substitute(list,"\n.*","","")
        let list=substitute(list,"[^\n]*\n", "", "")
        let aligned = s:Align(str, width)
        if( pos+strlen(aligned)+1 >= &columns)
            echo " "
            let pos=0
        endif
        echon aligned
        let pos = pos + strlen(aligned)
    endw
    echo "Press any key to continue"
    call getchar()
endfu

function! s:CurrentColor()
    return exists("g:colors_name") ? g:colors_name : ""
endfu

function! s:SetColor(name)
    exe "color ".a:name
    " if we do not assign a:colors_name, then
    " bad things happen if file colors/name.vim conmtains wrong assignment inside.
    " Wrong assignment inside happens when file was copied but
    " assignment inside not fixed.
    " Such wrong assignment cause up erratic switches unless
    " we do our own assignment to g:colors_name
    let g:colors_name=a:name
endfu

function! s:JumpByIndex(list,total)
    let ans = input("Enter colorscheme number (1-".a:total.") : ")
    let index = (ans<=0? 1 : 1+(ans-1)%a:total )
    let name = s:EntryByIndex(a:list, index )
    call s:SetColor(name)
endfu

function! s:JumpByIndex2(list,total, index)
    let mod = (a:index <= 0? 1 : 1+(a:index-1)%a:total )
    let name = s:EntryByIndex(a:list, mod )
    call s:SetColor(name)
endfu

function! s:ExitDialog(old, action)
    let ans = 0

    if a:old == s:CurrentColor()
        let ans=1
    elseif a:action == ''
        let ans = confirm("Keep this colorscheme ?", "&Yes\n&No\n&Cancel")
    elseif action == 'keep'
        ans = 1
    elseif action == 'revert'
        ans = 2
    endif

    if ans == 1 || ans==0
    " exit, keep colorscheme
        let msg = (a:old == s:CurrentColor() ? '' : "(original: '".a:old."')")
        call s:FinalEcho( msg )
    elseif ans == 2 
    " exit, revert colorscheme
        call s:SetColor(a:old)
        call s:FinalEcho('original color restored')
    elseif ans == 3
    " do not exit, continue browsing
        return -1
    endif
endfu

function! s:ColorScroller()
    let old = s:CurrentColor()
    let list = s:GetColorschemesList()
    let total = s:CountEntries(list)
    let loop=0

    if line("$") == 1 && getline(1) == "" && bufnr('$')==1
    " if buffer is empty, open something
        echo "We will open sample text with syntax highlighting."
        echo "Watch for the guiding prompt in the bottom line."
        echo "When the text will open, use Arrow keys to switch colorschemes, ? for help."
        echo " "
        echo "Press any key to continue"
        call getchar()
        :e $VIMRUNTIME/syntax/abc.vim
        :setlocal ro
        syntax on
        redraw
    endif

    if !exists("g:syntax_on")
        syntax on
        redraw
    endif

    while 1
        redraw
        let index = s:FindIndex(list, s:CurrentColor())
        echo "["
        echohl Search
        echon s:CurrentColor()
        echohl NONE
        if loop == 0
            echon "] ColorScroller: "
            echohl MoreMsg | echon "Arrows" | echohl NONE | echon "-next/prev; "
            echohl MoreMsg | echon "Esc" | echohl NONE | echon "-exit; "
            echohl MoreMsg | echon "?" | echohl NONE | echon "-help > "
        else
            echon "] "
            echon " " . index . "/" . total . " "
            echon s:Align("", 12-strlen(s:CurrentColor()))
            echon "> ColorScroll > "
            echon "Arrows,Esc,? > "
        endif
        let key = getchar()
        let c = nr2char(key)

        if     key == "\<Left>" || key == "\<Up>" || c ==# 'h' || c ==# 'j'
            call s:PrevSilent()
        elseif key == "\<Down>" || key == "\<Right>" || c ==# 'l' || c==# 'k' || c==# ' '
            call s:NextSilent()
        elseif c==# 'g' || c=='0' || c=='1'
            call s:SetColor( s:GetFirstColors() )
        elseif c=='$' || c==# 'G'
            call s:SetColor( s:GetLastColors() )
        elseif c ==# 'L'
        " command 'L' list colors
            call s:ListColors()
        elseif c=='Z' || c=='z' || key == 13 || c=='q' || c=='Q' || c==':' || key == 27
            if s:ExitDialog(old, '') != -1
                break
            endif
        elseif key == 12 " c=="\<C-L>"
            redraw
        elseif c == '#'
            call s:JumpByIndex(list,total)
        elseif key == "\<PageDown>"
            call s:JumpByIndex2(list,total, (index-10>=1 ? index-10 : index-10+total))
        elseif key == "\<PageUp>"
            call s:JumpByIndex2(list,total, index+10)
        elseif c == '?'
            call s:ScrollerHelp()
        elseif c == 'R'
            call s:RefreshColorschemesList()
            echo "Colorscheme list refreshed. Press any key to continue."
            call getchar()
        else
            call s:ScrollerHelp()
        endif
        let loop = loop + 1
    endw
endfu

" Get 1-based index of 'entry' in \n-separated 'list'
function! s:FindIndex(list,entry)
     " we assume entry has no special chars or we could escape() it
     let str = substitute("\n" . a:list . "\n", "\n" . a:entry . "\n.*$", "", "")
     return 1 + s:CountEntries(str)
endfu

" Get list element by 1-based index
function! s:EntryByIndex(list,index)
    let k=1
    let tail=a:list 
    while tail != '' && k < a:index
        let tail=substitute(tail, "^[^\n]*\n", "", "")
        let k = k + 1
    endw
    let tail = substitute(tail, "\n.*$", "", "")
    return tail
endfu

function! s:MakeWellFormedList(list) 

    " make sure last \n is present
    let str=a:list."\n"
    " make sure leading \n are not present
    let str=substitute(str, "^\n*", "", "")
    " make sure entries are separated by exactly one \n
    let str=substitute(str, "\n\\+", "\n", "g")

    return str
endfu

function! s:CountEntries(list)
    let str = s:MakeWellFormedList(a:list)

    let str=substitute(str, "[^\n]\\+\n", ".", "g")

    return strlen(str)
endfu

function! s:RemoveDuplicates(list)
    let sep = "\n"
    let res = s:MakeWellFormedList(a:list . "\n")
    let beg = 0
    while beg < strlen(res)
        let end = matchend(res, sep, beg)
        let str1 = strpart( res, beg, end - beg)
        let res = strpart(res,0,end) . substitute("\n".strpart(res,end), "\n".str1,"\n","g") 
        let res = substitute(res, "\n\\+", "\n", "g")
        let beg = end
    endw
    return res
endfu

if v:version >= 700

" s:SortVar(): sort components of string @var separated
" by delimiter @sep, and returns the sorted string.
" For example, s:SortVar("c\nb\na", "\n") returns "a\nb\nc\n"
function! s:SortVar(list, sep)
    let list = split( a:list, a:sep )
    let sorted = sort(list)
    let result = join( sorted, "\n" )
    return result . "\n"
endfun

endif

if v:version < 700
" s:SortVar(): sort components of string @var separated
" by delimiter @sep, and returns the sorted string.
" For example, s:SortVar("c\nb\na", "\n") returns "a\nb\nc\n"
function! s:SortVar(list, sep)

   let res=s:MakeWellFormedList(a:list . "\n")
   while 1
      let disorder=0
      let index1=0

      let len=strlen(res)
      while 1
         let index2=matchend(res, a:sep, index1)
         if index2 == -1 || index2>=len
            break
         endif
         let index3=matchend(res, a:sep, index2)
         if index3 == -1
            let index3=len
         endif
         let str1=strpart(res, index1, index2-index1)
         let str2=strpart(res, index2, index3-index2)
         if str1 > str2
            let disorder=1
            " swap str1 and str2 in res
            let res=strpart(res,0,index1).str2.str1.strpart(res,index3)
             let index1=index1 + strlen(str2)
         else
            let index1=index1 + strlen(str1)
         endif
      endw

      if !disorder
        break
      endif
   endw
   return res
endfu
endif " v:version < 700

let s:list = ""

function! s:GetColorschemesList()
   if s:list == ""
       let s:list = s:RefreshColorschemesList()
   endif
   return s:list
endfunction


function! s:RefreshColorschemesList() 
    let x=globpath(&rtp, "colors/*.vim")
    let y=substitute(x."\n","\\(^\\|\n\\)[^\n]*[/\\\\]", "\n", "g")
    let z=substitute(y,"\\.vim\n", "\n", "g")
    let sorted = s:SortVar(z, "\n")
    let s:list = s:RemoveDuplicates(sorted)
    return s:list
endfun

function! s:GetFirstColors() 
    let list=s:GetColorschemesList()
    let trim=substitute(list, "^\n\\+", "", "")
    return substitute(trim, "\n.*", "", "")
endfu

function! s:GetLastColors()
    let list=s:GetColorschemesList()
    let trim=substitute(list, "\n\\+$", "", "")
    return substitute(trim, "^.*\n", "", "")
endfu

function! s:FinalEcho(suffix)
    let list = s:GetColorschemesList()
    let total = s:CountEntries(list)
    let index = s:FindIndex(list, s:CurrentColor())

    redraw
    echon "["
    echohl Search
    echon  s:CurrentColor()
    echohl NONE
    echon "] colorscheme #".index ." of " . total.". "
    echon  a:suffix
endfu

function! s:GetNextColor(color)
    let list=s:GetColorschemesList()
    if ("\n".list) =~ ("\n".s:CurrentColor()."\n")
        let next=substitute("\n".list."\n", ".*\n".a:color."\n", "", "")
        let next = substitute(next, "\n.*", "", "")
        return next=='' ? s:GetFirstColors() : next
    else
        return s:GetFirstColors()
    endif
endfu

function! s:GetPrevColor(color)
    let list=s:GetColorschemesList()
    if ("\n".list) =~ ("\n".a:color."\n")
        let prev=substitute("\n".list."\n", "\n".a:color."\n.*", "", "")
        let prev=substitute(prev, "^.*\n", "", "")
        return prev=='' ? s:GetLastColors() : prev
    else
        return s:GetLastColors()
    endif
endfu

function! s:NextSilent()
    let old = s:CurrentColor()
    let next = s:GetNextColor(s:CurrentColor())
    call s:SetColor( next )
endfu

function! s:PrevSilent()
    let old = s:CurrentColor()
    let prev = s:GetPrevColor(s:CurrentColor())
    call s:SetColor( prev )
endfu

function! s:NextColorscheme()
    let old = s:CurrentColor()
    let next = s:GetNextColor(s:CurrentColor())
    call s:SetColor( next )
    redraw
    call s:FinalEcho('previous: '.old)
endfun

function! s:PrevColorscheme()
    let old = s:CurrentColor()
    let prev = s:GetPrevColor(s:CurrentColor())
    call s:SetColor( prev )
    redraw
    call s:FinalEcho('previous: '.old)
endfun

command! CN :call s:NextColorscheme()
command! CP :call s:PrevColorscheme()
map \n :CN<cr>
map \p :CP<cr>
map \c :echo g:colors_name<cr>

" 2006-07-18 fixed bug with Align() -> s:Align() (affected L command)
" 2006-07-18 added colorlist cache (s:list)
" 2006-07-18 added R key to refresh colorlist
" 2006-07-19 for vim7, sort using builtin sort() (bubblesort is slow)