created 2006 · complexity intermediate · author Luis A. Florit · version n/a
This tip adds a good calculator to Vim visual mode selections. It allows you to replace a block of math expressions by their calculated results.
Add the following lines to your vimrc.
function MyCalc(str) if exists("g:MyCalcRounding") return system("echo 'x=" . a:str . ";d=.5/10^" . g:MyCalcPresition \. ";if (x<0) d=-d; x+=d; scale=" . g:MyCalcPresition . ";print x/1' | bc -l") else return system("echo 'scale=" . g:MyCalcPresition . " ; print " . a:str . "' | bc -l") endif endfunction " Control the precision with this variable let g:MyCalcPresition = 2 " Comment this if you don't want rounding let g:MyCalcRounding = 1 " Use \C to replace the current line of math expression(s) by the value of the computation: map <silent> <Leader>c :s/.*/\=MyCalc(submatch(0))/<CR>:noh<CR> " Same for a visual selection block vmap <silent> <Leader>c :B s/.*/\=MyCalc(submatch(0))/<CR>:noh<CR> " With \C= don't replace, but add the result at the end of the current line map <silent> <Leader>c= :s/.*/\=submatch(0) . " = " . MyCalc(submatch(0))/<CR>:noh<CR> " Same for a visual selection block vmap <silent> <Leader>c= :B s/.*/\=submatch(0) . " = " . MyCalc(submatch(0))/<CR>:noh<CR> " Try: :B s/.*/\=MyCalc("1000 - " . submatch(0))/ " The concatenation is important, since otherwise it will try " to evaluate things like in ":echo 1000 - ' 1748.24'" vmap <Leader>c+ :B s/.*/\=MyCalc(' +' . submatch(0))/<C-Left><C-Left><C-Left><Left> vmap <Leader>c- :B s/.*/\=MyCalc(' -' . submatch(0))/<C-Left><C-Left><C-Left><Left> " With \Cs you add a block of expressions, whose result appears in the command line vmap <silent> <Leader>ct y:echo MyCalc(substitute(@0," *\n","+","g"))<CR>:silent :noh<CR> " Try: :MyCalc 12.7 + sqrt(98) command! -nargs=+ MyCalc :echo MyCalc("<args>")
Usage[]
As a visual block calculator
1. First, visually select a (block of) math expression(s). Example: "12.7 + sqrt(98.7)" (without the quotes).
Then type ether \C
or \C=
With \C
the formula will be replaced by its result from bc ("22.63" in the example).
With \C=
the formula will remain, but the result will be appended ("12.7 + sqrt(98.7) = 22.63" in the example).
2. First, visually select a (block of) math expression(s). Example: "sqrt(98.7)".
Then type:
:B s/.*/\=MyCalc("12.7 + " . submatch(0))/
The expression will be replaced by its result ("22.63" in the example).
The marks '<,'> will appear behind the "B", but that is fine (block marks). This is useful if you want to, say, add "12.7" to a (column of) number(s). The numbers do not have to be integers.
Both methods work for block of expressions. So, if you visually select the block:
12.7 + sqrt(98.7) 57 + 12 88 1 == 0 3*4 == 12 s(4)
and type \C
you will have the block replaced with:
22.63 69 88 0 1 -.75
Using bc, 's()' is the sine function.
As a command line calculator
3. In normal mode, type
:MyCalc 12.7 + sqrt(98.7)
You will get "22.63" in the command line. This usage mode is similar to VimTip1235, but doesn't need embedded python.
Requirements[]
It uses Dr.Chip's visual block plugin vis.vim, and the Unix/Linux command line calculator 'bc'.
Do a 'man bc' in the shell to know its built-in functions, like 's()' above. You can easily replace 'bc' by your favorite calculator program.
The precision of the calculator is controlled by the variable g:MyCalcPresition.
References[]
Comments[]
With this map you can add a block of expressions, and the result will appear in the command line:
vmap <Leader>Cs y:echo MyCalc(substitute(@0," *\n","+","g"))<CR>
" I've added the code for Windows. This has been checked " for the shells cmd and 4nt. " " For rounding, the '^' operator, to raise a number to an " integer power, happens to be the escape character for " these shells. Because of the odd escaping required in " CMD, a separate return is needed for CMD vs 4NT. There " is no difference for the non-rounding return. " " You can enter "2^10" for 2 to the power 10. let g:MyCalcPrecision = 2 let g:MyCalcRounding = 1 function MyCalc(str) if exists("g:MyCalcRounding") if has("win32") if &shell =~? "cmd\.exe" let s:str = substitute(a:str,'\^','^^^^','g') return system("echo x=".s:str.";d=.5/10^^^^".g:MyCalcPrecision \.";if(x^^^<0)d=-d;x+=d;scale=".g:MyCalcPrecision.";print x/1|bc -l") else let s:str = substitute(a:str,'\^','^^','g') return system("echo x=".s:str.";d=.5/10^^".g:MyCalcPrecision \.";if(x^<0)d=-d;x+=d;scale=".g:MyCalcPrecision.";print x/1|bc -l") endif else return system("echo 'x=" . a:str . ";d=.5/10^" . g:MyCalcPrecision \.";if (x<0) d=-d; x+=d; scale=" . g:MyCalcPrecision \. ";print x/1' | bc -l") endif else if has("win32") if &shell =~? "cmd\.exe" let s:str = substitute(a:str,'\^','^^^^','g') else let s:str = substitute(a:str,'\^','^^','g') endif return system("echo x=".s:str.";scale=".g:MyCalcPrecision \.";print x/1|bc -l") else return system("echo 'scale=" . g:MyCalcPrecision \. " ; print " . a:str . "' | bc -l") endif endif endfunction
See script#219.