From b61b58ce2c1371d6f904f108fa7feed3abfbe5c7 Mon Sep 17 00:00:00 2001 From: Robert Günzler Date: Wed, 8 Apr 2026 13:18:14 +0900 Subject: * MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Automated-commit-by: dots Signed-off-by: Robert Günzler --- bin/libfuzl.sh | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 bin/libfuzl.sh (limited to 'bin/libfuzl.sh') diff --git a/bin/libfuzl.sh b/bin/libfuzl.sh new file mode 100644 index 0000000..a28c861 --- /dev/null +++ b/bin/libfuzl.sh @@ -0,0 +1,114 @@ +#!/bin/bash +# local is well supported +# shellcheck disable=3043 + +set -eu + +# pick up configuration +FUZL_PROMPT=${FUZL_PROMPT:-fuzl} +FUZL_ICON=${FUZL_ICON:-󰈲} + +fuzl_try() { + [ "$1" == "--" ] && shift 1 + if ! { stderr=$( + set +x + eval "$*" 2>&1 1>&3 + ); } 3>&1; then + fuzl_notification "$* failed :(" "${stderr:--}" -c error + exit 1 + fi +} + +export FUZL_MENU_FILTER=filter +export FUZL_MENU_PASSWORD=passw +export FUZL_MENU_MESSAGE=msg +export FUZL_MENU_INPUT=input + +# Shows a menu +fuzl_menu() { + local form="$1" + shift 1 + + local prompt options_list maxw + + # If a prompt_icon is provided, prepend it. + prompt="$FUZL_PROMPT " + [ -n "$FUZL_ICON" ] && prompt="$FUZL_ICON $FUZL_PROMPT " + + options_list=$(cat) + maxw=$(echo -e "$prompt\n$options_list" | wc -L) + [ "$maxw" -lt 15 ] && maxw=15 + [ "$maxw" -gt 150 ] && maxw=100 + + case "$form" in + "$FUZL_MENU_FILTER") # Selection menu with a list of options passed via STDIN + echo -ne "$options_list" | fuzzel -d -w "$maxw" -p "$prompt" "$@" + ;; + "$FUZL_MENU_PASSWORD") # Password input menu (minimalist) + echo -n | fuzzel -d -w "$maxw" -p "$prompt" --password + ;; + "$FUZL_MENU_MESSAGE") # Message box menu (no input bar) + echo -ne "$options_list" | fuzzel -d -w "$maxw" -p "$prompt" "$@" + ;; + "$FUZL_MENU_INPUT") # Text input menu (no list view) + echo -n | fuzzel -d -p "$prompt" "$@" --lines 0 + ;; + esac +} + +FUZL_NOTIFICATION_ID= + +fuzl_notification() { + local summary="${1:?missing summary}" + local body="${2:?missing body}" + shift 2 + + FUZL_NOTIFICATION_ID=$( + fyi "$@" -p -a "${FUZL_PROMPT}" "${FUZL_PROMPT}: $summary" "$body" | + cut -d= -f2 + ) +} +fuzl_notification_cancel() { + fyi --close "$FUZL_NOTIFICATION_ID" || true + FUZL_NOTIFICATION_ID= +} + +FUZL_LOADING_PID= + +fuzl_loading() { + local summary="${1:?missing summary}" + echo -e "..." | FUZL_PROMPT="$summary" fuzl_menu $FUZL_MENU_MESSAGE & + FUZL_LOADING_PID=$! +} +fuzl_loading_cancel() { + local pgid + pgid="$(ps -o pgid= "$FUZL_LOADING_PID" || return)" + kill -- -"$pgid" || true + FUZL_LOADING_PID= +} + +FUZL_ACTIONS=() + +fuzl_action_add() { + local action="${1:?}" icon="${2:?}" + shift 2 + # prevent multiple occurences + printf '%s\n' "${FUZL_ACTIONS[@]}" | grep -q "^$action" && return + FUZL_ACTIONS+=("${action}\t${icon}\t${*}") +} + +fuzl_action_menu() { + local action + + action=$(printf '%s\n' "${FUZL_ACTIONS[@]}" | + FUZL_PROMPT="$FUZL_PROMPT: $*" fuzl_menu $FUZL_MENU_FILTER --with-nth='{2} {3..}' --accept-nth=1) + + # reset actions + FUZL_ACTIONS=() + + test -n "$action" || return + eval "${FUZL_PROMPT}_${action}" "'$*'" +} + +# setup common debug helper +[ -z "${DEBUG:-}" ] || set -x -- cgit 1.4.1