In Vi/Vim, how do I copy a substring inside a line - vim

I have a dictionary in my config file.
candidates = {'morpheus':(3,1), 'trinity':(3,1), 'neo':(3,1), 'switch':(3,1)}
I can highlight with my mouse one k/v pair (e.g. 'neo':(3,1)) to copy and paste if I needed add more k/v pairs to the dictionary but is there a way using vi keyboard commands to yank from the current cursor to the next comma or space to grab the 'neo':(3,1) k/v pair?
I know there's yw for yank word but in this case, vi stops at the punctuation marks and doesn't grab what I want. I think I can also yank characters to the left or right of the cursor but I don't want to count characters if I can help it.
Is there a way to tell vi to yank from the current cursor position to the next space or the next ) character?

yw, which is actually "yank to next word" rather than "yank word", is not to be taken as a single command. It really is two commands: an operator, y, followed by a motion, w. This is pretty important because understanding that operator+motion model allows you to freely compose very expressive editing commands.
In this case, you can move the cursor to the closing ) with f) or 2t,, which gives you the two following commands:
yf)
y2t,
See :help f, :help t, and the user manual's introduction of the operator+motion model: :help 04.1.

Yank to the next space (excluding space) yt (Note the space at the end, the character yanking to)
Yank to the second space (excluding space) y2t
Yank to the next space (including space) yf
Yank to end of line y$
Yank everything inside of current '...' yi'

Related

Changing case at the end of a word in Vim

I know gUw will turn properties to PROPERTIES and stay at the first character of the word.
But if I use gUb, it will be PROPERTIEs and cursor at the first charactoer.
If I use gUge, it will be PROPERTIES but cursor at last word.
What should I do if I want to turn the word to upper case, and stay at the end of the word(so that i can keep on typing without a w)
All operator+motion edits will leave the cursor on the first character of the motion. From :help motion.txt:
After applying the operator the cursor is mostly left at the start of the text that was operated upon. For example, "yfe" doesn't move the cursor, but "yFe" moves the cursor leftwards to the "e" where the yank started.
So, assuming your cursor is on the last character of the current word:
properties
^
there is no built-in way to ensure that the cursor will stay there after an operator+motion edit.
One can leave a mark and jump back to it after the edit:
m'gUiw``
but that's more work than just pressing w. It could be turned into a mapping, though, if that's a common need:
nnoremap <key> m'gUiw``
but that doesn't sound very scalable.
Another approach would be to record your edit:
qq
m'gUiw``
q
and play it back as needed:
#q
But your last sentence is puzzling:
What should I do if I want to turn the word to upper case, and stay at the end of the word(so that i can keep on typing without a w)
If you are at the end of:
properties
^
and your edit leaves the cursor at the beginning of:
PROPERTIES
^
w will move the cursor to the beginning of the next word:
PROPERTIES foo
^
and not to the end of the current word.
We are missing some context, here.

the command y3s to copy three lines in Normal Mode in Vim

