Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to get integer object motions in vim?

Tags:

vim

I often work on CSS files or other files that require twiddling numbers. I would love the ability to have a key that refers to integers much in the way that w refers to a word, or ( refers to a sentence. For example, in a css file I could navigate to the beginning of a height declaration, and change it's value without having to retype "px" a the end, which is what happens if I use w.

Is there such a thing, but I'm missing it in the documentation, or is there a way to add this functionality to my .vimrc?

Bonus points if there were a way to use it like ci" where I could be at the begining of the line and use the "change internal" command to jump to AND change the next integer.

More bonus points if I could do simple arithmetic. I would love to be able to issue a concise command that was short for "Add too, internal, integer, 5" and have the next integer on the current line be five grater then it was when I started.

Edit:

Some really great proposals everyone, some great ideas that are sure to improve my work. Thanks! Hassek's answer is probably the most likely to end up in my work-flow, but none of the others seem to have (fully) answered my inital question: A motion that works on integers. The proposal tracked down by romainl appears to have that goal, but I can't get it to work reliably.

For myself (and others perhaps) I will clarify my wants below:

A key that acts much in the way w acts for words, but on integers so that I can simply add it to my mental vim vocabulary and use it seamlessly. This includes the following scenarios. (I will use d as my example key):

  1. Normal mode d: Jump to the next integer
  2. Normal mode cd: Change to the end of the integer under the cursor (Note that cw is a special case that SHOULD change to the NEXT word. cw actually acts like ce.) I would expect this special case to be implemented with integers as well
  3. Visual mode id: Select [count] integers.
  4. Visual mode ad: Select [count] integers. Leading or trailing white space is included.

Am I missing any behavior that w has that might be expected for a new motion? Is there even a key available in both normal and visual modes?

like image 482
Jordan Eldredge Avatar asked Jul 03 '12 22:07

Jordan Eldredge


People also ask

How to use every motion command in Vim?

Every motion can be used after an operator command, so the command operates on the text comprised by the movement's reach. Just like operator commands, motions can include a count, so you can move by 2w ords, for example. In Vim, normal arrow/cursor keys ( ← ↓ ↑ →) work as expected.

What is a text object in Vim?

In Vim, these higher-level contexts are called text objects. Vim provides text objects for both plaintext and common programming language constructs. You can also define new text objects using Vim script. Learning these text objects can take your Vim editing to a whole new level of precision and speed.

What is operator movement in Vim?

Note: Vim recognizes two kinds of movement: operator movement ( :help movement) and jumps ( :help jumplist ). Movements like those executed with g ( gg, G, g,) count as jumps, as do changes. Changes get their own jumplist, which is navigable as mentioned above via g, and g; (see :help changelist ).

How to move by 2w Ords in Vim?

Just like operator commands, motions can include a count, so you can move by 2w ords, for example. In Vim, normal arrow/cursor keys ( ← ↓ ↑ →) work as expected.


2 Answers

you can add or substract from integers using this commands:

<num>Ctrl-a (to add)
<num>Ctrl-x (to substract)

and it will go right to the next number in line and execute the command

like image 127
Hassek Avatar answered Oct 24 '22 06:10

Hassek


See this proposal. It looks good.

edit

Indeed that one is quite nice. This made me think that my habit of doing /<number><Esc> was not very efficient so I've added these mappings (and slightly modified the mappings above for consistency) to my ~/.vimrc. Let's see if they are useful in the long run:

nnoremap è  /\v\d+<CR>
nnoremap é  ?\v\d+<CR>

At first sight, èciè132<Esc> seems to be marginally better than /2<Esc>{count}s132<Esc> in terms of keypresses but substantially better if it allows me to skip a. checking the first digit of the value I want to change and b. counting the characters to replace.

Time will tell.

re-edit

Here are the function and its mappings:

onoremap N  :<c-u>call <SID>NumberTextObject(0)<cr>
xnoremap N  :<c-u>call <SID>NumberTextObject(0)<cr>
onoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap aN :<c-u>call <SID>NumberTextObject(1)<cr>
onoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>
xnoremap iN :<c-u>call <SID>NumberTextObject(1)<cr>

function! s:NumberTextObject(whole)
    normal! v

    while getline('.')[col('.')] =~# '\v[0-9]'
        normal! l
    endwhile

    if a:whole
        normal! o

        while col('.') > 1 && getline('.')[col('.') - 2] =~# '\v[0-9]'
            normal! h
        endwhile
    endif
endfunction

With this, I can:

  • vcdy part of a number from the cursor until its end with <command>N. Somehow similarly to <command>e or <command>w.

    Here are some random numbers: 24 7635 1000018
                                            ^--->
    

    It doesn't work if the cursor is not already on the number and it doesn't go backward.

  • vcdy a whole number with <command>iN.

    Here are some random numbers: 24 7635 1000018
                                          <-^--->
    

    Again, it doesn't work if the cursor is not already on the number.

The whole thing could be improved, sure, but that's a start!

endedit

I work a lot with CSS, too.

I use two strategies to change numerical values:

  • {count}<C-a> and {count}<C-x>, as in Hassek's answer, when I know by how much I want to increment/decrement the number. Say I want to turn 20px into 25px, a simple 5<C-a> does the trick without requiring me to move the cursor to the number. This is extremely cool.

  • /<number><CR>{count}s<new number> when the new value is very different from the current value and I feel to lazy to calculate the delta. /2<CR>2s67<Esc> would allow me to change 23px into 67px. /2<CR>R67<Esc> is another way but it's only good if the new value as the same length as the current value. Use f<number> if you are on the same line.

Note that you can insert the result of expressions with <C-r>=137-42<CR> which I use it very often as well.

like image 37
romainl Avatar answered Oct 24 '22 07:10

romainl