• Stars
    star
    592
  • Rank 75,057 (Top 2 %)
  • Language
    Go
  • License
    BSD 2-Clause "Sim...
  • Created over 11 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

✂️ Clipboard access for local and remote tmux sessions

Clipper logo

Overview

Clipper is a macOS "launch agent" — or Linux daemon — that runs in the background providing a service that exposes the local clipboard to tmux sessions and other processes running both locally and remotely.

Example topology Example topology

In the above example, you start off in a shell on your local machine; from there you use ssh to a remote machine, where:

  1. You run vim (from a shell, inside tmux, which itself runs in a shell).
  2. When you "yank" text in vim, it is fed into the ~/.clipper.sock socket.
  3. Via a SSH RemoteForward connection, the yanked text arrives back to the Clipper process running on your local machine.
  4. The launch agent puts the text in your system clipboard.

Once everything is configured, all of this happens transparently; editing in vim on a remote machine feels exactly like doing it on your local machine. While the above example uses macOS, vim, and tmux, the same patterns apply to other platforms and tools.

At a glance

macOS installation (using Homebrew; for non-Homebrew installs see below)

brew install clipper # run this outside of a tmux session

Configuration for ~/.tmux.conf

tmux 2.4 and later

# Bind "Enter" in copy mode to both copy and forward to Clipper:
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc localhost 8377"

# Or, if you are running on a platform where nc requires the `-N` switch (eg. Ubuntu):
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc -N localhost 8377"

# Or, if you are running Clipper on a UNIX domain socket:
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc -U ~/.clipper.sock"

# Or, if your version of netcat doesn't have socket support and you want to use socat:
bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "socat - UNIX-CLIENT:~/.clipper.sock"

tmux >= 1.8 but < 2.4

# Bind "Enter" in copy mode to both copy and forward to Clipper:
bind-key -t vi-copy Enter copy-pipe "nc localhost 8377"

# Or, if you are running on a platform where nc requires the `-N` switch (eg. Ubuntu):
bind-key -t vi-copy Enter copy-pipe "nc -N localhost 8377"

# Or, if you are running Clipper on a UNIX domain socket:
bind-key -t vi-copy Enter copy-pipe "nc -U ~/.clipper.sock"

# Or, if your version of netcat doesn't have socket support and you want to use socat:
bind-key -t vi-copy Enter copy-pipe "socat - UNIX-CLIENT:~/.clipper.sock"

tmux < 1.8

# Bind <prefix>-y to forward to Clipper
bind-key y run-shell "tmux save-buffer - | nc localhost 8377"

# Or, if you are running on a platform where nc requires the `-N` switch (eg. Ubuntu):
bind-key y run-shell "tmux save-buffer - | nc -N localhost 8377"

# Or, if you are running Clipper on a UNIX domain socket:
bind-key y run-shell "tmux save-buffer - | nc -U ~/.clipper.sock"

# Or, if your version of netcat doesn't have socket support and you want to use socat:
bind-key y run-shell "tmux save-buffer - | socat - UNIX-CLIENT:~/.clipper.sock"

Configuration for ~/.vimrc

" Bind <leader>y to forward last-yanked text to Clipper
nnoremap <leader>y :call system('nc localhost 8377', @0)<CR>

" Or, if you are running on a platform where nc requires the `-N` switch (eg. Ubuntu):
nnoremap <leader>y :call system('nc -N localhost 8377', @0)<CR>

" Or, if you are running Clipper on a UNIX domain socket:
nnoremap <leader>y :call system('nc -U ~/.clipper.sock', @0)<CR>

" Or, if your version of netcat doesn't have socket support and you want to use socat:
nnoremap <leader>y :call system('socat - UNIX-CLIENT:~/.clipper.sock', @0)<CR>

Alternatively, use the vim-clipper plug-in.

Configuration for ~/.bash_profile, ~/.zshrc etc

# Pipe anything into `clip` to forward it to Clipper
alias clip="nc localhost 8377"

" Or, if you are running on a platform where nc requires the `-N` switch (eg. Ubuntu):
alias clip="nc -N localhost 8377"

# Or, if you are running Clipper on a UNIX domain socket:
alias clip="nc -U ~/.clipper.sock"

