[valadoc] add gir documentation importer



commit 76f8fb19dc8cd090bd69fe0abfd62ac2f2f3fada
Author: Florian Brosch <flo brosch gmail com>
Date:   Fri Aug 20 00:04:48 2010 +0200

    add gir documentation importer

 src/libvaladoc/Makefile.am                         |    5 +-
 src/libvaladoc/api/package.vala                    |    5 +-
 src/libvaladoc/api/tree.vala                       |  105 ++--
 src/libvaladoc/{importer => }/ctyperesolver.vala   |    2 +-
 .../documentation/documentationparser.vala         |  536 +++++++++++++++-
 .../documentation/girdocumentationscanner.vala     |  610 +++++++++++++++++
 src/libvaladoc/html/htmlrenderer.vala              |   20 +-
 src/libvaladoc/importer/documentationimporter.vala |    9 +-
 .../importer/girdocumentationbuilder.vala          |   56 ++
 .../importer/girdocumentationimporter.vala         |  687 ++++++++++++++++++++
 src/libvaladoc/parser/tokentype.vala               |  118 ++++-
 src/libvaladoc/settings.vala                       |    1 -
 src/libvaladoc/taglets/tagletlink.vala             |   15 +-
 src/libvaladoc/taglets/tagletparam.vala            |    2 +-
 src/libvaladoc/taglets/tagletsee.vala              |   13 +-
 src/valadoc/valadoc.vala                           |   26 +-
 16 files changed, 2110 insertions(+), 100 deletions(-)
---
diff --git a/src/libvaladoc/Makefile.am b/src/libvaladoc/Makefile.am
index b769576..d95cd94 100644
--- a/src/libvaladoc/Makefile.am
+++ b/src/libvaladoc/Makefile.am
@@ -30,13 +30,16 @@ libvaladoc_la_VALASOURCES = \
 	settings.vala \
 	markupwriter.vala \
 	devhelp-markupwriter.vala \
+	ctyperesolver.vala \
+	documentation/girdocumentationscanner.vala \
 	documentation/commentscanner.vala \
 	documentation/documentation.vala \
 	documentation/documentationparser.vala \
 	documentation/wiki.vala \
 	documentation/wikiscanner.vala \
+	importer/girdocumentationimporter.vala \
 	importer/documentationimporter.vala \
-	importer/ctyperesolver.vala \
+	importer/girdocumentationbuilder.vala \
 	api/array.vala \
 	api/class.vala \
 	api/constant.vala \
diff --git a/src/libvaladoc/api/package.vala b/src/libvaladoc/api/package.vala
index 16ddd3c..031ad40 100644
--- a/src/libvaladoc/api/package.vala
+++ b/src/libvaladoc/api/package.vala
@@ -22,6 +22,7 @@
 
 using Gee;
 using Valadoc.Content;
