#!/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]
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 "$@"