osc52
1 #!/bin/sh 2 # Copyright (c) 2012 The Chromium OS Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style license that can be 4 # found in the LICENSE file. 5 # Max length of the OSC 52 sequence. Sequences longer than this will not be 6 # sent to the terminal. 7 OSC_52_MAX_SEQUENCE="100000" 8 # Write an error message and exit. 9 # Usage: <message> 10 die() { 11 echo "ERROR: $*" 12 exit 1 13 } 14 # Send a DCS sequence through tmux. 15 # Usage: <sequence> 16 tmux_dcs() { 17 printf '\033Ptmux;\033%s\033\\' "$1" 18 } 19 # Send a DCS sequence through screen. 20 # Usage: <sequence> 21 screen_dcs() { 22 # Screen limits the length of string sequences, so we have to break it up. 23 # Going by the screen history: 24 # (v4.2.1) Apr 2014 - today: 768 bytes 25 # Aug 2008 - Apr 2014 (v4.2.0): 512 bytes 26 # ??? - Aug 2008 (v4.0.3): 256 bytes 27 # Since v4.2.0 is only ~4 years old, we'll use the 256 limit. 28 # We can probably switch to the 768 limit in 2022. 29 local limit=256 30 # We go 4 bytes under the limit because we're going to insert two bytes 31 # before (\eP) and 2 bytes after (\e\) each string. 32 echo "$1" | \ 33 sed -E "s:.{$(( limit - 4 ))}:&\n:g" | \ 34 sed -E -e 's:^:\x1bP:' -e 's:$:\x1b\\:' | \ 35 tr -d '\n' 36 } 37 # Send an escape sequence to hterm. 38 # Usage: <sequence> 39 print_seq() { 40 local seq="$1" 41 case ${TERM-} in 42 screen*) 43 # Since tmux defaults to setting TERM=screen (ugh), we need to detect 44 # it here specially. 45 if [ -n "${TMUX-}" ]; then 46 tmux_dcs "${seq}" 47 else 48 screen_dcs "${seq}" 49 fi 50 ;; 51 tmux*) 52 tmux_dcs "${seq}" 53 ;; 54 *) 55 echo "${seq}" 56 ;; 57 esac 58 } 59 # Base64 encode stdin. 60 b64enc() { 61 base64 | tr -d '\n' 62 } 63 # Send the OSC 52 sequence to copy the content. 64 # Usage: [string] 65 copy() { 66 local str 67 if [ $# -eq 0 ]; then 68 str="$(b64enc)" 69 else 70 str="$(echo "$@" | b64enc)" 71 fi 72 local len=${#str} 73 if [ ${len} -lt ${OSC_52_MAX_SEQUENCE} ]; then 74 print_seq "$(printf '\033]52;c;%s\a' "${str}")" 75 else 76 die "selection too long to send to terminal:" \ 77 "${OSC_52_MAX_SEQUENCE} limit, ${len} attempted" 78 fi 79 } 80 # Write tool usage and exit. 81 # Usage: [error message] 82 usage() { 83 if [ $# -gt 0 ]; then 84 exec 1>&2 85 fi 86 cat <<EOF 87 Usage: osc52 [options] [string] 88 Send an arbitrary string to the terminal clipboard using the OSC 52 escape 89 sequence as specified in xterm: 90 https://invisible-island.net/xterm/ctlseqs/ctlseqs.html 91 Section "Operating System Controls", Ps => 52. 92 The data can either be read from stdin: 93 $ echo "hello world" | osc52.sh 94 Or specified on the command line: 95 $ osc52.sh "hello world" 96 EOF 97 if [ $# -gt 0 ]; then 98 echo 99 die "$@" 100 else 101 exit 0 102 fi 103 } 104 main() { 105 set -e 106 while [ $# -gt 0 ]; do 107 case $1 in 108 -h|--help) 109 usage 110 ;; 111 -*) 112 usage "Unknown option: $1" 113 ;; 114 *) 115 break 116 ;; 117 esac 118 done 119 copy "$@" 120 } 121 main "$@"