]> ruderich.org/simon Gitweb - config/dotfiles.git/blob - vim/vim/plugin/matrix.vim
Merge branch 'multimedia' again
[config/dotfiles.git] / vim / vim / plugin / matrix.vim
1 " matrix.vim - Don Yang (uguu.org)
2 "
3 " Matrix screensaver for VIM.
4 "
5 "Usage:
6 " After loading the script, use :Matrix to start.
7 " Press any key a few times to exit.
8 "
9 " You will need to edit s:mindelay and s:maxdelay below to match your
10 " machine speed and window size.
11 "
12 "Known Issues:
13 " Sometimes you need to press keys a few times to exit instead of just
14 " once.  Press and hold is another way to go... feels like getchar is
15 " checking for keypress state instead of keystroke availability.
16 "
17 " If the window is too small, script will not run.  If the window is
18 " resized and become too small (less than 8 rows or 10 columns) after
19 " the script started, script will abort and *buffers may be lost*, so
20 " don't do that.  Resizing the window to most other sizes will be fine.
21 "
22 " Doesn't work if multiple windows exist before script started.  In
23 " that case the script will abort with error message.
24 "
25 " If the current buffer is modified, some error messages will appear
26 " before the script starts, and an extra window is left behind after
27 " the script exits.  Workaround: save your buffers first.
28 "
29 "Other Info:
30 " Inspired by cmatrix...
31 " Didn't feel inspired enough to start using pico/nano, of course ^_^;
32 "
33 " 05/13/08 - disable cursorline, cursorcolumn and spell
34 "            (thanks to Diederick Niehorster for the suggestion).
35 " 12/21/06 - multiwindow support by S. Lockwood-Childs.
36 " 10/03/05 - added silent! to cursor positioning code to stop drawing
37 "            numbers during animation (thanks to David Eggum for the
38 "            suggestion).
39 " 10/02/05 - disable showmatch
40 " 03/16/05 - make new buffer modifiable before running
41 " 01/27/05 - added sleep to consume less CPU
42 "            removed frame counter
43 " 01/26/05 - initial version
44
45
46 " Speed range, must be positive.  Lower delay = faster.
47 let s:mindelay = 1
48 let s:maxdelay = 5
49
50 " Session file for preserving original window layout
51 let s:session_file = tempname()
52
53
54 function! s:Rand()
55    let b:seed = b:seed * 22695477 + 1
56    if b:seed < 0
57       return -b:seed
58    endif
59    return b:seed
60 endfunction
61
62 function! s:CreateObject(i)
63    while 1
64       let b:x{a:i} = s:Rand() % b:columns
65       if b:reserve{b:x{a:i}} > 4
66          break
67       endif
68    endwhile
69    let b:y{a:i} = 1
70    let b:t{a:i} = s:Rand() % b:s{b:x{a:i}}
71    let b:head{a:i} = s:Rand() % 4
72    let b:len{a:i} = s:Rand() % b:h + 3
73    let b:reserve{b:x{a:i}} = 1 - b:len{a:i}
74 endfunction
75
76 function! s:DrawObject(i)
77    let x = b:x{a:i} * 2 + 1
78    let y = b:y{a:i}
79
80    " Draw head
81    if y <= b:h
82       if b:head{a:i}
83          silent! exec 'norm! :' . y . nr2char(13) . x . '|R' . b:d[s:Rand()%b:dl] . '_' . nr2char(27)
84          if y > 1
85             silent! exec 'norm! kR' . ((s:Rand() % 2) ? '`' : ' ') . nr2char(27)
86          endif
87       else
88          let a = ((s:Rand() % 2) ? '`' : ' ') . nr2char(27)
89          silent! exec 'norm! :'. y . nr2char(13) . x . '|R' . b:d[s:Rand() % b:dl] . a
90       endif
91    else
92       if b:head{a:i} && y == b:h + 1
93          silent! exec 'norm! :' . b:h . nr2char(13) . (x + 1) . '|R' . ((s:Rand() % 2) ? '`' : ' ') . nr2char(27)
94       endif
95    endif
96
97    " Draw tail
98    let y = y - b:len{a:i}
99    if 1 <= y && y <= b:h
100       silent! exec 'norm! :'. y . nr2char(13) . x . '|R  ' . nr2char(27)
101    endif
102    let b:reserve{b:x{a:i}} = y
103 endfunction
104
105 function! s:Animate()
106    let i = 0
107
108    while i < b:objcount
109       " Animate object
110       if b:t{i} <= 0
111          if b:y{i} - b:len{i} <= b:h
112             " Draw
113             call s:DrawObject(i)
114             let b:t{i} = b:s{b:x{i}}
115             let b:y{i} = b:y{i} + 1
116          else
117             " Regenerate
118             call s:CreateObject(i)
119          endif
120       endif
121
122       let b:t{i} = b:t{i} - 1
123       let i = i + 1
124    endwhile
125    redraw
126    if getchar(1)
127       let b:run = 0
128    endif
129    sleep 20m
130 endfunction
131
132 function! s:Reset()
133    " Clear screen
134    let b:w = winwidth(0)
135    let b:h = winheight(0)
136    exec 'norm! gg"_dG' . b:h . 'O' . nr2char(27) . 'gg'
137    redraw
138    if b:w < 10 || b:h < 8
139       let b:run = 0
140       return
141    endif
142
143    " Set number of columns.  This is rounded down due to line wrapping
144    " at the last column if the screen width is even.  So you end up
145    " seeing the cursor blinking a lot at the right side of the screen.
146    " Alternatively, ':set rl' before running the script to have it
147    " blink on the left side.
148    let b:columns = (b:w - 1) / 2
149
150    " Initialize columns.
151    let i = 0
152    while i < b:columns
153       " Set delay time.  Each column gets the same delay time.
154       let b:s{i} = s:Rand() % (s:maxdelay - s:mindelay) + s:mindelay
155
156       " Unreserve column
157       let b:reserve{i} = b:h
158       let i = i + 1
159    endwhile
160
161    " Initialize objects
162    let b:objcount = b:columns - 2
163    let i = 0
164    while i < b:objcount
165       call s:CreateObject(i)
166       let i = i + 1
167    endwhile
168 endfunction
169
170 function! s:Init()
171    " Create new buffer and hide the existing buffers.  Hiding the
172    " existing buffers without switching to a new buffer preserves
173    " undo history.
174    exec 'mksession! ' . s:session_file
175    let s:num_orig_win = winnr("$")
176
177    " move to top window, so created window will become window 1,
178    " then attempt to create new window
179    1 wincmd w
180    silent! new
181
182    " check that there really is an additional window
183    if winnr("$") != s:num_orig_win + 1
184       return 1
185    endif
186    let s:newbuf = bufnr('%')
187
188    " close all but window 1, which is the new window
189    only
190
191    setl bh=delete bt=nofile ma nolist nonu noro noswf tw=0 nowrap
192
193    " Set GUI options
194    if has('gui')
195       let s:o_gcr = &gcr
196       let s:o_go = &go
197       set gcr=a:ver1-blinkon0 go=
198    endif
199    if has('cmdline_info')
200       let s:o_ru = &ru
201       let s:o_sc = &sc
202       set noru nosc
203    endif
204    if has('title')
205       let s:o_ts = &titlestring
206       exec 'set titlestring=\ '
207    endif
208    if v:version >= 700
209       let s:o_spell = &spell
210       let s:o_cul = &cul
211       let s:o_cuc = &cuc
212       set nospell nocul nocuc
213    endif
214    let s:o_ch = &ch
215    let s:o_ls = &ls
216    let s:o_lz = &lz
217    let s:o_siso = &siso
218    let s:o_sm = &sm
219    let s:o_smd = &smd
220    let s:o_so = &so
221    let s:o_ve = &ve
222    set ch=1 ls=0 lz nosm nosmd siso=0 so=0 ve=all
223
224    " Initialize PRNG
225    let b:seed = localtime()
226    let b:run = 1
227
228    " Clear screen and initialize objects
229    call s:Reset()
230
231    " Set colors.  Output looks better if your color scheme has black
232    " background.  I would rather not have the script change the
233    " current color scheme since there is no good way to restore them
234    " afterwards.
235    hi MatrixHidden ctermfg=Black ctermbg=Black guifg=#000000 guibg=#000000
236    hi MatrixNormal ctermfg=DarkGreen ctermbg=Black guifg=#008000 guibg=#000000
237    hi MatrixBold ctermfg=LightGreen ctermbg=Black guifg=#00ff00 guibg=#000000
238    hi MatrixHead ctermfg=White ctermbg=Black guifg=#ffffff guibg=#000000
239    sy match MatrixNormal /^.*/ contains=MatrixHidden
240    sy match MatrixHidden contained /.`/ contains=MatrixBold
241    sy match MatrixHidden contained /._/ contains=MatrixHead
242    sy match MatrixBold contained /.\(`\)\@=/
243    sy match MatrixHead contained /.\(_\)\@=/
244
245    " Create random char dictionary
246    let b:d = ''
247    let i = 33
248    while i < 127
249       if i != 95 && i != 96
250          let b:d = b:d . nr2char(i)
251       endif
252       let i = i + 1
253    endwhile
254    let b:dl = strlen(b:d)
255    return 0
256 endfunction
257
258 function! s:Cleanup()
259    " Restore options
260    if has('gui')
261       let &gcr = s:o_gcr
262       let &go = s:o_go
263       unlet s:o_gcr s:o_go
264    endif
265    if has('cmdline_info')
266       let &ru = s:o_ru
267       let &sc = s:o_sc
268       unlet s:o_ru s:o_sc
269    endif
270    if has('title')
271       let &titlestring = s:o_ts
272       unlet s:o_ts
273    endif
274    if v:version >= 700
275       let &spell = s:o_spell
276       let &cul = s:o_cul
277       let &cuc = s:o_cuc
278       unlet s:o_cul s:o_cuc
279    endif
280    let &ch = s:o_ch
281    let &ls = s:o_ls
282    let &lz = s:o_lz
283    let &siso = s:o_siso
284    let &sm = s:o_sm
285    let &smd = s:o_smd
286    let &so = s:o_so
287    let &ve = s:o_ve
288    unlet s:o_ch s:o_ls s:o_lz s:o_siso s:o_sm s:o_smd s:o_so s:o_ve
289
290    " Restore old buffers
291    exec 'source ' . s:session_file
292    exec 'bwipe ' . s:newbuf
293    unlet s:newbuf
294
295    " Clear keystroke
296    let c = getchar(0)
297 endfunction
298
299 function! Matrix()
300    if s:Init()
301       echohl ErrorMsg
302       echon 'Can not create window'
303       echohl None
304       return
305    endif
306
307    while b:run
308       if b:w != winwidth(0) || b:h != winheight(0)
309          call s:Reset()
310       else
311          call s:Animate()
312       endif
313    endwhile
314
315    call s:Cleanup()
316 endfunction
317
318
319 if !has('virtualedit') || !has('windows') || !has('syntax')
320    echohl ErrorMsg
321    echon 'Not enough features, need at least +virtualedit, +windows and +syntax'
322    echohl None
323 else
324    command! Matrix call Matrix()
325 endif