How to manually mark lines and store to register - vim

What is an easy way to manually mark arbitrary lines and yank/delete them without writing to the document?
Eg line 10,17,33 in a 50 line document. Without using the line numbers, though.
My workaround so far:
I put a unique string at the beginning of the lines, eg x and
:g/^x/y R
yank them to a register (r in this case)
After putting I still have to delete the string
:s/^x//g
How can this be done better and without temporarily changing the document?
EDIT:
I want to keep the advantages of this method:
Keep the original order regardless of the order I marked the lines
I can see which lines are marked already
The fewer keystrokes per line the better, of course

If it's no more than 26 locations in the buffer, I would mark them with lowercase marks (ma, mb, ...), then step through them from the beginning of the buffer with ]' while yanking them into an uppercase register:
gg]'"ryy]'"Ryy]'"Ryy...
Unfortunately, ]' doesn't beep when there's no more mark, so you cannot employ a recursive macro that would automatically stop.

Move the cursor to the first line, do "Ryy, repeat.

Related

Deleting to beginning of line - d0 leaves extra space

I am trying to delete an indented line to the beginning of the line, with d0, but that leaves an extra space that I must delete with x.
The use case is that often I want to insert a blank line between two lines, and yes, I could use 'o' or 'O' and 'Esc' but often I enter insert mode out of habit and enter a line. The autoindent in vim adds a line with extra space (even with smartindent) so I am left with some dangling space that I have to delete with 'd0x'.
The extra 'x' seems awkward given that 'D' deletes to the end of the line leaving no extra space, and yes I could use '0D' to do the same with in one less stroke. But I would like your opinions as to the best approach for this situation. Thanks.
Addressing the very specific point of why d0 leaves an extra space: The 0 motion is an exclusive motion, which means the last character towards the end of the region is excluded from the operation.
You can use the v modifier to toggle the characterwise motion and make it inclusive:
dv0
This should remove all the characters from the beginning of the line, including the one under the cursor.
If there's some complicated thing you want to do in vim with minimal keystrokes, the usual approach is to just create a macro for it and bind that macro to a specific key sequence.
For example, for your use case of inserting a blank unindented line, you could just bind to O<ESC>0D (or whatever other key sequence you need). You can test this with the keystrokes (in normal mode, and <ESC> is a single press of the ESC key, not the five individual characters):
qdO<ESC>0Dq
Then just go to some line in your file, enter #d and, voila, an unindented blank line.
To make this permanent, just add it to your vimrc file:
let #d='O<ESC>0D'
where, if you're editing it with vim, ESC can be entered as CTRL-VESC.
Another possibility is to just not worry about indents until some point in the future. By all means, use whatever commands you desire to give yourself a blank line (possibly indented) but either fix that before final write by deleting all trailing tabs and spaces:
:g/[ <TAB>]\+$/s///
or run a script on all files to fix this in a batch operation (even better if this is done as part of automatic pre-checks before source code commit), for example:
find . -name *.cpp -exec sed -iE 's/[ \t]+$//' {} \;

How to delete, including the current character?