+using Valadoc.Importer;
 
 public class Valadoc.Api.Package : Node {
 	private ArrayList<Vala.SourceFile> vfiles = new ArrayList<Vala.SourceFile> ();
@@ -110,10 +111,6 @@ public class Valadoc.Api.Package : Node {
 			.get ();
 	}
 
-	internal void import_documentation (string path, Settings settings, DocumentationImporter importer) {
-		importer.process (path, settings, this);
-	}
-
 	internal Namespace get_namespace (Tree root, Vala.Symbol symbol) {
 		Vala.Symbol namespace_symbol = symbol;
 		while (!(namespace_symbol is Vala.Namespace)) {
diff --git a/src/libvaladoc/api/tree.vala b/src/libvaladoc/api/tree.vala
index 3a90dd5..7a3d698 100644
--- a/src/libvaladoc/api/tree.vala
+++ b/src/libvaladoc/api/tree.vala
@@ -31,23 +31,18 @@ public class Valadoc.Api.Tree {
 	private ArrayList<Package> packages = new ArrayList<Package>();
 	private Package source_package = null;
 	private Settings settings;
-	private Vala.CodeContext context;
 	private ErrorReporter reporter;
 	private Package sourcefiles = null;
 	private CTypeResolver _cresolver = null;
 
-	public WikiPageTree? wikitree {
+	internal Vala.CodeContext context {
 		private set;
 		get;
 	}
 
-	public CTypeResolver cresolver {
-		get {
-			if (_cresolver == null) {
-				_cresolver = new CTypeResolver (this);
-			}
-			return _cresolver;
-		}
+	public WikiPageTree? wikitree {
+		private set;
+		get;
 	}
 
 	public Collection<Package> get_package_list () {
@@ -117,6 +112,14 @@ public class Valadoc.Api.Tree {
 		return null;
 	}
 
+	public Node? search_symbol_cstr (string cname) {
+		if (_cresolver == null) {
+			_cresolver = new CTypeResolver (this);
+		}
+
+		return _cresolver.resolve_symbol (cname);
+	}
+
 	public Node? search_symbol_str (Node? element, string symname) {
 		string[] path = split_name (symname);
 
@@ -208,6 +211,25 @@ public class Valadoc.Api.Tree {
 		}
 	}
 
+	private void add_deps (string file_path, string pkg_name) {
+		if (FileUtils.test (file_path, FileTest.EXISTS)) {
+			try {
+				string deps_content;
+				ulong deps_len;
+				FileUtils.get_contents (file_path, out deps_content, out deps_len);
+				foreach (string dep in deps_content.split ("\n")) {
+					dep.strip ();
+					if (dep != "") {
+						if (!add_package (dep)) {
+							Vala.Report.error (null, "%s, dependency of %s, not found in specified Vala API directories".printf (dep, pkg_name));
+						}
+					}
+				}
+			} catch (FileError e) {
+				Vala.Report.error (null, "Unable to read dependency file: %s".printf (e.message));
+			}
+		}
+	}
 
 	private bool add_package (string pkg) {
 		if (context.has_package (pkg)) {
@@ -216,7 +238,6 @@ public class Valadoc.Api.Tree {
 		}
 
 		var package_path = context.get_package_path (pkg, settings.vapi_directories);
-
 		if (package_path == null) {
 			return false;
 		}
@@ -230,30 +251,12 @@ public class Valadoc.Api.Tree {
 		Package vdpkg = new Package (vfile, pkg, true);
 		this.packages.add (vdpkg);
 
-		var deps_filename = Path.build_filename (Path.get_dirname (package_path), "%s.deps".printf (pkg));
-		if (FileUtils.test (deps_filename, FileTest.EXISTS)) {
-			try {
-				string deps_content;
-				ulong deps_len;
-				FileUtils.get_contents (deps_filename, out deps_content, out deps_len);
-				foreach (string dep in deps_content.split ("\n")) {
-					dep.strip ();
-					if (dep != "") {
-						if (!add_package (dep)) {
-							Vala.Report.error (null, "%s, dependency of %s, not found in specified Vala API directories".printf (dep, pkg));
-						}
-					}
-				}
-			} catch (FileError e) {
-				Vala.Report.error (null, "Unable to read dependency file: %s".printf (e.message));
-			}
-		}
-
+		add_deps (Path.build_filename (Path.get_dirname (package_path), "%s.deps".printf (pkg)), pkg);
 		return true;
 	}
 
 	// copied from valacodecontext.vala
-	private string? get_file_path (string basename, string data_dir, string[] directories) {
+	private string? get_file_path (string basename, string[] directories) {
 		string filename = null;
 
 		if (directories != null) {
@@ -266,7 +269,7 @@ public class Valadoc.Api.Tree {
 		}
 
 		foreach (string dir in Environment.get_system_data_dirs ()) {
-			filename = Path.build_filename (dir, data_dir, basename);
+			filename = Path.build_filename (dir, basename);
 			if (FileUtils.test (filename, FileTest.EXISTS)) {
 				return filename;
 			}
@@ -275,21 +278,6 @@ public class Valadoc.Api.Tree {
 		return null;
 	}
 
-	// copied from valacodecontext.vala
-	private string? get_external_documentation_path (string pkg) {
-		var path = get_file_path (Path.build_filename (pkg, "documentation.xml"), "vala/vapi/documentation", settings.docu_directories);
-
-		if (path == null) {
-			/* last chance: try the package compiled-in vapi dir */
-			var filename = Path.build_filename (Config.vapi_dir, "vapi", "documentation", pkg, "documentation.xml");
-			if (FileUtils.test (filename, FileTest.EXISTS)) {
-				path = filename;
-			}
-		}
-
-		return path;
-	}
-
 	public void add_depencies (string[] packages) {
 		foreach (string package in packages) {
 			if (!add_package (package)) {
@@ -332,12 +320,13 @@ public class Valadoc.Api.Tree {
 					context.add_source_file (source_file);
 				} else if (source.has_suffix (".vapi")) {
 					string file_name = Path.get_basename (source);
-					file_name = file_name.ndup ( file_name.size() - ".vapi".size() );
+					file_name = file_name.ndup (file_name.size() - ".vapi".size());
 
 					var vfile = new Vala.SourceFile (context, rpath, true);
 					Package vdpkg = new Package (vfile, file_name);
 					context.add_source_file (vfile);
 					this.packages.add (vdpkg);
+					add_deps (Path.build_filename (Path.get_dirname (source), "%s.deps".printf (file_name)), file_name);
 				} else if (source.has_suffix (".c")) {
 					context.add_c_source_file (rpath);
 				} else {
@@ -376,6 +365,15 @@ public class Valadoc.Api.Tree {
 		return true;
 	}
 
+	private Package? find_package_by_name (string name) {
+		foreach (Package pkg in packages) {
+			if (name == pkg.name) {
+				return pkg;
+			}
+		}
+		return null;
+	}
+
 	private Package? find_package_for_file (Vala.SourceFile vfile) {
 		foreach (Package pkg in this.packages) {
 			if (pkg.is_package_for_file (vfile))
@@ -426,15 +424,16 @@ public class Valadoc.Api.Tree {
 		}
 	}
 
-	public void import_documentation (DocumentationImporter importer) {
-		foreach (Package pkg in this.packages) {
-			string? path = (pkg.is_package)? get_external_documentation_path (pkg.name) : null;
+	public void import_documentation (DocumentationImporter importer, string[] packages, string[] import_directories) {
+		foreach (string pkg_name in packages) {
+			string? path = get_file_path ("%s.%s".printf (pkg_name, importer.file_extension), import_directories);
 
-			if (pkg.is_browsable (settings) && path != null) {
-				pkg.import_documentation (path, settings, importer);
+			if (path == null) {
+				Vala.Report.error (null, "%s not found in specified import directories".printf (pkg_name));
+			} else {
+				importer.process (path);
 			}
 		}
-
 	}
 
 	internal Symbol? search_vala_symbol (Vala.Symbol symbol) {
diff --git a/src/libvaladoc/importer/ctyperesolver.vala b/src/libvaladoc/ctyperesolver.vala
similarity index 98%
rename from src/libvaladoc/importer/ctyperesolver.vala
rename to src/libvaladoc/ctyperesolver.vala
index 83af779..b9641bf 100644
--- a/src/libvaladoc/importer/ctyperesolver.vala
+++ b/src/libvaladoc/ctyperesolver.vala
@@ -24,7 +24,7 @@
 using Valadoc.Api;
 using Gee;
 
-public class Valadoc.Importer.CTypeResolver : Visitor {
+public class Valadoc.CTypeResolver : Visitor {
 	private Map<string, Api.Node> nodes = new HashMap<string, Api.Node> ();
 
 	public CTypeResolver (Api.Tree tree) {
diff --git a/src/libvaladoc/documentation/documentationparser.vala b/src/libvaladoc/documentation/documentationparser.vala
index 869c5e0..0c735c9 100644
--- a/src/libvaladoc/documentation/documentationparser.vala
+++ b/src/libvaladoc/documentation/documentationparser.vala
@@ -21,6 +21,7 @@
  */
 
 using Valadoc.Content;
+using Valadoc.Importer;
 using Gee;
 
 
@@ -42,7 +43,16 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 		_comment_parser = new Parser (_settings, _comment_scanner, _reporter);
 		_comment_scanner.set_parser (_comment_parser);
 
-		init_rules ();
+		_gir_scanner = new GirDocumentationScanner (_settings);
+		_gir_parser = new Parser (_settings, _gir_scanner, _reporter);
+		_gir_scanner.set_parser (_gir_parser);
+
+		_gir_taglet_scanner = new GirDocumentationScanner (_settings);
+		_gir_taglet_parser = new Parser (_settings, _gir_taglet_scanner, _reporter);
+		_gir_taglet_scanner.set_parser (_gir_taglet_parser);
+
+		init_valadoc_rules ();
+		init_girdoc_rules ();
 	}
 
 	private Settings _settings;
@@ -51,13 +61,17 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 	private ModuleLoader _modules;
 
 	private ContentFactory _factory;
+	private GirDocumentationScanner _gir_taglet_scanner;
+	private GirDocumentationScanner _gir_scanner;
 	private WikiScanner _wiki_scanner;
 	private CommentScanner _comment_scanner;
+	private Parser _gir_parser;
+	private Parser _gir_taglet_parser;
 	private Parser _wiki_parser;
 	private Parser _comment_parser;
 	
 	private Parser _parser;
-	private WikiScanner _scanner;
+	private Scanner _scanner;
 
 	public Comment? parse (Api.Node element, Vala.Comment source_comment) {
 		weak string content = source_comment.content;
@@ -71,6 +85,48 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 		}
 	}
 
+	public Comment? parse_gir_comment (Api.Node element, GirDocumentationBuilder doc) {
+		try {
+			_stack.clear ();
+
+			if (doc.content != null) {
+				_parser = _gir_parser;
+				_scanner = _gir_scanner;
+				_gir_parser.parse (doc.content, doc.source_reference.file.filename, doc.source_reference.first_line, doc.source_reference.first_column);
+			} else {
+				push (_factory.create_comment ());
+			}
+
+
+			_parser = _gir_taglet_parser;
+			_scanner = _gir_taglet_scanner;
+
+			if (doc.return_value != null && !(element is Api.Method && ((Api.Method) element).is_constructor)) {
+				push (_factory.create_taglet ("return"));
+				_gir_taglet_parser.parse (doc.return_value.content, doc.return_value.source_reference.file.filename, doc.return_value.source_reference.first_line, doc.return_value.source_reference.first_column);
+			}
+
+			var iter = doc.parameters.map_iterator ();
+			for (iter.next (); iter.has_next (); iter.next ()) {
+				var val = iter.get_value ();
+				var key = iter.get_key ();
+				if (key != "self") {
+					var param = _factory.create_taglet ("param") as Taglets.Param;
+					param.parameter_name = key;
+					push (param);
+					_gir_taglet_parser.parse (val.content, val.source_reference.file.filename, val.source_reference.first_line, val.source_reference.first_column);
+				}
+			}
+
+			var doc_comment = (Comment) pop ();
+			doc_comment.check (_tree, element, _reporter, _settings);
+
+			return doc_comment;
+		} catch (ParserError error) {
+			return null;
+		}
+	}
+
 	public Page? parse_wikipage (WikiPage page, Api.Package pkg) {
 		if (page.documentation != null) {
 			return page.documentation;
@@ -216,7 +272,465 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 		text.content += str;
 	}
 
-	private void init_rules () {
+	private void gir_append_link (Token token) throws ParserError {
+		var taglet = _factory.create_taglet ("link") as Taglets.Link;
+		if (!(taglet is Inline)) {
+			_parser.error ("Invalid taglet in this context: link");
+		}
+		taglet.symbol_name = "c::"+token.to_string ();
+		push (taglet);
+	}
+
+	private bool _gir_is_first_paragraph = true;
+
+	private void init_girdoc_rules () {
+		StubRule run = new StubRule ();
+		run.set_name ("Run");
+
+		TokenType.Action add_text = (token) => {
+			add_content_string (token.to_string ());
+		};
+
+		TokenType dot = TokenType.GTKDOC_DOT.action ((token) => { add_content_string ("."); });
+		TokenType word = TokenType.GTKDOC_ANY_WORD.action (add_text);
+		TokenType space = TokenType.GTKDOC_SPACE.action (add_text);
+		TokenType newline = TokenType.GTKDOC_EOL.action ((token) => { add_content_string (" "); });
+		Rule unprinted_space = Rule.one_of ({ space.action ((token) => {}), newline.action ((token) => {}) });
+		Rule unprinted_spaces = Rule.many ({ unprinted_space });
+		Rule optional_unprinted_spaces = Rule.option ({ unprinted_spaces });
+
+		Rule raw_text = Rule.many ({
+			Rule.one_of ({
+				word, space, newline, dot
+			})
+			.set_reduce (() => { ((InlineContent) peek ()).content.add ((Inline) pop ()); })
+		})
+		.set_name ("RawText");
+
+		Rule run_with_dot = Rule.many ({
+			Rule.one_of ({
+				run, dot
+			})
+			.set_reduce (() => { ((InlineContent) peek ()).content.add ((Inline) pop ()); })
+		})
+		.set_name ("FormatedText");
+
+		Rule xml_comment_raw = Rule.seq ({
+			TokenType.GTKDOC_XML_COMMENT_START,
+			Rule.option ({
+				Rule.many ({
+					Rule.one_of ({
+						word.action ((token) => {}),
+						space.action ((token) => {}),
+						newline.action ((token) => {}),
+						dot.action ((token) => {})
+						//TODO
+					})
+				})
+			}),
+			TokenType.GTKDOC_XML_COMMENT_END
+		});
+		
+
+		Rule xml_comment = Rule.seq ({
+			xml_comment_raw
+		})
+		.set_name ("XmlComment")
+		.set_start (() => { push (_factory.create_text ("")); });
+
+
+		Rule word_or_function = Rule.seq ({
+			TokenType.GTKDOC_ANY_WORD.action ((token) => { push (token); }),
+			Rule.option ({
+				Rule.many ({
+					Rule.one_of ({
+						space.action ((token) => {
+							if (((Token) peek ()).is_word) {
+								push (token);
+							}
+						}),
+						xml_comment_raw
+					})
+				})
+			}),
+			Rule.option ({
+				TokenType.GTKDOC_FUNCTION_BRACKETS.action ((token) => {
+					var last_token = (Token) pop ();
+					if (!last_token.is_word) {
+						last_token = (Token) pop ();
+					}
+
+					gir_append_link (last_token);
+				})
+			}).set_skip (() => {
+				var last_token = (Token) pop ();
+				if (last_token.is_word) {
+					add_content_string (last_token.to_string ());
+				} else {
+					add_content_string (((Token) pop ()).to_string ());
+					add_content_string (last_token.to_string ());
+				}
+			})
+		});
+
+		Rule node_link = Rule.one_of ({
+			Rule.seq ({
+				TokenType.GTKDOC_SYMBOL,
+				word.action ((token) => {
+					switch (token.to_string ()) {
+					case "FALSE":
+					case "TRUE":
+					case "NULL":
+						var myrun = _factory.create_run (Run.Style.MONOSPACED);
+						var mytext = _factory.create_text ();
+						mytext.content = token.to_string ().down ();
+						myrun.content.add (mytext);
+						push (myrun);
+						break;
+
+					default:
+						gir_append_link (token);
+						break;
+					}
+				})
+			})
+		})
+		.set_name ("TypeLink");
+
+		Rule link_element = Rule.seq ({
+			TokenType.GTKDOC_LINK_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_LINK_ELEMENT_CLOSE
+		})
+		.set_name ("Link")
+		.set_start (() => { push (_factory.create_run (Run.Style.NONE)); });
+
+		Rule filename_element = Rule.seq ({
+			TokenType.GTKDOC_FILENAME_ELEMENT_OPEN,
+			raw_text,
+			TokenType.GTKDOC_FILENAME_ELEMENT_CLOSE
+		})
+		.set_name ("Filename")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule envar_element = Rule.seq ({
+			TokenType.GTKDOC_ENVAR_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_ENVAR_ELEMENT_CLOSE
+		})
+		.set_name ("Envar")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule emphasis_element = Rule.seq ({
+			TokenType.GTKDOC_EMPHASIS_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_EMPHASIS_ELEMENT_CLOSE
+		})
+		.set_name ("Emphasis")
+		.set_start (() => { push (_factory.create_run (Run.Style.ITALIC)); });
+
+		Rule option_element = Rule.seq ({
+			TokenType.GTKDOC_OPTION_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_OPTION_ELEMENT_CLOSE
+		})
+		.set_name ("Option")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule term_element = Rule.seq ({
+			TokenType.GTKDOC_TERM_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_TERM_ELEMENT_CLOSE
+		})
+		.set_name ("Term")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule literal_element = Rule.seq ({
+			TokenType.GTKDOC_LITERAL_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_LITERAL_ELEMENT_CLOSE
+		})
+		.set_name ("Literal")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule replaceable_element = Rule.seq ({
+			TokenType.GTKDOC_REPLACEABLE_ELEMENT_OPEN,
+			raw_text,
+			TokenType.GTKDOC_REPLACEABLE_ELEMENT_CLOSE
+		})
+		.set_name ("Replaceable")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule guimenuitem_element = Rule.seq ({
+			TokenType.GTKDOC_GUI_MENU_ITEM_ELEMENT_OPEN,
+			raw_text,
+			TokenType.GTKDOC_GUI_MENU_ITEM_ELEMENT_CLOSE
+		})
+		.set_name ("GuiMenuItem")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+		Rule struct_name_element = Rule.seq ({
+			TokenType.GTKDOC_STRUCTNAME_ELEMENT_OPEN,
+			word.action ((token) => {
+				gir_append_link (token);
+			}),
+			TokenType.GTKDOC_STRUCTNAME_ELEMENT_CLOSE
+		})
+		.set_name ("Structname");
+
+		Rule param = Rule.one_of ({
+			Rule.seq ({
+				TokenType.GTKDOC_PARAM,
+				word
+			})
+		})
+		.set_name ("Parameter")
+		.set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); })
+		.set_reduce (() => { ((InlineContent) peek ()).content.add ((Inline) pop ()); });
+
+		run.set_rule (
+			Rule.many ({
+				Rule.one_of ({
+					newline, space, word_or_function, node_link, param, struct_name_element, link_element, xml_comment,
+					literal_element, guimenuitem_element, replaceable_element, envar_element, emphasis_element,
+					option_element,  term_element, filename_element
+				})
+			})
+			.set_name ("Run")
+		);
+
+		Rule paragraph_element = Rule.seq ({
+			TokenType.GTKDOC_PARA_ELEMENT_OPEN,
+			run_with_dot,
+			TokenType.GTKDOC_PARA_ELEMENT_CLOSE,
+			Rule.option ({
+				Rule.many({
+					Rule.one_of ({
+						space.action ((token) => {}),
+						newline.action ((token) => {})
+					})
+				})
+			})
+		})
+		.set_name ("ParagraphElement")
+		.set_start (() => { push (_factory.create_paragraph ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule source = Rule.seq ({
+			TokenType.GTKDOC_SOURCE_OPEN.action ((token) => { ((GirDocumentationScanner) _scanner).set_code_escape_mode (true); }),
+			Rule.many ({
+				word.action ((token) => { ((SourceCode) peek ()).code = token.to_string (); })
+			})
+			.set_start (() => { push (_factory.create_source_code ()); })
+			.set_reduce (() => { ((Paragraph) peek ()).content.add ((Inline) pop ()); }),
+			TokenType.GTKDOC_SOURCE_CLOSE.action ((token) => { ((GirDocumentationScanner) _scanner).set_code_escape_mode (false); }),
+			optional_unprinted_spaces
+		})
+		.set_name ("Source")
+		.set_start (() => { push (_factory.create_paragraph ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule program_listing_element = Rule.seq ({
+			TokenType.GTKDOC_PROGRAMLISTING_ELEMENT_OPEN.action ((token) => { ((GirDocumentationScanner) _scanner).set_code_element_escape_mode (true); }),
+			Rule.many ({
+				word.action ((token) => { ((SourceCode) peek ()).code = token.to_string (); })
+			})
+			.set_start (() => { push (_factory.create_source_code ()); })
+			.set_reduce (() => { ((Paragraph) peek ()).content.add ((Inline) pop ()); }),
+			TokenType.GTKDOC_PROGRAMLISTING_ELEMENT_CLOSE.action ((token) => { ((GirDocumentationScanner) _scanner).set_code_element_escape_mode (false); }),
+			optional_unprinted_spaces
+		})
+		.set_name ("ProgramListing")
+		.set_start (() => { push (_factory.create_paragraph ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule example_element = Rule.seq ({
+			Rule.one_of ({
+				program_listing_element,
+				Rule.seq ({
+					TokenType.GTKDOC_EXAMPLE_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+					Rule.option ({
+						TokenType.GTKDOC_TITLE_ELEMENT_OPEN,
+						Rule.many ({
+							Rule.one_of ({ word.action ((token) => {}) })
+						}),
+						TokenType.GTKDOC_TITLE_ELEMENT_CLOSE,
+						optional_unprinted_spaces
+					}),
+					program_listing_element,
+					TokenType.GTKDOC_EXAMPLE_ELEMENT_CLOSE
+				})
+			}),
+			optional_unprinted_spaces
+		})
+		.set_name ("SourceElement");
+
+		Rule paragraph = Rule.seq ({
+			run_with_dot
+		})
+		.set_name ("Paragraph")
+		.set_start (() => { push (_factory.create_paragraph ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule note_element = Rule.seq ({
+			TokenType.GTKDOC_NOTE_ELEMENT_OPEN,
+			optional_unprinted_spaces,
+			Rule.option ({
+				paragraph
+			}),
+			Rule.option ({
+				Rule.many ({
+					paragraph_element,
+					Rule.option ({ paragraph })
+				})
+			}),
+			TokenType.GTKDOC_NOTE_ELEMENT_CLOSE,
+			optional_unprinted_spaces
+		})
+		.set_name ("Note");
+
+		Rule warning_element = Rule.seq ({
+			TokenType.GTKDOC_WARNING_ELEMENT_OPEN,
+			optional_unprinted_spaces,
+			Rule.option ({
+				paragraph
+			}),
+			Rule.option ({
+				Rule.many ({
+					paragraph_element,
+					Rule.option ({ paragraph })
+				})
+			}),
+			TokenType.GTKDOC_WARNING_ELEMENT_CLOSE,
+			optional_unprinted_spaces
+		})
+		.set_name ("Warning");
+
+		Rule variable_list_element = Rule.seq ({
+			TokenType.GTKDOC_VARIABLE_LIST_ELEMENT_OPEN,
+			optional_unprinted_spaces,
+			Rule.many ({
+				Rule.seq ({
+					TokenType.GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+
+					TokenType.GTKDOC_TERM_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+					run_with_dot,
+					TokenType.GTKDOC_TERM_ELEMENT_CLOSE.action ((token) => { add_content_string (": "); }),
+					optional_unprinted_spaces,
+
+					TokenType.GTKDOC_LIST_ITEM_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+					run_with_dot,
+					TokenType.GTKDOC_LIST_ITEM_ELEMENT_CLOSE,
+					optional_unprinted_spaces,
+
+					TokenType.GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_CLOSE,
+					optional_unprinted_spaces
+				})
+				.set_start (() => { push (_factory.create_list_item ()); })
+				.set_reduce (() => { ((Content.List) peek ()).items.add ((Content.ListItem) pop ()); })
+			}),
+			TokenType.GTKDOC_VARIABLE_LIST_ELEMENT_CLOSE,
+			optional_unprinted_spaces
+		})
+		.set_name ("VariableList")
+		.set_start (() => { push (_factory.create_list ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule list_element = Rule.seq ({
+			TokenType.GTKDOC_ITEMIZED_LIST_ELEMENT_OPEN,
+			optional_unprinted_spaces,
+			Rule.many ({
+				Rule.seq ({
+					TokenType.GTKDOC_LIST_ITEM_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+					run_with_dot,
+					TokenType.GTKDOC_LIST_ITEM_ELEMENT_CLOSE,
+					optional_unprinted_spaces
+				})
+				.set_start (() => { push (_factory.create_list_item ()); })
+				.set_reduce (() => { ((Content.List) peek ()).items.add ((Content.ListItem) pop ()); })
+			}),
+			TokenType.GTKDOC_ITEMIZED_LIST_ELEMENT_CLOSE,
+			optional_unprinted_spaces
+		})
+		.set_name ("ItemizedList")
+		.set_start (() => { push (_factory.create_list ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule simple_list_element = Rule.seq ({
+			TokenType.GTKDOC_SIMPLELIST_ELEMENT_OPEN,
+			optional_unprinted_spaces,
+			Rule.many ({
+				Rule.seq ({
+					TokenType.GTKDOC_MEMBER_ELEMENT_OPEN,
+					optional_unprinted_spaces,
+					run_with_dot,
+					TokenType.GTKDOC_MEMBER_ELEMENT_CLOSE,
+					optional_unprinted_spaces
+				})
+				.set_start (() => { push (_factory.create_list_item ()); })
+				.set_reduce (() => { ((Content.List) peek ()).items.add ((Content.ListItem) pop ()); })
+			}),
+			TokenType.GTKDOC_SIMPLELIST_ELEMENT_CLOSE,
+			optional_unprinted_spaces
+		})
+		.set_name ("SimpleList")
+		.set_start (() => { push (_factory.create_list ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); });
+
+		Rule block_element = Rule.one_of ({
+			paragraph_element, list_element, note_element, warning_element, source,
+			example_element, variable_list_element, simple_list_element
+		})
+		.set_name ("Block");
+
+		// TODO: find out why the clean version does not work ...
+		Rule first_paragraph = Rule.many ({
+			Rule.one_of ({
+				Rule.seq ({ run }).set_reduce (() => { ((InlineContent) peek ()).content.add ((Inline) pop ()); }),
+				TokenType.GTKDOC_DOT.action ((token) => {
+					((InlineContent) peek ()).content.add (_factory.create_text ("."));
+					if (_gir_is_first_paragraph) {
+						((BlockContent) peek ()).content.add ((Block) pop ());
+						push (_factory.create_paragraph ());
+						_gir_is_first_paragraph = false;
+					}
+				})
+			})
+		})
+		.set_name ("BriefDescription")
+		.set_start (() => { push (_factory.create_paragraph ()); })
+		.set_reduce (() => { ((BlockContent) peek ()).content.add ((Block) pop ()); _gir_is_first_paragraph = true; });
+
+		Rule comment = Rule.seq ({
+			Rule.option ({
+				first_paragraph
+			}),
+			Rule.option ({
+				Rule.many ({
+					block_element,
+					Rule.option ({ paragraph })
+				})
+			})
+		})
+		.set_name ("Comment")
+		.set_start (() => { push (_factory.create_comment ()); });
+
+		Rule taglet = Rule.many ({
+			run_with_dot
+		})
+		.set_name ("Taglet")
+		.set_reduce (() => { ((Comment) peek ()).taglets.add ((Taglet) pop ()); });
+
+		_gir_taglet_parser.set_root_rule (taglet);
+		_gir_parser.set_root_rule (comment);
+	}
+
+	private void init_valadoc_rules () {
 		// Inline rules
 
 		StubRule run = new StubRule ();
@@ -311,35 +825,35 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 
 		Rule embedded =
 			Rule.seq ({
-				TokenType.DOUBLE_OPEN_BRACE.action (() => { _scanner.set_url_escape_mode (true); }),
+				TokenType.DOUBLE_OPEN_BRACE.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (true); }),
 				TokenType.any_word ().action ((token) => { ((Embedded) peek ()).url = token.to_string (); }),
 				Rule.option ({
-					TokenType.PIPE.action (() => { _scanner.set_url_escape_mode (false); }),
+					TokenType.PIPE.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); }),
 					text
 				})
 				.set_reduce (() => { var caption = pop () as Text; ((Embedded) peek ()).caption = caption.content; }),
-				TokenType.DOUBLE_CLOSED_BRACE.action (() => { _scanner.set_url_escape_mode (false); })
+				TokenType.DOUBLE_CLOSED_BRACE.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); })
 			})
 			.set_name ("Embedded")
 			.set_start (() => { push (_factory.create_embedded ()); });
 		Rule link =
 			Rule.seq ({
-				TokenType.DOUBLE_OPEN_BRACKET.action (() => { _scanner.set_url_escape_mode (true); }),
+				TokenType.DOUBLE_OPEN_BRACKET.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (true); }),
 				TokenType.any_word ().action ((token) => { ((Link) peek ()).url = token.to_string (); }),
 				Rule.option ({
-					TokenType.PIPE.action (() => { _scanner.set_url_escape_mode (false); }),
+					TokenType.PIPE.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); }),
 					run
 				}),
-				TokenType.DOUBLE_CLOSED_BRACKET.action (() => { _scanner.set_url_escape_mode (false); })
+				TokenType.DOUBLE_CLOSED_BRACKET.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); })
 			})
 			.set_name ("Link")
 			.set_start (() => { push (_factory.create_link ()); });
 
 		Rule source_code =
 			Rule.seq ({
-				TokenType.TRIPLE_OPEN_BRACE.action ((token) => { _scanner.set_code_escape_mode (true); }),
+				TokenType.TRIPLE_OPEN_BRACE.action ((token) => { ((WikiScanner) _scanner).set_code_escape_mode (true); }),
 				TokenType.any_word ().action ((token) => { ((SourceCode) peek ()).code = token.to_string (); }),
-				TokenType.TRIPLE_CLOSED_BRACE.action ((token) => { _scanner.set_code_escape_mode (false); })
+				TokenType.TRIPLE_CLOSED_BRACE.action ((token) => { ((WikiScanner) _scanner).set_code_escape_mode (false); })
 			})
 			.set_name ("SourceCode")
 			.set_start (() => { push (_factory.create_source_code ()); });
diff --git a/src/libvaladoc/documentation/girdocumentationscanner.vala b/src/libvaladoc/documentation/girdocumentationscanner.vala
new file mode 100644
index 0000000..aed78db
--- /dev/null
+++ b/src/libvaladoc/documentation/girdocumentationscanner.vala
@@ -0,0 +1,610 @@
+/* girdocuscanner.vala
+ *
+ * Copyright (C) 2010 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:
+ * 	Florian Brosch <flo brosch gmail com>
+ */
+
+using Valadoc;
+
+public class Valadoc.Importer.GirDocumentationScanner : Object, Scanner {
+
+	public GirDocumentationScanner (Settings settings) {
+		_settings = settings;
+	}
+
+	private Settings _settings;
+	private Parser _parser;
+
+	private string _content;
+	private int _index;
+	private bool _stop;
+	private int _last_index;
+	private int _last_line;
+	private int _last_column;
+	private int _line;
+	private int _column;
+	private bool _code_element_escape_mode;
+	private bool _code_escape_mode;
+	private bool _node_name;
+	private unichar _last_char;
+	private int _skip;
+	private StringBuilder _current_string = new StringBuilder ();
+
+	public void set_parser (Parser parser) {
+		_parser = parser;
+	}
+
+	public void reset () {
+		_stop = false;
+		_last_index = 0;
+		_last_line = 0;
+		_last_column = 0;
+		_line = 0;
+		_column = 0;
+		_code_element_escape_mode = false;
+		_code_escape_mode = false;
+		_node_name = false;
+		_last_char = 0;
+		_skip = 0;
+		_current_string.erase (0, -1);
+	}
+
+	public void scan (string _content) throws ParserError {
+		this._content = _content;
+		for (_index = 0; !_stop && _index < _content.length; _index++) {
+			unichar c = _content[_index];
+			accept (c);
+		}
+	}
+
+	public void end () throws ParserError {
+		emit_token (TokenType.GTKDOC_EOF);
+	}
+
+	public void stop () {
+		_stop = true;
+	}
+
+	public void set_code_element_escape_mode (bool escape_mode) {
+		_code_element_escape_mode = escape_mode;
+	}
+
+	public void set_code_escape_mode (bool escape_mode) {
+		_code_escape_mode = escape_mode;
+	}
+
+	public int get_line () {
+		return _line;
+	}
+
+	public virtual string get_line_content () {
+		int i = _index;
+		while (i > 0 && _content[i-1] != '\n') {
+			i--;
+		}
+		StringBuilder builder = new StringBuilder ();
+		while (i < _content.length && _content[i] != '\n') {
+			unichar c = _content[i++];
+			if (c == '\t') {
+				builder.append (" ");
+			} else {
+				builder.append_unichar (c);
+			}
+		}
+		return builder.str;
+	}
+
+	protected unichar get_next_char (int offset = 1) {
+		return _content[_index + offset];
+	}
+
+	private void emit_xml_node_open_token (string name, int offset) throws ParserError {
+		switch (name) {
+		case "structname":
+			emit_token (TokenType.GTKDOC_STRUCTNAME_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "link":
+			emit_token (TokenType.GTKDOC_LINK_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "literal":
+			emit_token (TokenType.GTKDOC_LITERAL_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "guimenuitem":
+			emit_token (TokenType.GTKDOC_GUI_MENU_ITEM_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "replaceable":
+			emit_token (TokenType.GTKDOC_REPLACEABLE_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "para":
+			emit_token (TokenType.GTKDOC_PARA_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "note":
+			emit_token (TokenType.GTKDOC_NOTE_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "itemizedlist":
+			emit_token (TokenType.GTKDOC_ITEMIZED_LIST_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "listitem":
+			emit_token (TokenType.GTKDOC_LIST_ITEM_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "warning":
+			emit_token (TokenType.GTKDOC_WARNING_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "programlisting":
+			emit_token (TokenType.GTKDOC_PROGRAMLISTING_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "informalexample":
+			emit_token (TokenType.GTKDOC_EXAMPLE_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "variablelist":
+			emit_token (TokenType.GTKDOC_VARIABLE_LIST_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "varlistentry":
+			emit_token (TokenType.GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "term":
+			emit_token (TokenType.GTKDOC_TERM_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "envar":
+			emit_token (TokenType.GTKDOC_ENVAR_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "option":
+			emit_token (TokenType.GTKDOC_OPTION_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "emphasis":
+			emit_token (TokenType.GTKDOC_EMPHASIS_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "filename":
+			emit_token (TokenType.GTKDOC_FILENAME_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "simplelist":
+			emit_token (TokenType.GTKDOC_SIMPLELIST_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		case "member":
+			emit_token (TokenType.GTKDOC_MEMBER_ELEMENT_OPEN);
+			_skip = offset;
+			break;
+
+		default:
+			append_char ('<');
+			break;
+		}
+	}
+
+	private void emit_xml_node_close_token (string name, int offset) throws ParserError {
+		switch (name) {
+		case "structname":
+			emit_token (TokenType.GTKDOC_STRUCTNAME_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "link":
+			emit_token (TokenType.GTKDOC_LINK_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "literal":
+			emit_token (TokenType.GTKDOC_LITERAL_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "guimenuitem":
+			emit_token (TokenType.GTKDOC_GUI_MENU_ITEM_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "replaceable":
+			emit_token (TokenType.GTKDOC_REPLACEABLE_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "para":
+			emit_token (TokenType.GTKDOC_PARA_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "note":
+			emit_token (TokenType.GTKDOC_NOTE_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "itemizedlist":
+			emit_token (TokenType.GTKDOC_ITEMIZED_LIST_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "listitem":
+			emit_token (TokenType.GTKDOC_LIST_ITEM_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "warning":
+			emit_token (TokenType.GTKDOC_WARNING_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "programlisting":
+			emit_token (TokenType.GTKDOC_PROGRAMLISTING_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "informalexample":
+			emit_token (TokenType.GTKDOC_EXAMPLE_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "variablelist":
+			emit_token (TokenType.GTKDOC_VARIABLE_LIST_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "varlistentry":
+			emit_token (TokenType.GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "term":
+			emit_token (TokenType.GTKDOC_TERM_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "envar":
+			emit_token (TokenType.GTKDOC_ENVAR_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "option":
+			emit_token (TokenType.GTKDOC_OPTION_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "emphasis":
+			emit_token (TokenType.GTKDOC_EMPHASIS_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "filename":
+			emit_token (TokenType.GTKDOC_FILENAME_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "simplelist":
+			emit_token (TokenType.GTKDOC_SIMPLELIST_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		case "member":
+			emit_token (TokenType.GTKDOC_MEMBER_ELEMENT_CLOSE);
+			_skip = offset;
+			break;
+
+		default:
+			append_char ('<');
+			break;
+		}
+	}
+
+	private inline bool is_numeric (unichar c) {
+		return c >= '0' && c <= '9';
+	}
+
+	private inline bool is_letter (unichar c) {
+		return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+	}
+
+	private void emmit_qualified_function_name (int offset) throws ParserError {
+		unichar c = get_next_char (offset);
+
+		if (!is_letter (c) && c != '_') {
+			emit_current_word ();
+			return;
+		}
+
+		append_char (c);
+
+		for (offset++; ; offset++) {
+			c = get_next_char (offset);
+
+			if (!is_letter (c) && c != '_' && !is_numeric (c) && c != '\0') {
+				break;
+			}
+
+			append_char (c);
+		}
+
+		unichar nc = get_next_char (offset+1);
+
+		if (c == '\0' || !((c == ':' && nc == ':' && is_letter (get_next_char (offset+2))) || (c == ':' && is_letter (nc)))) {
+			emit_current_word ();
+			_skip = offset-1;
+			return;
+		}
+
+		append_char (c);
+
+		if (nc == ':') {
+			append_char (nc);
+			offset++;
+		}
+
+		for (offset++; ; offset++) {
+			c = get_next_char (offset);
+
+			if (!is_letter (c) && c != '_' && !is_numeric (c)&& c != '-' && c != '\0') {
+				break;
+			}
+
+			append_char (c);
+		}
+
+		emit_current_word ();
+		_skip = offset-1;
+	}
+
+	protected void accept (unichar c) throws ParserError {
+		_column++;
+
+		if (_skip == 0) {
+			if (_code_element_escape_mode == true) {
+				switch (c) {
+				case '<':
+					if (get_next_char (1) == '/' && get_next_char (2) == 'p' &&
+						get_next_char (3) == 'r' && get_next_char (4) == 'o' &&
+						get_next_char (5) == 'g' && get_next_char (6) == 'r' &&
+						get_next_char (7) == 'a' && get_next_char (8) == 'm' &&
+						get_next_char (9) == 'l' && get_next_char (10) == 'i' &&
+						get_next_char (11) == 's' && get_next_char (12) == 't' &&
+						get_next_char (13) == 'i' && get_next_char (14) == 'n' &&
+						get_next_char (15) == 'g' && get_next_char (16) == '>') {
+
+						_code_element_escape_mode = false;
+						emit_token (TokenType.GTKDOC_PROGRAMLISTING_ELEMENT_CLOSE);
+						_skip = 16;
+					} else {
+						append_char (c);
+					}
+					return;
+				default:
+					append_char (c);
+					return;
+				}
+			} else if (_code_escape_mode == true) {
+				switch (c) {
+				case ']':
+					if (get_next_char (1) == '|') {
+						_code_escape_mode = false;
+						emit_token (TokenType.GTKDOC_SOURCE_CLOSE);
+						_skip = 2;
+					} else {
+						append_char (c);
+					}
+					return;
+				default:
+					append_char (c);
+					return;
+				}
+			} else {
+				switch (c) {
+				case '#':
+				case '%':
+					unichar nc = get_next_char (1);
+					if (is_letter (nc) || nc == '_') {
+						emit_token (TokenType.GTKDOC_SYMBOL);
+						emmit_qualified_function_name (1);
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case '@':
+					if (_last_char.isspace ()) {
+						emit_token (TokenType.GTKDOC_PARAM);
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case '-':
+					if (get_next_char (1) == '-' && get_next_char (2) == '>') {
+						emit_token (TokenType.GTKDOC_XML_COMMENT_END);
+						_skip = 2;
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case '(': // "(<spaces>?)"
+					int i = 1;
+
+					for (; get_next_char(i).isspace (); i++);
+					if (get_next_char(i) == ')') {
+						emit_token (TokenType.GTKDOC_FUNCTION_BRACKETS);
+						_skip = i;
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case '<':
+					if (get_next_char(1) == '!' && get_next_char(2) == '-' && get_next_char(3) == '-') {
+						emit_token (TokenType.GTKDOC_XML_COMMENT_START);
+						_skip = 3;
+						break;
+					}
+
+					var name = new StringBuilder ();
+					bool is_end_tag = false;
+					int i = 1;
+
+					if (get_next_char(i) == '/') {
+						is_end_tag = true;
+						i++;
+					}
+
+
+					for (; get_next_char(i) != '>' && !get_next_char(i).isspace (); i++) {
+						name.append_unichar (get_next_char(i));
+					}
+
+					if (name.len == 0) {
+						append_char (c);
+						break;
+					}
+
+					if (is_end_tag) {
+						if (get_next_char(i) != '>') {
+							append_char (c);
+							break;
+						}
+						emit_xml_node_close_token (name.str, i);
+					} else {
+						for (; get_next_char(i) != '>' && get_next_char(i) != '\0'; i++);
+						if (get_next_char(i) == '\0') {
+							append_char (c);
+							break;
+						}
+						emit_xml_node_open_token (name.str, i);
+					}
+					break;
+
+				case '|':
+					if (get_next_char (1) == '[') {
+						emit_token (TokenType.GTKDOC_SOURCE_OPEN);
+						_skip = 1;
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case ']':
+					if (get_next_char (1) == '|') {
+						emit_token (TokenType.GTKDOC_SOURCE_CLOSE);
+						_skip = 1;
+					} else {
+						append_char (c);
+					}
+					break;
+
+				case '\r':
+					break;
+
+				case '\n':
+					emit_token (TokenType.GTKDOC_EOL);
+					_line++;
+					_column = 0;
+					_last_column = 0;
+					break;
+
+				case '\t':
+				case ' ':
+					emit_token (TokenType.GTKDOC_SPACE);
+					break;
+
+				case '.':
+					emit_token (TokenType.GTKDOC_DOT);
+					break;
+
+				default:
+					append_char (c);
+					break;
+				}
+			}
+		} else {
+			_skip--;
+		}
+		_last_char = c;
+	}
+
+	private void append_char (unichar c) {
+		_current_string.append_unichar (c);
+	}
+
+	public int get_line_start_column () {
+		return 0;
+	}
+
+	private SourceLocation get_begin () {
+		return SourceLocation (_last_line, get_line_start_column () + _last_column);
+	}
+
+	private SourceLocation get_end (int offset = 0) {
+		return SourceLocation (_line, get_line_start_column () + _column + offset);
+	}
+
+	private void emit_current_word () throws ParserError {
+		if (_current_string.len > 0) {
+			_parser.accept_token (new Token.from_word (_current_string.str, get_begin (), get_end (-1)));
+			_current_string.erase (0, -1);
+
+			_last_index = _index;
+			_last_line = _line;
+			_last_column = _column - 1;
+		}
+	}
+
+	private void emit_token (TokenType type) throws ParserError {
+		emit_current_word ();
+
+		_parser.accept_token (new Token.from_type (type, get_begin (), get_end (_skip)));
+
+		_last_index = _index;
+		_last_line = _line;
+		_last_column = _column;
+	}
+}
diff --git a/src/libvaladoc/html/htmlrenderer.vala b/src/libvaladoc/html/htmlrenderer.vala
index 322dd61..66ef4d4 100755
--- a/src/libvaladoc/html/htmlrenderer.vala
+++ b/src/libvaladoc/html/htmlrenderer.vala
@@ -57,11 +57,17 @@ public class Valadoc.Html.HtmlRenderer : ContentRenderer {
 		return linker.get_relative_link (_container, symbol, _doclet.settings);
 	}
 
-	private void write_symbol_link (Api.Node symbol, string? label) {
-		var url = get_url (symbol);
-		writer.link (url,
-		             (label == null || label == "") ? symbol.get_full_name () : label,
-		             cssresolver.resolve (symbol));
+	private void write_symbol_link (Api.Node? symbol, string? label) {
+		if (symbol == null && label != null) {
+			writer.start_tag ("code");
+			writer.text (label);
+			writer.end_tag ("code");
+		} else if (symbol != null) {
+			var url = get_url (symbol);
+			writer.link (url,
+				         (label == null || label == "") ? symbol.get_full_name () : label,
+				         cssresolver.resolve (symbol));
+		}
 	}
 
 	private delegate void Write ();
@@ -230,10 +236,12 @@ public class Valadoc.Html.HtmlRenderer : ContentRenderer {
 	}
 
 	public override void visit_symbol_link (SymbolLink element) {
-		if (element.symbol == _container
+		if (element.symbol == null || element.symbol == _container
 		    || !element.symbol.is_browsable (_doclet.settings)
 		    || !element.symbol.package.is_browsable (_doclet.settings)) {
+			writer.start_tag ("code");
 			writer.text (element.label);
+			writer.end_tag ("code");
 		} else {
 			write_symbol_link (element.symbol, element.label);
 		}
diff --git a/src/libvaladoc/importer/documentationimporter.vala b/src/libvaladoc/importer/documentationimporter.vala
index d19f019..9cdf7b0 100644
--- a/src/libvaladoc/importer/documentationimporter.vala
+++ b/src/libvaladoc/importer/documentationimporter.vala
@@ -24,19 +24,18 @@
 using Gee;
 
 
-public abstract class Valadoc.DocumentationImporter : Object, ResourceLocator {
-	protected ErrorReporter errorreporter;
+public abstract class Valadoc.Importer.DocumentationImporter : Object, ResourceLocator {
 	protected ModuleLoader modules;
 	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, ErrorReporter errorreporter) {
+	public DocumentationImporter (Api.Tree tree, ModuleLoader modules, Settings settings) {
 		factory = new Content.ContentFactory (settings, this, modules);
 
-		this.errorreporter = errorreporter;
 		this.settings = settings;
 		this.modules = null;
 		this.tree = tree;
@@ -46,7 +45,7 @@ public abstract class Valadoc.DocumentationImporter : Object, ResourceLocator {
 		return path;
 	}
 
-	public abstract bool process (string filename, Settings settings, Api.Package package);
+	public abstract void process (string filename);
 }
 
 
diff --git a/src/libvaladoc/importer/girdocumentationbuilder.vala b/src/libvaladoc/importer/girdocumentationbuilder.vala
new file mode 100644
index 0000000..d502cf3
--- /dev/null
+++ b/src/libvaladoc/importer/girdocumentationbuilder.vala
@@ -0,0 +1,56 @@
+/* DocumentationBuilderimporter.vala
+ *
+ * Copyright (C) 2010 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:
+ * 	Florian Brosch <flo brosch gmail com>
+ */
+
+
+using Valadoc;
+using Gee;
+
+
+/**
+ * A documentation comment used by valadoc
+ */
+public class Valadoc.Importer.GirDocumentationBuilder : Vala.Comment {
+	private HashMap<string, Vala.Comment> _parameters = new HashMap<string, Vala.Comment> ();
+
+	public Map<string, Vala.Comment> parameters { owned get { return _parameters.read_only_view; } }
+
+	public Vala.Comment? return_value { get; internal set; }
+	
+	public GirDocumentationBuilder.empty (Vala.SourceReference _source_reference) {
+		base ("", _source_reference);
+		return_value = null;
+	}
+
+	public GirDocumentationBuilder (Vala.Comment comment) {
+		base (comment.content, comment.source_reference);
+		return_value = null;
+	}
+
+	internal void add_parameter (string name, Vala.Comment comment) {
+		_parameters.set (name, comment);
+	}
+
+	public bool is_empty () {
+		return return_value == null && (content == null || content == "") && parameters.is_empty;
+	}
+}
+
diff --git a/src/libvaladoc/importer/girdocumentationimporter.vala b/src/libvaladoc/importer/girdocumentationimporter.vala
new file mode 100644
index 0000000..a76215b
--- /dev/null
+++ b/src/libvaladoc/importer/girdocumentationimporter.vala
@@ -0,0 +1,687 @@
+/* DocumentationBuilderimporter.vala
+ *
+ * Copyright (C) 2010 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:
+ * 	Florian Brosch <flo brosch gmail com>
+ */
+
+// based on valagirparser.vala
+
+using Gee;
+
+public class Valadoc.Importer.GirDocumentationImporter : DocumentationImporter {
+	DocumentationParser docparser;
+	Vala.MarkupReader reader;
+
+	Vala.SourceFile current_source_file;
+	Vala.SourceLocation begin;
+	Vala.SourceLocation end;
+	Vala.MarkupTokenType current_token;
+
+	Vala.DataType dummy_type;
+
+	LinkedList<string> type_cname_stack = new LinkedList<string> ();
+
+	int anonymous_param_count = 0;
+
+	public override string file_extension { get { return "gir"; } }
+
+	public GirDocumentationImporter (Api.Tree tree, DocumentationParser docparser, ModuleLoader modules, Settings settings) {
+		base (tree, modules, settings);
+		this.dummy_type = new Vala.StructValueType (new Vala.Struct ("Dummy"));
+		this.docparser = docparser;
+	}
+
+	public override void process (string filename) {
+		parse_file (filename);
+	}
+
+	void parse_file (string gir_file) {
+		reader = new Vala.MarkupReader (gir_file);
+		this.current_source_file = new Vala.SourceFile (tree.context, GLib.Path. get_basename (gir_file));
+
+		// xml prolog
+		next ();
+		next ();
+
+		next ();
+		parse_repository ();
+		this.current_source_file = null;
+	}
+
+	Vala.Comment? parse_doc () {
+		start_element ("doc");
+
+		Vala.Comment comment = null;
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.TEXT) {
+			comment = new Vala.Comment (reader.content, get_current_src ());
+			next ();
+		}
+
+		end_element ("doc");
+		return comment;
+	}
+
+	void next () {
+		current_token = reader.read_token (out begin, out end);
+	}
+
+	void start_element (string name) {
+		if (current_token != Vala.MarkupTokenType.START_ELEMENT || reader.name != name) {
+			// error
+			Vala.Report.error (get_current_src (), "expected start element of `%s' instead of `%s'".printf (name, reader.name));
+		}
+	}
+
+	void end_element (string name) {
+		if (current_token != Vala.MarkupTokenType.END_ELEMENT || reader.name != name) {
+			// error
+			Vala.Report.error (get_current_src (), "expected end element of `%s' instead of `%s'".printf (name, reader.name));
+		}
+		next ();
+	}
+
+	Vala.SourceReference get_current_src () {
+		return new Vala.SourceReference (this.current_source_file, begin.line, begin.column, end.line, end.column);
+	}
+
+	void parse_repository () {
+		start_element ("repository");
+		next ();
+		while (current_token == Vala.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
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `repository'".printf (reader.name));
+				break;
+			}
+		}
+		end_element ("repository");
+	}
+
+	void parse_include () {
+		start_element ("include");
+		next ();
+		end_element ("include");
+	}
+
+	void parse_package () {
+		start_element ("package");
+		next ();
+		end_element ("package");
+	}
+
+	void parse_c_include () {
+		start_element ("c:include");
+		next ();
+		end_element ("c:include");
+	}
+
+	void skip_element () {
+		next ();
+
+		int level = 1;
+		while (level > 0) {
+			if (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+				level++;
+			} else if (current_token == Vala.MarkupTokenType.END_ELEMENT) {
+				level--;
+			} else if (current_token == Vala.MarkupTokenType.EOF) {
+				Vala.Report.error (get_current_src (), "unexpected end of file");
+				break;
+			}
+			next ();
+		}
+	}
+
+	void parse_namespace () {
+		start_element ("namespace");
+		next ();
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			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") {
+				if (reader.get_attribute ("glib:get-type") != null) {
+					parse_boxed ();
+				} else {
+					parse_record ();
+				}
+			} else if (reader.name == "class") {
+				parse_class ();
+			} else if (reader.name == "interface") {
+				parse_interface ();
+			} else if (reader.name == "glib:boxed") {
+				parse_boxed ();
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else if (reader.name == "constant") {
+				parse_constant ();
+			} else {
+				// error
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `namespace'".printf (reader.name));
+				break;
+			}
+		}
+		end_element ("namespace");
+	}
+
+	void parse_alias () {
+		start_element ("alias");
+		next ();
+		end_element ("alias");
+	}
+
+	void parse_enumeration () {
+		start_element ("enumeration");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "member") {
+				parse_enumeration_member ();
+			} else {
+				// error
+				break;
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("enumeration");
+	}
+
+	void parse_bitfield () {
+		start_element ("bitfield");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "member") {
+				parse_enumeration_member ();
+			} else {
+				// error
+				break;
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("bitfield");
+	}
+
+	void parse_enumeration_member () {
+		start_element ("member");
+		string cname = reader.get_attribute ("c:identifier");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		end_element ("member");
+	}
+
+	void parse_return_value (GirDocumentationBuilder doc) {
+		start_element ("return-value");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			doc.return_value = parse_doc ();
+		}
+
+		parse_type ();
+
+		end_element ("return-value");
+	}
+
+	void parse_parameter (GirDocumentationBuilder doc) {
+		start_element ("parameter");
+		string name = reader.get_attribute ("name");
+
+		if (name == null) {
+			name = "param%d".printf (anonymous_param_count);
+			anonymous_param_count++;
+		}
+
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			doc.add_parameter (name, parse_doc ());
+		}
+
+		if (reader.name == "varargs") {
+			start_element ("varargs");
+			next ();
+			end_element ("varargs");
+		} else {
+			parse_type ();
+		}
+
+		end_element ("parameter");
+	}
+
+	void parse_type () {
+		if (reader.name == "array" || reader.name == "callback" || reader.name == "type") {
+			skip_element ();
+		}
+	}
+
+	void parse_record () {
+		start_element ("record");
+		string glib_is_gtype_struct_for = reader.get_attribute ("glib:is-gtype-struct-for");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "callback") {
+				if (glib_is_gtype_struct_for != null) {
+					parse_method ("callback");
+				} else {
+					parse_callback ();
+				}
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else {
+				// error
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `record'".printf (reader.name));
+				break;
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("record");
+	}
+
+	void parse_class () {
+		start_element ("class");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "implements") {
+				start_element ("implements");
+				next ();
+				end_element ("implements");
+			} 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 (cname);
+			} 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
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
+				break;
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("class");
+	}
+
+	void parse_interface () {
+		start_element ("interface");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "prerequisite") {
+				start_element ("prerequisite");
+				next ();
+				end_element ("prerequisite");
+			} 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
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `interface'".printf (reader.name));
+				break;
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("interface");
+	}
+
+	void parse_field () {
+		start_element ("field");
+		string cname = reader.get_attribute ("name");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc" && cname != null) {
+			string real_cname = type_cname_stack.peek();
+			real_cname = (real_cname == null)? cname : real_cname+"."+cname;
+			process_documentation (real_cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		parse_type ();
+
+		end_element ("field");
+	}
+
+	void parse_property () {
+		start_element ("property");
+		string cname = reader.get_attribute ("name");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc" && cname != null) {
+			process_documentation (type_cname_stack.peek()+":"+cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		parse_type ();
+
+		end_element ("property");
+	}
+
+	void parse_callback () {
+		this.parse_function ("callback");
+	}
+
+	void parse_constructor (string? parent_ctype = null) {
+		start_element ("constructor");
+		string cname = reader.get_attribute ("c:identifier");
+		next ();
+
+		GirDocumentationBuilder doc;
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			doc = new GirDocumentationBuilder (parse_doc ());
+		} else {
+			doc = new GirDocumentationBuilder.empty (get_current_src ());
+		}
+
+		parse_return_value (doc);
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+			start_element ("parameters");
+			next ();
+			while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+				parse_parameter (doc);
+			}
+			end_element ("parameters");
+		}
+
+		if (!doc.is_empty ()) {
+			process_documentation (cname, doc);
+		}
+
+		end_element ("constructor");
+	}
+
+	void parse_function (string element_name) {
+		start_element (element_name);
+		string cname = reader.get_attribute ("c:identifier");
+		next ();
+
+		GirDocumentationBuilder doc;
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			doc = new GirDocumentationBuilder (parse_doc ());
+		} else {
+			doc = new GirDocumentationBuilder.empty (get_current_src ());
+		}
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+			parse_return_value (doc);
+		}
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+			start_element ("parameters");
+			next ();
+
+			while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+				parse_parameter (doc);
+			}
+
+			end_element ("parameters");
+		}
+
+		if (!doc.is_empty ()) {
+			process_documentation (cname, doc);
+		}
+
+		end_element (element_name);
+	}
+
+	void parse_method (string element_name) {
+		this.parse_function (element_name);
+	}
+
+	void parse_signal () {
+		start_element ("glib:signal");
+		string cname = reader.get_attribute ("name");
+		next ();
+
+		GirDocumentationBuilder doc;
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			doc = new GirDocumentationBuilder (parse_doc ());
+		} else {
+			doc = new GirDocumentationBuilder.empty (get_current_src ());
+		}
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+			parse_return_value (doc);
+		}
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+			start_element ("parameters");
+			next ();
+			while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+				parse_parameter (doc);
+			}
+			end_element ("parameters");
+		}
+		if (!doc.is_empty ()) {
+			process_documentation (type_cname_stack.peek()+"::"+cname, doc);
+		}
+		end_element ("glib:signal");
+	}
+
+	void parse_boxed () {
+		string cname = reader.get_attribute ("c:type");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			if (reader.name == "field") {
+				parse_field ();
+			} else if (reader.name == "constructor") {
+				parse_constructor ();
+			} else if (reader.name == "union") {
+				parse_union ();
+			} else if (reader.name == "method") {
+				parse_method ("method");
+			} else {
+				// error
+				Vala.Report.error (get_current_src (), "unknown child element `%s' in `class'".printf (reader.name));
+				break;
+			}
+		}
+
+		if (current_token != Vala.MarkupTokenType.END_ELEMENT) {
+			// error
+			Vala.Report.error (get_current_src (), "expected end element");
+		}
+		next ();
+	}
+
+	void parse_union () {
+		start_element ("union");
+		string cname = reader.get_attribute ("c:type");
+		type_cname_stack.add (cname);
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (cname, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		while (current_token == Vala.MarkupTokenType.START_ELEMENT) {
+			if (reader.get_attribute ("introspectable") == "0") {
+				skip_element ();
+				continue;
+			}
+
+			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 == "record") {
+				parse_record ();
+			}
+		}
+
+		type_cname_stack.poll_head ();
+		end_element ("union");
+	}
+
+	void parse_constant () {
+		start_element ("constant");
+		string name = reader.get_attribute ("name");
+		next ();
+
+		if (current_token == Vala.MarkupTokenType.START_ELEMENT && reader.name == "doc") {
+			process_documentation (name, new GirDocumentationBuilder (parse_doc ()));
+		}
+
+		parse_type ();
+
+		end_element ("constant");
+	}
+
+	void process_documentation (string? cname, GirDocumentationBuilder? doc) {
+		if (cname == null || doc == null) {
+			return;
+		}
+	
+		var node = tree.search_symbol_cstr (cname);
+		
+		if (node != null) {
+			node.documentation = docparser.parse_gir_comment (node, doc);
+		}
+	}
+}
+
diff --git a/src/libvaladoc/parser/tokentype.vala b/src/libvaladoc/parser/tokentype.vala
index 86f87dc..bd53da9 100644
--- a/src/libvaladoc/parser/tokentype.vala
+++ b/src/libvaladoc/parser/tokentype.vala
@@ -23,7 +23,7 @@
 using Gee;
 
 public class Valadoc.TokenType : Object {
-
+	// valadoc-comments:
 	public static TokenType ANY;
 	public static TokenType ANY_WORD;
 	public static TokenType ANY_NUMBER;
@@ -60,6 +60,64 @@ public class Valadoc.TokenType : Object {
 	public static TokenType ALIGN_RIGHT;
 	public static TokenType ALIGN_CENTER;
 
+	// Gir, doc-nodes:
+	public static TokenType GTKDOC_FUNCTION_BRACKETS;
+	public static TokenType GTKDOC_XML_COMMENT_START;
+	public static TokenType GTKDOC_XML_COMMENT_END;
+	public static TokenType GTKDOC_PARAM;
+	public static TokenType GTKDOC_SYMBOL;
+	public static TokenType GTKDOC_ANY_WORD;
+	public static TokenType GTKDOC_SPACE;
+	public static TokenType GTKDOC_EOF;
+	public static TokenType GTKDOC_EOL;
+	public static TokenType GTKDOC_STRUCTNAME_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_STRUCTNAME_ELEMENT_OPEN;
+	public static TokenType GTKDOC_LINK_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_LINK_ELEMENT_OPEN;
+	public static TokenType GTKDOC_ITEMIZED_LIST_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_ITEMIZED_LIST_ELEMENT_OPEN;
+	public static TokenType GTKDOC_LIST_ITEM_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_LIST_ITEM_ELEMENT_OPEN;
+	public static TokenType GTKDOC_NOTE_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_NOTE_ELEMENT_OPEN;
+	public static TokenType GTKDOC_PARA_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_PARA_ELEMENT_OPEN;
+	public static TokenType GTKDOC_LITERAL_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_LITERAL_ELEMENT_OPEN;
+	public static TokenType GTKDOC_GUI_MENU_ITEM_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_GUI_MENU_ITEM_ELEMENT_OPEN;
+	public static TokenType GTKDOC_REPLACEABLE_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_REPLACEABLE_ELEMENT_OPEN;
+	public static TokenType GTKDOC_WARNING_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_WARNING_ELEMENT_OPEN;
+	public static TokenType GTKDOC_SOURCE_CLOSE;
+	public static TokenType GTKDOC_SOURCE_OPEN;
+	public static TokenType GTKDOC_EXAMPLE_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_EXAMPLE_ELEMENT_OPEN;
+	public static TokenType GTKDOC_TITLE_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_TITLE_ELEMENT_OPEN;
+	public static TokenType GTKDOC_PROGRAMLISTING_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_PROGRAMLISTING_ELEMENT_OPEN;
+	public static TokenType GTKDOC_VARIABLE_LIST_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_VARIABLE_LIST_ELEMENT_OPEN;
+	public static TokenType GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_OPEN;
+	public static TokenType GTKDOC_TERM_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_TERM_ELEMENT_OPEN;
+	public static TokenType GTKDOC_ENVAR_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_ENVAR_ELEMENT_OPEN;
+	public static TokenType GTKDOC_OPTION_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_OPTION_ELEMENT_OPEN;
+	public static TokenType GTKDOC_EMPHASIS_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_EMPHASIS_ELEMENT_OPEN;
+	public static TokenType GTKDOC_FILENAME_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_FILENAME_ELEMENT_OPEN;
+	public static TokenType GTKDOC_SIMPLELIST_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_SIMPLELIST_ELEMENT_OPEN;
+	public static TokenType GTKDOC_MEMBER_ELEMENT_CLOSE;
+	public static TokenType GTKDOC_MEMBER_ELEMENT_OPEN;
+	public static TokenType GTKDOC_DOT;
+
 	private static bool initialized = false;
 
 	internal static void init_token_types () {
@@ -99,6 +157,64 @@ public class Valadoc.TokenType : Object {
 			DOUBLE_PIPE = new TokenType.basic ("||");
 			ALIGN_RIGHT = new TokenType.basic ("))");
 			ALIGN_CENTER = new TokenType.basic (")(");
+
+			GTKDOC_FUNCTION_BRACKETS = new TokenType.basic ("()");
+			GTKDOC_XML_COMMENT_START = new TokenType.basic ("<!--");
+			GTKDOC_XML_COMMENT_END = new TokenType.basic ("-->");
+			GTKDOC_PARAM = new TokenType.basic ("<c-parameter>");
+			GTKDOC_SYMBOL = new TokenType.basic ("<symbol>");
+			GTKDOC_STRUCTNAME_ELEMENT_CLOSE = new TokenType.basic ("</structname>");
+			GTKDOC_STRUCTNAME_ELEMENT_OPEN = new TokenType.basic ("<structname>");
+			GTKDOC_LINK_ELEMENT_CLOSE = new TokenType.basic ("</link>");
+			GTKDOC_LINK_ELEMENT_OPEN = new TokenType.basic ("<link>");
+			GTKDOC_ITEMIZED_LIST_ELEMENT_CLOSE = new TokenType.basic ("</itemizedlist>");
+			GTKDOC_ITEMIZED_LIST_ELEMENT_OPEN = new TokenType.basic ("<itemizedlist>");
+			GTKDOC_LIST_ITEM_ELEMENT_CLOSE = new TokenType.basic ("</listitem>");
+			GTKDOC_LIST_ITEM_ELEMENT_OPEN = new TokenType.basic ("<listitem>");
+			GTKDOC_NOTE_ELEMENT_CLOSE = new TokenType.basic ("</note>");
+			GTKDOC_NOTE_ELEMENT_OPEN = new TokenType.basic ("<note>");
+			GTKDOC_PARA_ELEMENT_CLOSE = new TokenType.basic ("</para>");
+			GTKDOC_PARA_ELEMENT_OPEN = new TokenType.basic ("<para>");
+			GTKDOC_LITERAL_ELEMENT_CLOSE = new TokenType.basic ("</literal>");
+			GTKDOC_LITERAL_ELEMENT_OPEN = new TokenType.basic ("<literal>");
+			GTKDOC_GUI_MENU_ITEM_ELEMENT_CLOSE = new TokenType.basic ("</guimenuitem>");
+			GTKDOC_GUI_MENU_ITEM_ELEMENT_OPEN = new TokenType.basic ("<guimenuitem>");
+			GTKDOC_REPLACEABLE_ELEMENT_CLOSE = new TokenType.basic ("</replaceable>");
+			GTKDOC_REPLACEABLE_ELEMENT_OPEN = new TokenType.basic ("<replaceable>");
+			GTKDOC_WARNING_ELEMENT_CLOSE = new TokenType.basic ("</warning>");
+			GTKDOC_WARNING_ELEMENT_OPEN = new TokenType.basic ("<warning>");
+			GTKDOC_SOURCE_CLOSE = new TokenType.basic ("|]");
+			GTKDOC_SOURCE_OPEN = new TokenType.basic ("[|");
+			GTKDOC_EXAMPLE_ELEMENT_CLOSE = new TokenType.basic ("</example>");
+			GTKDOC_EXAMPLE_ELEMENT_OPEN = new TokenType.basic ("<example>");
+			GTKDOC_TITLE_ELEMENT_CLOSE = new TokenType.basic ("</title>");
+			GTKDOC_TITLE_ELEMENT_OPEN = new TokenType.basic ("<title>");
+			GTKDOC_PROGRAMLISTING_ELEMENT_CLOSE = new TokenType.basic ("</programlisting>");
+			GTKDOC_PROGRAMLISTING_ELEMENT_OPEN = new TokenType.basic ("<programlisting>");
+			GTKDOC_VARIABLE_LIST_ELEMENT_CLOSE = new TokenType.basic ("</variablelist>");
+			GTKDOC_VARIABLE_LIST_ELEMENT_OPEN = new TokenType.basic ("<variablelist>");
+			GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_CLOSE = new TokenType.basic ("</varlistentry>");
+			GTKDOC_VARIABLE_LIST_ENTRY_ELEMENT_OPEN = new TokenType.basic ("<varlistentry>");
+			GTKDOC_TERM_ELEMENT_CLOSE = new TokenType.basic ("</term>");
+			GTKDOC_TERM_ELEMENT_OPEN = new TokenType.basic ("<term>");
+			GTKDOC_ENVAR_ELEMENT_CLOSE = new TokenType.basic ("</envar>");
+			GTKDOC_ENVAR_ELEMENT_OPEN = new TokenType.basic ("<envar>");
+			GTKDOC_OPTION_ELEMENT_CLOSE = new TokenType.basic ("</option>");
+			GTKDOC_OPTION_ELEMENT_OPEN = new TokenType.basic ("<option>");
+			GTKDOC_EMPHASIS_ELEMENT_CLOSE = new TokenType.basic ("</emphasis>");
+			GTKDOC_EMPHASIS_ELEMENT_OPEN = new TokenType.basic ("<emphasis>");
+			GTKDOC_FILENAME_ELEMENT_CLOSE = new TokenType.basic ("</filename>");
+			GTKDOC_FILENAME_ELEMENT_OPEN = new TokenType.basic ("<filename>");
+			GTKDOC_SIMPLELIST_ELEMENT_CLOSE = new TokenType.basic ("</simplelist>");
+			GTKDOC_SIMPLELIST_ELEMENT_OPEN = new TokenType.basic ("<simplelist>");
+			GTKDOC_MEMBER_ELEMENT_CLOSE = new TokenType.basic ("</member>");
+			GTKDOC_MEMBER_ELEMENT_OPEN = new TokenType.basic ("<member>");
+			GTKDOC_DOT = new TokenType.basic (".");
+			GTKDOC_ANY_WORD = ANY_WORD;
+			GTKDOC_EOL = TokenType.EOL;
+			GTKDOC_SPACE = SPACE;
+			GTKDOC_EOF = EOF;
+
 			initialized = true;
 		}
 	}
diff --git a/src/libvaladoc/settings.vala b/src/libvaladoc/settings.vala
index eca9f1c..f531136 100755
--- a/src/libvaladoc/settings.vala
+++ b/src/libvaladoc/settings.vala
@@ -46,7 +46,6 @@ public class Valadoc.Settings : Object {
 
 	public string[] defines;
 	public string[] vapi_directories;
-	public string[] docu_directories;
 }
 
 
diff --git a/src/libvaladoc/taglets/tagletlink.vala b/src/libvaladoc/taglets/tagletlink.vala
index a25976d..ad77b4c 100755
--- a/src/libvaladoc/taglets/tagletlink.vala
+++ b/src/libvaladoc/taglets/tagletlink.vala
@@ -25,7 +25,7 @@ using Valadoc.Content;
 
 
 public class Valadoc.Taglets.Link : InlineTaglet {
-	public string symbol_name { private set; get; }
+	public string symbol_name { internal set; get; }
 
 	private Api.Node _symbol;
 
@@ -36,10 +36,19 @@ public class Valadoc.Taglets.Link : InlineTaglet {
 	}
 
 	public override void check (Api.Tree api_root, Api.Node container, ErrorReporter reporter, Settings settings) {
-		_symbol = api_root.search_symbol_str (container, symbol_name);
+		if (symbol_name.has_prefix ("c::")) {
+			_symbol_name = _symbol_name.offset (3);
+			_symbol = api_root.search_symbol_cstr (symbol_name);
+			if (_symbol != null) {
+				symbol_name = _symbol.name;
+			}
+		} else {
+			_symbol = api_root.search_symbol_str (container, symbol_name);
+		}
+
 		if (_symbol == null) {
 			// TODO use ContentElement's source reference
-			reporter.simple_error ("%s does not exist".printf (symbol_name));
+			reporter.simple_warning ("%s does not exist".printf (symbol_name));
 		}
 
 		base.check (api_root, container, reporter, settings);
diff --git a/src/libvaladoc/taglets/tagletparam.vala b/src/libvaladoc/taglets/tagletparam.vala
index a4f1694..d0c7eff 100755
--- a/src/libvaladoc/taglets/tagletparam.vala
+++ b/src/libvaladoc/taglets/tagletparam.vala
@@ -25,7 +25,7 @@ using Valadoc.Content;
 
 
 public class Valadoc.Taglets.Param : InlineContent, Taglet, Block {
-	public string parameter_name { private set; get; }
+	public string parameter_name { internal set; get; }
 
 	public Rule? get_parser_rule (Rule run_rule) {
 		return Rule.seq ({
diff --git a/src/libvaladoc/taglets/tagletsee.vala b/src/libvaladoc/taglets/tagletsee.vala
index 6610d98..e1b3dc5 100755
--- a/src/libvaladoc/taglets/tagletsee.vala
+++ b/src/libvaladoc/taglets/tagletsee.vala
@@ -35,10 +35,19 @@ public class Valadoc.Taglets.See : ContentElement, Taglet, Block {
 	}
 
 	public override void check (Api.Tree api_root, Api.Node container, ErrorReporter reporter, Settings settings) {
-		symbol = api_root.search_symbol_str (container, symbol_name);
+		if (symbol_name.has_prefix ("c::")) {
+			symbol_name = symbol_name.offset (3);
+			symbol = api_root.search_symbol_cstr (symbol_name);
+			if (symbol != null) {
+				symbol_name = _symbol.name;
+			}
+		} else {
+			symbol = api_root.search_symbol_str (container, symbol_name);
+		}
+
 		if (symbol == null) {
 			// TODO use ContentElement's source reference
-			reporter.simple_error ("%s does not exist".printf (symbol_name));
+			reporter.simple_warning ("%s does not exist".printf (symbol_name));
 		}
 	}
 
diff --git a/src/valadoc/valadoc.vala b/src/valadoc/valadoc.vala
index 2bdeb5c..8946dba 100755
--- a/src/valadoc/valadoc.vala
+++ b/src/valadoc/valadoc.vala
@@ -21,6 +21,7 @@
  */
 
 using GLib.Path;
+using Valadoc.Importer;
 using Valadoc;
 using Config;
 using Gee;
@@ -54,9 +55,10 @@ public class ValaDoc : Object {
 	private static bool experimental_non_null = false;
 	private static bool disable_dbus_transformation;
 	private static string profile;
-
 	[CCode (array_length = false, array_null_terminated = true)]
-	private static string[] docu_directories;
+	private static string[] import_packages;
+	[CCode (array_length = false, array_null_terminated = true)]
+	private static string[] import_directories;
 	[CCode (array_length = false, array_null_terminated = true)]
 	private static string[] vapi_directories;
 	[CCode (array_length = false, array_null_terminated = true)]
@@ -73,11 +75,11 @@ public class ValaDoc : Object {
 		{ "enable-experimental-non-null", 0, 0, OptionArg.NONE, ref experimental_non_null, "Enable experimental enhancements for non-null types", null },
 		{ "disable-dbus-transformation", 0, 0, OptionArg.NONE, ref disable_dbus_transformation, "Disable transformation of D-Bus member names", null },
 		{ "vapidir", 0, 0, OptionArg.FILENAME_ARRAY, ref vapi_directories, "Look for package bindings in DIRECTORY", "DIRECTORY..." },
-		{ "docudir", 0, 0, OptionArg.FILENAME_ARRAY, ref docu_directories, "Look for external documentation in DIRECTORY", "DIRECTORY..." },
+		{ "importdir", 0, 0, OptionArg.FILENAME_ARRAY, ref import_directories, "Look for external documentation in DIRECTORY", "DIRECTORY..." },
 		{ "profile", 0, 0, OptionArg.STRING, ref profile, "Use the given profile instead of the default", "PROFILE" },
 
-
 		{ "pkg", 0, 0, OptionArg.STRING_ARRAY, ref packages, "Include binding for PACKAGE", "PACKAGE..." },
+		{ "import", 0, 0, OptionArg.STRING_ARRAY, ref import_packages, "Include binding for PACKAGE", "PACKAGE..." },
 		{ "directory", 'o', 0, OptionArg.FILENAME, ref directory, "Output directory", "DIRECTORY" },
 
 		{ "wiki", 0, 0, OptionArg.FILENAME, ref wikidirectory, "Wiki directory", "DIRECTORY" },
@@ -155,7 +157,6 @@ public class ValaDoc : Object {
 		settings.basedir = basedir;
 		settings.directory = directory;
 		settings.vapi_directories = vapi_directories;
-		settings.docu_directories = docu_directories;
 
 		settings.profile = profile;
 		settings.defines = defines;
@@ -163,19 +164,16 @@ public class ValaDoc : Object {
 		string fulldirpath = "";
 		if (pluginpath == null) {
 			fulldirpath = build_filename (Config.plugin_dir, "html");
-		}
-		else if ( is_absolute (pluginpath ) == false) {
+		} else if (is_absolute (pluginpath ) == false) {
 			// Test to see if the plugin exists in the expanded path and then fallback
 			// to using the configured plugin directory
 			string local_path = build_filename (Environment.get_current_dir(), pluginpath);
 			if ( FileUtils.test(local_path, FileTest.EXISTS)) {
 				fulldirpath = local_path;
-			}
-			else {
+			} else {
 				fulldirpath = build_filename (Config.plugin_dir, pluginpath);
 			}
-		}
-		else {
+		} else {
 			fulldirpath = pluginpath;
 		}
 
@@ -211,6 +209,12 @@ public class ValaDoc : Object {
 			return quit (reporter);
 		}
 
+		var gir_importer = new GirDocumentationImporter (doctree, docparser, modules, settings);
+		doctree.import_documentation (gir_importer, import_packages, import_directories);
+		if (reporter.errors > 0) {
+			return quit (reporter);
+		}
+
 		modules.doclet.process (settings, doctree);
 		return quit (reporter);
 	}



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