# Or, if your version of netcat doesn't have socket support and you want to use socat:
alias clip="socat - UNIX-CLIENT:~/.clipper.sock"

Configuration for ~/.ssh/config

# Forward Clipper connection to remote host
Host host.example.org
  RemoteForward 8377 localhost:8377

# Or, if you are running Clipper on a UNIX domain socket:
Host host.example.org
  RemoteForward /home/me/.clipper.sock /Users/me/.clipper.sock

Problem

You're running tmux, possibly on a remote machine via ssh, and want to copy something using tmux copy mode into your local system clipboard.

You can hold down Option and click to make a selection, bypassing tmux and allowing you to copy straight to the system clipboard, but that won't work if you're using vertical splits (because the selection will operate across the entire width of the terminal, crossing the splits) or if you want to grab more than what is currently visible.

As a workaround for the vertical split problem, you can hold down Option + Command to make a rectangular (non-contiguous) selection, but that will grab trailing whitespace as well, requiring you to manually clean it up later. Again, it won't work if you want to grab more than what is currently visible.

As a result, you often find yourself doing a tiresome sequence of:

  1. Copy a selection using tmux copy mode on a remote machine
  2. Still on the remote machine, open a new, empty buffer in Vim
  3. Enter Vim paste mode (:set paste)
  4. Paste the tmux copy buffer into the Vim buffer
  5. Write the file to a temporary location (eg. :w /tmp/buff)
  6. From the local machine, get the contents of the temporary file into the local system clipboard with ssh user@host cat /tmp/buff | pbcopy or similar

Solution

macOS comes with a pbcopy tool that allows you to get stuff into the clipboard from the command-line. xclip is an alternative that works on Linux. We've already seen this at work above. Basically, we can do things like echo foo | pbcopy to place "foo" in the system clipboard.

tmux has a few handy commands related to copy mode buffers, namely save-buffer, copy-pipe and copy-pipe-and-cancel, the availability of which depends on the version of tmux that you are running. With these, you can dump the contents of a buffer to standard out.

In theory, combining these elements, we can add something like this to our ~/.tmux.conf:

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel pbcopy

or, in a version of tmux prior to 2.4 (which use vi-copy instead of copy-mode-vi, and copy-pipe instead of copy-pipe-and-cancel):

bind-key -t vi-copy Enter copy-pipe pbcopy

