-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmenugenbase
executable file
·385 lines (350 loc) · 9.39 KB
/
menugenbase
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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
#!/usr/bin/env bash
# Internal values
declare -ga PREVMENU=("")
declare -ga PREVNAME=("")
CURRENTMENU="main" # Keeps track of the current menu
HASH="" # MD5 hash of current menu text for searching MENU data structures
SCRIPTNAME="$1"
# Special vars defined for each menu
declare -ga ITEMID
declare -gA ITEMNAME
declare -gA ITEMTYPE
declare -gA ITEMLINK
declare -gA ITEMACTION
name=""
prompt=""
numbered=true
autoselect=false
back=true
default_link=""
default_exec=""
# A simple wrapper to echo to stderr
function echoerr() {
echo "$@" 1>&2
}
# Test to see if a rendering function is provided
declare -f -F RENDERMENU >/dev/null
if [[ $? -eq 1 ]]; then
echoerr "ERROR: menumaker-base cannot be run by itself."
echoerr " It must be provided a RENDERMENU function to work."
echoerr " Check menumaker and menumaker-cli for examples."
exit -1
fi
# Function which creates a menu ITEM
# $1 - ITEM name
# $2 - Link location
# $3 - Action to perform on follow
function create_item() {
HASH=$(echo "$1" | md5sum | cut -d' ' -f 1)
# Check parameters
if [[ "$#" -ne 3 ]]; then
echoerr "ERROR: add_item requires 3 arguments (got $#)"
echoerr " - The name of the ITEM (value: \"$1\")"
echoerr " - The link location to the next menu (value: \"$2\")"
echoerr " - The action the ITEM will exec (value: \"$3\")"
exit -1
fi
# Name CANNOT be blank
if [[ "$1" == "" ]]; then
echoerr "ERROR: ITEM name must not be blank!"
exit -1
fi
# One of link or action MUST NOT be blank
if [[ "$1" == "" && "$2" == "" ]]; then
echoerr "ERROR: The ITEM must have either a link or an action"
exit -1
fi
ITEMNAME["$HASH"]="$1"
ITEMTYPE["$HASH"]="item"
ITEMLINK["$HASH"]="$2"
ITEMACTION["$HASH"]="$3"
}
# Function which adds ITEMs to the end of the menu
# $1 - ITEM name
# $2 - Link location
# $3 - Action to perform on follow
function add_item() {
create_item "$1" "$2" "$3"
ITEMID+=("$HASH")
}
# Function which adds ITEMs to the beginning of the menu
# $1 - ITEM name
# $2 - Link location
# $3 - Action to perform on follow
function cons_item() {
create_item "$1" "$2" "$3"
ITEMID=("$HASH" "${ITEMID[@]}")
}
# Function which creates a menu link
# $1 - link name
# $2 - Link location
function create_link() {
HASH=$(echo "$1" | md5sum | cut -d' ' -f 1)
# Check parameters
if [[ "$#" -ne 2 ]]; then
echoerr "ERROR: add_item requires 2 arguments (got $#)"
echoerr " - The name of the ITEM (value: \"$1\")"
echoerr " - The link location to the next menu (value: \"$2\")"
exit -1
fi
# Name and the link CANNOT be blank
if [[ "$1" == "" || "$2" == "" ]]; then
echoerr "ERROR: Neither the name nor the link can be blank!"
echoerr " - Provided name: \"$1\""
echoerr " - Provided link: \"$2\""
exit -1
fi
ITEMNAME["$HASH"]="$1"
ITEMTYPE["$HASH"]="item"
ITEMLINK["$HASH"]="$2"
ITEMACTION["$HASH"]=""
}
# Function which adds a link to the end of the menu
# $1 - link name
# $2 - Link location
function add_link() {
create_link "$1" "$2"
ITEMID+=("$HASH")
}
# Function which adds links to the beginning of the menu
# $1 - link name
# $2 - Link location
function cons_link() {
create_link "$1" "$2"
ITEMID=("$HASH" "${ITEMID[@]}")
}
# Function which creates a menu action
# $1 - link name
# $2 - Action to exec
function create_exec() {
HASH=$(echo "$1" | md5sum | cut -d' ' -f 1)
# Check parameters
if [[ "$#" -ne 2 ]]; then
echoerr "ERROR: add_item requires 2 arguments (got $#)"
echoerr " - The name of the ITEM (value: \"$1\")"
echoerr " - The action to exec (value: \"$2\")"
exit -1
fi
# Neither the name or the action can be blank
if [[ "$1" == "" || "$2" == "" ]]; then
echoerr "ERROR: Neither the name nor the link can be blank!"
echoerr " - Provided name: \"$1\""
echoerr " - Provided action: \"$2\""
exit -1
fi
ITEMNAME["$HASH"]="$1"
ITEMTYPE["$HASH"]="item"
ITEMLINK["$HASH"]=""
ITEMACTION["$HASH"]="$2"
}
# Function which adds actions to the end of the menu
# $1 - link name
# $2 - Action to exec
function add_exec() {
create_exec "$1" "$2"
ITEMID+=("$HASH")
}
# Function which adds actions to the beginning of the menu
# $1 - link name
# $2 - Action to exec
function cons_exec() {
create_exec "$1" "$2"
ITEMID=("$HASH" "${ITEMID[@]}")
}
# Function which adds BACK to the menu using menumaker's internal data structures
function create_back() {
local item_text=""
# No args provided, auto generate back item
if [[ "$#" -eq 0 ]]; then
if [[ "${PREVMENU[-1]}" == "" ]]; then
item_text="< Exit"
else
item_text="< Back to ${PREVNAME[-1]}"
fi
fi
HASH=$(echo "$item_text" | md5sum | cut -d' ' -f 1)
ITEMNAME["$HASH"]="$item_text"
ITEMTYPE["$HASH"]="back"
ITEMLINK["$HASH"]="${PREVMENU[-1]}"
}
# Function which adds back to the end of the menu
function add_back() {
create_back
ITEMID+=("$HASH")
}
# Function which adds BACK to the beginning of the menu
function cons_back() {
create_back
ITEMID=("$HASH" "${ITEMID[@]}")
}
# Function which adds NOPs to the menu
# $1 - nop text
# TODO: maybe add the ability to make NOPs run commands
function create_nop() {
if [[ "$#" -ne 1 ]]; then
echoerr "ERROR: add_nop requires the item text"
exit -1
fi
HASH=$(echo "$1" | md5sum | cut -d' ' -f 1)
ITEMNAME["$HASH"]="$1"
ITEMTYPE["$HASH"]="nop"
}
# Function which adds NOPs to the menu
# $1 - nop text
function add_nop() {
create_nop "$1"
ITEMID+=("$HASH")
}
# Function which adds NOPs to the menu
# $1 - nop text
function cons_nop() {
create_nop "$1"
ITEMID=("$HASH" "${ITEMID[@]}")
}
# Fucntion to test if the menu $1 is defined in the menu script
# Returns 0 if it exists, and -1 if it doesn't if isn't valid
# TODO: test if begin comes before end, whether begin pattern exists, and verify there is only one of each begin and end statement in the menuscript
function testForMenu() {
menu="$1"
# Test to make sure an end pattern exists, sed will just keep on chomping till the EOF otherwise
grep "#end $menu" $SCRIPTNAME > /dev/null
if [[ $? -ne 0 ]]; then
echoerr "ERROR: Menu $menu is missing #end statement"
return -1
fi
# See if a block exists
ret=$(sed -n "/#begin $menu/,/#end $menu/p" $SCRIPTNAME | wc -l)
if [[ $ret -eq 0 ]]; then
echoerr "ERROR: Menu $menu doesn't exist"
return -1
fi
}
# Function to reset all the values to their defaults to keep the menu system working cleanly
function resetAllToDefault() {
unset ITEMID
unset ITEMNAME
unset ITEMTYPE
unset ITEMLINK
unset ITEMACTION
declare -ga ITEMID
declare -gA ITEMNAME
declare -gA ITEMTYPE
declare -gA ITEMLINK
declare -gA ITEMACTION
HASH=""
name=""
prompt=""
numbered=true
autoselect=false
back=true
default_link=""
default_exec=""
}
# Function to reset all the values to their defaults to keep the menu system working cleanly
function resetVarsToDefault() {
HASH=""
name=""
prompt=""
numbered=true
autoselect=false
back=true
default_link=""
default_exec=""
}
##
## MAIN PROGRAM
##
# Test the $1 script is provided
if [[ "$#" -lt 1 ]]; then
echoerr "ERROR: menumaker requires a menumaker script as it's parameter"
exit -1
fi
if [ ! -e "$SCRIPTNAME" ]; then
echoerr "ERROR: The script \"$SCRIPTNAME\" does not exist"
exit -1
fi
# Load the setup block to initialize the state
# Don't print errors if we don't need to
testForMenu "setup" 2>/dev/null
if [[ "$?" -eq 0 ]]; then
source <(sed -n "/#begin setup/,/#end setup/p" $SCRIPTNAME)
fi
while [ "$CURRENTMENU" != "" ]; do
ROFIMENU=""
resetAllToDefault
# Load current menu - abort the program if we can't find it
testForMenu $CURRENTMENU
if [[ "$?" -ne 0 ]]; then
exit -1
fi
source <(sed -n "/#begin $CURRENTMENU/,/#end $CURRENTMENU/p" $SCRIPTNAME)
# Add autogenerated back if necessary
if [[ "$back" == true ]]; then
cons_nop "---"
cons_back
fi
# Generate a prompt if one does not exist
if [[ "$prompt" == "" ]]; then
prompt="$name > "
fi
# Convert menu items to string to render in rofi
num=1
for key in "${ITEMID[@]}"; do
item="${ITEMNAME[$key]}"
if [[ "${ITEMTYPE[$key]}" == item ]]; then
if [[ $numbered == true ]]; then
ROFIMENU+="$num $item\n"
((num++))
else
ROFIMENU+="$item\n"
fi
else
ROFIMENU+="$item\n"
fi
done
# Run the specified selector! (Make sure to strip the trailing newline)
result=$(RENDERMENU "$(printf "$ROFIMENU")" "$prompt" "$autoselect")
# If nothing was returned, the user quit
if [[ "$result" == "" ]]; then
break
else
# Otherwise, remove the number if added
if [[ $numbered == true ]]; then
SELECTION=$(echo $result | sed -r 's/^[0-9]+ //g')
else
SELECTION=$result
fi
# Calculate the lookup key
key=$(echo "$SELECTION" | md5sum | cut -d' ' -f 1)
# Then lookup our next action
if [[ "${ITEMTYPE["$key"]}" == "nop" ]]; then
continue
elif [[ "${ITEMTYPE["$key"]}" == "item" ]]; then
if [[ "$back" == true ]]; then
PREVMENU+=("$CURRENTMENU")
PREVNAME+=("$name")
fi
# If the item has an action, run it
if [[ "${ITEMACTION["$key"]}" != "" ]]; then
eval "${ITEMACTION["$key"]}"
fi
CURRENTMENU=${ITEMLINK["$key"]}
elif [[ "${ITEMTYPE["$key"]}" == "back" ]]; then
CURRENTMENU=${PREVMENU[-1]}
unset PREVMENU[${#PREVMENU[@]}-1]
unset PREVNAME[${#PREVNAME[@]}-1]
else
if [[ "$SELECTION" != "" ]]; then
# Custom command was input
# Set up the next menu (if it's not set, i.e. empty, MM will exit)
CURRENTMENU="$default_link"
# Run the appropriate action
if [[ "$default_exec" != "" ]]; then
eval "$default_exec"
fi
else
echoerr "ERROR: Invalid ITEM type"
fi
fi
fi
done