5 # ./waf configure --luadoc ....
7 # ./gtk2_ardour/arluadoc > doc/luadoc.json
9 # php tools/fmt-luadoc.php > /tmp/luadoc.html
12 ################################################################################
13 ################################################################################
15 $json = file_get_contents (dirname (__FILE__).'/../doc/luadoc.json');
17 foreach (json_decode ($json, true) as $b) {
18 if (!isset ($b['type'])) { continue; }
22 if (count ($doc) == 0) {
23 fwrite (STDERR, "Failed to read luadoc.json\n");
27 ################################################################################
28 ## Global result variables
29 ################################################################################
31 $classlist = array ();
32 $constlist = array ();
35 ################################################################################
36 ## Pre-process the data, collect functions, parse arguments, cross reference
37 ################################################################################
40 ################################################################################
41 # some internal helper functions first
47 function my_die ($msg) {
48 fwrite (STDERR, $msg."\n");
52 ##function ptr_strip ($ctype) {
53 # # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
54 # # -> std::list<ARDOUR::Route>
55 # $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
56 # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
59 function arg2lua ($argtype) {
63 # LuaBridge abstracts C++ references
64 $flags = preg_match ('/&$/', $argtype);
65 $arg = preg_replace ('/&$/', '', $argtype);
67 # filter out basic types
68 $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
69 if (in_array ($arg, $builtin)) {
70 return array ($arg => $flags);
73 # check Class declarations first
74 foreach (array_merge ($classes, $consts) as $b) {
75 if ($b['decl'] == $arg) {
76 return array ($b['lua'] => $flags);
80 # strip class pointers -- TODO Check C'tor for given class
81 $arg = preg_replace ('/[&*]*$/', '', $argtype);
82 foreach (array_merge ($classes, $consts) as $b) {
83 if ($b['decl'] == $arg) {
84 return array ($b['lua'] => $flags);
87 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
90 function stripclass ($classname, $name) {
92 if (strpos ($name, $classname) !== 0) {
93 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
95 return substr ($name, strlen ($classname));
98 function datatype ($decl) {
99 # TODO handle spaces in type. Works because
100 # we don't yet have templated types (with_space <here >)
101 return substr ($decl, 0, strpos ($decl, ' '));
104 function luafn2class ($lua) {
105 return substr ($lua, 0, strrpos ($lua, ':'));
108 function checkclass ($b) {
110 if (!isset ($classlist[luafn2class ($b['lua'])])) {
111 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
115 # parse functions argument list to lua-names
116 function decl2args ($decl) {
117 $start = strrpos ($decl, '(');
118 $end = strrpos ($decl, ')');
119 $args = substr ($decl, $start + 1, $end - $start - 1);
120 $arglist = preg_split ('/, */', $args);
122 foreach ($arglist as $a) {
123 if (empty ($a)) { continue; }
124 $rv[] = arg2lua ($a);
129 ################################################################################
130 # step 1: build class indices
132 foreach ($doc as $b) {
133 if (strpos ($b['type'], "[C] ") === 0) {
135 $classlist[$b['lua']] = $b;
136 if (strpos ($b['type'], 'Pointer Class') === false) {
137 $classdecl[$b['decl']] = $b;
142 foreach ($classes as $c) {
143 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
144 if (isset ($c['parent'])) {
145 if (isset ($classdecl[$c['parent']])) {
146 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
148 my_die ('unknown parent class: ' . print_r ($c, true));
153 # step 2: extract constants/enum
154 foreach ($doc as $b) {
155 switch ($b['type']) {
156 case "Constant/Enum":
157 case "Constant/Enum Member":
158 if (strpos ($b['decl'], '::') === false) {
159 # for extern c enums, use the Lua Namespace
160 $b['decl'] = str_replace (':', '::', luafn2class ($b['lua']));
162 $ns = str_replace ('::', ':', $b['decl']);
163 $constlist[$ns][] = $b;
173 # step 3: process functions
174 foreach ($doc as $b) {
175 switch ($b['type']) {
177 case "Weak/Shared Pointer Constructor":
179 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
180 'name' => luafn2class ($b['lua']),
181 'args' => decl2args ($b['decl']),
186 $classlist[luafn2class ($b['lua'])]['data'][] = array (
188 'ret' => arg2lua (datatype ($b['decl']))
192 # we required C functions to be in a class namespace
193 case "Ext C Function":
195 $args = array (array ('--custom--' => 0));
196 $ret = array ('...' => 0);
197 $ns = luafn2class ($b['lua']);
198 $cls = $classlist[$ns];
199 ## std::Vector std::List types
200 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['decl'], $templ)) {
201 // XXX -> move to C-source
202 switch (stripclass($ns, $b['lua'])) {
204 $args = array (array ('LuaTable {'.$templ[1].'}' => 0));
205 $ret = array ('LuaTable' => 0);
209 $ret = array ('LuaIter' => 0);
213 $ret = array ('LuaTable' => 0);
218 } else if (strpos ($cls['type'], ' Array') !== false) {
219 $templ = preg_replace ('/[&*]*$/', '', $cls['decl']);
220 switch (stripclass($ns, $b['lua'])) {
223 $ret = array ('LuaMetaTable' => 0);
227 $ret = array ('LuaTable' => 0);
230 $args = array (array ('LuaTable {'.$templ.'}' => 0));
231 $ret = array ('void' => 0);
237 $classlist[luafn2class ($b['lua'])]['func'][] = array (
246 case "Free Function":
247 case "Free Function RefReturn":
248 $funclist[luafn2class ($b['lua'])][] = array (
251 'args' => decl2args ($b['decl']),
252 'ret' => arg2lua ($b['ret']),
253 'ref' => (strpos ($b['type'], "RefReturn") !== false)
256 case "Member Function":
257 case "Member Function RefReturn":
258 case "Member Pointer Function":
259 case "Weak/Shared Pointer Function":
260 case "Weak/Shared Pointer Function RefReturn":
261 case "Weak/Shared Null Check":
262 case "Weak/Shared Pointer Cast":
263 case "Static Member Function":
265 $classlist[luafn2class ($b['lua'])]['func'][] = array (
268 'args' => decl2args ($b['decl']),
269 'ret' => arg2lua ($b['ret']),
270 'ref' => (strpos ($b['type'], "RefReturn") !== false)
273 case "Constant/Enum":
274 case "Constant/Enum Member":
275 # already handled -> $consts
278 if (strpos ($b['type'], "[C] ") !== 0) {
279 my_die ('unhandled type: ' . $b['type']);
286 # step 4: collect/group/sort
288 # step 4a: unify weak/shared Ptr classes
289 foreach ($classlist as $ns => $cl) {
290 if (strpos ($cl['type'], ' Array') !== false) {
291 $classlist[$ns]['arr'] = true;
294 foreach ($classes as $c) {
295 if ($c['lua'] == $ns) {
296 if (strpos ($c['type'], 'Pointer Class') !== false) {
297 $classlist[$ns]['ptr'] = true;
298 $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
305 # step4b: sanity check
306 foreach ($classlist as $ns => $cl) {
307 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
308 my_die ('missing parent class: ' . print_r ($cl, true));
312 # step 4c: merge free functions into classlist
313 foreach ($funclist as $ns => $fl) {
314 if (isset ($classlist[$ns])) {
315 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
317 $classlist[$ns]['func'] = $fl;
318 $classlist[$ns]['free'] = true;
321 # step 4d: order to chaos
322 # no array_multisort() here, sub-types are sorted after merging parents
326 ################################################################################
327 ################################################################################
328 ################################################################################
331 #### -- split here -- ####
333 # from here on, only $classlist and $constlist arrays are relevant.
335 # TODO: read function documentation from doxygen
336 # and/or reference source-code lines e.g from CSV list:
337 # ctags -o /tmp/tags.csv --fields=+afiKkmnsSzt libs/ardour/ardour/session.h
340 ################################################################################
342 ################################################################################
345 ################################################################################
349 function ctorname ($name) {
350 return htmlentities (str_replace (':', '.', $name));
353 function shortname ($name) {
354 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
357 function varname ($a) {
358 return array_keys ($a)[0];
361 function name_sort_cb ($a, $b) {
362 return strcmp ($a['name'], $b['name']);
365 function traverse_parent ($ns, &$inherited) {
368 if (isset ($classlist[$ns]['luaparent'])) {
369 $parents = array_unique ($classlist[$ns]['luaparent']);
371 foreach ($parents as $p) {
372 if (!empty ($rv)) { $rv .= ', '; }
373 $rv .= typelink ($p);
374 $inherited[$p] = $classlist[$p];
375 traverse_parent ($p, $inherited);
381 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
384 # all cross-reference links are generated here.
385 # currently anchors on a single page.
386 if (isset($classlist[$a]['free'])) {
387 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
388 } else if (in_array ($a, array_keys ($classlist))) {
389 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
390 } else if (in_array ($a, array_keys ($constlist))) {
391 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
393 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
397 function format_args ($args) {
398 $rv = '<span class="functionargs"> (';
400 foreach ($args as $a) {
401 if (!$first) { $rv .= ', '; }; $first = false;
402 $flags = $a[varname ($a)];
404 $rv .= typelink (varname ($a), true, 'em', '', '&');
406 $rv .= typelink (varname ($a), true, 'em');
413 function format_class_members ($ns, $cl, &$dups) {
415 if (isset ($cl['ctor'])) {
416 usort ($cl['ctor'], 'name_sort_cb');
417 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
418 foreach ($cl['ctor'] as $f) {
419 $rv.= ' <tr><td class="def">ℂ</td><td class="decl">';
420 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
421 $rv.= format_args ($f['args']);
422 $rv.= '</td><td class="fill"></td></tr>'.NL;
426 if (isset ($cl['func'])) {
427 foreach ($cl['func'] as $f) {
428 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
432 if (count ($nondups) > 0) {
433 usort ($nondups, 'name_sort_cb');
434 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
435 foreach ($nondups as $f) {
436 $dups[] = stripclass ($ns, $f['name']);
437 $rv.= ' <tr><td class="def">';
438 if ($f['ref'] && isset ($f['ext'])) {
439 # external C functions
440 $rv.= '<em>'.varname ($f['ret']).'</em>';
441 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
442 # functions with reference args return args
443 $rv.= '<em>LuaTable</em>(...)';
444 } elseif ($f['ref']) {
445 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret'], false, 'em')).', ...)';
447 $rv.= typelink (varname ($f['ret']), true, 'em');
449 $rv.= '</td><td class="decl">';
450 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
451 $rv.= format_args ($f['args']);
452 $rv.= '</td><td class="fill"></td></tr>'.NL;
455 if (isset ($cl['data'])) {
456 usort ($cl['data'], 'name_sort_cb');
457 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
458 foreach ($cl['data'] as $f) {
459 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
460 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
461 $rv.= '</td><td class="fill"></td></tr>'.NL;
468 ################################################################################
472 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
474 <title>Ardour Lua Bindings</title>
475 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
476 <style type="text/css">
477 div.content { max-width:60em; margin: 1em auto; }
478 h1 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black;}
479 h2.cls { margin:2em 0 0 0; padding-left:1em; border: 1px dashed #6666ee;}
480 h2.cls abbr { text-decoration:none; cursor:default;}
481 h3.cls { margin:1em 0 0 0;}
482 h2.class { background-color: #aaee66; }
483 h2.enum { background-color: #aaaaaa; }
484 h2.pointerclass { background-color: #eeaa66; }
485 h2.array { background-color: #66aaee; }
486 h2.opaque { background-color: #6666aa; }
487 p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em;}
488 ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
489 div.clear { clear:both; }
490 table.classmembers { width: 100%; }
491 table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
492 table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap;}
493 table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
494 table.classmembers td.fill { width: 99%;}
495 table.classmembers span.em { font-style: italic;}
496 span.functionname abbr { text-decoration:none; cursor:default;}
497 div.header {text-align:center;}
498 div.header h1 {margin:0;}
499 div.header p {margin:.25em;}
504 <h1>Ardour Lua Bindings</h1>
506 <a href="#h_classes">Class Documentation</a>
508 <a href="#h_enum">Enum/Constants</a>
510 <a href="#h_index">Index</a>
513 <div class="content">
515 <h1 id="h_intro">Overview</h1>
517 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
518 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
521 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
522 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
523 <?=typelink('LuaSignal:Set')?> etc.
526 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
528 <h2>Short introduction to Ardour classes</h2>
530 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
531 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
532 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
533 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
536 Operations are performed on objects. One gets a reference to an object and then calls a method.
537 e.g obj = Session:route_by_name("Audio") obj:set_name("Guitar")
540 Object lifetimes are managed by the Session. Most Objects cannot be directly created, but one asks the Session to create or destroy them. This is mainly due to realtime constrains:
541 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
545 echo '<h1 id="h_classes">Class Documentation</h1>'.NL;
547 foreach ($classlist as $ns => $cl) {
549 $tbl = format_class_members ($ns, $cl, $dups);
553 echo '<h2 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h2>'.NL;
555 else if (isset ($classlist[$ns]['free'])) {
556 echo '<h2 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h2>'.NL;
558 else if (isset ($classlist[$ns]['arr'])) {
559 echo '<h2 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h2>'.NL;
561 else if (isset ($classlist[$ns]['ptr'])) {
562 echo '<h2 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h2>'.NL;
564 echo '<h2 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h2>'.NL;
566 if (isset ($cl['decl'])) {
567 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['decl']).'</p>'.NL;
570 # print class inheritance
571 $inherited = array ();
572 $isa = traverse_parent ($ns, $inherited);
574 echo ' <p>is-a: '.$isa.'</p>'.NL;
576 echo '<div class="clear"></div>'.NL;
578 # member documentation
580 echo '<p>This class object is only used indirectly as return-value and function-parameter.</p>'.NL;
582 echo '<table class="classmembers">'.NL;
587 # traverse parent classes (inherited members)
588 foreach ($inherited as $pns => $pcl) {
589 $tbl = format_class_members ($pns, $pcl, $dups);
591 echo '<h3 class="cls">Inherited from '.$pns.'</h3>'.NL;
592 echo '<table class="classmembers">'.NL;
599 echo '<h1 id="h_enum">Enum/Constants</h1>'.NL;
600 foreach ($constlist as $ns => $cs) {
601 echo '<h2 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h2>'.NL;
602 echo '<ul class="enum">'.NL;
603 foreach ($cs as $c) {
604 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
609 echo '<h1 id="h_index" >Class Index</h1>'.NL;
610 echo '<ul class="classindex">'.NL;
611 foreach ($classlist as $ns => $cl) {
612 echo '<li>'.typelink($ns).'</li>'.NL;