or, in an even older version of tmux prior to 1.8 (which don't have the copy-pipe-and-cancel or copy-pipe commands):

bind-key y run-shell "tmux save-buffer - | pbcopy"

In practice, this won't work on versions of macOS prior to 10.10 "Yosemite" or after 10.11 "El Capitan" — there was a brief lapse during those versions where it did work — because tmux uses the daemon(3) system call, which ends up putting it in a different execution context from which it cannot interact with the system clipboard. For (much) more detail, see:

One workaround comes in the form of the reattach-to-user-space tool available here:

This is a wrapper which allows you to launch a process and have it switch from the daemon execution context to the "user" context where access to the system clipboard is possible. The suggestion is that you can add a command like the following to your ~/.tmux.conf to make this occur transparently whenever you open a new pane or window:

set-option -g default-command "reattach-to-user-namespace -l zsh"

Despite the fact that the wrapper tool relies on an undocumented, private API, it is written quite defensively and appears to work pretty well. While this is a workable solution when running on the local machine — so workable in fact that it is baked into tmux itself in version 2.6 — we'll need something else if we want things to work transparently both locally and remotely, or on older versions of tmux. This is where Clipper comes in.

Clipper is a server process that you can run on your local machine. It will listen on the network or on a UNIX domain socket for connections, and place any content that it receives into the system clipboard.

It can be set to run automatically as a "launch agent" in the appropriate execution context, which means you don't have to worry about starting it, and it will still have access to the system clipboard despite being "daemon"-like.

Through the magic of ssh -R it is relatively straightforward to have a shared tmux configuration that you can use both locally and remotely and which will provide you with transparent access to the local system clipboard from both places.

Setup

Installing

For Homebrew users, install by running (outside of all tmux sessions):

brew install clipper # and follow the prompts...

Alternatively, if you have a working Go environment on your system you can do:

go get github.com/wincent/clipper

Finally, if you want to do things manually, you can clone from the authoritative Git repo and build manually (which again requires a working Go environment):

git clone git://git.wincent.com/clipper.git
cd clipper
go build

Additional steps for non-Homebrew installs

If you plan to use Clipper as a launch agent you'll need to put it somewhere the system can find it (ie. at a location in the standard PATH, such as under /usr/local/bin/) and update the included property list file to specify the full path to the location where you installed the Clipper executable.

The following examples show how you would install the built Clipper executable to /usr/local/bin/ after cloning the repo and performing a build. It also shows how you would set up Clipper as a launch agent (on macOS) or systemd service (on Linux) and start it running:

macOS example setup

sudo cp clipper /usr/local/bin
cp contrib/darwin/tcp-port/com.wincent.clipper.plist ~/Library/LaunchAgents/
launchctl load -w -S Aqua ~/Library/LaunchAgents/com.wincent.clipper.plist

Note that these commands may fail to do the right thing inside of a tmux session under macOS. Run launchctl from outside of tmux, otherwise Clipper may find itself in the wrong execution context. Similarly, when running manually, either run Clipper outside of tmux or use the aforementioned reattach-to-user-space as a wrapper.

Linux example setup

sudo cp clipper /usr/local/bin
cp contrib/linux/systemd-service/clipper.service ~/.config/systemd/user
systemctl --user daemon-reload
systemctl --user enable clipper.service
systemctl --user start clipper.service

Manual setup

Alternatively, if you'd like to run Clipper manually, you can do so with:

./clipper [--address=IP_ADDR|UNIX_SOCKET] \
          [--port=PORT] \
          [--logfile=LOGFILE] \
          [--config=CONFIG_FILE]

Uninstalling

A Homebrew installation can be reversed with:

brew uninstall clipper

A manual launch agent installation can be reversed with the following (and as before, note that you should probably only run launchctl outside of a tmux session):

launchctl unload ~/Library/LaunchAgents/com.wincent.clipper.plist
rm ~/Library/LaunchAgents/com.wincent.clipper.plist
sudo rm /usr/local/bin/clipper

On Linux:

systemctl --user stop clipper.service
systemctl --user disable clipper.service
sudo rm /usr/local/bin/clipper
rm -r ~/.config/clipper

To kill a manually-launched instance of Clipper, just hit Control+C in the terminal where it is running.

Configuring Clipper

As previously noted, Clipper supports a number of command line options, which you can see by running clipper -h:

Usage of clipper:
  -a string
        address to bind to (default loopback interface)
  -address string
        address to bind to (default loopback interface)
  -c string
        path to (JSON) config file (default "~/.clipper.json")
  -config string
        path to (JSON) config file (default "~/.clipper.json")
  -e string
        program called to write to clipboard (default "pbcopy")
  -executable string
        program called to write to clipboard (default "pbcopy")
  -f string
        arguments passed to clipboard executable
  -flags string
        arguments passed to clipboard executable
  -h    show usage information
  -help
        show usage information
  -l string
        path to logfile (default "~/Library/Logs/com.wincent.clipper.log")
  -logfile string
        path to logfile (default "~/Library/Logs/com.wincent.clipper.log")
  -p int
        port to listen on (default 8377)
  -port int
        port to listen on (default 8377)
  -v    show version information
  -version
        show version information

The defaults shown above apply on macOS. Run clipper -h on Linux to see the defaults that apply there.

You can explicitly set these on the command line, or in the plist file if you are using Clipper as a launch agent. Clipper will also look for a configuration file in JSON format at ~/.clipper.json (this location can be overidden with the --config/-c options) and read options from that. The following options are supported:

  • address
  • executable
  • flags
  • logfile
  • port

Here is a sample ~/.clipper.json config file:

{
  "address": "~/.run/clipper.sock",
  "logfile": "~/Library/Logs/clipper.log"
}

Note that explicit command line options — including options supplied via a plist — trump options read from a config file.

--address

Specifies the address on which the Clipper daemon will listen for connections. Defaults to "localhost", and listens on both IPv4 and IPv6 addresses, when available. This is a reasonable default, but you may wish to set it to a filesystem path instead in order to have Clipper create a UNIX domain socket at that location and listen on that instead (for better security: see "Security" below for more). Or perhaps you would like to only listen on IPv4 or IPv6, in which case you would use "127.0.0.1" or "[::1]" respectively (the square brackets around the IPv6 address are needed by the Go networking libraries in order to disambiguate the colons in the address from colons used to separate it from the port number). Note that if you see an error of the form "too many colons in address", it is likely that you have forgotten to wrap the IPv6 address in surrounding brackets.

--port

The port on which the Clipper daemon will accept TCP connections. Defaults to 8377. You may wish to set this to some other value, to avoid colliding with another service (or Clipper user) on your system using that port, or because you want some tiny extra dose of security through obscurity.

Note that if you use the --address option to make Clipper use a UNIX domain socket, then setting the --port has no useful effect.

See the "Security" section below for more.

--logfile

Unsurprisingly, controls where the Clipper daemon logs its output. Defaults to "~/Library/Logs/com.wincent.clipper.log".

As an example, you could disable all logging by setting this to "/dev/null".

--executable

The executable used to place content on the clipboard (defaults to pbcopy on macOS and xclip on Linux).

--flags

The flags to pass to the executable (defaults to -selection clipboard on Linux and nothing on macOS).

Configuring tmux

Now we can use a slight modification of our command from earlier. Assuming we kept the standard listen address (127.0.0.1) and port (8377), we can use a command like this to send the last-copied text whenever we hit our tmux prefix key followed by y; here we're using netcat (nc) to send the contents of the buffer to the listening Clipper agent:

bind-key y run-shell "tmux save-buffer - | nc localhost 8377"

Or, if you are running on a platform where nc requires the -N switch (eg. Ubuntu):

bind-key y run-shell "tmux save-buffer - | nc -N localhost 8377"

If we instead configured Clipper to listen on a UNIX domain socket at ~/.clipper.sock, then we could do something like:

bind-key y run-shell "tmux save-buffer - | nc -U ~/.clipper.sock"

Or, alternatively, with socat (which may be useful if your version of nc doesn't support the -U switch):

bind-key y run-shell "tmux save-buffer - | socat - UNIX-CLIENT:~/.clipper.sock"

In tmux 1.8 to 2.3, we have access to the new copy-pipe command and can use a single key binding to copy text into the tmux copy buffer and send it to Clipper and therefore the system clipboard at the same time:

bind-key -t vi-copy Enter copy-pipe "nc localhost 8377"

Or, if you are running on a platform where nc requires the -N switch (eg. Ubuntu):

bind-key -t vi-copy Enter copy-pipe "nc -N localhost 8377"

Or, for a UNIX domain socket at ~/.clipper.sock:

bind-key -t vi-copy Enter copy-pipe "nc -U ~/.clipper.sock"

Or, with socat:

bind-key -t vi-copy Enter copy-pipe "socat - UNIX-CLIENT:~/.clipper.sock"

In tmux 2.4 and above, we would use:

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc localhost 8377"

Or, if you are running on a platform where nc requires the -N switch (eg. Ubuntu):

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc -N localhost 8377"

Or, for a UNIX domain socket at ~/.clipper.sock:

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "nc -U ~/.clipper.sock"

Or, with socat:

bind-key -T copy-mode-vi Enter send-keys -X copy-pipe-and-cancel "socat - UNIX-CLIENT:~/.clipper.sock"

Configuring Vim

There is nothing inherent in Clipper that ties it to tmux. We can use it from any process, including Vim.

For example, we can add a mapping to our ~/.vimrc to send the last-yanked text to Clipper by hitting <leader>y:

nnoremap <leader>y :call system('nc localhost 8377', @0)<CR>

Or, if you are running on a platform where nc requires the -N switch (eg. Ubuntu):

nnoremap <leader>y :call system('nc -N localhost 8377', @0)<CR>

Equivalently, we could do the same for a Clipper daemon listening on a UNIX domain socket at ~/.clipper.sock with:

nnoremap <leader>y :call system('nc -U ~/.clipper.sock', @0)<CR>

Or, with socat:

nnoremap <leader>y :call system('socat - UNIX-CLIENT:~/.clipper.sock', @0)<CR>

For the lazy, this functionality plus a :Clip command is made available as a separate Vim plug-in called "vim-clipper", which additionally makes it possible to use the TextYankPost autocommand to forward all yanked text to Clipper automatically on versions of Vim that support it (currently, Neovim).

Configuring Zsh (or Bash)

By setting up an alias like:

alias clip="nc localhost 8377"

Or, if you are running on a platform where nc requires the -N switch (eg. Ubuntu):

alias clip="nc -N localhost 8377"

Or (in the case of Clipper listening on a UNIX domain socket at ~/.clipper.sock):

alias clip="nc -U ~/.clipper.sock"

Or, with socat:

alias clip="socat - UNIX-CLIENT:~/.clipper.sock"

You can conveniently get files and other content into your clipboard:

cat example.txt | clip
ls /etc | clip

Configuring SSH

Again, assuming default address and port, we can use -R like this:

ssh -R localhost:8377:localhost:8377 [email protected]

Or, in the case of a UNIX domain socket at ~/.clipper.sock and a sufficiently recent version of OpenSSH (version 6.7 or above):

# Assuming a local socket on macOS in $HOME at /Users/me/.clipper.sock
# and a remote Linux machine with $HOME is in /home rather than /Users:
ssh -R /home/me/.clipper.sock:/Users/me/.clipper.sock host.example.org

With this, a tmux process running on the remote host can use the same configuration file, and our run-shell from above will send the buffer contents to localhost:8377 (or the UNIX domain socket) on the remote machine, which will then be forwarded back over the SSH connection to localhost:8377 (or the UNIX domain socket) on the local machine, where Clipper is listening.

See the "Security" section below for some considerations.

To make this automated, entries can be set up in .ssh/config:

# TCP forwarding:
Host host.example.org
  RemoteForward 8377 localhost:8377

# UNIX domain socket forwarding:
Host host.example.org
  RemoteForward /home/me/.clipper.sock:/Users/me/.clipper.sock

With this, forwarding is automatically set up any time you run:

This works particularly well if you use the ControlMaster, ControlPath and ControlPersist settings described in the ssh_config man page. These allow you to set up a single forward, and re-use it each time you connect, even if you have multiple concurrent connnections to a given server. An example ~/.ssh/config configuration that would give you this for all hosts would be something like:

Host *
  ControlMaster auto
  ControlPath ~/.ssh/%r@%h:%p
  ControlPersist 240

Configuring Mosh

Mosh is an alternative to SSH that aims to be a superior "mobile shell" than SSH. It is designed to handle intermittent connectivity, and provides relatively intelligent local echoing of line editing commands, but it doesn't yet support any kind of port forwarding (as of the current release, which is version 1.2.5 at the time of writing).

One way to use Clipper with Mosh is to use Mosh for interactive editing but keep using SSH for port forwarding. For example, just say you want to connect to a remote machine with the alias "sandbox", you could have entries like this in your ~/.ssh/config:

Host sandbox
  ControlMaster no
  ControlPath none
  Hostname sandbox.example.com

Host sandbox-clipper
  ControlMaster no
  ControlPath none
  ExitOnForwardFailure yes
  Hostname sandbox.example.com
  RemoteForward 8377 localhost:8377

With this set-up, you can set up the tunnel with:

ssh -N -f sandbox-clipper

SSH will connect to the server, set up the port forwarding and then go into the background.

Then connect using Mosh (it will respect the settings in your ~/.ssh/config file because it uses SSH to bootstrap new connections):

mosh sandbox

You could also set up a shell alias to make setting up the Clipper tunnel more convenient; for example:

alias clip-sandbox='ssh -N -f sandbox-clipper'

You should only need to re-run this command if the connection is interrupted for some reason.

Troubleshooting

Fixing remote port forwarding failed for listen port 8377

This message can be emitted when the remote host you're connecting to already has something bound to the requested port. If there is a competing service that you can't move to another port, Clipper can be configured to use a different port with the --port switch, described above.

Another reason you might see this warning is because an old or stale SSH daemon is lingering from a prior connection attempt. The following example commands show how you can detect the PID of such a process (in this example, 29517) and kill it off:

$ sudo netstat -antpl | grep 8377 # look for offending PID (29517) in output
$ ps auxww | grep 29517           # confirm it's your old sshd process
$ kill 29517                      # kill off old process
$ ps auxww | grep 29517           # confirm that process is really gone

For the bold and lazy, you can simply kill off all sshd process belonging to your user with:

$ killall -u $USER sshd

Do not do this as root, as you will lock yourself out of your server.

Consult the netstat man page for more details (supported options may vary depending on the host operating system).

Fixing remote port forwarding failed when using UNIX domain sockets

Just as with TCP port forwarding, forwarding can fail when using UNIX domain sockets if a stale socket doesn't get automatically cleaned up (or overwritten, as should be the case when StreamLocalBindUnlink yes is present in the server's sshd_config file).

In this case, the fix is to remove the stale socket on the remote host. For example, assuming a socket in $HOME/.clipper.sock on the remote host, $HOST:

 $ ssh $HOST rm .clipper.sock

Fixing delays when sending data to Clipper via nc

It's been reported that on some systems sending data to Clipper via nc may be affected by an annoying delay. Reportedly, adding the -N switch to nc may address this issue.

"Reverse" Clipper

Clipper helps you get content into your local clipboard from other, possibly remote, processes. To send content in the other direction, just paste normally. Note that to make this pleasant in an environment like Vim, you may want to set up bracketed paste mode; see my dotfiles for an example of how this can be done.

Security

At the moment, Clipper doesn't employ any authentication. It does, by default, listen only on the loopback interface, which means that random people on your network won't be able to connect to it. People with access to your local machine, however, will have access; they can push content into your clipboard even if they can't read from it.

This may be fine on a single-user machine, but when you start using ssh -R to expose your Clipper instance on another machine you're evidently increasing your surface area. In order to mitigate this risk, you can configure Clipper to listen only on a UNIX domain socket, and place that socket in a location where the file-system permissions prevent others from accessing it.

Most SSH systems are configured to use restrictive permissions on forwarded socket files (unless overridden; see the documentation for StreamLocalBindMask in man ssh_config), but you may wish to place the socket in a non-shared location like ~/.clipper.sock rather than a shared one like /tmp/clipper.sock in any case.

Frequently Asked Questions

How does Clipper compare to the OSC-52 escape sequence?

OSC-52 is a relatively recent unofficial addition to the set of ANSI escape sequences but it is supported by many programs1. In these compatible programs, with some configuration or support from a plug-in, the escape sequence can be used to instruct the receiving application to insert content into the system clipboard. The main attraction of this implementation is that, if it works at all, it will work irrespective of the location where the copy is happening. For example, a process such as Vim running inside tmux inside an SSH session on a remote host inside a Kitty terminal window can insert text into the clipboard just as easily as it could if run on the local host.

Personally, I continue to use Clipper because most OSC-52 implementations seem to have arbitrary, incompatible limitations imposed on maximum payload size. In some cases, this limit can be configured (for example, see kitty#3937), but in practice I found that it only takes one weak link in the chain to silently truncate copied content in a way that undermines confidence in the entire system. Given that I routinely copy absurdly large slabs of text (eg. log or debug output) in various environments (ie. local and remote), the downsides make OSC-52 unattractive for my personal use. But if a beginner were to ask me how to get remote copying working with as little effort as possible, I'd point them towards OSC-52 — with a suitable disclaimer about possible silent truncation — because their tools may already support it, and they won't have to go to the effort of installing and configuring Clipper.

Authors

Clipper is written and maintained by Greg Hurrell <[email protected]>.

Other contributors that have submitted patches include, in alphabetical order:

  • Daniel Thatcher
  • Jannis Hermanns
  • Nelson Fernandez
  • Paul Choi

Development

The official Clipper source code repo is at:

Mirrors exist at:

Patches are welcome via the usual mechanisms (pull requests, email, posting to the project issue tracker etc).

Website

The official website for Clipper is:

Bug reports should be submitted to the issue tracker at:

License

Copyright 2013-present Greg Hurrell. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

History

main (not yet released)

  • Automatically create logfile directory (patch from Daniel Thatcher, #21).

2.0.0 (4 September 2018)

  • Accept an empty string for the --flags option, allowing flags to be suppressed (#15).

1.0.0 (28 December 2017)

  • Automatically clean up stale socket files at startup.

0.4.2 (14 April 2017)

  • Fix binding to all interfaces instead of just the loopback interface when no address is provided (#9).

0.4.1 (13 December 2016)

  • Create socket with user-only permissions, for better security.

0.4 (28 November 2016)

  • Linux support via xclip instead of pbcopy (patch from Nelson Fernandez).
  • Added --executable and --flags options.
  • On dual-stack systems, listen on both IPv4 and IPv6 loopback interfaces by default.

0.3 (3 June 2016)

  • Add support for listening over a UNIX domain socket.
  • Add support for reading options from a config file (--config/-c switch).

0.2 (2 November 2013)

  • Documentation updates.
  • Updated sample plist to use UTF-8 encoding by default.

0.1 (19 February 2013)

  • Initial release.

Footnotes

  1. A sign of just how recent this addition is the fact that Wikipedia doesn't currently mention it, and the most authoritative explanation for what it is currently exists in the form of a Reddit thread.

More Repositories

1

command-t

⌨️ Fast file navigation for VIM
Lua
2,707
star
2

wincent

💾 Dot-files
Vim Script
1,110
star
3

ferret

🐀 Enhanced multi-file search for Vim
Vim Script
678
star
4

terminus

🖥 Enhanced terminal integration for Vim
Vim Script
452
star
5

vim-university

A curriculum for leveling up your Vim
Shell
242
star
6

loupe

🔍 Enhanced in-file search for Vim
Vim Script
145
star
7

scalpel

🔪 Fast within-file word replacement for Vim
Vim Script
110
star
8

corpus

📝 A note-management application
Vim Script
91
star
9

git-cipher

🔐 Tools for storing encrypted content in Git
Ruby
82
star
10

masochist

⛓ Website infrastructure for over-engineers
Hack
79
star
11

vim-clipper

Clipper integration for Vim
Vim Script
40
star
12

wikitext

🌐 Fast wikitext-to-HTML translator
Ruby
34
star
13

vcs-jump

🤾🏻‍♀️ Jump to interesting places with a Git or Mercurial repo
Vim Script
30
star
14

docvim

Documentation generator for Vim plug-ins
Haskell
26
star
15

yak-layout

Yak keyboard layout and optimizer
JavaScript
25
star
16

relay-2-simpler-faster-more-predictable

"Relay 2: simpler, faster, more predictable" presentation given at the Silicon Valley ReactJS Meetup on August 17th, 2016
HTML
21
star
17

base16-nvim

base16 color schemes in Lua for Neovim
Lua
19
star
18

pinnacle

🏔 Highlight group manipulation for Vim
Vim Script
17
star
19

replay

🔁 Convenient re-run of last recorded Vim macro
Vim Script
17
star
20

presentation-template

Simple starting template for slideshow presentations built using reveal.js, highlight.js and HTML
HTML
12
star
21

synergy

Lightweight iTunes controller for Mac OS X
Objective-C
11
star
22

vim-docvim

Syntax highlighting for Docvim comments
Vim Script
11
star
23

passage

🔑 macOS keychain caching proxy
Go
11
star
24

cv

📜 Curriculum vitae
JavaScript
10
star
25

prefnerd

Monitors changes to the OS X defaults database
Ruby
9
star
26

hextrapolate

Number base conversion tool
JavaScript
7
star
27

gerrit-best-practices-tech-talk

Slides from a tech talk at Causes on the subject of best practices for Gerrit code review
CSS
7
star
28

typing-in-js

An introduction to JavaScript type systems
HTML
6
star
29

secure-notes-exporter

🔐 Export Secure Notes from the OS X keychain
C
6
star
30

js

☕️ Assorted JavaScript
TypeScript
5
star
31

Google-Breakpad

Fork of the official Google Breakpad repository
C++
5
star
32

algorithms

Code related to the Princeton Algorithms course
JavaScript
5
star
33

atosym

dSYM-compatible replacement for atos
Objective-C
4
star
34

bansshee

Anti-SSH-attack tool
4
star
35

walrat

Ruby packrat parser generator
Ruby
4
star
36

gdiff

Mac OS X-native diff and patch visualization tool for Git
Objective-C
4
star
37

WinSwitch

Fast User Switching menu replacement for Mac OS X
R
3
star
38

walrus

Object-oriented templating system
Ruby
3
star
39

WOPublic

Common code used in all Wincent products
Objective-C
3
star
40

react-training-week-8

⚛️ Simple exercises for React training week 8
JavaScript
3
star
41

next

To-do app
TypeScript
3
star
42

automatic-octo-barnacle-theme

Empty Liferay 7.1 theme created for testing purposes
CSS
3
star
43

converter

⚛️ Simple demo app for React workshop
JavaScript
3
star
44

remote-component-test

HTML
2
star
45

jost

🤡 Just Jost (not Jest)
JavaScript
2
star
46

url-lengthening-as-a-service

URL lengthener
JavaScript
2
star
47

remote-app-test

JavaScript
2
star
48

presentation

A dead simple presentation boilerplate
JavaScript
2
star
49

wincent-strings-util

Strings file localization tool
Objective-C
2
star
50

login-tool

Command-line tool for managing startup items
Objective-C
2
star
51

clipper-lightning-talk

Lightning talk on Clipper (clipboard access for local and remote tmux sessions)
JavaScript
2
star
52

wopen3

Open3 replacement
Ruby
2
star
53

git-submodules-tech-talk

Slides from a tech talk that I gave at Causes on Git submodules
CSS
2
star
54

buildtools

Build scripts and configuration for use across all Wincent projects
Shell
2
star
55

static-react-boilerplate

Boilerplate for simple static React web applications
JavaScript
2
star
56

wincent-icon-util

Custom folder icon utility
Objective-C
2
star
57

testable-js-lightning-talk

Slides for a lightning talk on writing testable JS and testing it with Jasmine
Ruby
2
star
58

WOHotKey

Hot Key support for Cocoa applications
Objective-C
2
star
59

mkdtemp

Secure creation of temporary directories
Ruby
2
star
60

dented

↔️ Indenting and dedenting utilities
JavaScript
2
star
61

simple-debounce

🏀 Simple debounce implementation that fires on the trailing edge only
JavaScript
2
star
62

rails-3-lightning-talk

Slides for a 5-minute lightning talk on view escaping in Rails 3
JavaScript
2
star
63

unpack-content

🗃 Extract header data and body from plaintext (Markdown-ish) markup source
JavaScript
2
star
64

git-filter-branch-lightning-talk

How to open-source your repo without open-sourcing your repo
CSS
2
star
65

null

An empty value
1
star
66

minimal-npm-boilerplate

Minimal boilerplate for creating an NPM package
JavaScript
1
star
67

fusion

Pure plug-in architecture framework for Objective-C
Objective-C
1
star
68

fusion-base

Base plug-in for building "pure plug-in" apps
Objective-C
1
star
69

fusion-meta

Plug-in management plug-in for building "pure plug-in" apps
Objective-C
1
star
70

fusion-updater

Updater plug-in for building "pure plug-in" apps
C
1
star
71

fusion-crash-reporter

Crash reporter plug-in for building "pure plug-in" apps
C
1
star
72

wincent-on-rails

Legacy Rails application that used to power wincent.com
HTML
1
star
73

askpass

Graphical password prompter
C
1
star
74

compass-lightning-talk

Tiny demo app showing off some features of Compass for a 5-minute lightning talk at Causes
Ruby
1
star
75

conway

Conway's Game of Life
JavaScript
1
star
76

seven-languages-prolog-tech-talk

Slides and code from a tech talk on Prolog given at Causes for our Seven Languages in Seven Weeks reading group
Prolog
1
star
77

tiktoken-ruby

Rust
1
star
78

fusion-demo

Demonstration app for Fusion framework
Objective-C
1
star
79

fusion-menu

Menu plug-in for building "pure plug-in" apps
Objective-C
1
star
80

fusion-help

Help plug-in for building "pure plug-in" apps
C
1
star
81

WOBezel

Bezels, splashes and HUDs for Mac OS X
Objective-C
1
star
82

fusion-prefs

Preferences plug-in for building "pure plug-in" apps
Objective-C
1
star
83

WOTest

Objective-C unit testing framework
Objective-C
1
star
84

gerrit-intro-tech-talk

Slides from an introductory tech talk at Causes on the subject of Gerrit code review
CSS
1
star