~ubuntu-branches/ubuntu/oneiric/haxe/oneiric

« back to all changes in this revision

Viewing changes to haxe/std/tools/haxedoc/HtmlPrinter.hx

  • Committer: Bazaar Package Importer
  • Author(s): Jens Peter Secher
  • Date: 2008-06-15 11:04:09 UTC
  • mfrom: (2.1.6 intrepid)
  • Revision ID: james.westby@ubuntu.com-20080615110409-7pyykgwmk5v0cues
Tags: 1:1.19-3
* Remove bashism in script.
  (Closes: #484390)
* Upgrade to Policy 3.8.0 by including a README.source explaining how to
  use dpatch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package tools.haxedoc;
 
2
import haxe.rtti.Type;
 
3
 
 
4
class HtmlPrinter {
 
5
 
 
6
        static function loadTemplate() {
 
7
                var hdata = try
 
8
                        // load in current local/web directory
 
9
                        neko.io.File.getContent(neko.Web.getCwd()+"template.xml")
 
10
                catch( e : Dynamic ) try {
 
11
                        // load in haxe subdirectory (TODO : make it work on linux/osx)
 
12
                        var p = ~/[\/\\]/g.split(neko.Sys.executablePath());
 
13
                        p.pop();
 
14
                        neko.io.File.getContent(p.join("/")+"/std/tools/template.xml");
 
15
                } catch( e : Dynamic )
 
16
                        default_template;
 
17
                return Xml.parse(hdata);
 
18
        }
 
19
 
 
20
        static var default_template = "<html><body><data/></body></html>";
 
21
        static var template = loadTemplate();
 
22
 
 
23
        public var baseUrl : String;
 
24
        var indexUrl : String;
 
25
        var fileExtension : String;
 
26
        var curpackage : String;
 
27
        var filters : List<String>;
 
28
        var typeParams : TypeParams;
 
29
 
 
30
        public function new( baseUrl, fileExtension, indexUrl ) {
 
31
                this.baseUrl = baseUrl;
 
32
                this.fileExtension = fileExtension;
 
33
                this.indexUrl = indexUrl;
 
34
                filters = new List();
 
35
                typeParams = new Array();
 
36
        }
 
37
 
 
38
        public function output(str) {
 
39
                neko.Lib.print(str);
 
40
        }
 
41
 
 
42
        public function addFilter(f) {
 
43
                filters.add(f);
 
44
        }
 
45
 
 
46
        public function print(str, ?params : Dynamic ) {
 
47
                if( params != null )
 
48
                        for( f in Reflect.fields(params) )
 
49
                                str = StringTools.replace(str, "$"+f, Std.string(Reflect.field(params, f)));
 
50
                output(str);
 
51
        }
 
52
 
 
53
        public function process(t) {
 
54
                processHtml(t,template);
 
55
        }
 
56
 
 
57
        public function filtered( path : Path, isPackage : Bool ) {
 
58
                if( isPackage && path == "Remoting" )
 
59
                        return true;
 
60
                if( StringTools.endsWith(path,"__") )
 
61
                        return true;
 
62
                if( filters.isEmpty() )
 
63
                        return false;
 
64
                for( x in filters )
 
65
                        if( StringTools.startsWith(path,x) )
 
66
                                return false;
 
67
                return true;
 
68
        }
 
69
 
 
70
        function makeUrl( url, text, css ) {
 
71
                return "<a href=\"" + baseUrl + url + fileExtension + "\" class=\""+css+"\">"+text+"</a>";
 
72
        }
 
73
 
 
74
        function prefix( arr : Array<String>, path : String ) {
 
75
                var arr = arr.copy();
 
76
                for( i in 0...arr.length )
 
77
                        arr[i] = path + "." + arr[i];
 
78
                return arr;
 
79
        }
 
80
 
 
81
        function makePathUrl( path : Path, css ) {
 
82
                var p = path.split(".");
 
83
                var name = p.pop();
 
84
                var local = (p.join(".") == curpackage);
 
85
                for( x in typeParams )
 
86
                        if( x == path )
 
87
                                return name;
 
88
                p.push(name);
 
89
                if( local )
 
90
                        return makeUrl(p.join("/"),name,css);
 
91
                return makeUrl(p.join("/"),fmtpath(path),css);
 
92
        }
 
93
 
 
94
        function fmtpath(path : String) {
 
95
                if( path.substr(0,7) == "flash9." )
 
96
                        return "flash."+path.substr(7);
 
97
                var pack = path.split(".");
 
98
                if( pack.length > 1 && pack[pack.length-2].charAt(0) == "_" ) {
 
99
                        pack.splice(-2,1);
 
100
                        path = pack.join(".");
 
101
                }
 
102
                return path;
 
103
        }
 
104
 
 
105
        public function processHtml(t,html : Xml) {
 
106
                var ht = html.nodeType;
 
107
                if( ht == Xml.Element ) {
 
108
                        if( html.nodeName == "data" ) {
 
109
                                processPage(t);
 
110
                                return;
 
111
                        }
 
112
                        if( !html.iterator().hasNext() ) {
 
113
                                print(html.toString());
 
114
                                return;
 
115
                        }
 
116
                        print("<");
 
117
                        print(html.nodeName);
 
118
                        for( k in html.attributes() )
 
119
                                print(" "+k+"=\""+html.get(k)+"\"");
 
120
                        print(">");
 
121
                        for( x in html )
 
122
                                processHtml(t,x);
 
123
                        print("</"+html.nodeName+">");
 
124
                } else if( ht == Xml.Document )
 
125
                        for( x in html )
 
126
                                processHtml(t,x);
 
127
                else
 
128
                        print(html.toString());
 
129
        }
 
130
 
 
131
        public function processPage(t) {
 
132
                switch(t) {
 
133
                case TPackage(p,full,list):
 
134
                        processPackage(p,list);
 
135
                default:
 
136
                        var head = '<a href="#" onclick="javascript:history.back(-1); return false" class="index">Back</a> | '+makeUrl(indexUrl,"Index","index");
 
137
                        print(head);
 
138
                        var inf = TypeApi.typeInfos(t);
 
139
                        typeParams = prefix(inf.params,inf.path);
 
140
                        var p = inf.path.split(".");
 
141
                        p.pop();
 
142
                        curpackage = p.join(".");
 
143
                        switch(t) {
 
144
                        case TClassdecl(c): processClass(c);
 
145
                        case TEnumdecl(e): processEnum(e);
 
146
                        case TTypedecl(t): processTypedef(t);
 
147
                        case TPackage(_,_,_): throw "ASSERT";
 
148
                        }
 
149
                        print(head);
 
150
                }
 
151
        }
 
152
 
 
153
        function processPackage(name,list : Array<TypeTree> ) {
 
154
                print('<ul class="entry">');
 
155
                for( e in list ) {
 
156
                        switch e {
 
157
                        case TPackage(name,full,list):
 
158
                                if( filtered(full,true) )
 
159
                                        continue;
 
160
                                var isPrivate = name.charAt(0) == "_";
 
161
                                if( !isPrivate )
 
162
                                        print('<li><a href="#" class="package" onclick="return toggle(\'$id\')">$name</a><div id="$id" class="package_content">', { id : full.split(".").join("_"), name : name });
 
163
                                var old = curpackage;
 
164
                                curpackage = full;
 
165
                                processPackage(name,list);
 
166
                                curpackage = old;
 
167
                                if( !isPrivate )
 
168
                                        print("</div></li>");
 
169
                        default:
 
170
                                var i = TypeApi.typeInfos(e);
 
171
                                if( i.isPrivate || i.path == "@Main" || filtered(i.path,false) )
 
172
                                        continue;
 
173
                                print("<li>"+makePathUrl(i.path,"entry")+"</li>");
 
174
                        }
 
175
                }
 
176
                print("</ul>");
 
177
        }
 
178
 
 
179
        function processInfos(t : TypeInfos) {
 
180
                if( t.module != null )
 
181
                        print('<div class="importmod">import $module</div>',{ module : t.module });
 
182
                if( !t.platforms.isEmpty() ) {
 
183
                        print('<div class="platforms">Available in ');
 
184
                        display(t.platforms,output,", ");
 
185
                        print('</div>');
 
186
                }
 
187
                if( t.doc != null ) {
 
188
                        print('<div class="classdoc">');
 
189
                        processDoc(t.doc);
 
190
                        print('</div>');
 
191
                }
 
192
        }
 
193
 
 
194
        function processClass(c : Classdef) {
 
195
                print('<div class="classname">');
 
196
                if( c.isExtern )
 
197
                        keyword("extern");
 
198
                if( c.isPrivate )
 
199
                        keyword("private");
 
200
                if( c.isInterface )
 
201
                        keyword("interface");
 
202
                else
 
203
                        keyword("class");
 
204
                print(fmtpath(c.path));
 
205
                if( c.params.length != 0 ) {
 
206
                        print("&lt;");
 
207
                        print(c.params.join(", "));
 
208
                        print("&gt;");
 
209
                }
 
210
                print('</div>');
 
211
                if( c.superClass != null ) {
 
212
                        print('<div class="extends">extends ');
 
213
                        processPath(c.superClass.path,c.superClass.params);
 
214
                        print('</div>');
 
215
                }
 
216
                for( i in c.interfaces ) {
 
217
                        print('<div class="implements">implements ');
 
218
                        processPath(i.path,i.params);
 
219
                        print('</div>');
 
220
                }
 
221
                if( c.dynamic != null ) {
 
222
                        var d = new List();
 
223
                        d.add(c.dynamic);
 
224
                        print('<div class="implements">implements ');
 
225
                        processPath("Dynamic",d);
 
226
                        print('</div>');
 
227
                }
 
228
                processInfos(c);
 
229
                print('<dl>');
 
230
                for( f in c.fields )
 
231
                        processClassField(c.platforms,f,false);
 
232
                for( f in c.statics )
 
233
                        processClassField(c.platforms,f,true);
 
234
                print('</dl>');
 
235
        }
 
236
 
 
237
        function processClassField(platforms : Platforms,f : ClassField,stat) {
 
238
                if( !f.isPublic )
 
239
                        return;
 
240
                var oldParams = typeParams;
 
241
                if( f.params != null )
 
242
                        typeParams = typeParams.concat(prefix(f.params,f.name));
 
243
                print('<dt>');
 
244
                if( stat ) keyword("static");
 
245
                var isMethod = false;
 
246
                switch( f.type ) {
 
247
                case TFunction(args,ret):
 
248
                        if( f.get == RNormal && (f.set == RNormal || f.set == RF9Dynamic) ) {
 
249
                                isMethod = true;
 
250
                                if( f.set == RF9Dynamic )
 
251
                                        keyword("f9dynamic");
 
252
                                keyword("function");
 
253
                                print(f.name);
 
254
                                if( f.params != null )
 
255
                                        print("&lt;"+f.params.join(", ")+"&gt;");
 
256
                                print("(");
 
257
                                var me = this;
 
258
                                display(args,function(a) {
 
259
                                        if( a.opt )
 
260
                                                me.print("?");
 
261
                                        if( a.name != null && a.name != "" ) {
 
262
                                                me.print(a.name);
 
263
                                                me.print(" : ");
 
264
                                        }
 
265
                                        me.processType(a.t);
 
266
                                },", ");
 
267
                                print(") : ");
 
268
                                processType(ret);
 
269
                        }
 
270
                default:
 
271
                }
 
272
                if( !isMethod ) {
 
273
                        keyword("var");
 
274
                        print(f.name);
 
275
                        if( f.get != RNormal || f.set != RNormal )
 
276
                                print("("+rightsStr(f.get)+","+rightsStr(f.set)+")");
 
277
                        print(" : ");
 
278
                        processType(f.type);
 
279
                }
 
280
                if( f.platforms.length != platforms.length ) {
 
281
                        print('<div class="platforms">Available in ');
 
282
                        display(f.platforms,output,", ");
 
283
                        print('</div>');
 
284
                }
 
285
                print('</dt>');
 
286
                print('<dd>');
 
287
                processDoc(f.doc);
 
288
                print('</dd>');
 
289
                if( f.params != null )
 
290
                        typeParams = oldParams;
 
291
        }
 
292
 
 
293
        function processEnum(e : Enumdef) {
 
294
                print('<div class="classname">');
 
295
                if( e.isExtern )
 
296
                        keyword("extern");
 
297
                if( e.isPrivate )
 
298
                        keyword("private");
 
299
                keyword("enum");
 
300
                print(fmtpath(e.path));
 
301
                if( e.params.length != 0 ) {
 
302
                        print("&lt;");
 
303
                        print(e.params.join(", "));
 
304
                        print("&gt;");
 
305
                }
 
306
                print('</div>');
 
307
                processInfos(e);
 
308
                print('<dl>');
 
309
                for( c in e.constructors ) {
 
310
                        print('<dt>');
 
311
                        print(c.name);
 
312
                        if( c.args != null ) {
 
313
                                print("(");
 
314
                                var me = this;
 
315
                                display(c.args,function(a) {
 
316
                                        if( a.opt )
 
317
                                                me.print("?");
 
318
                                        me.print(a.name);
 
319
                                        me.print(" : ");
 
320
                                        me.processType(a.t);
 
321
                                },",");
 
322
                                print(")");
 
323
                        }
 
324
                        print("</dt>");
 
325
                        print("<dd>");
 
326
                        processDoc(c.doc);
 
327
                        print("</dd>");
 
328
                }
 
329
                print('</dl>');
 
330
        }
 
331
 
 
332
        function processTypedef(t : Typedef) {
 
333
                print('<div class="classname">');
 
334
                if( t.isPrivate )
 
335
                        keyword("private");
 
336
                keyword("typedef");
 
337
                print(fmtpath(t.path));
 
338
                if( t.params.length != 0 ) {
 
339
                        print("&lt;");
 
340
                        print(t.params.join(", "));
 
341
                        print("&gt;");
 
342
                }
 
343
                print('</div>');
 
344
                processInfos(t);
 
345
                if( t.platforms.length == 0 ) {
 
346
                        processTypedefType(t.type,t.platforms,t.platforms);
 
347
                        return;
 
348
                }
 
349
                var platforms = new List();
 
350
                for( p in t.platforms )
 
351
                        platforms.add(p);
 
352
                for( p in t.types.keys() ) {
 
353
                        var td = t.types.get(p);
 
354
                        var support = new List();
 
355
                        for( p2 in platforms )
 
356
                                if( TypeApi.typeEq(td,t.types.get(p2)) ) {
 
357
                                        platforms.remove(p2);
 
358
                                        support.add(p2);
 
359
                                }
 
360
                        if( support.length == 0 )
 
361
                                continue;
 
362
                        processTypedefType(td,t.platforms,support);
 
363
                }
 
364
        }
 
365
 
 
366
        function processTypedefType(t,all,platforms) {
 
367
                switch( t ) {
 
368
                case TAnonymous(fields):
 
369
                        print('<dl>');
 
370
                        for( f in fields ) {
 
371
                                processClassField(all,{
 
372
                                        name : f.name,
 
373
                                        type : f.t,
 
374
                                        isPublic : true,
 
375
                                        doc : null,
 
376
                                        get : RNormal,
 
377
                                        set : RNormal,
 
378
                                        params : null,
 
379
                                        platforms : platforms,
 
380
                                },false);
 
381
                        }
 
382
                        print('</dl>');
 
383
                default:
 
384
                        if( all.length != platforms.length ) {
 
385
                                print('<div class="platforms">Defined in ');
 
386
                                display(platforms,output,", ");
 
387
                                print('</div>');
 
388
                        }
 
389
                        print('<div class="typedef">= ');
 
390
                        processType(t);
 
391
                        print('</div>');
 
392
                }
 
393
        }
 
394
 
 
395
        function processPath( path : Path, ?params : List<Type> ) {
 
396
                print(makePathUrl(path,"type"));
 
397
                if( params != null && !params.isEmpty() ) {
 
398
                        print("&lt;");
 
399
                        for( t in params )
 
400
                                processType(t);
 
401
                        print("&gt;");
 
402
                }
 
403
        }
 
404
 
 
405
        function processType( t : Type ) {
 
406
                switch( t ) {
 
407
                case TUnknown:
 
408
                        print("Unknown");
 
409
                case TEnum(path,params):
 
410
                        processPath(path,params);
 
411
                case TClass(path,params):
 
412
                        processPath(path,params);
 
413
                case TTypedef(path,params):
 
414
                        processPath(path,params);
 
415
                case TFunction(args,ret):
 
416
                        if( args.isEmpty() ) {
 
417
                                processPath("Void");
 
418
                                print(" -> ");
 
419
                        }
 
420
                        for( a in args ) {
 
421
                                if( a.opt )
 
422
                                        print("?");
 
423
                                if( a.name != null && a.name != "" )
 
424
                                        print(a.name+" : ");
 
425
                                processTypeFun(a.t,true);
 
426
                                print(" -> ");
 
427
                        }
 
428
                        processTypeFun(ret,false);
 
429
                case TAnonymous(fields):
 
430
                        print("{ ");
 
431
                        var me = this;
 
432
                        display(fields,function(f) {
 
433
                                me.print(f.name+" : ");
 
434
                                me.processType(f.t);
 
435
                        },", ");
 
436
                        print("}");
 
437
                case TDynamic(t):
 
438
                        if( t == null )
 
439
                                processPath("Dynamic");
 
440
                        else {
 
441
                                var l = new List();
 
442
                                l.add(t);
 
443
                                processPath("Dynamic",l);
 
444
                        }
 
445
                }
 
446
        }
 
447
 
 
448
        function processTypeFun( t : Type, isArg ) {
 
449
                var parent =  switch( t ) { case TFunction(_,_): true; case TEnum(n,_): isArg && n == "Void"; default : false; };
 
450
                if( parent )
 
451
                        print("(");
 
452
                processType(t);
 
453
                if( parent )
 
454
                        print(")");
 
455
        }
 
456
 
 
457
        function rightsStr(r) {
 
458
                return switch(r) {
 
459
                case RNormal: "default";
 
460
                case RNo: "null";
 
461
                case RMethod(m): m;
 
462
                case RDynamic: "dynamic";
 
463
                case RF9Dynamic: "f9dynamic";
 
464
                }
 
465
        }
 
466
 
 
467
        function keyword(w) {
 
468
                print('<span class="kwd">'+w+' </span>');
 
469
        }
 
470
 
 
471
        function processDoc(doc : String) {
 
472
                if( doc == null )
 
473
                        return;
 
474
 
 
475
                // unixify line endings
 
476
                doc = doc.split("\r\n").join("\n").split("\r").join("\n");
 
477
 
 
478
                // trim stars
 
479
                doc = ~/^([ \t]*)\*+/gm.replace(doc, "$1");
 
480
                doc = ~/\**[ \t]*$/gm.replace(doc, "");
 
481
 
 
482
                // process [] blocks
 
483
                var rx = ~/\[/;
 
484
                var tmp = new StringBuf();
 
485
                var codes = new List();
 
486
                while (rx.match(doc)) {
 
487
                        tmp.add( rx.matchedLeft() );
 
488
 
 
489
                        var code = rx.matchedRight();
 
490
                        var brackets = 1;
 
491
                        var i = 0;
 
492
                        while( i < code.length && brackets > 0 ) {
 
493
                                switch( code.charCodeAt(i++) ) {
 
494
                                case 91: brackets++;
 
495
                                case 93: brackets--;
 
496
                                }
 
497
                        }
 
498
                        doc = code.substr(i);
 
499
                        code = code.substr(0, i-1);
 
500
                        code = ~/&/g.replace(code, "&amp;");
 
501
                        code = ~/</g.replace(code, "&lt;");
 
502
                        code = ~/>/g.replace(code, "&gt;");
 
503
                        var tag = "##__code__"+codes.length+"##";
 
504
                        if( code.indexOf('\n') != -1 ) {
 
505
                                tmp.add("<pre>");
 
506
                                tmp.add(tag);
 
507
                                tmp.add("</pre>");
 
508
                                codes.add(code.split("\t").join("    "));
 
509
                        } else {
 
510
                                tmp.add("<code>");
 
511
                                tmp.add(tag);
 
512
                                tmp.add("</code>");
 
513
                                codes.add(code);
 
514
                        }
 
515
                }
 
516
                tmp.add(doc);
 
517
 
 
518
                // separate into paragraphs
 
519
                var parts = ~/\n[ \t]*\n/g.split(tmp.toString());
 
520
                if( parts.length == 1 )
 
521
                        doc = parts[0];
 
522
                else
 
523
                        doc = Lambda.map(parts,function(x) { return "<p>"+StringTools.trim(x)+"</p>"; }).join("\n");
 
524
 
 
525
                // put back code parts
 
526
                var i = 0;
 
527
                for( c in codes )
 
528
                        doc = doc.split("##__code__"+(i++)+"##").join(c);
 
529
                print(doc);
 
530
        }
 
531
 
 
532
        function display<T>( l : List<T>, f : T -> Void, sep : String ) {
 
533
                var first = true;
 
534
                for( x in l ) {
 
535
                        if( first )
 
536
                                first = false;
 
537
                        else
 
538
                                print(sep);
 
539
                        f(x);
 
540
                }
 
541
        }
 
542
 
 
543
}