#!/bin/sh
# rbcat — show an image or play audio in the rbterm pane you're in, even
# over ssh: the file travels through the terminal as an OSC 1337 inline
# file (iTerm2's protocol), so it works wherever the pane's bytes go.
#
#   rbcat photo.jpg song.mp3      always send inline
#   rbcat --cat FILE...           behave like the shell-integration `cat`
#                                 wrapper: media inline, everything else
#                                 through the real cat
#
# rbterm is recognised by LC_TERMINAL/TERM_PROGRAM, else by asking the
# terminal (XTVERSION). RBTERM_INLINE=1 forces it (e.g. inside tmux).
#
# Images (png jpeg gif bmp) show as a click-to-dismiss overlay; audio
# (mp3 wav ogg) gets a player card that only plays when you click it.
# Inside tmux the sequence is wrapped for passthrough — needs
# `set -g allow-passthrough on` in tmux.conf.

# >>> rbterm-inline-media (keep identical in rbterm-shell-integration.{bash,zsh})
_rbterm_inline_max=50000000
_rbterm_in_rbterm() {
    if [ "${LC_TERMINAL:-}" = rbterm ] || [ "${TERM_PROGRAM:-}" = rbterm ] ||
       [ "${RBTERM_INLINE:-}" = 1 ]; then
        return 0
    fi
    # Over ssh LC_TERMINAL only survives if sshd's AcceptEnv allows it
    # (Debian/Ubuntu: LC_*; RHEL/CentOS: a fixed list without it). So ask
    # the terminal itself — XTVERSION, answered as "rbterm(<ver>)" — once
    # per shell. Not inside tmux (tmux answers for itself; set
    # RBTERM_INLINE=1 there).
    case ${_rbterm_probed:-} in yes) return 0 ;; no) return 1 ;; esac
    _rbterm_probed=no
    [ -t 0 ] && [ -t 1 ] && [ -z "${TMUX:-}" ] || return 1
    _rb_stty=$(stty -g 2>/dev/null) || return 1
    stty -echo -icanon min 0 time 10 2>/dev/null
    printf '\033[>q'
    _rb_reply=$(dd bs=256 count=1 2>/dev/null)
    stty "$_rb_stty" 2>/dev/null
    case $_rb_reply in *rbterm*) _rbterm_probed=yes; return 0 ;; esac
    return 1
}
_rbterm_is_media() {
    if command -v file >/dev/null 2>&1; then
        case $(file -b --mime-type -- "$1" 2>/dev/null) in
            image/png|image/jpeg|image/gif|image/bmp|image/x-ms-bmp) return 0 ;;
            audio/mpeg|audio/mp3|audio/x-wav|audio/wav|audio/vnd.wave) return 0 ;;
            audio/ogg|audio/x-vorbis+ogg|application/ogg) return 0 ;;
        esac
        return 1
    fi
    case $1 in
        *.png|*.PNG|*.jpg|*.JPG|*.jpeg|*.JPEG|*.gif|*.GIF|*.bmp|*.BMP) return 0 ;;
        *.mp3|*.MP3|*.wav|*.WAV|*.ogg|*.OGG) return 0 ;;
    esac
    return 1
}
# Sent as iTerm2's multipart form: a header, 3 KB base64 chunks each in its
# own complete escape, then FileEnd. One escape per small write matters on
# Windows: the console host closes an unfinished escape at every write
# boundary, so a single File= escape split across printf/base64/printf
# arrived with an empty body. Chunks also suit tmux passthrough.
_rbterm_send_file() {
    _rb_size=$(wc -c < "$1" | tr -d ' ')
    if [ "$_rb_size" -gt "$_rbterm_inline_max" ]; then
        printf 'rbterm: %s is too large to show inline (%s bytes, limit %s)\n' \
            "$1" "$_rb_size" "$_rbterm_inline_max" >&2
        return 1
    fi
    _rb_name=$(printf '%s' "${1##*/}" | base64 | tr -d '\n')
    if [ -n "${TMUX:-}" ]; then
        _rb_pre='\033Ptmux;\033\033]'; _rb_post='\a\033\\'
    else
        _rb_pre='\033]'; _rb_post='\a'
    fi
    printf "${_rb_pre}1337;MultipartFile=name=%s;size=%s;inline=1${_rb_post}" "$_rb_name" "$_rb_size"
    # awk, not a shell read loop (~40x faster); fflush per chunk keeps
    # each escape in its own write. Delimiters go via ENVIRON so awk
    # doesn't reinterpret their backslashes.
    base64 < "$1" | tr -d '\n' | fold -w 3000 |
        _RB_P=$(printf "$_rb_pre") _RB_Q=$(printf "$_rb_post") awk \
            '{ printf "%s1337;FilePart=%s%s", ENVIRON["_RB_P"], $0, ENVIRON["_RB_Q"]; fflush() }'
    printf "${_rb_pre}1337;FileEnd${_rb_post}"
}
# The wrapper: media files go to the pane inline, anything else — text,
# pipes (`cat x | grep`), options, stdin — goes through the real cat. The
# terminal is only probed when a media file is actually involved.
_rbterm_cat() {
    if [ -t 1 ] && [ $# -gt 0 ] && [ -z "${RBTERM_CAT_PLAIN:-}" ]; then
        _rb_any=
        for _rb_a in "$@"; do
            case $_rb_a in -*) command cat "$@"; return ;; esac
            [ -f "$_rb_a" ] || { command cat "$@"; return; }
            _rbterm_is_media "$_rb_a" && _rb_any=1
        done
        if [ -n "$_rb_any" ] && _rbterm_in_rbterm; then
            _rb_rc=0
            for _rb_a in "$@"; do
                if _rbterm_is_media "$_rb_a"; then
                    _rbterm_send_file "$_rb_a" || _rb_rc=1
                else
                    command cat -- "$_rb_a" || _rb_rc=1
                fi
            done
            return $_rb_rc
        fi
    fi
    command cat "$@"
}
# <<< rbterm-inline-media

if [ "${1:-}" = "--cat" ]; then
    shift
    _rbterm_cat "$@"
    exit $?
fi
if [ $# -eq 0 ]; then
    echo "usage: rbcat FILE...   (or rbcat --cat FILE... for wrapper behaviour)" >&2
    exit 2
fi
rc=0
for f in "$@"; do
    if [ ! -f "$f" ]; then echo "rbcat: $f: no such file" >&2; rc=1; continue; fi
    _rbterm_send_file "$f" || rc=1
done
exit $rc