Let's say I've typed "abcdefg", with the cursor at the end. I want to delete back to the c, so that I only have "abc" left.
Is there a command like d that includes the current character? I know I could do dTcx, but the x feels like a work-around and I suppose there's a better solution.
No. Backward motions always start on the left of the current character for c, y and d which is somehow logical but also unnerving.
The only "clean" solutions I could think of either imply moving to the char after c first and then do a forward delete:
Tcde
or using visual mode:
vTcd
v3hd
But, given your sample and assuming you are entering normal mode just for that correction, the whole thing sounds extremely wasteful to me.
What about staying in insert mode and simply doing ←←←←?
try this:
TcD
this will leave abc for your example... well if the abcdefg is the last word of the line.
if it is not the last word in that line, you may do:
ldTc
or golfing, do it within 3 key-stroke:
3Xx or l4X
See this answer to a similar question : there is a setting to be allowed to go beyond the end of the line
From the doc :
Virtual editing means that the cursor can be positioned where there is
no actual character. This can be halfway into a tab or beyond the end
of the line. Useful for selecting a rectangle in Visual mode and
editing a table.
"onemore" is not the same, it will only allow moving the cursor just
after the last character of the line. This makes some commands more
consistent. Previously the cursor was always past the end of the line
if the line was empty. But it is far from Vi compatible. It may also
break some plugins or Vim scripts. For example because |l| can move
the cursor after the last character. Use with care!
Using the $ command will move to the last character in the line, not
past it. This may actually move the cursor to the left!
The g$ command will move to the end of the screen line.
It doesn't make sense to combine "all" with "onemore", but you will
not get a warning for it.
In short, you could try :set virtualedit=onemore, and see if your environment is stable or not with it.
Use d?c
That will start d mode, search back to 'c' and then delete up to your cursor position.
Edit: nope, that does not include current position...
I may be misunderstanding your request, but does 3hd$ do it?
I would use vFdd in this example. I think it's nicer than the other solutions since the command explicitly shows what to delete. It includes the current character and the specified character when deleting.
v: enter visual mode (mark text)
F: find/goto character backwards
d: the character "d" that will be included for removal.
d: delete command
Since it is visual mode, the cursor can also be moved before executing the actual removal d. This makes the command powerful even for deleting up to a non unique character by first marking a special character close to the character and then adjusting the position.

Vim: Yank distant line without moving

