#!/usr/bin/env bash # Whether to disable tmux/screen DCS escape sequences : "${OSC777_NO_DCS:=0}" die() { echo "ERROR: $*" exit 1 } usage() { if [ $# -gt 0 ]; then exec 1>&2 fi cat << EOF Usage: $0 [options] <message> Send a notification (title and message) to the host system using the OSC 777 escape sequence: Options: -h, --help This screen. -d, --no-dcs Disable tmux/screen specific DCS sequences, only use OSC 777 -- Stop options processing EOF if [ $# -gt 0 ]; then echo die "$@" else exit 0 fi } tmux_seq() { # shellcheck disable=1003 printf '\033Ptmux;\033%s\033\\' "$1" } screen_seq() { # Screen limits the length of string sequences, so we have to break it up. # Going by the screen history: # (v4.2.1) Apr 2014 - today: 768 bytes # Aug 2008 - Apr 2014 (v4.2.0): 512 bytes # ??? - Aug 2008 (v4.0.3): 256 bytes local limit=768 # We go 4 bytes under the limit because we're going to insert two bytes # before (\eP) and 2 bytes after (\e\) each string. printf '%s' "$1" | sed -E "s:.{$((limit - 4))}:&\n:g" | sed -E -e 's:^:\x1bP:' -e 's:$:\x1b\\:' | tr -d '\n' } osc777_seq() { printf '%s' "$1" } print_seq() { local seq="$1" if [ "${OSC777_NO_DCS}" != 0 ]; then # Override TERM to avoid tmux/screen DCS escape logic TERM=dummy fi case ${TERM-} in screen*) # Since tmux defaults to setting TERM=screen, special case it. if [ -n "${TMUX-}" ]; then tmux_seq "${seq}" else screen_seq "${seq}" fi ;; tmux*) tmux_seq "${seq}" ;; *) osc777_seq "${seq}" ;; esac } notify() { local title=$1 local message=$2 # shellcheck disable=1003 print_seq "$(printf '\033]777;notify;%s;%s\e\\' "${title}" "${message}")" } main() { set -e local args=() while [ $# -gt 0 ]; do case $1 in -h | --help) usage ;; -d | --no-dcs) OSC777_NO_DCS=1 ;; --) shift args+=("$@") break ;; -*) usage "Unknown option: $1" ;; *) args+=("$1") ;; esac shift done if [ "${#args[@]}" -ne 2 ]; then usage "Supply exactly two arguments" fi notify "${args[@]}" } main "$@"