According to Vim's Verb, Noun, and Modifier logic the command y3s should potentially copy three sentences, but in my version of Vim it doesn't do that. I am wondering if there is a reason for it. Looking up online it seems like there are other ways to copy a specific number of sentences, but I am curious why this approach doesn't work. Thanks!
Several misconceptions here. First, there is a difference between motions and text objects.
A motion (:help navigation) is a command that changes the position of the cursor: l for right, j for down, ) for sentence forward, 2Fx backward to before-previous x in the same line, /foo/e+2<CR> forward to 2 characters after the end of next foo, w start of next word. Commands whose argument is a motion operate on the text span from the current position to the new motion-specified position. dw thus deletes from current position to the start of the next word.
A text object (:help text-objects) specifies a semantic unit of text; it typically consists of two keypresses, the first of which is i (inside, inner) or a (a, an, around). i" inside double quotes, a( around parenthesis, is inner sentence (i.e. without spaces around it), 2aw twice a word. Thus daw delete around this word (including the space), or simpler, delete a word.
The difference is clear: if you are in the middle of a word, e.g. Some peng|uins fly (with | representing the cursor), dw gives you Some peng|fly (deleting from cursor to start of the next word), while daw gives you Some |fly (deleting the entire word penguins, along with the next space because of the "around" modifier). diw would give you Some | fly (not including the space into the deletion).
As you'll note, "sentence" has a different mapping in text motions (( sentence backward, ) sentence forward) and text objects (is inner sentence, as a sentence). Meanwhile, ( as a text object, equivalently to ) and b, is everything inside, or around, parentheses; and s as a text motion does not exist by default.
Thus, y2s is not a known mapping, since you are deleting by motion (no i or a), and there is no motion s; it will not do anything.
You can use y2), which would yank about a sentence and a half (i.e. from cursor to the start of the second next sentence); or you can use y2as to yank the current sentence and the next sentence and a space after it; or y2is for the same except without that last space; but you cannot use y2s. (You can also write all of those as 2y), 2yas, 2yis.)
In y2y (or equivalently 2yy), the second y is the duplication of the operator. It is almost a rule in Vim that the motion equal to the operator is a line: yy yank a line, dd delete a line, gqgq (or gqq) reformat a line, == filter a line, gugu (or guu) uppercase a line etc. The reason is a simple convenience: lines are what we operate on most frequently, and it's hard to make a faster incantation than the same key pressed twice. Thus, the second y by itself does not have a meaning: it signifies that the first y is working on lines (thus y2y or 2yy yank two lines).
The whole :help motion.txt page is a very useful read, I heartily recommend it.
If you want to copy 3 lines, you should do y3y, not y3s. y stands for Yank or copy.
Update,
#Amadan 's answer has more explanation and also for why y3y works.
Simpley 3Y will do, where Y will yank a line and 3 will repeat it 3 times. In Vim there are no sentences, only lines, words, and characters.

What is the best way to refactor a Ruby ‘if’ statement into one-line shorthand form in Vim?

