3

I can increment the number under the cursor (by e.g. 10) by doing

10<C-a>

But how do I multiply the number under the cursor with x amount and the replace it in the same way I do when incrementing by a constant amount?

0

2 Answers 2

3

There's no magic, single operation for arithmetic. You can use substitution with sub-replace expression. This will replace all numbers on the current line with their value multiplied by 5.

s/\d\+/\=submatch(0)*5/

The \= operator tells Vim to treat everything that follows as an expression, evaluate it, and use the result as the replacement of the final matched text. And when submatch(0) is evaluated it returns whatever the pattern on the left matched. I'm multiplying that by 5, as I mentioned.

Tune the pattern part as needed for your particular situation. I'm matching any numbers but you could just put 10 there though that's not particularly useful for general needs. If there are other things on the line that you want to ignore you could use \zs and \ze to isolate a number. This one will only effect a number that follows a colon at the beginning of the line:

s/^:\zs\d\+\ze/\=submatch(0)*5/

Rather than describe in detail how sub-replace expressions generally work in this space you can look at my answer here: How to run a substitute command on only a certain part of the line

2
  • Dont you need a string to number conversion on submatch? Or are you relying on implicit coercions?
    – D. Ben Knoble
    Feb 25, 2021 at 15:31
  • 1
    I am converting. Somewhere in the docs there are instructions on how to convert a string to a number. Something like "100" + 0 => 100, i.e. arithmetic is pretty explicit conversion.
    – B Layer
    Feb 25, 2021 at 15:57
1

You could use the following to reimplement a mechanism similar to <c-a> but for multiplication:

function! MultiplyInPlace(count) abort
    " Get the word under the cursor
    let current_word = expand('<cword>')

    " If we don't match a number return
    if (current_word !~ '\d\+')
        return
    endif

    " Get cursor position
    let col = getcurpos()[2]


    " Calculate the result and replace in buffer
    let res = current_word * a:count
    execute 's/\%' . col . 'c' . current_word . '/' . res 

    " Move back to the number we changed
    normal! g``
endfunction

" Use [count]<leader><c-x> to multiply number under cursor by [count]
nnoremap <silent> <leader><c-x> :<C-U>call MultiplyInPlace(v:count1)<CR>

The idea is to create a function MultiplyInPlace() which takes a count as argument. The function will use :h <cword> to get the word under the cursor and match it against /\d\+/ to make sure it's a number (:h expr-=~).

If it's a number a simple multiplication is done and we use a substitute command forged with execute to do the replacement. (:h :execute).

In the substitute command get use the :h /\%c atom to match the current column of the cursor to avoid the bug described by @Benji in their comment on this answer.

The last line is needed to avoid the cursor jumping at the beginning of the line. (`:h g``)

Then you can create a normal mode mapping (here <leader><c-x>) which will take a count and call the function with it (and use 1) if no count is provided. (:h v:count)

You can then adapt the code pretty simply to also handle the divisions (either create a second function DivideInPlace() or add a new argument to MultiplyInPlace() to switch between behaviors).

2
  • There is a bug in the above. Because of the way s is used to replace the word, if there are two of the same numbers on the line, the first will be replaced even if the cursor is over the second.
    – Benji York
    Feb 5, 2022 at 14:16
  • 1
    That's true thanks @BenjiYork for pointing that out. I edited my answer: By using getcurpos() to get the column where the cursor is and using /\%c in the pattern I think the bug is fixed.
    – statox
    Feb 7, 2022 at 12:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.