#!/bin/sh
# xsel-osc52 - drop-in replacement for xsel that uses OSC 52 escape sequences
# instead of X11 clipboard. Designed for use in JupyterLab terminals where
# no X display is available but the terminal emulator supports OSC 52.
#
# Supports the same flags as xsel for copy operations:
#   -i, --input       read from stdin (default)
#   -o, --output      output current selection (not supported)
#   -a, --append      append to selection (not supported)
#   -c, --clear       clear the selection
#   -p, --primary     operate on PRIMARY selection (default)
#   -s, --secondary   operate on SECONDARY selection
#   -b, --clipboard   operate on CLIPBOARD selection
#   --trim            remove trailing newline
#   -h, --help        show usage
#   --version         show version
#
# Usage:
#   echo "text" | xsel-osc52 --clipboard
#   symlink as 'xsel' and place earlier in PATH to override system xsel
#
# OSC 52 sequence format: ESC ] 52 ; <target> ; <base64-data> BEL

VERSION="1.0.0"
SELECTION="primary"
MODE=""
TRIM=0
CLEAR=0
VERBOSE=0

print_usage() {
    cat <<'USAGE'
Usage: xsel-osc52 [options]
Copy input to clipboard via OSC 52 escape sequences (xsel-compatible).

Input options
  -a, --append          Not supported (falls back to input)
  -f, --follow          Not supported
  -i, --input           Read standard input into the selection

Output options
  -o, --output          Not supported (OSC 52 is write-only)

Action options
  -c, --clear           Clear the selection
  -d, --delete          Clear the selection

Selection options
  -p, --primary         Operate on the PRIMARY selection (default)
  -s, --secondary       Operate on the SECONDARY selection
  -b, --clipboard       Operate on the CLIPBOARD selection

Miscellaneous options
  --trim                Remove trailing newline
  --display             Ignored (no X server needed)
  -n, --nodetach        Ignored
  -h, --help            Display this help
  -v, --verbose         Print informative messages
  --version             Output version information
USAGE
}

# Parse arguments - compatible with xsel's flag style
while [ $# -gt 0 ]; do
    case "$1" in
        -i|--input)
            MODE="input"
            ;;
        -o|--output)
            MODE="output"
            ;;
        -a|--append)
            MODE="input"  # fallback: treat append as input
            ;;
        -f|--follow)
            MODE="input"  # fallback
            ;;
        -c|--clear|-d|--delete)
            CLEAR=1
            ;;
        -p|--primary)
            SELECTION="primary"
            ;;
        -s|--secondary)
            SELECTION="secondary"
            ;;
        -b|--clipboard)
            SELECTION="clipboard"
            ;;
        -k|--keep|-x|--exchange)
            # Ignored - not applicable to OSC 52
            ;;
        --trim)
            TRIM=1
            ;;
        --display)
            shift  # consume display arg, ignore
            ;;
        -m|--name)
            shift  # consume name arg, ignore
            ;;
        -t|--selectionTimeout)
            shift  # consume timeout arg, ignore
            ;;
        -l|--logfile)
            shift  # consume logfile arg, ignore
            ;;
        -n|--nodetach)
            # Ignored
            ;;
        -v|--verbose)
            VERBOSE=1
            ;;
        -z|--zeroflush)
            # Ignored
            ;;
        -h|--help)
            print_usage
            exit 0
            ;;
        --version)
            echo "xsel-osc52 version $VERSION (OSC 52 shim for xsel)"
            exit 0
            ;;
        -*)
            # Ignore unknown flags for compatibility
            ;;
        *)
            break
            ;;
    esac
    shift
done

# Map selection name to OSC 52 target character
case "$SELECTION" in
    clipboard)  OSC_TARGET="c" ;;
    secondary)  OSC_TARGET="s" ;;
    primary|*)  OSC_TARGET="p" ;;
esac

# Auto-detect mode like xsel does:
# - if stdin is not a tty (piped), default to input
# - if stdout is not a tty (piped), default to output
# - if both are ttys, default to output (matches xsel behavior)
if [ -z "$MODE" ] && [ "$CLEAR" -eq 0 ]; then
    if ! [ -t 0 ]; then
        MODE="input"
    elif ! [ -t 1 ]; then
        MODE="output"
    else
        MODE="output"
    fi
fi

# Handle clear
if [ "$CLEAR" -eq 1 ]; then
    # Send empty content to clear the selection
    printf '\033]52;%s;%s\a' "$OSC_TARGET" "" > /dev/tty 2>/dev/null || \
    printf '\033]52;%s;%s\a' "$OSC_TARGET" ""
    if [ "$VERBOSE" -eq 1 ]; then
        echo "xsel-osc52: cleared $SELECTION selection" >&2
    fi
    exit 0
fi

if [ "$MODE" = "output" ]; then
    if [ "$VERBOSE" -eq 1 ]; then
        echo "xsel-osc52: output mode (-o) is not supported via OSC 52" >&2
    fi
    exit 1
fi

# Read input from stdin
DATA=$(cat)

# Remove trailing newline if requested
if [ "$TRIM" -eq 1 ]; then
    DATA=$(printf '%s' "$DATA" | sed -e 's/\n$//')
fi

# Base64 encode
B64=$(printf '%s' "$DATA" | base64 | tr -d '\n')

# Emit OSC 52 sequence
printf '\033]52;%s;%s\a' "$OSC_TARGET" "$B64" > /dev/tty 2>/dev/null || \
printf '\033]52;%s;%s\a' "$OSC_TARGET" "$B64"

if [ "$VERBOSE" -eq 1 ]; then
    echo "xsel-osc52: sent ${#DATA} bytes to $SELECTION selection via OSC 52" >&2
fi