I have the following Ruby code:
if some_cond && another
foo_bar
end
and I want to change it to:
foo_bar if some_cond && another
What are the most idiomatic ways to do that in Vim?
Assuming that the cursor is located at the if-line prior to
refactoring (not necessarily at the beginning of that line),
I would use the following sequence of Normal-mode commands:
ddjVpkJ<<
or this chain of Ex commands:
:m+|-j|<|+d
Here the if-line is first moved down one line by the :move + command.
The :move command cuts a given range of lines (the current line, if
not specified) and pastes it below the line addressed by the argument.
The + address is a shorthand for .+1 referring to the next line
(see :help {address}).
Second, the line containing the body of the conditional statement is
joined with the just moved if-line. The :join command concatenates
a given range of lines into a single line. The - range is a shortened
form of the .-1 address referring to the line just above the cursor
(see :help {address}).
Third, the newly joined line is unindented by one shiftwidth using
the :< command.
Finally, the remaining end-line, which can now be addressed as +,
is removed by the :delete command.
I see few (probably non-optimal) solutions:
cursor in first character in first line:
D - remove if condition but leave cursor in same position (don't delete line)
J - join next line to current
A <Space> <ESC> - append space and exit to Normal mode
p - paste if condition
and then remove remaining end with jdd
cursor in first character in first line, as previously:
j - move to next line
dd - remove this line
k - move back to if condition
P - paste removed line before actual line, cursor should be placed to pasted line
J - join next line to current
== or << - unindent current line
and then remove remaining end with jdd
another solution:
j - move to second line
JD - join line with next, remove what was joined
dd - remove current line
k - step to previous line
PJ<< - paste, join and unshift
It's probably not optimal, but I do it without thinking, because most of this commands are in my muscle memory (you don't think how to move around you, how to yank/delete and paste most of the time, and joining line is also helpful to remember).
If you have virtualedit enabled in config, instead of A <Space> <Esc> you can $ <Space>, but I find $ harder to use than A followed by Ctrl-[ (it's simmilar to ESC).
As an advice: if you use some upper letter commands, try to chain them if it's possible, so you only need to keep Shift pressed and then execute some commands, instead of mixing upper and lower letter commands and pressing two keys at a time (upper letter is 2 key press, one is Shift). Once I found combo helpful for restarting server in console Ctrl+cpj, which sends Ctrl+c, Ctrl+p (previous command) and Ctrl+j (Enter key) with single Ctrl press. Since then I try to find simmilar time-saving combination in Vim too mostly with Shift, as Ctrl is not much used in Vim.
Yet another way:
ddpkJjdd
ddp swap the two lines
kJ move up and join the lines
== re-indent the line
jdd move down and delete the last line
There are probably 30 ways to do this.
Here is one, assuming you are starting from the end of the word end in normal mode:
dd (delete last line)
"aD (delete and copy foo_bar to buffer a)
dd (delete now-empty line 2)
"aP (paste from buffer a before caret)
aSpaceEsc (insert space and return to normal mode)
Again, "properly" rarely applies in Vim because there are so many ways to accomplish something. This is so small a change that even re-typing foo_bar could be justifiable.

How do you yank X number of characters in vim?

I know I can cut 5 characters in vim by typing 5x, and I often use this to copy and paste text by doing 5xu then pasting them somewhere else.
I am lazy and would rather just yank the 5 characters so I don't have to undo the cut action.
How can I do this?
Yank supports standard movement commands. Use y5l (<- that's a lowercase L)
And if you want to yank 5 characters backwards, use y5h.
Now, if you're feeling really lazy, remap this particular sequence to a key-combination, like so:
:nnoremap <C-l> y5l
In this case, "yank 5 to the right" gets mapped to Ctrl+L (lowercase L).
If you'd like, you can also use Space instead of L to yank characters in the forward direction (examples: ySpace for a single character or 5ySpace for 5). Some people may find it to be quicker or easier than hitting L.
This is complementing the answer of voithos:
You can also use 5ySpace or y5Space (ty #hauleth for suggestion)
This is useful for me especially when I want to yank just one character:
ySpace
Is easier (for me at least) to find and hit Space than l.
Found this post because I too wanted to yank x number characters without cutting and learned this while testing.
There may be times when is easier to look for certain characters than to count the number of characters to yank.
Enter the motions t and T.
Think ytx as yank forward to character x
Think yTx as yank backward to character x
y5 will do it. yy yanks lines, y yanks characters.

Vim yanking range of lines

I'm a C# developer who has just recently decided to expand my knowledge of the tools available to me. The first tool I've decided to learn is Vi/Vim. Everything has been going well so far, but there are a couple of questions I can't seem to find the answer to:
Lets say I wanted to yank a range of lines. I know there are many ways of doing so, but I would like to do it by line number. I figured it would be similar to how the substitute commands work, something like 81,91y. Is there a way to do this?
I'm a little confused about the g command in normal mode. It seems to do a myriad of things and I can't really determine what the g command does at its core. I'm confused on whether or not it's a motion command or a kind of "catch all" for other commands ran through normal mode. Can someone please explain this or point me to a reference that gives a good explanation of the g command?
Yank lines 81-91
:81,91y<enter>
If your fingers don't like to find the : and , keys, this would work as well (go to line 81, yank 11 lines)
81gg11yy
My only use of g is 5gg. To go to the 5th line. 22gg: 22nd line. As jimbo said, it's really only a modifier for some other commands.
For completeness, (http://vim.wikia.com/wiki/Power_of_g) explains a lot of how g works in command mode.
You can also copy the current lines to your present cursor location using 't'.
:81,91t.<enter>
This will paste the lines 81-91 under the line the cursor is on.
I learned this from http://vimcasts.org which is an excellent resource on VIM.
I also like to use vim's relative line number option which means I can just enter:
:-10,-7ya a
to yank the text into named buffer a.
N.B. Specifying A will append what you're yanking to the current contents of buffer a.
Don't forget you can also copy blocks of text and move blocks of text around as well with the similar commands:
:-10,-7co .
means copy the four lines of text 10 lines above to below the current line, and
:-10,-7mo .
means move the four lines of text 10 lines above to below the current line.
The G command goes to a certain line number, if it's accompanied by a count value. 81G puts you on line 81.
The y command can be combined with a movement, like G. So to yank everything until line 91 you can use y91G.
Together you get:
81Gy91G
Go to line 81, then yank while going to line 91.
g doesn't do anything by itself. It's one of a couple meta-commands that holds a bunch of sorta-unrelated commands.
z is yet another command like that.
In addition to :91,96y a which yanks (y) lines 91 through 96 into register a, (pasted with "ap), the yanked lines can be appended to the register with:
:91,96y A
I.e. the capitalization of the A register causes an appending operation into register a instead of an overwrite. Capitalization of the register always works like this, e.g. :let #A=';' appends a ; to register a.
Using plus (+) or minus (-) references lines relative to the current cursor position:
:-10,+10y b
I.e. it would yank(y) 21 lines around the current cursor position and put them in register b.
An absence of input actually represents the current cursor position as well, which means that this:
:-5,y a
would yank the text from 5 lines above to current cursor position into named buffer a, and:
:,+5y a
would yank the 5 lines after the current cursor position into buffer a.
Note: If you have a macro in buffer a it was just overwritten by the previous yank, as yank registers and macro registers are really the same thing. Which is why, coincidentally, you can paste a macro, edit it, and then yank it back into it's register. I personally use letters reached by my left hand for yanks, and letters reached by my right hand for macros.
Moving blocks of text around, looks like this:
:+10,+13m.
which means move the four lines positioned 10 lines ahead of current cursor, to below the current line.
Addendum
I previously confused ya in :91,95ya a to be somehow synonymous with ya{motion} where the motion was supplied by 91,95. This was incorrect and the "a" in ya is completely unnecessary. In my defense, my help yank does not convey that ya is a possible alias of yank.
The best solution would be to enter "visual mode", by pressing v. And after selecting lines just copy them by pressing y. Then paste copied lines by pressing p.
Vim's :help index describes g as:
|g| g{char} extended commands, see |g| below
Scroll down (or :help g) for a list.
As a long time Vi/Vim user I tend to use 'marks' instead of line numbers (or 'line markers'). It works like this: m is the 'mark' character; then use any letter to identify/name the mark. To return to a mark preface the named mark with a single quote ( 'a)These marks can be used as the range. Examples:
File:
<line 1>
<line 2>
<line 3>
<line 4>
<line 5>
When in command mode move cursor to line 2, typema. scroll to line 4, typemb.
To yank from mark a to mark b type:
:'a,'byank
To delete from mark a to mark b type:
:'a,'bdel
To search from mark a to mark b and replace 'ine' with 'ink':
:'a,'bs/ine/ink/g
To copy mark a through mark b and paste below the current position (the 'dot' always references the line where the cursor currently is positioned):
:'a,'bco .
Shift lines of code, between mark a through mark b, one tab to the right (use opposite chevron, <, to move left):
:'a,'b>
In command mode you can move back to marks by simply typing 'a to move back to the line marked a. Typing '' moves you back to previous position (unfortuantely only remembers the previous position, not two back).
You can yank to named buffers, copy, delete lines, search&replace just portions of your code, etc. without needing to know the line numbers.
To yank lines from line number 81 to 91 :
approach 1: 81gg11yy
not bad but you have to do little bit of math to find out how many lines to yank
approach 2: 81gg then shift+v then 91gg then y
BEST IN MY OPINION because this is straight forward, you only have to know the obvious thing i.e from which line number to which line number you want to yank

Resources