diff --git a/lib/clipboard.zsh b/lib/clipboard.zsh index 5bba11d16..6102f3324 100644 --- a/lib/clipboard.zsh +++ b/lib/clipboard.zsh @@ -3,10 +3,23 @@ # This file has support for doing system clipboard copy and paste operations # from the command line in a generic cross-platform fashion. # -# On OS X and Windows, the main system clipboard or "pasteboard" is used. On other -# Unix-like OSes, this considers the X Windows CLIPBOARD selection to be the -# "system clipboard", and the X Windows `xclip` command must be installed. - +# This is uses essentially the same heuristic as neovim, with the additional +# special support for Cygwin. +# See: https://github.com/neovim/neovim/blob/e682d799fa3cf2e80a02d00c6ea874599d58f0e7/runtime/autoload/provider/clipboard.vim#L55-L121 +# +# - pbcopy, pbpaste (macOS) +# - cygwin (Windows running Cygwin) +# - wl-copy, wl-paste (if $WAYLAND_DISPLAY is set) +# - xclip (if $DISPLAY is set) +# - xsel (if $DISPLAY is set) +# - lemonade (for SSH) https://github.com/pocke/lemonade +# - doitclient (for SSH) http://www.chiark.greenend.org.uk/~sgtatham/doit/ +# - win32yank (Windows) +# - tmux (if $TMUX is set) +# +# Defines two functions, clipcopy and clippaste, based on the detected platform. +## +# # clipcopy - Copy data to clipboard # # Usage: @@ -15,41 +28,8 @@ # # clipcopy - copies a file's contents to clipboard # -function clipcopy() { - emulate -L zsh - local file=$1 - if [[ $OSTYPE == darwin* ]]; then - if [[ -z $file ]]; then - pbcopy - else - cat $file | pbcopy - fi - elif [[ $OSTYPE == (cygwin|msys)* ]]; then - if [[ -z $file ]]; then - cat > /dev/clipboard - else - cat $file > /dev/clipboard - fi - else - if (( $+commands[xclip] )); then - if [[ -z $file ]]; then - xclip -in -selection clipboard - else - xclip -in -selection clipboard $file - fi - elif (( $+commands[xsel] )); then - if [[ -z $file ]]; then - xsel --clipboard --input - else - cat "$file" | xsel --clipboard --input - fi - else - print "clipcopy: Platform $OSTYPE not supported or xclip/xsel not installed" >&2 - return 1 - fi - fi -} - +## +# # clippaste - "Paste" data from clipboard to stdout # # Usage: @@ -67,20 +47,55 @@ function clipcopy() { # # # Paste to a file # clippaste > file.txt -function clippaste() { +# +function detect-clipboard() { emulate -L zsh - if [[ $OSTYPE == darwin* ]]; then - pbpaste - elif [[ $OSTYPE == (cygwin|msys)* ]]; then - cat /dev/clipboard + + if [[ "${OSTYPE}" == darwin* ]] && (( ${+commands[pbcopy]} )) && (( ${+commands[pbpaste]} )); then + function clipcopy() { pbcopy < "${1:-/dev/stdin}"; } + function clippaste() { pbpaste; } + elif [[ "${OSTYPE}" == (cygwin|msys)* ]]; then + function clipcopy() { cat "${1:-/dev/stdin}" > /dev/clipboard; } + function clippaste() { cat /dev/clipboard; } + elif [ -n "${WAYLAND_DISPLAY:-}" ] && (( ${+commands[wl-copy]} )) && (( ${+commands[wl-paste]} )); then + function clipcopy() { wl-copy < "${1:-/dev/stdin}"; } + function clippaste() { wl-paste; } + elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xclip]} )); then + function clipcopy() { xclip -in -selection clipboard < "${1:-/dev/stdin}"; } + function clippaste() { xclip -out -selection clipboard; } + elif [ -n "${DISPLAY:-}" ] && (( ${+commands[xsel]} )); then + function clipcopy() { xsel --clipboard --input < "${1:-/dev/stdin}"; } + function clippaste() { xsel --clipboard --output; } + elif (( ${+commands[lemonade]} )); then + function clipcopy() { lemonade copy < "${1:-/dev/stdin}"; } + function clippaste() { lemonade paste; } + elif (( ${+commands[doitclient]} )); then + function clipcopy() { doitclient wclip < "${1:-/dev/stdin}"; } + function clippaste() { doitclient wclip -r; } + elif (( ${+commands[win32yank]} )); then + function clipcopy() { win32yank -i < "${1:-/dev/stdin}"; } + function clippaste() { win32yank -o; } + elif [ -n "${TMUX:-}" ] && (( ${+commands[tmux]} )); then + function clipcopy() { tmux load-buffer "${1:--}"; } + function clippaste() { tmux save-buffer -; } else - if (( $+commands[xclip] )); then - xclip -out -selection clipboard - elif (( $+commands[xsel] )); then - xsel --clipboard --output - else - print "clipcopy: Platform $OSTYPE not supported or xclip/xsel not installed" >&2 - return 1 - fi + function _retry_clipboard_detection_or_fail() { + local clipcmd="${1}"; shift + if detect-clipboard; then + "${clipcmd}" "$@" + else + print "${clipcmd}: Platform $OSTYPE not supported or xclip/xsel not installed" >&2 + return 1 + fi + } + function clipcopy() { _retry_clipboard_detection_or_fail clipcopy "$@"; } + function clippaste() { _retry_clipboard_detection_or_fail clippaste "$@"; } + return 1 fi } + +# Detect at startup. A non-zero exit here indicates that the dummy clipboards were set, +# which is not really an error. If the user calls them, they will attempt to redetect +# (for example, perhaps the user has now installed xclip) and then either print an error +# or proceed successfully. +detect-clipboard || true