forked from thehunmonkgroup/jester
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhelp.lua
More file actions
343 lines (324 loc) · 10.2 KB
/
help.lua
File metadata and controls
343 lines (324 loc) · 10.2 KB
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
module(..., package.seeall)
jester.conf.debug = false
require "jester.support.string"
require "jester.support.table"
-- The CLI version assumes it's being run from the FreeSWITCH scripts
-- directory, but when run from FreeSWITCH the full path must be specified.
local script_path = "./"
if jester.is_freeswitch then
script_path = jester.conf.scripts_dir .. "/"
end
--[[
Initialize the help system.
]]
function init_module_help()
local help_file
-- Create a map of all module help that can be called.
jester.help_map = {}
for _, mod in ipairs(jester.conf.modules) do
help_file = "jester.modules." .. mod .. ".help"
if require(help_file) then
jester.debug_log("Loaded module help '%s'", help_file)
else
jester.debug_log("Failed loading module help '%s'!", help_file)
end
end
end
--[[
Get help for the passed subtopics.
]]
function get_help(...)
local output = ""
local help_path, output
local arguments = {...}
local arg_string = table.concat(arguments, " ")
-- Check for special topics first.
if arguments[1] == "modules" or arguments[1] == "module" or arguments[1] == "actions" or arguments[1] == "action" then
init_module_help()
local help_type = "action"
-- Module help.
if arguments[1] == "modules" or arguments[1] == "module" then
help_type = "module"
if arguments[2] then
output = module_help_detail(arguments[2])
else
output = module_help()
end
-- Action help.
else
if arguments[2] then
output = action_help_detail(arguments[2])
else
output = action_help()
end
end
-- Module and action details might return nothing if the arguments were
-- bad, catch that here.
if not output then
output = string.format("No %s help available for '%s'", help_type, arg_string)
end
-- General topic help.
else
-- Initialize the map.
jester.help_map = {}
-- Load all general topics.
require "lfs"
local error_message = {}
local path = script_path .. jester.conf.help_path
local file_list = {}
for file in lfs.dir(path) do
-- Exclude directory references and hidden files.
if not string.match(file, "^%..*") then
table.insert(file_list, file)
end
end
-- Since help files are nested tables, we want to enforce an alphabetical
-- loading order so that help topics nested more deeply can be loaded
-- after higher topics.
table.sort(file_list)
local f, e
for _, file in ipairs(file_list) do
f, e = loadfile(path .. "/" .. file)
if f then
jester.debug_log("Loaded help file '%s'", file)
f()
else
table.insert(error_message, e)
end
end
if #error_message == 0 then
-- Navigate into the help tree, and see if the requested subtopic is
-- available.
help_path = jester.help_map
if #arguments > 0 then
for a = 1, #arguments do
help_path = help_path[arguments[a]]
if not help_path then break end
end
end
-- No subtopics passed, start at main help.
if #arguments == 0 then
output = topic_help(jester.help_map, true)
-- Subtopic help found.
elseif help_path then
output = topic_help(help_path)
-- Help subtopic not found.
else
output = string.format("No help available for '%s'", arg_string)
end
else
output = string.format("Error loading help files: %s", table.concat(error_message, "; "))
end
end
help_output(output)
end
--[[
Output help to the appropriate location.
]]
function help_output(help)
if jester.is_freeswitch then
stream:write("\n" .. tostring(help) .. "\n")
else
print("\n" .. help .. "\n")
end
end
--[[
Build topical help.
]]
function topic_help(topic, main)
local output = {}
local description
-- Main help page must be caught and generated specially.
if main then
description = welcome()
else
description = topic.description_long or topic.description_short
end
if description then
table.insert(output, description:wrap(79))
end
-- Grab subtopics for the topic requested.
local subtopics = {}
for _, sub in ipairs(table.orderkeys(topic)) do
if type(topic[sub]) == "table" then
table.insert(subtopics, sub .. ":")
if topic[sub].description_short then
description = topic[sub].description_short:wrap(79, " ")
else
description = ""
end
table.insert(subtopics, description)
end
end
if #subtopics > 0 then
subtopic_list = string.format("SUBTOPICS:\n\n%s", table.concat(subtopics, "\n"))
table.insert(output, subtopic_list)
end
return table.concat(output, "\n\n")
end
--[[
Main help page text.
]]
function welcome()
return [[Welcome to Jester help!
Here you'll find extensive information on all the important areas of Jester. Start by reviewing the topic list below for an area of interest. The general format for accessing help is 'help [sub-topic] [sub-sub-topic] [...]', and this is how you'll see it referenced internally.]]
end
--[[
Get a list of all modules in the help system.
]]
function get_modules()
local module_list = {}
for _, module_name in ipairs(table.ordervalues(jester.conf.modules)) do
module_list[module_name] = jester.help_map[module_name]
end
return module_list
end
--[[
Build summary help for all modules.
]]
function module_help()
local module_list = {}
local help, description
-- Build an alphabetical summary of all modules enabled in the global config.
for _, name in ipairs(table.ordervalues(jester.conf.modules)) do
help = jester.help_map[name]
table.insert(module_list, name .. ":")
if help.description_short then
description = help.description_short:wrap(79, " ")
else
description = ""
end
table.insert(module_list, description)
end
return string.format("Run 'help module [name]' to get more help on a specific module.\n\nCurrently installed modules:\n\n%s", table.concat(module_list, "\n"))
end
--[[
Build detailed help for a module.
]]
function module_help_detail(module_name)
local description, actions
-- Loop through all modules looking for the passed one.
for name_to_check, data in pairs(jester.help_map) do
if name_to_check == module_name then
if data.description_long then
description = data.description_long:wrap(79)
elseif data.description_short then
description = data.description_short:wrap(79)
end
break
end
end
-- Found the module.
if description then
local list = {}
module_data = jester.help_map[module_name]
action_data = jester.help_map[module_name].actions
table.insert(list, description)
-- Found actions for the module.
if action_data then
table.insert(list, "\nACTIONS:")
-- Build an ordered list of actions.
for _, action in ipairs(table.orderkeys(action_data)) do
table.insert(list, " " .. action .. ":")
if action_data[action].description_short then
description = action_data[action].description_short:wrap(79, " ")
else
description = ""
end
table.insert(list, description)
end
end
-- Display all handlers for the module.
if module_data.handlers then
list = build_handlers(module_data, list)
end
return table.concat(list, "\n")
end
end
--[[
Build handler help.
]]
function build_handlers(module_data, list)
local handlers = module_data.handlers
table.insert(list, "\nHANDLERS:")
for _, handler in ipairs(table.orderkeys(handlers)) do
table.insert(list, " " .. handler .. ":")
table.insert(list, handlers[handler]:wrap(79, " "))
end
return list
end
--[[
Get a list of all actions in the help system.
]]
function get_actions()
local action_list = {}
local actions
for _, module_name in ipairs(table.ordervalues(jester.conf.modules)) do
actions = jester.help_map[module_name].actions
for action, data in pairs(actions) do
action_list[action] = data
end
end
return action_list
end
--[[
Build summary help for all actions.
]]
function action_help()
local action_list = {}
local actions, description
-- Loop through an alphabetically ordered list of modules.
for _, module_name in ipairs(table.ordervalues(jester.conf.modules)) do
actions = jester.help_map[module_name].actions
table.insert(action_list, "\nModule: " .. module_name)
-- Build and alphabetical list of actions for the module.
for _, action in ipairs(table.orderkeys(actions)) do
table.insert(action_list, " " .. action .. ":")
if actions[action].description_short then
description = actions[action].description_short:wrap(79, " ")
else
description = ""
end
table.insert(action_list, description)
end
end
return string.format("Run 'help action [name]' to get more help on a specific action.\n\nCurrently installed actions:\n%s", table.concat(action_list, "\n"))
end
--[[
Build detailed help for an action.
]]
function action_help_detail(action)
-- Loop through the modules looking for the passed action.
for _, module_data in pairs(jester.help_map) do
for action_to_check, action_data in pairs(module_data.actions) do
-- Found the action.
if action_to_check == action then
local list = {}
local description
if action_data.description_long then
description = action_data.description_long:wrap(79)
elseif action_data.description_short then
description = action_data.description_short:wrap(79)
else
description = ""
end
table.insert(list, description)
-- Look for parameters for the action.
local params = action_data.params
if params then
table.insert(list, "\nPARAMETERS:")
-- Build an ordered list of parameters.
for _, param in ipairs(table.orderkeys(params)) do
table.insert(list, " " .. param .. ":")
table.insert(list, params[param]:wrap(79, " "))
end
end
-- Display available handlers for the action.
if module_data.handlers then
list = build_handlers(module_data, list)
end
return table.concat(list, "\n")
end
end
end
end