Suppose I have the following (* = cursor):
...
*
Kittens
Puppies
Humans
...
How do I yank the "Humans" (cursor relative 3rd line) while leaving the cursor in place?
Preferably in one motion or one (generic) command.
Try this:
:+3y
It uses the range +3 , that it is the point where it will begin to yank. and by default it does one line.
UPDATE: If you wanted to copy both the second and third line without moving cursor, you would use same command but with a range of two points, like:
:+2,+3y
It would copy both Puppies and Humans.
Now, for those who are wondering, based on Birei's answer, you can also do :ny, where n is the line number you want to yank. This is actually what I was looking for when I came to this page, and is helpful if you've got set number on and don't want to count relative lines.
Now, I wonder, how to perform this yank to a particular register! :D
My LineJuggler plugin combines yanks and puts into various short mappings; e.g. with 3[f you can fetch a line 3 lines below the current line and put it below the current line.

How to replace the whole line with the text in the buffer in VIM?

Here is the text I'm working on:
line1: website = "a.com";
...
line3: website = "b.com";
...
line5: website = "c.com";
Suppose I want to change all website to "stackoverflow.com", I can do:
- change "a.com" to "stackoverflow.com"
- yank the whole line (Y)
- go to line3, hit p, k, dd to paste from buffer and delete the old "b.com" line.
Now the problem is that since dd puts the "b.com" into the buffer, to replace line5 I'll have to yank the whole line again.
Is there any simple way so that I can replace line3 and line5 with the already yanked line quickly?
UPDATE:
Thanks for the answers, now there are several ways doing it: delete to black hole, yank from named buffer, etc. I found this being my favorite method ( I use key R instead r as sometime I need to replace a single character):
In Vim is there a way to delete without putting text in the register?
I put some links to similar SO questions below:
How to Delete (desired text), delete (undesired text), and paste (desired text) in Vim
In Vim is there a way to delete without putting text in the register?
First things first
You can go one better by not needing to explicitly delete the line:
yank the whole line into register x: "xY
go to the next line to replace
visually select the whole line: V
paste over the selection from register x: "xp
Now the deleted line is in register ", as always, but the yanked line is still in register x, so you can repeat steps 2 through 4 without having to yank over and over.
Repeated things repeated
Unfortunately you cannot use . to repeat steps 3+4. So if you have to do this for a lot of lines, insert a few more steps to record a macro:
yank the whole line into a register x: "xY
go to the next line to replace
record a macro into the w register: qw
visually select the whole line: V
paste over the selection from register x: "xp
stop recording: q
go to the next line to replace
replay the macro recorded into w: #w
go to the next line to replace
and now finally, you can replay same-as-last-time: ##
Then you can simply repeat steps 9 and 10 for the next 50 lines you need to replace.
Last (repeated) things last
In fact, if you find the next line by searching, then you should use that search to go to the first line as well. Because then the n that you use to go to the next line can be included as part of the macro – basically you just swap steps 6 and 7.
Then you don’t have to manually go to the next line to replace at all, because the macro will send you there as the last thing it does. You can just keep hitting ##, along with any occasional ns whenever you happen to want to skip a particular match.
References
help "
help registers
help complex-repeat
You can use named buffers for this instead of the default unnamed buffer: "lY then "lp to yank resp. paste from register l, then let the dd use the default buffer.
This is not an answer to your question as put but it is an answer to your real question, I think.
Technique 1: Are you aware of :s? If you are just wanting to replace all matches, you could do something like this:
:%s/^website = "\zs.*\ze\.com";$/stackoverflow/
As you haven't specified precise format of it all and whether or not you are wanting to replace all or only some, I can't say whether this is what you want or not.
Technique 1b: Even if you only want to replace some, there's a useful and not terribly widely known flag for :s: c, "confirm". (See :help :s_flags and more specifically :help :s_c.) Then you can decide with each one whether you want to replace it or not.
:%s/^website = "\zs.*\ze\.com";$/stackoverflow/c
Technique 2: You could also search, replace and then repeat. /^website = "\zs.*\ze\.com";$, then cwstackoverflowEsc to replace the word with "stackoverflow". Then n to go to the next match and if you want to replace it with "stackoverflow", use ..
Rereading this question I think this is closer to what you're after:
In Vim is there a way to delete without putting text in the register?
E.g. instead of using dd use "_dd
The "0 register always contain your last yanked text. Then you can do:
change "a.com" to "stackoverflow.com"
yank the whole line (Y)
go to line3, hit "0p, k, dd to paste from buffer and delete the old "b.com" line.
go to line5, hit "0p, k, dd to paste from buffer and delete the old "c.com" line.
ci" - change inside the ""
ctrl-r 0 - put default register
jj - move down two lines
. - repeat last command
jj
.

Append general buffer to the end of every line in VI

I'm trying to add the contents of the general buffer to the end of every line. I'm sure this is fairly simple, however, an hour of google searches have lead me nowhere.
This is what my file looks like
::Things to bring camping
--matches
--tent
--sleeping bags
--inflatable bed
--firewood
--camping stove
--skillet
I want to add "::Things to bring camping" to the end of every line.
This is i have figured out so far.
/:: -> brings me to the line in question
Y -> yanks the entire line to the general buffer
I tried :%s/$/\p -> this added a "p" to the end of every line.
My problem is with step 3. How do I tell the "search and replace command" to used the "p" (the contents of the general buffer) instead of the "p" the character
Thank you so much for your help.
Just a suggestion: If you try doing it with a macro, you will be able to use 'p' to add the contents of the general buffer.
Sorry, I had to go into vim and find out.
The way to copy your entire line while in command mode, is:
^r "
(that's CTRL and r, then " )
That should paste the entire line you yanked into your search and replace command
For step three, instead of \p, you should use ctrl-R-a. Hold down the control key and type an uppercase "R", continue holding control, and type a lowercase "a".
For a line with multiple words, use ctrl-R-" instead.
I agree with using a macro - they're very powerful.
In this case I took your list example and positioned it at the first colon.
I used y$ to grab the remainder of the line in the buffer.
Then I recorded the macro - I chose 1.
q1
j$pq
Then you can call it for any number of rows in your list. E.g. 10#1
Learned something figuring this one out ...
:%s/$/\=getreg()/
The \= says that what follows is an expression to be evaluated, and the getreg() call gets the contents of the register, by default the "general buffer" as it used to be called by vi.

Resources