Vim Tips Wiki
Advertisement
Tip 1349 Printable Monobook Previous Next

created October 1, 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