[valadoc] libvaladoc: gir-importer, c-resolver : various improvements



commit 726d32238c7ff6958664bb766cbb5d78c283024a
Author: Florian Brosch <flo brosch gmail com>
Date:   Sun Dec 18 18:51:14 2011 +0100

    libvaladoc: gir-importer, c-resolver : various improvements

 src/driver/0.10.x/treebuilder.vala                 |    4 +-
 src/driver/0.13.x/treebuilder.vala                 |   14 +-
 src/driver/0.14.x/treebuilder.vala                 |    6 +-
 src/driver/0.16.x/treebuilder.vala                 |   24 +-
 src/libvaladoc/Makefile.am                         |    1 +
 src/libvaladoc/api/struct.vala                     |   10 +-
 src/libvaladoc/api/tree.vala                       |    8 +
 src/libvaladoc/ctyperesolver.vala                  |   53 ++-
 .../documentation/gtkdoccommentparser.vala         |  152 +++++-
 src/libvaladoc/importer/documentationimporter.vala |    4 -
 .../importer/girdocumentationimporter.vala         |  635 ++++++++++++++++++++
 .../importer/valadocdocumentationimporter.vala     |    3 +
 src/libvaladoc/markupreader.vala                   |   11 +
 src/libvaladoc/taglets/tagletlink.vala             |   33 +-
 14 files changed, 915 insertions(+), 43 deletions(-)
---
diff --git a/src/driver/0.10.x/treebuilder.vala b/src/driver/0.10.x/treebuilder.vala
index 6bc66b4..2f1cd7c 100644
--- a/src/driver/0.10.x/treebuilder.vala
+++ b/src/driver/0.10.x/treebuilder.vala
@@ -776,7 +776,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_class == null && element.name == "string";
 
-		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, element.get_cname (), Vala.GDBusModule.get_dbus_name (element), element.get_param_spec_function (), element.get_type_id (), element.get_ref_function (), element.get_unref_function (), element.get_take_value_function (), element.get_get_value_function (), element.get_set_value_function (), element.is_fundamental (), element.is_abstract, is_basic_type, element);
+		Class node = new Class (parent, file, element.name, get_access_modifier (element), comment, element.get_cname (), Vala.GDBusModule.get_dbus_name (element), element.get_type_id (), element.get_param_spec_function (), element.get_ref_function (), element.get_unref_function (), element.get_take_value_function (), element.get_get_value_function (), element.get_set_value_function (), element.is_fundamental (), element.is_abstract, is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
@@ -836,7 +836,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_type == null && (element.is_boolean_type () || element.is_floating_type () || element.is_integer_type ());
 
-		Struct node = new Struct (parent, file, element.name, get_access_modifier(element), comment, element.get_cname(), element.get_dup_function (), element.get_free_function (), is_basic_type, element);
+		Struct node = new Struct (parent, file, element.name, get_access_modifier (element), comment, element.get_cname(), element.get_type_id (), element.get_dup_function (), element.get_free_function (), is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
diff --git a/src/driver/0.13.x/treebuilder.vala b/src/driver/0.13.x/treebuilder.vala
index 9cfac52..d898cee 100644
--- a/src/driver/0.13.x/treebuilder.vala
+++ b/src/driver/0.13.x/treebuilder.vala
@@ -233,11 +233,17 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 		}
 	}
 
