From 4cc259d532f19e01251f378359d09a819d488f64 Mon Sep 17 00:00:00 2001 From: Simon Rieger Date: Sat, 11 Nov 2023 18:51:55 +0100 Subject: [PATCH] add shellfish support --- .chezmoitemplates/zshrc_linux.tmpl | 2 + dot_shellfishrc | 449 +++++++++++++++++++++++++++++ 2 files changed, 451 insertions(+) create mode 100644 dot_shellfishrc diff --git a/.chezmoitemplates/zshrc_linux.tmpl b/.chezmoitemplates/zshrc_linux.tmpl index d91d275..f9ae26d 100644 --- a/.chezmoitemplates/zshrc_linux.tmpl +++ b/.chezmoitemplates/zshrc_linux.tmpl @@ -128,3 +128,5 @@ alias wezterm='flatpak run org.wezfurlong.wezterm' export EDITOR=vim eval "$(starship init zsh)" + +est -e "$HOME/.shellfishrc" && source "$HOME/.shellfishrc" diff --git a/dot_shellfishrc b/dot_shellfishrc new file mode 100644 index 0000000..7cb33dc --- /dev/null +++ b/dot_shellfishrc @@ -0,0 +1,449 @@ +# include this from .bashrc, .zshrc or +# another shell startup file with: +# source $HOME/.shellfishrc +# +# Running from Secure ShellFish +# this gives access to: +# openUrl to open pages or deeps links +# pbcopy to copy text to iOS clipboard +# pbpaste to paste from iOS clipboard +# quicklook to preview files +# runShortcut to run Shortcuts +# setbarcolor to change toolbar color +# sharesheet to invoke iOS share sheet +# snip to add new snippets +# textastic to edit files with Textastic +# +# In any terminal use: +# thumbnail to write exif thumbnails +# notify to post notifications +# widget to change lock/home screen +# widgets & apple watch complications +# +# +# this part does nothing outside ShellFish +if [[ "$LC_TERMINAL" = "ShellFish" ]]; then + ios_printURIComponent() { + awk 'BEGIN {while (y++ < 125) z[sprintf("%c", y)] = y + while (y = substr(ARGV[1], ++j, 1)) + q = y ~ /[a-zA-Z0-9]/ ? q y : q sprintf("%%%02X", z[y]) + printf("%s", q)}' "$1" + } + + ios_printBase64Component() { + echo -n "$1" | base64 + } + + which printf > /dev/null + ios_hasPrintf=$? + ios_printf() { + if [ $ios_hasPrintf ]; then + printf "$1" + else + awk "BEGIN {printf \"$1\"}" + fi + } + + ios_sequence() { + if [[ -n "$TMUX" ]]; then + OUTPUT=$( + ios_printf '\033Ptmux;\033\033]' + echo -n "$1" | tr -d '[:space:]' + ios_printf '\a\033\\' ) + else + OUTPUT=$( + ios_printf '\033]' + echo -n "$1" | tr -d '[:space:]' + ios_printf '\a' ) + fi + if [ -t 1 ] ; then + echo -n $OUTPUT + elif [[ -n "$SSH_TTY" ]]; then + echo -n $OUTPUT > $SSH_TTY + else + echo >&2 'Standard output is not tty and there is no $SSH_TTY' + fi + } + + ios_sequence_spaced() { + if [[ -n "$TMUX" ]]; then + OUTPUT=$( + ios_printf '\033Ptmux;\033\033]' + echo -n "$1" + ios_printf '\a\033\\' ) + else + OUTPUT=$( + ios_printf '\033]' + echo -n "$1" + ios_printf '\a' ) + fi + if [ -t 1 ] ; then + echo -n $OUTPUT + elif [[ -n "$SSH_TTY" ]]; then + echo -n $OUTPUT > $SSH_TTY + else + echo >&2 'Standard output is not tty and there is no $SSH_TTY' + fi + } + + # prepare fifo for communicating result back to shell + ios_prepareResult() { + FIFO=$(mktemp) + rm -f $FIFO + mkfifo $FIFO + echo $FIFO + } + + # wait for terminal to complete action + ios_handleResult() { + FIFO=$1 + if [ -n "$FIFO" ]; then + read <$FIFO -s + rm -f $FIFO + + if [[ $REPLY = error* ]]; then + echo "${REPLY#error=}" | base64 >&2 -d + return 1 + fi + + if [[ $REPLY = result* ]]; then + echo "${REPLY#result=}" | base64 -d + fi + fi + } + + sharesheet() { + if [[ $# -eq 0 ]]; then + if tty -s; then + cat < + +Open in Textastic 9.5 or later. +File must be in directory represented in the Files app to allow writing back edits. +EOF + else + if [ ! -e "$1" ]; then + touch "$1" + fi + OUTPUT=$( + awk 'BEGIN {printf "6;textastic://?ver=2&pwd="}' + ios_printBase64Component "$PWD" + awk 'BEGIN {printf "&home="}' + ios_printBase64Component "$HOME" + awk 'BEGIN {printf "&path="}' + ios_printBase64Component "$1" + ) + ios_sequence "$OUTPUT" + fi + } + + setbarcolor() { + if [[ $# -eq 0 ]]; then + cat < + +Set color of terminal toolbar color with values such as + red, #f00, #ff0000, rgb(255,0,0), color(p3 1.0 0.0 0.0) +EOF + else + OUTPUT=$( + awk 'BEGIN {printf "6;settoolbar://?ver=2&color="}' + ios_printBase64Component "$1" + ) + ios_sequence "$OUTPUT" + fi + } + + openUrl() { + if [[ $# -eq 0 ]]; then + cat < + +Open URL on iOS. +EOF + else + FIFO=$(ios_prepareResult) + OUTPUT=$( + awk 'BEGIN {printf "6;open://?ver=2&respond="}' + ios_printBase64Component "$FIFO" + awk 'BEGIN {printf "&url="}' + ios_printBase64Component "$1" + ) + ios_sequence "$OUTPUT" + ios_handleResult "$FIFO" + fi + } + + runShortcut() { + local baseUrl="shortcuts://run-shortcut" + if [[ $1 == "--x-callback" ]]; then + local baseUrl="shortcuts://x-callback-url/run-shortcut" + shift + fi + + if [[ $# -eq 0 ]]; then + cat < [input-for-shortcut] + +Run in Shortcuts app bringing back results if --x-callback is included. +EOF + else + local name=$(ios_printURIComponent "$1") + shift + if [[ $* == "-" ]]; then + local text=$(cat -) + local input=$(ios_printURIComponent "$text") + else + local input=$(ios_printURIComponent "$*") + fi + openUrl "$baseUrl?name=$name&input=$input" + fi + } + + # copy standard input or arguments to iOS clipboard + pbcopy() { + OUTPUT=$( + awk 'BEGIN {printf "52;c;"} ' + if [ $# -eq 0 ]; then + base64 | tr -d '\n' + else + echo -n "$@" | base64 | tr -d '\n' + fi + ) + ios_sequence "$OUTPUT" + } + + # paste from iOS device clipboard to standard output + pbpaste() { + FIFO=$(ios_prepareResult) + OUTPUT=$( + awk 'BEGIN {printf "6;pbpaste://?ver=2&respond="}' + ios_printBase64Component "$FIFO" + ) + ios_sequence "$OUTPUT" + ios_handleResult "$FIFO" + } + + # create new snippets + snip() { + if [[ $# -eq 0 ]]; then + cat < + +EOF + else + OUTPUT=$( + awk 'BEGIN {printf "6;addsnippet://?ver=2&text="}' + ios_printBase64Component "$*" + ) + ios_sequence "$OUTPUT" + fi + } + + # Secure ShellFish supports 24-bit colors + export COLORTERM=truecolor + + # We need to pass through escape sequences through tmux + if [[ -n "$TMUX" ]]; then + # ignore error from old versions of tmux without this command + tmux 2> /dev/null set -g allow-passthrough on || true + fi + + if [[ -z "$INSIDE_EMACS" && $- = *i* ]]; then + # tmux mouse mode enables scrolling with + # swipe and mouse wheel + if [[ -n "$TMUX" ]]; then + tmux set -g mouse on + fi + + # send the current directory using OSC 7 when showing prompt to + # make filename detection work better for interactive shell + update_terminal_cwd() { + ios_sequence $( + awk "BEGIN {printf \"7;%s\", \"file://$HOSTNAME\"}" + ios_printURIComponent "$PWD" + ) + } + if [ -n "$ZSH_VERSION" ]; then + precmd() { update_terminal_cwd; } + elif [[ $PROMPT_COMMAND != *"update_terminal_cwd"* ]]; then + PROMPT_COMMAND="update_terminal_cwd${PROMPT_COMMAND:+; $PROMPT_COMMAND}" + fi + fi +fi + +# this part works in any context + +thumbnail() { + if [[ $# -eq 0 ]]; then + cat < [image-file-2] ... + +Add Exif thumnails to image files using ImageMagick convert and exiftool. + +EOF +else + # make sure ImageMagick and exiftool are available + convert -version 1>/dev/null 2>/dev/null || { echo "ImageMagick convert needs to be installed"; return 1; } + exiftool -v 1>/dev/null 2>/dev/null || { echo "exiftool needs to be installed"; return 1; } + + THUMBNAIL=/tmp/thumbnail.jpg + for arg in "$@" + do + echo "$arg" + convert "$arg" -thumbnail 160x120^ "$THUMBNAIL" + exiftool -q -overwrite_original "-thumbnailimage<=$THUMBNAIL" "$arg" + rm -f "$THUMBNAIL" + done +fi +} + + +# Updates Terminal Data widget in Secure ShellFish +# +# This command sends encrypted data through push notifications such +# that it doesn't need to run from a Secure ShellFish terminal. +widget() { + if [[ $# -eq 0 ]]; then + cat < ... + +Update widget on device from which this function was installed with a number of content parameters that can be string, progress, icon, target, color, url or shortcut. + +Each argument type is derived from input, where the first argument is assumed to be a target if it matches a target configured on the widget. + +Progress has the form: 50% or 110/220 + +Icon must match valid SF Symbol name such as globe or terminal.fill + +Colors must be hex colours such as #000 #ff00ff where the color is used for later content and 'foreground' switches back to default colour + +Target is used to send different content to different widgets after configuring the widgets with different target identifiers which requires the pro unlock. The target parameter is never assumed unless --target is used and is effective until next --target parameter allowing updates of several widgets with a single command + +URL is used when tapping the widget and is assumed for arguments starting with https:// and other schemes are supported by using --url + +Shortcut works like URL running the Shortcut with the given name and is never assumed without --shortcut + +String is the fallback type if nothing else matches, but content type can be forced for next parameter with --progress, --icon, --color, --text or --target with something like: + widget --text "50/100" + +You can update several widgets at once by using --target to send all parameters until the next --target to a particular widget. Updating several widgets at once allows more total updates per day. + +EOF + return 0 + fi + + local key=ab5d8c58fd13a6a2536504580a527d682fe9f5560aa57298b4a4135ef5ed6987 + local user=jBkLbEYRBy33rdItwbMJq0WHYwYoMy2Zf1gBCfVj + local iv=ab5bbeb426015da7eedcee8bee3dffb7 + + local plain=$( + echo Secure ShellFish Widget 2.0 + for var in "$@" + do + echo -ne "$var" | base64 + done) + local base64=$(echo "$plain" | openssl enc -aes-256-cbc -base64 -K $key -iv $iv) + curl -sS -X POST -H "Content-Type: text/plain" --data "$base64" "https://secureshellfish.app/push/?user=$user" +} + + +# Shows notification on your device with Secure ShellFish installed +# optionally opening URL or running Shortcut when notification is +# opened. +# +# This command sends encrypted data through push notifications such +# that it doesn't need to run from a Secure ShellFish terminal. +notify() { + if [[ $# -eq 0 ]]; then + cat < ... + +EOF + return 0 + fi + + local key=ab5d8c58fd13a6a2536504580a527d682fe9f5560aa57298b4a4135ef5ed6987 + local user=jBkLbEYRBy33rdItwbMJq0WHYwYoMy2Zf1gBCfVj + local iv=ab5bbeb426015da7eedcee8bee3dffb7 + + local plain=$( + echo Secure ShellFish Notify 2.0 + for var in "$@" + do + echo -ne "$var" | base64 + done) + local base64=$(echo "$plain" | openssl enc -aes-256-cbc -base64 -K $key -iv $iv) + curl -sS -X POST -H "Content-Type: text/plain" --data "$base64" "https://secureshellfish.app/push/?user=$user&mutable" +}