cmake build system: visiblity support for clang
[supercollider.git] / SCClassLibrary / Common / Helper / autoClassHelper.sc
blobfed488c500877dbfd3b22b7122c4236d2f697a92
1 // a class for autogenerating help files from source markup
2 // a special multiline comment is used: /*@@*/
3 // plus some other conventions
4 // After class name you can write
5 /*@
6 shortDesc: description of the method
7 longDesc: longer one
8 seeAlso: refs
9 issues: other aspects
10 testvar: a name of a instance var
11 classtestvar: a name of a class var
12 instDesc: the name of the instance methods section
13 longInstDesc: a comment related to the instance methods section
14 @*/
16 // After each method you can write
17 /*@
18 desc: a description of the method
19 argName: for each arg. Default value is added automatically
20 ex: multiline example
21 @*/
22 // started after 04/11/07
23 // andreavalle
25 AutoClassHelper {
27         var class, path, parser, classDoc, cmDict, imDict ;
28         var shortDesc, longDesc, seeAlso, issues, instDesc, longInstDesc ;
29         var varDict ;
30         var doctype, head, preface, examples ;
32         *new { arg undocumentedClass, path ;
33                         ^super.new.initClassHelper( undocumentedClass, path )
34         }
36         initClassHelper { arg aClass, aPath ;
37                 class = aClass ;
38                 parser = DocParser.new(class) ;
39                 classDoc = parser.getDocs[0] ;
40                 cmDict = parser.getDocs[1] ;
41                 imDict = parser.getDocs[2] ;
42                 varDict = IdentityDictionary.new ;
43                 // <head> tag
44                 head = "
45 <head>
46 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">
47 <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">
48 <title></title>
49 <meta name=\"Generator\" content=\"Cocoa HTML Writer\">
50 <meta name=\"CocoaVersion\" content=\"824.42\">
51 <style type=\"text/css\">
52 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
53 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
54 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
55 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
56 p.p5 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco; min-height: 12.0px}
57 p.p6 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 12.0px Helvetica}
58 p.p7 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 12.0px Helvetica; min-height: 14.0px}
59 p.p8 {margin: 0.0px 0.0px 0.0px 85.0px; text-indent: -85.0px; font: 12.0px Helvetica}
60 p.p9 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco; color: #d40000}
61 p.p10 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco}
62 p.p11 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 14.0px Helvetica}
63 p.p12 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 14.0px Helvetica; min-height: 17.0px}
64 p.p13 {margin: 0.0px 0.0px 0.0px 85.0px; text-indent: -85.0px; font: 12.0px Helvetica; min-height: 14.0px}
65 p.p14 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #d40000}
66 p.p15 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
67 span.s1 {font: 18.0px Helvetica}
68 span.s2 {color: #1200c4}
69 span.s3 {color: #1200c4}
70 span.s4 {color: #000000}
71 span.s5 {color: #1200c4}
72 span.s6 {color: #d40000}
73 span.s7 {font: 12.0px Helvetica; color: #000000}
74 span.s8 {color: #0000ff}
75 span.s9 {color: #1200c4}
76 span.Apple-tab-span {white-space:pre}
77 </style>
78 </head>
79 " ;
80                         doctype = "
81 <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">
82 " ;
83                 path = aPath ;
84                 if ( path.isNil, {
85                         GUI.current.dialog.savePanel({ arg newPath ;
86                                  path = newPath ; {this.makeHelp}.defer })
87                         }, { this.makeHelp }) ;
89         }
91         makeHelp {
92                 var title = class.name.asString ;
93                 var preface = this.createPreface ;
94                 var classMethodBlock = this.createClassMethodBlock ;
95                 var getterSetter = this.createGetterSetterBlock ;
96                 var instanceMethodBlock = this.createInstanceMethodBlock ;
97                 var doc, content ;
98                 // here we put together all the stuff
99                 content = doctype +
100                                  "<hmtl>\n"+
101                                  head+
102                                  "<body>\n"+
103                                  preface +
104                                  classMethodBlock +
105                                  getterSetter +
106                                 instanceMethodBlock +
107                                 // examples+
108                                  "</body>"+
109                                  "</html>" ;
110                 File.new(path, "w")
111                                 .write(content)
112                                 .close ;
113                 // and reopen thru class.openHelpFile
114                 // open works if the path is a place where SC looks for Help files
115                 class.openHelpFile
116         }
118         createPreface {
119                 var superclasses, parents = "" ;
120                 this.createClassDocBlock ;
121                 // here only for the special case of Object
122                 superclasses = if ( class == Object, { nil }, { class.superclasses.reverse }) ;
123                 superclasses.do({arg item ; parents = parents+item+":" }) ;
124                 ^preface = "
125 <p class=\"p1\"><span class=\"s1\"><b>SomeClass<span class=\"Apple-tab-span\">  </span><span class=\"Apple-tab-span\">  </span><span class=\"Apple-tab-span\">  </span></b></span><b>shortDesc</b><span class=\"s1\"><b><span class=\"Apple-tab-span\"> </span></b></span></p>
126 <p class=\"p2\"><br></p>
127 <p class=\"p1\"><b>Inherits from: </b><b>Parents</b></p>
128 <p class=\"p3\"><br></p>
129 <p class=\"p1\">longDesc</p>
130 <p class=\"p2\"><br></p>
131 <p class=\"p1\"><b>See also:</b> seeAlso</p>
132 <p class=\"p2\"><br></p>
133 <p class=\"p4\"><b>Other Issues</b></p>
134 <p class=\"p2\"><br></p>
135 <p class=\"p1\">issues</a></p>
136 <p class=\"p2\"><br></p>
137 "                       .replace("SomeClass", class.name.asString)
138                         .replace("Parents", parents[..parents.size-2])
139                         .replace("shortDesc", shortDesc)
140                         .replace("longDesc", longDesc)
141                         .replace("issues", issues)
142                         .replace("seeAlso", seeAlso)
144         }
146         createClassMethodBlock {
147                 var isEx, methodTitle ;
148                 var classMethods = "
149 <p class=\"p4\"><b>Creation / Class Methods</b></p>
150 <p class=\"p5\"><br></p>
151 " ;
152                 var method, name, args, def, txt, ex, default ;
153                 cmDict.keys.asArray.sort.do({ arg key ;
154                         isEx = false ;
155                         method = cmDict[key][0] ;
156                         name = method.name ;
157                         methodTitle = "
158 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span>name</b></p>
159 "                               .replace("name", "*"++name+this.makeName(method)) ;
160                         if ( cmDict[key][1] != "", {classMethods = classMethods + methodTitle }) ;
161                         args = cmDict[key][1].split($\n).reject({|i| i.size < 2}) ;
162                         args[..args.size-2].do({ arg line ;
163                                 case    { line.contains("desc:") }
164                                                 {       def = line.split($:)[0] ;
165                                                         txt = line.split($:)[1] ;
166                                                         classMethods = classMethods + "
167 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span><span class=\"Apple-tab-span\">  </span></b>desc</p>
168 "                                       .replace("desc", txt)
169                                                          }
170                                         { line.contains("ex:") }
171                                                 {       isEx = true ;
172                                                         def = line.split($:)[0] ;
173                                                         txt = line.split($:)[1] ;
174                                                         classMethods = classMethods +
176 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span></p>
177 <p class=\"p9\"><span class=\"s4\"><span class=\"Apple-tab-span\">      </span><span class=\"Apple-tab-span\">  </span></span>// Example</p>
178 <p class=\"p10\"><span class=\"Apple-tab-span\">        </span><span class=\"Apple-tab-span\">  </span>ex</p>
180                                         .replace("ex", txt)
181                                                         }
183                                         { line.contains("desc:").not && isEx }
184                                                 {       classMethods = classMethods +
185 "<p class=\"p10\"><span class=\"Apple-tab-span\">       </span><span class=\"Apple-tab-span\">  </span>ex</p>"
186                                         .replace("ex", line)
187                                                         }
189                                         { line.contains("desc:").not }
190                                                 {
191                                                         def = line.split($:)[0] ;
192                                                         default = this.getDefault(method, def) ;
193                                                         txt = line.split($:)[1] ;
194                                                         classMethods = classMethods +
196 <p class=\"p8\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span><b>def </b>- txt. Default value is dfv.</p>
197 "                                                       .replace("def", def)
198                                                         .replace("txt", txt).replace("dfv", default);
200                                                         }
201                         });
202                 }) ;
203                 ^(classMethods+"<p class=\"p5\"><br></p>\n")
205         }
208         makeName { arg method ;
209                 var name = method.argumentString.replace("this, ", "").split($,)
210                         .collect({ arg i ; i.split($=)[0]}).asString ;
211                         ^"("++name[2..name.size-3]++")"
213         }
215         getDefault { arg method, name ;
216                 var mString = method.argumentString.replace(" ", "") ;
217                 var pos ;
218                 var next ;
219                 name = name.reject( { arg i; i.isAlphaNum.not } ) ;
220                 pos = mString.find(name) ;
221                 if ( pos.notNil, {
222                          next = mString[pos+name.size] ;
223                                 if (next == $=, { mString = mString[pos+name.size..].split($=)[1] ;
224                                                                 ^mString = mString.split($,)[0] },
225                                                         {^"nil"})
226                         }, {^"nil"})
227         }
229         createInstanceMethodBlock {
230                 var isEx, methodTitle ;
231                 var instanceMethods = "<p class=\"p11\"><b>instDesc</b></p>
232 <p class=\"p12\"><br></p>
233 <p class=\"p6\">longInstDesc</p>
234 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span></p>
235 "                       .replace("instDesc", instDesc)
236                         .replace("longInstDesc", longInstDesc)
237                         ;
238                 var method, name, args, def, txt, ex, default ;
239                 imDict.keys.asArray.sort.do({ arg key ;
240                         isEx = false ;
241                         method = imDict[key][0] ;
242                         name = method.name ;
243                         methodTitle = "<p class=\"p5\"><br></p>\n"+
244                         "
245 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span>name</b></p>
246 "                               .replace("name", name++" "++this.makeName(method)) ;
247                         if ( imDict[key][1] != "", { instanceMethods = instanceMethods + methodTitle }) ;
248                         args = imDict[key][1].split($\n).reject({|i| i.size < 2}) ;
249                         args[..args.size-2].do({ arg line ;
250                                 case    { line.contains("desc:") }
251                                                 {       def = line.split($:)[0] ;
252                                                         txt = line.split($:)[1] ;
253                                                         instanceMethods = instanceMethods + "
254 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span><span class=\"Apple-tab-span\">  </span></b>desc</p>
255 "                                       .replace("desc", txt)
256                                                          }
257                                         { line.contains("ex:") }
258                                                 {       isEx = true ;
259                                                         def = line.split($:)[0] ;
260                                                         txt = line.split($:)[1] ;
261                                                         instanceMethods = instanceMethods +
263 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span></p>
264 <p class=\"p9\"><span class=\"s4\"><span class=\"Apple-tab-span\">      </span><span class=\"Apple-tab-span\">  </span></span>// Example</p>
265 <p class=\"p10\"><span class=\"Apple-tab-span\">        </span><span class=\"Apple-tab-span\">  </span>ex</p>
267                                         .replace("ex", txt)
268                                                         }
270                                         { line.contains("desc:").not && isEx }
271                                                 {
272                                                         instanceMethods = instanceMethods +
273 "<p class=\"p10\"><span class=\"Apple-tab-span\">       </span><span class=\"Apple-tab-span\">  </span>ex</p>"
274                                         .replace("ex", line)
275                                                         }
278                                         { line.contains("desc:").not }
279                                                 {       def = line.split($:)[0] ;                                                       default = this.getDefault(method, def) ;
280                                                         txt = line.split($:)[1] ;
281                                                         instanceMethods = instanceMethods +
283 <p class=\"p8\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span><b>def </b>- txt. Default value is dfv.</p>
284 "                                                       .replace("def", def).replace("txt", txt).replace("dfv", default);
286                                                         }
287                         });
288                 }) ;
289                 ^(instanceMethods+"<p class=\"p5\"><br></p>\n")
290         }
293         createClassDocBlock {
294                 var args = classDoc.split($\n).reject({|i| i.size < 2}) ;
295                 args.do({ arg line ;
296                         case    { line.contains("shortDesc:") }
297                                         { shortDesc = line.split($:)[1] ; }
298                                 { line.contains("longDesc:") }
299                                         { longDesc = line.split($:)[1] ; }
300                                 { line.contains("seeAlso:") }
301                                         { seeAlso = line.split($:)[1] ; }
302                                 { line.contains("issues:") }
303                                         { issues = line.split($:)[1] ; }
304                                 { line.contains("instDesc:") }
305                                         { instDesc = line.split($:)[1] ; }
306                                 { line.contains("longInstDesc:") }
307                                         { longInstDesc = line.split($:)[1] ; }
308                                 // residual: allows to create the varDict
309                                 { line.contains("longInstDesc:").not }
310                                         { varDict.add( line.split($:)[0]
311                                                 .select({|i| i.isAlphaNum })
312                                                 .asSymbol
313                                                 -> line.split($:)[1] ); }
314                         }) ;
315         }
318         createGetterSetterBlock {
319                 var getterSetterBlock = "
320 <p class=\"p11\"><b>Accessing Instance and Class Variables</b></p>
321 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span></p>
322 " ;
323                 var getters = parser.getters.collect(_.name) ;
324                 var setters = parser.setters.collect(_.name) ;
325                 var name, comment, line ;
326                 varDict.keys.do({ arg key ;
327                         comment = varDict[key] ;
328                         line = "" ;
329                         line = if ( getters.includes(key), {
331 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span>someVar</b></p>
332 "                               .replace("someVar", key.asString)
333                         },{""}) ;
334                         if ( setters.includes((key++"_").asSymbol), {  line = line +
336 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span>someVar_</b></p>
337 "                               .replace("someVar", key.asString)
338                         }) ;
339                         if ( class.classVarNames.includes(key), {  line = line +
341 <p class=\"p6\"><b><span class=\"Apple-tab-span\">      </span>someVar</b></p>
342 "                               .replace("someVar", key.asString)
344                         }) ;
345                         getterSetterBlock = getterSetterBlock + line +
347 <p class=\"p7\"><b><span class=\"Apple-tab-span\">      </span></b><span class=\"Apple-tab-span\">      </span></p>
348 <p class=\"p6\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span>"+comment+"</p>
349 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\">  </span><span class=\"Apple-tab-span\">  </span><span class=\"Apple-tab-span\">  </span></p>
351                 }) ;
352                 ^getterSetterBlock
353         }