created 2005 · complexity basic · author Bryce Wagner · version 5.7
I do a lot of mathematical operations on data in text files, and I wanted a way to do it inline instead of having to copy it to a spreadsheet, perform the operations, and copy it back. The following map the four keypad operators (plus, minus, multiply, divide), to their equivalent operation. There are two versions, one for normal mode and one for visual mode.
noremap <kMinus> <C-X> vnoremap <silent><kMinus> :<C-U>'<,'>s%\(-\?\d\+\)%\=submatch(1) - v:count1%g<CR>:noh<CR>gv noremap <kPlus> <C-A> vnoremap <silent><kPlus> :<C-U>'<,'>s%\(-\?\d\+\)%\=submatch(1) + v:count1%g<CR>:noh<CR>gv noremap <silent><kMultiply> :<C-U>s%\(-\?\d*\%#\d\+\)%\=submatch(1) * v:count1%<CR><C-O>h/\d\+/e<CR>:noh<CR> vnoremap <silent><kMultiply> :<C-U>'<,'>s%\(-\?\d\+\)%\=submatch(1) * v:count1%g<CR>:noh<CR>gv noremap <silent><kDivide> :<C-U>s%\(-\?\d*\%#\d\+\)%\=submatch(1) / v:count1%<CR><C-O> ?\d\+?e<CR>:noh<CR> vnoremap <silent><kDivide> :<C-U>'<,'>s%\(-\?\d\+\)%\=submatch(1) / v:count1%g<CR>:noh<CR>gv
Problems I tried hard to get the cursor location to act the same for the multiply and divide as the built in add and subtract, but there are a few conditions where it doesn't. It also clobbers your last search in the process.
Comments[]
Using submatch(0), you wouldn't need the grouping parentheses.
If you use a function, I think you can avoid the change of the search pattern and maybe other anomalies:
function! MultiplyCursor(x) let p = @/ s%\d*\%#\d\+%\=submatch(0) * a:x% exe "normal \<C-O>" let @/ = p endfunction noremap <silent><kMultiply> :<C-U>call MultiplyCursor(v:count1)<CR>
And the same for the other commands.
The minus sign in the search pattern is not needed, because multiplication and division don't change the sign.
If you're going to use a function, might as well do it right. This will catch "failed search" errors and prevent the control-O from being executed. The stuff inside the inner try isn't necessary, but it makes it act more like the built in add and subtract, finding the next number after the cursor on the same line if the cursor isn't already on a number.
function! MultiplyCursor(x) let p = @/ try silent s%-\?\d*\%#\d\+%\=submatch(0) * a:x% exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ try silent exe "normal /\\%#.\\{-}\\zs\\d\\+/b\<CR>" s%-\?\d*\%#\d\+%\=submatch(0) * a:x% exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ endtry finally let @/ = p endtry endfunction function! DivideCursor(x) let p = @/ try s%-\?\d*\%#\d\+%\=submatch(0) / a:x% exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ try silent exe "normal /\\%#.\\{-}\\zs\\d\\+/b\<CR>" s%-\?\d*\%#\d\+%\=submatch(0) / a:x% exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ endtry finally let @/ = p endtry endfunction
A minor addition just for the sake of reducing duplications:
function! CalculateCursor(x, operator) let p = @/ try silent exe "s%-\\?\d*\\%#\\d\\+%\\=submatch(0) " . a:operator . " a:x%" exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ try silent exe "normal /\\%#.\\{-}\\zs\\d\\+/b\<CR>" exe "s%-\\?\d*\\%#\\d\\+%\\=submatch(0) " . a:operator . " a:x%" exe "normal \<C-O>" catch /^Vim\%((\a\+)\)\=:E486/ endtry finally let @/ = p endtry endfunction noremap <kMinus> <C-X> vnoremap <silent><kMinus> :<C-U>'<,'>call CalculateCursor(v:count1, "-")<CR>:noh<CR>gv noremap <kPlus> <C-A> vnoremap <silent><kPlus> :<C-U>'<,'>call CalculateCursor(v:count1, "+")<CR>:noh<CR>gv noremap <silent><kMultiply> :<C-U>call CalculateCursor(v:count1, "*")<CR> vnoremap <silent><kMultiply> :<C-U>'<,'>call CalculateCursor(v:count1, "*")<CR>:noh<CR>gv noremap <silent><kDivide> :<C-U>call CalculateCursor(v:count1, "/")<CR> vnoremap <silent><kDivide> :<C-U>'<,'>call CalculateCursor(v:count1, "/")<CR>:noh<CR>gv