5 ## generate doc/luadoc.json.gz (lua binding doc)
6 # ./waf configure --luadoc ....
8 # ./gtk2_ardour/arluadoc > doc/luadoc.json.gz
10 ## generate doc/ardourapi.json.gz (ardour header doxygen doc)
11 # cd ../../tools/doxy2json
15 ## format HTML (using this scripterl)
16 # php tools/fmt-luadoc.php > /tmp/luadoc.html
19 ################################################################################
20 ################################################################################
22 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz'));
24 foreach (json_decode ($json, true) as $b) {
25 if (!isset ($b['type'])) { continue; }
26 $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl']));
27 if (isset ($b['ret'])) {
28 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
33 if (count ($doc) == 0) {
34 fwrite (STDERR, "Failed to read luadoc.json\n");
38 ################################################################################
39 ## Global result variables
40 ################################################################################
42 $classlist = array ();
43 $constlist = array ();
46 ################################################################################
47 ## Pre-process the data, collect functions, parse arguments, cross reference
48 ################################################################################
51 ################################################################################
52 # some internal helper functions first
58 function my_die ($msg) {
59 fwrite (STDERR, $msg."\n");
63 ##function ptr_strip ($ctype) {
64 # # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
65 # # -> std::list<ARDOUR::Route>
66 # $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
67 # return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
70 function arg2lua ($argtype, $flags = 0) {
74 # LuaBridge abstracts C++ references
75 $flags |= preg_match ('/&$/', $argtype);
76 $arg = preg_replace ('/&$/', '', $argtype);
77 $arg = preg_replace ('/ $/', '', $arg);
79 # filter out basic types
80 $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
81 if (in_array ($arg, $builtin)) {
82 return array ($arg => $flags);
85 # check Class declarations first
86 foreach (array_merge ($classes, $consts) as $b) {
87 if ($b['ldec'] == $arg) {
88 return array ($b['lua'] => $flags);
92 # strip class pointers -- TODO Check C'tor for given class
93 $arg = preg_replace ('/[&*]*$/', '', $argtype);
94 foreach (array_merge ($classes, $consts) as $b) {
95 if ($b['ldec'] == $arg) {
96 return array ($b['lua'] => $flags);
100 return array ($argtype => ($flags | 4));
102 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
106 function stripclass ($classname, $name) {
108 if (strpos ($name, $classname) !== 0) {
109 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
111 return substr ($name, strlen ($classname));
114 function datatype ($decl) {
115 # TODO handle spaces in type. Works because
116 # we don't yet have templated types (with_space <here >)
117 return substr ($decl, 0, strpos ($decl, ' '));
120 function luafn2class ($lua) {
121 return substr ($lua, 0, strrpos ($lua, ':'));
124 function checkclass ($b) {
126 if (!isset ($classlist[luafn2class ($b['lua'])])) {
127 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
131 # parse functions argument list to lua-names
132 function decl2args ($decl) {
133 $start = strrpos ($decl, '(');
134 $end = strrpos ($decl, ')');
135 $args = substr ($decl, $start + 1, $end - $start - 1);
136 $arglist = preg_split ('/, */', $args);
138 foreach ($arglist as $a) {
139 if (empty ($a)) { continue; }
140 $rv[] = arg2lua ($a);
145 function canonical_ctor ($b) {
147 if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
148 $lc = luafn2class ($b['lua']);
149 $cn = str_replace (':', '::', $lc);
150 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
151 $rv = $cn . '::'. $fn . $matches[2];
156 function canonical_decl ($b) {
159 # match clang's declatation format
160 if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
161 if (strpos ($b['type'], 'Free Function') !== false) {
162 $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
164 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
165 $rv = $matches[1] . $fn . '(';
166 $arglist = preg_split ('/, */', $matches[2]);
168 foreach ($arglist as $a) {
169 if (!$first) { $rv .= ', '; }; $first = false;
170 if (empty ($a)) { continue; }
171 $a = preg_replace ('/([^>]) >/', '$1>', $a);
172 $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
173 $a = preg_replace ('/([^ ])&/', '$1 &', $a);
174 $a = str_replace ('vector', 'std::vector', $a);
175 $a = str_replace ('std::string', 'string', $a);
176 $a = str_replace ('string const', 'const string', $a);
177 $a = str_replace ('string', 'std::string', $a);
185 ################################################################################
186 # step 1: build class indices
188 foreach ($doc as $b) {
189 if (strpos ($b['type'], "[C] ") === 0) {
191 $classlist[$b['lua']] = $b;
192 if (strpos ($b['type'], 'Pointer Class') === false) {
193 $classdecl[$b['ldec']] = $b;
198 foreach ($classes as $c) {
199 if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
200 if (isset ($c['parent'])) {
201 if (isset ($classdecl[$c['parent']])) {
202 $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
204 my_die ('unknown parent class: ' . print_r ($c, true));
209 # step 2: extract constants/enum
210 foreach ($doc as $b) {
211 switch ($b['type']) {
212 case "Constant/Enum":
213 case "Constant/Enum Member":
214 if (strpos ($b['ldec'], '::') === false) {
215 # for extern c enums, use the Lua Namespace
216 $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
218 $ns = str_replace ('::', ':', $b['ldec']);
219 $constlist[$ns][] = $b;
229 # step 3: process functions
230 foreach ($doc as $b) {
231 switch ($b['type']) {
233 case "Weak/Shared Pointer Constructor":
235 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
236 'name' => luafn2class ($b['lua']),
237 'args' => decl2args ($b['ldec']),
238 'cand' => canonical_ctor ($b)
243 $classlist[luafn2class ($b['lua'])]['data'][] = array (
245 'ret' => arg2lua (datatype ($b['ldec']))
249 # we required C functions to be in a class namespace
250 case "Ext C Function":
252 $args = array (array ('--lua--' => 0));
253 $ret = array ('...' => 0);
254 $ns = luafn2class ($b['lua']);
255 $cls = $classlist[$ns];
256 ## std::Vector std::List types
257 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
258 // XXX -> move to C-source
259 switch (stripclass($ns, $b['lua'])) {
261 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
262 $args = array (arg2lua ($templ[1], 2));
263 $ret = array ('LuaTable' => 0);
267 $ret = array ('LuaIter' => 0);
271 $ret = array ('LuaTable' => 0);
276 } else if (strpos ($cls['type'], ' Array') !== false) {
277 $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
278 switch (stripclass($ns, $b['lua'])) {
281 $ret = array ('LuaMetaTable' => 0);
285 $ret = array ('LuaTable' => 0);
288 $args = array (array ('LuaTable {'.$templ.'}' => 0));
289 $ret = array ('void' => 0);
295 $classlist[luafn2class ($b['lua'])]['func'][] = array (
302 'cand' => canonical_decl ($b)
305 case "Free Function":
306 case "Free Function RefReturn":
307 $funclist[luafn2class ($b['lua'])][] = array (
310 'args' => decl2args ($b['ldec']),
311 'ret' => arg2lua ($b['ret']),
312 'ref' => (strpos ($b['type'], "RefReturn") !== false),
313 'cand' => canonical_decl ($b)
316 case "Member Function":
317 case "Member Function RefReturn":
318 case "Member Pointer Function":
319 case "Weak/Shared Pointer Function":
320 case "Weak/Shared Pointer Function RefReturn":
321 case "Weak/Shared Null Check":
322 case "Weak/Shared Pointer Cast":
323 case "Static Member Function":
325 $classlist[luafn2class ($b['lua'])]['func'][] = array (
328 'args' => decl2args ($b['ldec']),
329 'ret' => arg2lua ($b['ret']),
330 'ref' => (strpos ($b['type'], "RefReturn") !== false),
331 'cand' => canonical_decl ($b)
334 case "Constant/Enum":
335 case "Constant/Enum Member":
336 # already handled -> $consts
339 if (strpos ($b['type'], "[C] ") !== 0) {
340 my_die ('unhandled type: ' . $b['type']);
347 # step 4: collect/group/sort
349 # step 4a: unify weak/shared Ptr classes
350 foreach ($classlist as $ns => $cl) {
351 if (strpos ($cl['type'], ' Array') !== false) {
352 $classlist[$ns]['arr'] = true;
355 foreach ($classes as $c) {
356 if ($c['lua'] == $ns) {
357 if (strpos ($c['type'], 'Pointer Class') !== false) {
358 $classlist[$ns]['ptr'] = true;
359 $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
366 # step4b: sanity check
367 foreach ($classlist as $ns => $cl) {
368 if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
369 my_die ('missing parent class: ' . print_r ($cl, true));
373 # step 4c: merge free functions into classlist
374 foreach ($funclist as $ns => $fl) {
375 if (isset ($classlist[$ns])) {
376 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
378 $classlist[$ns]['func'] = $fl;
379 $classlist[$ns]['free'] = true;
382 # step 4d: order to chaos
383 # no array_multisort() here, sub-types are sorted after merging parents
387 ################################################################################
388 ################################################################################
389 ################################################################################
392 #### -- split here -- ####
394 # from here on, only $classlist and $constlist arrays are relevant.
396 # read function documentation from doxygen
397 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
399 foreach (json_decode ($json, true) as $a) {
400 if (!isset ($a['decl'])) { continue; }
401 if (empty ($a['decl'])) { continue; }
402 $canon = str_replace (' *', '*', $a['decl']);
408 function doxydoc ($canonical_declaration) {
412 if (isset ($api[$canonical_declaration])) {
414 return $api[$canonical_declaration]['doc'];
416 elseif (isset ($api['ARDOUR::'.$canonical_declaration])) {
418 return $api['ARDOUR::'.$canonical_declaration]['doc'];
426 ################################################################################
428 ################################################################################
431 ################################################################################
435 function ctorname ($name) {
436 return htmlentities (str_replace (':', '.', $name));
439 function shortname ($name) {
440 return htmlentities (substr ($name, strrpos ($name, ':') + 1));
443 function varname ($a) {
444 return array_keys ($a)[0];
447 function name_sort_cb ($a, $b) {
448 return strcmp ($a['name'], $b['name']);
451 function traverse_parent ($ns, &$inherited) {
454 if (isset ($classlist[$ns]['luaparent'])) {
455 $parents = array_unique ($classlist[$ns]['luaparent']);
457 foreach ($parents as $p) {
458 if (!empty ($rv)) { $rv .= ', '; }
459 $rv .= typelink ($p);
460 $inherited[$p] = $classlist[$p];
461 traverse_parent ($p, $inherited);
467 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
470 # all cross-reference links are generated here.
471 # currently anchors on a single page.
472 if (isset($classlist[$a]['free'])) {
473 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
474 } else if (in_array ($a, array_keys ($classlist))) {
475 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
476 } else if (in_array ($a, array_keys ($constlist))) {
477 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
479 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
483 function format_args ($args) {
484 $rv = '<span class="functionargs"> (';
486 foreach ($args as $a) {
487 if (!$first) { $rv .= ', '; }; $first = false;
488 $flags = $a[varname ($a)];
490 $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
492 elseif ($flags & 1) {
493 $rv .= typelink (varname ($a), true, 'em', '', '&');
496 $rv .= typelink (varname ($a), true, 'em');
503 function format_doxyclass ($cl) {
505 if (isset ($cl['decl'])) {
506 $doc = doxydoc ($cl['decl']);
508 $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
514 function format_doxydoc ($f) {
516 if (isset ($f['cand'])) {
517 $doc = doxydoc ($f['cand']);
519 $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
520 $rv.= '</div></td></tr>'.NL;
521 } else if (1) { # debug
522 $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
523 $rv.= '</td></tr>'.NL;
528 function format_class_members ($ns, $cl, &$dups) {
530 if (isset ($cl['ctor'])) {
531 usort ($cl['ctor'], 'name_sort_cb');
532 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
533 foreach ($cl['ctor'] as $f) {
534 $rv.= ' <tr><td class="def">ℂ</td><td class="decl">';
535 $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
536 $rv.= format_args ($f['args']);
537 $rv.= '</td><td class="fill"></td></tr>'.NL;
538 $rv.= format_doxydoc($f);
542 if (isset ($cl['func'])) {
543 foreach ($cl['func'] as $f) {
544 if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
548 if (count ($nondups) > 0) {
549 usort ($nondups, 'name_sort_cb');
550 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
551 foreach ($nondups as $f) {
552 $dups[] = stripclass ($ns, $f['name']);
553 $rv.= ' <tr><td class="def">';
554 if ($f['ref'] && isset ($f['ext'])) {
555 # external C functions
556 $rv.= '<em>'.varname ($f['ret']).'</em>';
557 } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
558 # functions with reference args return args
559 $rv.= '<em>LuaTable</em>(...)';
560 } elseif ($f['ref']) {
561 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
563 $rv.= typelink (varname ($f['ret']), true, 'em');
565 $rv.= '</td><td class="decl">';
566 $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
567 $rv.= format_args ($f['args']);
568 $rv.= '</td><td class="fill"></td></tr>'.NL;
569 $rv.= format_doxydoc($f);
572 if (isset ($cl['data'])) {
573 usort ($cl['data'], 'name_sort_cb');
574 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
575 foreach ($cl['data'] as $f) {
576 $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
577 $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
578 $rv.= '</td><td class="fill"></td></tr>'.NL;
585 ################################################################################
589 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
591 <title>Ardour Lua Bindings</title>
592 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
593 <style type="text/css">
594 div.content { max-width:60em; margin: 1em auto; }
595 h1 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black;}
596 h2.cls { margin:2em 0 0 0; padding-left:1em; border: 1px dashed #6666ee;}
597 h2.cls abbr { text-decoration:none; cursor:default;}
598 h3.cls { margin:1em 0 0 0;}
599 h2.class { background-color: #aaee66; }
600 h2.enum { background-color: #aaaaaa; }
601 h2.pointerclass { background-color: #eeaa66; }
602 h2.array { background-color: #66aaee; }
603 h2.opaque { background-color: #6666aa; }
604 p.cdecl { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em;}
605 ul.classindex { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
606 div.clear { clear:both; }
607 p.classinfo { margin: .25em 0;}
608 div.classdox { padding: .1em 1em;}
609 div.classdox p { margin: .5em 0 .5em .6em;}
610 div.classdox p { margin: .5em 0 .5em .6em;}
611 div.classdox { padding: .1em 1em;}
612 div.classdox p { margin: .5em 0 .5em .6em;}
613 table.classmembers { width: 100%; }
614 table.classmembers th { text-align:left; border-bottom:1px solid black; padding-top:1em; }
615 table.classmembers td.def { text-align:right; padding-right:.5em; white-space: nowrap;}
616 table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
617 table.classmembers td.doc { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%;}
618 table.classmembers td.doc div.dox {background-color:#ddd; padding: .1em 1em;}
619 table.classmembers td.doc p { margin: .5em 0; }
620 table.classmembers td.doc p.para-brief { font-size:120%; }
621 table.classmembers td.doc p.para-returns { font-size:120%; }
622 table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
623 table.classmembers td.doc dt { font-style: italic; }
624 table.classmembers td.fill { width: 99%;}
625 table.classmembers span.em { font-style: italic;}
626 span.functionname abbr { text-decoration:none; cursor:default;}
627 div.header {text-align:center;}
628 div.header h1 {margin:0;}
629 div.header p {margin:.25em;}
634 <h1>Ardour Lua Bindings</h1>
636 <a href="#h_classes">Class Documentation</a>
638 <a href="#h_enum">Enum/Constants</a>
640 <a href="#h_index">Index</a>
643 <div class="content">
645 <h1 id="h_intro">Overview</h1>
647 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
648 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
651 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
652 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
653 <?=typelink('LuaSignal:Set')?> etc.
656 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
658 <h2>Short introduction to Ardour classes</h2>
660 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
661 Audio and Midi tracks are derived from a more general "Track" Object, which in turn is derived from a "Route" (aka Bus).
662 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
663 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
666 Operations are performed on objects. One gets a reference to an object and then calls a method.
667 e.g obj = Session:route_by_name("Audio") obj:set_name("Guitar")
670 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:
671 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
675 echo '<h1 id="h_classes">Class Documentation</h1>'.NL;
677 foreach ($classlist as $ns => $cl) {
679 $tbl = format_class_members ($ns, $cl, $dups);
683 echo '<h2 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">∅</abbr> '.htmlentities ($ns).'</h2>'.NL;
685 else if (isset ($classlist[$ns]['free'])) {
686 echo '<h2 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">ℕ</abbr> '.ctorname($ns).'</h2>'.NL;
688 else if (isset ($classlist[$ns]['arr'])) {
689 echo '<h2 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">⋯</abbr> '.htmlentities ($ns).'</h2>'.NL;
691 else if (isset ($classlist[$ns]['ptr'])) {
692 echo '<h2 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">↠</abbr> '. htmlentities ($ns).'</h2>'.NL;
694 echo '<h2 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">∁</abbr> '.htmlentities ($ns).'</h2>'.NL;
696 if (isset ($cl['decl'])) {
697 echo '<p class="cdecl"><em>C‡</em>: '.htmlentities ($cl['decl']).'</p>'.NL;
700 # print class inheritance
701 $inherited = array ();
702 $isa = traverse_parent ($ns, $inherited);
704 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
706 echo '<div class="clear"></div>'.NL;
708 echo format_doxyclass ($cl);
710 # member documentation
712 echo '<p class="classinfo">This class object is only used indirectly as return-value and function-parameter. It provides no methods by itself.</p>'.NL;
714 echo '<table class="classmembers">'.NL;
719 # traverse parent classes (inherited members)
720 foreach ($inherited as $pns => $pcl) {
721 $tbl = format_class_members ($pns, $pcl, $dups);
723 echo '<h3 class="cls">Inherited from '.$pns.'</h3>'.NL;
724 echo '<table class="classmembers">'.NL;
731 echo '<h1 id="h_enum">Enum/Constants</h1>'.NL;
732 foreach ($constlist as $ns => $cs) {
733 echo '<h2 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">∈</abbr> '.ctorname ($ns).'</h2>'.NL;
734 echo '<ul class="enum">'.NL;
735 foreach ($cs as $c) {
736 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
741 echo '<h1 id="h_index" >Class Index</h1>'.NL;
742 echo '<ul class="classindex">'.NL;
743 foreach ($classlist as $ns => $cl) {
744 echo '<li>'.typelink($ns).'</li>'.NL;
748 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");