1if not modules then modules = { } end modules ['mtx-server-ctx-help'] = {
2 version = 1.001,
3 comment = "Basic Definition Browser",
4 author = "Hans Hagen",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9local gsub, find, lower, match = string.gsub, string.find, string.lower, string.match
10local concat, sort = table.concat, table.sort
11
12dofile(resolvers.findfile("trac-lmx.lua","tex"))
13dofile(resolvers.findfile("util-sci.lua","tex"))
14dofile(resolvers.findfile("char-def.lua","tex"))
15dofile(resolvers.findfile("char-ini.lua","tex"))
16dofile(resolvers.findfile("char-utf.lua","tex"))
17
18local scite = utilities.scite
19local formatters = string.formatters
20local sortedkeys = table.sortedkeys
21local setmetatableindex = table.setmetatableindex
22local lowercase = characters.lower
23local uppercase = characters.upper
24local interfaces = dofile(resolvers.findfile("mult-def.lua","tex"))
25local i_setupstrings = interfaces.setupstrings
26local i_commands = interfaces.commands
27local i_variables = interfaces.variables
28local i_constants = interfaces.constants
29local i_elements = interfaces.elements
30local report = logs.reporter("ctx-help")
31local gettime = os.gettimeofday or os.clock
32
33local xmlcollected = xml.collected
34local xmlfirst = xml.first
35local xmltext = xml.text
36local xmlload = xml.load
37
38document = document or { }
39document.setups = document.setups or { }
40
41local usedsetupfile = resolvers.findfile("i-context.xml") or ""
42local usedsetuproot = usedsetupfile ~= "" and xmlload(usedsetupfile) or false
43local useddefinitions = { }
44
45if usedsetuproot then
46 report("main file loaded: %s",usedsetupfile)
47 xml.include(usedsetuproot,"cd:interfacefile","filename",true,function(s)
48 local fullname = resolvers.findfile(s)
49 if fullname and fullname ~= "" then
50 report("inclusion loaded: %s",fullname)
51 return io.loaddata(fullname)
52 end
53 end)
54else
55 report("no main file")
56 return false, false
57end
58
59local defaultinterface = "en"
60
61
62
63for e in xmlcollected(usedsetuproot,"cd:define") do
64 useddefinitions[e.at.name] = e
65end
66
67for e in xml.collected(usedsetuproot,"cd:interface/cd:interface") do
68 e.at.file = e.__f__
69end
70
71local f_divs_t = {
72 pe = formatters["<div dir='rtl' lang='arabic'>%s</div>"],
73}
74
75local f_spans_t = {
76 pe = formatters["<span dir='rtl' lang='arabic'>%s</span>"]
77}
78
79local f_href_in_list_t = {
80 tex = formatters["<a class='setupmenuurl' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s'>%s</a>"],
81 lua = formatters["<a class='setupmenuurl' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s'>%s</a>"],
82}
83
84local f_href_in_list_i = {
85 tex = formatters["<a class='setupmenucmd' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s' id='#current'>%s</a>"],
86 lua = formatters["<a class='setupmenucmd' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s' id='#current'>%s</a>"],
87}
88
89local f_href_as_command_t = {
90 tex = formatters["<a class='setuplisturl' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s'>\\%s</a>"],
91 lua = formatters["<a class='setuplisturl' href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s'>context.%s</a>"],
92}
93
94local f_modes_t = {
95 tex = formatters["<a class='setupmodeurl' href='mtx-server-ctx-help.lua?interface=%s&mode=lua'>lua mode</a>"],
96 lua = formatters["<a class='setupmodeurl' href='mtx-server-ctx-help.lua?interface=%s&mode=tex'>tex mode</a>"],
97}
98
99local f_views_t = {
100 groups = formatters["<a class='setupviewurl' href='mtx-server-ctx-help.lua?interface=%s&view=names'>names</a>"],
101 names = formatters["<a class='setupviewurl' href='mtx-server-ctx-help.lua?interface=%s&view=groups'>groups</a>"],
102}
103
104local f_interface = formatters["<a href='mtx-server-ctx-help.lua?interface=%s&command=%s&mode=%s'>%s</a>"]
105local f_source = formatters["<a href='mtx-server-ctx-help.lua?interface=%s&command=%s&source=%s&mode=%s'>%s</a>"]
106local f_keyword = formatters[" <tr>\n <td width='15%%'>%s</td>\n <td width='85%%' colspan='2'>%s</td>\n </tr>\n"]
107local f_parameter = formatters[" <tr>\n <td width='15%%'>%s</td>\n <td width='15%%'>%s</td>\n <td width='70%%'>%s</td>\n </tr>\n"]
108local f_url = formatters[" <tr>\n <td width='15%%'>%s</td>\n <td width='85%%' colspan='2'><i>%s</i>: %s</td>\n </tr>\n"]
109local f_parameters = formatters["\n<table width='100%%'>\n%s</table>\n"]
110local f_instance = formatters["<tt>%s</tt>"]
111local f_instances = formatters["\n<div class='setupinstances'><b>predefined instances</b>: %s</div>\n"]
112local f_listing = formatters["<pre><t>%s</t></pre>"]
113local f_special = formatters["<i>%s</i>"]
114local f_default = formatters["<u>%s</u>"]
115local f_group = formatters["<div class='setupmenugroup'>\n<div class='setupmenucategory'>%s</div>%s</div>"]
116
117
118
119
120
121
122
123
124
125local function translate(tag,interface,noformat)
126 local translation = i_setupstrings[tag]
127 local translated = translation and (translation[interface] or translation[interface]) or tag
128 if noformat then
129 return translated
130 else
131 return f_special(translated)
132 end
133end
134
135local function translatedparameter(e,interface)
136 local attributes = e.at
137 local s = attributes.type or "?"
138 if find(s,"^cd:") then
139 local t = i_setupstrings[s]
140 local f = t and (t[interface] or t.en) or s
141 return f
142 else
143 local t = i_variables[s]
144 local f = t and (t[interface] or t.en) or s
145 return f
146 end
147end
148
149local function translatedkeyword(e,interface)
150 local attributes = e.at
151 local s = attributes.type or "?"
152 if find(s,"^cd:") then
153 local t = i_setupstrings[s]
154 local f = t and (t[interface] or t.en) or s
155 return f
156 else
157 local t = i_variables[s]
158 local f = t and (t[interface] or t.en) or s
159 if attributes.default == "yes" then
160 return f_default(f)
161 else
162 return f
163 end
164 end
165end
166
167local function translatedvariable(s,interface)
168 local t = i_variables[s]
169 return t and (t[interface] or t.en) or s
170end
171
172local function translatedconstant(s,interface)
173 local t = i_constants[s]
174 return t and (t[interface] or t.en) or s
175end
176
177local function translatedelement(s,interface)
178 local t = i_elements[s]
179 return t and (t[interface] or t.en) or s
180end
181
182local function translatedstring(s,interface)
183 local t = i_commands[s]
184 if t then
185 t = t[interface] or t.en
186 end
187 if t then
188 return t
189 end
190 t = i_elements[s]
191 return t and (t[interface] or t.en) or s
192end
193
194local function translatedcommand(s,interface)
195 local t = i_commands[s]
196 return t and (t[interface] or t.en) or s
197end
198
199local function makeidname(e)
200 local at = e.at
201 local name = at.name
202 if at.type == 'environment' then
203 name = name .. ":environment"
204 end
205 if at.generated == "yes" then
206 name = name .. ":generated"
207 end
208 if at.variant then
209 name = name .. ":" .. at.variant
210 end
211 return lower(name)
212end
213
214local function makecsname(e,interface,prefix)
215 local cs = ""
216 local at = e.at
217 local ok = false
218 local en = at.type == 'environment'
219 if prefix and en then
220 cs = translatedelement("start",interface)
221 end
222 for f in xmlcollected(e,'cd:sequence/(cd:string|cd:variable)') do
223 local tag = f.tg
224 local val = f.at.value or ""
225 if tag == "string" then
226 cs = cs .. translatedstring(val,interface)
227 elseif tag == "variable" then
228 cs = cs .. f_special(translatedconstant("name",interface))
229 else
230 cs = cs .. val
231 end
232 ok = true
233 end
234 if not ok then
235 if en then
236 cs = cs .. translatedstring(at.name,interface)
237 else
238 cs = cs .. translatedcommand(at.name,interface)
239 end
240 end
241 return cs
242end
243
244local function getnames(root,interface)
245 local found = { }
246 local names = { }
247 local groups = { }
248 local extra = { }
249 for e in xmlcollected(root,'cd:interface/cd:interface') do
250 local category = match(e.at.file or "","^i%-(.*)%.xml$")
251 local list = { }
252 for e in xmlcollected(e,'cd:command') do
253 local idname = makeidname(e)
254 local csname = makecsname(e,interface,true)
255 if not found[idname] then
256 local t = { idname, csname }
257 names[#names+1] = t
258 list[#list+1] = t
259 found[idname] = e
260 extra[csname] = e
261 else
262
263 end
264 end
265 if #list > 0 then
266 sort(list, function(a,b) return lower(a[2]) < lower(b[2]) end)
267 groups[#groups+1] = { category, list }
268 end
269
270 end
271 sort(names, function(a,b) return lower(a[2]) < lower(b[2]) end)
272 sort(groups, function(a,b) return lower(a[1]) < lower(b[1]) end)
273 return names, groups, found, extra
274end
275
276local loaded = setmetatableindex(function(loaded,interface)
277 local names, groups, found, extra = getnames(usedsetuproot,interface)
278 local current = {
279 interface = interface,
280 root = usedsetuproot,
281 definitions = useddefinitions,
282 names = names,
283 groups = groups,
284 found = found,
285 extra = extra,
286 }
287 loaded[interface] = current
288 return current
289end)
290
291local function collect(current,name,interface,lastmode)
292 local command = current.found[name] or current.extra[name]
293 if command then
294 local definitions = current.definitions
295 local attributes = command.at or { }
296 local generated = attributes.generated == "yes"
297 local environment = attributes.type == "environment"
298 local sequence = { }
299 local tags = { }
300 local arguments = { }
301 local parameters = { }
302 local instances = { }
303 local tag = ""
304 local category = attributes.category or ""
305 local source = attributes.file and f_source(lastinterface,lastcommand,attributes.file,lastmode,attributes.file) or ""
306
307
308
309 local start = environment and (attributes["begin"] or translatedelement("start",interface)) or ""
310 local stop = environment and (attributes["end"] or translatedelement("stop" ,interface)) or ""
311 local name = makecsname(command,interface)
312 local valid = true
313 local texmode = lastmode == "tex"
314
315 local function process(e)
316 for e in xmlcollected(e,"/*") do
317 if not e.special then
318 local tag = e.tg
319 local attributes = e.at
320 if tag == "resolve" then
321 local resolved = definitions[e.at.name or ""]
322 if resolved then
323 process(resolved)
324 end
325 else
326
327 local delimiters = attributes.delimiters or "brackets"
328 local optional = attributes.optional == "yes"
329 local list = attributes.list == "yes"
330 if texmode then
331 local okay
332 if tag == "keywords" then
333
334 okay = i_setupstrings["cd:" .. delimiters .. (list and "-l" or "-s")]
335 elseif tag == "assignments" then
336
337 okay = i_setupstrings["cd:assignment" .. delimiters .. (list and "-l" or "-s")]
338 elseif tag == "delimiter" then
339 tag = "\\" .. attributes.name
340 elseif tag == "string" then
341 tag = translatedstring(attributes.value,interface)
342 else
343
344 okay = i_setupstrings["cd:" .. tag .. (list and "-l" or "-s")]
345 or i_setupstrings["cd:" .. tag]
346 end
347 if okay then
348 tag = okay.en or tag
349 end
350 else
351 local okay
352 if tag == "keywords" then
353
354 okay = i_setupstrings["cd:" .. delimiters .. (list and "-l" or "-s")]
355 elseif tag == "assignments" then
356
357 okay = i_setupstrings["cd:assignment" .. delimiters .. (list and "-l" or "-s")]
358 elseif tag == "delimiter" then
359 okay = false
360 elseif tag == "string" then
361 okay = false
362 else
363
364 okay = i_setupstrings["cd:" .. tag .. (list and "-l" or "-s")]
365 or i_setupstrings["cd:" .. tag]
366 end
367 if okay then
368 local luatag = okay.lua
369 if luatag then
370 tag = luatag
371 else
372 tag = "unsupported"
373 valid = false
374 end
375 else
376 tag = "unsupported"
377 valid = false
378 end
379 end
380 if tag then
381 sequence[#sequence+1] = tag
382 tags[#tags+1] = tag
383 end
384 end
385 end
386 end
387 end
388
389 if start and start ~= "" then
390 if texmode then
391 sequence[#sequence+1] = formatters["\\%s%s"](start,name)
392 else
393 sequence[#sequence+1] = formatters["context.%s%s("](start,name)
394 end
395 else
396 if texmode then
397 sequence[#sequence+1] = formatters["\\%s"](name)
398 else
399 sequence[#sequence+1] = formatters["context.%s("](name)
400 end
401 end
402
403 for e in xmlcollected(command,"/cd:arguments") do
404 process(e)
405 end
406
407 if texmode then
408 if stop and stop ~= "" then
409 sequence[#sequence+1] = "\\" .. stop .. name
410 end
411 else
412 for i=2,#sequence-1 do
413 sequence[i] = sequence[i] .. ", "
414 end
415
416 if stop and stop ~= "" then
417 sequence[#sequence+1] = formatters[") context.%s%s()"](stop,name)
418 else
419 sequence[#sequence+1] = ")"
420 end
421 end
422
423 if valid then
424
425 sequence = concat(sequence," ")
426
427
428
429 local n = 0
430
431 local function process(e)
432 for e in xmlcollected(e,"/*") do
433 local tag = e.tg
434
435 if tag == "resolve" then
436
437 local resolved = definitions[e.at.name or ""]
438 if resolved then
439 process(resolved)
440 end
441
442 elseif tag == "keywords" then
443
444 n = n + 1
445 local left = tags[n]
446 local right = { }
447
448 local function processkeyword(e)
449 right[#right+1] = translatedkeyword(e,interface)
450 end
451
452 for e in xmlcollected(e,"/*") do
453 if not e.special then
454 local tag = e.tg
455 if tag == "resolve" then
456 local resolved = definitions[e.at.name or ""]
457 if resolved then
458 processkeyword(resolved)
459 end
460 elseif tag == "constant" then
461 processkeyword(e)
462 else
463 right[#right+1] = "KEYWORD TODO"
464 end
465 end
466 end
467 parameters[#parameters+1] = f_keyword(left,concat(right, ", "))
468
469 elseif tag == "assignments" then
470
471 n = n + 1
472 local what = tags[n]
473 local done = false
474
475 local function processparameter(e,right)
476 for e in xmlcollected(e,"/*") do
477 if not e.special then
478 local tag = e.tg
479 if tag == "resolve" then
480 local resolved = definitions[e.at.name or ""]
481 if resolved then
482 processparameter(resolved,right)
483 end
484 elseif tag == "constant" then
485 right[#right+1] = translatedparameter(e,interface)
486 else
487 right[#right+1] = "PARAMETER TODO"
488 end
489 end
490 end
491 end
492
493 for e in xmlcollected(e,"/*") do
494 if not e.special then
495 local tag = e.tg
496 local left = translatedconstant(e.at.name,interface)
497 local right = { }
498 if tag == "resolve" then
499 local resolved = definitions[e.at.name or ""]
500 if resolved then
501
502 process(resolved)
503 end
504 elseif tag == "inherit" then
505 local name = e.at.name or "?"
506 local url = f_href_as_command_t[lastmode](lastinterface,name,lastmode,name)
507 parameters[#parameters+1] = f_url(what,translate("cd:inherits",interface),url)
508 elseif tag == "parameter" then
509 processparameter(e,right)
510 parameters[#parameters+1] = f_parameter(what,left,concat(right, ", "))
511 else
512 parameters[#parameters+1] = "PARAMETER TODO"
513 end
514 if not done then
515 done = true
516 what = ""
517 end
518 end
519 end
520
521 what = ""
522 else
523
524 n = n + 1
525 local left = tags[n]
526 local right = i_setupstrings["cd:"..tag]
527
528 if right then
529 right = uppercase(right[interface] or right.en or tag)
530 end
531
532 parameters[#parameters+1] = f_keyword(left,right)
533
534 end
535 end
536 end
537
538 for e in xmlcollected(command,"/cd:arguments") do
539 process(e)
540 end
541
542 else
543 if texmode then
544 sequence = formatters["unsupported command '%s%s'"](start or "",name)
545 else
546 sequence = formatters["unsupported function '%s%s'"](start or "",name)
547 end
548 parameters = { }
549 end
550
551
552 for e in xmlcollected(command,"/cd:instances/cd:constant") do
553 instances[#instances+1] = f_instance(translatedconstant(e.at.value or "?",interface))
554 end
555
556 return {
557 category = category,
558 source = source,
559 mode = f_modes_t[lastmode or "tex"](lastinterface),
560 view = f_views_t[lastview or "groups"](lastinterface),
561 sequence = sequence,
562 parameters = parameters,
563 instances = instances,
564 }
565 end
566end
567
568
569
570local interfaces = {
571 czech = 'cz',
572 dutch = 'nl',
573 english = 'en',
574 french = 'fr',
575 german = 'de',
576 italian = 'it',
577 persian = 'pe',
578 romanian = 'ro',
579}
580
581local variables = {
582 ['color-background-main-left'] = '#3F3F3F',
583 ['color-background-main-right'] = '#5F5F5F',
584 ['color-background-one'] = lmx.get('color-background-green'),
585 ['color-background-two'] = lmx.get('color-background-blue'),
586 ['title'] = 'ConTeXt Help Information',
587}
588
589local what = { "environment", "category", "source", "mode", "view" }
590
591local function generate(configuration,filename,hashed)
592
593 local start = gettime()
594 local detail = hashed.queries or { }
595 local variables = setmetatableindex({},variables)
596
597 if detail then
598 local lastinterface = detail.interface or defaultinterface or "en"
599 local lastcommand = detail.command or ""
600 local lastview = detail.view or "groups"
601 local lastsource = detail.source or ""
602 local lastmode = detail.mode or "tex"
603
604 local current = loaded[lastinterface]
605
606 local title = variables.title .. ": " .. lastinterface
607 variables.title = title
608
609 lastcommand = gsub(lastcommand,"%s*^\\*(.+)%s*","%1")
610
611 local f_div = f_divs_t[lastinterface]
612
613
614 local names = current.names
615 local groups = current.groups
616 local refs = { }
617 local ints = { }
618
619 local function addnames(names)
620 local target = { }
621 for k=1,#names do
622 local namedata = names[k]
623 local command = namedata[1]
624 local text = namedata[2]
625 if command == lastcommand then
626 target[#target+1] = f_href_in_list_i[lastmode](lastinterface,command,lastmode,text)
627 else
628 target[#target+1] = f_href_in_list_t[lastmode](lastinterface,command,lastmode,text)
629 end
630 end
631 return concat(target,"<br/>\n")
632 end
633
634 if lastview == "groups" then
635 local target = { }
636 for i=1,#groups do
637 local group = groups[i]
638 target[#target+1] = f_group(group[1],addnames(group[2]))
639 end
640 refs = concat(target,"<br/>\n")
641 else
642 refs = addnames(names)
643 end
644
645 if lastmode ~= "lua" then
646 local sorted = sortedkeys(interfaces)
647 for k=1,#sorted do
648 local v = sorted[k]
649 ints[k] = f_interface(interfaces[v],lastcommand,lastmode,v)
650 end
651 end
652
653 local n = refs
654 local i = concat(ints,"<br/><br/>\n")
655
656 if f_div then
657 variables.names = f_div(n)
658 variables.interfaces = f_div(i)
659 else
660 variables.names = n
661 variables.interfaces = i
662 end
663
664
665
666 if lastsource and lastsource ~= "" then
667
668 local name = lastsource
669 local full = resolvers.findfile(name)
670 if full == "" and file.suffix(lastsource) == "tex" then
671 name = file.replacesuffix(lastsource,"mkiv")
672 full = resolvers.findfile(name)
673 if full == "" then
674 name = file.replacesuffix(lastsource,"mkvi")
675 full = resolvers.findfile(name)
676 end
677 end
678 if full == "" then
679 variables.maintitle = lastsource
680 variables.maintext = f_listing("no source found")
681 else
682 local data = io.loaddata(full)
683 data = scite.html(data,file.suffix(full),true)
684 variables.maintitle = name
685 variables.maintext = f_listing(data)
686 end
687 lastsource = ""
688 variables.extra = "mode: " .. f_modes_t.tex(lastinterface) .. " " .. f_modes_t.lua(lastinterface)
689
690 elseif lastcommand and lastcommand ~= "" then
691
692 local data = collect(current,lastcommand,lastinterface,lastmode)
693 if data then
694 local extra = { }
695 for k=1,#what do
696 local v = what[k]
697 if data[v] and data[v] ~= "" then
698 lmx.set(v, data[v])
699 extra[#extra+1] = v .. ": " .. data[v]
700 end
701 end
702 local instances = data.instances
703 variables.maintitle = data.sequence
704 variables.maintext = f_parameters(concat(data.parameters)) .. (#instances > 0 and f_instances(concat(instances,", ")) or "")
705 variables.extra = concat(extra," ")
706 else
707 variables.maintitle = "no definition"
708 variables.maintext = ""
709 variables.extra = ""
710 end
711 else
712 variables.maintitle = "no definition"
713 variables.maintext = ""
714 variables.extra = ""
715 end
716
717 else
718
719 variables.maintitle = "no definition"
720 variables.maintext = "some error"
721 variables.extra = ""
722
723 end
724
725 local content = lmx.convert('context-help.lmx',false,variables)
726
727 report("time spent on building page: %0.03f seconds",gettime()-start)
728
729 return { content = content }
730end
731
732return generate, true
733 |