-	private string get_ccode_type_id (Vala.Class node) {
+	private string? get_ccode_type_id (Vala.CodeNode node) {
 #if VALA_0_13_X
 		return Vala.CCodeBaseModule.get_ccode_type_id (node);
 #else
-		return node.get_type_id ();
+		if (node is Vala.Class) {
+			return ((Vala.Class) node).get_type_id ();
+		} else (node is Vala.Struct) {
+			return ((Vala.Struct) node).get_type_id ();
+		}
+
+		return null;
 #endif
 	}
 
@@ -874,7 +880,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_class == null && element.name == "string";
 
-		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_param_spec_function (element), get_ccode_type_id (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
+		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_ccode_type_id (element), get_param_spec_function (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
@@ -934,7 +940,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_type == null && (element.is_boolean_type () || element.is_floating_type () || element.is_integer_type ());
 
-		Struct node = new Struct (parent, file, element.name, get_access_modifier(element), comment, get_cname(element), get_dup_function (element), get_free_function (element), is_basic_type, element);
+		Struct node = new Struct (parent, file, element.name, get_access_modifier (element), comment, get_cname (element), get_ccode_type_id (element), get_dup_function (element), get_free_function (element), is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
diff --git a/src/driver/0.14.x/treebuilder.vala b/src/driver/0.14.x/treebuilder.vala
index daff9b2..f61b08f 100644
--- a/src/driver/0.14.x/treebuilder.vala
+++ b/src/driver/0.14.x/treebuilder.vala
@@ -233,7 +233,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 		}
 	}
 
-	private string get_ccode_type_id (Vala.Class node) {
+	private string get_ccode_type_id (Vala.CodeNode node) {
 		return Vala.CCodeBaseModule.get_ccode_type_id (node);
 	}
 
@@ -808,7 +808,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_class == null && element.name == "string";
 
-		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_param_spec_function (element), get_ccode_type_id (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
+		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_ccode_type_id (element), get_param_spec_function (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
@@ -868,7 +868,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_type == null && (element.is_boolean_type () || element.is_floating_type () || element.is_integer_type ());
 
-		Struct node = new Struct (parent, file, element.name, get_access_modifier(element), comment, get_cname(element), get_dup_function (element), get_free_function (element), is_basic_type, element);
+		Struct node = new Struct (parent, file, element.name, get_access_modifier(element), comment, get_cname(element), get_ccode_type_id (element), get_dup_function (element), get_free_function (element), is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
diff --git a/src/driver/0.16.x/treebuilder.vala b/src/driver/0.16.x/treebuilder.vala
index 512d7b1..3687610 100644
--- a/src/driver/0.16.x/treebuilder.vala
+++ b/src/driver/0.16.x/treebuilder.vala
@@ -237,7 +237,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 		}
 	}
 
-	private string get_ccode_type_id (Vala.Class node) {
+	private string? get_ccode_type_id (Vala.CodeNode node) {
 		return Vala.CCodeBaseModule.get_ccode_type_id (node);
 	}
 
@@ -245,32 +245,32 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 		return Vala.CCodeBaseModule.is_reference_counting (sym);
 	}
 
-	private string get_ref_function (Vala.Class sym) {
+	private string? get_ref_function (Vala.Class sym) {
 		return Vala.CCodeBaseModule.get_ccode_ref_function (sym);
 	}
 
-	private string get_unref_function (Vala.Class sym) {
+	private string? get_unref_function (Vala.Class sym) {
 		return Vala.CCodeBaseModule.get_ccode_unref_function (sym);
 	}
 
-	private string get_finish_name (Vala.Method m) {
+	private string? get_finish_name (Vala.Method m) {
 		return Vala.CCodeBaseModule.get_ccode_finish_name (m);
 	}
 
-	private string get_take_value_function (Vala.Class sym) {
+	private string? get_take_value_function (Vala.Class sym) {
 		return Vala.CCodeBaseModule.get_ccode_take_value_function (sym);
 	}
 
-	private string get_get_value_function (Vala.Class sym) {
+	private string? get_get_value_function (Vala.Class sym) {
 		return Vala.CCodeBaseModule.get_ccode_get_value_function (sym);
 	}
 
-	private string get_set_value_function (Vala.Class sym) {
+	private string? get_set_value_function (Vala.Class sym) {
 		return Vala.CCodeBaseModule.get_ccode_set_value_function (sym);
 	}
 
 
-	private string get_param_spec_function (Vala.CodeNode sym) {
+	private string? get_param_spec_function (Vala.CodeNode sym) {
 		return Vala.CCodeBaseModule.get_ccode_param_spec_function (sym);
 	}
 
@@ -278,11 +278,11 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 		return Vala.CCodeBaseModule.get_ccode_dup_function (sym);
 	}
 
-	private string get_free_function (Vala.TypeSymbol sym) {
+	private string? get_free_function (Vala.TypeSymbol sym) {
 		return Vala.CCodeBaseModule.get_ccode_free_function (sym);
 	}
 
-	private string get_nick (Vala.Property prop) {
+	private string? get_nick (Vala.Property prop) {
 		return Vala.CCodeBaseModule.get_ccode_nick (prop);
 	}
 
@@ -832,7 +832,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_class == null && element.name == "string";
 
-		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_param_spec_function (element), get_ccode_type_id (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
+		Class node = new Class (parent, file, element.name, get_access_modifier(element), comment, get_cname (element), Vala.GDBusModule.get_dbus_name (element), get_ccode_type_id (element), get_param_spec_function (element), get_ref_function (element), get_unref_function (element), get_take_value_function (element), get_get_value_function (element), get_set_value_function (element), element.is_fundamental (), element.is_abstract, is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
@@ -892,7 +892,7 @@ public class Valadoc.Drivers.TreeBuilder : Vala.CodeVisitor {
 
 		bool is_basic_type = element.base_type == null && (element.is_boolean_type () || element.is_floating_type () || element.is_integer_type ());
 
-		Struct node = new Struct (parent, file, element.name, get_access_modifier(element), comment, get_cname(element), get_dup_function (element), get_free_function (element), is_basic_type, element);
+		Struct node = new Struct (parent, file, element.name, get_access_modifier (element), comment, get_cname (element), get_ccode_type_id (element), get_dup_function (element), get_free_function (element), is_basic_type, element);
 		symbol_map.set (element, node);
 		parent.add_child (node);
 
diff --git a/src/libvaladoc/Makefile.am b/src/libvaladoc/Makefile.am
index 14a8bfa..310a3db 100755
--- a/src/libvaladoc/Makefile.am
+++ b/src/libvaladoc/Makefile.am
@@ -41,6 +41,7 @@ libvaladoc_la_VALASOURCES = \
 	importer/documentationimporter.vala \
 	importer/valadocdocumentationimporter.vala \
 	importer/valadocdocumentationimporterscanner.vala \
+	importer/girdocumentationimporter.vala \
 	api/symbolaccessibility.vala \
 	api/sourcecomment.vala \
 	api/girsourcecomment.vala \
diff --git a/src/libvaladoc/api/struct.vala b/src/libvaladoc/api/struct.vala
index d0ebe5b..58d33f3 100755
--- a/src/libvaladoc/api/struct.vala
+++ b/src/libvaladoc/api/struct.vala
@@ -30,9 +30,10 @@ using Valadoc.Content;
 public class Valadoc.Api.Struct : TypeSymbol {
 	private string? dup_function_cname;
 	private string? free_function_cname;
+	private string? type_id;
 	private string? cname;
 
-	public Struct (Node parent, SourceFile file, string name, SymbolAccessibility accessibility, SourceComment? comment, string? cname, string? dup_function_cname, string? free_function_cname, bool is_basic_type, void* data) {
+	public Struct (Node parent, SourceFile file, string name, SymbolAccessibility accessibility, SourceComment? comment, string? cname, string? type_id, string? dup_function_cname, string? free_function_cname, bool is_basic_type, void* data) {
 		base (parent, file, name, accessibility, comment, is_basic_type, data);
 
 		this.dup_function_cname = dup_function_cname;
@@ -58,6 +59,13 @@ public class Valadoc.Api.Struct : TypeSymbol {
 	}
 
 	/**
+	 * Returns the C symbol representing the runtime type id for this data type.
+	 */
+	public string? get_type_id () {
+		return type_id;
+	}
+
+	/**
 	 * Returns the C function name that duplicates instances of this data
 	 * type.
 	 */
diff --git a/src/libvaladoc/api/tree.vala b/src/libvaladoc/api/tree.vala
index 1298d06..0133b0b 100755
--- a/src/libvaladoc/api/tree.vala
+++ b/src/libvaladoc/api/tree.vala
@@ -156,6 +156,14 @@ public class Valadoc.Api.Tree {
 		return null;
 	}
 
+	public TypeSymbol? search_symbol_type_cstr (string cname) {
+		if (_cresolver == null) {
+			_cresolver = new CTypeResolver (this);
+		}
+
+		return _cresolver.resolve_symbol_type (cname);		
+	}
+
 	public Node? search_symbol_cstr (Node? element, string cname) {
 		if (_cresolver == null) {
 			_cresolver = new CTypeResolver (this);
diff --git a/src/libvaladoc/ctyperesolver.vala b/src/libvaladoc/ctyperesolver.vala
index a7adac8..0467d48 100755
--- a/src/libvaladoc/ctyperesolver.vala
+++ b/src/libvaladoc/ctyperesolver.vala
@@ -28,13 +28,15 @@ using Gee;
  * Resolves symbols by C-names
  */
 public class Valadoc.CTypeResolver : Visitor {
+	private Map<string, Api.TypeSymbol> types = new HashMap<string, Api.TypeSymbol> ();
 	private Map<string, Api.Node> nodes = new HashMap<string, Api.Node> ();
+	private Api.Tree tree;
 
 	public CTypeResolver (Api.Tree tree) {
 		tree.accept (this);
+		this.tree = tree;
 	}
 
-
 	private string convert_array_to_camelcase (string[] elements) {
 		StringBuilder builder = new StringBuilder ();
 
@@ -72,10 +74,7 @@ public class Valadoc.CTypeResolver : Visitor {
 		if (is_capitalized_and_underscored (name)) {
 			string[] segments = name.split ("_");
 			unowned string last_segment = segments[segments.length - 1];
-			if (last_segment == "ERROR") {
-			} else if (last_segment == "TYPE") {
-				segments.resize (segments.length - 1);
-			} else {
+			if (last_segment != "ERROR") {
 				return null;
 			}
 
@@ -92,6 +91,28 @@ public class Valadoc.CTypeResolver : Visitor {
 		return null;
 	}
 
+	public Api.TypeSymbol? resolve_symbol_type (string name) {
+		TypeSymbol? symbol = types.get (name);
+		if (symbol != null) {
+			return symbol;
+		}
+
+		if (is_capitalized_and_underscored (name)) {
+			string[] segments = name.split ("_");
+
+			if (segments[segments.length - 1] == "TYPE") {
+				segments.resize (segments.length - 1);
+				return types.get (convert_array_to_camelcase (segments));
+			} else if (segments.length > 2 && segments[1] == "TYPE") {
+				string[] _segments = segments[1:segments.length];
+				_segments[0] = segments[0];
+				return types.get (convert_array_to_camelcase (_segments));
+			}
+		}
+
+		return null;
+	}
+
 	/**
 	 * Resolves symbols by C-names
 	 *
@@ -127,9 +148,29 @@ public class Valadoc.CTypeResolver : Visitor {
 			return nodes.get (alternative);
 		}
 
+		if (element != null && _name.has_prefix (":")) {
+			if (element is Class && ((Class) element).get_cname () != null) {
+				return nodes.get (((Class) element).get_cname () + "." + _name);
+			} else if (element is Struct && ((Struct) element).get_cname () != null) {
+				return nodes.get (((Struct) element).get_cname () + "." + _name);
+			}
+		}
+
+		if (name == "dgettext") {
+			return nodes.get ("g_dgettext");
+		} else if (name == "printf") {
+			return this.tree.search_symbol_str (null, "GLib.FileStream.printf");
+		}
+
 		return null;
 	}
 
+	private void register_symbol_type (string? name, Api.TypeSymbol symbol) {
+		if (name != null) {
+			types.set (name, symbol);
+		}
+	}
+
 	private void register_symbol (string? name, Api.Node node) {
 		if (name != null) {
 			nodes.set (name.replace ("-", "_"), node);
@@ -187,6 +228,7 @@ public class Valadoc.CTypeResolver : Visitor {
 	 * { inheritDoc}
 	 */
 	public override void visit_class (Class item) {
+		register_symbol_type (item.get_type_id (), item);
 		register_symbol (item.get_cname (), item);
 		item.accept_all_children (this, false);
 	}
@@ -195,6 +237,7 @@ public class Valadoc.CTypeResolver : Visitor {
 	 * { inheritDoc}
 	 */
 	public override void visit_struct (Struct item) {
+		register_symbol_type (item.get_type_id (), item);
 		register_symbol (item.get_cname (), item);
 		item.accept_all_children (this, false);
 	}
diff --git a/src/libvaladoc/documentation/gtkdoccommentparser.vala b/src/libvaladoc/documentation/gtkdoccommentparser.vala
index 48e5227..e9873e4 100644
--- a/src/libvaladoc/documentation/gtkdoccommentparser.vala
+++ b/src/libvaladoc/documentation/gtkdoccommentparser.vala
@@ -32,6 +32,7 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 	private Token current;
 
 	private LinkedList<string> stack = new LinkedList<string> ();
+	private LinkedList<LinkedList<Block>> footnotes = new LinkedList<LinkedList<Block>> ();
 
 	private ContentFactory factory;
 	private ErrorReporter reporter;
@@ -47,9 +48,10 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		this.scanner.reset (comment.content);
 		this.show_warnings = !comment.file.package.is_package || settings.verbose;
 		this.comment_lines = null;
+		this.footnotes.clear ();
 		this.comment = comment;
-		current = null;
-		stack.clear ();
+		this.current = null;
+		this.stack.clear ();
 	}
 
 	private void report_unexpected_token (Token got, string expected) {
@@ -100,6 +102,21 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 			comment.taglets.add (taglet);
 		}
 
+		bool first = true;
+		foreach (LinkedList<Block> note in this.footnotes) {
+			if (first == true && note.size > 0) {
+				Paragraph p = note.first () as Paragraph;
+				if (p == null) {
+					p = factory.create_paragraph ();
+					comment.content.add (p);
+				}
+
+				p.content.insert (0, factory.create_text ("\n"));
+			}
+			comment.content.add_all (note);
+			first = false;
+		}
+
 		comment.check (tree, element, reporter, settings);
 		return comment;
 	}
@@ -234,7 +251,7 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		next ();
 
 		// TODO: check xml
-		while (current.type != TokenType.XML_CLOSE && current.content != tagname && current.type != TokenType.EOF) {
+		while (!(current.type == TokenType.XML_CLOSE && current.content == tagname) && current.type != TokenType.EOF) {
 			if (current.type == TokenType.XML_OPEN) {
 			} else if (current.type == TokenType.XML_CLOSE) {
 			} else if (current.type == TokenType.XML_COMMENT) {
@@ -311,22 +328,26 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		next ();
 	}
 
-	private void parse_xref () {
+	private Run? parse_xref () {
 		if (!check_xml_open_tag ("xref")) {
 			this.report_unexpected_token (current, "<xref>");
-			return;
+			return null;
 		}
 
 		string linkend = current.attributes.get ("linkend");
 		next ();
 		// TODO register xref
 
+		Run run = factory.create_run (Run.Style.ITALIC);
+		run.content.add (factory.create_text (linkend));
+
 		if (!check_xml_close_tag ("xref")) {
 			this.report_unexpected_token (current, "</xref>");
-			return;
+			return run;
 		}
 
 		next ();
+		return run;
 	}
 
 	private Run? parse_highlighted_template (string tag_name, Run.Style style) {
@@ -674,7 +695,15 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 			parse_docbook_spaces ();
 		}
 
-		append_block_content_not_null (content, parse_docbook_programlisting ());
+		if (current.type == TokenType.XML_OPEN && current.content == "programlisting") {
+			append_block_content_not_null (content, parse_docbook_programlisting ());
+		} else if (current.type == TokenType.XML_OPEN && current.content == "programlisting") {
+			Embedded? img = parse_docbook_inlinegraphic ();
+			Paragraph p = factory.create_paragraph ();
+			append_block_content_not_null (content, p);
+			p.content.add (img);
+
+		}
 
 		parse_docbook_spaces ();
 
@@ -761,6 +790,58 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		return content;
 	}
 
+	private Run? parse_docbook_footnote () {
+		if (!check_xml_open_tag ("footnote")) {
+			this.report_unexpected_token (current, "<footnote>");
+			return null;
+		}
+		next ();
+
+		int counter = this.footnotes.size + 1;
+		Run? nr = factory.create_run (Run.Style.ITALIC);
+		nr.content.add (factory.create_text ("[%d] ".printf (counter)));
+		LinkedList<Block> content = new LinkedList<Block> ();
+		this.footnotes.add (content);
+
+		Token tmp = null;
+		while (tmp != current) {
+			tmp = current;
+			parse_docbook_spaces ();
+
+			Run? run = parse_inline_content ();
+			if (run != null && run.content.size > 0) {
+				Paragraph p = factory.create_paragraph ();
+				p.content.add (run);
+				content.add (p);
+				continue;
+			}
+
+			LinkedList<Block> lst = parse_block_content ();
+			if (lst != null && run.content.size > 0) {
+				content.add_all (lst);
+				continue;
+			}
+		}
+
+		Paragraph first = content.first () as Paragraph;
+		if (first == null) {
+			first = factory.create_paragraph ();
+			content.insert (0, first);
+		}
+
+		Run entry = factory.create_run (Run.Style.ITALIC);
+		entry.content.add (factory.create_text (counter.to_string () + ": "));
+		first.content.insert (0, entry);
+
+		if (!check_xml_close_tag ("footnote")) {
+			this.report_unexpected_token (current, "</footnote>");
+			return nr;
+		}
+
+		next ();
+		return nr;
+	}
+
 	private inline void append_block_content_not_null_all (LinkedList<Block> run, LinkedList<Block>? elements) {
 		if (elements != null) {
 			run.add_all (elements);
@@ -781,6 +862,8 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 
 			if (current.type == TokenType.XML_OPEN && current.content == "itemizedlist") {
 				this.append_block_content_not_null (content, parse_docbook_itemizedlist ());
+			} else if (current.type == TokenType.XML_OPEN && current.content == "programlisting") {
+				this.append_block_content_not_null (content, parse_docbook_programlisting ());
 			} else if (current.type == TokenType.XML_OPEN && current.content == "para") {
 				this.append_block_content_not_null_all (content, parse_docbook_para ());
 			} else if (current.type == TokenType.XML_OPEN && current.content == "informalexample") {
@@ -805,6 +888,45 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		return content;
 	}
 
+	private Run? parse_xml_tag () {
+		if (!check_xml_open_tag ("tag")) {
+			this.report_unexpected_token (current, "<tag>");
+			return null;
+		}
+		string? _class = current.attributes.get ("class");
+		next ();
+
+		parse_docbook_spaces (false);
+
+		if (current.type != TokenType.WORD) {
+			this.report_unexpected_token (current, "<WORD>");
+			return null;
+		}
+
+		Run run = factory.create_run (Run.Style.MONOSPACED);
+		if (_class == null || _class == "starttag") {
+			run.content.add (factory.create_text ("<" + current.content + ">"));
+			next ();
+		} else if (_class == "endtag") {
+			run.content.add (factory.create_text ("</" + current.content + ">"));
+			next ();
+		} else {
+			this.report_unexpected_token (current, "<tag class=\"%s\">".printf (_class));
+			return run;
+		}
+
+		parse_docbook_spaces (false);
+
+
+		if (!check_xml_close_tag ("tag")) {
+			this.report_unexpected_token (current, "</tag>");
+			return run;
+		}
+
+		next ();
+		return run;
+	}
+
 	private void append_inline_content_string (Run run, string current) {
 		Text last_as_text = null;
 
@@ -824,7 +946,7 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 	private Inline create_type_link (string name) {
 		if (name == "TRUE" || name == "FALSE" || name == "NULL") {
 			var monospaced = factory.create_run (Run.Style.MONOSPACED);
-			monospaced.content.add (factory.create_text (name));
+			monospaced.content.add (factory.create_text (name.down ()));
 			return monospaced;
 		} else {
 			Taglets.Link? taglet = factory.create_taglet ("link") as Taglets.Link;
@@ -846,14 +968,20 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 		while (current.type != TokenType.EOF) {
 			if (current.type == TokenType.XML_OPEN && current.content == "firstterm") {
 				append_inline_content_not_null (run, parse_highlighted_template ("firstterm", Run.Style.ITALIC));
+			} else if (current.type == TokenType.XML_OPEN && current.content == "term") {
+				append_inline_content_not_null (run, parse_highlighted_template ("term", Run.Style.ITALIC));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "literal") {
 				append_inline_content_not_null (run, parse_highlighted_template ("literal", Run.Style.ITALIC));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "application") {
 				append_inline_content_not_null (run, parse_highlighted_template ("application", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "emphasis") {
 				append_inline_content_not_null (run, parse_highlighted_template ("emphasis", Run.Style.MONOSPACED));
+			} else if (current.type == TokenType.XML_OPEN && current.content == "pre") {
+				append_inline_content_not_null (run, parse_highlighted_template ("pre", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "code") {
 				append_inline_content_not_null (run, parse_highlighted_template ("code", Run.Style.MONOSPACED));
+			} else if (current.type == TokenType.XML_OPEN && current.content == "guimenuitem") {
+				append_inline_content_not_null (run, parse_highlighted_template ("guimenuitem", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "command") {
 				append_inline_content_not_null (run, parse_highlighted_template ("command", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "option") {
@@ -866,8 +994,12 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 				append_inline_content_not_null (run, parse_highlighted_template ("envar", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "filename") {
 				append_inline_content_not_null (run, parse_highlighted_template ("filename", Run.Style.MONOSPACED));
+			} else if (current.type == TokenType.XML_OPEN && current.content == "parameter") {
+				append_inline_content_not_null (run, parse_highlighted_template ("parameter", Run.Style.MONOSPACED));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "replaceable") {
 				append_inline_content_not_null (run, parse_highlighted_template ("replaceable", Run.Style.ITALIC));
+			} else if (current.type == TokenType.XML_OPEN && current.content == "footnote") {
+				append_inline_content_not_null (run, parse_docbook_footnote ());
 			} else if (current.type == TokenType.XML_OPEN && current.content == "type") {
 				append_inline_content_not_null (run, parse_symbol_link ("type"));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "function") {
@@ -889,7 +1021,9 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
 			} else if (current.type == TokenType.XML_OPEN && current.content == "ulink") {
 				append_inline_content_not_null (run, parse_docbook_link_tempalte ("ulink"));
 			} else if (current.type == TokenType.XML_OPEN && current.content == "xref") {
-				parse_xref ();
+				append_inline_content_not_null (run, parse_xref ());
+			} else if (current.type == TokenType.XML_OPEN && current.content == "tag") {
+				append_inline_content_not_null (run, parse_xml_tag ());
 			} else if (current.type == TokenType.GTKDOC_FUNCTION) {
 				run.content.add (this.create_type_link (current.content));
 				next ();
diff --git a/src/libvaladoc/importer/documentationimporter.vala b/src/libvaladoc/importer/documentationimporter.vala
index 85ba188..1a0f0ba 100755
--- a/src/libvaladoc/importer/documentationimporter.vala
+++ b/src/libvaladoc/importer/documentationimporter.vala
@@ -29,13 +29,9 @@ public abstract class Valadoc.Importer.DocumentationImporter : Object, ResourceL
 	protected Settings settings;
 	protected Api.Tree tree;
 
-	protected Content.ContentFactory factory;
-
 	public abstract string file_extension { get; }
 
 	public DocumentationImporter (Api.Tree tree, ModuleLoader modules, Settings settings) {
-		factory = new Content.ContentFactory (settings, this, modules);
-
 		this.settings = settings;
 		this.modules = null;
 		this.tree = tree;
diff --git a/src/libvaladoc/importer/girdocumentationimporter.vala b/src/libvaladoc/importer/girdocumentationimporter.vala
new file mode 100644
index 0000000..789409b
--- /dev/null
+++ b/src/libvaladoc/importer/girdocumentationimporter.vala
@@ -0,0 +1,635 @@
+/* girdocumentationimporter.vala
+ *
+ * Copyright (C) 2008-2010  JÃrg Billeter
+ * Copyright (C) 2011  Luca Bruno
+ * Copyright (C) 2011  Florian Brosch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	JÃrg Billeter <j bitron ch>
+ * 	Luca Bruno <lucabru src gnome org>
+ *  Florian Brosch <flo brosch gmail com>
+ */
+
+
+using Valadoc;
+using GLib;
+
+
+
+public class Valadoc.Importer.GirDocumentationImporter : DocumentationImporter {
+	public override string file_extension { get { return "gir"; } }
+
+	private MarkupTokenType current_token;
+	private MarkupSourceLocation begin;
+	private MarkupSourceLocation end;
+	private MarkupReader reader;
+
+	private DocumentationParser parser;
+	private ErrorReporter reporter;
+	private Api.SourceFile file;
+
+	private string parent_c_identifier;
+
+	public GirDocumentationImporter (Api.Tree tree, DocumentationParser parser, ModuleLoader modules, Settings settings, ErrorReporter reporter) {
+		base (tree, modules, settings);
+		this.reporter = reporter;
+		this.parser = parser;
+	}
+
+	public override void process (string source_file) {
+		this.file = new Api.SourceFile (new Api.Package (Path.get_basename (source_file), true, null), source_file, null);
+		this.reader = new MarkupReader (source_file, reporter);
+
+		// xml prolog
+		next ();
+		next ();
+
+		next ();
+		parse_repository ();
+
+		reader = null;
+		file = null;
+	}
+
+	private void attach_comment (string cname, Api.GirSourceComment? comment) {
+		if (comment == null) {
+			return ;
+		}
+
+		Api.Node? node = this.tree.search_symbol_cstr (null, cname);
+		if (node == null) {
+			return;
+		}
+
+		Content.Comment? content = this.parser.parse (node, comment);
+		if (content == null) {
+			return;
+		}
+
+		node.documentation = content;
+	}
+
+	private void error (string message) {
+		reporter.error (this.file.relative_path, this.begin.line, this.begin.column, this.end.column, this.reader.get_line_content (this.begin.line), message);
+	}
+
+	private void next () {
+		current_token = reader.read_token (out begin, out end);
+	}
+
+	private void start_element (string name) {
+		if (current_token != MarkupTokenType.START_ELEMENT || reader.name != name) {
+			// error
+			error ("expected start element of `%s'".printf (name));
+		}
+	}
+
+	private void end_element (string name) {
+		if (current_token != MarkupTokenType.END_ELEMENT || reader.name != name) {
+			// error
+			error ("expected end element of `%s'".printf (name));
+		}
+		next ();
+	}
+
+	private const string GIR_VERSION = "1.2";
+
+	private void parse_repository () {
+		start_element ("repository");
+		if (reader.get_attribute ("version") != GIR_VERSION) {
+			error ("unsupported GIR version %s (supported: %s)".printf (reader.get_attribute ("version"), GIR_VERSION));
+			return;
+		}
+		next ();
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "namespace") {
+				parse_namespace ();
+			} else if (reader.name == "include") {
+				parse_include ();
+			} else if (reader.name == "package") {
+				parse_package ();
+			} else if (reader.name == "c:include") {
+				parse_c_include ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `repository'".printf (reader.name));
+				skip_element ();
+			}
+		}
+		end_element ("repository");
+	}
+
+	private void parse_include () {
+		start_element ("include");
+		next ();
+
+		end_element ("include");
+	}
+
+	private void parse_package () {
+		start_element ("package");
+		next ();
+
+		end_element ("package");
+	}
+
+	private void parse_c_include () {
+		start_element ("c:include");
+		next ();
+
+		end_element ("c:include");
+	}
+
+	private void skip_element () {
+		next ();
+
+		int level = 1;
+		while (level > 0) {
+			if (current_token == MarkupTokenType.START_ELEMENT) {
+				level++;
+			} else if (current_token == MarkupTokenType.END_ELEMENT) {
+				level--;
+			} else if (current_token == MarkupTokenType.EOF) {
+				error ("unexpected end of file");
+				break;
+			}
+			next ();
+		}
+	}
+
+	private void parse_namespace () {
+		start_element ("namespace");
+
+		next ();
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "alias") {
+				parse_alias ();
+			} else if (reader.name == "enumeration") {
+				parse_enumeration ();
+			} else if (reader.name == "bitfield") {
+				parse_bitfield ();
+			} else if (reader.name == "function") {
+				parse_method ("function");
+			} else if (reader.name == "callback") {
+				parse_callback ();
+			} else if (reader.name == "record") {
+				parse_record ();
+			} else if (reader.name == "class") {
+				parse_class ();
+			} else if (reader.name == "interface") {
+				parse_interface ();
+			} else if (reader.name == "glib:boxed") {
+				parse_boxed ("glib:boxed");
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else if (reader.name == "constant") {
+				parse_constant ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `namespace'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		end_element ("namespace");
+	}
+
+	private void parse_alias () {
+		start_element ("alias");
+		string c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (c_identifier, comment);
+
+		parse_type ();
+
+		end_element ("alias");
+	}
+
+	private Api.GirSourceComment? parse_symbol_doc () {
+		if (reader.name != "doc") {
+			return null;
+		}
+
+		start_element ("doc");
+		next ();
+
+		Api.GirSourceComment? comment = null;
+
+		if (current_token == MarkupTokenType.TEXT) {
+			comment = new Api.GirSourceComment (reader.content, file, begin.line, begin.column, end.line, end.column);
+			next ();
+		}
+
+		end_element ("doc");
+		return comment;
+	}
+
+	private Api.SourceComment? parse_doc () {
+		if (reader.name != "doc") {
+			return null;
+		}
+
+		start_element ("doc");
+		next ();
+
+		Api.SourceComment? comment = null;
+
+		if (current_token == MarkupTokenType.TEXT) {
+			comment = new Api.SourceComment (reader.content, file, begin.line, begin.column, end.line, end.column);
+			next ();
+		}
+
+		end_element ("doc");
+		return comment;
+	}
+
+	private void parse_enumeration (string element_name = "enumeration") {
+		start_element (element_name);
+		this.parent_c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (this.parent_c_identifier, comment);
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "member") {
+				parse_enumeration_member ();
+			} else if (reader.name == "function") {
+				skip_element ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `%s'".printf (reader.name, element_name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element (element_name);
+	}
+
+	private void parse_bitfield () {
+		parse_enumeration ("bitfield");
+	}
+
+	private void parse_enumeration_member () {
+		start_element ("member");
+		string c_identifier = reader.get_attribute ("c:identifier");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (c_identifier, comment);
+
+		end_element ("member");
+	}
+
+	private void parse_return_value (out Api.SourceComment? comment = null) {
+		start_element ("return-value");
+		next ();
+
+		comment = parse_doc ();
+
+		parse_type ();
+
+		end_element ("return-value");
+	}
+
+	private void parse_parameter (out Api.SourceComment? comment, out string param_name) {
+		start_element ("parameter");
+		param_name = reader.get_attribute ("name");
+		next ();
+
+		comment = parse_doc ();
+
+		if (reader.name == "varargs") {
+			start_element ("varargs");
+			param_name = "...";
+			next ();
+
+			end_element ("varargs");
+		} else {
+			parse_type ();
+		}
+
+		end_element ("parameter");
+	}
+
+	private void parse_type () {
+		skip_element ();
+	}
+
+	private void parse_record () {
+		start_element ("record");
+		this.parent_c_identifier = reader.get_attribute ("c:type");
+		if (this.parent_c_identifier.has_suffix ("Private")) {
+			this.parent_c_identifier = null;
+			skip_element ();
+			return ;
+		}
+
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (this.parent_c_identifier, comment);
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "function") {
+				skip_element ();
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `record'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element ("record");
+	}
+
+	private void parse_class () {
+		start_element ("class");
+		this.parent_c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (this.parent_c_identifier, comment);
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "implements") {
+				skip_element ();
+			} else if (reader.name == "constant") {
+				parse_constant ();
+			} else if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "property") {
+				parse_property ();
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "function") {
+				parse_method ("function");
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "virtual-method") {
+				parse_method ("virtual-method");
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else if (reader.name == "glib:signal") {
+				parse_signal ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `class'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element ("class");
+	}
+
+	private void parse_interface () {
+		start_element ("interface");
+		this.parent_c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (this.parent_c_identifier, comment);
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "prerequisite") {
+				skip_element ();
+			} else if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "property") {
+				parse_property ();
+			} else if (reader.name == "virtual-method") {
+				parse_method ("virtual-method");
+			} else if (reader.name == "function") {
+				parse_method ("function");
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "glib:signal") {
+				parse_signal ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `interface'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element ("interface");
+	}
+
+	private void parse_field () {
+		start_element ("field");
+		string c_identifier = reader.get_attribute ("name");
+		if (this.parent_c_identifier != null) {
+			c_identifier = this.parent_c_identifier + "." + c_identifier;
+		}
+		next ();
+
+		parse_symbol_doc ();
+
+		parse_type ();
+
+		end_element ("field");
+	}
+
+	private void parse_property () {
+		start_element ("property");
+		string c_identifier = "%s:%s".printf (parent_c_identifier, reader.get_attribute ("name").replace ("-", "_"));
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (c_identifier, comment);
+
+		parse_type ();
+
+		end_element ("property");
+	}
+
+	private void parse_callback () {
+		skip_element ();
+	}
+
+	private void parse_constructor () {
+		parse_function ("constructor");
+	}
+
+	private void parse_function (string element_name) {
+		start_element (element_name);
+
+		string? c_identifier = null;
+		switch (element_name) {
+		case "constructor":
+		case "function":
+		case "method":
+			c_identifier = reader.get_attribute ("c:identifier");
+			break;
+
+		case "virtual-method":
+			c_identifier = "%s->%s".printf (this.parent_c_identifier, reader.get_attribute ("name").replace ("-", "_"));
+			break;
+
+		case "glib:signal":
+			c_identifier = "%s::%s".printf (this.parent_c_identifier, reader.get_attribute ("name").replace ("-", "_"));
+			break;
+
+		default:
+			skip_element ();
+			return ;
+		}
+
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+
+		if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+			Api.SourceComment? return_comment;
+			parse_return_value (out return_comment);
+			if (return_comment != null) {
+				if (comment == null) {
+					comment = new Api.GirSourceComment ("", file, begin.line, begin.column, end.line, end.column);
+				}
+				comment.return_comment = return_comment;
+			}
+		}
+
+
+		if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+			start_element ("parameters");
+			next ();
+
+			while (current_token == MarkupTokenType.START_ELEMENT) {
+				Api.SourceComment? param_comment;
+				string? param_name;
+
+				parse_parameter (out param_comment, out param_name);
+
+				if (param_comment != null) {
+					if (comment == null) {
+						comment = new Api.GirSourceComment ("", file, begin.line, begin.column, end.line, end.column);
+					}
+
+					comment.add_parameter_content (param_name, param_comment);
+				}
+			}
+			end_element ("parameters");
+		}
+
+		attach_comment (c_identifier, comment);
+		end_element (element_name);
+	}
+
+	private void parse_method (string element_name) {
+		parse_function (element_name);
+	}
+
+	private void parse_signal () {
+		parse_function ("glib:signal");
+	}
+
+	private void parse_boxed (string element_name) {
+		start_element (element_name);
+
+		this.parent_c_identifier = reader.get_attribute ("name");
+		if (this.parent_c_identifier == null) {
+			this.parent_c_identifier = reader.get_attribute ("glib:name");
+		}
+
+		next ();
+
+		parse_symbol_doc ();
+
+		// TODO: process comments
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "function") {
+				skip_element ();
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `class'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element (element_name);
+	}
+
+	private void parse_union () {
+		start_element ("union");
+		this.parent_c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (this.parent_c_identifier, comment);
+
+		while (current_token == MarkupTokenType.START_ELEMENT) {
+			if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "function") {
+				skip_element ();
+			} else if (reader.name == "record") {
+				parse_record ();
+			} else {
+				// error
+				error ("unknown child element `%s' in `union'".printf (reader.name));
+				skip_element ();
+			}
+		}
+
+		this.parent_c_identifier = null;
+		end_element ("union");
+	}
+
+	private void parse_constant () {
+		start_element ("constant");
+		string c_identifier = reader.get_attribute ("c:type");
+		next ();
+
+		Api.GirSourceComment? comment = parse_symbol_doc ();
+		attach_comment (c_identifier, comment);
+
+		parse_type ();
+
+		end_element ("constant");
+	}
+}
+
diff --git a/src/libvaladoc/importer/valadocdocumentationimporter.vala b/src/libvaladoc/importer/valadocdocumentationimporter.vala
index 16bb108..2cbedc6 100755
--- a/src/libvaladoc/importer/valadocdocumentationimporter.vala
+++ b/src/libvaladoc/importer/valadocdocumentationimporter.vala
@@ -37,11 +37,14 @@ public class Valadoc.Importer.ValadocDocumentationImporter : DocumentationImport
 	private string _cname;
 	private StringBuilder _comment;
 	private SourceLocation _comment_location;
+	protected Content.ContentFactory factory;
+
 
 	private ErrorReporter reporter;
 
 	public ValadocDocumentationImporter (Api.Tree tree, DocumentationParser parser, ModuleLoader modules, Settings settings, ErrorReporter reporter) {
 		base (tree, modules, settings);
+		this.factory = new Content.ContentFactory (settings, this, modules);
 		this.reporter = reporter;
 
 		_scanner = new ValadoDocumentationScanner (settings);
diff --git a/src/libvaladoc/markupreader.vala b/src/libvaladoc/markupreader.vala
index 626508e..825b2b2 100644
--- a/src/libvaladoc/markupreader.vala
+++ b/src/libvaladoc/markupreader.vala
@@ -46,6 +46,7 @@ public class Valadoc.MarkupReader : Object {
 
 	private MappedFile mapped_file;
 
+	private string[] lines;
 	private char* begin;
 	private char* current;
 	private char* end;
@@ -62,6 +63,7 @@ public class Valadoc.MarkupReader : Object {
 		this.filename = filename;
 		this.reporter = reporter;
 
+		lines = content.split ("\n");
 		begin = content;
 		end = begin + content.size ();
 		current = begin;
@@ -77,6 +79,7 @@ public class Valadoc.MarkupReader : Object {
 		try {
 			mapped_file = new MappedFile (filename, false);
 			begin = mapped_file.get_contents ();
+			lines = ((string) begin).split ("\n");
 			end = begin + mapped_file.get_length ();
 
 			current = begin;
@@ -88,6 +91,14 @@ public class Valadoc.MarkupReader : Object {
 		}
 	}
 
+	public string? get_line_content (int line_nr) {
+		if (this.lines.length > line_nr) {
+			return this.lines[line_nr];
+		}
+
+		return null;
+	}
+
 	public string? get_attribute (string attr) {
 		return attributes[attr];
 	}
diff --git a/src/libvaladoc/taglets/tagletlink.vala b/src/libvaladoc/taglets/tagletlink.vala
index 57b1474..633fc41 100755
--- a/src/libvaladoc/taglets/tagletlink.vala
+++ b/src/libvaladoc/taglets/tagletlink.vala
@@ -27,6 +27,12 @@ using Valadoc.Content;
 public class Valadoc.Taglets.Link : InlineTaglet {
 	public string symbol_name { internal set; get; }
 
+	private enum SymbolContext {
+		NORMAL,
+		TYPE
+	}
+
+	private SymbolContext _context = SymbolContext.NORMAL;
 	private Api.Node _symbol;
 
 	public override Rule? get_parser_rule (Rule run_rule) {
@@ -48,8 +54,13 @@ public class Valadoc.Taglets.Link : InlineTaglet {
 		if (symbol_name.has_prefix ("c::")) {
 			_symbol_name = _symbol_name.substring (3);
 			_symbol = api_root.search_symbol_cstr (container, symbol_name);
+			_context = SymbolContext.NORMAL;
+
 			if (_symbol == null) {
-				
+				_symbol = api_root.search_symbol_type_cstr (symbol_name);
+				if (_symbol != null) {
+					_context = SymbolContext.TYPE;
+				}
 			}
 
 			if (_symbol != null) {
@@ -59,7 +70,7 @@ public class Valadoc.Taglets.Link : InlineTaglet {
 			_symbol = api_root.search_symbol_str (container, symbol_name);
 		}
 
-		if (_symbol == null) {
+		if (_symbol == null && symbol_name != "main") {
 			// TODO use ContentElement's source reference
 			reporter.simple_warning ("%s: %s does not exist", container.get_full_name (), symbol_name);
 		}
@@ -71,6 +82,22 @@ public class Valadoc.Taglets.Link : InlineTaglet {
 		var link = new Content.SymbolLink ();
 		link.symbol = _symbol;
 		link.label = symbol_name;
-		return link;
+
+		switch (_context) {
+		case SymbolContext.TYPE:
+			Content.Run content = new Content.Run (Run.Style.MONOSPACED);
+
+			Content.Run keyword = new Content.Run (Run.Style.LANG_KEYWORD);
+			keyword.content.add (new Content.Text ("typeof"));
+			content.content.add (keyword);
+
+			content.content.add (new Content.Text (" ("));
+			content.content.add (link);
+			content.content.add (new Content.Text (")"));
+			return content;
+
+		default:
+			return link;
+		}
 	}
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]