summary refs log tree commit diff
path: root/bin/libfuzl.sh
blob: c53a71fef3557491694fe97cb52b2dadae351413 (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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/bin/bash
# local is well supported
# shellcheck disable=3043

set -eu

# TODO: use custom-1 somehow

# pick up configuration
FUZL_PROMPT=${FUZL_PROMPT:-fuzl}
FUZL_ICON=${FUZL_ICON:-󰈲}
FUZL_CLI_ARGS=${FUZL_CLI_ARGS:-$@}

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_reset() {
	# reset actions
	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_help() {
	echo "usage: $FUZL_PROMPT [action]"
	echo
	for action in "${FUZL_ACTIONS[@]}"; do
		echo -e "       $action"
	done
	echo
	exit 0
}

fuzl_action_menu() {
	local action

	# only actually ask if action wasn't provided on cli
	action=${FUZL_CLI_ARGS}
	if [[ "$action" == "--help" ]]; then
		fuzl_action_help
	fi
	if test -z "$action"; then
		action=$(printf '%s\n' "${FUZL_ACTIONS[@]}" |
			FUZL_PROMPT="$FUZL_PROMPT: $*" fuzl_menu $FUZL_MENU_FILTER --with-nth='{2}  {3..}' --accept-nth=1)
	fi

	fuzl_action_reset

	if declare -f "${FUZL_PROMPT}_${action}" >/dev/null; then
		eval "${FUZL_PROMPT}_${action}" "'$*'"
	else
		return 1
	fi
}

# setup common debug helper
[ -z "${DEBUG:-}" ] || set -x