I'm trying to improve the answer here for copying to clipboard in a vim without the +clipboard option. The problem with the above approach is that :w always writes the entire line, so it is not possible to copy only a part of the line. I made use of the advice here to come up with the following solution:

vnoremap <C-C> "zy:call writefile(getreg('z', 1, 1), "/home/user/.vim_clipboard")<CR>:call system("xclip -r -sel c /home/user/.vim_clipboard")<CR>

However, since I am still a novice in vimscript, can someone help me to improve the answer. Specifically, I'm hoping to

  • Replace /home/user with an environment variable like $HOME, or better still a reference to the folder $HOME/.vim. (Is there a vim-specific variable for that folder?)
  • Write the above in a more readable form, e.g., by defining a function and calling it.

Many thanks!

  • Might want to look into fauxClip plugin for some inspiration Aug 6 '20 at 14:10
  • You can typically :write !xsel or similar
    – D. Ben Knoble
    Aug 6 '20 at 14:28
  • @D.BenKnoble, I don't think :write works because of this.
    – Tim Mak
    Aug 7 '20 at 1:44

FYI, I'm taking a "Vim learning" approach and demonstrating how to take what OP has already (for the most part) and properly move much of it into a function. As a couple of the comments above show, though, there certainly could be nice alternative approaches that also solve the problem in question.

There are a few ways you could go about it. They mainly differ in how much you want to do prior to the function call. I might be inclined to extract the register value sooner rather than later in which case you could do

vnoremap <C-C> y:call YourFunc(getreg('"', 1, 1))

This would probably be my preference because it leaves behind buffer specific things when we call the function. IOW, in the function we just process a list containing strings and don't have to worry about yanking and registers and visually selected text. That makes the function more general and reusable.

(There are other ways to get visually selected text into usuable form but for simplicity's sake and since getreg() nicely transforms buffer lines to a list of strings I'm sticking with your choice.)

Speaking of registers and yanking, I'd avoid a letter register since you're more likely to overwrite something you previously saved. I'm using the "unnamed" register which automatically receives text yanked with y.

So the function just looks like this:

func! YourFunc(lofs)
    let l:clipboard = $HOME . "/.vim_clipboard"
    call writefile(a:lofs, l:clipboard)
    call system("xclip -r -sel c " . l:clipboard)

You may be wondering about the a: that precedes lofs. Vimscript requires that those two characters be prepended to a function parameter name when referencing the parameter from within the body of the function.

To avoid repeating the path string I put it in a local variable. Though not required like a: I'm using the prefix l: (for "local"). This is just a convention which is meant to improve clarity/readability. (This is a tiny function so it doesn't help much here but it doesn't hurt to practice good habits all the time.) The local variable is being passed as the second parameter to writefile() and is also being concatenated to the string passed to system()

Regarding your question about environment variables, Vim inherits them from the runtime environment and you can access them similar to shell scripting: $FOO.

As far as $HOME goes this should be set if you're using *nix. On Windows it's set based on a couple rules which you can find here: :h $HOME-windows

Are you not interested in the output of the system call? If you were you could replace call with return and get the output from the function directly. Or you could replace call with echo or equivalent.

  • What do the a: and l: mean? I suppose the . is a "concatenate" operator? What is a good online reference for vimscript?
    – Tim Mak
    Aug 6 '20 at 5:57
  • 1
    In the body of a function the names of parameters passed to the function must be prefixed with a:, e.g. lofs -> a:lofs. The prefix l: on the other hand is just a convention to make it clear that a variable is local (not a global variable or a parameter). Yes, . is string concatenate operator. There is no better reference for Vim than it's own documentation (the help files). They are, obviously available from within Vim but you can read them online, too: vimhelp.appspot.com
    – B Layer
    Aug 6 '20 at 6:03
  • @TimMak Just FYI and because I happened to be looking at it.... While my original answer about Vim help being the best reference for vimscript holds true, if you want a well-regarded resource for learning vimscript there's this one: learnvimscriptthehardway.stevelosh.com
    – B Layer
    Aug 18 '20 at 10:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.