" 20170501 SumOfSelection() 1.8 " " This function sums up a visual (block) selection of " numbers and echoes the result. " " Arithmetic operators are also supported: ^ ** * % / - + () " Without operators each line is considered to have one number " and the result of the sum is printed to screen. " " The result is stored in the unnamed register "" and register "0. " You can paste the result in normal mode with p or "0p. And in " insert mode with 0. " " Example mappings: " vmap t :call SumOfSelection() " imap :yank * \| call SumOfSelection() " imap :yank * \| call SumOfSelection()a0 " " Note: mapping requires removing the menu bar with :set go-=m " " Links " http://www.vim.org/scripts/ " http://learnvimscriptthehardway.stevelosh.com/chapters/26.html " http://vim.1045645.n5.nabble.com/my-vimrc-td3396590.html function! SumOfSelection() range let @" = "" let @0 = "" let resultString = "" let resultList = [] let sum = "" let total = "" let warning = "" let error = "" let isVisual = 0 let hasError = 0 " Yank selection into tmp file, instead of pasting the selection in a " new window which would affect window sizes. let tmpFile = tempname() let yankedText = eval("@*") let yankedTextList = add([], yankedText) call writefile(yankedTextList, tmpFile) redir => resultString " redirect stdout to variable total " Remove characters not a number or a point, calculate sum, and print sum. silent exe "w !cat ".tmpFile.' | \perl -e '' \ use strict; \ use warnings; \ use bignum; \ \ $/ = "\x0"; \ my $mathSymbols = "*^\%\\-+\/"; \ my $prevItem = ""; \ my $symbol=""; \ my $total=""; \ my $sum=""; \ my $result=""; \ my $warning=""; \ my $c = "code comments"; \ \ local $SIG{__WARN__} = sub { \ $warning = shift; \ }; \ \ while () \ { \ $_ =~ s/[^0-9]*\.+[^0-9.]+//g; $c="Remove non-numeric chars and their non decimal marks"; \ $_ =~ s/[^0-9\.()$mathSymbols]+//g; $c="Remove chars not a number, point, parenth. or a math symbol"; \ $_ =~ s/\*\*/\^/g; $c="Temporarily use caret as exponentiation symbol"; \ $_ =~ s/[$mathSymbols]{2,}//g; $c="Remove consecutive math symbols"; \ $_ =~ s/\.{2,}/./g; $c="Convert consecutive points to a single point"; \ $_ =~ s/\^/\*\*/g; $c="Translate caret to Perl exponentiation symbol"; \ \ if ($_ eq "") \ { \ next; \ } \ \ $symbol=""; \ $c="IF the previous item didnt end with a math symbol AND"; \ $c="the current item doesnt start with a math symbol THEN"; \ $c="use addition symbol."; \ if ($prevItem \!~ /[$mathSymbols]{1}$/ && \ $_ \!~ /^[$mathSymbols]{1}/) \ { \ $symbol = "+" \ } \ $sum = $sum . $symbol . $_; \ $prevItem = $_; \ } \ { \ $result = eval($sum); \ if ($@) { \ print $sum."|".$result."|".$warning."|".$@; \ } \ else { \ print $sum."|".$result; \ } \ }''' redir END let resultString = substitute(resultString, '\n', '', 'g') let resultList = split(resultString,"|") let sum = get(resultList, 0) let total = get(resultList, 1, "") let warning = get(resultList, 2, "") let error = get(resultList, 3, "") " If the current line is not equal to the selection assume visual selection let isVisual = getline(".")!=strpart(yankedText, 0, strlen(yankedText)-1) let hasError = error!="" if (isVisual) " Restore previous visual mode and escape (i.e. restore cursor pos). silent exe "normal gv\e" endif redraw " force redraw to prevent any postponed redraws (:help echo) if (!hasError) if (total!="") let @"=total let @0=total echo total endif else if (isVisual) echo "Calculation failed\n" echo "Sum : ".sum."\n" if (warning) echo "Warning : ".warning endif echo "Error : ".error endif endif endfunction