4

I'm using the following command to copy all lines of text in a document to the system clipboard:

%y+

Usually, especially in order to copy code to StackOverflow ;), I apply a sed transformation to my buffer in order to make it easier to paste in with MarkDown:

%s:^:\t:g

Is there a way to chain the commands without actually applying it to my buffer, only to the copied text?

Naftuli Kay
  • 75,812
  • 80
  • 244
  • 374
  • 1
    +1 for `:%y+` -- I was still stuck with the crappy habit of `gg"+yG` because ... I always forget that most linewise normal commands have succinct ex versions :). Another **big** advantage with `:%y+` is that it is instantly repeatable with `@:` – sehe Sep 13 '11 at 07:30
  • Yeah, I, for one am frustrated that [here](http://stackoverflow.com/questions/1620018/vi-editor-copy-all-the-lines-to-clipboard/1620030#1620030) it wasn't selected as the right answer to the question. How is `gg"*yG` easier than `%y+`? – Naftuli Kay Sep 13 '11 at 07:34
  • 1
    Is that a rhetorical question? It seems confusing to me now. `:%y+` is obviously quicker. However, ex commands are less frequently used in general and hence it might be _just one more thing to remember_? – sehe Sep 13 '11 at 07:37
  • I do suppose it's rhetorical. I'm new to `vim` and quickly falling in love with it as an editor. It's just... so... _awesome_... – Naftuli Kay Sep 13 '11 at 07:38
  • @TK Kocheran, the same question asked before had another selected answer: http://stackoverflow.com/questions/829935/vim-yank-entire-file/830075#830075 ... – Luc Hermitte Sep 13 '11 at 08:47
  • Apparently there _is_ justice in the world ;) – Naftuli Kay Sep 13 '11 at 08:49
  • I would not rely on the assumption that one tab = 4 spaces – Benoit Sep 13 '11 at 10:01

3 Answers3

6

I suggest using a CLI utility to put it on the clipboard: there are several I found previously, but here's one:

So you'd do

:%!sed 's:^:\t:g`|xclip

or

:%!sed 's:^:\t:g`|xclip -selection c

the latter uses the X clipboard instead of the primary clipboard (assuming UNIX).

On windows, there are likely similar utilities

Edit

A pure vim solution would be:

:let @+=substitute(join(getbufline("%", 1, "$"), "\r\n"), "^\\|\n", "\&\t", "g")

Notes:

  • it is not very efficient (but you use it SO posts... so it's not Homer's Oddyssee)
  • I assume that you want Windows line-ends (which is what I get when copying from SO anyways)
sehe
  • 328,274
  • 43
  • 416
  • 565
  • Oh, ok. I didn't know how easy it was to use external commands from within `vim`, as I'm kinda new to it. If I would have known this, then it would have been one `sed 's:^:\t:g' | xclip -selection clipboard` away from victory. There isn't a native to `vim` solution available? – Naftuli Kay Sep 13 '11 at 07:36
  • 1
    I'd prefer simpler `:%s/^/\t/|%y+|u` command instead of any of these two solutions. (Despite the fact that it adds a new entry to the undo list.) – ib. Sep 13 '11 at 10:10
3

If you do not mind adding an entry to the undo list (that means actually editing contents of the buffer), you can perform substitution, yank the text, and undo that substitution in one command.

:%s/^/\t/|%y+|u

Another solution would be to make the substitution right in the contents of the + register just after copying.

:%y+|let@+=substitute(@+,'^\|\n\zs','\t','g')
ib.
  • 25,324
  • 10
  • 71
  • 97
  • 1
    The last one is arguably the best option of all the good approaches seen on this page. Some excellent Vim fu here on SO! – sehe Sep 13 '11 at 11:51
  • 1
    I like the first command a lot, that's how I would go about doing it :) – Naftuli Kay Sep 13 '11 at 17:30
  • @sehe: Thanks! There is even more ways to do that--see my last comment to Benoit's answer, for example. – ib. Sep 14 '11 at 02:17
2

If shiftwidth equals 4 and expandtab is set, I would do:

:set guioptions+=a
ggVG>gv

7 keystrokes is not that bad. Of course there is no ex command. If you want ex commands you could do:

function! ToSo()
    %y +
    let @+ = "    " . substitute(@+, '\n', "\n    ", 'g')
endfunction
command! -nargs=0 ToSo :call ToSo()<Enter>

And then:

:ToSo

will put whatever you want into the clipboard

Benoit
  • 70,220
  • 21
  • 189
  • 223
  • +1 interesting enough. I'd not have expected `:se go+=a` to hit the Windows clipboard when under `behave xterm`. It does, however. I'm sure I'm going to hate it clobbering my clipboard, but I'll give it a try to see whether it works for me. It has potential to be a habit disruptor. Interesting. – sehe Sep 13 '11 at 10:13
  • Is an auxiliary register necessary? Why not just `%y+|let@+=substitute(@+,'^\|\n\zs',"\t",'g')`? (By the way, you restore the register's contents incorrectly--imagine that `x` contains text copied from blockwise Visual mode.) – ib. Sep 13 '11 at 10:21
  • @ib.: yes, I should have done it with `getregtype`, `getreg` and `setreg`. You are absolutely right that I could do it only with the `+` register but having a cliboard monitoring application (Ditto) it would fill it with one unnecessary item in its history. – Benoit Sep 13 '11 at 11:05
  • @Benoit: Hm, duplicating item in a clipboard monitoring application could be annoying. If that is the case, you can try `:redir=>s|sil%p|redir END|let@+=s` or something like the second @sehe's solution. – ib. Sep 13 '11 at 11:36