Copy visual mode selection below selection in vi

2

1

In vim, I often find myself repeating the same steps to copy a section before making changes to it:

  1. V to start Visual mode linewise
  2. j until I have selected the section I want to copy
  3. y to yank the selection
  4. j to scroll down to the last line of the text I just selected
  5. p to copy the yanked section below the current line
  6. O to start a new blank line above the copied text
  7. ESC to leave insert mode

Is there a more efficient way to accomplish this (or any part of it)? In particular, it seems like there should be a better way to put text below the selection you just selected, rather than scrolling down to select it, yanking it, and scrolling down to the bottom again.

jrdioko

Posted 2012-10-12T18:21:42.410

Reputation: 8 205

Answers

2

The real bottleneck, here seems to be all the jjjj… that you are doing. The supposed superiority of hjkl over the arrow keys is cited so often that people tend to forget the immense value of Vim's motions and text-objects over both tedious methods.

Supposing you are on the first line of a paragraph as defined by Vim (text between blank lines), y'}P should yank the whole paragraph including the blank line that follows and paste it above the current line.

some text above 

[l]orem ipsum dolor sit amet
ipsum lorem dolor sit amet
lorem dolor ipsum sit amet
lorem ipsum sit dolor amet
lorem ipsum dolor amet sit

some text below

y'}P

some text above

[l]orem ipsum dolor sit amet
ipsum lorem dolor sit amet
lorem dolor ipsum sit amet
lorem ipsum sit dolor amet
lorem ipsum dolor amet sit

lorem ipsum dolor sit amet
ipsum lorem dolor sit amet
lorem dolor ipsum sit amet
lorem ipsum sit dolor amet
lorem ipsum dolor amet sit

some text below

v}yP should work too, in a more comfortable way.

If your block is not a "paragraph", there's probably a way to define the selection with a motion instead of jjj. Something like V/it$<cr>.

edit

Here is another variant that places the copy below the original: y'}'}p.

edit

I think that the most generic way to shorten the whole process is to extend the visual selection either:

  • with a search motion if you can identify a "hook" on the last line of the block you want to duplicate (V/foo<CR>)

  • or a count (V5j).

Once the selection is done, you can:

  • yank (y),

  • move to the end of the visual selection ('> or 5j but '> is more generic),

  • open a new line (o),

  • leave insert mode (<Esc>),

  • paste (p)

This method is probably the most generic but that's still a lot of typing. That's where mappings come to the rescue:

vnoremap <F9> y'>o<Esc>p

The idea, here, is to separate the contextual from the generic:

  • the contextual part is when you define the block to duplicate, because there's no way to predict what you want to duplicate I leave this part to your discretion but I hope you'll use a better method than jjjjjj…

  • the generic part is everything that follows the selection, done here with a simple mapping.

The whole process is now reduced to V5j<F9> which is as quick as you can get.

romainl

Posted 2012-10-12T18:21:42.410

Reputation: 19 227

I'll look into those. It's often a method in Python I'm going for, but sometimes more arbitrary blocks of text. – jrdioko – 2012-10-12T20:53:01.420

These options won't wind up with your cursor in between the two sections though, it seems. You still have to move down after the put. – jrdioko – 2012-10-12T21:49:00.637

Yes but that's not what the OP is trying to achieve. He wants to duplicate a block of text to modify it. Ending up with the cursor between the two blocks would be counterproductive because he would need to move the cursor again to even begin to edit the copy. With y'}P, the cursor ends up on the first line of the copy, ready for further editing. – romainl – 2012-10-13T06:33:10.017

Yes it is, I am the OP :) Sorry for the confusion, what I'm trying to do is copy a piece of text, then begin editing the bottom version (that's why I wanted the cursor in the middle). It looks like your edit does accomplish that for the "paragraph" case. Is there a way to do that with an arbitrary visual mode selection? – jrdioko – 2012-10-14T00:54:11.720

Your usecase is "fuzzy": sometimes you would want to work on a logical block, sometimes not. Vim is great for shortening key sequences in common, specific and well defined situations. It's still better than other editors when dealing with non-regular situations but it'll necessarilly be less terse if you want more "general" solutions. Globally your way is fine and IMO the only "generic" way to achieve your goal. But you don't have a "logical" problem, you have a jj… problem. VjyjpO<ESC> is not bad per se but you should use motions, counts, marks and co. instead of j as much as possible. – romainl – 2012-10-14T06:41:32.930

See my edit for more details. – romainl – 2012-10-14T07:17:42.227

I think the '> cuts out the part I thought was most annoying. There's always more to learn about vim. Thanks. – jrdioko – 2012-10-14T20:58:07.147

1:help motion.txt will blow your mind. – romainl – 2012-10-14T21:15:38.457

3

If I understand, your goal is to have essentially two copies of some chunk of text one right after the other. In that case, try this:

  1. Shift-V
  2. j to select region
  3. y to yank
  4. Shift-P to put above your current location
  5. When you do the put, it will tell you how many lines it added. Type this number then hit j
  6. Shift-O

I realize that all this does is remove the scrolling, but for any sizeable amount of text, that will be the longest bit of the evolution and the most prone to over/under shooting the right location.

EBGreen

Posted 2012-10-12T18:21:42.410

Reputation: 7 834

Yes, I'm just trying to copy a chunk of text I want to use as the base for something else. That Shift-P was the missing piece, I think (you don't even need your step 5). I was copying below, scrolling down, and editing the copy, but I guess there's no reason I can't copy above, avoid scrolling, and edit the original. Thanks. – jrdioko – 2012-10-12T19:22:53.893

Oh nevermind maybe, Shift-P doesn't move the cursor like I thought it would. – jrdioko – 2012-10-12T21:45:40.000