Release 0.41.92
[vala-gnome.git] / libvaladoc / gtkdocrenderer.vala
blob6ffc801418b9379b97848905766676f6e62fea9d
1 /* gtkdocrenderer.vala
3 * Copyright (C) 2011 Florian Brosch
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Florian Brosch <flo.brosch@gmail.com>
23 using GLib;
24 using Valadoc.Content;
26 public class Valadoc.GtkdocRenderer : ContentRenderer {
27 private GtkDocMarkupWriter writer = new GtkDocMarkupWriter ();
28 protected Settings settings;
29 private bool separated;
31 private string? get_cname (Api.Item item) {
32 if (item is Api.Method) {
33 return ((Api.Method)item).get_cname ();
34 } else if (item is Api.FormalParameter) {
35 return ((Api.FormalParameter)item).name;
36 } else if (item is Api.Constant) {
37 return ((Api.Constant)item).get_cname ();
38 } else if (item is Api.Property) {
39 return ((Api.Property)item).get_cname ();
40 } else if (item is Api.Signal) {
41 var name = ((Api.Signal)item).get_cname ();
42 return name.replace ("_", "-");
43 } else if (item is Api.Class) {
44 return ((Api.Class)item).get_cname ();
45 } else if (item is Api.Struct) {
46 return ((Api.Struct)item).get_cname ();
47 } else if (item is Api.Interface) {
48 return ((Api.Interface)item).get_cname ();
49 } else if (item is Api.ErrorDomain) {
50 return ((Api.ErrorDomain)item).get_cname ();
51 } else if (item is Api.ErrorCode) {
52 return ((Api.ErrorCode)item).get_cname ();
53 } else if (item is Api.Delegate) {
54 return ((Api.Delegate)item).get_cname ();
55 } else if (item is Api.Enum) {
56 return ((Api.Enum)item).get_cname ();
57 } else if (item is Api.EnumValue) {
58 return ((Api.EnumValue)item).get_cname ();
61 return null;
64 public void write_docbook_link (Api.Item item) {
65 writer.set_wrap (false);
67 if (item is Api.Method) {
68 writer.start_tag ("function")
69 .text (((Api.Method)item).get_cname ())
70 .end_tag ("function");
71 } else if (item is Api.FormalParameter) {
72 writer.start_tag ("parameter").
73 text (((Api.FormalParameter)item).name ?? "...")
74 .end_tag ("parameter");
75 } else if (item is Api.Constant) {
76 writer.start_tag ("constant").text (((Api.Constant)item)
77 .get_cname ())
78 .end_tag ("constant");
79 } else if (item is Api.Property) {
80 // TODO: use docbook-tags instead
81 writer.text ("#").text (get_cname(item.parent))
82 .text (":")
83 .text (((Api.Property)item)
84 .get_cname ().replace ("_", "-"));
85 } else if (item is Api.Signal) {
86 // TODO: use docbook-tags instead
87 writer.text ("#").text (get_cname(item.parent))
88 .text ("::")
89 .text (((Api.Signal)item).get_cname ().replace ("_", "-"));
90 } else if (item is Api.Namespace) {
91 writer.text (((Api.Namespace) item).get_full_name ());
92 } else {
93 writer.start_tag ("type")
94 .text (get_cname (item))
95 .end_tag ("type");
98 writer.set_wrap (true);
101 public GtkdocRenderer () {
104 public override void render (ContentElement element) {
105 reset ();
106 element.accept (this);
109 public void render_symbol (Content.Comment? documentation) {
110 render (documentation);
112 append_exceptions (documentation.find_taglets (null, typeof(Taglets.Throws)));
113 append_see (documentation.find_taglets (null, typeof(Taglets.See)));
114 append_since (documentation.find_taglets (null, typeof(Taglets.Since)));
117 public override void render_children (ContentElement element) {
118 reset ();
119 element.accept_children (this);
122 private void reset () {
123 separated = false;
124 writer.reset ();
127 public unowned string content {
128 get {
129 if (writer.content.has_prefix ("\n")) {
130 return writer.content.next_char ();
133 return writer.content;
137 public override void visit_comment (Comment element) {
138 element.accept_children (this);
141 public override void visit_embedded (Embedded element) {
142 writer.start_tag ("figure");
143 if (element.caption != null) {
144 writer.start_tag ("title")
145 .text (element.caption)
146 .end_tag ("title");
149 writer.start_tag ("mediaobject");
151 writer.start_tag ("imageobject")
152 .simple_tag ("imagedata", {"fileref", element.url})
153 .end_tag ("imageobject");
155 if (element.caption != null) {
156 writer.start_tag ("textobject")
157 .start_tag ("phrase")
158 .text (element.caption)
159 .end_tag ("phrase")
160 .end_tag ("textobject");
163 writer.end_tag ("mediaobject");
164 writer.end_tag ("figure");
167 public override void visit_headline (Headline element) {
168 assert_not_reached ();
171 public override void visit_wiki_link (WikiLink element) {
172 // wiki pages are not supported by gir
173 if (element.content.size > 0) {
174 element.accept_children (this);
175 } else {
176 write_string (element.name);
180 public override void visit_link (Link element) {
181 writer.start_tag ("ulink", {"url", element.url});
182 element.accept_children (this);
183 writer.end_tag ("ulink");
186 public override void visit_symbol_link (SymbolLink element) {
187 if (element.content.size > 0) {
188 writer.text ("\"");
189 element.accept_children (this);
190 writer.text ("\" (");
191 write_symbol_link (element);
192 writer.text (")");
193 } else {
194 write_symbol_link (element);
198 public void write_symbol_link (SymbolLink element) {
199 if (element.symbol == null) {
200 writer.text (element.given_symbol_name);
201 } else {
202 write_docbook_link (element.symbol);
206 public override void visit_list (Content.List element) {
207 string tag = "orderedlist";
208 switch (element.bullet) {
209 case Content.List.Bullet.NONE:
210 writer.start_tag ("itemizedlist", {"mark", "none"});
211 tag = "itemizedlist";
212 break;
214 case Content.List.Bullet.UNORDERED:
215 writer.start_tag ("itemizedlist");
216 tag = "itemizedlist";
217 break;
219 case Content.List.Bullet.ORDERED:
220 writer.start_tag ("orderedlist");
221 break;
223 case Content.List.Bullet.ORDERED_NUMBER:
224 writer.start_tag ("orderedlist", {"numeration", "arabic"});
225 break;
227 case Content.List.Bullet.ORDERED_LOWER_CASE_ALPHA:
228 writer.start_tag ("orderedlist", {"numeration", "loweralpha"});
229 break;
231 case Content.List.Bullet.ORDERED_UPPER_CASE_ALPHA:
232 writer.start_tag ("orderedlist", {"numeration", "upperalpha"});
233 break;
235 case Content.List.Bullet.ORDERED_LOWER_CASE_ROMAN:
236 writer.start_tag ("orderedlist", {"numeration", "lowerroman"});
237 break;
239 case Content.List.Bullet.ORDERED_UPPER_CASE_ROMAN:
240 writer.start_tag ("orderedlist", {"numeration", "upperroman"});
241 break;
243 default:
244 assert_not_reached ();
247 element.accept_children (this);
249 writer.end_tag (tag);
252 public override void visit_list_item (ListItem element) {
253 writer.start_tag ("listitem");
254 element.accept_children (this);
255 writer.end_tag ("listitem");
258 public override void visit_page (Page element) {
259 element.accept_children (this);
262 public override void visit_paragraph (Paragraph element) {
263 writer.start_tag ("para");
264 element.accept_children (this);
265 writer.end_tag ("para");
268 public override void visit_warning (Warning element) {
269 writer.start_tag ("warning");
270 element.accept_children (this);
271 writer.end_tag ("warning");
274 public override void visit_note (Note element) {
275 writer.start_tag ("note");
276 element.accept_children (this);
277 writer.end_tag ("note");
280 public override void visit_run (Run element) {
281 string? tag = null;
283 switch (element.style) {
284 case Run.Style.BOLD:
285 writer.start_tag ("emphasis", {"role", "bold"});
286 tag = "emphasis";
287 break;
289 case Run.Style.ITALIC:
290 writer.start_tag ("emphasis");
291 tag = "emphasis";
292 break;
294 case Run.Style.UNDERLINED:
295 writer.start_tag ("emphasis", {"role", "underline"});
296 tag = "emphasis";
297 break;
299 case Run.Style.MONOSPACED:
300 writer.start_tag ("blockquote");
301 tag = "blockquote";
302 break;
305 element.accept_children (this);
307 if (tag != null) {
308 writer.end_tag (tag);
312 public override void visit_source_code (SourceCode element) {
313 writer.start_tag ("example")
314 .start_tag ("programlisting");
315 writer.text (element.code);
316 writer.end_tag ("programlisting")
317 .end_tag ("example");
320 public override void visit_table (Table element) {
321 writer.start_tag ("table", {"align", "center"});
322 element.accept_children (this);
323 writer.end_tag ("table");
326 public override void visit_table_cell (TableCell element) {
327 writer.start_tag ("td", {"colspan", element.colspan.to_string (), "rowspan", element.rowspan.to_string ()});
328 element.accept_children (this);
329 writer.end_tag ("td");
332 public override void visit_table_row (TableRow element) {
333 writer.start_tag ("tr");
334 element.accept_children (this);
335 writer.end_tag ("tr");
338 public override void visit_text (Text element) {
339 write_string (element.content);
342 private void write_string (string content) {
343 unichar chr = content[0];
344 long lpos = 0;
345 int i = 0;
347 for (i = 0; chr != '\0' ; i++, chr = content[i]) {
348 switch (chr) {
349 case '<':
350 writer.raw_text (content.substring (lpos, i-lpos));
351 writer.raw_text ("&lt;");
352 lpos = i+1;
353 break;
355 case '>':
356 writer.raw_text (content.substring (lpos, i-lpos));
357 writer.raw_text ("&gt;");
358 lpos = i+1;
359 break;
361 case '"':
362 writer.raw_text (content.substring (lpos, i-lpos));
363 writer.raw_text ("&quot;");
364 lpos = i+1;
365 break;
367 case '\'':
368 writer.raw_text (content.substring (lpos, i-lpos));
369 writer.raw_text ("&apos;");
370 lpos = i+1;
371 break;
373 case '&':
374 writer.raw_text (content.substring (lpos, i-lpos));
375 writer.raw_text ("&amp;");
376 lpos = i+1;
377 break;
379 case '#':
380 writer.raw_text (content.substring (lpos, i-lpos));
381 writer.raw_text ("&num;");
382 lpos = i+1;
383 break;
385 case '%':
386 writer.raw_text (content.substring (lpos, i-lpos));
387 writer.raw_text ("&percnt;");
388 lpos = i+1;
389 break;
391 case '@':
392 writer.raw_text (content.substring (lpos, i-lpos));
393 writer.raw_text ("&commat;");
394 lpos = i+1;
395 break;
397 case '(':
398 writer.raw_text (content.substring (lpos, i-lpos));
399 writer.raw_text ("&lpar;");
400 lpos = i+1;
401 break;
403 case ')':
404 writer.raw_text (content.substring (lpos, i-lpos));
405 writer.raw_text ("&rpar;");
406 lpos = i+1;
407 break;
409 case '\n':
410 writer.raw_text (content.substring (lpos, i-lpos));
411 writer.simple_tag ("br");
412 lpos = i+1;
413 break;
417 writer.raw_text (content.substring (lpos, i-lpos));
420 public void append_since (Vala.List<Content.Taglet> taglets) {
421 foreach (Content.Taglet _taglet in taglets) {
422 Taglets.Since taglet = _taglet as Taglets.Since;
423 if (taglet == null || taglet.version == null) {
424 // ignore unexpected taglets
425 continue ;
428 if (separated == false) {
429 writer.text ("\n");
432 writer.set_wrap (false);
433 writer.text ("\nSince: ")
434 .text (taglet.version);
435 writer.set_wrap (true);
436 separated = true;
438 // ignore multiple occurrences
439 return ;
443 public void append_see (Vala.List<Content.Taglet> taglets) {
444 bool first = true;
445 foreach (Content.Taglet _taglet in taglets) {
446 Taglets.See taglet = _taglet as Taglets.See;
447 if (taglet == null || taglet.symbol == null) {
448 // ignore unexpected taglets
449 continue ;
452 if (first) {
453 writer.start_tag ("para").text ("See also: ");
454 } else {
455 writer.text (", ");
458 write_docbook_link (taglet.symbol);
459 first = false;
462 if (first == false) {
463 writer.end_tag ("para");
467 public void append_exceptions (Vala.List<Content.Taglet> taglets) {
468 bool first = true;
469 foreach (Content.Taglet _taglet in taglets) {
470 Taglets.Throws taglet = _taglet as Taglets.Throws;
471 if (taglet == null || taglet.error_domain == null) {
472 // ignore unexpected taglets
473 continue ;
476 if (first) {
477 writer.start_tag ("para")
478 .text ("This function may throw:")
479 .end_tag ("para");
480 writer.start_tag ("table");
483 writer.start_tag ("tr");
485 writer.start_tag ("td");
486 write_docbook_link (taglet.error_domain);
487 writer.end_tag ("td");
489 writer.start_tag ("td");
490 taglet.accept_children (this);
491 writer.end_tag ("td");
493 writer.end_tag ("tr");
495 first = false;
498 if (first == false) {
499 writer.end_tag ("table");