· 8 years ago · Mar 13, 2018, 02:54 AM
1<?xml version="1.0" encoding="iso-8859-1"?>
2<!DOCTYPE muclient>
3
4<muclient>
5<plugin
6 name="MUSHclient_Help"
7 author="Nick Gammon"
8 id="d2fa45d390d935d947cdc169"
9 language="Lua"
10 purpose="Shows the MUSHclient help file"
11 save_state="y"
12 date_written="2011-06-13 08:58:30"
13 date_modified="2011-07-14 08:40:00"
14 requires="4.76"
15 version="1.0"
16 >
17<description trim="y">
18<![CDATA[
19To get general help:
20
21 mchelp <search string>
22 mchelps <search string> --> get help with snippet (context) shown
23
24 mchelp --> on its own, shows this help
25
26Search strings can have boolean operators in them, namely the words:
27
28 AND NEAR NOT OR
29
30These words must be in all capitals or they are just searched for literally.
31
32For example:
33
34 mchelp trigger AND alias
35 mchelp delete AND trigger NEAR count
36 mchelp search NOT table
37 mchelp search -table
38 mchelp add OR delete
39 mchelp next NEAR/5 table
40 mchelp add AND (trigger OR alias)
41
42(The syntax NEAR/5 means if one word is within 5 words of another word, the default is 10)
43
44You can use a wildcard suffix, eg.
45
46 mchelp trigg*
47
48You can look for phrases by putting them in quotes, eg.
49
50 mchelp "hash a string"
51
52You can restrict the lookup to the item name (eg. the function name) like this:
53
54 mchelp name:utils.*
55
56]]>
57</description>
58
59</plugin>
60
61
62<!-- Aliases -->
63
64<aliases>
65 <alias
66 script="help_find"
67 match="^mchelp (.+)$"
68 enabled="y"
69 group="help"
70 regexp="y"
71 sequence="100"
72 >
73 </alias>
74
75 <alias
76 script="help_find_snippet"
77 match="^mchelps (.+)$"
78 enabled="y"
79 group="help"
80 regexp="y"
81 sequence="100"
82 >
83 </alias>
84
85 <alias
86 script="OnHelp"
87 match="^mchelps?$"
88 enabled="y"
89 regexp="y"
90 >
91 </alias>
92
93</aliases>
94
95<!-- Script -->
96
97
98<script>
99<![CDATA[
100
101require "pairsbykeys"
102
103-- major headings
104local HEADINGCOLOUR = "yellow"
105local NAMECOLOUR = "cyan"
106local SUMMARYCOLOUR = "white"
107local PROTOTYPECOLOUR = "cyan"
108local DESCRIPTIONCOLOUR = "white"
109local NOTESCOLOUR = "white"
110local HELPCOLOUR = "indianred"
111
112-- tags (eg. bold, italic)
113local CODECOLOUR = "greenyellow"
114local RETURNVALUE = "thistle"
115local BOLDCOLOUR = "orange"
116local ITALICCOLOUR = "linen"
117
118-- for snippets
119local RESET = ANSI (0)
120local BOLD = ANSI (1)
121local UNBOLD = ANSI (22)
122local SNIPPETSIZE = -15 -- how many tokens to show around snippet
123
124local styles
125
126-- SQL fixup function
127
128local function fixsql (s)
129 -- replace single quotes with two lots of single quotes
130 if s then
131 return "'" .. (string.gsub (s, "'", "''")) .. "'"
132 end -- if string exists
133
134 return "NULL"
135end -- fixsql
136
137-- for fixing up entities
138local entities = {
139 ["<"] = "<";
140 [">"] = ">";
141 ["&"] = "&";
142 ["""] = "\"";
143 } -- end of entities
144
145-- what to do on getting a tag like <b>
146local tag_handlers = {
147 ["<b>"] = function () SetNoteColourFore (ColourNameToRGB (BOLDCOLOUR)) end;
148 ["<i>"] = function () SetNoteColourFore (ColourNameToRGB (ITALICCOLOUR)) end;
149 ["<code>"] = function () SetNoteColourFore (ColourNameToRGB (CODECOLOUR)) end;
150 ["<ul>"] = function () end;
151 ["<li/>"] = function () Tell (" * ") end;
152 ["<hr/>"] = function () NoteHr () end;
153
154 } -- end of tag_handlers
155
156-- called by LPEG to output an opening, closing, or empty tag
157local function tag_output (tag)
158
159 -- restore colour on closing tag, save colour on nested tag
160 if tag:sub (2, 2) == "/" then
161 SetNoteColourFore (table.remove (styles))
162 elseif tag:sub (-2, -2) ~= "/" then
163 table.insert (styles, GetNoteColourFore () )
164 end -- if
165
166 local f = tag_handlers [tag:lower ()]
167 if f then
168 f ()
169 end -- if handler found
170
171end -- tag_output
172
173-- called by LPEG to output straight text
174local function text_output (text)
175 -- fix up entities like <
176 Tell ((text:gsub ("&%a-;", entities)))
177end -- text_output
178
179-- LPEG grammar for (simplified) HTML
180local P, R, S, C, Cc, Ct = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Ct
181local TAG = (P"<" * P"/"^-1 * R("AZ", "az")^1 * P"/"^-1 * P">")/tag_output
182local NOT_TAG = ((1 - lpeg.P"<")^0/text_output)
183local HTML = (NOT_TAG * TAG * NOT_TAG)^1 + NOT_TAG
184
185-- show a help item with a coloured heading, and coloured text
186
187local function show_item (hdg_colour, hdg, text_colour, text, tagged)
188
189 if text and text ~= "" then
190
191 if hdg and hdg ~= "" then
192 ColourNote (hdg_colour, "", hdg)
193 print ""
194 end -- if any heading
195
196 if tagged then
197 local notecolour = GetNoteColourFore ()
198 styles = {} -- nested styles - start off with none
199 SetNoteColourFore (ColourNameToRGB (text_colour))
200 lpeg.match (HTML, text)
201 SetNoteColourFore (notecolour)
202 print "" -- probably doesn't end with newline
203 else
204 ColourNote (text_colour, "", text)
205 end -- if tagged or not
206
207 print ""
208 end -- if any text
209
210end -- show_item
211
212-- normal functions
213local function show_functions_help (row)
214 NoteHr ()
215 show_item (HEADINGCOLOUR, "Function", NAMECOLOUR, row.name)
216 show_item (HEADINGCOLOUR, "Summary", SUMMARYCOLOUR, row.summary)
217 show_item (HEADINGCOLOUR, "Prototype", PROTOTYPECOLOUR, row.prototype)
218 show_item (HEADINGCOLOUR, "Description", DESCRIPTIONCOLOUR, row.description)
219 show_item (HEADINGCOLOUR, "Return Value", RETURNVALUE, row.return_value)
220 show_item (HEADINGCOLOUR, "Lua Example", CODECOLOUR, row.lua_example)
221 show_item (HEADINGCOLOUR, "Lua Notes", NOTESCOLOUR, row.lua_notes)
222end -- show_functions_help
223
224-- general help (major topics)
225local function show_general_help (row)
226 NoteHr ()
227 show_item (NOTESCOLOUR, "", NAMECOLOUR, row.title)
228 show_item (HEADINGCOLOUR, "Summary", SUMMARYCOLOUR, row.description, true) -- HTML codes
229end -- show_general_help
230
231-- lua functions
232local function show_lua_functions_help (row)
233 NoteHr ()
234 show_item (HEADINGCOLOUR, "Lua", NAMECOLOUR, row.name)
235 show_item (HEADINGCOLOUR, "Summary", SUMMARYCOLOUR, row.summary)
236 show_item (HEADINGCOLOUR, "Prototype", PROTOTYPECOLOUR, row.prototype)
237 show_item (HEADINGCOLOUR, "Description", DESCRIPTIONCOLOUR, row.description, true) -- HTML codes
238end -- show_lua_functions_help
239
240
241local hyperlink_handlers = {
242
243 functions = { sql = "SELECT * FROM functions WHERE name = %s",
244 handler = show_functions_help };
245
246 general = { sql = "SELECT * FROM general_doc WHERE doc_name = %s",
247 handler = show_general_help };
248
249 lua_functions = { sql = "SELECT * FROM lua_functions WHERE name = %s",
250 handler = show_lua_functions_help };
251
252 } -- end of hyperlink_handlers
253
254-- here when hyperlink clicked
255
256function do_hyperlink (s)
257 local what, name = string.match (s, "([%a_]+):([%a%d_%. :]+)")
258
259 if not what then return end
260
261 local help = hyperlink_handlers [what]
262
263 if not help then
264 ColourNote ("red", "", "Handler not found for " .. what)
265 return
266 end -- if not found
267
268 -- should only find one match here ...
269 for row in db:nrows(string.format (help.sql, fixsql (name))) do
270 help.handler (row)
271 end -- finding function
272
273end -- do_hyperlink
274
275function general_help (search_string, want_snippet)
276
277 local searchfor = fixsql (search_string)
278
279 AnsiNote (RESET)
280
281 if not db then
282 ColourNote ("red", "", "MUSHclient help database 'help.db' not found.")
283 return
284 end -- if
285
286 local count = 0
287 local functions = {}
288 local general = {}
289 local lua_functions = {}
290
291 function show_snippet (what, name, title, extra, snippet)
292 Tell " "
293 Hyperlink ("!!" .. GetPluginID () .. ":do_hyperlink(" .. what .. ":" .. name .. ")",
294 title, "Click for help on " .. title, "cyan", "", false)
295 if extra ~= "" then
296 Tell (" - ", extra)
297 end -- if
298 print ""
299
300 -- show snippet
301
302 if want_snippet then
303 -- get rid of newlines, and multiple spaces
304 AnsiNote (RESET .. string.gsub (snippet, "%s+", " "))
305 print ""
306 end -- if snippet wanted
307
308 end -- show_snippet
309
310 NoteHr ()
311
312 -- GENERAL documentation
313
314 -- find matching items using FTS
315 for row in db:nrows(string.format (
316 [[
317 SELECT name, summary, snippet(general_doc_lookup, '%s', '%s', ' ... ', -1, %i) AS snippet
318 FROM general_doc_lookup
319 WHERE general_doc_lookup MATCH %s]],
320 BOLD, UNBOLD, SNIPPETSIZE,
321 searchfor)) do
322 general [row.name] = { snippet = row.snippet, summary = row.summary }
323 count = count + 1
324 end -- finding item
325
326 if next (general) then
327 ColourNote (HEADINGCOLOUR, "", "Topics")
328 for k, v in pairsByKeys (general) do
329 show_snippet ("general", k, v.summary, "", v.snippet)
330 end -- for
331 end -- if
332
333 -- FUNCTIONS documentation
334
335 -- find matching items using FTS
336 for row in db:nrows(string.format (
337 [[
338 SELECT name, summary, snippet(functions_lookup, '%s', '%s', ' ... ', -1, %i) AS snippet
339 FROM functions_lookup
340 WHERE functions_lookup MATCH %s]],
341 BOLD, UNBOLD, SNIPPETSIZE,
342 searchfor)) do
343 functions [row.name] = { snippet = row.snippet, summary = row.summary }
344 count = count + 1
345 end -- finding item
346
347 if next (functions) then
348 ColourNote (HEADINGCOLOUR, "", "Functions")
349 for k, v in pairsByKeys (functions) do
350 show_snippet ("functions", k, k, v.summary, v.snippet)
351 end -- for
352 end -- if
353
354 -- LUA FUNCTIONS documentation
355
356 -- find matching items using FTS
357 for row in db:nrows(string.format (
358 [[
359 SELECT name, summary, snippet(lua_functions_lookup, '%s', '%s', ' ... ', -1, %i) AS snippet
360 FROM lua_functions_lookup
361 WHERE lua_functions_lookup MATCH %s]],
362 BOLD, UNBOLD, SNIPPETSIZE,
363 searchfor)) do
364 lua_functions [row.name] = { snippet = row.snippet, summary = row.summary }
365 count = count + 1
366 end -- finding item
367
368 if next (lua_functions) then
369 ColourNote (HEADINGCOLOUR, "", "Lua")
370 for k, v in pairsByKeys (lua_functions) do
371 show_snippet ("lua_functions", k, k, v.summary, v.snippet)
372 end -- for
373 end -- if
374
375 if count == 0 then
376 print ("Nothing found for:", search_string)
377 end -- if
378
379end -- general_help
380
381-- here when they want to search the help
382
383function help_find (name, line, wildcards)
384 general_help (wildcards [1], false)
385end -- help_find
386
387function help_find_snippet (name, line, wildcards)
388 general_help (wildcards [1], true)
389end -- help_find_snippet
390
391local function fix_description (s)
392 if not s then
393 return ""
394 end -- if
395
396 -- get rid of tags
397 s = s:gsub ("</?%a+/?>", "")
398
399 -- convert entities ...
400 s = s:gsub ("&%a-;", entities)
401
402 return s
403end -- fix_description
404
405function OnPluginInstall ()
406 -- open database on disk
407
408 if not db then
409 db = assert (sqlite3.open(GetInfo (66) .. "help.db"))
410 end -- if
411
412 local commands = false
413
414 -- see if commands table exists
415 for row in db:nrows("SELECT * FROM sqlite_master WHERE type = 'table' AND name = 'commands'") do
416 commands = true
417 end
418
419 if not commands then
420 ColourNote ("red", "", "MUSHclient help database 'help.db' not found.")
421 db:close ()
422 db = nil
423 return
424 end -- if
425
426 local fts4 = false
427
428 -- see if fts4 tables exist
429 for row in db:nrows("SELECT * FROM sqlite_master WHERE type = 'table' AND name = 'commands_lookup'") do
430 fts4 = true
431 end
432
433 -- if no fts4 tables, make them
434 if not fts4 then
435 local start = utils.timer ()
436 ColourNote ("cyan", "", "Creating help database full-text lookup tables ...")
437
438 -- START
439 assert (db:execute [[
440 BEGIN TRANSACTION;
441 DROP TABLE IF EXISTS commands_lookup;
442 DROP TABLE IF EXISTS dialogs_lookup;
443 DROP TABLE IF EXISTS functions_lookup;
444 DROP TABLE IF EXISTS general_doc_lookup;
445 DROP TABLE IF EXISTS errors_lookup;
446 DROP TABLE IF EXISTS lua_functions_lookup;
447 ]])
448
449 -- COMMANDS
450 assert (db:execute "CREATE VIRTUAL TABLE commands_lookup USING FTS4(name, summary, description)")
451
452 -- fix up HTML stuff
453 for row in db:nrows("SELECT command_name, short_description, description FROM commands") do
454 assert (db:execute (string.format ([[
455 INSERT INTO commands_lookup (name, summary, description)
456 VALUES (%s, %s, %s)]],
457 fixsql (row.command_name),
458 fixsql (row.short_description),
459 fixsql (fix_description (row.description)))))
460 end -- for
461
462 -- DIALOGS
463 assert (db:execute "CREATE VIRTUAL TABLE dialogs_lookup USING FTS4(name, summary, description)")
464
465 -- fix up HTML stuff
466 for row in db:nrows("SELECT dialog_name, title, description FROM dialogs") do
467 assert (db:execute (string.format ([[
468 INSERT INTO dialogs_lookup (name, summary, description)
469 VALUES (%s, %s, %s)]],
470 fixsql (row.dialog_name),
471 fixsql (row.title),
472 fixsql (fix_description (row.description)))))
473 end -- for
474
475 -- WORLD FUNCTIONS
476 assert (db:execute "CREATE VIRTUAL TABLE functions_lookup USING FTS4(name, summary, description, lua_example, lua_notes)")
477 assert (db:execute [[INSERT INTO functions_lookup (name, summary, description, lua_example, lua_notes)
478 SELECT name, summary, description, lua_example, lua_notes FROM functions]])
479
480 -- GENERAL TOPICS
481 assert (db:execute "CREATE VIRTUAL TABLE general_doc_lookup USING FTS4(name, summary, description)")
482
483 -- fix up HTML stuff
484 for row in db:nrows("SELECT doc_name, title, description FROM general_doc") do
485 assert (db:execute (string.format ([[
486 INSERT INTO general_doc_lookup (name, summary, description)
487 VALUES (%s, %s, %s)]],
488 fixsql (row.doc_name),
489 fixsql (row.title),
490 fixsql (fix_description (row.description)))))
491 end -- for
492
493 -- ERRORS
494 assert (db:execute "CREATE VIRTUAL TABLE errors_lookup USING FTS4(name, error_code, description)")
495 assert (db:execute [[INSERT INTO errors_lookup (name, error_code, description)
496 SELECT error_name, error_code, meaning FROM errors ]])
497
498 -- LUA FUNCTIONS
499 assert (db:execute "CREATE VIRTUAL TABLE lua_functions_lookup USING FTS4(name, summary, description)")
500
501 -- fix up HTML stuff
502 for row in db:nrows("SELECT name, summary, description FROM lua_functions") do
503 assert (db:execute (string.format ([[
504 INSERT INTO lua_functions_lookup (name, summary, description)
505 VALUES (%s, %s, %s)]],
506 fixsql (row.name),
507 fixsql (row.summary),
508 fixsql (fix_description (row.description)))))
509 end -- for
510
511 -- DONE
512 assert (db:execute "COMMIT;")
513 ColourNote ("cyan", "", string.format ("Done. Took %0.3f seconds.", utils.timer () - start))
514
515 end -- if
516
517end -- OnPluginInstall
518
519function OnHelp ()
520 NoteHr ()
521 ColourNote (HELPCOLOUR, "", world.GetPluginInfo (world.GetPluginID (), 3))
522end
523
524]]>
525</script>
526
527</muclient>