From 0da7b7b7b98e3c85f2984a008aa23876b93546ff Mon Sep 17 00:00:00 2001 From: Simon Ruderich Date: Sun, 26 Apr 2009 14:33:44 +0200 Subject: [PATCH] matrix: Add plugin, version 1.10. Matrix screen saver. --- plugin/matrix.vim | 325 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 325 insertions(+) create mode 100644 plugin/matrix.vim diff --git a/plugin/matrix.vim b/plugin/matrix.vim new file mode 100644 index 0000000..9ed838d --- /dev/null +++ b/plugin/matrix.vim @@ -0,0 +1,325 @@ +" matrix.vim - Don Yang (uguu.org) +" +" Matrix screensaver for VIM. +" +"Usage: +" After loading the script, use :Matrix to start. +" Press any key a few times to exit. +" +" You will need to edit s:mindelay and s:maxdelay below to match your +" machine speed and window size. +" +"Known Issues: +" Sometimes you need to press keys a few times to exit instead of just +" once. Press and hold is another way to go... feels like getchar is +" checking for keypress state instead of keystroke availability. +" +" If the window is too small, script will not run. If the window is +" resized and become too small (less than 8 rows or 10 columns) after +" the script started, script will abort and *buffers may be lost*, so +" don't do that. Resizing the window to most other sizes will be fine. +" +" Doesn't work if multiple windows exist before script started. In +" that case the script will abort with error message. +" +" If the current buffer is modified, some error messages will appear +" before the script starts, and an extra window is left behind after +" the script exits. Workaround: save your buffers first. +" +"Other Info: +" Inspired by cmatrix... +" Didn't feel inspired enough to start using pico/nano, of course ^_^; +" +" 05/13/08 - disable cursorline, cursorcolumn and spell +" (thanks to Diederick Niehorster for the suggestion). +" 12/21/06 - multiwindow support by S. Lockwood-Childs. +" 10/03/05 - added silent! to cursor positioning code to stop drawing +" numbers during animation (thanks to David Eggum for the +" suggestion). +" 10/02/05 - disable showmatch +" 03/16/05 - make new buffer modifiable before running +" 01/27/05 - added sleep to consume less CPU +" removed frame counter +" 01/26/05 - initial version + + +" Speed range, must be positive. Lower delay = faster. +let s:mindelay = 1 +let s:maxdelay = 5 + +" Session file for preserving original window layout +let s:session_file = tempname() + + +function! s:Rand() + let b:seed = b:seed * 22695477 + 1 + if b:seed < 0 + return -b:seed + endif + return b:seed +endfunction + +function! s:CreateObject(i) + while 1 + let b:x{a:i} = s:Rand() % b:columns + if b:reserve{b:x{a:i}} > 4 + break + endif + endwhile + let b:y{a:i} = 1 + let b:t{a:i} = s:Rand() % b:s{b:x{a:i}} + let b:head{a:i} = s:Rand() % 4 + let b:len{a:i} = s:Rand() % b:h + 3 + let b:reserve{b:x{a:i}} = 1 - b:len{a:i} +endfunction + +function! s:DrawObject(i) + let x = b:x{a:i} * 2 + 1 + let y = b:y{a:i} + + " Draw head + if y <= b:h + if b:head{a:i} + silent! exec 'norm! :' . y . nr2char(13) . x . '|R' . b:d[s:Rand()%b:dl] . '_' . nr2char(27) + if y > 1 + silent! exec 'norm! kR' . ((s:Rand() % 2) ? '`' : ' ') . nr2char(27) + endif + else + let a = ((s:Rand() % 2) ? '`' : ' ') . nr2char(27) + silent! exec 'norm! :'. y . nr2char(13) . x . '|R' . b:d[s:Rand() % b:dl] . a + endif + else + if b:head{a:i} && y == b:h + 1 + silent! exec 'norm! :' . b:h . nr2char(13) . (x + 1) . '|R' . ((s:Rand() % 2) ? '`' : ' ') . nr2char(27) + endif + endif + + " Draw tail + let y = y - b:len{a:i} + if 1 <= y && y <= b:h + silent! exec 'norm! :'. y . nr2char(13) . x . '|R ' . nr2char(27) + endif + let b:reserve{b:x{a:i}} = y +endfunction + +function! s:Animate() + let i = 0 + + while i < b:objcount + " Animate object + if b:t{i} <= 0 + if b:y{i} - b:len{i} <= b:h + " Draw + call s:DrawObject(i) + let b:t{i} = b:s{b:x{i}} + let b:y{i} = b:y{i} + 1 + else + " Regenerate + call s:CreateObject(i) + endif + endif + + let b:t{i} = b:t{i} - 1 + let i = i + 1 + endwhile + redraw + if getchar(1) + let b:run = 0 + endif + sleep 20m +endfunction + +function! s:Reset() + " Clear screen + let b:w = winwidth(0) + let b:h = winheight(0) + exec 'norm! gg"_dG' . b:h . 'O' . nr2char(27) . 'gg' + redraw + if b:w < 10 || b:h < 8 + let b:run = 0 + return + endif + + " Set number of columns. This is rounded down due to line wrapping + " at the last column if the screen width is even. So you end up + " seeing the cursor blinking a lot at the right side of the screen. + " Alternatively, ':set rl' before running the script to have it + " blink on the left side. + let b:columns = (b:w - 1) / 2 + + " Initialize columns. + let i = 0 + while i < b:columns + " Set delay time. Each column gets the same delay time. + let b:s{i} = s:Rand() % (s:maxdelay - s:mindelay) + s:mindelay + + " Unreserve column + let b:reserve{i} = b:h + let i = i + 1 + endwhile + + " Initialize objects + let b:objcount = b:columns - 2 + let i = 0 + while i < b:objcount + call s:CreateObject(i) + let i = i + 1 + endwhile +endfunction + +function! s:Init() + " Create new buffer and hide the existing buffers. Hiding the + " existing buffers without switching to a new buffer preserves + " undo history. + exec 'mksession! ' . s:session_file + let s:num_orig_win = winnr("$") + + " move to top window, so created window will become window 1, + " then attempt to create new window + 1 wincmd w + silent! new + + " check that there really is an additional window + if winnr("$") != s:num_orig_win + 1 + return 1 + endif + let s:newbuf = bufnr('%') + + " close all but window 1, which is the new window + only + + setl bh=delete bt=nofile ma nolist nonu noro noswf tw=0 nowrap + + " Set GUI options + if has('gui') + let s:o_gcr = &gcr + let s:o_go = &go + set gcr=a:ver1-blinkon0 go= + endif + if has('cmdline_info') + let s:o_ru = &ru + let s:o_sc = &sc + set noru nosc + endif + if has('title') + let s:o_ts = &titlestring + exec 'set titlestring=\ ' + endif + if v:version >= 700 + let s:o_spell = &spell + let s:o_cul = &cul + let s:o_cuc = &cuc + set nospell nocul nocuc + endif + let s:o_ch = &ch + let s:o_ls = &ls + let s:o_lz = &lz + let s:o_siso = &siso + let s:o_sm = &sm + let s:o_smd = &smd + let s:o_so = &so + let s:o_ve = &ve + set ch=1 ls=0 lz nosm nosmd siso=0 so=0 ve=all + + " Initialize PRNG + let b:seed = localtime() + let b:run = 1 + + " Clear screen and initialize objects + call s:Reset() + + " Set colors. Output looks better if your color scheme has black + " background. I would rather not have the script change the + " current color scheme since there is no good way to restore them + " afterwards. + hi MatrixHidden ctermfg=Black ctermbg=Black guifg=#000000 guibg=#000000 + hi MatrixNormal ctermfg=DarkGreen ctermbg=Black guifg=#008000 guibg=#000000 + hi MatrixBold ctermfg=LightGreen ctermbg=Black guifg=#00ff00 guibg=#000000 + hi MatrixHead ctermfg=White ctermbg=Black guifg=#ffffff guibg=#000000 + sy match MatrixNormal /^.*/ contains=MatrixHidden + sy match MatrixHidden contained /.`/ contains=MatrixBold + sy match MatrixHidden contained /._/ contains=MatrixHead + sy match MatrixBold contained /.\(`\)\@=/ + sy match MatrixHead contained /.\(_\)\@=/ + + " Create random char dictionary + let b:d = '' + let i = 33 + while i < 127 + if i != 95 && i != 96 + let b:d = b:d . nr2char(i) + endif + let i = i + 1 + endwhile + let b:dl = strlen(b:d) + return 0 +endfunction + +function! s:Cleanup() + " Restore options + if has('gui') + let &gcr = s:o_gcr + let &go = s:o_go + unlet s:o_gcr s:o_go + endif + if has('cmdline_info') + let &ru = s:o_ru + let &sc = s:o_sc + unlet s:o_ru s:o_sc + endif + if has('title') + let &titlestring = s:o_ts + unlet s:o_ts + endif + if v:version >= 700 + let &spell = s:o_spell + let &cul = s:o_cul + let &cuc = s:o_cuc + unlet s:o_cul s:o_cuc + endif + let &ch = s:o_ch + let &ls = s:o_ls + let &lz = s:o_lz + let &siso = s:o_siso + let &sm = s:o_sm + let &smd = s:o_smd + let &so = s:o_so + let &ve = s:o_ve + 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 + + " Restore old buffers + exec 'source ' . s:session_file + exec 'bwipe ' . s:newbuf + unlet s:newbuf + + " Clear keystroke + let c = getchar(0) +endfunction + +function! Matrix() + if s:Init() + echohl ErrorMsg + echon 'Can not create window' + echohl None + return + endif + + while b:run + if b:w != winwidth(0) || b:h != winheight(0) + call s:Reset() + else + call s:Animate() + endif + endwhile + + call s:Cleanup() +endfunction + + +if !has('virtualedit') || !has('windows') || !has('syntax') + echohl ErrorMsg + echon 'Not enough features, need at least +virtualedit, +windows and +syntax' + echohl None +else + command! Matrix call Matrix() +endif -- 2.44.1