update lua documentation tools
[ardour.git] / tools / fmt-luadoc.php
1 #!/usr/bin/php
2 <?php
3 ## USAGE
4 #
5 ## generate doc/luadoc.json.gz (lua binding doc)
6 # ./waf configure --luadoc ....
7 # ./waf
8 # ./gtk2_ardour/arluadoc > doc/luadoc.json.gz
9 #
10 ## generate doc/ardourapi.json.gz (ardour header doxygen doc)
11 # cd ../../tools/doxy2json
12 # ./ardourdoc.sh
13 # cd -
14 #
15 ## format HTML (using this scripterl)
16 # php tools/fmt-luadoc.php > /tmp/luadoc.html
17 #
18
19 $options = getopt("m");
20 if (isset ($options['m'])) {
21         $HTMLOUTPUT = false; ## set to false to output ardour-manual
22 } else {
23         $HTMLOUTPUT = true; ## set to false to output ardour-manual
24 }
25
26 ################################################################################
27 ################################################################################
28
29 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/luadoc.json.gz'));
30 $doc = array ();
31 $ardourversion = '';
32 foreach (json_decode ($json, true) as $b) {
33         if (!isset ($b['type'])) {
34                 if (isset ($b['version'])) { $ardourversion = $b['version']; }
35                 continue;
36         }
37         $b ['lua'] = preg_replace ('/:_end/', ':end', $b ['lua']);
38         $b ['ldec'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['decl']));
39         if (isset ($b['ret'])) {
40                 $b['ret'] = preg_replace ('/ const/', '', preg_replace ('/ const&/', '', $b['ret']));
41         }
42         $doc[] = $b;
43 }
44
45 if (count ($doc) == 0) {
46         fwrite (STDERR, "Failed to read luadoc.json\n");
47         exit (1);
48 }
49
50 ################################################################################
51 ## Global result variables
52 ################################################################################
53
54 $classlist = array ();
55 $constlist = array ();
56
57
58 ################################################################################
59 ## Pre-process the data, collect functions, parse arguments, cross reference
60 ################################################################################
61
62
63 ################################################################################
64 # some internal helper functions first
65
66 $funclist = array ();
67 $classes = array ();
68 $consts = array ();
69
70 function my_die ($msg) {
71         fwrite (STDERR, $msg."\n");
72         exit (1);
73 }
74
75 ##function ptr_strip ($ctype) {
76 #       # boost::shared_ptr<std::list<boost::shared_ptr<ARDOUR::Route>> > >
77 #       # -> std::list<ARDOUR::Route>
78 #       $ctype = preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
79 #       return preg_replace ('/boost::shared_ptr<([^>]*)[ ]*>/', '$1', $ctype);
80 #}
81
82 function arg2lua ($argtype, $flags = 0) {
83         global $classes;
84         global $consts;
85
86         # LuaBridge abstracts C++ references
87         $flags |= preg_match ('/&$/', $argtype);
88         $arg = preg_replace ('/&$/', '', $argtype);
89         $arg = preg_replace ('/ $/', '', $arg);
90
91         # filter out basic types
92         $builtin = array ('float', 'double', 'bool', 'std::string', 'int', 'long', 'unsigned long', 'unsigned int', 'unsigned char', 'char', 'void', 'char*', 'unsigned char*', 'void*');
93         if (in_array ($arg, $builtin)) {
94                 return array ($arg => $flags);
95         }
96
97         # check Class declarations first
98         foreach (array_merge ($classes, $consts) as $b) {
99                 if ($b['ldec'] == $arg) {
100                         return array ($b['lua'] => $flags);
101                 }
102         }
103
104         # strip class pointers -- TODO Check C'tor for given class
105         $arg = preg_replace ('/[&*]*$/', '', $argtype);
106         foreach (array_merge ($classes, $consts) as $b) {
107                 if ($b['ldec'] == $arg) {
108                         return array ($b['lua'] => $flags);
109                 }
110         }
111         if ($flags & 2) {
112                 return array ($argtype => ($flags | 4));
113         } else {
114                 return array ('--MISSING (' . $argtype . ')--' => ($flags | 4));
115         }
116 }
117
118 function stripclass ($classname, $name) {
119         $classname .= ':';
120         if (strpos ($name, $classname) !== 0) {
121                 my_die ('invalid class prefix: ' .$classname. ' -- '. $name);
122         }
123         return substr ($name, strlen ($classname));
124 }
125
126 function datatype ($decl) {
127         # TODO handle spaces in type. Works because
128         # we don't yet have templated types (with_space <here >)
129         return substr ($decl, 0, strrpos ($decl, ' '));
130 }
131
132 function luafn2class ($lua) {
133         return substr ($lua, 0, strrpos ($lua, ':'));
134 }
135
136 function luafn2name ($lua) {
137         $fn = strrpos ($lua, ':');
138         if ($fn !== 0 && strlen($lua) > $fn + 1) {
139                 return substr ($lua, $fn + 1);
140         }
141         my_die ('invalid class prefix: '. $name);
142 }
143
144
145 function checkclass ($b) {
146         global $classlist;
147         if (!isset ($classlist[luafn2class ($b['lua'])])) {
148                 my_die ('MISSING CLASS FOR '. print_r ($b['lua'], true));
149         }
150 }
151
152 # parse functions argument list to lua-names
153 function decl2args ($decl) {
154         $start = strrpos ($decl, '(');
155         $end = strrpos ($decl, ')');
156         $args = substr ($decl, $start + 1, $end - $start - 1);
157         $arglist = preg_split ('/, */', $args);
158         $rv = array ();
159         foreach ($arglist as $a) {
160                 if (empty ($a)) { continue; }
161                 $rv[] = arg2lua ($a);
162         }
163         return $rv;
164 }
165
166 function canonical_ctor ($b) {
167         $rv = '';
168         if (preg_match('/[^(]*\(([^)*]*)\*\)(\(.*\))/', $b['decl'], $matches)) {
169                 $lc = luafn2class ($b['lua']);
170                 $cn = str_replace (':', '::', $lc);
171                 $fn = substr ($lc, 1 + strrpos ($lc, ':'));
172                 $rv = $cn . '::'. $fn . $matches[2];
173         }
174         return $rv;
175 }
176
177 function canonical_decl ($b) {
178         $rv = '';
179         $pfx = '';
180         # match clang's declatation format
181         if (preg_match('/[^(]*\(([^)*]*)\*\)\((.*)\)/', $b['decl'], $matches)) {
182                 if (strpos ($b['type'], 'Free Function') !== false) {
183                         $pfx = str_replace (':', '::', luafn2class ($b['lua'])) . '::';
184                 }
185                 $fn = substr ($b['lua'], 1 + strrpos ($b['lua'], ':'));
186                 $rv = $matches[1] . $fn . '(';
187                 $arglist = preg_split ('/, */', $matches[2]);
188                 $first = true;
189                 foreach ($arglist as $a) {
190                         if (!$first) { $rv .= ', '; }; $first = false;
191                         if (empty ($a)) { continue; }
192                         $a = preg_replace ('/([^>]) >/', '$1>', $a);
193                         $a = preg_replace ('/^Cairo::/', '', $a); // special case cairo enums
194                         $a = preg_replace ('/([^ ])&/', '$1 &', $a);
195                         $a = str_replace ('vector', 'std::vector', $a);
196                         $a = str_replace ('std::string', 'string', $a);
197                         $a = str_replace ('string const', 'const string', $a);
198                         $a = str_replace ('string', 'std::string', $a);
199                         $rv .= $a;
200                 }
201                 $rv .= ')';
202         }
203         return $pfx . $rv;
204 }
205
206 ################################################################################
207 # step 1: build class indices
208
209 foreach ($doc as $b) {
210         if (strpos ($b['type'], "[C] ") === 0) {
211                 $classes[] = $b;
212                 $classlist[$b['lua']] = $b;
213                 if (strpos ($b['type'], 'Pointer Class') === false) {
214                         $classdecl[$b['ldec']] = $b;
215                 }
216         }
217 }
218
219 foreach ($classes as $c) {
220         if (strpos ($c['type'], 'Pointer Class') !== false) { continue; }
221         if (isset ($c['parent'])) {
222                 if (isset ($classdecl[$c['parent']])) {
223                         $classlist[$c['lua']]['luaparent'][] = $classdecl[$c['parent']]['lua'];
224                 } else {
225                         my_die ('unknown parent class: ' . print_r ($c, true));
226                 }
227         }
228 }
229
230 # step 2: extract constants/enum
231 foreach ($doc as $b) {
232         switch ($b['type']) {
233         case "Constant/Enum":
234         case "Constant/Enum Member":
235                 if (strpos ($b['ldec'], '::') === false) {
236                         # for extern c enums, use the Lua Namespace
237                         $b['ldec'] = str_replace (':', '::', luafn2class ($b['lua']));
238                 }
239                 $ns = str_replace ('::', ':', $b['ldec']);
240                 $constlist[$ns][] = $b;
241                 # arg2lua lookup
242                 $b['lua'] = $ns;
243                 $consts[] = $b;
244                 break;
245         default:
246                 break;
247         }
248 }
249
250 # step 3: process functions
251 foreach ($doc as $b) {
252         switch ($b['type']) {
253         case "Constructor":
254         case "Weak/Shared Pointer Constructor":
255                 checkclass ($b);
256                 $classlist[luafn2class ($b['lua'])]['ctor'][] = array (
257                         'name' => luafn2class ($b['lua']),
258                         'args' => decl2args ($b['ldec']),
259                         'cand' => canonical_ctor ($b)
260                 );
261                 break;
262         case "Data Member":
263                 checkclass ($b);
264                 $classlist[luafn2class ($b['lua'])]['data'][] = array (
265                         'name' => $b['lua'],
266                         'ret'  => arg2lua (datatype ($b['ldec']))
267                 );
268                 break;
269         case "Static C Function":
270                 checkclass ($b);
271                 if (strpos ($b['lua'], 'ARDOUR:DataType:') === 0) {
272                         # special case ARDOUR:DataType convenience c'tor
273                         $args = array ();
274                         $ret = array (luafn2class ($b['lua']) => 0);
275                         $canon = 'ARDOUR::LuaAPI::datatype_ctor_'.strtolower (luafn2name ($b['lua'])).'(lua_State*)';
276                 } else {
277                         my_die ('unhandled Static C: ' . print_r($b, true));
278                 }
279                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
280                         'bind' => $b,
281                         'name' => $b['lua'],
282                         'args' => $args,
283                         'ret'  => $ret,
284                         'ref'  => false,
285                         'ext'  => false,
286                         'cand' => $canon
287                 );
288                 break;
289         case "C Function":
290                 # we required C functions to be in a class namespace
291         case "Ext C Function":
292                 checkclass ($b);
293                 $args = array (array ('--lua--' => 0));
294                 $ret = array ('...' => 0);
295                 $ns = luafn2class ($b['lua']);
296                 $cls = $classlist[$ns];
297                 if (preg_match ('/.*<([^>]*)[ ]*>/', $cls['ldec'], $templ)) {
298                         # std::vector, std::list types
299                         switch (stripclass($ns, $b['lua'])) {
300                         case 'add':
301                                 #$args = array (array ('LuaTable {'.$templ[1].'}' => 0));
302                                 $args = array (arg2lua ($templ[1], 2));
303                                 $ret = array ('LuaTable' => 0);
304                                 break;
305                         case 'iter':
306                                 $args = array ();
307                                 $ret = array ('LuaIter' => 0);
308                                 break;
309                         case 'table':
310                                 $args = array ();
311                                 $ret = array ('LuaTable' => 0);
312                                 break;
313                         default:
314                                 break;
315                         }
316                 } else if (strpos ($cls['type'], ' Array') !== false) {
317                         # catches  C:FloatArray, C:IntArray
318                         $templ = preg_replace ('/[&*]*$/', '', $cls['ldec']);
319                         switch (stripclass($ns, $b['lua'])) {
320                         case 'array':
321                                 $args = array ();
322                                 $ret = array ('LuaMetaTable' => 0);
323                                 break;
324                         case 'get_table':
325                                 $args = array ();
326                                 $ret = array ('LuaTable' => 0);
327                                 break;
328                         case 'set_table':
329                                 $args = array (array ('LuaTable {'.$templ.'}' => 0));
330                                 $ret = array ('void' => 0);
331                                 break;
332                         default:
333                                 break;
334                         }
335                 }
336                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
337                         'bind' => $b,
338                         'name' => $b['lua'],
339                         'args' => $args,
340                         'ret'  => $ret,
341                         'ref'  => true,
342                         'ext'  => true,
343                         'cand' => canonical_decl ($b)
344                 );
345                 break;
346         case "Free C Function":
347                 $funclist[luafn2class ($b['lua'])][] = array (
348                         'bind' => $b,
349                         'name' => $b['lua'],
350                         'args' => $args,
351                         'ret'  => $ret,
352                         'ref'  => false,
353                         'ext'  => true,
354                         'cand' => str_replace (':', '::', $b['lua']).'(lua_State*)'
355                 );
356                 break;
357         case "Free Function":
358         case "Free Function RefReturn":
359                 $funclist[luafn2class ($b['lua'])][] = array (
360                         'bind' => $b,
361                         'name' => $b['lua'],
362                         'args' => decl2args ($b['ldec']),
363                         'ret'  => arg2lua ($b['ret']),
364                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
365                         'cand' => canonical_decl ($b)
366                 );
367                 break;
368         case "Member Function":
369         case "Member Function RefReturn":
370         case "Member Pointer Function":
371         case "Weak/Shared Pointer Function":
372         case "Weak/Shared Pointer Function RefReturn":
373         case "Weak/Shared Null Check":
374         case "Weak/Shared Pointer Cast":
375         case "Static Member Function":
376                 checkclass ($b);
377                 $classlist[luafn2class ($b['lua'])]['func'][] = array (
378                         'bind' => $b,
379                         'name' => $b['lua'],
380                         'args' => decl2args ($b['ldec']),
381                         'ret'  => arg2lua ($b['ret']),
382                         'ref'  => (strpos ($b['type'], "RefReturn") !== false),
383                         'cand' => canonical_decl ($b)
384                 );
385                 break;
386         case "Constant/Enum":
387         case "Constant/Enum Member":
388                 # already handled -> $consts
389                 break;
390         default:
391                 if (strpos ($b['type'], "[C] ") !== 0) {
392                         my_die ('unhandled type: ' . $b['type']);
393                 }
394                 break;
395         }
396 }
397
398
399 # step 4: collect/group/sort
400
401 # step 4a: unify weak/shared Ptr classes
402 foreach ($classlist as $ns => $cl) {
403         if (strpos ($cl['type'], ' Array') !== false) {
404                 $classlist[$ns]['arr'] = true;
405                 continue;
406         }
407         foreach ($classes as $c) {
408                 if ($c['lua'] == $ns) {
409                         if (strpos ($c['type'], 'Pointer Class') !== false) {
410                                 $classlist[$ns]['ptr'] = true;
411                                 $classlist[$ns]['decl'] = 'boost::shared_ptr< '.$c['decl']. ' >, boost::weak_ptr< '.$c['decl']. ' >';
412                                 break;
413                         }
414                 }
415         }
416 }
417
418 # step4b: sanity check
419 foreach ($classlist as $ns => $cl) {
420         if (isset ($classes[$ns]['parent']) && !isset ($classlist[$ns]['luaparent'])) {
421                 my_die ('missing parent class: ' . print_r ($cl, true));
422         }
423 }
424
425 # step 4c: merge free functions into classlist
426 foreach ($funclist as $ns => $fl) {
427         if (isset ($classlist[$ns])) {
428                 my_die ('Free Funcion in existing namespace: '.$ns.' '. print_r ($ns, true));
429         }
430         $classlist[$ns]['func'] = $fl;
431         $classlist[$ns]['free'] = true;
432 }
433
434 # step 4d: order to chaos
435 # no array_multisort() here, sub-types are sorted after merging parents
436 ksort ($classlist);
437
438
439 ################################################################################
440 ################################################################################
441 ################################################################################
442
443
444 #### -- split here --  ####
445
446 # from here on, only $classlist and $constlist arrays are relevant.
447 # we also pull in C++ header annotation from doxygen to $api
448
449
450 # read documentation from doxygen
451 $json = gzdecode (file_get_contents (dirname (__FILE__).'/../doc/ardourapi.json.gz'));
452 $api = array ();
453 foreach (json_decode ($json, true) as $a) {
454         if (!isset ($a['decl'])) { continue; }
455         if (empty ($a['decl'])) { continue; }
456         $canon = str_replace (' *', '*', $a['decl']);
457         $api[$canon] = $a;
458 }
459
460 # keep track of found/missing doc
461 $dox_found = 0;
462 $dox_miss = 0;
463
464 # retrive a value from $api
465 function doxydoc ($canonical_declaration) {
466         global $api;
467         global $dox_found;
468         global $dox_miss;
469         if (isset ($api[$canonical_declaration])) {
470                 $dox_found++;
471                 return $api[$canonical_declaration]['doc'];
472         } else {
473                 $dox_miss++;
474                 return '';
475         }
476 }
477
478 ################################################################################
479 # OUTPUT
480 ################################################################################
481
482
483 ################################################################################
484 # Helper functions
485 define ('NL', "\n");
486
487 # constructors, enums (constants) use a dot.  (e.g. "LuaOSC.Address" -> "LuaOSC.Address" )
488 function ctorname ($name) {
489         return htmlentities (str_replace (':', '.', $name));
490 }
491
492 # strip class prefix (e.g "Evoral:MidiEvent:channel"  -> "channel")
493 function shortname ($name) {
494         return htmlentities (substr ($name, strrpos ($name, ':') + 1));
495 }
496
497 # retrieve variable name from    array["VARNAME"] => FLAGS
498 function varname ($a) {
499         return array_keys ($a)[0];
500 }
501
502 # recusively collect class parents (derived classes)
503 function traverse_parent ($ns, &$inherited) {
504         global $classlist;
505         $rv = '';
506         if (isset ($classlist[$ns]['luaparent'])) {
507                 $parents = array_unique ($classlist[$ns]['luaparent']);
508                 asort ($parents);
509                 foreach ($parents as $p) {
510                         if (!empty ($rv)) { $rv .= ', '; }
511                         $rv .= typelink ($p);
512                         $inherited[$p] = $classlist[$p];
513                         traverse_parent ($p, $inherited);
514                 }
515         }
516         return $rv;
517 }
518
519 # create a cross-reference to a type (class or enum)
520 # *all* <a> links are generated here, currently anchors on a single page.
521 function typelink ($a, $short = false, $argcls = '', $linkcls = '', $suffix = '') {
522         global $classlist;
523         global $constlist;
524         if (isset($classlist[$a]['free'])) {
525                 return '<a class="'.$linkcls.'" href="#'.htmlentities ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
526         } else if (in_array ($a, array_keys ($classlist))) {
527                 return '<a class="'.$linkcls.'" href="#'.htmlentities($a).'">'.($short ? shortname($a) : htmlentities($a)).$suffix.'</a>';
528         } else if (in_array ($a, array_keys ($constlist))) {
529                 return '<a class="'.$linkcls.'" href="#'.ctorname ($a).'">'.($short ? shortname($a) : ctorname($a)).$suffix.'</a>';
530         } else {
531                 return '<span class="'.$argcls.'">'.htmlentities($a).$suffix.'</span>';
532         }
533 }
534
535 # output format function arguments
536 function format_args ($args) {
537         $rv = '<span class="functionargs"> (';
538         $first = true;
539         foreach ($args as $a) {
540                 if (!$first) { $rv .= ', '; }; $first = false;
541                 $flags = $a[varname ($a)];
542                 if ($flags & 2) {
543                         $rv .= '<em>LuaTable</em> {'.typelink (varname ($a), true, 'em').'}';
544                 }
545                 elseif ($flags & 1) {
546                         $rv .= typelink (varname ($a), true, 'em', '', '&amp;');
547                 }
548                 else {
549                         $rv .= typelink (varname ($a), true, 'em');
550                 }
551         }
552         $rv .= ')</span>';
553         return $rv;
554 }
555
556 # format doxygen documentation for class-definition
557 function format_doxyclass ($cl) {
558         $rv = '';
559         if (isset ($cl['decl'])) {
560                 $doc = doxydoc ($cl['decl']);
561                 if (!empty ($doc)) {
562                         $rv.= '<div class="classdox">'.$doc.'</div>'.NL;
563                 }
564         }
565         return $rv;
566 }
567
568 # format doxygen documentation for class-members
569 function format_doxydoc ($f) {
570         $rv = '';
571         if (isset ($f['cand'])) {
572                 $doc = doxydoc ($f['cand']);
573                 if (!empty ($doc)) {
574                         $rv.= '<tr><td></td><td class="doc" colspan="2"><div class="dox">'.$doc;
575                         $rv.= '</div></td></tr>'.NL;
576                 } else if (0) { # debug
577                         $rv.= '<tr><td></td><td class="doc" colspan="2"><p>'.htmlentities($f['cand']).'</p>';
578                         $rv.= '</td></tr>'.NL;
579                 }
580         }
581         return $rv;
582 }
583
584 # usort() callback for class-members
585 function name_sort_cb ($a, $b) {
586         return strcmp ($a['name'], $b['name']);
587 }
588
589 # main output function for every class
590 function format_class_members ($ns, $cl, &$dups) {
591         $rv = '';
592         # print contructor - if any
593         if (isset ($cl['ctor'])) {
594                 usort ($cl['ctor'], 'name_sort_cb');
595                 $rv.= ' <tr><th colspan="3">Constructor</th></tr>'.NL;
596                 foreach ($cl['ctor'] as $f) {
597                         $rv.= ' <tr><td class="def">&Copf;</td><td class="decl">';
598                         $rv.= '<span class="functionname">'.ctorname ($f['name']).'</span>';
599                         $rv.= format_args ($f['args']);
600                         $rv.= '</td><td class="fill"></td></tr>'.NL;
601                         # doxygen documentation (may be empty)
602                         $rv.= format_doxydoc($f);
603                 }
604         }
605
606         # strip duplicates (inherited or derived methods)
607         # e.g  AudioTrack -> Track -> Route -> SessionObject -> Stateful
608         # all 5 have "isnil()"
609         $nondups = array ();
610         if (isset ($cl['func'])) {
611                 foreach ($cl['func'] as $f) {
612                         if (in_array (stripclass ($ns, $f['name']), $dups)) { continue; }
613                         $nondups[] = $f;
614                 }
615         }
616
617         # print methods - if any
618         if (count ($nondups) > 0) {
619                 usort ($nondups, 'name_sort_cb');
620                 $rv.= ' <tr><th colspan="3">Methods</th></tr>'.NL;
621                 foreach ($nondups as $f) {
622                         $dups[] = stripclass ($ns, $f['name']);
623                         # return value/type
624                         $rv.= ' <tr><td class="def">';
625                         if ($f['ref'] && isset ($f['ext'])) {
626                                 # external C functions
627                                 $rv.= '<em>'.varname ($f['ret']).'</em>';
628                         } elseif ($f['ref'] && varname ($f['ret']) == 'void') {
629                                 # void functions with reference args
630                                 $rv.= '<em>LuaTable</em>(...)';
631                         } elseif ($f['ref']) {
632                                 # functions with reference args and return value
633                                 $rv.= '<em>LuaTable</em>('.typelink (varname ($f['ret']), true, 'em').', ...)';
634                         } else {
635                                 # normal class members
636                                 $rv.= typelink (varname ($f['ret']), true, 'em');
637                         }
638                         # function declaration and arguments
639                         $rv.= '</td><td class="decl">';
640                         $rv.= '<span class="functionname"><abbr title="'.htmlentities($f['bind']['decl']).'">'.stripclass ($ns, $f['name']).'</abbr></span>';
641                         $rv.= format_args ($f['args']);
642                         $rv.= '</td><td class="fill"></td></tr>'.NL;
643                         # doxygen documentation (may be empty)
644                         $rv.= format_doxydoc($f);
645                 }
646         }
647         # print data members - if any
648         if (isset ($cl['data'])) {
649                 usort ($cl['data'], 'name_sort_cb');
650                 $rv.= ' <tr><th colspan="3">Data Members</th></tr>'.NL;
651                 foreach ($cl['data'] as $f) {
652                         $rv.= ' <tr><td class="def">'.typelink (array_keys ($f['ret'])[0], false, 'em').'</td><td class="decl">';
653                         $rv.= '<span class="functionname">'.stripclass ($ns, $f['name']).'</span>';
654                         $rv.= '</td><td class="fill"></td></tr>'.NL;
655                 }
656         }
657         return $rv;
658 }
659
660
661 ################################################################################
662 # Start Output
663
664 if ($HTMLOUTPUT) {
665
666 ?><!DOCTYPE html>
667 <html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
668 <head>
669 <title>Ardour Lua Bindings</title>
670 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
671 <style type="text/css">
672 div.header         { text-align:center; }
673 div.header h2      { margin:0; }
674 div.header p       { margin:.25em; text-align:center; }
675 div.luafooter      { text-align:center; font-size:80%; color: #888; margin: 2em 0; }
676 #luaref            { max-width:60em; margin: 1em auto; }
677
678 #luaref h2                 { margin:2em 0 0 0; padding:0em; border-bottom: 1px solid black; }
679 #luaref h3.cls             { margin:2em 0 0 0; padding: 0 0 0 1em; border: 1px dashed #6666ee; }
680 #luaref h3.cls abbr        { text-decoration:none; cursor:default; }
681 #luaref h4.cls             { margin:1em 0 0 0; }
682 #luaref h3.class           { background-color: #aaee66; }
683 #luaref h3.enum            { background-color: #aaaaaa; }
684 #luaref h3.pointerclass    { background-color: #eeaa66; }
685 #luaref h3.array           { background-color: #66aaee; }
686 #luaref h3.opaque          { background-color: #6666aa; }
687 #luaref p                  { text-align: justify; }
688 #luaref p.cdecl            { text-align: right; float:right; font-size:90%; margin:0; padding: 0 0 0 1em; }
689 #luaref ul.classindex      { columns: 2; -webkit-columns: 2; -moz-columns: 2; }
690 #luaref div.clear          { clear:both; }
691 #luaref p.classinfo        { margin: .25em 0; }
692 #luaref div.code           { width:80%; margin:.5em auto; }
693 #luaref div.code div       { width:45%; }
694 #luaref div.code pre       { line-height: 1.2em; margin: .25em 0; }
695 #luaref div.code samp      { color: green; font-weight: bold; background-color: #eee; }
696 #luaref div.classdox       { padding: .1em 1em; }
697 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
698 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
699 #luaref div.classdox       { padding: .1em 1em; }
700 #luaref div.classdox p     { margin: .5em 0 .5em .6em; }
701 #luaref table.classmembers { width: 100%; }
702 #luaref table.classmembers th      { text-align:left; border-bottom:1px solid black; padding-top:1em; }
703 #luaref table.classmembers td.def  { text-align:right; padding-right:.5em;  white-space: nowrap; }
704 #luaref table.classmembers td.decl { text-align:left; padding-left:.5em; white-space: nowrap; }
705 #luaref table.classmembers td.doc  { text-align:left; padding-left:.6em; line-height: 1.2em; font-size:80%; }
706 #luaref table.classmembers td.doc div.dox {background-color:#eee; padding: .1em 1em; }
707 #luaref table.classmembers td.doc p { margin: .5em 0; }
708 #luaref table.classmembers td.doc p.para-brief { font-size:120%; }
709 #luaref table.classmembers td.doc p.para-returns { font-size:120%; }
710 #luaref table.classmembers td.doc dl { font-size:120%; line-height: 1.3em; }
711 #luaref table.classmembers td.doc dt { font-style: italic; }
712 #luaref table.classmembers td.fill { width: 99%; }
713 #luaref table.classmembers span.em { font-style: italic; }
714 #luaref span.functionname abbr     { text-decoration:none; cursor:default; }
715 </style>
716 </head>
717 <body>
718 <div class="header">
719 <h2>Ardour Lua Bindings</h2>
720 <p>
721 <a href="#h_classes">Class Documentation</a>
722 &nbsp;|&nbsp;
723 <a href="#h_enum">Enum/Constants</a>
724 &nbsp;|&nbsp;
725 <a href="#h_index">Index</a>
726 </p>
727 </div>
728
729 <!-- #### SNIP #### !-->
730
731 <?php
732
733 } else {
734
735 ?>
736 ---
737 layout: default
738 style: luadoc
739 title: Class Reference
740 ---
741
742 <p class="warning">
743 This documention is far from complete may be inaccurate and subject to change.
744 </p>
745
746 <?php
747 }
748 ?>
749
750 <div id="luaref">
751
752 <?php
753
754 ################################################################################
755 # some general documentation -- should really go elsehere
756
757 ?>
758
759 <h2 id="h_intro">Overview</h2>
760 <p>
761 The top-level entry point are <?=typelink('ARDOUR:Session')?> and <?=typelink('ArdourUI:Editor')?>.
762 Most other Classes are used indirectly starting with a Session function. e.g. Session:get_routes().
763 </p>
764 <p>
765 A few classes are dedicated to certain script types, e.g. Lua DSP processors have exclusive access to
766 <?=typelink('ARDOUR:DSP')?> and <?=typelink('ARDOUR:ChanMapping')?>. Action Hooks Scripts to
767 <?=typelink('LuaSignal:Set')?> etc.
768 </p>
769 <p>
770 Detailed documentation (parameter names, method description) is not yet available. Please stay tuned.
771 </p>
772 <h3>Short introduction to Ardour classes</h3>
773 <p>
774 Ardour's structure is object oriented. The main object is the Session. A Session contains Audio Tracks, Midi Tracks and Busses.
775 Audio and Midi tracks are derived from a more general "Track" Object,  which in turn is derived from a "Route" (aka Bus).
776 (We say "An Audio Track <em>is-a</em> Track <em>is-a</em> Route").
777 Tracks contain specifics. For Example a track <em>has-a</em> diskstream (for file i/o).
778 </p>
779 <p>
780 Operations are performed on objects. One gets a reference to an object and then calls a method.
781 e.g <code>obj = Session:route_by_name("Audio")   obj:set_name("Guitar")</code>.
782 </p>
783 <p>
784 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:
785 you cannot simply remove a track that is currently processing audio. There are various <em>factory</em> methods for object creation or removal.
786 </p>
787 <h3>Pass by Reference</h3>
788 <p>
789 Since lua functions are closures, C++ methods that pass arguments by reference cannot be used as-is.
790 All parameters passed to a C++ method which uses references are returned as Lua Table.
791 If the C++ method also returns a value it is prefixed. Two parameters are returned: the value and a Lua Table holding the parameters.
792 </p>
793
794 <div class="code">
795         <div style="float:left;">C++
796
797 <pre><code class="cxx">void set_ref (int&amp; var, long&amp; val)
798 {
799         printf ("%d %ld\n", var, val);
800         var = 5;
801         val = 7;
802 }
803 </code></pre>
804
805         </div>
806         <div style="float:right;">Lua
807
808 <pre><code class="lua">local var = 0;
809 ref = set_ref (var, 2);
810 -- output from C++ printf()
811 </code><samp class="lua">0 2</samp><code>
812 -- var is still 0 here
813 print (ref[1], ref[2])
814 </code><samp class="lua">5 7</samp></pre>
815
816         </div>
817 </div>
818 <div class="clear"></div>
819 <div class="code">
820         <div style="float:left;">
821
822 <pre><code class="cxx">int set_ref2 (int &amp;var, std::string unused)
823 {
824         var = 5;
825         return 3;
826 }
827 </code></pre>
828
829         </div>
830         <div style="float:right;">
831 <pre><code class="lua">rv, ref = set_ref2 (0, "hello");
832 print (rv, ref[1], ref[2])
833 </code><samp class="lua">3 5 hello</samp></pre>
834         </div>
835 </div>
836 <div class="clear"></div>
837
838 <h3>Pointer Classes</h3>
839 <p>
840 Libardour makes extensive use of reference counted <code>boost::shared_ptr</code> to manage lifetimes.
841 The Lua bindings provide a complete abstration of this. There are no pointers in lua.
842 For example a <?=typelink('ARDOUR:Route')?> is a pointer in C++, but lua functions operate on it like it was a class instance.
843 </p>
844 <p>
845 <code>shared_ptr</code> are reference counted. Once assigned to a lua variable, the C++ object will be kept and remains valid.
846 It is good practice to assign references to lua <code>local</code> variables or reset the variable to <code>nil</code> to drop the ref.
847 </p>
848 <p>
849 All pointer classes have a <code>isnil ()</code> method. This is for two cases:
850 Construction may fail. e.g. <code><?=typelink('ARDOUR:LuaAPI')?>.newplugin()</code>
851 may not be able to find the given plugin and hence cannot create an object.
852 </p>
853 <p>
854 The second case if for <code>boost::weak_ptr</code>. As opposed to <code>boost::shared_ptr</code> weak-pointers are not reference counted.
855 The object may vanish at any time.
856 If lua code calls a method on a nil object, the interpreter will raise an exception and the script will not continue.
857 This is not unlike <code>a = nil a:test()</code> which results in en error "<em>attempt to index a nil value</em>".
858 </p>
859 <p>
860 From the lua side of things there is no distinction between weak and shared pointers. They behave identically.
861 Below they're inidicated in orange and have an arrow to indicate the pointer type.
862 Pointer Classes cannot be created in lua scripts. It always requires a call to C++ to create the Object and obtain a reference to it.
863 </p>
864
865
866 <?php
867
868 #################################
869 # Main output function -- Classes
870
871 echo '<h2 id="h_classes">Class Documentation</h2>'.NL;
872 foreach ($classlist as $ns => $cl) {
873         $dups = array ();
874         $tbl =  format_class_members ($ns, $cl, $dups);
875
876         # format class title - depending on type
877         if (empty ($tbl)) {
878                 # classes with no members (no ctor, no methods, no data)
879                 echo '<h3 id="'.htmlentities ($ns).'" class="cls opaque"><abbr title="Opaque Object">&empty;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
880         }
881         else if (isset ($classlist[$ns]['free'])) {
882                 # free functions (no class)
883                 echo '<h3 id="'.htmlentities ($ns).'" class="cls freeclass"><abbr title="Namespace">&Nopf;</abbr>&nbsp;'.ctorname($ns).'</h3>'.NL;
884         }
885         else if (isset ($classlist[$ns]['arr'])) {
886                 # C Arrays
887                 echo '<h3 id="'.htmlentities ($ns).'" class="cls array"><abbr title="C Array">&ctdot;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
888         }
889         else if (isset ($classlist[$ns]['ptr'])) {
890                 # Pointer Classes
891                 echo '<h3 id="'.htmlentities ($ns).'" class="cls pointerclass"><abbr title="Pointer Class">&Rarr;</abbr>&nbsp;'. htmlentities ($ns).'</h3>'.NL;
892         }
893         else {
894                 # Normal Class
895                 echo '<h3 id="'.htmlentities ($ns).'" class="cls class"><abbr title="Class">&comp;</abbr>&nbsp;'.htmlentities ($ns).'</h3>'.NL;
896         }
897
898         # show original C++ declaration
899         if (isset ($cl['decl'])) {
900                 echo '<p class="cdecl"><em>C&#8225;</em>: '.htmlentities ($cl['decl']).'</p>'.NL;
901         }
902
903         # print class inheritance (direct parent *name* only)
904         $inherited = array ();
905         $isa = traverse_parent ($ns, $inherited);
906         if (!empty ($isa)) {
907                 echo ' <p class="classinfo">is-a: '.$isa.'</p>'.NL;
908         }
909         echo '<div class="clear"></div>'.NL;
910
911
912         # class documentation (if any)
913         echo format_doxyclass ($cl);
914
915         # member documentation
916         if (empty ($tbl)) {
917                 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;
918         } else {
919                 echo '<table class="classmembers">'.NL;
920                 echo $tbl;
921                 echo ' </table>'.NL;
922         }
923
924         # traverse parent classes (all inherited members)
925         foreach ($inherited as $pns => $pcl) {
926                 $tbl = format_class_members ($pns, $pcl, $dups);
927                 if (!empty ($tbl)) {
928                         echo '<h4 class="cls">Inherited from '.$pns.'</h4>'.NL;
929                         echo '<table class="classmembers">'.NL;
930                         echo $tbl;
931                         echo '</table>'.NL;
932                 }
933         }
934 }
935
936 ####################
937 # Enum and Constants
938
939 echo '<h2 id="h_enum">Enum/Constants</h2>'.NL;
940 foreach ($constlist as $ns => $cs) {
941         echo '<h3 id="'.ctorname ($ns).'" class="cls enum"><abbr title="Enum">&isin;</abbr>&nbsp;'.ctorname ($ns).'</h3>'.NL;
942         echo '<ul class="enum">'.NL;
943         foreach ($cs as $c) {
944                 echo '<li class="const">'.ctorname ($c['lua']).'</li>'.NL;
945         }
946         echo '</ul>'.NL;
947 }
948
949 ######################
950 # Index of all classes
951
952 echo '<h2 id="h_index" >Class Index</h2>'.NL;
953 echo '<ul class="classindex">'.NL;
954 foreach ($classlist as $ns => $cl) {
955         echo '<li>'.typelink($ns).'</li>'.NL;
956 }
957 echo '</ul>'.NL;
958
959
960 # see how far there is still to go...
961 fwrite (STDERR, "Found $dox_found annotations. missing: $dox_miss\n");
962 echo '<!-- '.$dox_found.' / '.$dox_miss.' !-->'.NL;
963
964 ?>
965 </div>
966 <div class="luafooter">Ardour <?=$ardourversion?> &nbsp;-&nbsp; <?=date('r')?></div>
967 <?php
968
969 if ($HTMLOUTPUT) {
970         echo '<!-- #### SNIP #### !-->'.NL;
971         echo '</body>'.NL;
972         echo '</html>'.NL;
973 }