Vim Tips Wiki
Register
Advertisement
Tip 1349 Printable Monobook Previous Next

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.


Advertisement