1 " matrix.vim - Don Yang (uguu.org)
3 " Matrix screensaver for VIM.
6 " After loading the script, use :Matrix to start.
7 " Press any key a few times to exit.
9 " You will need to edit s:mindelay and s:maxdelay below to match your
10 " machine speed and window size.
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.
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.
22 " Doesn't work if multiple windows exist before script started. In
23 " that case the script will abort with error message.
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.
30 " Inspired by cmatrix...
31 " Didn't feel inspired enough to start using pico/nano, of course ^_^;
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
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
46 " Speed range, must be positive. Lower delay = faster.
50 " Session file for preserving original window layout
51 let s:session_file = tempname()
55 let b:seed = b:seed * 22695477 + 1
62 function! s:CreateObject(i)
64 let b:x{a:i} = s:Rand() % b:columns
65 if b:reserve{b:x{a:i}} > 4
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}
76 function! s:DrawObject(i)
77 let x = b:x{a:i} * 2 + 1
83 silent! exec 'norm! :' . y . nr2char(13) . x . '|R' . b:d[s:Rand()%b:dl] . '_' . nr2char(27)
85 silent! exec 'norm! kR' . ((s:Rand() % 2) ? '`' : ' ') . nr2char(27)
88 let a = ((s:Rand() % 2) ? '`' : ' ') . nr2char(27)
89 silent! exec 'norm! :'. y . nr2char(13) . x . '|R' . b:d[s:Rand() % b:dl] . a
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)
98 let y = y - b:len{a:i}
100 silent! exec 'norm! :'. y . nr2char(13) . x . '|R ' . nr2char(27)
102 let b:reserve{b:x{a:i}} = y
105 function! s:Animate()
111 if b:y{i} - b:len{i} <= b:h
114 let b:t{i} = b:s{b:x{i}}
115 let b:y{i} = b:y{i} + 1
118 call s:CreateObject(i)
122 let b:t{i} = b:t{i} - 1
134 let b:w = winwidth(0)
135 let b:h = winheight(0)
136 exec 'norm! gg"_dG' . b:h . 'O' . nr2char(27) . 'gg'
138 if b:w < 10 || b:h < 8
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
150 " Initialize 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
157 let b:reserve{i} = b:h
162 let b:objcount = b:columns - 2
165 call s:CreateObject(i)
171 " Create new buffer and hide the existing buffers. Hiding the
172 " existing buffers without switching to a new buffer preserves
174 exec 'mksession! ' . s:session_file
175 let s:num_orig_win = winnr("$")
177 " move to top window, so created window will become window 1,
178 " then attempt to create new window
182 " check that there really is an additional window
183 if winnr("$") != s:num_orig_win + 1
186 let s:newbuf = bufnr('%')
188 " close all but window 1, which is the new window
191 setl bh=delete bt=nofile ma nolist nonu noro noswf tw=0 nowrap
197 set gcr=a:ver1-blinkon0 go=
199 if has('cmdline_info')
205 let s:o_ts = &titlestring
206 exec 'set titlestring=\ '
209 let s:o_spell = &spell
212 set nospell nocul nocuc
222 set ch=1 ls=0 lz nosm nosmd siso=0 so=0 ve=all
225 let b:seed = localtime()
228 " Clear screen and initialize objects
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
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 /.\(_\)\@=/
245 " Create random char dictionary
249 if i != 95 && i != 96
250 let b:d = b:d . nr2char(i)
254 let b:dl = strlen(b:d)
258 function! s:Cleanup()
265 if has('cmdline_info')
271 let &titlestring = s:o_ts
275 let &spell = s:o_spell
278 unlet s:o_cul s:o_cuc
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
290 " Restore old buffers
291 exec 'source ' . s:session_file
292 exec 'bwipe ' . s:newbuf
302 echon 'Can not create window'
308 if b:w != winwidth(0) || b:h != winheight(0)
319 if !has('virtualedit') || !has('windows') || !has('syntax')
321 echon 'Not enough features, need at least +virtualedit, +windows and +syntax'
324 command! Matrix call Matrix()