Skip to content

Commit 41b611d

Browse files
committed
Initial stab at README
Signed-off-by: Wincent Colaiuta <[email protected]>
1 parent a1049e4 commit 41b611d

File tree

1 file changed

+257
-0
lines changed

1 file changed

+257
-0
lines changed

README.md

Lines changed: 257 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
# Overview
2+
3+
Clipper is an OS X "launch agent" that runs in the background providing a
4+
service that exposes the local clipboard to tmux sessions and other processes
5+
running both locally and remotely.
6+
7+
# Problem
8+
9+
You're running tmux, possibly on a remote machine via ssh, and want to copy
10+
something using tmux copy mode into your local system clipboard.
11+
12+
You can hold down Option and click to make a selection, bypassing tmux and
13+
allowing you to copy straight to the system clipboard, but that won't work if
14+
you're using vertical splits (because the selection will operate across the
15+
entire width of the terminal, crossing the splits) or if you want to grab more
16+
than what is currently visible.
17+
18+
As a workaround for the vertical split problem, you can hold down Option +
19+
Command to make a rectangular (non-contiguous) selection, but that will grab
20+
trailing whitespace as well, requiring you to manually clean it up later.
21+
Again, it won't work if you want to grab more than what is currently visible.
22+
23+
As a result, you often find yourself doing a tiresome sequence of:
24+
25+
1. Copy a selection using tmux copy mode on a remote machine
26+
2. Still on the remote machine, open a new, empty buffer in Vim
27+
3. Enter Vim paste mode (`:set paste`)
28+
4. Paste the tmux copy buffer into the Vim buffer
29+
5. Write the file to a temporary location (eg. `:w /tmp/buff`)
30+
6. From the local machine, get the contents of the temporary file into the local
31+
system clipboard with `ssh user@host cat /tmp/buff | pbcopy` or similar
32+
33+
# Solution
34+
35+
OS X comes with a `pbcopy` tool that allows you to get stuff into the clipboard
36+
from the command-line. We've already seen this at work above. Basically, we can
37+
do things like `echo foo | pbcopy` to place "foo" in the system clipboard.
38+
39+
tmux has a couple of handy commands related to copy mode buffers, namely
40+
`save-buffer` and `show-buffer`. With these, you can dump the contents of a
41+
buffer into a text file, or emit it over standard out.
42+
43+
In theory, combining these two elements, we can add something like this to our
44+
`~/.tmux.conf`:
45+
46+
bind-key C-y run-shell "tmux save-buffer - | pbcopy"
47+
48+
In practice, this doesn't work because tmux uses the `daemon(3)` system call,
49+
which ends up putting it in a different execution context from which it cannot
50+
interact with the system clipboard. For (much) more detail, see:
51+
52+
- http://developer.apple.com/library/mac/#technotes/tn2083/_index.html
53+
54+
One workaround comes in the form of the `reattach-to-user-space` tool available
55+
here:
56+
57+
- https://github.com/ChrisJohnsen/tmux-MacOSX-pasteboard
58+
59+
This is a wrapper which allows you to launch a process and have it switch from
60+
the daemon execution context to the "user" context where access to the system
61+
clipboard is possible. The suggestion is that you can add a command like the
62+
following to your `~/.tmux.conf` to make this occur transparently whenever you
63+
open a new pane or window:
64+
65+
set-option -g default-command "reattach-to-user-namespace -l zsh"
66+
67+
Despite the fact that the wrapper tool relies on an undocumented, private API,
68+
it is written quite defensively and appears to work pretty well. While this is a
69+
workable solution when running only the local machine, we'll need something else
70+
if we want things to work transparently both locally and remotely. This is where
71+
Clipper comes in.
72+
73+
Clipper is a server process that you can run on your local machine. It will
74+
listen on the network for connections, and place any content that it receives
75+
into the system clipboard.
76+
77+
It can be set to run automatically as a "launch agent" in the appropriate
78+
execution context, which means you don't have to worry about starting it, and it
79+
will still have access to the system clipboard despite being "daemon"-like.
80+
81+
Through the magic of `ssh -R` it is relatively straightforward to have a shared
82+
tmux configuration that you can use both locally and remotely and which will
83+
provide you with transparent access to the local system clipboard from both
84+
places.
85+
86+
# Setup
87+
88+
## Installing
89+
90+
I'm relatively new to Go so am not yet sure what the best way to distribute a
91+
command-line applicaton is. So, for now, it boils down to:
92+
93+
git clone git://git.wincent.com/clipper.git
94+
cd clipper
95+
go build clipper.go
96+
sudo cp clipper /usr/bin
97+
cp com.wincent.clipper.plist ~/Library/LaunchAgents/
98+
launchctl load -w -S Aqua ~/Library/LaunchAgents/com.wincent.clipper.plist
99+
100+
Alternatively, if you'd like to run Clipper manually, you can do so with:
101+
102+
./clipper [--address=IP_ADDR] [--port=PORT] [--logfile=LOGFILE]
103+
104+
Note that both of these commands will fail to do the right thing inside of a
105+
tmux session. Run `launchctl` from outside of tmux, otherwise Clipper will find
106+
itself in the wrong execution context. Similarly, when running manually, either
107+
run Clipper outside of tmux or use the aforementioned `reattach-to-user-space`
108+
as a wrapper.
109+
110+
## Uninstalling
111+
112+
The launch agent installation can be reversed with:
113+
114+
launchctl unload ~/Library/LaunchAgents/com.wincent.clipper.plist
115+
rm ~/Library/LaunchAgents/com.wincent.clipper.plist
116+
sudo rm /usr/bin/clipper
117+
118+
As before, note that you should only run `launchctl` outside of a tmux session.
119+
120+
To kill a manually-launched instance of Clipper, just hit Control+C in the
121+
terminal where it is running.
122+
123+
## Configuring tmux
124+
125+
Now we can use a slight modification of our command from earlier. Assuming we
126+
kept the standard listen address (127.0.0.1) and port (8377), we can use a
127+
command like this:
128+
129+
bind-key C-y run-shell "tmux save-buffer - | nc localhost 8377"
130+
131+
Here we're using netcat (`nc`)` to send the contents of the buffer to the
132+
listening Clipper agent.
133+
134+
## Configuring Vim
135+
136+
There is nothing inherent in Clipper that ties it to tmux. We can use it from
137+
any process, including Vim.
138+
139+
For example, we can add a mapping to our `~/.vimrc` to send the last-yanked text
140+
to Clipper:
141+
142+
nnoremap <leader>y :call system('nc localhost 8377', @0)<CR>
143+
144+
## Configuring Zsh
145+
146+
By setting up an alias:
147+
148+
alias clip="nc localhost 8377"
149+
150+
you can conveniently get files and other content into your clipboard:
151+
152+
cat example.txt | clip
153+
154+
## Configuring SSH
155+
156+
Again, assuming default address and port, we can use `-R` like this:
157+
158+
ssh -R localhost:8337:localhost:8377 [email protected]
159+
160+
With this, a tmux process running on the remote host can use the same
161+
configuration file, and our `run-shell` from above will send the buffer
162+
contents to localhost:8377 on the remote machine, which will then be forwarded
163+
back over the SSH connection to localhost:8377 on the local machine, where
164+
Clipper is listening.
165+
166+
See the "Security" section below for some considerations.
167+
168+
To make this automated, entries can be set up in `.ssh/config`:
169+
170+
Host host.example.org
171+
RemoteForward 8377 localhost:8377
172+
173+
# Security
174+
175+
At the moment, Clipper doesn't employ any authentication. It does, by default,
176+
listen only on the loopback interface, which means that random people on your
177+
network won't be able to connect to it. People with access to your local
178+
machine, however, will have access; they can push content into your clipboard
179+
even if they can't read from it.
180+
181+
This may be fine on a single-user machine, but when you start using `ssh -R` to
182+
expose your Clipper instance on another machine you're evidently increasing your
183+
surface area. This may be ok, but my intention is to add an authentication
184+
mechanism to the protocol in the near future in any case.
185+
186+
# Author
187+
188+
Clipper is written and maintained by Wincent Colaiuta <[email protected]>.
189+
190+
# Development
191+
192+
Development in progress can be inspected via the project's Git web-based
193+
repository browser at:
194+
195+
https://wincent.com/repos/clipper
196+
197+
the clone URL for which is:
198+
199+
git://git.wincent.com/clipper.git
200+
201+
Mirrors exist on GitHub and Gitorious; these are automatically updated once
202+
per hour from the authoritative repository:
203+
204+
https://github.com/wincent/clipper
205+
https://gitorious.org/clipper/clipper
206+
207+
Patches are welcome via the usual mechanisms (pull requests, email, posting to
208+
the project issue tracker etc).
209+
210+
# Website
211+
212+
The official website for Clipper is:
213+
214+
https://wincent.com/products/clipper
215+
216+
Bug reports should be submitted to the issue tracker at:
217+
218+
https://wincent.com/issues
219+
220+
# Donations
221+
222+
Clipper is free software released under the terms of the BSD license. If you
223+
would like to support further development you can make a donation via PayPal to
224+
225+
226+
- https://www.paypal.com/xclick/[email protected]&item_name=clipper+donation&no_note=1&currency_code=EUR&lc=GB
227+
228+
# License
229+
230+
Copyright 2013 Wincent Colaiuta. All rights reserved.
231+
232+
Redistribution and use in source and binary forms, with or without
233+
modification, are permitted provided that the following conditions are met:
234+
235+
1. Redistributions of source code must retain the above copyright notice,
236+
this list of conditions and the following disclaimer.
237+
2. Redistributions in binary form must reproduce the above copyright notice,
238+
this list of conditions and the following disclaimer in the documentation
239+
and/or other materials provided with the distribution.
240+
241+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
242+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
243+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
244+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
245+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
246+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
247+
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
248+
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
249+
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
250+
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
251+
POSSIBILITY OF SUCH DAMAGE.
252+
253+
# History
254+
255+
## 0.1 (not yet released)
256+
257+
- Initial release

0 commit comments

Comments
 (0)