Mercurial > dotfiles.old
diff vim/bundle/math/plugin/vmath.vim @ 22:b2c16cd71d95
Add math plugin
author | zegervdv <zegervdv@me.com> |
---|---|
date | Sun, 23 Mar 2014 18:08:34 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vim/bundle/math/plugin/vmath.vim Sun Mar 23 18:08:34 2014 +0100 @@ -0,0 +1,140 @@ +" Vim global plugin for math on visual regions +" Maintainer: Damian Conway +" License: This file is placed in the public domain. + +"###################################################################### +"## ## +"## To use: ## +"## ## +"## vmap <expr> ++ VMATH_YankAndAnalyse() ## +"## nmap ++ vip++ ## +"## ## +"## (or whatever keys you prefer to remap these actions to) ## +"## ## +"###################################################################### + + +" If already loaded, we're done... +if exists("loaded_vmath") + finish +endif +let loaded_vmath = 1 + +" Preserve external compatibility options, then enable full vim compatibility... +let s:save_cpo = &cpo +set cpo&vim + +" Grab visual selection and do simple math on it... +function! VMATH_YankAndAnalyse () + return "y:call VMATH_Analyse()\<CR>gv" +endfunction + +" What to consider a number... +let s:NUM_PAT = '^[+-]\?\d\+\%([.]\d\+\)\?\([eE][+-]\?\d\+\)\?$' + +" How widely to space the report components... +let s:REPORT_GAP = 5 "spaces between components + +" Do simple math on current yank buffer... +function! VMATH_Analyse () + " Extract data from selection... + let selection = getreg('') + let raw_numbers = filter(split(selection), 'v:val =~ s:NUM_PAT') + let numbers = map(copy(raw_numbers), 'str2float(v:val)') + + " Results include a newline if original selection did... + let newline = selection =~ "\n" ? "\n" : "" + + " Calculate and en-register various interesting metrics... + let summation = len(numbers) ? join( numbers, ' + ') : '0' + call setreg('s', s:tidy( eval( summation ) )) " Sum --> register s + call setreg('a', s:average(raw_numbers) ) " Average --> register a + call setreg('x', s:tidy( s:max(numbers) )) " Max --> register x + call setreg('n', s:tidy( s:min(numbers) )) " Min --> register n + call setreg('r', @n . ' to ' . @x ) " Range --> register r + + " Default paste buffer should depend on original contents (TODO) + call setreg('', @s ) + + " Report... + let gap = repeat(" ", s:REPORT_GAP) + highlight NormalUnderlined term=underline cterm=underline gui=underline + echohl NormalUnderlined + echo 's' + echohl NONE + echon 'um: ' . @s . gap + echohl NormalUnderlined + echon 'a' + echohl NONE + echon 'vg: ' . @a . gap + echon 'mi' + echohl NormalUnderlined + echon 'n' + echohl NONE + echon ': ' . @n . gap + echon 'ma' + echohl NormalUnderlined + echon 'x' + echohl NONE + echon ': ' . @x . gap + +endfunction + +" Prettify numbers... +function! s:tidy (number) + let tidied = printf('%g', a:number) + return substitute(tidied, '[.]0\+$', '', '') +endfunction + +" Compute average with meaningful number of decimal places... +function! s:average (numbers) + " Compute average... + let summation = eval( len(a:numbers) ? join( a:numbers, ' + ') : '0' ) + let avg = 1.0 * summation / s:max([len(a:numbers), 1]) + + " Determine significant figures... + let min_decimals = 15 + for num in a:numbers + let decimals = strlen(matchstr(num, '[.]\d\+$')) - 1 + if decimals < min_decimals + let min_decimals = decimals + endif + endfor + + " Adjust answer... + return min_decimals > 0 ? printf('%0.'.min_decimals.'f', avg) + \ : string(avg) +endfunction + +" Reimplement these because the builtins don't handle floats (!!!) +function! s:max (numbers) + if !len(a:numbers) + return 0 + endif + let numbers = copy(a:numbers) + let maxnum = numbers[0] + for nextnum in numbers[1:] + if nextnum > maxnum + let maxnum = nextnum + endif + endfor + return maxnum +endfunction + +function! s:min (numbers) + if !len(a:numbers) + return 0 + endif + let numbers = copy(a:numbers) + let minnum = numbers[0] + for nextnum in numbers[1:] + if nextnum < minnum + let minnum = nextnum + endif + endfor + return minnum +endfunction + + +" Restore previous external compatibility options +let &cpo = s:save_cpo