From 7c4afaf4aa358c5ec5be8596df1685663aef719c Mon Sep 17 00:00:00 2001 From: ConnerWill Date: Tue, 20 Aug 2024 04:50:47 +0000 Subject: [PATCH] shellfish --- .../functions-available/wetty-download.zsh | 32 ++ .../functions-enabled/wetty-download.zsh | 1 + .config/zsh/zsh/user/zsh.d/82_colors.zsh | 4 +- .shellfishrc | 449 ++++++++++++++++++ 4 files changed, 485 insertions(+), 1 deletion(-) create mode 100644 .config/zsh/zsh/user/functions/functions-available/wetty-download.zsh create mode 120000 .config/zsh/zsh/user/functions/functions-enabled/wetty-download.zsh create mode 100755 .shellfishrc diff --git a/.config/zsh/zsh/user/functions/functions-available/wetty-download.zsh b/.config/zsh/zsh/user/functions/functions-available/wetty-download.zsh new file mode 100644 index 0000000..5db218a --- /dev/null +++ b/.config/zsh/zsh/user/functions/functions-available/wetty-download.zsh @@ -0,0 +1,32 @@ +# WeTTY supports file downloads by printing terminal escape sequences between a base64 encoded file. The name of the downloaded file can optionally be provided, also base64 encoded, before the encoded file contents with a : separating them. +# +# The terminal escape sequences used are ^[[5i and ^[[4i (VT100 for “enter auto print” and “exit auto print” respectively - https://vt100.net/docs/tp83/appendixc.html). +# +# To take advantage add the following bash function to your .bashrc +# +# Copy to clipboardErrorCopied +# You are then able to download files via WeTTY! +# +# wetty-download my-pdf-file.pdf +# Copy to clipboardErrorCopied +# or you can still use the classic style: +# +# $ cat my-pdf-file.pdf | wetty-download +# Copy to clipboardErrorCopied +# WeTTY will then issue a popup like the following that links to a local file blob: Download ready: file-20191015233654.pdf + +function wetty-download() { + file=${1:-/dev/stdin} + + nameprefix="" + if [[ -f "$file" ]]; then + nameprefix="$(basename "$file" | base64 -w 0):" + fi + + + if [[ -f "$file" || "$file" == "/dev/stdin" ]]; then + printf "\033[5i"$nameprefix$(cat "$file" | base64 -w 0)"\033[4i" + else + echo "$file does not appear to be a file" + fi +} diff --git a/.config/zsh/zsh/user/functions/functions-enabled/wetty-download.zsh b/.config/zsh/zsh/user/functions/functions-enabled/wetty-download.zsh new file mode 120000 index 0000000..689bb76 --- /dev/null +++ b/.config/zsh/zsh/user/functions/functions-enabled/wetty-download.zsh @@ -0,0 +1 @@ +../functions-available/wetty-download.zsh \ No newline at end of file diff --git a/.config/zsh/zsh/user/zsh.d/82_colors.zsh b/.config/zsh/zsh/user/zsh.d/82_colors.zsh index 8d73db4..891d603 100644 --- a/.config/zsh/zsh/user/zsh.d/82_colors.zsh +++ b/.config/zsh/zsh/user/zsh.d/82_colors.zsh @@ -1,6 +1,8 @@ #shellcheck disable=2148,2154 -function _zsh_256color_debug(){ [[ -n "${ZSH_256COLOR_DEBUG}" ]] && echo "zsh-256color: ${*}" >&2; } +function _zsh_256color_debug(){ + [[ -n "${ZSH_256COLOR_DEBUG}" ]] && echo "zsh-256color: ${*}" >&2 +} function _zsh_terminal_set_256color(){ [[ "${TERM}" =~ "-256color$" ]] && _zsh_256color_debug "256 color terminal already set." && return diff --git a/.shellfishrc b/.shellfishrc new file mode 100755 index 0000000..b41c25a --- /dev/null +++ b/.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=88850f3a88bfd0c1e361efd864763bf78300b5ca867609678fbf830eaab7e832 + local user=ArMDQHmWakfnQMcNPBStmwEj4okqqjjNzycr8X2p + 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=88850f3a88bfd0c1e361efd864763bf78300b5ca867609678fbf830eaab7e832 + local user=ArMDQHmWakfnQMcNPBStmwEj4okqqjjNzycr8X2p + 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" +}