Weird behaviour of C-A of vim? [duplicate] - vim

This question already has answers here:
Why does incrementing with CTRL-A in Vim take me from "07" to "10"?
(2 answers)
Closed 3 years ago.
The behavior of vim's Ctrl A is weird when incrementing numbers <= 0.005.
Due to some personal need, I want to get a set of numbers that increments by 0.005 each time from 0.005,
like this:
0.005
0.010
0.015
...
then I thought of vim's macro and Ctrl A.
I entered 0.005 in vim's first line, use y y p Ctrl A to record a macro. But when I moved the cursor to 5 and then pressed Ctrl A continuously, the third time, the number changed directly from 0.007 to 0.010. If I just press 3 times, the output will become:
0.005
0.010
0.013
0.016
...
That means that I cannot complete the task using vim.
After doing this in other ways, I started to be interested in the behavior of vim's Ctrl A.
The text below comes from vim's help manual:
:h CTRL-A:
Add [count] to the number or alphabetic character at or after the cursor.
and :h count:
An optional number that may precede the command to multiply or iterate the command.
If no number is given, a count of one is used, unless otherwise noted.
When I tested some other numbers, I found that the behavior becomes weird starting from 0.01. But I still don't know why Ctrl A behaves like this.
Before starting to read the source of vim, does anyone know why vim's Ctrl A behaves like this on decimals?
BTW, My PC environment is Win10, and I use vim_only_x64 downloading from vim's official site.

As #Simson Said, vim thinks it is an octal number and increses 0.07 to 0.10.
You can change this behavior by telling vim not to use octal numbers.
:set nrformats-=octal
Then it increases as expected 0.09 => 0.10
You can see the definition o numbers with :h expr-number

Vim does not recognize 0.004 as a decimal fraction, it interpreters it as something.004 The leading 0 of a number encodes an octal number so it increments from 007 to 010
Fun fact it will also recognize hexadecimal numbers 0x09 will be incremented to 0x0a

Related

Vim - Increase number without changing column width

