Skip to content

Instantly share code, notes, and snippets.

@vuori
Created August 13, 2022 13:59
Show Gist options
  • Save vuori/39871a883292e99ae98c881a56ed7792 to your computer and use it in GitHub Desktop.
Save vuori/39871a883292e99ae98c881a56ed7792 to your computer and use it in GitHub Desktop.
get/set X selections from zsh
# copy selection: same as xclip, but works from remote hosts too
zclip() {
# See https://invisible-island.net/xterm/ctlseqs/ctlseqs.html#h3-Operating-System-Commands
# for targets. Usually either p(rimary), c(lipboard) or both, or s(elect) to use
# the definition of SELECT from X resources. For the adventurous, q (secondary)
# is also available.
#
# Note: SetSelection must be in allowed window ops.
#
# Flags: -n don't chomp newline, -t pass to stdout ("tee")
local -a tee_mode nochomp_mode
zparseopts -F -D t=tee_mode n=nochomp_mode || return
local target=${1:-pc} data chomp_data=''
# Read input data into memory. We could kinda sorta
# stream this, but with chomping and everything, it
# just isn't worth the trouble.
IFS='' read -s -r -d $'\004' data
if ! (( ${#nochomp_mode} )) ; then
# Chomp it
[[ $data[-1] == $'\n' ]] && chomp_data=$data[0,-2]
else
# Pass through as is
chomp_data=$data
fi
# Cut down the data to a reasonable size. We might
# want to fail here instead if it's too large.
chomp_data=$chomp_data[1,2048]
# Output to the terminal for copy
{
print -n "\e]52;$target;"
print -n -r -- $chomp_data | openssl base64 -A -a
print -n '\e\\'
} > /dev/tty
# and if we're tee'ing, output it here for viewing
(( ${#tee_mode} )) && print -n -- $data
return 0
}
# paste selection: as above
zgetclip() {
local data=()
local source=${1:-s}
# Request clipboard data (OSC 52). Response format is
# ^[]52;p;DDD^[\ where DDD is Base64-encoded data.
#
# Note: GetSelection must be in allowed window ops.
#
# We need to force tty access here to have this work
# with redirection.
print -n "\e]52;$source;?\e\\" > /dev/tty
IFS=$'\e;' read -r -s -d '\' -t 1 -A data < /dev/tty
if [[ $data[2] != ']52' ]] ; then
printf "zgetclip: unexpected response %q;%q\n" $data[2] $data[3] >& 2
return 1
fi
openssl base64 -a -d <<< $data[4]
}
_zgetclip_to_var() {
unset REPLY
zgetclip $@ | IFS='' read -r -d $'\004' REPLY
(( ${#REPLY} ))
}
_zgetclip_to_kill_ring() {
local source=s
case $WIDGET in
*-clipboard)
source=c
;;
*-primary)
source=p
;;
*-secondary)
source=q
;;
esac
_zgetclip_to_var $source || return
zle copy-region-as-kill $REPLY
}
_zgetclip_yank() {
_zgetclip_to_kill_ring || return
zle yank
}
zle -N zclip-yank _zgetclip_yank # uses SELECT
zle -N zclip-yank-from-clipboard _zgetclip_yank
zle -N zclip-yank-from-primary _zgetclip_yank
zle -N zclip-yank-from-secondary _zgetclip_yank
_zclip_from_region() {
local target=pc
case $WIDGET in
*-clipboard)
source=c
;;
*-primary)
source=p
;;
*-secondary)
source=q
;;
esac
zle copy-region-as-kill
zclip <<< $CUTBUFFER
}
zle -N zclip-copy _zclip_from_region # uses PRIMARY+CLIPBOARD
zle -N zclip-copy-to-clipboard _zclip_from_region
zle -N zclip-copy-to-primary_zclip_from_region
zle -N zclip-copy-to-secondary _zclip_from_region
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment