summary refs log tree commit diff
path: root/bin/libfuzl.sh
blob: a28c861f5fa4eedce567f0d9cb64bff0bf8d8181 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
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