I'm dealing with a fixed-width file format and I need to increase all of the numbers in some columns. I have a simple macro that adds a value to a number, moves to the next line and repeats (like 2aj) However, these numbers start from 1 and usually end above 10000, so the column widths get messed up, e.g. (underscores as spaces, this example only covering the jump from 9 to 10)
FOO_7_BAR
FOO_8_BAR
FOO_9_BAR
becomes
FOO_9BAR
FOO_10_BAR
FOO_11_BAR
(note the new column of text that will break my program)
when I need
FOO_9_BAR
FOO10_BAR
FOO11_BAR
I have been manual going through and deleting a space from the first 9 columns, then 90, then 900, but I am looking for a more robust way to handle this without dealing with the first 10, 100, 1000, etc. with different macros or any manual input.
Thanks.
I come up with this way, I think the animation explains itself:
The final result is:
FOO 3 BAR
FOO 4 BAR
FOO 5 BAR
FOO 6 BAR
FOO 7 BAR
FOO 8 BAR
FOO 9 BAR
FOO10 BAR
FOO11 BAR
This requires a bit of manual hackery, but it's still better than manually deleting spaces.
You could also probably write a function that does this automagically, via Vimscript, though!
First, find the length of the shortest line. You can do this via ex. :echo col("$") on the shortest line.
Then, run the following command:
:g/.\{NUM\}/exec "norm! /[0-9]\<cr>X"
Replace NUM in the above command with the original number you got in the previous step.
Here's an explanation of how it works:
:g/.\{NUM\}/ Find lines that are too long
exec "norm! A common idiom: build a string to execute in normal mode
/[0-9]<cr> Find the first number on the line
X Delete the space before it (equivalent to "hx")
Then simply repeatedly run the same command (you can do this by pressing :UpReturn) until all the lines are the same length—it will result in an error once this is the case (since it won't find any matching lines).
Here's a short animation of the entire process:
This can be done with :s and a sub-replace expression.
:%s/\v([^0-9]*)(\d+)/\=strpart(submatch(1), 0, 5 - len(submatch(2))).submatch(2)
The idea is we capture the portion before the digits and the digits themselves. The replacement execute an vim expression via \= which put the two capture groups back together. However slice the first capture group via strpart() to a fixed width (5 in this example) minus the length of our second capture group, len(submatch(2)).
For more help see:
:h sub-replace-expression
:h strpart()
:h len()

What is the difference between number command motion and command number motion

I'm learning vim with vimtutor. I was wondering if there is a difference between command motion number and number command motion.
For example:
2dw seems to me to work exactly like d2w, similarly 2dd does the same as d2d.
The two numbers are both called [count], in your example, indeed, they do same job. But the two counts come from different concept.
[count]command
this will do the command [count] times, 2dd does dd twice; 2dw does dw twice.
The second is from the {motion}, 2w, 2j etc.
If you want to see some differences, here are two I can think of:
Some commands don't support {motion}. For example, the X, you press 2X, will remove 2 characters before the cursor. However, you cannot do X{motion}. other commands that don't support {motion} p (paste), s etc. You can do 2p, 2s, but you cannot do p2w s3w
You get same result from 2dw and d2w, but the two 2 have different meaning, understanding what the number does is ok. you can combine the count and motion, like 2d3w.
The number command motion can use on all command, but number motion only in a few.
The most important is that repeat-action(.) redo the previous action.
Example:
2dd->. = 2dd->dd
d2d->. = d2d->d2d
Usually, I suggest use the first command. Because it is easier to be repeated.

Vim undocumented side effect when using a numeric value instead of a flag when doing replacement?

While experimenting with Vim substitutions I noticed that something like s/\w*/(&)/2 behaves like 0,2s/\w*/(&). In other words having a numerical value where the g or i or c flags would be(or no flag at all), acts as the max limit of a range affecting the first match on every line.
E.g. running both versions of the above would produce the same output on the text below
alpha
beta
gamma
to
(alpha)
(beta)
gamma
However going through the Vim docs for s_flags as well as searching online I do not see this mentioned somewhere. Has anyone else come against this before and/or is there a perfectly normal explanation?
From :help :s,
:[range]s[ubstitute]/{pattern}/{string}/[flags] [count]
...
When [count] is given, replace in [count] lines,
starting with the last line in [range]. When [range]
is omitted start in the current line.
...
In other words, your 2 is a count, not a flag. It is not clear from this doc that the space is optional, but it seems to be (and I would not relish the job of rewriting it to make that clear).

Vim - count lines in selected range

I want to count lines in a range, not matter what range, but let it be, say, a visual block.
What is the shortest way to do it. All that comes to my mind is something like: '<,'>s/.//n
but I don't believe it is the shortest way.
So, can somebody give me a hint?
In visual mode, press gC-g
Typical output:
Selected 7 of 22 Lines; 8 of 32 Words; 201 of 491 Chars; 201 of 497 Bytes-- VISUAL LINE --
Source: :he count-items (discoverable as: :heTabTab...)
Set the option showcmd (:h 'sc'), and you will never ever need to type anything to know how many lines are selected -- at first, as I forget that I've set this option, I didn't understand the point of your question. ^^'
Otherwise, if you want to obtain that number programmatically, it's simply:
:echo line("'>") - line("'<") + 1
From within a range-function, it can also be obtained by a:lastline-a:firstline+1. (:h function-range-example)
'<,'>s///n is one character shorter. :-)
If I just want to know the number of lines in a visual selection I usually just yank it (hit y). It'll say "5 lines yanked" or "block of 5 lines yanked" depending on the type of selection.

Change the next N characters in VIM

Say I have the following line:
|add_test() (| == cursor position)
And want to replace the 'add' with a 'del'.
del|_test()
I can either press X three times and then press i to insert and type del.
What I want is something like 3c or 3r to overwrite just 3 characters.
Both of these don't do what I want, 3c overwrites 3 characters with the same
character, 3r does several other things.
Is there an easy way to do this without manually Xing and inserting the text?
3s, "substitute 3 characters" is the same as c3l. 3cl and c3l should be the same, I don't know why you'd see the same character repeated. I'm also a fan of using t, e.g. ct_ as another poster mentioned, then I don't have to count characters and can just type "del".
I struggled with the "replace a couple of characters" for a few days too; 'r' was great for single characters, R was great for a string of matching length, but I wanted something like the OP is asking for. So, I typed :help x and read for a while, it turns out that the description of s and S are just a couple of pages down from x.
In other words, :help is your friend. Read and learn.
Use c{motion} command:
cf_ - change up to the first '_' (including);
ct_ - change up to the first '_' (excluding);
cw - change the first word;
The word is determined by iskeyword variable. Check it with :set iskeyword? and remove any '_', like that :set iskeyword=#,48-57,192-255.
By the way see :help c and :help motion if you want more.
I think 3cl is what you want. It changes 3 characters to the right. I'd type ct_del<esc>, but that's not what you asked
c3  ('c', '3', space), then type the characters you want to insert. (Or you can use right-arrow or l rather than space.)
Or, as #Mike just said in a comment, R works nicely if the number of characters happens to match the number of characters you're deleting.
Or ct_ to change from the cursor to the next _ character.
Or, as #bloody suggests in a comment, 3s.
If the works have the same length you can use the R command which replaces what you had previously with what you type.
The other answers given use numbers. When the text is longer it's easier to not have to count. For example I often make headlines in markdown files like:
Some super duper long title that I don't want to have to count
double the line with yy pp
Some super duper long title that I don't want to have to count
Some super duper long title that I don't want to have to count
Highlighth the whole line with V
then use r{char} or in this case r= to get:
Some super duper long title that I don't want to have to count
==============================================================
(I added a space above to trip stack overflow's markdown formatting)

Resources