summaryrefslogtreecommitdiff
path: root/libvaladoc
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2017-06-27 12:21:44 +0200
committerRico Tzschichholz <ricotz@ubuntu.com>2017-06-27 12:21:44 +0200
commit93d9fe647be1f2effc0bfeeec903b5e030182f6c (patch)
treed28aab5aa5c0e4a149e40b22246246dd2b2d5957 /libvaladoc
parentb4f3f73a01b86fe7f9edde7a3991b493346eea23 (diff)
downloadvala-93d9fe647be1f2effc0bfeeec903b5e030182f6c.tar.gz
Prepare valadoc source-tree for merge
Diffstat (limited to 'libvaladoc')
-rw-r--r--libvaladoc/Makefile.am232
-rw-r--r--libvaladoc/api/array.vala70
-rw-r--r--libvaladoc/api/attribute.vala109
-rw-r--r--libvaladoc/api/attributeargument.vala135
-rw-r--r--libvaladoc/api/browsable.vala35
-rw-r--r--libvaladoc/api/callable.vala51
-rw-r--r--libvaladoc/api/childsymbolregistrar.vala99
-rw-r--r--libvaladoc/api/class.vala361
-rw-r--r--libvaladoc/api/constant.vala81
-rw-r--r--libvaladoc/api/delegate.vala142
-rw-r--r--libvaladoc/api/driver.vala43
-rw-r--r--libvaladoc/api/enum.vala72
-rw-r--r--libvaladoc/api/enumvalue.vala115
-rw-r--r--libvaladoc/api/errorcode.vala108
-rw-r--r--libvaladoc/api/errordomain.vala101
-rw-r--r--libvaladoc/api/field.vala111
-rw-r--r--libvaladoc/api/formalparameter.vala155
-rw-r--r--libvaladoc/api/formalparametertype.vala44
-rw-r--r--libvaladoc/api/girsourcecomment.vala60
-rw-r--r--libvaladoc/api/interface.vala215
-rw-r--r--libvaladoc/api/item.vala71
-rw-r--r--libvaladoc/api/member.vala63
-rw-r--r--libvaladoc/api/method.vala266
-rw-r--r--libvaladoc/api/methodbindingtype.vala55
-rw-r--r--libvaladoc/api/namespace.vala97
-rw-r--r--libvaladoc/api/node.vala725
-rw-r--r--libvaladoc/api/nodetype.vala119
-rw-r--r--libvaladoc/api/ownership.vala47
-rw-r--r--libvaladoc/api/package.vala139
-rw-r--r--libvaladoc/api/pointer.vala55
-rw-r--r--libvaladoc/api/property.vala202
-rw-r--r--libvaladoc/api/propertyaccessor.vala134
-rw-r--r--libvaladoc/api/propertyaccessortype.vala42
-rw-r--r--libvaladoc/api/propertybindingtype.vala48
-rw-r--r--libvaladoc/api/signal.vala146
-rw-r--r--libvaladoc/api/signaturebuilder.vala180
-rw-r--r--libvaladoc/api/sourcecomment.vala86
-rw-r--r--libvaladoc/api/sourcefile.vala60
-rw-r--r--libvaladoc/api/struct.vala174
-rw-r--r--libvaladoc/api/symbol.vala158
-rw-r--r--libvaladoc/api/symbolaccessibility.vala51
-rw-r--r--libvaladoc/api/tree.vala352
-rw-r--r--libvaladoc/api/typeparameter.vala62
-rw-r--r--libvaladoc/api/typereference.vala168
-rw-r--r--libvaladoc/api/typesymbol.vala114
-rw-r--r--libvaladoc/api/visitor.vala171
-rw-r--r--libvaladoc/charts/chart.vala73
-rw-r--r--libvaladoc/charts/chartfactory.vala53
-rw-r--r--libvaladoc/charts/hierarchychart.vala82
-rw-r--r--libvaladoc/charts/simplechartfactory.vala87
-rw-r--r--libvaladoc/content/block.vala25
-rw-r--r--libvaladoc/content/blockcontent.vala66
-rw-r--r--libvaladoc/content/comment.vala106
-rw-r--r--libvaladoc/content/contentelement.vala46
-rw-r--r--libvaladoc/content/contentfactory.vala124
-rw-r--r--libvaladoc/content/contentrenderer.vala32
-rw-r--r--libvaladoc/content/contentvisitor.vala86
-rw-r--r--libvaladoc/content/embedded.vala125
-rw-r--r--libvaladoc/content/headline.vala66
-rw-r--r--libvaladoc/content/inline.vala25
-rw-r--r--libvaladoc/content/inlinecontent.vala75
-rw-r--r--libvaladoc/content/inlinetaglet.vala71
-rw-r--r--libvaladoc/content/link.vala115
-rw-r--r--libvaladoc/content/list.vala156
-rw-r--r--libvaladoc/content/listitem.vala59
-rw-r--r--libvaladoc/content/note.vala55
-rw-r--r--libvaladoc/content/page.vala65
-rw-r--r--libvaladoc/content/paragraph.vala74
-rw-r--r--libvaladoc/content/resourcelocator.vala29
-rw-r--r--libvaladoc/content/run.vala208
-rw-r--r--libvaladoc/content/sourcecode.vala240
-rw-r--r--libvaladoc/content/styleattributes.vala116
-rw-r--r--libvaladoc/content/symbollink.vala72
-rw-r--r--libvaladoc/content/table.vala79
-rw-r--r--libvaladoc/content/tablecell.vala93
-rw-r--r--libvaladoc/content/tablerow.vala77
-rw-r--r--libvaladoc/content/taglet.vala38
-rw-r--r--libvaladoc/content/text.vala63
-rw-r--r--libvaladoc/content/warning.vala55
-rw-r--r--libvaladoc/content/wikilink.vala78
-rw-r--r--libvaladoc/ctyperesolver.vala402
-rw-r--r--libvaladoc/devhelp-markupwriter.vala93
-rw-r--r--libvaladoc/doclet.vala52
-rw-r--r--libvaladoc/documentation/commentscanner.vala69
-rw-r--r--libvaladoc/documentation/documentation.vala39
-rw-r--r--libvaladoc/documentation/documentationparser.vala897
-rw-r--r--libvaladoc/documentation/girmetadata.vala156
-rw-r--r--libvaladoc/documentation/gtkdoccommentparser.vala1668
-rw-r--r--libvaladoc/documentation/gtkdoccommentscanner.vala890
-rw-r--r--libvaladoc/documentation/gtkdocmarkdownparser.vala840
-rw-r--r--libvaladoc/documentation/gtkdocmarkdownscanner.vala761
-rw-r--r--libvaladoc/documentation/importerhelper.vala266
-rw-r--r--libvaladoc/documentation/wiki.vala159
-rw-r--r--libvaladoc/documentation/wikiscanner.vala395
-rw-r--r--libvaladoc/errorreporter.vala392
-rw-r--r--libvaladoc/filehelper.vala200
-rw-r--r--libvaladoc/gtkdocmarkupwriter.vala73
-rw-r--r--libvaladoc/gtkdocrenderer.vala503
-rw-r--r--libvaladoc/highlighter/codescanner.vala572
-rw-r--r--libvaladoc/highlighter/codetoken.vala58
-rw-r--r--libvaladoc/highlighter/highlighter.vala366
-rw-r--r--libvaladoc/highlighter/scanner.vala32
-rw-r--r--libvaladoc/highlighter/xmlscanner.vala374
-rw-r--r--libvaladoc/html/basicdoclet.vala1159
-rw-r--r--libvaladoc/html/cssclassresolver.vala117
-rw-r--r--libvaladoc/html/htmlchartfactory.vala54
-rw-r--r--libvaladoc/html/htmlmarkupwriter.vala132
-rw-r--r--libvaladoc/html/htmlrenderer.vala632
-rw-r--r--libvaladoc/html/linkhelper.vala189
-rw-r--r--libvaladoc/importer/documentationimporter.vala47
-rw-r--r--libvaladoc/importer/girdocumentationimporter.vala863
-rw-r--r--libvaladoc/importer/internalidregistrar.vala88
-rw-r--r--libvaladoc/importer/valadocdocumentationimporter.vala199
-rw-r--r--libvaladoc/importer/valadocdocumentationimporterscanner.vala187
-rw-r--r--libvaladoc/markupreader.vala337
-rw-r--r--libvaladoc/markupsourcelocation.vala39
-rw-r--r--libvaladoc/markuptokentype.vala51
-rw-r--r--libvaladoc/markupwriter.vala272
-rw-r--r--libvaladoc/moduleloader.vala254
-rw-r--r--libvaladoc/parser/manyrule.vala112
-rw-r--r--libvaladoc/parser/oneofrule.vala98
-rw-r--r--libvaladoc/parser/optionalrule.vala88
-rw-r--r--libvaladoc/parser/parser.vala306
-rw-r--r--libvaladoc/parser/parsercallback.vala37
-rw-r--r--libvaladoc/parser/rule.vala173
-rw-r--r--libvaladoc/parser/scanner.vala36
-rw-r--r--libvaladoc/parser/sequencerule.vala132
-rw-r--r--libvaladoc/parser/sourcelocation.vala35
-rw-r--r--libvaladoc/parser/stubrule.vala62
-rw-r--r--libvaladoc/parser/token.vala110
-rw-r--r--libvaladoc/parser/tokentype.vala271
-rw-r--r--libvaladoc/settings.vala169
-rw-r--r--libvaladoc/taglets/tagletdeprecated.vala61
-rw-r--r--libvaladoc/taglets/tagletinheritdoc.vala232
-rw-r--r--libvaladoc/taglets/tagletinit.vala35
-rw-r--r--libvaladoc/taglets/tagletlink.vala186
-rw-r--r--libvaladoc/taglets/tagletparam.vala166
-rw-r--r--libvaladoc/taglets/tagletreturn.vala79
-rw-r--r--libvaladoc/taglets/tagletsee.vala77
-rw-r--r--libvaladoc/taglets/tagletsince.vala63
-rw-r--r--libvaladoc/taglets/tagletthrows.vala125
-rw-r--r--libvaladoc/valadoc-1.0.deps.in3
-rw-r--r--libvaladoc/valadoc-1.0.pc.in14
143 files changed, 25485 insertions, 0 deletions
diff --git a/libvaladoc/Makefile.am b/libvaladoc/Makefile.am
new file mode 100644
index 000000000..a53b08892
--- /dev/null
+++ b/libvaladoc/Makefile.am
@@ -0,0 +1,232 @@
+NULL =
+
+DEFAULT_DRIVER = $(shell $(VALAC) --api-version >/dev/null 2>&1; if [ $$? = 0 ]; then $(VALAC) --api-version; else $(VALAC) --version; fi)
+
+AM_CFLAGS = \
+ -DPACKAGE_ICONDIR=\"$(datadir)/valadoc/icons/\" \
+ -DPACKAGE_DATADIR=\"$(libdir)/valadoc\" \
+ -DPACKAGE_VERSION=\"$(VERSION)\" \
+ -DDEFAULT_DRIVER=\"$(DEFAULT_DRIVER)\" \
+ $(LIBGVC_CFLAGS) \
+ $(GLIB_CFLAGS) \
+ $(LIBGEE_CFLAGS) \
+ $(GMODULE_CFLAGS) \
+ -g \
+ -w \
+ $(NULL)
+
+AM_VALAFLAGS = \
+ $(VALAFLAGS) \
+ --vapidir $(top_srcdir)/src/vapi/ \
+ --basedir $(srcdir) \
+ --directory $(builddir) \
+ -C \
+ -g \
+ $(NULL)
+
+BUILT_SOURCES = \
+ libvaladoc.vala.stamp \
+ valadoc-1.0.h \
+ $(NULL)
+
+lib_LTLIBRARIES = libvaladoc.la
+
+libvaladoc_la_VALASOURCES = \
+ doclet.vala \
+ errorreporter.vala \
+ filehelper.vala \
+ moduleloader.vala \
+ settings.vala \
+ markupwriter.vala \
+ gtkdocmarkupwriter.vala \
+ devhelp-markupwriter.vala \
+ ctyperesolver.vala \
+ markupsourcelocation.vala \
+ markuptokentype.vala \
+ markupreader.vala \
+ gtkdocrenderer.vala \
+ documentation/commentscanner.vala \
+ documentation/documentation.vala \
+ documentation/documentationparser.vala \
+ documentation/wiki.vala \
+ documentation/wikiscanner.vala \
+ documentation/gtkdoccommentparser.vala \
+ documentation/gtkdoccommentscanner.vala \
+ documentation/gtkdocmarkdownparser.vala \
+ documentation/gtkdocmarkdownscanner.vala \
+ documentation/importerhelper.vala \
+ documentation/girmetadata.vala \
+ importer/documentationimporter.vala \
+ importer/valadocdocumentationimporter.vala \
+ importer/valadocdocumentationimporterscanner.vala \
+ importer/girdocumentationimporter.vala \
+ importer/internalidregistrar.vala \
+ api/symbolaccessibility.vala \
+ api/sourcecomment.vala \
+ api/girsourcecomment.vala \
+ api/attributeargument.vala \
+ api/attribute.vala \
+ api/array.vala \
+ api/callable.vala \
+ api/childsymbolregistrar.vala \
+ api/class.vala \
+ api/constant.vala \
+ api/delegate.vala \
+ api/enum.vala \
+ api/enumvalue.vala \
+ api/errorcode.vala \
+ api/errordomain.vala \
+ api/field.vala \
+ api/formalparameter.vala \
+ api/formalparametertype.vala \
+ api/interface.vala \
+ api/item.vala \
+ api/member.vala \
+ api/method.vala \
+ api/methodbindingtype.vala \
+ api/namespace.vala \
+ api/node.vala \
+ api/nodetype.vala \
+ api/ownership.vala \
+ api/package.vala \
+ api/pointer.vala \
+ api/property.vala \
+ api/propertyaccessor.vala \
+ api/propertyaccessortype.vala \
+ api/propertybindingtype.vala \
+ api/signal.vala \
+ api/signaturebuilder.vala \
+ api/sourcefile.vala \
+ api/struct.vala \
+ api/symbol.vala \
+ api/tree.vala \
+ api/typeparameter.vala \
+ api/typereference.vala \
+ api/typesymbol.vala \
+ api/browsable.vala \
+ api/visitor.vala \
+ api/driver.vala \
+ content/block.vala \
+ content/blockcontent.vala \
+ content/comment.vala \
+ content/contentfactory.vala \
+ content/contentelement.vala \
+ content/contentrenderer.vala \
+ content/contentvisitor.vala \
+ content/embedded.vala \
+ content/headline.vala \
+ content/inline.vala \
+ content/inlinetaglet.vala \
+ content/inlinecontent.vala \
+ content/wikilink.vala \
+ content/link.vala \
+ content/list.vala \
+ content/listitem.vala \
+ content/page.vala \
+ content/paragraph.vala \
+ content/warning.vala \
+ content/note.vala \
+ content/resourcelocator.vala \
+ content/run.vala \
+ content/sourcecode.vala \
+ content/styleattributes.vala \
+ content/symbollink.vala \
+ content/table.vala \
+ content/tablecell.vala \
+ content/tablerow.vala \
+ content/taglet.vala \
+ content/text.vala \
+ charts/chart.vala \
+ charts/chartfactory.vala \
+ charts/hierarchychart.vala \
+ charts/simplechartfactory.vala \
+ parser/manyrule.vala \
+ parser/oneofrule.vala \
+ parser/optionalrule.vala \
+ parser/parser.vala \
+ parser/parsercallback.vala \
+ parser/rule.vala \
+ parser/scanner.vala \
+ parser/sequencerule.vala \
+ parser/sourcelocation.vala \
+ parser/stubrule.vala \
+ parser/token.vala \
+ parser/tokentype.vala \
+ taglets/tagletdeprecated.vala \
+ taglets/tagletinheritdoc.vala \
+ taglets/tagletinit.vala \
+ taglets/tagletlink.vala \
+ taglets/tagletparam.vala \
+ taglets/tagletreturn.vala \
+ taglets/tagletsee.vala \
+ taglets/tagletsince.vala \
+ taglets/tagletthrows.vala \
+ highlighter/scanner.vala \
+ highlighter/codescanner.vala \
+ highlighter/xmlscanner.vala \
+ highlighter/codetoken.vala \
+ highlighter/highlighter.vala \
+ html/basicdoclet.vala \
+ html/htmlchartfactory.vala \
+ html/linkhelper.vala \
+ html/cssclassresolver.vala \
+ html/htmlmarkupwriter.vala \
+ html/htmlrenderer.vala \
+ $(NULL)
+
+nodist_libvaladoc_la_SOURCES = \
+ $(libvaladoc_la_VALASOURCES:.vala=.c) \
+ $(NULL)
+
+valadoc-1.0.vapi valadoc-1.0.h: libvaladoc.vala.stamp
+libvaladoc.vala.stamp: $(libvaladoc_la_VALASOURCES) Makefile
+ $(VALAC) \
+ $(AM_VALAFLAGS) \
+ -H valadoc-1.0.h \
+ --library valadoc-1.0 \
+ --vapi valadoc-1.0.vapi \
+ --pkg config \
+ --pkg gee-0.8 \
+ --pkg gmodule-2.0 \
+ --pkg libgvc \
+ $(filter %.vala %.c,$^)
+ touch $@
+
+libvaladoc_la_LDFLAGS = -no-undefined
+
+libvaladoc_la_LIBADD = \
+ $(LIBGVC_LIBS) \
+ $(LIBGEE_LIBS) \
+ $(GLIB_LIBS) \
+ $(GMODULE_LIBS) \
+ $(NULL)
+
+libvaladocincludedir = $(includedir)/
+nodist_libvaladocinclude_HEADERS = \
+ valadoc-1.0.h \
+ $(NULL)
+
+pkgconfigdir = $(libdir)/pkgconfig
+nodist_pkgconfig_DATA = valadoc-1.0.pc
+
+vapidir = $(datadir)/vala/vapi
+nodist_vapi_DATA = \
+ valadoc-1.0.vapi \
+ valadoc-1.0.deps \
+ $(NULL)
+
+EXTRA_DIST = \
+ $(libvaladoc_la_VALASOURCES) \
+ valadoc-1.0.deps.in \
+ valadoc-1.0.pc.in \
+ $(NULL)
+
+CLEANFILES = \
+ $(BUILT_SOURCES) \
+ $(nodist_libvaladoc_la_SOURCES) \
+ valadoc-1.0.deps \
+ valadoc-1.0.pc \
+ valadoc-1.0.vapi \
+ valadoc-1.0.h \
+ $(NULL)
+
diff --git a/libvaladoc/api/array.vala b/libvaladoc/api/array.vala
new file mode 100644
index 000000000..cfbd64291
--- /dev/null
+++ b/libvaladoc/api/array.vala
@@ -0,0 +1,70 @@
+/* array.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an array declaration.
+ */
+public class Valadoc.Api.Array : Item {
+
+ /**
+ * The element type.
+ */
+ public Item data_type {
+ set;
+ get;
+ }
+
+ public Array (Item parent, void* data) {
+ base (data);
+
+ this.parent = parent;
+ }
+
+ private inline bool element_is_owned () {
+ TypeReference reference = data_type as TypeReference;
+ if (reference == null) {
+ return true;
+ }
+
+ return !reference.is_unowned && !reference.is_weak;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ SignatureBuilder builder = new SignatureBuilder ();
+ if (element_is_owned ()) {
+ builder.append_content (data_type.signature);
+ } else {
+ builder.append ("(", false);
+ builder.append_content (data_type.signature, false);
+ builder.append (")", false);
+ }
+ builder.append ("[]", false);
+ return builder.get ();
+ }
+}
diff --git a/libvaladoc/api/attribute.vala b/libvaladoc/api/attribute.vala
new file mode 100644
index 000000000..04fac9b18
--- /dev/null
+++ b/libvaladoc/api/attribute.vala
@@ -0,0 +1,109 @@
+/* attribute.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Valadoc.Content;
+using Gee;
+
+
+public class Valadoc.Api.Attribute : Item {
+ private ArrayList<AttributeArgument> args = new ArrayList<AttributeArgument> ();
+ private SourceFile file;
+
+ public string name {
+ private set;
+ get;
+ }
+
+ public Attribute (Node parent, SourceFile file, string name, void* data) {
+ base (data);
+
+ this.parent = parent;
+ this.name = name;
+ this.file = file;
+ }
+
+ public AttributeArgument? get_argument (string name) {
+ if (args != null) {
+ foreach (AttributeArgument arg in args) {
+ if (arg.name == name) {
+ return arg;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ public AttributeArgument add_boolean (string name, bool value, void* data = null) {
+ AttributeArgument arg = new AttributeArgument.boolean (this, file, name, value, data);
+ args.add (arg);
+ return arg;
+ }
+
+ public AttributeArgument add_integer (string name, int value, void* data = null) {
+ AttributeArgument arg = new AttributeArgument.integer (this, file, name, value, data);
+ args.add (arg);
+ return arg;
+ }
+
+ public AttributeArgument add_double (string name, double value, void* data = null) {
+ AttributeArgument arg = new AttributeArgument.double (this, file, name, value, data);
+ args.add (arg);
+ return arg;
+ }
+
+ public AttributeArgument add_string (string name, string value, void* data = null) {
+ AttributeArgument arg = new AttributeArgument.string (this, file, name, value, data);
+ args.add (arg);
+ return arg;
+ }
+
+ public SourceFile get_source_file () {
+ return file;
+ }
+
+ protected override Inline build_signature () {
+ SignatureBuilder builder = new SignatureBuilder ();
+
+ builder.append_attribute ("[");
+ builder.append_type_name (name);
+
+ if (args.size > 0) {
+ builder.append_attribute ("(");
+ bool first = true;
+
+ foreach (AttributeArgument arg in args) {
+ if (first == false) {
+ builder.append_attribute (", ");
+ }
+ builder.append_content (arg.signature);
+ first = false;
+ }
+ builder.append_attribute (")");
+ }
+
+ builder.append_attribute ("]");
+
+ return builder.get ();
+ }
+}
+
diff --git a/libvaladoc/api/attributeargument.vala b/libvaladoc/api/attributeargument.vala
new file mode 100644
index 000000000..7bcd0c6d8
--- /dev/null
+++ b/libvaladoc/api/attributeargument.vala
@@ -0,0 +1,135 @@
+/* attributeargument.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+using Valadoc.Content;
+using Gee;
+
+
+
+public class Valadoc.Api.AttributeArgument : Item {
+ public enum Type {
+ BOOLEAN,
+ INTEGER,
+ DOUBLE,
+ STRING
+ }
+
+ private SourceFile file;
+
+ public string name {
+ private set;
+ get;
+ }
+
+ public AttributeArgument.Type argument_type {
+ private set;
+ get;
+ }
+
+ public string value {
+ private set;
+ get;
+ }
+
+ public AttributeArgument.boolean (Attribute parent, SourceFile file, string name, bool value, void* data) {
+ this (parent, file, name, Type.BOOLEAN, value.to_string (), data);
+ }
+
+ public AttributeArgument.integer (Attribute parent, SourceFile file, string name, int value, void* data) {
+ this (parent, file, name, Type.INTEGER, value.to_string (), data);
+ }
+
+ public AttributeArgument.double (Attribute parent, SourceFile file, string name, double value, void* data) {
+ this (parent, file, name, Type.DOUBLE, value.to_string (), data);
+ }
+
+ public AttributeArgument.string (Attribute parent, SourceFile file, string name, string value, void* data) {
+ this (parent, file, name, Type.STRING, value, data);
+ }
+
+ private AttributeArgument (Attribute parent, SourceFile file, string name, Type type, string value, void* data) {
+ base (data);
+
+ this.argument_type = type;
+ this.parent = parent;
+ this.value = value;
+ this.file = file;
+ this.name = name;
+ }
+
+ public SourceFile get_source_file () {
+ return file;
+ }
+
+ public bool get_value_as_boolean () {
+ assert (argument_type == Type.BOOLEAN);
+
+ bool tmp;
+
+ if (bool.try_parse (value, out tmp)) {
+ return tmp;
+ }
+
+ assert_not_reached ();
+ }
+
+ public int get_value_as_integer () {
+ assert (argument_type == Type.INTEGER);
+
+ double tmp;
+
+ if (global::double.try_parse (value, out tmp) && tmp >= int.MIN && tmp <= int.MAX) {
+ return (int) tmp;
+ }
+
+ assert_not_reached ();
+ }
+
+ public double get_value_as_double () {
+ assert (argument_type == Type.DOUBLE);
+
+ double tmp;
+
+ if (global::double.try_parse (value, out tmp)) {
+ return tmp;
+ }
+
+ assert_not_reached ();
+ }
+
+ public string get_value_as_string () {
+ assert (argument_type == Type.STRING);
+
+ return value;
+ }
+
+ protected override Inline build_signature () {
+ SignatureBuilder builder = new SignatureBuilder ();
+
+ builder.append_attribute (name);
+ builder.append_attribute ("=");
+ builder.append_literal (value);
+
+ return builder.get ();
+ }
+}
diff --git a/libvaladoc/api/browsable.vala b/libvaladoc/api/browsable.vala
new file mode 100644
index 000000000..498ba0dd8
--- /dev/null
+++ b/libvaladoc/api/browsable.vala
@@ -0,0 +1,35 @@
+/* browsable.vala
+ *
+ * Copyright (C) 2008 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 Gee;
+
+
+/**
+ * Specifies whether users are able to browse the item.
+ */
+public interface Valadoc.Api.Browsable : Item {
+
+ /**
+ * Specifies whether users are able to browse the item.
+ */
+ public abstract bool is_browsable (Settings settings);
+}
diff --git a/libvaladoc/api/callable.vala b/libvaladoc/api/callable.vala
new file mode 100644
index 000000000..60515ee1b
--- /dev/null
+++ b/libvaladoc/api/callable.vala
@@ -0,0 +1,51 @@
+/* callable.vala
+ *
+ * Copyright (C) 2012 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 GLib;
+using Gee;
+
+
+/**
+ * Used to translate imported C-documentation
+ */
+public interface Valadoc.Api.Callable : Symbol {
+ /**
+ * The return type of this symbol.
+ *
+ * @return The return type of this symbol or null for void
+ */
+ public abstract TypeReference? return_type {
+ set;
+ get;
+ }
+
+ /**
+ * Used to avoid warnings for implicit parameters
+ */
+ internal abstract string? implicit_array_length_cparameter_name {
+ get;
+ set;
+ }
+}
+
diff --git a/libvaladoc/api/childsymbolregistrar.vala b/libvaladoc/api/childsymbolregistrar.vala
new file mode 100644
index 000000000..e044327b0
--- /dev/null
+++ b/libvaladoc/api/childsymbolregistrar.vala
@@ -0,0 +1,99 @@
+/* childsymbolregistrar.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Valadoc.Api;
+using Gee;
+
+
+public class Valadoc.Api.ChildSymbolRegistrar : Visitor {
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_tree (Api.Tree item) {
+ item.accept_children (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_package (Package item) {
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_namespace (Namespace item) {
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_interface (Interface item) {
+ Collection<TypeReference> interfaces = item.get_implemented_interface_list ();
+ foreach (var type_ref in interfaces) {
+ ((Interface) type_ref.data_type).register_related_interface (item);
+ }
+
+ if (item.base_type != null) {
+ ((Class) item.base_type.data_type).register_derived_interface (item);
+ }
+
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_class (Class item) {
+ Collection<TypeReference> interfaces = item.get_implemented_interface_list ();
+ foreach (TypeReference type_ref in interfaces) {
+ ((Interface) type_ref.data_type).register_implementation (item);
+ }
+
+ if (item.base_type != null) {
+ ((Class) item.base_type.data_type).register_child_class (item);
+ }
+
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_struct (Struct item) {
+ if (item.base_type != null) {
+ ((Struct) item.base_type.data_type).register_child_struct (item);
+ }
+
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_property (Property item) {
+ item.accept_all_children (this, false);
+ }
+}
+
diff --git a/libvaladoc/api/class.vala b/libvaladoc/api/class.vala
new file mode 100644
index 000000000..8d792a75a
--- /dev/null
+++ b/libvaladoc/api/class.vala
@@ -0,0 +1,361 @@
+/* class.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a class declaration.
+ */
+public class Valadoc.Api.Class : TypeSymbol {
+ private ArrayList<TypeReference> interfaces;
+
+ private string? dbus_name;
+ private string? take_value_function_cname;
+ private string? get_value_function_cname;
+ private string? set_value_function_cname;
+ private string? unref_function_name;
+ private string? ref_function_name;
+ private string? free_function_name;
+ private string? finalize_function_name;
+ private string? param_spec_function_name;
+ private string? type_id;
+ private string? is_class_type_macro_name;
+ private string? class_type_macro_name;
+ private string? class_macro_name;
+ private string? private_cname;
+ private string? cname;
+
+ public Class (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? private_cname, string? class_macro_name,
+ string? type_macro_name, string? is_type_macro_name, string? type_cast_macro_name,
+ string? type_function_name, string? class_type_macro_name, string? is_class_type_macro_name,
+ string? dbus_name, string? type_id, string? param_spec_function_name, string? ref_function_name,
+ string? unref_function_name, string? free_function_name, string? finalize_function_name,
+ string? take_value_function_cname, string? get_value_function_cname, string? set_value_function_cname,
+ bool is_fundamental, bool is_abstract, bool is_basic_type, void* data)
+ {
+ base (parent, file, name, accessibility, comment, type_macro_name,
+ is_type_macro_name, type_cast_macro_name, type_function_name, is_basic_type, data);
+
+ this.interfaces = new ArrayList<TypeReference> ();
+
+ this.is_class_type_macro_name = is_class_type_macro_name;
+ this.class_type_macro_name = class_type_macro_name;
+ this.class_macro_name = class_macro_name;
+ this.private_cname = private_cname;
+ this.dbus_name = dbus_name;
+ this.type_id = type_id;
+ this.cname = cname;
+
+ this.param_spec_function_name = param_spec_function_name;
+
+ this.unref_function_name = unref_function_name;
+ this.ref_function_name = ref_function_name;
+ this.finalize_function_name = finalize_function_name;
+ this.free_function_name = free_function_name;
+
+ this.take_value_function_cname = take_value_function_cname;
+ this.get_value_function_cname = get_value_function_cname;
+ this.set_value_function_cname = set_value_function_cname;
+
+ this.is_fundamental = is_fundamental;
+ this.is_abstract = is_abstract;
+ }
+
+ /**
+ * Specifies the base class.
+ */
+ public TypeReference? base_type {
+ set;
+ get;
+ }
+
+ /**
+ * Returns the name of this class as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * Returns the name of this class' private data structure as it is used in C.
+ */
+ public string? get_private_cname () {
+ return private_cname;
+ }
+
+ /**
+ * 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 increments the reference count of
+ * instances of this data type.
+ *
+ * @return the name of the C function or null if this data type does not
+ * support reference counting
+ */
+ public string? get_ref_function_cname () {
+ return ref_function_name;
+ }
+
+ /**
+ * Returns the C function name that decrements the reference count of
+ * instances of this data type.
+ *
+ * @return the name of the C function or null if this data type does not
+ * support reference counting
+ */
+ public string? get_unref_function_cname () {
+ return unref_function_name;
+ }
+
+ /**
+ * Returns the C function name that frees the
+ * instances of this data type.
+ *
+ * @return the name of the C function or null
+ */
+ public string? get_free_function_name () {
+ return free_function_name;
+ }
+
+ /**
+ * Returns the C function name that finalizes the
+ * instances of this data type.
+ *
+ * @return the name of the C function or null
+ */
+ public string? get_finalize_function_name () {
+ return finalize_function_name;
+ }
+
+ /**
+ * Returns the cname of the GValue parameter spec function.
+ */
+ public string? get_param_spec_function_cname () {
+ return param_spec_function_name;
+ }
+
+ /**
+ * Returns the cname of the GValue setter function.
+ */
+ public string? get_set_value_function_cname () {
+ return set_value_function_cname;
+ }
+
+ /**
+ * Returns the cname of the GValue getter function.
+ */
+ public string? get_get_value_function_cname () {
+ return get_value_function_cname;
+ }
+
+ /**
+ * Returns the cname of the GValue taker function.
+ */
+ public string? get_take_value_function_cname () {
+ return take_value_function_cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string? get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which returns the class struct.
+ */
+ public string get_class_macro_name () {
+ return class_macro_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which returns the type of the class.
+ */
+ public string get_class_type_macro_name () {
+ return class_type_macro_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which returns whether a class instance is of a given type.
+ */
+ public string get_is_class_type_macro_name () {
+ return is_class_type_macro_name;
+ }
+
+ /**
+ * Returns a list of all newly implemented interfaces.
+ *
+ * @see get_full_implemented_interface_list
+ */
+ public Collection<TypeReference> get_implemented_interface_list () {
+ return this.interfaces;
+ }
+
+ private Collection<TypeReference> _full_implemented_interfaces = null;
+
+ /**
+ * Returns a list of all implemented interfaces.
+ *
+ * @see get_implemented_interface_list
+ */
+ public Collection<TypeReference> get_full_implemented_interface_list () {
+ if (_full_implemented_interfaces == null) {
+ _full_implemented_interfaces = new LinkedList<TypeReference> ();
+ _full_implemented_interfaces.add_all (this.interfaces);
+
+ if (base_type != null) {
+ _full_implemented_interfaces.add_all (((Class) base_type.data_type).get_full_implemented_interface_list ());
+ }
+ }
+
+ return _full_implemented_interfaces;
+ }
+
+ public void add_interface (TypeReference iface) {
+ interfaces.add (iface);
+ }
+
+ /**
+ * Specifies whether this class is abstract.
+ */
+ public bool is_abstract {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether this class is fundamental.
+ */
+ public bool is_fundamental {
+ private set;
+ get;
+ }
+
+ public bool is_compact {
+ get {
+ return base_type == null && get_attribute ("Compact") != null;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type { get { return NodeType.CLASS; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_class (this);
+ }
+
+ private Set<Interface> _known_derived_interfaces = new TreeSet<Interface> ();
+ private Set<Class> _known_child_classes = new TreeSet<Class> ();
+
+ /**
+ * Returns a list of all known classes based on this class
+ */
+ public Collection<Class> get_known_child_classes () {
+ return _known_child_classes.read_only_view;
+ }
+
+ /**
+ * Returns a list of all known interfaces based on this class
+ */
+ public Collection<Interface> get_known_derived_interfaces () {
+ return _known_derived_interfaces.read_only_view;
+ }
+
+ public void register_derived_interface (Interface iface) {
+ _known_derived_interfaces.add (iface);
+ }
+
+ public void register_child_class (Class cl) {
+ if (this.base_type != null) {
+ ((Class) this.base_type.data_type).register_child_class (cl);
+ }
+
+ _known_child_classes.add (cl);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ if (is_abstract) {
+ signature.append_keyword ("abstract");
+ }
+ signature.append_keyword ("class");
+ signature.append_symbol (this);
+
+ var type_parameters = get_children_by_type (NodeType.TYPE_PARAMETER, false);
+ if (type_parameters.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_parameters) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ bool first = true;
+ if (base_type != null) {
+ signature.append (":");
+
+ signature.append_content (base_type.signature);
+ first = false;
+ }
+
+ if (interfaces.size > 0) {
+ if (first) {
+ signature.append (":");
+ }
+
+ foreach (Item implemented_interface in interfaces) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (implemented_interface.signature);
+ first = false;
+ }
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/constant.vala b/libvaladoc/api/constant.vala
new file mode 100644
index 000000000..351584be4
--- /dev/null
+++ b/libvaladoc/api/constant.vala
@@ -0,0 +1,81 @@
+/* constant.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+/**
+ * Represents a type member with a constant value.
+ */
+public class Valadoc.Api.Constant : Member {
+ private string? cname;
+
+ /**
+ * The data type of this constant.
+ */
+ public TypeReference constant_type {
+ set;
+ get;
+ }
+
+ public Constant (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, void* data)
+ {
+ base (parent, file, name, accessibility, comment, data);
+
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this constant as it is used in C.
+ */
+ public string get_cname () {
+ return cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_keyword (accessibility.to_string ())
+ .append_keyword ("const")
+ .append_content (constant_type.signature)
+ .append_symbol (this)
+ .get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.CONSTANT; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_constant (this);
+ }
+}
+
diff --git a/libvaladoc/api/delegate.vala b/libvaladoc/api/delegate.vala
new file mode 100644
index 000000000..cd7e7c552
--- /dev/null
+++ b/libvaladoc/api/delegate.vala
@@ -0,0 +1,142 @@
+/* delegate.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a Delegate.
+ */
+public class Valadoc.Api.Delegate : TypeSymbol, Callable {
+ private string? cname;
+
+ /**
+ * {@inheritDoc}
+ */
+ internal string? implicit_array_length_cparameter_name {
+ get;
+ set;
+ }
+
+
+ public Delegate (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, bool is_static, void* data)
+ {
+ base (parent, file, name, accessibility, comment, null, null, null, null, false, data);
+
+ this.is_static = is_static;
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this delegate as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public TypeReference? return_type {
+ set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.DELEGATE; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_delegate (this);
+ }
+
+ /**
+ * Specifies whether this delegate is static
+ */
+ public bool is_static {
+ private set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ signature.append_keyword ("delegate");
+ signature.append_content (return_type.signature);
+ signature.append_symbol (this);
+
+ var type_parameters = get_children_by_type (NodeType.TYPE_PARAMETER);
+ if (type_parameters.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_parameters) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ signature.append ("(");
+
+ bool first = true;
+ foreach (Node param in get_children_by_type (NodeType.FORMAL_PARAMETER, false)) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, !first);
+ first = false;
+ }
+
+ signature.append (")", false);
+
+ var exceptions = get_children_by_types ({NodeType.ERROR_DOMAIN, NodeType.CLASS});
+ if (exceptions.size > 0) {
+ signature.append_keyword ("throws");
+ first = true;
+ foreach (Node param in exceptions) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_type (param);
+ first = false;
+ }
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/driver.vala b/libvaladoc/api/driver.vala
new file mode 100644
index 000000000..a43abcff0
--- /dev/null
+++ b/libvaladoc/api/driver.vala
@@ -0,0 +1,43 @@
+/* driver.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Valadoc.Api;
+using Gee;
+
+
+/**
+ * A plugin register function for drivers
+ *
+ * @see ModuleLoader
+ */
+[CCode (has_target = false)]
+public delegate Type Valadoc.DriverRegisterFunction (ModuleLoader module_loader);
+
+
+
+public interface Valadoc.Driver : Object {
+ public abstract void write_gir (Settings settings, ErrorReporter reporter);
+
+ public abstract Api.Tree? build (Settings settings, ErrorReporter reporter);
+}
+
+
diff --git a/libvaladoc/api/enum.vala b/libvaladoc/api/enum.vala
new file mode 100644
index 000000000..230c0bb64
--- /dev/null
+++ b/libvaladoc/api/enum.vala
@@ -0,0 +1,72 @@
+/* enum.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an enum declaration.
+ */
+public class Valadoc.Api.Enum : TypeSymbol {
+ private string cname;
+
+ public Enum (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? type_macro_name,
+ string? type_function_name, void* data)
+ {
+ base (parent, file, name, accessibility, comment, type_macro_name, null, null,
+ type_function_name, false, data);
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this enum as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type { get { return NodeType.ENUM; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_enum (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_keyword (accessibility.to_string ())
+ .append_keyword ("enum")
+ .append_symbol (this)
+ .get ();
+ }
+}
+
diff --git a/libvaladoc/api/enumvalue.vala b/libvaladoc/api/enumvalue.vala
new file mode 100644
index 000000000..34804ff55
--- /dev/null
+++ b/libvaladoc/api/enumvalue.vala
@@ -0,0 +1,115 @@
+/* enumvalue.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an enum member.
+ */
+public class Valadoc.Api.EnumValue: Symbol {
+ private SourceComment? source_comment;
+ private string? cname;
+
+ public Content.Run default_value {
+ get;
+ set;
+ }
+
+ /**
+ * Specifies whether the parameter has a default value
+ */
+ public bool has_default_value {
+ get {
+ return default_value != null;
+ }
+ }
+
+ public EnumValue (Enum parent, SourceFile file, string name, SourceComment? comment, string? cname, void* data) {
+ base (parent, file, name, parent.accessibility, data);
+
+ this.source_comment = comment;
+ this.cname = cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ return ;
+ }
+
+ if (source_comment != null) {
+ documentation = parser.parse (this, source_comment);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ parser.check (this, documentation);
+ }
+
+ base.check_comments (settings, parser);
+ }
+
+ /**
+ * Returns the name of this enum value as it is used in C.
+ */
+ public string get_cname () {
+ return cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type { get { return NodeType.ENUM_VALUE; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_enum_value (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var builder = new SignatureBuilder ()
+ .append_symbol (this);
+
+ if (has_default_value) {
+ builder.append ("=");
+ builder.append_content (default_value);
+ }
+
+ return builder.get ();
+ }
+}
+
diff --git a/libvaladoc/api/errorcode.vala b/libvaladoc/api/errorcode.vala
new file mode 100644
index 000000000..d7cf55128
--- /dev/null
+++ b/libvaladoc/api/errorcode.vala
@@ -0,0 +1,108 @@
+/* errorcode.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an errordomain member in the source code.
+ */
+public class Valadoc.Api.ErrorCode : Symbol {
+ private SourceComment? source_comment;
+ private string? dbus_name;
+ private string? cname;
+
+ public ErrorCode (ErrorDomain parent, SourceFile file, string name, SourceComment? comment,
+ string? cname, string? dbus_name, void* data)
+ {
+ base (parent, file, name, parent.accessibility, data);
+
+ this.source_comment = comment;
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ return ;
+ }
+
+ if (source_comment != null) {
+ documentation = parser.parse (this, source_comment);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ parser.check (this, documentation);
+ }
+
+ base.check_comments (settings, parser);
+ }
+
+ /**
+ * Returns the name of this class as it is used in C.
+ */
+ public string get_cname () {
+ return cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.ERROR_CODE; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_error_code (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_symbol (this)
+ .get ();
+ }
+}
+
diff --git a/libvaladoc/api/errordomain.vala b/libvaladoc/api/errordomain.vala
new file mode 100644
index 000000000..969f294a3
--- /dev/null
+++ b/libvaladoc/api/errordomain.vala
@@ -0,0 +1,101 @@
+/* errordomain.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an error domain declaration.
+ */
+public class Valadoc.Api.ErrorDomain : TypeSymbol {
+ private string? quark_function_name;
+ private string? quark_macro_name;
+ private string? dbus_name;
+ private string? cname;
+
+ public ErrorDomain (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? quark_macro_name,
+ string? quark_function_name, string? dbus_name, void* data)
+ {
+ base (parent, file, name, accessibility, comment, null, null, null, null, false, data);
+
+ this.quark_function_name = quark_function_name;
+ this.quark_macro_name = quark_macro_name;
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this errordomain as it is used in C.
+ */
+ public string? get_cname () {
+ return this.cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string? get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * Gets the name of the quark() function which represents the error domain
+ */
+ public string get_quark_function_name () {
+ return quark_function_name;
+ }
+
+ /**
+ * Gets the name of the quark macro which represents the error domain
+ */
+ public string get_quark_macro_name () {
+ return quark_macro_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.ERROR_DOMAIN; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_error_domain (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_keyword (accessibility.to_string ())
+ .append_keyword ("errordomain")
+ .append_symbol (this)
+ .get ();
+ }
+}
+
diff --git a/libvaladoc/api/field.vala b/libvaladoc/api/field.vala
new file mode 100644
index 000000000..a167c35b8
--- /dev/null
+++ b/libvaladoc/api/field.vala
@@ -0,0 +1,111 @@
+/* field.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a field.
+ */
+public class Valadoc.Api.Field : Member {
+ private string? cname;
+
+ public Field (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, bool is_static, bool is_volatile,
+ void* data)
+ {
+ base (parent, file, name, accessibility, comment, data);
+
+ this.is_static = !(parent is Namespace) && is_static;
+ this.is_volatile = is_volatile;
+
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this field as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * The field type.
+ *
+ * @return The field type or null for void
+ */
+ public TypeReference? field_type {
+ set;
+ get;
+ }
+
+ /**
+ * Specifies whether the field is static.
+ */
+ public bool is_static {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether the field is volatile.
+ */
+ public bool is_volatile {
+ private set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ if (is_static) {
+ signature.append_keyword ("static");
+ }
+ if (is_volatile) {
+ signature.append_keyword ("volatile");
+ }
+
+ signature.append_content (field_type.signature);
+ signature.append_symbol (this);
+ return signature.get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.FIELD; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_field (this);
+ }
+}
+
diff --git a/libvaladoc/api/formalparameter.vala b/libvaladoc/api/formalparameter.vala
new file mode 100644
index 000000000..82ed872a2
--- /dev/null
+++ b/libvaladoc/api/formalparameter.vala
@@ -0,0 +1,155 @@
+/* formalparameter.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+/**
+ * Represents a formal parameter in method, signal and delegate signatures.
+ */
+public class Valadoc.Api.FormalParameter : Symbol {
+ public Content.Run default_value {
+ get;
+ set;
+ }
+
+ /**
+ * Used to translate imported C-documentation
+ */
+ internal string? implicit_array_length_cparameter_name {
+ get;
+ set;
+ }
+
+ /**
+ * Used to translate imported C-documentation
+ */
+ internal string? implicit_closure_cparameter_name {
+ get;
+ set;
+ }
+
+ /**
+ * Used to translate imported C-documentation
+ */
+ internal string? implicit_destroy_cparameter_name {
+ get;
+ set;
+ }
+
+ private FormalParameterType type;
+
+ public FormalParameter (Node parent, SourceFile file, string? name, SymbolAccessibility accessibility, FormalParameterType type, bool ellipsis, void* data) {
+ base (parent, file, name, accessibility, data);
+ assert ((name == null && ellipsis) || (name != null && !ellipsis));
+
+ this.ellipsis = ellipsis;
+ this.type = type;
+ }
+
+ /**
+ * Specifies whether the parameter direction is out
+ */
+ public bool is_out {
+ get {
+ return type == FormalParameterType.OUT;
+ }
+ }
+
+ /**
+ * Specifies whether the parameter direction is ref
+ */
+ public bool is_ref {
+ get {
+ return type == FormalParameterType.REF;
+ }
+ }
+
+ /**
+ * Specifies whether the parameter has a default value
+ */
+ public bool has_default_value {
+ get {
+ return default_value != null;
+ }
+ }
+
+ /**
+ * The parameter type.
+ *
+ * @return The parameter type or null for void
+ */
+ public TypeReference? parameter_type {
+ set;
+ get;
+ }
+
+ /**
+ * Specifies whether the methods accepts a variable number of arguments
+ */
+ public bool ellipsis {
+ private set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.FORMAL_PARAMETER; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_formal_parameter (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ if (ellipsis) {
+ signature.append ("...");
+ } else {
+ if (is_out) {
+ signature.append_keyword ("out");
+ } else if (is_ref) {
+ signature.append_keyword ("ref");
+ }
+
+ signature.append_content (parameter_type.signature);
+ signature.append (name);
+
+ if (has_default_value) {
+ signature.append ("=");
+ signature.append_content (default_value);
+ }
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/formalparametertype.vala b/libvaladoc/api/formalparametertype.vala
new file mode 100644
index 000000000..d95cc0f5f
--- /dev/null
+++ b/libvaladoc/api/formalparametertype.vala
@@ -0,0 +1,44 @@
+/* formalparametertype.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+public enum Valadoc.Api.FormalParameterType {
+ IN,
+ OUT,
+ REF;
+
+ public string to_string () {
+ switch (this) {
+ case FormalParameterType.OUT:
+ return "out";
+
+ case FormalParameterType.REF:
+ return "ref";
+
+ case FormalParameterType.IN:
+ return "";
+
+ }
+
+ assert_not_reached ();
+ }
+}
+
diff --git a/libvaladoc/api/girsourcecomment.vala b/libvaladoc/api/girsourcecomment.vala
new file mode 100644
index 000000000..c935ba39e
--- /dev/null
+++ b/libvaladoc/api/girsourcecomment.vala
@@ -0,0 +1,60 @@
+/* sourcecomment.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+using Gee;
+
+
+/**
+ * A documentation comment used by valadoc
+ */
+public class Valadoc.Api.GirSourceComment : SourceComment {
+ private Map<string, SourceComment> parameters = new HashMap<string, SourceComment> ();
+
+ public string? instance_param_name { set; get; }
+ public SourceComment? return_comment { set; get; }
+ public SourceComment? deprecated_comment { set; get; }
+ public SourceComment? version_comment { get; set; }
+ public SourceComment? stability_comment { get; set; }
+
+
+ public MapIterator<string, SourceComment> parameter_iterator () {
+ return parameters.map_iterator ();
+ }
+
+ public void add_parameter_content (string param_name, SourceComment comment) {
+ this.parameters.set (param_name, comment);
+ }
+
+ public SourceComment? get_parameter_comment (string param_name) {
+ if (parameters == null) {
+ return null;
+ }
+
+ return parameters.get (param_name);
+ }
+
+ public GirSourceComment (string content, SourceFile file, int first_line, int first_column, int last_line, int last_column) {
+ base (content, file, first_line, first_column, last_line, last_column);
+ }
+}
+
diff --git a/libvaladoc/api/interface.vala b/libvaladoc/api/interface.vala
new file mode 100644
index 000000000..c75846ed8
--- /dev/null
+++ b/libvaladoc/api/interface.vala
@@ -0,0 +1,215 @@
+/* interface.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+
+/**
+ * Represents a interface declaration in the source code.
+ */
+public class Valadoc.Api.Interface : TypeSymbol {
+ private string? interface_macro_name;
+ private string? dbus_name;
+ private string? cname;
+
+
+ public Interface (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? type_macro_name, string? is_type_macro_name,
+ string? type_cast_macro_name, string? type_function_name, string interface_macro_name,
+ string? dbus_name, void* data)
+ {
+ base (parent, file, name, accessibility, comment, type_macro_name, is_type_macro_name,
+ type_cast_macro_name, type_function_name, false, data);
+
+ this.interface_macro_name = interface_macro_name;
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+ }
+
+ /**
+ * A list of preconditioned interfaces
+ */
+ private ArrayList<TypeReference> interfaces = new ArrayList<TypeReference> ();
+
+ /**
+ * Add a newpreconditioned interface to the list
+ */
+ public void add_interface (TypeReference iface) {
+ interfaces.add (iface);
+ }
+
+ /**
+ * Returns a list of newly preconditioned interfaces
+ */
+ public Collection<TypeReference> get_implemented_interface_list () {
+ return this.interfaces;
+ }
+
+
+ /**
+ * A list of all preconditioned interfaces
+ */
+ private Collection<TypeReference> _full_implemented_interfaces = null;
+
+ /**
+ * Returns a list of all preconditioned interfaces
+ */
+ public Collection<TypeReference> get_full_implemented_interface_list () {
+ if (_full_implemented_interfaces == null) {
+ _full_implemented_interfaces = new LinkedList<TypeReference> ();
+ _full_implemented_interfaces.add_all (this.interfaces);
+
+ if (base_type != null) {
+ _full_implemented_interfaces.add_all (((Class) base_type.data_type).get_full_implemented_interface_list ());
+ }
+ }
+
+ return _full_implemented_interfaces;
+ }
+
+ /**
+ * Returns the name of this interface as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string? get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which returns the interface struct.
+ */
+ public string get_interface_macro_name () {
+ return interface_macro_name;
+ }
+
+ /**
+ * A preconditioned class or null
+ */
+ public TypeReference? base_type {
+ set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.INTERFACE; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_interface (this);
+ }
+
+ /**
+ * A list of all known related (sub-)interfaces
+ */
+ private Set<Interface> _known_related_interfaces = new TreeSet<Interface> ();
+
+ /**
+ * A list of all known implementations of this interface
+ */
+ private Set<Class> _known_implementations = new TreeSet<Class> ();
+
+ /**
+ * Returns a list of all known implementations of this interface
+ */
+ public Collection<Class> get_known_implementations () {
+ return _known_implementations;
+ }
+
+ /**
+ * Returns a list of all known related (sub-)interfaces
+ */
+ public Collection<Interface> get_known_related_interfaces () {
+ return _known_related_interfaces;
+ }
+
+ public void register_related_interface (Interface iface) {
+ _known_related_interfaces.add (iface);
+ }
+
+ public void register_implementation (Class cl) {
+ _known_implementations.add (cl);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ signature.append_keyword ("interface");
+ signature.append_symbol (this);
+
+ var type_parameters = get_children_by_type (NodeType.TYPE_PARAMETER, false);
+ if (type_parameters.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_parameters) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ bool first = true;
+ if (base_type != null) {
+ signature.append (":");
+
+ signature.append_content (base_type.signature);
+ first = false;
+ }
+
+ if (interfaces.size > 0) {
+ if (first) {
+ signature.append (":");
+ }
+
+ foreach (Item implemented_interface in interfaces) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (implemented_interface.signature);
+ first = false;
+ }
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/item.vala b/libvaladoc/api/item.vala
new file mode 100644
index 000000000..63b994736
--- /dev/null
+++ b/libvaladoc/api/item.vala
@@ -0,0 +1,71 @@
+/* item.vala
+ *
+ * Copyright (C) 2008 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.Content;
+using Gee;
+
+
+/**
+ * Represents a node in the api tree.
+ */
+public abstract class Valadoc.Api.Item : Object {
+ private Inline _signature;
+
+ public void* data {
+ private set;
+ get;
+ }
+
+ /**
+ * The parent of this item.
+ */
+ public Item parent {
+ protected set;
+ get;
+ }
+
+ public Item (void* data) {
+ this.data = data;
+ }
+
+ internal virtual void parse_comments (Settings settings, DocumentationParser parser) {
+ }
+
+ internal virtual void check_comments (Settings settings, DocumentationParser parser) {
+ }
+
+
+ /**
+ * The signature of this item.
+ */
+ public Inline signature {
+ get {
+ if (_signature == null) {
+ _signature = build_signature ();
+ }
+ return _signature;
+ }
+ }
+
+ protected abstract Inline build_signature ();
+}
+
diff --git a/libvaladoc/api/member.vala b/libvaladoc/api/member.vala
new file mode 100644
index 000000000..b8271c37b
--- /dev/null
+++ b/libvaladoc/api/member.vala
@@ -0,0 +1,63 @@
+/* member.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public abstract class Valadoc.Api.Member : Symbol {
+ private SourceComment? source_comment;
+
+ public Member (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, void* data)
+ {
+ base (parent, file, name, accessibility, data);
+
+ this.source_comment = comment;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ return ;
+ }
+
+ if (source_comment != null) {
+ documentation = parser.parse (this, source_comment);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ parser.check (this, documentation);
+ }
+
+ base.check_comments (settings, parser);
+ }
+}
diff --git a/libvaladoc/api/method.vala b/libvaladoc/api/method.vala
new file mode 100644
index 000000000..ce891e112
--- /dev/null
+++ b/libvaladoc/api/method.vala
@@ -0,0 +1,266 @@
+/* method.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Valadoc.Content;
+using Gee;
+
+
+/**
+ * Represents a function or a method.
+ */
+public class Valadoc.Api.Method : Member, Callable {
+ private string? finish_function_cname;
+ private string? dbus_result_name;
+ private string? dbus_name;
+ private string? cname;
+
+ private MethodBindingType binding_type;
+
+ /**
+ * {@inheritDoc}
+ */
+ internal string? implicit_array_length_cparameter_name {
+ get;
+ set;
+ }
+
+
+ public Method (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? dbus_name, string? dbus_result_name,
+ string? finish_function_cname, MethodBindingType binding_type, bool is_yields,
+ bool is_dbus_visible, bool is_constructor, void* data)
+ {
+ base (parent, file, name, accessibility, comment, data);
+
+ this.finish_function_cname = finish_function_cname;
+ this.dbus_result_name = dbus_result_name;
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+
+ this.binding_type = binding_type;
+ this.is_dbus_visible = is_dbus_visible;
+ this.is_constructor = is_constructor;
+ this.is_yields = is_yields;
+ }
+
+ /**
+ * Returns the name of this method as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * Returns the name of the finish function as it is used in C.
+ */
+ public string? get_finish_function_cname () {
+ return finish_function_cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string get_dbus_name () {
+ return dbus_name;
+ }
+
+ public string get_dbus_result_name () {
+ return dbus_result_name;
+ }
+
+ /**
+ * Specifies the virtual or abstract method this method overrides.
+ */
+ public weak Method? base_method {
+ set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public TypeReference? return_type {
+ set;
+ get;
+ }
+
+ /**
+ * Specifies whether this method is asynchronous
+ */
+ public bool is_yields {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether this method is abstract
+ */
+ public bool is_abstract {
+ get {
+ return binding_type == MethodBindingType.ABSTRACT;
+ }
+ }
+
+ /**
+ * Specifies whether this method is virtual
+ */
+ public bool is_virtual {
+ get {
+ return binding_type == MethodBindingType.VIRTUAL;
+ }
+ }
+
+ /**
+ * Specifies whether this method overrides another one
+ */
+ public bool is_override {
+ get {
+ return binding_type == MethodBindingType.OVERRIDE;
+ }
+ }
+
+ /**
+ * Specifies whether this method is static
+ */
+ public bool is_static {
+ get {
+ return !is_constructor && binding_type == MethodBindingType.STATIC
+ && parent is Namespace == false;
+ }
+ }
+
+ /**
+ * Specifies whether this method is a creation method
+ */
+ public bool is_constructor {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether this method is inline
+ */
+ public bool is_inline {
+ get {
+ return binding_type == MethodBindingType.INLINE;
+ }
+ }
+
+ /**
+ * Specifies whether this method is visible for dbus
+ */
+ public bool is_dbus_visible {
+ private set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+
+ if (!is_constructor) {
+ if (is_static) {
+ signature.append_keyword ("static");
+ } else if (is_abstract) {
+ signature.append_keyword ("abstract");
+ } else if (is_override) {
+ signature.append_keyword ("override");
+ } else if (is_virtual) {
+ signature.append_keyword ("virtual");
+ }
+ if (is_inline) {
+ signature.append_keyword ("inline");
+ }
+ if (is_yields) {
+ signature.append_keyword ("async");
+ }
+
+ signature.append_content (return_type.signature);
+ }
+
+ signature.append_symbol (this);
+
+ var type_parameters = get_children_by_type (NodeType.TYPE_PARAMETER, false);
+ if (type_parameters.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_parameters) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ signature.append ("(");
+
+ bool first = true;
+ foreach (Node param in get_children_by_type (NodeType.FORMAL_PARAMETER, false)) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, !first);
+ first = false;
+ }
+
+ signature.append (")", false);
+
+ var exceptions = get_children_by_types ({NodeType.ERROR_DOMAIN, NodeType.CLASS});
+ if (exceptions.size > 0) {
+ signature.append_keyword ("throws");
+ first = true;
+ foreach (Node param in exceptions) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_type (param);
+ first = false;
+ }
+ }
+
+ return signature.get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get {
+ return is_constructor ? NodeType.CREATION_METHOD :
+ is_static ? NodeType.STATIC_METHOD : NodeType.METHOD;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_method (this);
+ }
+}
+
diff --git a/libvaladoc/api/methodbindingtype.vala b/libvaladoc/api/methodbindingtype.vala
new file mode 100644
index 000000000..c340c30b6
--- /dev/null
+++ b/libvaladoc/api/methodbindingtype.vala
@@ -0,0 +1,55 @@
+/* methodbindingtype.vala
+ *
+ * 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+
+public enum Valadoc.MethodBindingType {
+ UNMODIFIED,
+ OVERRIDE,
+ ABSTRACT,
+ VIRTUAL,
+ INLINE,
+ STATIC;
+
+ public string to_string () {
+ switch (this) {
+ case OVERRIDE:
+ return "override";
+
+ case ABSTRACT:
+ return "abstract";
+
+ case VIRTUAL:
+ return "virtual";
+
+ case INLINE:
+ return "inline";
+
+ case STATIC:
+ return "static";
+
+ case UNMODIFIED:
+ return "";
+ }
+
+ assert_not_reached ();
+ }
+}
diff --git a/libvaladoc/api/namespace.vala b/libvaladoc/api/namespace.vala
new file mode 100644
index 000000000..c2cba30d4
--- /dev/null
+++ b/libvaladoc/api/namespace.vala
@@ -0,0 +1,97 @@
+/* namespace.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a namespace declaration.
+ */
+public class Valadoc.Api.Namespace : Symbol {
+ private SourceComment? source_comment;
+
+ public Namespace (Api.Node parent, SourceFile file, string? name, SourceComment? comment, void* data) {
+ base (parent, file, name, SymbolAccessibility.PUBLIC, data);
+
+ this.source_comment = comment;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ return ;
+ }
+
+ if (source_comment != null) {
+ documentation = parser.parse (this, source_comment);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ parser.check (this, documentation);
+ }
+
+ base.check_comments (settings, parser);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_keyword (accessibility.to_string ())
+ .append_keyword ("namespace")
+ .append_symbol (this)
+ .get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type { get { return NodeType.NAMESPACE; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_namespace (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool is_browsable (Settings settings) {
+ return has_visible_children (settings);
+ }
+}
+
diff --git a/libvaladoc/api/node.vala b/libvaladoc/api/node.vala
new file mode 100644
index 000000000..580828ff6
--- /dev/null
+++ b/libvaladoc/api/node.vala
@@ -0,0 +1,725 @@
+/* node.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ * Copyright (C) 20011 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+/**
+ * Represents a node in the api tree.
+ */
+public abstract class Valadoc.Api.Node : Item, Browsable, Documentation, Comparable<Node> {
+ protected bool do_document = false;
+ private SourceFile file;
+
+ /**
+ * The name of the node
+ */
+ public string? name {
+ private set;
+ get;
+ }
+
+ public SourceFile get_source_file () {
+ return file;
+ }
+
+ /**
+ * Returns the type of this node
+ */
+ public abstract NodeType node_type { get; }
+
+ private Map<string, Node> per_name_children;
+ private Map<NodeType, Gee.List<Node>> per_type_children;
+
+
+ public Node (Node? parent, SourceFile? file, string? name, void* data) {
+ base (data);
+
+ per_name_children = new HashMap<string, Node> ();
+ per_type_children = new HashMap<NodeType, Gee.List<Node>> ();
+
+ if (name != null && (is_keyword (name) || name[0].isdigit ())) {
+ this.name = "@" + name;
+ } else {
+ this.name = name;
+ }
+
+ this.parent = parent;
+ this.file = file;
+ }
+
+ /**
+ * Visits this node with the specified Visitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ */
+ public abstract void accept (Visitor visitor);
+
+ /**
+ * {@inheritDoc}
+ */
+ // TODO: rename to is_visible
+ public abstract bool is_browsable (Settings settings);
+
+ /**
+ * {@inheritDoc}
+ */
+ public string? get_filename () {
+ if (file == null) {
+ return null;
+ }
+
+ return file.relative_path;
+ }
+
+ public void add_child (Symbol child) {
+ if (child.name != null) {
+ if (child.name[0] == '@') {
+ per_name_children.set (child.name.next_char (), child);
+ } else {
+ per_name_children.set (child.name, child);
+ }
+ } else {
+ // Special case for the root namespace
+ per_name_children.set ("", child);
+ }
+
+ Gee.List<Node> children = per_type_children.get (child.node_type);
+ if (children == null) {
+ children = new ArrayList<Node> ();
+ per_type_children.set (child.node_type, children);
+ }
+
+ children.add (child);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ do_document = true;
+
+ foreach (Node node in per_name_children.values) {
+ if (node.is_browsable (settings)) {
+ node.parse_comments (settings, parser);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+
+ foreach (Node node in per_name_children.values) {
+ if (node.is_browsable (settings)) {
+ node.check_comments (settings, parser);
+ }
+ }
+ }
+
+
+ /**
+ * Specifies whether this node has at least one visible child with the given type
+ *
+ * @param type a node type
+ */
+ public bool has_visible_children_by_type (NodeType type, Settings settings) {
+ Gee.List<Node>? all_children = per_type_children.get (type);
+ if (all_children != null) {
+ foreach (Node node in all_children) {
+ if (node.is_browsable (settings)) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Specifies whether this node has at least one visible child with the given types
+ *
+ * @param types a list of node types
+ */
+ public bool has_visible_children_by_types (NodeType[] types, Settings settings) {
+ foreach (NodeType type in types) {
+ if (has_visible_children_by_type (type, settings)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Specifies whether this node has at least one visible child
+ */
+ public bool has_visible_children (Settings settings) {
+ return has_visible_children_by_types (per_type_children.keys.to_array (), settings);
+ }
+
+ /**
+ * Specifies whether this node has at least one child with the given type
+ *
+ * @param type a node type
+ */
+ public bool has_children_by_type (NodeType type) {
+ Gee.List<Node>? all_children = per_type_children.get (type);
+ return all_children != null && !all_children.is_empty;
+ }
+
+ /**
+ * Specifies whether this node has at least one child with the given types
+ *
+ * @param types a list of node types
+ */
+ public bool has_children (NodeType[] types) {
+ foreach (NodeType type in types) {
+ if (has_children_by_type (type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns a list of all children with the given type.
+ *
+ * @param type a node type
+ * @param filtered specifies whether nodes which are not browsable should appear in the list
+ */
+ public Gee.List<Node> get_children_by_type (NodeType type, bool filtered = true) {
+ var children = new ArrayList<Node> ();
+
+ Gee.List<Node> all_children = per_type_children.get (type);
+ if (all_children != null) {
+ foreach (Node node in all_children) {
+ if (node.do_document || !filtered) {
+ children.add (node);
+ }
+ }
+ }
+
+ return children;
+ }
+
+ /**
+ * Returns a list of all children with the given types.
+ *
+ * @param types a list of node types
+ * @param filtered specifies whether nodes which are not browsable should appear in the list
+ */
+ public Gee.List<Node> get_children_by_types (NodeType[] types, bool filtered = true) {
+ var children = new ArrayList<Node> ();
+
+ foreach (NodeType type in types) {
+ children.add_all (get_children_by_type (type, filtered));
+ }
+
+ return children;
+ }
+
+ /**
+ * Visits all children of this node with the given type with the specified Visitor.
+ *
+ * @param type a node type
+ * @param visitor the visitor to be called while traversing
+ * @param filtered specifies whether nodes which are not browsable should appear in the list
+ */
+ public void accept_children_by_type (NodeType type, Visitor visitor, bool filtered = true) {
+ Gee.List<Node> all_children = per_type_children.get (type);
+ if (all_children != null) {
+ foreach (Node node in all_children) {
+ if (node.do_document || !filtered) {
+ node.accept (visitor);
+ }
+ }
+ }
+ }
+
+ /**
+ * Visits all children of this node with the given types with the specified Visitor.
+ *
+ * @param types a list of node types
+ * @param visitor the visitor to be called while traversing
+ * @param filtered specifies whether nodes which are not browsable should appear in the list
+ */
+ public void accept_children (NodeType[] types, Visitor visitor, bool filtered = true) {
+ foreach (NodeType type in types) {
+ accept_children_by_type (type, visitor, filtered);
+ }
+ }
+
+ /**
+ * Visits all children of this node with the specified Visitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ * @param filtered specifies whether nodes which are not browsable should appear in the list
+ */
+ public void accept_all_children (Visitor visitor, bool filtered = true) {
+ foreach (Gee.List<Node> children in per_type_children.values) {
+ foreach (Node node in children) {
+ if (node.do_document || !filtered) {
+ node.accept (visitor);
+ }
+ }
+ }
+ }
+
+ public Node? find_by_name (string name) {
+ if (name[0] == '@') {
+ return per_name_children.get (name.next_char ());
+ } else {
+ return per_name_children.get (name);
+ }
+ }
+
+ private Namespace? _nspace = null;
+ private Package? _package = null;
+ private string _full_name = null;
+
+ /**
+ * The corresponding namespace
+ */
+ public Namespace? nspace {
+ get {
+ if (this._nspace == null) {
+ Api.Item ast = this;
+ while (ast is Valadoc.Api.Namespace == false) {
+ ast = ast.parent;
+ if (ast == null) {
+ return null;
+ }
+ }
+ this._nspace = (Valadoc.Api.Namespace)ast;
+ }
+ return this._nspace;
+ }
+ }
+
+ /**
+ * The corresponding package such as a vapi or gir file
+ */
+ public Package? package {
+ get {
+ if (this._package == null) {
+ Api.Item ast = this;
+ while (ast is Valadoc.Api.Package == false) {
+ ast = ast.parent;
+ if (ast == null) {
+ return null;
+ }
+ }
+ this._package = (Valadoc.Api.Package)ast;
+ }
+ return this._package;
+ }
+ }
+
+ public Content.Comment? documentation {
+ internal set;
+ get;
+ }
+
+ /**
+ * Returns canonicalized absolute name (GLib.FileStream for instance)
+ */
+ public string? get_full_name () {
+ if (this._full_name == null) {
+ if (this.name == null) {
+ return null;
+ }
+
+ GLib.StringBuilder full_name = new GLib.StringBuilder (this.name);
+
+ if (this.parent != null) {
+ for (Item pos = this.parent; pos is Package == false ; pos = pos.parent) {
+ string name = ((Node)pos).name;
+ if (name != null) {
+ full_name.prepend_unichar ('.');
+ full_name.prepend (name);
+ }
+ }
+ }
+ this._full_name = full_name.str;
+ }
+ return this._full_name;
+ }
+
+ /**
+ * A comparison function used to sort nodes in alphabetical order
+ */
+ public int compare_to (Node node) {
+ return strcmp (name, node.name);
+ }
+
+ private bool is_keyword (string name) {
+ switch (name[0]) {
+ case 'a':
+ switch (name[1]) {
+ case 'b':
+ return name == "abstract";
+
+ case 's':
+ if (name[2] == '\0') {
+ return true;
+ }
+
+ return name == "async";
+ }
+ break;
+
+ case 'b':
+ switch (name[1]) {
+ case 'a':
+ return name == "base";
+
+ case 'r':
+ return name == "break";
+ }
+ break;
+
+ case 'c':
+ switch (name[1]) {
+ case 'a':
+ switch (name[2]) {
+ case 's':
+ return name == "case";
+
+ case 't':
+ return name == "catch";
+ }
+ break;
+
+ case 'l':
+ return name == "class";
+
+ case 'o':
+ if (name[2] != 'n') {
+ return false;
+ }
+
+ switch (name[3]) {
+ case 's':
+ if (name[4] == 't') {
+ switch (name[5]) {
+ case '\0':
+ return true;
+
+ case 'r':
+ return name == "construct";
+ }
+ }
+ break;
+
+ case 't':
+ return name == "continue";
+ }
+ break;
+ }
+ break;
+
+ case 'd':
+ switch (name[1]) {
+ case 'e':
+ switch (name[2]) {
+ case 'f':
+ return name == "default";
+
+ case 'l':
+ if (name[3] != 'e') {
+ return false;
+ }
+
+ switch (name[4]) {
+ case 'g':
+ return name == "delegate";
+
+ case 't':
+ return name == "delete";
+ }
+ break;
+ }
+ break;
+
+ case 'o':
+ return name[2] == '\0';
+
+ case 'y':
+ return name == "dynamic";
+ }
+ break;
+
+ case 'e':
+ switch (name[1]) {
+ case 'l':
+ return name == "else";
+
+ case 'n':
+ switch (name[2]) {
+ case 's':
+ return name == "ensures";
+
+ case 'u':
+ return name == "enum";
+ }
+ break;
+
+ case 'r':
+ return name == "errordomain";
+
+ case 'x':
+ return name == "extern";
+ }
+ break;
+
+ case 'f':
+ switch (name[1]) {
+ case 'a':
+ return name == "false";
+
+ case 'i':
+ return name == "finally";
+
+ case 'o':
+ if (name[2] != 'r') {
+ return false;
+ }
+
+ switch (name[3]) {
+ case '\0':
+ return true;
+
+ case 'e':
+ return name == "foreach";
+ }
+ break;
+ }
+ break;
+
+ case 'g':
+ return name == "get";
+
+ case 'i':
+ switch (name[1]) {
+ case 'f':
+ return name[2] == '\0';
+
+ case 'n':
+ switch (name[2]) {
+ case '\0':
+ return true;
+
+ case 'l':
+ return name == "inline";
+
+ case 't':
+ return name == "interface" || name == "internal";
+ }
+ break;
+
+ case 's':
+ return name[2] == '\0';
+ }
+ break;
+
+ case 'l':
+ return name == "lock";
+
+ case 'n':
+ switch (name[1]) {
+ case 'a':
+ return name == "namespace";
+
+ case 'e':
+ return name == "new";
+
+ case 'u':
+ return name == "null";
+ }
+ break;
+
+ case 'o':
+ switch (name[1]) {
+ case 'u':
+ return name == "out";
+
+ case 'v':
+ return name == "override";
+
+ case 'w':
+ return name == "owned";
+ }
+ break;
+
+ case 'p':
+ switch (name[1]) {
+ case 'a':
+ return name == "params";
+
+ case 'r':
+ switch (name[2]) {
+ case 'i':
+ return name == "private";
+
+ case 'o':
+ return name == "protected";
+ }
+ break;
+ case 'u':
+ return name == "public";
+ }
+ break;
+
+ case 'r':
+ if (name[1] != 'e') {
+ return false;
+ }
+
+ switch (name[2]) {
+ case 'f':
+ return name[3] == '\0';
+
+ case 'q':
+ return name == "requires";
+
+ case 't':
+ return name == "return";
+ }
+ break;
+
+ case 's':
+ switch (name[1]) {
+ case 'e':
+ switch (name[2]) {
+ case 'a':
+ return name == "sealed";
+
+ case 't':
+ return name[3] == '\0';
+ }
+ break;
+
+ case 'i':
+ switch (name[2]) {
+ case 'g':
+ return name == "signal";
+ case 'z':
+ return name == "sizeof";
+ }
+ break;
+
+ case 't':
+ switch (name[2]) {
+ case 'a':
+ return name == "static";
+
+ case 'r':
+ return name == "struct";
+ }
+ break;
+
+ case 'w':
+ return name == "switch";
+ }
+ break;
+
+ case 't':
+ switch (name[1]) {
+ case 'h':
+ switch (name[2]) {
+ case 'i':
+ return name == "this";
+
+ case 'r':
+ if (name[3] == 'o' && name[4] == 'w') {
+ return name[5] == '\0' || (name[5] == 's' && name[6] == '\0');
+ }
+ break;
+ }
+ break;
+
+ case 'r':
+ switch (name[2]) {
+ case 'u':
+ return name == "true";
+
+ case 'y':
+ return name[3] == '\0';
+ }
+ break;
+
+ case 'y':
+ return name == "typeof";
+ }
+ break;
+
+ case 'u':
+ switch (name[1]) {
+ case 'n':
+ return name == "unowned";
+
+ case 's':
+ return name == "using";
+ }
+ break;
+
+ case 'v':
+ switch (name[1]) {
+ case 'a':
+ return name == "var";
+
+ case 'i':
+ return name == "virtual";
+
+ case 'o':
+ switch (name[2]) {
+ case 'i':
+ return name == "void";
+
+ case 'l':
+ return name == "volatile";
+ }
+ break;
+ }
+ break;
+
+ case 'w':
+ switch (name[1]) {
+ case 'e':
+ return name == "weak";
+
+ case 'h':
+ return name == "while";
+ }
+ break;
+
+ case 'y':
+ return name == "yield";
+ }
+
+ return false;
+ }
+}
+
diff --git a/libvaladoc/api/nodetype.vala b/libvaladoc/api/nodetype.vala
new file mode 100644
index 000000000..1fbc22e66
--- /dev/null
+++ b/libvaladoc/api/nodetype.vala
@@ -0,0 +1,119 @@
+/* node.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2007-20012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+/**
+ * Specifies the context of a node.
+ */
+public enum Valadoc.Api.NodeType {
+ CLASS,
+ CONSTANT,
+ CREATION_METHOD,
+ DELEGATE,
+ ENUM,
+ ENUM_VALUE,
+ ERROR_CODE,
+ ERROR_DOMAIN,
+ FIELD,
+ FORMAL_PARAMETER,
+ INTERFACE,
+ METHOD,
+ NAMESPACE,
+ PACKAGE,
+ PROPERTY,
+ PROPERTY_ACCESSOR,
+ SIGNAL,
+ STATIC_METHOD,
+ STRUCT,
+ TYPE_PARAMETER;
+
+ public string to_string () {
+ switch (this) {
+ case CLASS:
+ return "CLASS";
+
+ case CONSTANT:
+ return "CONSTANT";
+
+ case CREATION_METHOD:
+ return "CREATION_METHOD";
+
+ case DELEGATE:
+ return "DELEGATE";
+
+ case ENUM:
+ return "ENUM";
+
+ case ENUM_VALUE:
+ return "ENUM_VALUE";
+
+ case ERROR_CODE:
+ return "ERROR_CODE";
+
+ case ERROR_DOMAIN:
+ return "ERROR_DOMAIN";
+
+ case FIELD:
+ return "FIELD";
+
+ case FORMAL_PARAMETER:
+ return "FORMAL_PARAMETER";
+
+ case INTERFACE:
+ return "INTERFACE";
+
+ case METHOD:
+ return "METHOD";
+
+ case NAMESPACE:
+ return "NAMESPACE";
+
+ case PACKAGE:
+ return "PACKAGE";
+
+ case PROPERTY:
+ return "PROPERTY";
+
+ case PROPERTY_ACCESSOR:
+ return "PROPERTY_ACCESSOR";
+
+ case SIGNAL:
+ return "SIGNAL";
+
+ case STATIC_METHOD:
+ return "STATIC_METHOD";
+
+ case STRUCT:
+ return "STRUCT";
+
+ case TYPE_PARAMETER:
+ return "TYPE_PARAMETER";
+
+ default:
+ assert_not_reached ();
+ }
+ }
+}
+
diff --git a/libvaladoc/api/ownership.vala b/libvaladoc/api/ownership.vala
new file mode 100644
index 000000000..eb4f5b0fc
--- /dev/null
+++ b/libvaladoc/api/ownership.vala
@@ -0,0 +1,47 @@
+/* ownership.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+public enum Valadoc.Api.Ownership {
+ DEFAULT,
+ UNOWNED,
+ OWNED,
+ WEAK;
+
+ public string to_string () {
+ switch (this) {
+ case Ownership.UNOWNED:
+ return "unowned";
+
+ case Ownership.OWNED:
+ return "owned";
+
+ case Ownership.WEAK:
+ return "weak";
+
+ case Ownership.DEFAULT:
+ return "";
+ }
+
+ assert_not_reached ();
+ }
+}
diff --git a/libvaladoc/api/package.vala b/libvaladoc/api/package.vala
new file mode 100644
index 000000000..8c2cad184
--- /dev/null
+++ b/libvaladoc/api/package.vala
@@ -0,0 +1,139 @@
+/* package.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+using Valadoc.Importer;
+
+public class Valadoc.Api.Package : Node {
+
+ /**
+ * Specifies whether this package is a dependency
+ */
+ public bool is_package {
+ private set;
+ get;
+ }
+
+ internal void set_dependency_list (ArrayList<Package> list) {
+ this._dependencies = list;
+ }
+
+ private ArrayList<Package> _dependencies;
+
+ /**
+ * Returns a list with all dependencies
+ */
+ public Collection<Package> get_full_dependency_list () {
+ ArrayList<Package> list = new ArrayList<Package> ();
+
+ if (this._dependencies == null) {
+ return list.read_only_view;
+ }
+
+ foreach (Package pkg in this._dependencies) {
+ if (list.contains ( pkg ) == false) {
+ list.add (pkg);
+ }
+
+ var pkg_list = pkg.get_full_dependency_list ();
+ foreach (Package pkg2 in pkg_list) {
+ if (list.contains (pkg2) == false) {
+ list.add (pkg2);
+ }
+ }
+ }
+ return list.read_only_view;
+ }
+
+ public Collection<Package> get_dependency_list () {
+ if (this._dependencies == null) {
+ return Collection.empty<Package> ();
+ }
+
+ return this._dependencies.read_only_view;
+ }
+
+ public Package (string name, bool is_package, void* data) {
+ base (null, null, name, data);
+
+ this.is_package = is_package;
+ this.parent = null;
+ }
+
+ // <version, symbols>
+ private HashMap<string?, ArrayList<Symbol>> deprecated;
+
+ internal void register_deprecated_symbol (Symbol symbol, string? version) {
+ if (deprecated == null) {
+ deprecated = new HashMap<string?, ArrayList<Symbol>> ();
+ }
+
+ ArrayList<Symbol> list = deprecated.get (version);
+ if (list == null) {
+ list = new ArrayList<Symbol> ();
+ deprecated.set (version, list);
+ }
+
+ list.add (symbol);
+ }
+
+ public Map<string?, Collection<Symbol>> get_deprecated_symbols () {
+ if (deprecated == null) {
+ return Map<string?, Collection<Symbol>>.empty<string?, Collection<Symbol>> ();
+ }
+
+ return deprecated;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool is_browsable (Settings settings) {
+ return !(this.is_package && settings.with_deps == false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.PACKAGE; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_package (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_keyword ("package")
+ .append (name)
+ .get ();
+ }
+}
+
diff --git a/libvaladoc/api/pointer.vala b/libvaladoc/api/pointer.vala
new file mode 100644
index 000000000..aec541bb8
--- /dev/null
+++ b/libvaladoc/api/pointer.vala
@@ -0,0 +1,55 @@
+/* pointer.vala
+ *
+ * Copyright (C) 2008 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 Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a pointer declaration.
+ */
+public class Valadoc.Api.Pointer : Item {
+
+ /**
+ * The type the pointer is referring to.
+ */
+ public Item data_type {
+ set;
+ get;
+ }
+
+ public Pointer (Item parent, void* data) {
+ base (data);
+
+ this.parent = parent;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_content (data_type.signature)
+ .append ("*", false)
+ .get ();
+ }
+}
diff --git a/libvaladoc/api/property.vala b/libvaladoc/api/property.vala
new file mode 100644
index 000000000..556c7c9bf
--- /dev/null
+++ b/libvaladoc/api/property.vala
@@ -0,0 +1,202 @@
+/* property.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a property declaration.
+ */
+public class Valadoc.Api.Property : Member {
+ private PropertyBindingType binding_type;
+ private string? dbus_name;
+ private string? cname;
+
+ public Property (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? dbus_name, bool is_dbus_visible,
+ PropertyBindingType binding_type, void* data)
+ {
+ base (parent, file, name, accessibility, comment, data);
+
+ this.is_dbus_visible = is_dbus_visible;
+ this.binding_type = binding_type;
+
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+ }
+
+ /**
+ * Returns the name of this method as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * The property type.
+ *
+ * @return The property type or null for void
+ */
+ public TypeReference? property_type {
+ set;
+ get;
+ }
+
+ /**
+ * Specifies whether the property is virtual.
+ */
+ public bool is_virtual {
+ get {
+ return binding_type == PropertyBindingType.VIRTUAL;
+ }
+ }
+
+ /**
+ * Specifies whether the property is abstract.
+ */
+ public bool is_abstract {
+ get {
+ return binding_type == PropertyBindingType.ABSTRACT;
+ }
+ }
+
+ /**
+ * Specifies whether the property is override.
+ */
+ public bool is_override {
+ get {
+ return binding_type == PropertyBindingType.OVERRIDE;
+ }
+ }
+
+ /**
+ * Specifies whether the property is visible.
+ */
+ public bool is_dbus_visible {
+ private set;
+ get;
+ }
+
+ public PropertyAccessor? setter {
+ internal set;
+ get;
+ }
+
+ public PropertyAccessor? getter {
+ internal set;
+ get;
+ }
+
+ /**
+ * Specifies the virtual or abstract property this property overrides.
+ */
+ public Property base_property {
+ set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (getter != null && getter.is_browsable (settings)) {
+ getter.parse_comments (settings, parser);
+ }
+
+ if (setter != null && setter.is_browsable (settings)) {
+ setter.parse_comments (settings, parser);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (getter != null && getter.is_browsable (settings)) {
+ getter.check_comments (settings, parser);
+ }
+
+ if (setter != null && setter.is_browsable (settings)) {
+ setter.check_comments (settings, parser);
+ }
+
+ base.check_comments (settings, parser);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ if (is_abstract) {
+ signature.append_keyword ("abstract");
+ } else if (is_override) {
+ signature.append_keyword ("override");
+ } else if (is_virtual) {
+ signature.append_keyword ("virtual");
+ }
+
+ signature.append_content (property_type.signature);
+ signature.append_symbol (this);
+ signature.append ("{");
+
+ if (setter != null && setter.do_document) {
+ signature.append_content (setter.signature);
+ }
+
+ if (getter != null && getter.do_document) {
+ signature.append_content (getter.signature);
+ }
+
+ signature.append ("}");
+
+ return signature.get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.PROPERTY; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_property (this);
+ }
+}
+
diff --git a/libvaladoc/api/propertyaccessor.vala b/libvaladoc/api/propertyaccessor.vala
new file mode 100644
index 000000000..0a79dd3fc
--- /dev/null
+++ b/libvaladoc/api/propertyaccessor.vala
@@ -0,0 +1,134 @@
+/* propertyaccessor.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a get or set accessor of a property.
+ */
+public class Valadoc.Api.PropertyAccessor : Symbol {
+ private PropertyAccessorType type;
+ private Ownership ownership;
+ private string? cname;
+
+ public PropertyAccessor (Property parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ string? cname, PropertyAccessorType type, Ownership ownership, void* data)
+ {
+ base (parent, file, name, accessibility, data);
+
+ this.ownership = ownership;
+ this.cname = cname;
+ this.type = type;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.PROPERTY_ACCESSOR; }
+ }
+
+ /**
+ * Returns the name of this property accessor as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ }
+
+ /**
+ * Specifies whether this accessor may be used to construct the property.
+ */
+ public bool is_construct {
+ get {
+ return (type & PropertyAccessorType.CONSTRUCT) != 0;
+ }
+ }
+
+ /**
+ * Specifies whether this accessor is a setter.
+ */
+ public bool is_set {
+ get {
+ return (type & PropertyAccessorType.SET) != 0;
+ }
+ }
+
+ /**
+ * Specifies whether this accessor is a getter.
+ */
+ public bool is_get {
+ get {
+ return (type & PropertyAccessorType.GET) != 0;
+ }
+ }
+
+ /**
+ * Specifies whether the property is owned.
+ */
+ public bool is_owned {
+ get {
+ return ownership == Ownership.OWNED;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ // FIXME
+ if (!do_document) {
+ return signature.get ();
+ }
+
+ if (((Property) parent).accessibility != accessibility) {
+ signature.append_keyword (accessibility.to_string ());
+ }
+
+ if (is_set || is_construct) {
+ if (is_construct) {
+ signature.append_keyword ("construct");
+ }
+ if (is_set) {
+ signature.append_keyword ("set");
+ }
+ } else if (is_get) {
+ if (is_owned) {
+ signature.append_keyword ("owned");
+ }
+ signature.append_keyword ("get");
+ }
+ signature.append (";", false);
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/propertyaccessortype.vala b/libvaladoc/api/propertyaccessortype.vala
new file mode 100644
index 000000000..609815ae0
--- /dev/null
+++ b/libvaladoc/api/propertyaccessortype.vala
@@ -0,0 +1,42 @@
+/* propertyaccessor.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+public enum Valadoc.Api.PropertyAccessorType {
+ CONSTRUCT = 1 << 0,
+ SET = 1 << 1,
+ GET = 1 << 2;
+
+ public string to_string () {
+ if ((this & PropertyAccessorType.CONSTRUCT) != 0) {
+ if ((this & PropertyAccessorType.SET) != 0) {
+ return "construct set";
+ }
+ return "construct";
+ } else if ((this & PropertyAccessorType.SET) != 0) {
+ return "set";
+ } else if ((this & PropertyAccessorType.GET) != 0) {
+ return "get";
+ }
+
+ assert_not_reached ();
+ }
+}
diff --git a/libvaladoc/api/propertybindingtype.vala b/libvaladoc/api/propertybindingtype.vala
new file mode 100644
index 000000000..a8ce1617b
--- /dev/null
+++ b/libvaladoc/api/propertybindingtype.vala
@@ -0,0 +1,48 @@
+/* propertybindingtype.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+public enum Valadoc.Api.PropertyBindingType {
+ UNMODIFIED,
+ OVERRIDE,
+ ABSTRACT,
+ VIRTUAL;
+
+ public string to_string () {
+ switch (this) {
+ case OVERRIDE:
+ return "override";
+
+ case ABSTRACT:
+ return "abstract";
+
+ case VIRTUAL:
+ return "virtual";
+
+ case UNMODIFIED:
+ return "";
+ }
+
+ assert_not_reached ();
+ }
+}
+
diff --git a/libvaladoc/api/signal.vala b/libvaladoc/api/signal.vala
new file mode 100644
index 000000000..4bbbb2320
--- /dev/null
+++ b/libvaladoc/api/signal.vala
@@ -0,0 +1,146 @@
+/* signal.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents an signal.
+ */
+public class Valadoc.Api.Signal : Member, Callable {
+ private string? default_impl_cname;
+ private string? dbus_name;
+ private string? cname;
+
+
+ /**
+ * {@inheritDoc}
+ */
+ internal string? implicit_array_length_cparameter_name {
+ get;
+ set;
+ }
+
+
+ public Signal (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? default_impl_cname, string? dbus_name, bool is_dbus_visible,
+ bool is_virtual, void* data)
+ {
+ base (parent, file, name, accessibility, comment, data);
+
+ this.default_impl_cname = default_impl_cname;
+ this.dbus_name = dbus_name;
+ this.cname = cname;
+
+ this.is_dbus_visible = is_dbus_visible;
+ this.is_virtual = is_virtual;
+ }
+
+ /**
+ * Returns the name of this signal as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ public string? get_default_impl_cname () {
+ return default_impl_cname;
+ }
+
+ /**
+ * Returns the dbus-name.
+ */
+ public string get_dbus_name () {
+ return dbus_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public TypeReference? return_type {
+ set;
+ get;
+ }
+
+ /**
+ * Specifies whether this signal is virtual
+ */
+ public bool is_virtual {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether this signal is visible for dbus
+ */
+ public bool is_dbus_visible {
+ private set;
+ get;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ if (is_virtual) {
+ signature.append_keyword ("virtual");
+ }
+
+ signature.append_keyword ("signal");
+
+ signature.append_content (return_type.signature);
+ signature.append_symbol (this);
+ signature.append ("(");
+
+ bool first = true;
+ foreach (Node param in get_children_by_type (NodeType.FORMAL_PARAMETER, false)) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, !first);
+ first = false;
+ }
+
+ signature.append (")", false);
+
+ return signature.get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.SIGNAL; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_signal (this);
+ }
+}
+
diff --git a/libvaladoc/api/signaturebuilder.vala b/libvaladoc/api/signaturebuilder.vala
new file mode 100644
index 000000000..158bd6e41
--- /dev/null
+++ b/libvaladoc/api/signaturebuilder.vala
@@ -0,0 +1,180 @@
+/* signaturebuilder.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Valadoc.Content;
+
+
+/**
+ * Builds up a signature from the given items.
+ */
+public class Valadoc.Api.SignatureBuilder {
+ private Run run;
+ private Inline last_appended;
+
+ /**
+ * Creates a new SignatureBuilder
+ */
+ public SignatureBuilder () {
+ run = new Run (Run.Style.NONE);
+ }
+
+ private void append_text (string text) {
+ if (last_appended is Text) {
+ ((Text) last_appended).content += text;
+ } else {
+ run.content.add (last_appended = new Text (text));
+ }
+ }
+
+ /**
+ * Adds text onto the end of the builder.
+ *
+ * @param text a string
+ * @param spaced add a space at the front of the string if necessary
+ * @return this
+ */
+ public SignatureBuilder append (string text, bool spaced = true) {
+ string content = (last_appended != null && spaced ? " " : "") + text;
+ append_text (content);
+ return this;
+ }
+
+ /**
+ * Adds text onto the end of the builder.
+ *
+ * @param text a string
+ * @param spaced add a space at the front of the string if necessary
+ * @return this
+ */
+ public SignatureBuilder append_attribute (string text, bool spaced = true) {
+ string content = (last_appended != null && spaced ? " " : "") + text;
+ append_text (content);
+ return this;
+ }
+
+ /**
+ * Adds highlighted text onto the end of the builder.
+ *
+ * @param text a string
+ * @param spaced add a space at the front of the string if necessary
+ * @return this
+ */
+ public SignatureBuilder append_highlighted (string text, bool spaced = true) {
+ string content = (last_appended != null && spaced ? " " : "") + text;
+ Run inner = new Run (Run.Style.ITALIC);
+ inner.content.add (new Text (content));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * Adds a Inline onto the end of the builder.
+ *
+ * @param content a content
+ * @param spaced add a space at the front of the inline if necessary
+ * @return this
+ */
+ public SignatureBuilder append_content (Inline content, bool spaced = true) {
+ if (last_appended != null && spaced) {
+ append_text (" ");
+ }
+ run.content.add (last_appended = content);
+ return this;
+ }
+
+ /**
+ * Adds a keyword onto the end of the builder.
+ *
+ * @param keyword a keyword
+ * @param spaced add a space at the front of the keyword if necessary
+ * @return this
+ */
+ public SignatureBuilder append_keyword (string keyword, bool spaced = true) {
+ Run inner = new Run (Run.Style.LANG_KEYWORD);
+ inner.content.add (new Text (keyword));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * Adds a symbol onto the end of the builder.
+ *
+ * @param node a node
+ * @param spaced add a space at the front of the node if necessary
+ * @return this
+ */
+ public SignatureBuilder append_symbol (Node node, bool spaced = true) {
+ Run inner = new Run (Run.Style.BOLD);
+ inner.content.add (new SymbolLink (node, node.name));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * Adds a type onto the end of the builder.
+ *
+ * @param node a node
+ * @param spaced add a space at the front of the node if necessary
+ * @return this
+ */
+ public SignatureBuilder append_type (Node node, bool spaced = true) {
+ Run.Style style = Run.Style.LANG_TYPE;
+ if (node is TypeSymbol && ((TypeSymbol)node).is_basic_type) {
+ style = Run.Style.LANG_BASIC_TYPE;
+ }
+
+ Run inner = new Run (style);
+ inner.content.add (new SymbolLink (node, node.name));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * Adds a type name onto the end of the builder.
+ *
+ * @param name a type name
+ * @param spaced add a space at the front of the type name if necessary
+ * @return this
+ */
+ public SignatureBuilder append_type_name (string name, bool spaced = true) {
+ Run inner = new Run (Run.Style.LANG_TYPE);
+ inner.content.add (new Text (name));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * Adds a literal onto the end of the builder.
+ *
+ * @param literal a literal
+ * @param spaced add a space at the front of the literal if necessary
+ * @return this
+ */
+ public SignatureBuilder append_literal (string literal, bool spaced = true) {
+ Run inner = new Run (Run.Style.LANG_LITERAL);
+ inner.content.add (new Text (literal));
+ return append_content (inner, spaced);
+ }
+
+ /**
+ * The content
+ */
+ public new Run get () {
+ return run;
+ }
+}
+
diff --git a/libvaladoc/api/sourcecomment.vala b/libvaladoc/api/sourcecomment.vala
new file mode 100644
index 000000000..df6d1e1da
--- /dev/null
+++ b/libvaladoc/api/sourcecomment.vala
@@ -0,0 +1,86 @@
+/* sourcecomment.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+
+/**
+ * A documentation comment used by valadoc
+ */
+public class Valadoc.Api.SourceComment {
+ public SourceFile file {
+ private set;
+ get;
+ }
+
+ /**
+ * The text describing the referenced source code.
+ */
+ public string content {
+ private set;
+ get;
+ }
+
+ /**
+ * The first line number of the referenced source code.
+ */
+ public int first_line {
+ private set;
+ get;
+ }
+
+ /**
+ * The first column number of the referenced source code.
+ */
+ public int first_column {
+ private set;
+ get;
+ }
+
+ /**
+ * The last line number of the referenced source code.
+ */
+ public int last_line {
+ private set;
+ get;
+ }
+
+ /**
+ * The last column number of the referenced source code.
+ */
+ public int last_column {
+ private set;
+ get;
+ }
+
+ public SourceComment (string content, SourceFile file, int first_line, int first_column,
+ int last_line, int last_column)
+ {
+ this.first_column = first_column;
+ this.last_column = last_column;
+ this.first_line = first_line;
+ this.last_line = last_line;
+ this.content = content;
+ this.file = file;
+ }
+}
+
+
diff --git a/libvaladoc/api/sourcefile.vala b/libvaladoc/api/sourcefile.vala
new file mode 100644
index 000000000..46d1801be
--- /dev/null
+++ b/libvaladoc/api/sourcefile.vala
@@ -0,0 +1,60 @@
+/* sourcefile.vala
+ *
+ * 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+/**
+ * Represents a source file
+ */
+public class Valadoc.Api.SourceFile : Object {
+
+ public Package package {
+ private set;
+ get;
+ }
+
+ public string relative_path {
+ private set;
+ get;
+ }
+
+ public string? relative_c_path {
+ private set;
+ get;
+ }
+
+ public string get_name () {
+ return Path.get_basename (relative_path);
+ }
+
+ public void* data {
+ private set;
+ get;
+ }
+
+ public SourceFile (Package package, string relative_path, string? relative_c_path, void* data) {
+ this.relative_c_path = relative_c_path;
+ this.relative_path = relative_path;
+ this.package = package;
+ this.data = data;
+ }
+}
+
+
diff --git a/libvaladoc/api/struct.vala b/libvaladoc/api/struct.vala
new file mode 100644
index 000000000..e1df479c3
--- /dev/null
+++ b/libvaladoc/api/struct.vala
@@ -0,0 +1,174 @@
+/* struct.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a struct declaration.
+ */
+public class Valadoc.Api.Struct : TypeSymbol {
+ private string? dup_function_cname;
+ private string? copy_function_cname;
+ private string? free_function_cname;
+ private string? destroy_function_cname;
+ private string? type_id;
+ private string? cname;
+
+ public Struct (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? cname, string? type_macro_name,
+ string? type_function_name, string? type_id, string? dup_function_cname,
+ string? copy_function_cname, string? destroy_function_cname,
+ string? free_function_cname, bool is_basic_type, void* data)
+ {
+ base (parent, file, name, accessibility, comment, type_macro_name, null, null,
+ type_function_name, is_basic_type, data);
+
+ this.dup_function_cname = dup_function_cname;
+ this.copy_function_cname = copy_function_cname;
+ this.free_function_cname = free_function_cname;
+ this.destroy_function_cname = destroy_function_cname;
+
+ this.cname = cname;
+ }
+
+ /**
+ * Specifies the base struct.
+ */
+ public TypeReference? base_type {
+ set;
+ get;
+ }
+
+
+ /**
+ * Returns the name of this struct as it is used in C.
+ */
+ public string? get_cname () {
+ return cname;
+ }
+
+ /**
+ * 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.
+ */
+ public string? get_dup_function_cname () {
+ return dup_function_cname;
+ }
+
+ /**
+ * Returns the C function name that copies instances of this data
+ * type.
+ */
+ public string? get_copy_function_cname () {
+ return copy_function_cname;
+ }
+
+ /**
+ * Returns the C function name that frees instances of this data type.
+ */
+ public string? get_free_function_cname () {
+ return free_function_cname;
+ }
+
+ /**
+ * Returns the C function name that destroys instances of this data type.
+ */
+ public string? get_destroy_function_cname () {
+ return destroy_function_cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type {
+ get { return NodeType.STRUCT; }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_struct (this);
+ }
+
+
+ private Set<Struct> _known_child_structs = new TreeSet<Struct> ();
+
+ /**
+ * Returns a list of all known structs based on this struct
+ */
+ public Collection<Struct> get_known_child_structs () {
+ return _known_child_structs.read_only_view;
+ }
+
+ public void register_child_struct (Struct stru) {
+ if (this.base_type != null) {
+ ((Struct) this.base_type.data_type).register_child_struct (stru);
+ }
+
+ _known_child_structs.add (stru);
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ signature.append_keyword (accessibility.to_string ());
+ signature.append_keyword ("struct");
+ signature.append_symbol (this);
+
+ var type_parameters = get_children_by_type (NodeType.TYPE_PARAMETER, false);
+ if (type_parameters.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_parameters) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ if (base_type != null) {
+ signature.append (":");
+
+ signature.append_content (base_type.signature);
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/symbol.vala b/libvaladoc/api/symbol.vala
new file mode 100644
index 000000000..aec2bdd75
--- /dev/null
+++ b/libvaladoc/api/symbol.vala
@@ -0,0 +1,158 @@
+/* symbol.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+/**
+ * Represents a node in the symbol tree.
+ */
+public abstract class Valadoc.Api.Symbol : Node {
+ private ArrayList<Attribute> attributes;
+
+ public bool is_deprecated {
+ default = false;
+ private set;
+ get;
+ }
+
+ public Symbol (Node parent, SourceFile file, string? name, SymbolAccessibility accessibility,
+ void* data)
+ {
+ base (parent, file, name, data);
+
+ this.accessibility = accessibility;
+ }
+
+ public void add_attribute (Attribute att) {
+ if (attributes == null) {
+ attributes = new ArrayList<Attribute> ();
+ }
+
+ // register deprecated symbols:
+ if (att.name == "Version") {
+ AttributeArgument? deprecated = att.get_argument ("deprecated");
+ AttributeArgument? version = att.get_argument ("deprecated_since");
+ if ((deprecated != null && deprecated.get_value_as_boolean ()) || version != null) {
+ string? version_str = (version != null) ? version.get_value_as_string () : null;
+
+ package.register_deprecated_symbol (this, version_str);
+ is_deprecated = true;
+ }
+ } else if (att.name == "Deprecated") {
+ AttributeArgument? version = att.get_argument ("version");
+ string? version_str = (version != null) ? version.get_value_as_string () : null;
+
+ package.register_deprecated_symbol (this, version_str);
+ is_deprecated = true;
+ }
+
+ attributes.add (att);
+ }
+
+ public Collection<Attribute> get_attributes () {
+ if (attributes == null) {
+ return Collection<Attribute>.empty<Attribute> ();
+ } else {
+ return attributes;
+ }
+ }
+
+ public Attribute? get_attribute (string name) {
+ if (attributes != null) {
+ foreach (Attribute att in attributes) {
+ if (att.name == name) {
+ return att;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override bool is_browsable (Settings settings) {
+ if (!settings._private && this.is_private) {
+ return false;
+ }
+ if (!settings._internal && this.is_internal) {
+ return false;
+ }
+ if (!settings._protected && this.is_protected) {
+ return false;
+ }
+
+ Item? pos = parent;
+ while (pos != null && pos is Symbol && pos is Namespace == false) {
+ if (((Symbol) pos).is_browsable (settings) == false) {
+ return false;
+ }
+ pos = pos.parent;
+ }
+
+ return true;
+ }
+
+ public SymbolAccessibility accessibility {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies whether this symbol is public.
+ */
+ public bool is_public {
+ get {
+ return accessibility == SymbolAccessibility.PUBLIC;
+ }
+ }
+
+ /**
+ * Specifies whether this symbol is protected.
+ */
+ public bool is_protected {
+ get {
+ return accessibility == SymbolAccessibility.PROTECTED;
+ }
+ }
+
+ /**
+ * Specifies whether this symbol is internal.
+ */
+ public bool is_internal {
+ get {
+ return accessibility == SymbolAccessibility.INTERNAL;
+ }
+ }
+
+ /**
+ * Specifies whether this symbol is private.
+ */
+ public bool is_private {
+ get {
+ return accessibility == SymbolAccessibility.PRIVATE;
+ }
+ }
+}
+
diff --git a/libvaladoc/api/symbolaccessibility.vala b/libvaladoc/api/symbolaccessibility.vala
new file mode 100644
index 000000000..9b78aa671
--- /dev/null
+++ b/libvaladoc/api/symbolaccessibility.vala
@@ -0,0 +1,51 @@
+/* SymbolAccessibility.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+/**
+ * The access modifier
+ */
+public enum Valadoc.Api.SymbolAccessibility {
+ PROTECTED,
+ INTERNAL,
+ PRIVATE,
+ PUBLIC;
+
+ public string to_string () {
+ switch (this) {
+ case SymbolAccessibility.PROTECTED:
+ return "protected";
+
+ case SymbolAccessibility.INTERNAL:
+ return "internal";
+
+ case SymbolAccessibility.PRIVATE:
+ return "private";
+
+ case SymbolAccessibility.PUBLIC:
+ return "public";
+
+ default:
+ assert_not_reached ();
+ }
+ }
+}
diff --git a/libvaladoc/api/tree.vala b/libvaladoc/api/tree.vala
new file mode 100644
index 000000000..a5ae3c54b
--- /dev/null
+++ b/libvaladoc/api/tree.vala
@@ -0,0 +1,352 @@
+/* tree.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Valadoc.Importer;
+using Gee;
+
+
+
+/**
+ * The root of the code tree.
+ */
+public class Valadoc.Api.Tree {
+ private Deque<InheritDocContainer> inheritdocs = new LinkedList<InheritDocContainer> ();
+ private ArrayList<string> external_c_files = new ArrayList<string>();
+ private ArrayList<Package> packages = new ArrayList<Package>();
+ private Package source_package = null;
+ private Settings settings;
+ private ErrorReporter reporter;
+ private Highlighter.Highlighter _highlighter;
+ private CTypeResolver _cresolver = null;
+ private Package _source_package;
+
+
+ private class InheritDocContainer {
+ public unowned Taglets.InheritDoc taglet;
+ public unowned Api.Node taglet_container;
+
+ public InheritDocContainer (Api.Node taglet_container, Taglets.InheritDoc taglet) {
+ this.taglet_container = taglet_container;
+ this.taglet = taglet;
+ }
+ }
+
+
+ public void add_package(Package package) {
+ this.packages.add (package);
+ }
+
+ public void* data {
+ set;
+ get;
+ }
+
+ public Highlighter.Highlighter highlighter {
+ get {
+ if (_highlighter == null) {
+ _highlighter = new Highlighter.Highlighter ();
+ }
+
+ return _highlighter;
+ }
+ }
+
+ /**
+ * The root of the wiki tree.
+ */
+ public WikiPageTree? wikitree {
+ private set;
+ get;
+ }
+
+ /**
+ * Returns a list of C source files.
+ *
+ * @return list of C source files
+ */
+ public Collection<string> get_external_c_files () {
+ return external_c_files.read_only_view;
+ }
+
+ public void add_external_c_files (string name) {
+ external_c_files.add (name);
+ }
+
+
+ /**
+ * Returns a list of all packages in the tree
+ *
+ * @return list of all packages
+ */
+ public Collection<Package> get_package_list () {
+ return this.packages.read_only_view;
+ }
+
+ private void add_dependencies_to_source_package () {
+ if ( this.source_package != null ) {
+ ArrayList<Package> deplst = new ArrayList<Package> ();
+ foreach (Package pkg in this.packages) {
+ if (pkg != this.source_package) {
+ deplst.add (pkg);
+ }
+ }
+ this.source_package.set_dependency_list (deplst);
+ }
+ }
+
+ /**
+ * Visits this node with the specified Visitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ */
+ public void accept (Visitor visitor) {
+ visitor.visit_tree (this);
+ }
+
+ /**
+ * Visits all children of this node with the given types with the specified Visitor.
+ *
+ * @param visitor the visitor to be called while traversing
+ */
+ public void accept_children (Visitor visitor) {
+ foreach (Node node in packages) {
+ node.accept (visitor);
+ }
+ }
+
+ private Node? search_relative_to (Node element, string[] path) {
+ Api.Node? node = element;
+
+ foreach (string name in path) {
+ node = node.find_by_name (name);
+ if (node == null) {
+ break;
+ }
+ }
+
+ if (node == null && element.parent != null) {
+ node = search_relative_to ((Node) element.parent, path);
+ }
+
+ return node;
+ }
+
+ public Node? search_symbol_path (Node? element, string[] path) {
+ Api.Node? node = null;
+
+ // relative to element
+ if (element != null) {
+ node = search_relative_to (element, path);
+ if (node != null) {
+ return node;
+ }
+ }
+
+
+ // absolute
+ foreach (Package package in packages) {
+ // search in root namespace
+
+ Node? global = package.find_by_name ("");
+ if (global != null) {
+ node = search_relative_to (global, path);
+ if (node != null) {
+ return node;
+ }
+ }
+ }
+
+ 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);
+ }
+
+ return _cresolver.resolve_symbol (element, cname);
+ }
+
+ public Node? search_symbol_str (Node? element, string symname) {
+ string[] path = split_name (symname);
+
+ var node = search_symbol_path (element, path);
+ if (node != null) {
+ return node;
+ }
+
+ if (path.length >= 2 && path[path.length-2] == path[path.length-2]) {
+ path[path.length-2] = path[path.length-2]+"."+path[path.length-1];
+ path.resize (path.length-1);
+ return search_symbol_path (element, path);
+ }
+
+ return null;
+ }
+
+ private string[] split_name (string full_name) {
+ string[] params = (full_name).split (".", -1);
+ int i = 0; while (params[i] != null) i++;
+ params.length = i;
+ return params;
+ }
+
+ public Tree (ErrorReporter reporter, Settings settings, void* data = null) {
+ this.settings = settings;
+ this.reporter = reporter;
+ this.data = data;
+ }
+
+ // copied from valacodecontext.vala
+ private string? get_file_path (string basename, string[] directories) {
+ string filename = null;
+
+ if (directories != null) {
+ foreach (string dir in directories) {
+ filename = Path.build_filename (dir, basename);
+ if (FileUtils.test (filename, FileTest.EXISTS)) {
+ return filename;
+ }
+ }
+ }
+
+ foreach (string dir in Environment.get_system_data_dirs ()) {
+ filename = Path.build_filename (dir, basename);
+ if (FileUtils.test (filename, FileTest.EXISTS)) {
+ return filename;
+ }
+ }
+
+ return null;
+ }
+
+ public bool create_tree ( ) {
+ this.add_dependencies_to_source_package ();
+ return true;
+ }
+
+ private Package? get_source_package () {
+ if (_source_package == null) {
+ foreach (Package pkg in packages) {
+ if (!pkg.is_package) {
+ _source_package = pkg;
+ break;
+ }
+ }
+ }
+
+ return _source_package;
+ }
+
+ private void parse_wiki (DocumentationParser docparser) {
+ this.wikitree = new WikiPageTree ();
+ var pkg = get_source_package ();
+ if (pkg != null) {
+ wikitree.parse (settings, docparser, pkg, reporter);
+ }
+ }
+
+ private void check_wiki (DocumentationParser docparser) {
+ Package pkg = get_source_package ();
+ if (pkg != null) {
+ wikitree.check (settings, docparser, pkg);
+ }
+ }
+
+ public void parse_comments (DocumentationParser docparser) {
+ parse_wiki (docparser);
+
+ foreach (Package pkg in this.packages) {
+ if (pkg.is_browsable (settings)) {
+ pkg.parse_comments (settings, docparser);
+ }
+ }
+ }
+
+ public void check_comments (DocumentationParser docparser) {
+ check_wiki (docparser);
+
+ foreach (Package pkg in this.packages) {
+ if (pkg.is_browsable (settings)) {
+ pkg.check_comments (settings, docparser);
+ postprocess_inheritdoc (docparser);
+ }
+ }
+ }
+
+ internal void register_inheritdoc (Api.Node container, Taglets.InheritDoc taglet) {
+ inheritdocs.add (new InheritDocContainer (container, taglet));
+ }
+
+ private void postprocess_inheritdoc (DocumentationParser docparser) {
+ while (!this.inheritdocs.is_empty) {
+ InheritDocContainer container = this.inheritdocs.poll_head ();
+
+ docparser.transform_inheritdoc (container.taglet_container, container.taglet);
+ }
+ }
+
+
+ /**
+ * Import documentation from various sources
+ *
+ * @param importers a list of importers
+ * @param packages sources
+ * @param import_directories List of directories where to find the files
+ */
+ public void import_comments (DocumentationImporter[] importers, string[] packages,
+ string[] import_directories)
+ {
+ HashSet<string> processed = new HashSet<string> ();
+ foreach (string pkg_name in packages) {
+ bool imported = false;
+ foreach (DocumentationImporter importer in importers) {
+ string? path = get_file_path ("%s.%s".printf (pkg_name, importer.file_extension),
+ import_directories);
+ if (path == null) {
+ continue;
+ }
+
+ path = realpath (path);
+ imported = true;
+
+ if (!processed.contains (path)) {
+ importer.process (path);
+ processed.add (path);
+ }
+ }
+
+ if (imported == false) {
+ reporter.simple_error (null, "'%s' not found in specified import directories", pkg_name);
+ }
+ }
+ }
+}
+
diff --git a/libvaladoc/api/typeparameter.vala b/libvaladoc/api/typeparameter.vala
new file mode 100644
index 000000000..b5f33b860
--- /dev/null
+++ b/libvaladoc/api/typeparameter.vala
@@ -0,0 +1,62 @@
+/* typeparameter.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * Represents a generic type parameter in the source code.
+ */
+public class Valadoc.Api.TypeParameter : Symbol {
+
+ public TypeParameter (Node parent, SourceFile file, string name, void* data) {
+ base (parent, file, name, SymbolAccessibility.PUBLIC, data);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ return new SignatureBuilder ()
+ .append_symbol (this)
+ .get ();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override NodeType node_type { get { return NodeType.TYPE_PARAMETER; } }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void accept (Visitor visitor) {
+ visitor.visit_type_parameter (this);
+ }
+
+ public override bool is_browsable (Settings settings) {
+ return false;
+ }
+
+}
+
diff --git a/libvaladoc/api/typereference.vala b/libvaladoc/api/typereference.vala
new file mode 100644
index 000000000..0d5bffc1f
--- /dev/null
+++ b/libvaladoc/api/typereference.vala
@@ -0,0 +1,168 @@
+/* typereference.vala
+ *
+ * Copyright (C) 2008-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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+/**
+ * A reference to a data type.
+ */
+public class Valadoc.Api.TypeReference : Item {
+ private ArrayList<TypeReference> type_arguments = new ArrayList<TypeReference> ();
+ private string? dbus_type_signature;
+ private Ownership ownership;
+
+ public TypeReference (Item parent, Ownership ownership, bool pass_ownership, bool is_dynamic,
+ bool is_nullable, string? dbus_type_signature, void* data)
+ {
+ base (data);
+
+ this.dbus_type_signature = dbus_type_signature;
+ this.pass_ownership = pass_ownership;
+ this.is_nullable = is_nullable;
+ this.is_dynamic = is_dynamic;
+ this.ownership = ownership;
+ this.parent = parent;
+ }
+
+ /**
+ * Returns a copy of the list of generic type arguments.
+ *
+ * @return type argument list
+ */
+ public Gee.Collection<TypeReference> get_type_arguments () {
+ return this.type_arguments.read_only_view;
+ }
+
+ public void add_type_argument (TypeReference type_ref) {
+ type_arguments.add (type_ref);
+ }
+
+ /**
+ * The referred data type.
+ */
+ public Item? data_type {
+ set;
+ get;
+ }
+
+ public bool pass_ownership {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies that the expression is owned.
+ */
+ public bool is_owned {
+ get {
+ return ownership == Ownership.OWNED;
+ }
+ }
+
+ /**
+ * Specifies that the expression is weak.
+ */
+ public bool is_weak {
+ get {
+ return ownership == Ownership.WEAK;
+ }
+ }
+
+ /**
+ * Specifies that the expression is unwoned.
+ */
+ public bool is_unowned {
+ get {
+ return ownership == Ownership.UNOWNED;
+ }
+ }
+
+
+ /**
+ * Specifies that the expression is dynamic.
+ */
+ public bool is_dynamic {
+ private set;
+ get;
+ }
+
+ /**
+ * Specifies that the expression may be null.
+ */
+ public bool is_nullable {
+ private set;
+ get;
+ }
+
+ public string? get_dbus_type_signature () {
+ return dbus_type_signature;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected override Inline build_signature () {
+ var signature = new SignatureBuilder ();
+
+ if (is_dynamic) {
+ signature.append_keyword ("dynamic");
+ }
+
+ if (is_weak) {
+ signature.append_keyword ("weak");
+ } else if (is_owned) {
+ signature.append_keyword ("owned");
+ } else if (is_unowned) {
+ signature.append_keyword ("unowned");
+ }
+
+ if (data_type == null) {
+ signature.append_keyword ("void");
+ } else if (data_type is Symbol) {
+ signature.append_type ((Symbol) data_type);
+ } else {
+ signature.append_content (data_type.signature);
+ }
+
+ if (type_arguments.size > 0) {
+ signature.append ("<", false);
+ bool first = true;
+ foreach (Item param in type_arguments) {
+ if (!first) {
+ signature.append (",", false);
+ }
+ signature.append_content (param.signature, false);
+ first = false;
+ }
+ signature.append (">", false);
+ }
+
+ if (is_nullable) {
+ signature.append ("?", false);
+ }
+
+ return signature.get ();
+ }
+}
+
diff --git a/libvaladoc/api/typesymbol.vala b/libvaladoc/api/typesymbol.vala
new file mode 100644
index 000000000..3574688e6
--- /dev/null
+++ b/libvaladoc/api/typesymbol.vala
@@ -0,0 +1,114 @@
+/* typesymbol.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+/**
+ * Represents a runtime data type.
+ */
+public abstract class Valadoc.Api.TypeSymbol : Symbol {
+ private SourceComment? source_comment;
+ private string? type_macro_name;
+ private string? is_type_macro_name;
+ private string? type_cast_macro_name;
+ private string? type_function_name;
+
+ public TypeSymbol (Node parent, SourceFile file, string name, SymbolAccessibility accessibility,
+ SourceComment? comment, string? type_macro_name, string? is_type_macro_name,
+ string? type_cast_macro_name, string? type_function_name, bool is_basic_type,
+ void* data)
+ {
+ base (parent, file, name, accessibility, data);
+
+ this.type_cast_macro_name = type_cast_macro_name;
+ this.is_type_macro_name = is_type_macro_name;
+ this.type_function_name = type_function_name;
+ this.type_macro_name = type_macro_name;
+
+ this.is_basic_type = is_basic_type;
+ this.source_comment = comment;
+ }
+
+ /**
+ * Specifies whether this symbol is a basic type (string, int, char, etc)
+ */
+ public bool is_basic_type {
+ private set;
+ get;
+ }
+
+ /**
+ * Gets the name of the GType macro which represents the type symbol
+ */
+ public string get_type_macro_name () {
+ return type_macro_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which casts a type instance to the given type.
+ */
+ public string get_type_cast_macro_name () {
+ return type_cast_macro_name;
+ }
+
+ /**
+ * Gets the name of the GType macro which determines whether a type instance is of a given type.
+ */
+ public string get_is_type_macro_name () {
+ return is_type_macro_name;
+ }
+
+ /**
+ * Gets the name of the get_type() function which represents the type symbol
+ */
+ public string get_type_function_name () {
+ return type_function_name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void parse_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ return ;
+ }
+
+ if (source_comment != null) {
+ documentation = parser.parse (this, source_comment);
+ }
+
+ base.parse_comments (settings, parser);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ internal override void check_comments (Settings settings, DocumentationParser parser) {
+ if (documentation != null) {
+ parser.check (this, documentation);
+ }
+
+ base.check_comments (settings, parser);
+ }
+}
diff --git a/libvaladoc/api/visitor.vala b/libvaladoc/api/visitor.vala
new file mode 100644
index 000000000..bf66a456b
--- /dev/null
+++ b/libvaladoc/api/visitor.vala
@@ -0,0 +1,171 @@
+/* visitor.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+
+/**
+ * Abstract visitor for traversing API.
+ */
+public abstract class Valadoc.Api.Visitor : GLib.Object {
+ /**
+ * Visit operation called for api trees.
+ *
+ * @param item a tree
+ */
+ public virtual void visit_tree (Tree item) {
+ }
+
+ /**
+ * Visit operation called for packages like gir-files and vapi-files.
+ *
+ * @param item a package
+ */
+ public virtual void visit_package (Package item) {
+ }
+
+ /**
+ * Visit operation called for namespaces
+ *
+ * @param item a namespace
+ */
+ public virtual void visit_namespace (Namespace item) {
+ }
+
+ /**
+ * Visit operation called for interfaces.
+ *
+ * @param item a interface
+ */
+ public virtual void visit_interface (Interface item) {
+ }
+
+ /**
+ * Visit operation called for classes.
+ *
+ * @param item a class
+ */
+ public virtual void visit_class (Class item) {
+ }
+
+ /**
+ * Visit operation called for structs.
+ *
+ * @param item a struct
+ */
+ public virtual void visit_struct (Struct item) {
+ }
+
+ /**
+ * Visit operation called for properties.
+ *
+ * @param item a property
+ */
+ public virtual void visit_property (Property item) {
+ }
+
+ /**
+ * Visit operation called for fields.
+ *
+ * @param item a field
+ */
+ public virtual void visit_field (Field item) {
+ }
+
+ /**
+ * Visit operation called for constants.
+ *
+ * @param item a constant
+ */
+ public virtual void visit_constant (Constant item) {
+ }
+
+ /**
+ * Visit operation called for delegates.
+ *
+ * @param item a delegate
+ */
+ public virtual void visit_delegate (Delegate item) {
+ }
+
+ /**
+ * Visit operation called for signals.
+ *
+ * @param item a signal
+ */
+ public virtual void visit_signal (Signal item) {
+ }
+
+ /**
+ * Visit operation called for methods.
+ *
+ * @param item a method
+ */
+ public virtual void visit_method (Method item) {
+ }
+
+ /**
+ * Visit operation called for type parameters.
+ *
+ * @param item a type parameter
+ */
+ public virtual void visit_type_parameter (TypeParameter item) {
+ }
+
+ /**
+ * Visit operation called for formal parameters.
+ *
+ * @param item a formal parameter
+ */
+ public virtual void visit_formal_parameter (FormalParameter item) {
+ }
+
+ /**
+ * Visit operation called for error domains.
+ *
+ * @param item a error domain
+ */
+ public virtual void visit_error_domain (ErrorDomain item) {
+ }
+
+ /**
+ * Visit operation called for error codes.
+ *
+ * @param item a error code
+ */
+ public virtual void visit_error_code (ErrorCode item) {
+ }
+
+ /**
+ * Visit operation called for enums.
+ *
+ * @param item a enum
+ */
+ public virtual void visit_enum (Enum item) {
+ }
+
+ /**
+ * Visit operation called for enum values.
+ *
+ * @param item a enum value
+ */
+ public virtual void visit_enum_value (EnumValue item) {
+ }
+}
diff --git a/libvaladoc/charts/chart.vala b/libvaladoc/charts/chart.vala
new file mode 100644
index 000000000..a6307d7ff
--- /dev/null
+++ b/libvaladoc/charts/chart.vala
@@ -0,0 +1,73 @@
+/* chart.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+
+public class Valadoc.Charts.Chart : Api.Visitor {
+ protected Gvc.Context context;
+ protected Gvc.Graph graph;
+ protected Factory factory;
+
+ static construct {
+ #if !WITH_CGRAPH
+ Gvc.init ();
+ #endif
+ }
+
+ public Chart (Factory factory, Api.Node node) {
+ graph = factory.create_graph (node);
+ this.factory = factory;
+ node.accept (this);
+ }
+
+ public void save (string file_name, string file_type = "png") {
+ if (context == null) {
+ context = factory.create_context (graph);
+ }
+ context.render_filename (graph, file_type, file_name);
+ }
+
+ public void write (GLib.FileStream file, string file_type) {
+ if (context == null) {
+ context = factory.create_context (graph);
+ }
+ context.render (graph, file_type, file);
+ }
+
+ public uint8[]? write_buffer (string file_type) {
+ if (context == null) {
+ context = factory.create_context (graph);
+ }
+
+ uint8[]? data;
+
+ /* This will return null in data if it fails. */
+ context.render_data (graph, file_type, out data);
+ return data;
+ }
+
+ ~Chart () {
+ if (context != null) {
+ context.free_layout (graph);
+ }
+ }
+}
+
diff --git a/libvaladoc/charts/chartfactory.vala b/libvaladoc/charts/chartfactory.vala
new file mode 100644
index 000000000..c2582ab9f
--- /dev/null
+++ b/libvaladoc/charts/chartfactory.vala
@@ -0,0 +1,53 @@
+/* chartfactory.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+
+public abstract class Valadoc.Charts.Factory : Object {
+ protected Gvc.Node create_type (Gvc.Graph graph, Api.Node item) {
+ #if WITH_CGRAPH
+ return graph.create_node (item.get_full_name (), 1);
+ #else
+ return graph.create_node (item.get_full_name ());
+ #endif
+ }
+
+ public abstract Gvc.Graph create_graph (Api.Node item);
+
+ public abstract Gvc.Context create_context (Gvc.Graph graph);
+
+ public abstract Gvc.Node create_class (Gvc.Graph graph, Api.Class item);
+
+ public abstract Gvc.Node create_struct (Gvc.Graph graph, Api.Struct item);
+
+ public abstract Gvc.Node create_interface (Gvc.Graph graph, Api.Interface item);
+
+ public abstract Gvc.Node create_enum (Gvc.Graph graph, Api.Enum item);
+
+ public abstract Gvc.Node create_delegate (Gvc.Graph graph, Api.Delegate item);
+
+ public abstract Gvc.Node create_errordomain (Gvc.Graph graph, Api.ErrorDomain item);
+
+ public abstract Gvc.Node create_namespace (Gvc.Graph graph, Api.Namespace item);
+
+ public abstract Gvc.Edge add_children (Gvc.Graph graph, Gvc.Node parent, Gvc.Node child);
+}
+
diff --git a/libvaladoc/charts/hierarchychart.vala b/libvaladoc/charts/hierarchychart.vala
new file mode 100644
index 000000000..ce3613488
--- /dev/null
+++ b/libvaladoc/charts/hierarchychart.vala
@@ -0,0 +1,82 @@
+/* hierarchychart.vala
+ *
+ * Copyright (C) 2008 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 Gee;
+
+
+public class Valadoc.Charts.Hierarchy : Charts.Chart {
+ public Hierarchy (Factory factory, Api.Node node) {
+ base (factory, node);
+ }
+
+ private void draw_implemented_interfaces (Gvc.Node child, Collection<Api.TypeReference> interfaces) {
+ foreach (Api.TypeReference typeref in interfaces) {
+ var parent = factory.create_interface (graph, (Api.Interface) typeref.data_type);
+ factory.add_children (graph, parent, child);
+ }
+ }
+
+ private void draw_parent_classes (Api.Class item, Gvc.Node? child = null) {
+ var parent = factory.create_class (graph, item);
+
+ if (child != null) {
+ factory.add_children (graph, parent, child);
+ }
+
+ if (item.base_type != null) {
+ draw_parent_classes ((Api.Class) item.base_type.data_type, parent);
+ }
+
+ draw_implemented_interfaces (parent, item.get_implemented_interface_list ());
+ }
+
+ private void draw_parent_structs (Api.Struct item, Gvc.Node? child = null) {
+ var parent = factory.create_struct (graph, item);
+
+ if (child != null) {
+ factory.add_children (graph, parent, child);
+ }
+
+ if (item.base_type != null) {
+ draw_parent_structs ((Api.Struct) item.base_type.data_type, parent);
+ }
+ }
+
+ public override void visit_interface (Api.Interface item) {
+ var iface = factory.create_interface (graph, item);
+
+ if (item.base_type != null) {
+ draw_parent_classes ((Api.Class) item.base_type.data_type, iface);
+ }
+
+ draw_implemented_interfaces (iface, item.get_implemented_interface_list ());
+ }
+
+ public override void visit_class (Api.Class item) {
+ draw_parent_classes (item);
+ }
+
+ public override void visit_struct (Api.Struct item) {
+ draw_parent_structs (item);
+ }
+}
+
diff --git a/libvaladoc/charts/simplechartfactory.vala b/libvaladoc/charts/simplechartfactory.vala
new file mode 100644
index 000000000..06da97e13
--- /dev/null
+++ b/libvaladoc/charts/simplechartfactory.vala
@@ -0,0 +1,87 @@
+/* simplechartfactory.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+
+
+public class Valadoc.Charts.SimpleFactory : Charts.Factory {
+ protected virtual Gvc.Node configure_type (Gvc.Node node, Api.Node item) {
+ node.safe_set ("shape", "box", "");
+ node.safe_set ("fontname", "Times", "");
+ node.safe_set ("label", item.get_full_name (), "");
+ return node;
+ }
+
+ public override Gvc.Graph create_graph (Api.Node item) {
+ #if WITH_CGRAPH
+ var graph = new Gvc.Graph (item.get_full_name (), Gvc.Agdirected, 0);
+ #else
+ var graph = new Gvc.Graph (item.get_full_name (), Gvc.GraphKind.AGDIGRAPH);
+ #endif
+ return graph;
+ }
+
+ public override Gvc.Context create_context (Gvc.Graph graph) {
+ var context = new Gvc.Context ();
+ context.layout_jobs (graph);
+ context.layout (graph, "dot");
+ return context;
+ }
+
+ public override Gvc.Node create_class (Gvc.Graph graph, Api.Class item) {
+ var node = configure_type (create_type (graph, item), item);
+ node.safe_set ("style", "bold", "");
+ return node;
+ }
+
+ public override Gvc.Node create_struct (Gvc.Graph graph, Api.Struct item) {
+ var node = configure_type (create_type (graph, item), item);
+ node.safe_set ("style", "bold", "");
+ return node;
+ }
+
+ public override Gvc.Node create_interface (Gvc.Graph graph, Api.Interface item) {
+ return configure_type (create_type (graph, item), item);
+ }
+
+ public override Gvc.Node create_enum (Gvc.Graph graph, Api.Enum item) {
+ return configure_type (create_type (graph, item), item);
+ }
+
+ public override Gvc.Node create_delegate (Gvc.Graph graph, Api.Delegate item) {
+ return configure_type (create_type (graph, item), item);
+ }
+
+ public override Gvc.Node create_errordomain (Gvc.Graph graph, Api.ErrorDomain item) {
+ return configure_type (create_type (graph, item), item);
+ }
+
+ public override Gvc.Node create_namespace (Gvc.Graph graph, Api.Namespace item) {
+ return configure_type (create_type (graph, item), item);
+ }
+
+ public override Gvc.Edge add_children (Gvc.Graph graph, Gvc.Node parent, Gvc.Node child) {
+ var edge = graph.create_edge (parent, child);
+ edge.safe_set ("dir", "back", "");
+ return edge;
+ }
+}
+
diff --git a/libvaladoc/content/block.vala b/libvaladoc/content/block.vala
new file mode 100644
index 000000000..99273aee1
--- /dev/null
+++ b/libvaladoc/content/block.vala
@@ -0,0 +1,25 @@
+/* block.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+public interface Valadoc.Content.Block : ContentElement {
+}
+
diff --git a/libvaladoc/content/blockcontent.vala b/libvaladoc/content/blockcontent.vala
new file mode 100644
index 000000000..47e99a217
--- /dev/null
+++ b/libvaladoc/content/blockcontent.vala
@@ -0,0 +1,66 @@
+/* blockcontent.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public abstract class Valadoc.Content.BlockContent : ContentElement {
+ public Gee.List<Block> content { get { return _content; } }
+
+ private Gee.List<Block> _content;
+
+ construct {
+ _content = new ArrayList<Block> ();
+ }
+
+ internal BlockContent () {
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ foreach (Block element in _content) {
+ element.parent = this;
+ element.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ foreach (Block element in _content) {
+ element.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ foreach (Block item in content) {
+ if (!item.is_empty ()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
diff --git a/libvaladoc/content/comment.vala b/libvaladoc/content/comment.vala
new file mode 100644
index 000000000..f4ba4a09f
--- /dev/null
+++ b/libvaladoc/content/comment.vala
@@ -0,0 +1,106 @@
+/* comment.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Valadoc.Taglets;
+using Gee;
+
+
+public class Valadoc.Content.Comment : BlockContent {
+ public Gee.List<Taglet> taglets { get { return _taglets; } }
+ private Gee.List<Taglet> _taglets;
+
+ private bool checked = false;
+
+
+ internal Comment () {
+ base ();
+ _taglets = new ArrayList<Taglet> ();
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ if (checked == true) {
+ return ;
+ }
+
+ checked = true;
+
+
+ base.check (api_root, container, file_path, reporter, settings);
+
+ foreach (Taglet element in _taglets) {
+ element.parent = this;
+ element.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_comment (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ base.accept_children (visitor);
+
+ foreach (Taglet element in _taglets) {
+ element.accept (visitor);
+ }
+ }
+
+ public Gee.List<Taglet> find_taglets (Api.Node? container, Type taglet_type) {
+ Gee.List<Taglet> selected_taglets = new ArrayList<Taglet> ();
+
+ // TODO inherit stuff if needed
+
+ foreach (Taglet taglet in _taglets) {
+ if (taglet.get_type () == taglet_type) {
+ selected_taglets.add (taglet);
+ }
+ }
+
+ return selected_taglets;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ assert (new_parent == null);
+
+ Comment comment = new Comment ();
+ comment.parent = new_parent;
+
+ foreach (Block element in content) {
+ Block copy = element.copy (comment) as Block;
+ comment.content.add (copy);
+ }
+
+ foreach (Taglet taglet in _taglets) {
+ Taglet copy = taglet.copy (comment) as Taglet;
+ comment.taglets.add (copy);
+ }
+
+ return comment;
+ }
+}
+
diff --git a/libvaladoc/content/contentelement.vala b/libvaladoc/content/contentelement.vala
new file mode 100644
index 000000000..6e2c65934
--- /dev/null
+++ b/libvaladoc/content/contentelement.vala
@@ -0,0 +1,46 @@
+/* contentelement.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+
+
+public abstract class Valadoc.Content.ContentElement : Object {
+ public ContentElement parent { get; internal set; }
+
+ public abstract ContentElement copy (ContentElement? new_parent = null);
+
+
+ public virtual void configure (Settings settings, ResourceLocator locator) {
+ }
+
+ public abstract void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings);
+
+ public abstract void accept (ContentVisitor visitor);
+
+ public abstract bool is_empty ();
+
+ public virtual void accept_children (ContentVisitor visitor) {
+ }
+}
+
diff --git a/libvaladoc/content/contentfactory.vala b/libvaladoc/content/contentfactory.vala
new file mode 100644
index 000000000..dda8a8763
--- /dev/null
+++ b/libvaladoc/content/contentfactory.vala
@@ -0,0 +1,124 @@
+/* contentfactory.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.ContentFactory : Object {
+
+ public ContentFactory (Settings settings, ResourceLocator locator, ModuleLoader modules) {
+ _settings = settings;
+ _locator = locator;
+ _modules = modules;
+ }
+
+ private Settings _settings;
+ private ResourceLocator _locator;
+ private ModuleLoader _modules;
+
+ private inline ContentElement configure (ContentElement element) {
+ element.configure (_settings, _locator);
+ return element;
+ }
+
+ public Comment create_comment () {
+ return (Comment) configure (new Comment ());
+ }
+
+ public Embedded create_embedded () {
+ return (Embedded) configure (new Embedded ());
+ }
+
+ public Headline create_headline () {
+ return (Headline) configure (new Headline ());
+ }
+
+ public Link create_link () {
+ return (Link) configure (new Link ());
+ }
+
+ public WikiLink create_wiki_link () {
+ return (WikiLink) configure (new WikiLink ());
+ }
+
+ public List create_list () {
+ return (List) configure (new List ());
+ }
+
+ public ListItem create_list_item () {
+ return (ListItem) configure (new ListItem ());
+ }
+
+ public Page create_page () {
+ return (Page) configure (new Page ());
+ }
+
+ public Paragraph create_paragraph () {
+ return (Paragraph) configure (new Paragraph ());
+ }
+
+ public Warning create_warning () {
+ return (Warning) configure (new Warning ());
+ }
+ public Note create_note () {
+ return (Note) configure (new Note ());
+ }
+
+ public Run create_run (Run.Style style) {
+ return (Run) configure (new Run (style));
+ }
+
+ public SourceCode create_source_code () {
+ return (SourceCode) configure (new SourceCode ());
+ }
+
+ public Table create_table () {
+ return (Table) configure (new Table ());
+ }
+
+ public TableCell create_table_cell () {
+ return (TableCell) configure (new TableCell ());
+ }
+
+ public TableRow create_table_row () {
+ return (TableRow) configure (new TableRow ());
+ }
+
+ public Taglet? create_taglet (string name) {
+ return _modules.create_taglet (name);
+ }
+
+ public Text create_text (string? text = null) {
+ return (Text) configure (new Text (text));
+ }
+
+ public ContentElement set_style_attributes (StyleAttributes element,
+ VerticalAlign? valign,
+ HorizontalAlign? halign,
+ string? style) {
+ element.vertical_align = valign;
+ element.horizontal_align = halign;
+ element.style = style;
+ return element;
+ }
+}
diff --git a/libvaladoc/content/contentrenderer.vala b/libvaladoc/content/contentrenderer.vala
new file mode 100644
index 000000000..153e35deb
--- /dev/null
+++ b/libvaladoc/content/contentrenderer.vala
@@ -0,0 +1,32 @@
+/* contentrenderer.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+
+
+public abstract class Valadoc.Content.ContentRenderer : ContentVisitor {
+
+ public abstract void render (ContentElement element);
+
+ public abstract void render_children (ContentElement element);
+}
+
diff --git a/libvaladoc/content/contentvisitor.vala b/libvaladoc/content/contentvisitor.vala
new file mode 100644
index 000000000..d1b14c453
--- /dev/null
+++ b/libvaladoc/content/contentvisitor.vala
@@ -0,0 +1,86 @@
+/* contentvisitor.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+
+
+public abstract class Valadoc.Content.ContentVisitor : Object {
+
+ public virtual void visit_comment (Comment element) {
+ }
+
+ public virtual void visit_embedded (Embedded element) {
+ }
+
+ public virtual void visit_headline (Headline element) {
+ }
+
+ public virtual void visit_link (Link element) {
+ }
+
+ public virtual void visit_wiki_link (WikiLink element) {
+ }
+
+ public virtual void visit_symbol_link (SymbolLink element) {
+ }
+
+ public virtual void visit_list (List element) {
+ }
+
+ public virtual void visit_list_item (ListItem element) {
+ }
+
+ public virtual void visit_paragraph (Paragraph element) {
+ }
+
+ public virtual void visit_warning (Warning element) {
+ }
+
+ public virtual void visit_note (Note element) {
+ }
+
+ public virtual void visit_page (Page element) {
+ }
+
+ public virtual void visit_run (Run element) {
+ }
+
+ public virtual void visit_source_code (SourceCode element) {
+ }
+
+ public virtual void visit_table (Table element) {
+ }
+
+ public virtual void visit_table_cell (TableCell element) {
+ }
+
+ public virtual void visit_table_row (TableRow element) {
+ }
+
+ public virtual void visit_taglet (Taglet element) {
+ }
+
+ public virtual void visit_text (Text element) {
+ }
+}
+
diff --git a/libvaladoc/content/embedded.vala b/libvaladoc/content/embedded.vala
new file mode 100644
index 000000000..b1d7d9525
--- /dev/null
+++ b/libvaladoc/content/embedded.vala
@@ -0,0 +1,125 @@
+/* embedded.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Embedded : ContentElement, Inline, StyleAttributes {
+ public string url {
+ get;
+ set;
+ }
+
+ public string? caption {
+ get;
+ set;
+ }
+
+ public HorizontalAlign? horizontal_align {
+ get;
+ set;
+ }
+
+ public VerticalAlign? vertical_align {
+ get;
+ set;
+ }
+
+ public string? style {
+ get;
+ set;
+ }
+
+ public Api.Package package;
+
+ private ResourceLocator _locator;
+
+ internal Embedded () {
+ base ();
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ _locator = locator;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // search relative to our file
+ if (!Path.is_absolute (url)) {
+ string relative_to_file = Path.build_path (Path.DIR_SEPARATOR_S,
+ Path.get_dirname (file_path),
+ url);
+ if (FileUtils.test (relative_to_file, FileTest.EXISTS | FileTest.IS_REGULAR)) {
+ url = (owned) relative_to_file;
+ package = container.package;
+ return ;
+ }
+ }
+
+ // search relative to the current directory / absoulte path
+ if (!FileUtils.test (url, FileTest.EXISTS | FileTest.IS_REGULAR)) {
+ string base_name = Path.get_basename (url);
+
+ foreach (unowned string dir in settings.alternative_resource_dirs) {
+ string alternative_path = Path.build_path (Path.DIR_SEPARATOR_S,
+ dir,
+ base_name);
+ if (FileUtils.test (alternative_path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
+ url = (owned) alternative_path;
+ package = container.package;
+ return ;
+ }
+ }
+
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_error ("%s: %s{{".printf (file_path, node_segment),
+ "'%s' does not exist", url);
+ } else {
+ package = container.package;
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_embedded (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Embedded embedded = new Embedded ();
+ embedded.parent = new_parent;
+
+ embedded.horizontal_align = horizontal_align;
+ embedded.vertical_align = vertical_align;
+ embedded._locator = _locator;
+ embedded.caption = caption;
+ embedded.package = package;
+ embedded.style = style;
+ embedded.url = url;
+
+ return embedded;
+ }
+}
diff --git a/libvaladoc/content/headline.vala b/libvaladoc/content/headline.vala
new file mode 100644
index 000000000..56a4a443e
--- /dev/null
+++ b/libvaladoc/content/headline.vala
@@ -0,0 +1,66 @@
+/* headline.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Headline : InlineContent, Block {
+ public int level { get; set; }
+
+ internal Headline () {
+ base ();
+ _level = 0;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // TODO report error if level == 0 ?
+ // TODO: content.size == 0?
+
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_headline (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Headline headline = new Headline ();
+ headline.parent = new_parent;
+ headline.level = level;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (headline) as Inline;
+ headline.content.add (copy);
+ }
+
+ return headline;
+ }
+}
+
diff --git a/libvaladoc/content/inline.vala b/libvaladoc/content/inline.vala
new file mode 100644
index 000000000..3a6af7564
--- /dev/null
+++ b/libvaladoc/content/inline.vala
@@ -0,0 +1,25 @@
+/* inline.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+
+public interface Valadoc.Content.Inline : ContentElement {
+}
diff --git a/libvaladoc/content/inlinecontent.vala b/libvaladoc/content/inlinecontent.vala
new file mode 100644
index 000000000..f67ee4e1a
--- /dev/null
+++ b/libvaladoc/content/inlinecontent.vala
@@ -0,0 +1,75 @@
+/* inlinecontent.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public abstract class Valadoc.Content.InlineContent : ContentElement {
+ public Gee.List<Inline> content {
+ get {
+ return _content;
+ }
+ }
+
+ private Gee.List<Inline> _content;
+
+ construct {
+ _content = new ArrayList<Inline> ();
+ }
+
+ internal InlineContent () {
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ foreach (Inline element in _content) {
+ element.parent = this;
+ element.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ foreach (Inline element in _content) {
+ element.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ foreach (Inline item in content) {
+ if (!item.is_empty ()) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ internal void replace_node (Inline old, Inline replacement) {
+ int index = _content.index_of (old);
+ assert (index >= 0);
+
+ _content.set (index, replacement);
+ }
+}
+
diff --git a/libvaladoc/content/inlinetaglet.vala b/libvaladoc/content/inlinetaglet.vala
new file mode 100644
index 000000000..812eab39a
--- /dev/null
+++ b/libvaladoc/content/inlinetaglet.vala
@@ -0,0 +1,71 @@
+/* taglet.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public abstract class Valadoc.Content.InlineTaglet : ContentElement, Taglet, Inline {
+ protected Settings settings;
+ protected ResourceLocator locator;
+ private ContentElement _content;
+
+ public InlineTaglet () {
+ base ();
+ }
+
+ public abstract Rule? get_parser_rule (Rule run_rule);
+
+ public abstract ContentElement produce_content ();
+
+ private ContentElement get_content () {
+ if (_content == null) {
+ _content = produce_content ();
+ }
+ return _content;
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ this.settings = settings;
+ this.locator = locator;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ ContentElement element = get_content ();
+ element.parent = this;
+
+ element.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ ContentElement element = get_content ();
+ element.accept (visitor);
+ }
+
+ public override bool is_empty () {
+ // taglets are not empty by default
+ return false;
+ }
+}
+
diff --git a/libvaladoc/content/link.vala b/libvaladoc/content/link.vala
new file mode 100644
index 000000000..ba641e7e5
--- /dev/null
+++ b/libvaladoc/content/link.vala
@@ -0,0 +1,115 @@
+/* link.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2014 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Link : InlineContent, Inline {
+ public string url {
+ set;
+ get;
+ }
+
+ /**
+ * Used by importers to transform internal URLs
+ */
+ public Importer.InternalIdRegistrar id_registrar {
+ internal set;
+ get;
+ }
+
+
+ internal Link () {
+ base ();
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+
+ // Internal gktdoc-id? (gir-importer)
+ if (id_registrar != null) {
+ Api.Node? node = id_registrar.map_symbol_id (url);
+ if (node != null) {
+ InlineContent _parent = parent as InlineContent;
+ assert (_parent != null);
+
+ SymbolLink replacement = new SymbolLink (node);
+ replacement.content.add_all (content);
+
+ replacement.check (api_root, container, file_path, reporter, settings);
+ _parent.replace_node (this, replacement);
+ return ;
+ }
+
+
+ string _url = id_registrar.map_url_id (url);
+ if (_url == null) {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_warning ("%s: %s[[".printf (file_path, node_segment),
+ "unknown imported internal id '%s'", url);
+
+ InlineContent _parent = parent as InlineContent;
+ assert (_parent != null);
+
+ Run replacement = new Run (Run.Style.ITALIC);
+ replacement.content.add_all (content);
+ replacement.check (api_root, container, file_path, reporter, settings);
+
+ _parent.replace_node (this, replacement);
+ return ;
+ }
+
+ url = _url;
+ }
+
+
+ //TODO: check url
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_link (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Link link = new Link ();
+ link.id_registrar = id_registrar;
+ link.parent = new_parent;
+ link.url = url;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (link) as Inline;
+ link.content.add (copy);
+ }
+
+ return link;
+ }
+}
diff --git a/libvaladoc/content/list.vala b/libvaladoc/content/list.vala
new file mode 100644
index 000000000..b23452648
--- /dev/null
+++ b/libvaladoc/content/list.vala
@@ -0,0 +1,156 @@
+/* list.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.List : ContentElement, Block {
+ public enum Bullet {
+ NONE,
+ UNORDERED,
+ ORDERED,
+ ORDERED_NUMBER,
+ ORDERED_LOWER_CASE_ALPHA,
+ ORDERED_UPPER_CASE_ALPHA,
+ ORDERED_LOWER_CASE_ROMAN,
+ ORDERED_UPPER_CASE_ROMAN;
+
+ public static Bullet? from_string (string? str) {
+ switch (str) {
+ case "none":
+ return Bullet.NONE;
+
+ case "unordered":
+ return Bullet.UNORDERED;
+
+ case "ordered":
+ return Bullet.ORDERED;
+
+ case "ordered-number":
+ return Bullet.ORDERED_NUMBER;
+
+ case "ordered-lower-case-alpa":
+ return Bullet.ORDERED_LOWER_CASE_ALPHA;
+
+ case "ordered-upper-case-alpha":
+ return Bullet.ORDERED_UPPER_CASE_ALPHA;
+
+ case "ordered-lower-case-roman":
+ return Bullet.ORDERED_LOWER_CASE_ROMAN;
+
+ case "ordered-upper-case-roman":
+ return Bullet.ORDERED_UPPER_CASE_ROMAN;
+ }
+
+ return null;
+ }
+
+ public unowned string to_string () {
+ switch (this) {
+ case Bullet.NONE:
+ return "none";
+
+ case Bullet.UNORDERED:
+ return "unordered";
+
+ case Bullet.ORDERED:
+ return "ordered";
+
+ case Bullet.ORDERED_NUMBER:
+ return "ordered-number";
+
+ case Bullet.ORDERED_LOWER_CASE_ALPHA:
+ return "ordered-lower-case-alpa";
+
+ case Bullet.ORDERED_UPPER_CASE_ALPHA:
+ return "ordered-upper-case-alpha";
+
+ case Bullet.ORDERED_LOWER_CASE_ROMAN:
+ return "ordered-lower-case-roman";
+
+ case Bullet.ORDERED_UPPER_CASE_ROMAN:
+ return "ordered-upper-case-roman";
+ }
+
+ assert (true);
+ return "";
+ }
+ }
+
+ public Bullet bullet {
+ get;
+ set;
+ }
+
+ // TODO add initial value (either a number or some letters)
+ public Gee.List<ListItem> items {
+ get {
+ return _items;
+ }
+ }
+
+ private Gee.List<ListItem> _items;
+
+ internal List () {
+ base ();
+ _bullet = Bullet.NONE;
+ _items = new ArrayList<ListItem> ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check individual list items
+ foreach (ListItem element in _items) {
+ element.parent = this;
+ element.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_list (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ foreach (ListItem element in _items) {
+ element.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ return _items.size == 0;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Content.List list = new Content.List ();
+ list.parent = new_parent;
+ list.bullet = bullet;
+
+ foreach (ListItem item in items) {
+ ListItem copy = item.copy (list) as ListItem;
+ list.items.add (copy);
+ }
+
+ return list;
+ }
+}
diff --git a/libvaladoc/content/listitem.vala b/libvaladoc/content/listitem.vala
new file mode 100644
index 000000000..299ce4e4e
--- /dev/null
+++ b/libvaladoc/content/listitem.vala
@@ -0,0 +1,59 @@
+/* listitem.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.ListItem : BlockContent {
+
+ internal ListItem () {
+ base ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check block content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_list_item (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ base.accept_children (visitor);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ ListItem item = new ListItem ();
+ item.parent = new_parent;
+
+ foreach (Block block in content) {
+ Block copy = block.copy (item) as Block;
+ item.content.add (copy);
+ }
+
+ return item;
+ }
+}
diff --git a/libvaladoc/content/note.vala b/libvaladoc/content/note.vala
new file mode 100644
index 000000000..d35347e05
--- /dev/null
+++ b/libvaladoc/content/note.vala
@@ -0,0 +1,55 @@
+/* note.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Note : BlockContent, Block {
+ internal Note () {
+ base ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_note (this);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Note note = new Note ();
+ note.parent = new_parent;
+
+ foreach (Block block in content) {
+ Block copy = block.copy (note) as Block;
+ note.content.add (copy);
+ }
+
+ return note;
+ }
+}
+
diff --git a/libvaladoc/content/page.vala b/libvaladoc/content/page.vala
new file mode 100644
index 000000000..f180be84f
--- /dev/null
+++ b/libvaladoc/content/page.vala
@@ -0,0 +1,65 @@
+/* page.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Page : BlockContent {
+ private bool checked = false;
+
+
+ internal Page () {
+ base ();
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_page (this);
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ if (checked == true) {
+ return ;
+ }
+
+ checked = true;
+
+
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ assert (new_parent == null);
+
+ Content.Page page = new Content.Page ();
+ page.parent = new_parent;
+
+ foreach (Block block in content) {
+ Block copy = block.copy (page) as Block;
+ page.content.add (copy);
+ }
+
+ return page;
+ }
+}
+
diff --git a/libvaladoc/content/paragraph.vala b/libvaladoc/content/paragraph.vala
new file mode 100644
index 000000000..6d474b940
--- /dev/null
+++ b/libvaladoc/content/paragraph.vala
@@ -0,0 +1,74 @@
+/* paragraph.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Paragraph : InlineContent, Block, StyleAttributes {
+ public HorizontalAlign? horizontal_align {
+ get;
+ set;
+ }
+
+ public VerticalAlign? vertical_align {
+ get;
+ set;
+ }
+
+ public string? style {
+ get;
+ set;
+ }
+
+ internal Paragraph () {
+ base ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_paragraph (this);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Paragraph p = new Paragraph ();
+ p.parent = new_parent;
+
+ p.horizontal_align = horizontal_align;
+ p.vertical_align = vertical_align;
+ p.style = style;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (p) as Inline;
+ p.content.add (copy);
+ }
+
+ return p;
+ }
+}
+
diff --git a/libvaladoc/content/resourcelocator.vala b/libvaladoc/content/resourcelocator.vala
new file mode 100644
index 000000000..beffdfd0e
--- /dev/null
+++ b/libvaladoc/content/resourcelocator.vala
@@ -0,0 +1,29 @@
+/* resourcelocator.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+
+
+public interface Valadoc.ResourceLocator : Object {
+ public abstract string resolve (string path);
+}
+
diff --git a/libvaladoc/content/run.vala b/libvaladoc/content/run.vala
new file mode 100644
index 000000000..01eace6b2
--- /dev/null
+++ b/libvaladoc/content/run.vala
@@ -0,0 +1,208 @@
+/* run.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Run : InlineContent, Inline {
+ public enum Style {
+ NONE,
+ BOLD,
+ ITALIC,
+ UNDERLINED,
+ MONOSPACED,
+ STROKE,
+ LANG_KEYWORD,
+ LANG_LITERAL,
+ LANG_BASIC_TYPE,
+ LANG_TYPE,
+ LANG_PREPROCESSOR,
+ LANG_COMMENT,
+ LANG_ESCAPE,
+
+ XML_ESCAPE,
+ XML_ELEMENT,
+ XML_ATTRIBUTE,
+ XML_ATTRIBUTE_VALUE,
+ XML_COMMENT,
+ XML_CDATA;
+
+ public static Style? from_string (string str) {
+ switch (str) {
+ case "none":
+ return Style.NONE;
+
+ case "bold":
+ return Style.BOLD;
+
+ case "italic":
+ return Style.ITALIC;
+
+ case "underlined":
+ return Style.UNDERLINED;
+
+ case "monospaced":
+ return Style.MONOSPACED;
+
+ case "stroke":
+ return Style.STROKE;
+
+ case "lang-escape":
+ return Style.LANG_ESCAPE;
+
+ case "lang-keyword":
+ return Style.LANG_KEYWORD;
+
+ case "lang-literal":
+ return Style.LANG_LITERAL;
+
+ case "lang-basic-type":
+ return Style.LANG_BASIC_TYPE;
+
+ case "lang-type":
+ return Style.LANG_TYPE;
+
+ case "lang-preprocessor":
+ return Style.LANG_PREPROCESSOR;
+
+ case "lang-comment":
+ return Style.LANG_COMMENT;
+
+ case "xml-escape":
+ return Style.XML_ESCAPE;
+
+ case "xml-element":
+ return Style.XML_ELEMENT;
+
+ case "xml-attribute":
+ return Style.XML_ATTRIBUTE;
+
+ case "xml-attribute-value":
+ return Style.XML_ATTRIBUTE_VALUE;
+
+ case "xml-comment":
+ return Style.XML_COMMENT;
+
+ case "xml-cdata":
+ return Style.XML_CDATA;
+ }
+
+ return null;
+ }
+
+ public unowned string to_string () {
+ switch (this) {
+ case Style.NONE:
+ return "none";
+
+ case Style.BOLD:
+ return "bold";
+
+ case Style.ITALIC:
+ return "italic";
+
+ case Style.UNDERLINED:
+ return "underlined";
+
+ case Style.MONOSPACED:
+ return "monospaced";
+
+ case Style.STROKE:
+ return "stroke";
+
+ case Style.LANG_ESCAPE:
+ return "lang-escape";
+
+ case Style.LANG_KEYWORD:
+ return "lang-keyword";
+
+ case Style.LANG_LITERAL:
+ return "lang-literal";
+
+ case Style.LANG_BASIC_TYPE:
+ return "lang-basic-type";
+
+ case Style.LANG_TYPE:
+ return "lang-type";
+
+ case Style.LANG_PREPROCESSOR:
+ return "lang-preprocessor";
+
+ case Style.LANG_COMMENT:
+ return "lang-comment";
+
+ case Style.XML_ESCAPE:
+ return "xml-escape";
+
+ case Style.XML_ELEMENT:
+ return "xml-element";
+
+ case Style.XML_ATTRIBUTE:
+ return "xml-attribute";
+
+ case Style.XML_ATTRIBUTE_VALUE:
+ return "xml-attribute-value";
+
+ case Style.XML_COMMENT:
+ return "xml-comment";
+
+ case Style.XML_CDATA:
+ return "xml-cdata";
+ }
+
+ assert (true);
+ return "";
+ }
+ }
+
+ public Style style { get; set; }
+
+ internal Run (Style style) {
+ base ();
+ _style = style;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_run (this);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Run run = new Run (style);
+ run.parent = new_parent;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (run) as Inline;
+ run.content.add (copy);
+ }
+
+ return run;
+ }
+}
+
diff --git a/libvaladoc/content/sourcecode.vala b/libvaladoc/content/sourcecode.vala
new file mode 100644
index 000000000..31803f026
--- /dev/null
+++ b/libvaladoc/content/sourcecode.vala
@@ -0,0 +1,240 @@
+/* sourcecode.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public class Valadoc.Content.SourceCode : ContentElement, Inline {
+ public enum Language {
+ GENIE,
+ VALA,
+ XML,
+ C;
+
+ public static Language? from_path (string path) {
+ int pos = path.last_index_of (".");
+ if (pos < 0) {
+ return null;
+ }
+
+ string ext = path.substring (pos + 1);
+ return from_string (ext, true);
+ }
+
+ public static Language? from_string (string str, bool is_extension = false) {
+ switch (str) {
+ case "genie":
+ if (is_extension) {
+ return null;
+ }
+ return Language.GENIE;
+
+ case "gs":
+ return Language.GENIE;
+
+ case "xml":
+ return Language.XML;
+
+ case "vala":
+ return Language.VALA;
+
+ case "c":
+ case "h":
+ return Language.C;
+ }
+
+ return null;
+ }
+
+ public unowned string to_string () {
+ switch (this) {
+ case Language.GENIE:
+ return "genie";
+
+ case Language.VALA:
+ return "vala";
+
+ case Language.XML:
+ return "xml";
+
+ case Language.C:
+ return "c";
+ }
+
+ assert (true);
+ return "";
+ }
+ }
+
+
+ public string code {
+ get;
+ set;
+ }
+
+ public Run? highlighted_code {
+ get;
+ private set;
+ }
+
+ public Language? language {
+ get;
+ set;
+ }
+
+ internal SourceCode () {
+ base ();
+ _language = Language.VALA;
+ }
+
+ private string? get_path (string path, Api.Node container, string source_file_path,
+ ErrorReporter reporter)
+ {
+ // search relative to our file
+ if (!Path.is_absolute (path)) {
+ string relative_to_file = Path.build_path (Path.DIR_SEPARATOR_S,
+ Path.get_dirname (source_file_path),
+ path);
+ if (FileUtils.test (relative_to_file, FileTest.EXISTS | FileTest.IS_REGULAR)) {
+ return (owned) relative_to_file;
+ }
+ }
+
+ // search relative to the current directory / absoulte path
+ if (!FileUtils.test (path, FileTest.EXISTS | FileTest.IS_REGULAR)) {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ code = "File '%s' does not exist".printf (path);
+ reporter.simple_warning ("%s: %s{{{".printf (source_file_path, node_segment),
+ "%s", code);
+ return null;
+ }
+
+ return path;
+ }
+
+ private void load_source_code (string _path, Api.Node container, string source_file_path,
+ ErrorReporter reporter)
+ {
+ string? path = get_path (_path, container, source_file_path, reporter);
+ if (path == null) {
+ return ;
+ }
+
+ try {
+ string content = null;
+ FileUtils.get_contents (path, out content);
+ _language = Language.from_path (path);
+ code = (owned) content;
+ } catch (FileError err) {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_error ("%s: %s{{{".printf (source_file_path, node_segment),
+ "Can't read file '%s': %s", path, err.message);
+ }
+ }
+
+ private inline bool is_empty_string (string line) {
+ for (int i = 0; line[i] != '\0'; i++) {
+ if (line[i].isspace () == false) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private string strip_code (string code) {
+ string[] lines = code.split ("\n");
+ for (int i = lines.length - 1; i >= 0 && is_empty_string (lines[i]); i--) {
+ lines[i] = null;
+ }
+
+ string** _lines = lines;
+ for (int i = 0; lines[i] != null && is_empty_string (lines[i]); i++) {
+ _lines = &lines[i + 1];
+ }
+
+ return string.joinv ("\n", (string[]) _lines);
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ string[] splitted = code.split ("\n", 2);
+ if (splitted[0].strip () == "") {
+ code = splitted[1] ?? "";
+ } else if (splitted[0].has_prefix ("#!")) {
+ unowned string start = (string) (((char*) splitted[0]) + 2);
+ if (start.has_prefix ("include:")) {
+ start = (string) (((char*) start) + 8);
+ string path = start.strip ();
+ load_source_code (path, container, file_path, reporter);
+ } else {
+ string name = start._strip ().down ();
+ _language = Language.from_string (name);
+ code = splitted[1] ?? "";
+ if (_language == null && name != "none") {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_warning ("%s: %s{{{".printf (file_path, node_segment),
+ "Unsupported programming language '%s'", name);
+ }
+ }
+ }
+
+ code = strip_code (code);
+
+ if (_language == Language.VALA) {
+ highlighted_code = api_root.highlighter.highlight_vala (code);
+ } else if (_language == Language.XML) {
+ highlighted_code = api_root.highlighter.highlight_xml (code);
+ } else if (_language == Language.C) {
+ highlighted_code = api_root.highlighter.highlight_c (code);
+ } else {
+ highlighted_code = new Run (Run.Style.MONOSPACED);
+ highlighted_code.content.add (new Text (code));
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_source_code (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ if (highlighted_code != null) {
+ highlighted_code.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ // empty source blocks are visible as well
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ SourceCode source_code = new SourceCode ();
+ source_code.parent = new_parent;
+
+ source_code.language = language;
+ source_code.code = code;
+
+ return source_code;
+ }
+}
diff --git a/libvaladoc/content/styleattributes.vala b/libvaladoc/content/styleattributes.vala
new file mode 100644
index 000000000..c24893aaf
--- /dev/null
+++ b/libvaladoc/content/styleattributes.vala
@@ -0,0 +1,116 @@
+/* styleattributes.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public enum Valadoc.Content.HorizontalAlign {
+ LEFT,
+ RIGHT,
+ CENTER;
+
+ public static HorizontalAlign? from_string (string str) {
+ switch (str) {
+ case "left":
+ return HorizontalAlign.LEFT;
+
+ case "right":
+ return HorizontalAlign.RIGHT;
+
+ case "center":
+ return HorizontalAlign.CENTER;
+ }
+
+ return null;
+ }
+
+ public unowned string to_string () {
+ switch (this) {
+ case HorizontalAlign.LEFT:
+ return "left";
+
+ case HorizontalAlign.RIGHT:
+ return "right";
+
+ case HorizontalAlign.CENTER:
+ return "center";
+ }
+
+ assert (true);
+ return "";
+ }
+}
+
+public enum Valadoc.Content.VerticalAlign {
+ TOP,
+ MIDDLE,
+ BOTTOM;
+
+ public static VerticalAlign? from_string (string str) {
+ switch (str) {
+ case "top":
+ return VerticalAlign.TOP;
+
+ case "middle":
+ return VerticalAlign.MIDDLE;
+
+ case "bottom":
+ return VerticalAlign.BOTTOM;
+ }
+
+ return null;
+ }
+
+ public unowned string to_string () {
+ switch (this) {
+ case VerticalAlign.TOP:
+ return "top";
+
+ case VerticalAlign.MIDDLE:
+ return "middle";
+
+ case VerticalAlign.BOTTOM:
+ return "bottom";
+ }
+
+ assert (true);
+ return "";
+ }
+}
+
+public interface Valadoc.Content.StyleAttributes : ContentElement {
+ public abstract HorizontalAlign? horizontal_align {
+ get;
+ set;
+ }
+
+ public abstract VerticalAlign? vertical_align {
+ get;
+ set;
+ }
+
+ public abstract string? style {
+ get;
+ set;
+ }
+}
+
diff --git a/libvaladoc/content/symbollink.vala b/libvaladoc/content/symbollink.vala
new file mode 100644
index 000000000..70e528495
--- /dev/null
+++ b/libvaladoc/content/symbollink.vala
@@ -0,0 +1,72 @@
+/* symbollink.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2014 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.SymbolLink : InlineContent, Inline {
+ public Api.Node symbol {
+ get;
+ set;
+ }
+
+ public string given_symbol_name {
+ get;
+ set;
+ }
+
+ internal SymbolLink (Api.Node? symbol = null, string? given_symbol_name = null) {
+ base ();
+ _symbol = symbol;
+ _given_symbol_name = given_symbol_name;
+ }
+
+ public override void configure (Settings settings, ResourceLocator locator) {
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_symbol_link (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ SymbolLink link = new SymbolLink (symbol, _given_symbol_name);
+ link.parent = new_parent;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (link) as Inline;
+ link.content.add (copy);
+ }
+
+ return link;
+ }
+}
+
diff --git a/libvaladoc/content/table.vala b/libvaladoc/content/table.vala
new file mode 100644
index 000000000..0a7941a04
--- /dev/null
+++ b/libvaladoc/content/table.vala
@@ -0,0 +1,79 @@
+/* table.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Table : ContentElement, Block {
+ public Gee.List<TableRow> rows {
+ get {
+ return _rows;
+ }
+ }
+
+ private Gee.List<TableRow> _rows;
+
+ internal Table () {
+ base ();
+ _rows = new ArrayList<TableRow> ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check the table consistency in term of row/column number
+
+ // Check individual rows
+ foreach (var row in _rows) {
+ row.parent = this;
+ row.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_table (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ foreach (TableRow element in _rows) {
+ element.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Table table = new Table ();
+ table.parent = new_parent;
+
+ foreach (var row in _rows) {
+ TableRow copy = row.copy (table) as TableRow;
+ table.rows.add (copy);
+ }
+
+ return table;
+ }
+}
+
diff --git a/libvaladoc/content/tablecell.vala b/libvaladoc/content/tablecell.vala
new file mode 100644
index 000000000..50c7fd4ba
--- /dev/null
+++ b/libvaladoc/content/tablecell.vala
@@ -0,0 +1,93 @@
+/* tablecell.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.TableCell : InlineContent, StyleAttributes {
+ public HorizontalAlign? horizontal_align {
+ get;
+ set;
+ }
+
+ public VerticalAlign? vertical_align {
+ get;
+ set;
+ }
+
+ public string? style {
+ get;
+ set;
+ }
+
+ public int colspan {
+ get;
+ set;
+ }
+
+ public int rowspan {
+ get;
+ set;
+ }
+
+ internal TableCell () {
+ base ();
+ _colspan = 1;
+ _rowspan = 1;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_table_cell (this);
+ }
+
+ public override bool is_empty () {
+ // empty cells are displayed as well
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ TableCell cell = new TableCell ();
+ cell.parent = new_parent;
+
+ cell.horizontal_align = horizontal_align;
+ cell.vertical_align = vertical_align;
+ cell.colspan = colspan;
+ cell.rowspan = rowspan;
+ cell.style = style;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (cell) as Inline;
+ cell.content.add (copy);
+ }
+
+ return cell;
+ }
+}
+
diff --git a/libvaladoc/content/tablerow.vala b/libvaladoc/content/tablerow.vala
new file mode 100644
index 000000000..d8759caac
--- /dev/null
+++ b/libvaladoc/content/tablerow.vala
@@ -0,0 +1,77 @@
+/* tablerow.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.TableRow : ContentElement {
+ public Gee.List<TableCell> cells {
+ get {
+ return _cells;
+ }
+ }
+
+ private Gee.List<TableCell> _cells;
+
+ internal TableRow () {
+ base ();
+ _cells = new ArrayList<TableCell> ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check individual cells
+ foreach (var cell in _cells) {
+ cell.parent = this;
+ cell.check (api_root, container, file_path, reporter, settings);
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_table_row (this);
+ }
+
+ public override void accept_children (ContentVisitor visitor) {
+ foreach (TableCell element in _cells) {
+ element.accept (visitor);
+ }
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ TableRow row = new TableRow ();
+ row.parent = new_parent;
+
+ foreach (TableCell cell in _cells) {
+ TableCell copy = cell.copy (row) as TableCell;
+ row.cells.add (copy);
+ }
+
+ return row;
+ }
+}
+
diff --git a/libvaladoc/content/taglet.vala b/libvaladoc/content/taglet.vala
new file mode 100644
index 000000000..c492621a1
--- /dev/null
+++ b/libvaladoc/content/taglet.vala
@@ -0,0 +1,38 @@
+/* taglet.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public interface Valadoc.Content.Taglet : ContentElement {
+
+ public abstract Rule? get_parser_rule (Rule run_rule);
+
+ public virtual Gee.List<ContentElement>? get_inheritable_documentation () {
+ return null;
+ }
+
+ public virtual bool inheritable (Taglet taglet) {
+ return false;
+ }
+}
+
diff --git a/libvaladoc/content/text.vala b/libvaladoc/content/text.vala
new file mode 100644
index 000000000..42ce1e15f
--- /dev/null
+++ b/libvaladoc/content/text.vala
@@ -0,0 +1,63 @@
+/* text.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Text : ContentElement, Inline {
+ public string content {
+ get;
+ set;
+ }
+
+ construct {
+ _content = "";
+ }
+
+ internal Text (string? text = null) {
+ if (text != null) {
+ _content = text;
+ }
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_text (this);
+ }
+
+
+ public override bool is_empty () {
+ return content == "";
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Text text = new Text (content);
+ text.parent = new_parent;
+ return text;
+ }
+}
+
diff --git a/libvaladoc/content/warning.vala b/libvaladoc/content/warning.vala
new file mode 100644
index 000000000..445a447f8
--- /dev/null
+++ b/libvaladoc/content/warning.vala
@@ -0,0 +1,55 @@
+/* warning.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.Warning : BlockContent, Block {
+ internal Warning () {
+ base ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check inline content
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_warning (this);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Warning warning = new Warning ();
+ warning.parent = new_parent;
+
+ foreach (Block block in content) {
+ Block copy = block.copy (warning) as Block;
+ warning.content.add (copy);
+ }
+
+ return warning;
+ }
+}
+
diff --git a/libvaladoc/content/wikilink.vala b/libvaladoc/content/wikilink.vala
new file mode 100644
index 000000000..1c180316b
--- /dev/null
+++ b/libvaladoc/content/wikilink.vala
@@ -0,0 +1,78 @@
+/* link.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+
+public class Valadoc.Content.WikiLink : InlineContent, Inline {
+ public WikiPage page {
+ internal set;
+ get;
+ }
+
+ public string name {
+ get;
+ set;
+ }
+
+ internal WikiLink () {
+ base ();
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ base.check (api_root, container, file_path, reporter, settings);
+
+ page = api_root.wikitree.search (name);
+ if (page == null) {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_warning ("%s: %s[[".printf (file_path, node_segment),
+ "'%s' does not exist", name);
+ return ;
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_wiki_link (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ WikiLink link = new WikiLink ();
+ link.parent = new_parent;
+
+ link.page = page;
+ link.name = name;
+
+ foreach (Inline element in content) {
+ Inline copy = element.copy (link) as Inline;
+ link.content.add (copy);
+ }
+
+ return link;
+ }
+}
diff --git a/libvaladoc/ctyperesolver.vala b/libvaladoc/ctyperesolver.vala
new file mode 100644
index 000000000..6901d960e
--- /dev/null
+++ b/libvaladoc/ctyperesolver.vala
@@ -0,0 +1,402 @@
+/* ctyperesolver.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.Api;
+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 ();
+
+ foreach (string element in elements) {
+ builder.append_c (((char[])element)[0].toupper ());
+ builder.append (element.next_char ().down ());
+ }
+
+ return (owned) builder.str;
+ }
+
+ private bool is_capitalized_and_underscored (string name) {
+ unowned string pos;
+
+ unichar c = name.get_char ();
+
+
+ if (c < 'A' || c > 'Z') {
+ return false;
+ }
+
+ bool last_was_underscore = false;
+ for (c = (pos = name).get_char (); c != '\0' ; c = (pos = pos.next_char ()).get_char ()) {
+ if ((c != '_' && !(c >= 'A' && c <= 'Z')) || (last_was_underscore && c == '_')) {
+ return false;
+ }
+
+ last_was_underscore = (c == '_');
+ }
+
+ return !last_was_underscore;
+ }
+
+ private string? translate_cname_to_g (string name) {
+ if (is_capitalized_and_underscored (name)) {
+ string[] segments = name.split ("_");
+ unowned string last_segment = segments[segments.length - 1];
+ if (last_segment != "ERROR") {
+ return null;
+ }
+
+ return convert_array_to_camelcase (segments);
+ }
+
+ int length = name.length;
+ if (length > 5 && name.has_suffix ("Iface")) {
+ return name.substring (0, length - 5);
+ } else if (length > 5 && name.has_suffix ("Class")) {
+ return name.substring (0, length - 5);
+ }
+
+ 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
+ *
+ * @param _name a C-name
+ * @return the resolved node or null
+ */
+ public Api.Node? resolve_symbol (Api.Node? element, string _name) {
+ string name = _name.replace ("->", ".").replace ("-", "_");
+
+ if (element != null && name.has_prefix (":")) {
+ Item parent = element;
+ while (parent != null && !(parent is Class || parent is Interface)) {
+ parent = parent.parent;
+ }
+
+ if (parent is Class && ((Class) parent).get_cname () != null) {
+ name = ((Class) parent).get_cname () + name;
+ } else if (parent is Interface && ((Interface) parent).get_cname () != null) {
+ name = ((Interface) parent).get_cname () + name;
+ } else {
+ return null;
+ }
+
+ }
+
+ Api.Node? node = nodes.get (name);
+ if (node != null) {
+ return node;
+ }
+
+ string? alternative = translate_cname_to_g (name);
+ if (alternative != null) {
+ 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");
+ }
+
+ int dotpos = name.index_of_char ('.');
+ if (dotpos > 0) {
+ string fst = name.substring (0, dotpos);
+ string snd = name.substring (dotpos + 1);
+ return nodes.get (fst + ":" + snd);
+ }
+
+ 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);
+ }
+ }
+
+ private string? get_parent_type_cname (Item item) {
+ string parent_cname = null;
+ if (item.parent is Class) {
+ parent_cname = ((Class) item.parent).get_cname ();
+ } else if (item.parent is Interface) {
+ parent_cname = ((Interface) item.parent).get_cname ();
+ } else if (item.parent is Struct) {
+ parent_cname = ((Struct) item.parent).get_cname ();
+ } else if (item.parent is ErrorDomain) {
+ parent_cname = ((ErrorDomain) item.parent).get_cname ();
+ } else if (item.parent is Api.Enum) {
+ parent_cname = ((Api.Enum) item.parent).get_cname ();
+ } else {
+ assert (true);
+ }
+ return parent_cname;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_tree (Api.Tree item) {
+ item.accept_children (this);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_package (Package item) {
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_namespace (Namespace item) {
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_interface (Interface item) {
+ register_symbol (item.get_cname (), item);
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@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);
+ }
+
+ /**
+ * {@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);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_property (Property item) {
+ string parent_cname = get_parent_type_cname (item);
+ assert (parent_cname != null);
+
+ string cname = item.get_cname ();
+ register_symbol (parent_cname+":"+cname, item);
+
+
+ Collection<Interface> interfaces = null;
+ Collection<Class> classes = null;
+
+ if (item.parent is Interface) {
+ interfaces = ((Api.Interface) item.parent).get_known_related_interfaces ();
+ classes = ((Api.Interface) item.parent).get_known_implementations ();
+ } else if (item.parent is Class) {
+ interfaces = ((Api.Class) item.parent).get_known_derived_interfaces ();
+ classes = ((Api.Class) item.parent).get_known_child_classes ();
+ }
+
+ foreach (Interface iface in interfaces) {
+ register_symbol (iface.get_cname () + ":" + cname, item);
+ }
+
+ foreach (Class cl in classes) {
+ register_symbol (cl.get_cname () + ":" + cname, item);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_field (Field item) {
+ if (item.parent is Namespace || item.is_static) {
+ register_symbol (item.get_cname (), item);
+ } else {
+ string parent_cname = get_parent_type_cname (item);
+ if (parent_cname != null) {
+ register_symbol (parent_cname + "." + item.get_cname (), item);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_constant (Constant item) {
+ register_symbol (item.get_cname (), item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_delegate (Delegate item) {
+ register_symbol (item.get_cname (), item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_signal (Api.Signal item) {
+ string parent_cname = get_parent_type_cname (item);
+ assert (parent_cname != null);
+
+ string? default_impl_cname = item.get_default_impl_cname ();
+ string cname = item.get_cname ();
+ register_symbol (parent_cname+"::"+cname, item);
+
+ if (item.is_virtual) {
+ // only supported by classes
+ register_symbol (parent_cname + "Class." + item.name, item);
+ }
+
+ Collection<Interface> interfaces = null;
+ Collection<Class> classes = null;
+
+ if (item.parent is Interface) {
+ interfaces = ((Api.Interface) item.parent).get_known_related_interfaces ();
+ classes = ((Api.Interface) item.parent).get_known_implementations ();
+ } else if (item.parent is Class) {
+ interfaces = ((Api.Class) item.parent).get_known_derived_interfaces ();
+ classes = ((Api.Class) item.parent).get_known_child_classes ();
+ }
+
+ foreach (Interface iface in interfaces) {
+ register_symbol (iface.get_cname () + "::" + cname, item);
+ }
+
+ foreach (Class cl in classes) {
+ register_symbol (cl.get_cname () + "::" + cname, item);
+ }
+
+ if (default_impl_cname != null) {
+ register_symbol (default_impl_cname, item);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_method (Method item) {
+ if (item.is_abstract || item.is_virtual || item.is_override) {
+ string parent_cname = get_parent_type_cname (item);
+
+ if (item.parent is Class) {
+ register_symbol (parent_cname + "Class." + item.name, item);
+ } else {
+ register_symbol (parent_cname + "Iface." + item.name, item);
+ }
+
+ // Allow to resolve invalid links:
+ register_symbol (parent_cname + "." + item.name, item);
+ }
+
+ register_symbol (item.get_cname (), item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_error_domain (ErrorDomain item) {
+ register_symbol (item.get_cname (), item);
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_error_code (ErrorCode item) {
+ register_symbol (item.get_cname (), item);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_enum (Api.Enum item) {
+ register_symbol (item.get_cname (), item);
+ item.accept_all_children (this, false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public override void visit_enum_value (Api.EnumValue item) {
+ register_symbol (item.get_cname (), item);
+ }
+}
+
+
diff --git a/libvaladoc/devhelp-markupwriter.vala b/libvaladoc/devhelp-markupwriter.vala
new file mode 100644
index 000000000..ae524384c
--- /dev/null
+++ b/libvaladoc/devhelp-markupwriter.vala
@@ -0,0 +1,93 @@
+/* devhelp-markupwriter.vala
+ *
+ * Copyright (C) 2008-2009 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>
+ */
+
+public class Valadoc.Devhelp.MarkupWriter : Valadoc.MarkupWriter {
+
+ public MarkupWriter (FileStream stream, bool xml_declaration = true) {
+ // avoid broken implicit copy
+ unowned FileStream _stream = stream;
+
+ base ((str) => { _stream.printf (str); }, xml_declaration);
+ }
+
+ protected override bool inline_element (string name) {
+ return name != "book";
+ }
+
+ protected override bool content_inline_element (string name) {
+ return name == "keyword"
+ || name == "sub";
+ }
+
+ public MarkupWriter start_book (string title, string lang, string link, string name, string version, string author) {
+ this.start_tag ("book", {"xmlns", "http://www.devhelp.net/book",
+ "title", title,
+ "language", lang,
+ "name", name,
+ "version", version,
+ "author", author,
+ "link", link});
+ return this;
+ }
+
+ public MarkupWriter end_book () {
+ this.end_tag ("book");
+ return this;
+ }
+
+ public MarkupWriter start_functions () {
+ this.start_tag ("functions");
+ return this;
+ }
+
+ public MarkupWriter end_functions () {
+ this.end_tag ("functions");
+ return this;
+ }
+
+ public MarkupWriter start_chapters () {
+ this.start_tag ("chapters");
+ return this;
+ }
+
+ public MarkupWriter end_chapters () {
+ this.end_tag ("chapters");
+ return this;
+ }
+
+ public MarkupWriter start_sub (string name, string link) {
+ this.start_tag ("sub", {"name", name, "link", link});
+ return this;
+ }
+
+ public MarkupWriter end_sub () {
+ this.end_tag ("sub");
+ return this;
+ }
+
+ public MarkupWriter keyword (string name, string type, string link) {
+ this.start_tag ("keyword", {"type", type, "name", name, "link", link});
+ this.end_tag ("keyword");
+ return this;
+ }
+}
+
diff --git a/libvaladoc/doclet.vala b/libvaladoc/doclet.vala
new file mode 100644
index 000000000..c8c580444
--- /dev/null
+++ b/libvaladoc/doclet.vala
@@ -0,0 +1,52 @@
+/* doclet.vala
+ *
+ * Copyright (C) 2008-2009 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+using Gee;
+
+/**
+ * A plugin register function for doclets
+ *
+ * @see ModuleLoader
+ */
+[CCode (has_target = false)]
+public delegate Type Valadoc.DocletRegisterFunction (ModuleLoader module_loader);
+
+
+
+/**
+ * Provides a mechanism to inspect the API & documentation of programs and libraries
+ */
+public interface Valadoc.Doclet : GLib.Object {
+
+ /**
+ * Allows the doclet to inspect the given {@link Api.Tree}
+ *
+ * @param settings various configurations
+ * @param tree the tree to inspect
+ * @param reporter the reporter to use
+ * @see Content.ContentVisitor
+ * @see Api.Visitor
+ */
+ public abstract void process (Settings settings, Api.Tree tree, ErrorReporter reporter);
+}
+
+
diff --git a/libvaladoc/documentation/commentscanner.vala b/libvaladoc/documentation/commentscanner.vala
new file mode 100644
index 000000000..ad0160167
--- /dev/null
+++ b/libvaladoc/documentation/commentscanner.vala
@@ -0,0 +1,69 @@
+/* commentscanner.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+public class Valadoc.CommentScanner : WikiScanner {
+
+ public CommentScanner (Settings settings) {
+ base (settings);
+ }
+
+ private bool in_line_start;
+ private bool past_star;
+ private int start_column;
+
+ public override void reset () {
+ base.reset ();
+
+ in_line_start = true;
+ past_star = false;
+ start_column = 0;
+ }
+
+ public override int get_line_start_column () {
+ return start_column;
+ }
+
+ protected override void accept (unichar c) throws ParserError {
+ if (in_line_start) {
+ start_column++;
+ if (c == '*') {
+ past_star = true;
+ } else if (past_star) {
+ past_star = false;
+ if (c == '\n') {
+ base.accept (c);
+ in_line_start = true;
+ start_column = 0;
+ } else {
+ in_line_start = false;
+ }
+ }
+ } else {
+ base.accept (c);
+ if (c == '\n') {
+ in_line_start = true;
+ start_column = 0;
+ }
+ }
+ }
+}
+
diff --git a/libvaladoc/documentation/documentation.vala b/libvaladoc/documentation/documentation.vala
new file mode 100644
index 000000000..6df57eaa4
--- /dev/null
+++ b/libvaladoc/documentation/documentation.vala
@@ -0,0 +1,39 @@
+/* documentation.vala
+ *
+ * Copyright (C) 2008-2009 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 Gee;
+
+public interface Valadoc.Documentation : Object {
+
+ /**
+ * The corresponding package
+ */
+ public abstract Api.Package? package {
+ get;
+ }
+
+ /**
+ * The corresponding file name
+ */
+ public abstract string? get_filename ();
+}
+
diff --git a/libvaladoc/documentation/documentationparser.vala b/libvaladoc/documentation/documentationparser.vala
new file mode 100644
index 000000000..fe6d68505
--- /dev/null
+++ b/libvaladoc/documentation/documentationparser.vala
@@ -0,0 +1,897 @@
+/* documentationparser.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Valadoc.Content;
+using Valadoc.Importer;
+using Gee;
+
+
+public class Valadoc.DocumentationParser : Object, ResourceLocator {
+ private HashMap<Api.SourceFile, GirMetaData> metadata;
+ private Importer.InternalIdRegistrar id_registrar;
+
+
+ public DocumentationParser (Settings settings, ErrorReporter reporter,
+ Api.Tree tree, ModuleLoader modules)
+ {
+ _settings = settings;
+ _reporter = reporter;
+ _tree = tree;
+ _modules = modules;
+
+ _factory = new ContentFactory (_settings, this, _modules);
+
+ _wiki_scanner = new WikiScanner (_settings);
+ _wiki_parser = new Parser (_settings, _wiki_scanner, _reporter);
+ _wiki_scanner.set_parser (_wiki_parser);
+
+ _comment_scanner = new CommentScanner (_settings);
+ _comment_parser = new Parser (_settings, _comment_scanner, _reporter);
+ _comment_scanner.set_parser (_comment_parser);
+
+ gtkdoc_parser = new Gtkdoc.Parser (settings, reporter, tree, modules);
+ gtkdoc_markdown_parser = new Gtkdoc.MarkdownParser (settings, reporter, tree, modules);
+
+
+ metadata = new HashMap<Api.SourceFile, GirMetaData> ();
+ id_registrar = new Importer.InternalIdRegistrar ();
+
+ init_valadoc_rules ();
+ }
+
+ private Gtkdoc.Parser gtkdoc_parser;
+ private Gtkdoc.MarkdownParser gtkdoc_markdown_parser;
+
+ private Settings _settings;
+ private ErrorReporter _reporter;
+ private Api.Tree _tree;
+ private ModuleLoader _modules;
+
+ private ContentFactory _factory;
+ private WikiScanner _wiki_scanner;
+ private CommentScanner _comment_scanner;
+ private Parser _wiki_parser;
+ private Parser _comment_parser;
+
+ private Parser _parser;
+ private Scanner _scanner;
+
+ public Comment? parse (Api.Node element, Api.SourceComment comment) {
+ if (comment is Api.GirSourceComment) {
+ Api.GirSourceComment gir_comment = (Api.GirSourceComment) comment;
+ GirMetaData metadata = get_metadata_for_comment (gir_comment);
+
+ if (metadata.is_docbook) {
+ Comment doc_comment = gtkdoc_parser.parse (element, gir_comment, metadata, id_registrar);
+ return doc_comment;
+ } else {
+ Comment doc_comment = gtkdoc_markdown_parser.parse (element, gir_comment, metadata, id_registrar);
+ return doc_comment;
+ }
+ } else {
+ return parse_comment_str (element, comment.content, comment.file.get_name (),
+ comment.first_line, comment.first_column);
+ }
+ }
+
+ public Comment? parse_comment_str (Api.Node element, string content, string filename,
+ int first_line, int first_column)
+ {
+ try {
+ Comment doc_comment = parse_comment (content, filename, first_line, first_column);
+ return doc_comment;
+ } catch (ParserError error) {
+ return null;
+ }
+ }
+
+ public Page? parse_wikipage (Api.Package pkg, WikiPage page) {
+ if (page.documentation != null) {
+ return page.documentation;
+ }
+
+ if (page.documentation_str == null) {
+ return null;
+ }
+
+ try {
+ Page documentation = parse_wiki (page.documentation_str, page.get_filename ());
+ return documentation;
+ } catch (ParserError error) {
+ return null;
+ }
+ }
+
+ private Comment parse_comment (string content, string filename, int first_line, int first_column)
+ throws ParserError
+ {
+ _parser = _comment_parser;
+ _scanner = _comment_scanner;
+ _stack.clear ();
+ _comment_parser.parse (content, filename, first_line, first_column);
+ return (Comment) pop ();
+ }
+
+ private Page parse_wiki (string content, string filename) throws ParserError {
+ _parser = _wiki_parser;
+ _scanner = _wiki_scanner;
+ _stack.clear ();
+ _wiki_parser.parse (content, filename, 0, 0);
+ return (Page) pop ();
+ }
+
+ public void check (Api.Node element, Comment comment) {
+ comment.check (_tree, element, element.get_source_file ().relative_path, _reporter, _settings);
+ }
+
+ public void check_wikipage (Api.Package package, WikiPage page) {
+ page.documentation.check (_tree, package, page.path, _reporter, _settings);
+ }
+
+ public void transform_inheritdoc (Api.Node taglet_owner, Taglets.InheritDoc taglet) {
+ if (taglet.inherited == null) {
+ return ;
+ }
+
+
+ taglet.inherited.parse_comments (_settings, this);
+ if (taglet.inherited.documentation == null) {
+ return ;
+ }
+
+
+ taglet.inherited.check_comments (_settings, this);
+
+ taglet.transform (_tree, taglet_owner, taglet_owner.get_source_file ().get_name (), _reporter, _settings);
+ }
+
+ private GirMetaData get_metadata_for_comment (Api.GirSourceComment gir_comment) {
+ GirMetaData metadata = metadata.get (gir_comment.file);
+ if (metadata != null) {
+ return metadata;
+ }
+
+ metadata = new GirMetaData (gir_comment.file.relative_path, _settings.metadata_directories, _reporter);
+ if (metadata.index_sgml != null) {
+ id_registrar.read_index_sgml_file (metadata.index_sgml, metadata.index_sgml_online, _reporter);
+ }
+
+ this.metadata.set (gir_comment.file, metadata);
+ return metadata;
+ }
+
+ public string resolve (string path) {
+ return path;
+ }
+
+ private ArrayList<Object> _stack = new ArrayList<Object> ();
+
+ private void push (Object element) {
+ _stack.add (element);
+ }
+
+ private Object peek (int offset = -1) {
+ assert (_stack.size >= - offset);
+ return _stack.get (_stack.size + offset);
+ }
+
+ private Object pop () {
+ Object node = peek ();
+ _stack.remove_at (_stack.size - 1);
+ return node;
+ }
+
+ private Rule multiline_block_run;
+ private Rule multiline_run;
+ private int current_level = 0;
+ private int[] levels = new int[0];
+
+ private void new_list_item (Content.List.Bullet bullet) throws ParserError {
+ var new_item = _factory.create_list_item ();
+
+ Content.List list = null;
+ if (levels.length >= 1) {
+ if (current_level > levels[levels.length - 1]) {
+ list = _factory.create_list ();
+ list.bullet = bullet;
+
+ var current_item = peek () as ListItem;
+ current_item.content.add (list);
+ push (list);
+
+ levels += current_level;
+ } else {
+ bool poped_some_lists = false;
+ while (current_level < levels[levels.length - 1]) {
+ // Pop current item and list
+ pop ();
+ pop ();
+ levels.resize (levels.length - 1);
+ poped_some_lists = true;
+ }
+ list = peek (-2) as Content.List;
+
+ if (!poped_some_lists && bullet == Content.List.Bullet.NONE) {
+ ((Paragraph) ((ListItem) peek ()).content[0]).content.add (_factory.create_text (" "));
+ return;
+ } else if (list.bullet != bullet) {
+ _parser.error (null, "Invalid bullet type '%s': expected '%s'"
+ .printf (bullet_type_string (bullet), bullet_type_string (list.bullet)));
+ return;
+ }
+
+ pop ();
+ }
+ } else {
+ list = _factory.create_list ();
+ list.bullet = bullet;
+
+ ((BlockContent) peek ()).content.add (list);
+ push (list);
+
+ levels = new int[0];
+ levels += current_level;
+ }
+
+ list.items.add (new_item);
+ push (new_item);
+ }
+
+ private string bullet_type_string (Content.List.Bullet bullet) {
+ switch (bullet) {
+ case Content.List.Bullet.NONE:
+ return ".";
+ case Content.List.Bullet.UNORDERED:
+ return "*";
+ case Content.List.Bullet.ORDERED_NUMBER:
+ return "1.";
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ALPHA:
+ return "a.";
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ALPHA:
+ return "A.";
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ROMAN:
+ return "i.";
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ROMAN:
+ return "I.";
+ }
+ return "";
+ }
+
+ private void finish_list () {
+ while (peek () is ListItem) {
+ pop ();
+ pop ();
+ levels.resize (levels.length - 1);
+ }
+ }
+
+ private void add_content_string (string str) {
+ var text = peek () as Text;
+ if (text == null) {
+ push (text = _factory.create_text ());
+ }
+ text.content += str;
+ }
+
+ private void add_content_space () {
+ // avoid double spaces
+ var head = peek ();
+ Text text_node = null;
+
+ if (head is Text) {
+ text_node = (Text) head;
+ } else if (head is InlineContent && ((InlineContent) head).content.size > 0
+ && ((InlineContent) head).content.last () is Text)
+ {
+ text_node = (Text) ((InlineContent) head).content.last ();
+ } else {
+ text_node = _factory.create_text ();
+ ((InlineContent) peek ()).content.add (text_node);
+ }
+
+ if (!text_node.content.has_suffix (" ")) {
+ text_node.content += " ";
+ }
+ }
+
+ private void init_valadoc_rules () {
+ // Inline rules
+
+ StubRule run = new StubRule ();
+ run.set_name ("Run");
+
+ TokenType.Action add_text = (token) => {
+ add_content_string (token.to_string ());
+ };
+
+ TokenType space = TokenType.SPACE.action ((token) => { add_content_space (); });
+ TokenType word = TokenType.any_word ().action (add_text);
+
+ Rule optional_invisible_spaces =
+ Rule.option ({
+ Rule.many ({ TokenType.SPACE })
+ });
+
+ Rule optional_spaces =
+ Rule.option ({
+ Rule.many ({
+ TokenType.SPACE.action ((token) => { add_content_space (); })
+ })
+ });
+
+
+ Rule text =
+ Rule.many ({
+ Rule.one_of ({
+ TokenType.BREAK.action ((token) => { add_content_string ("\n"); }),
+ TokenType.CLOSED_BRACE.action (add_text),
+ TokenType.MINUS.action (add_text),
+ TokenType.ALIGN_BOTTOM.action (add_text),
+ TokenType.ALIGN_TOP.action (add_text),
+ TokenType.GREATER_THAN.action (add_text),
+ TokenType.LESS_THAN.action (add_text),
+ TokenType.DOUBLE_PIPE.action (add_text),
+ TokenType.PIPE.action (add_text),
+ TokenType.ALIGN_RIGHT.action (add_text),
+ TokenType.ALIGN_CENTER.action (add_text),
+ TokenType.EQUAL_1.action (add_text),
+ TokenType.EQUAL_2.action (add_text),
+ TokenType.EQUAL_3.action (add_text),
+ TokenType.EQUAL_4.action (add_text),
+ TokenType.EQUAL_5.action (add_text),
+ word
+ }),
+ Rule.option ({ space })
+ })
+ .set_name ("Text")
+ .set_start (() => { push (_factory.create_text ()); });
+
+ Rule run_with_spaces =
+ Rule.seq ({
+ Rule.many ({
+ Rule.one_of ({
+ optional_invisible_spaces,
+ run
+ })
+ })
+ })
+ .set_name ("RunWithSpaces");
+
+ multiline_run = Rule.many ({
+ run_with_spaces,
+ TokenType.EOL.action (() => { add_content_space (); })
+ })
+ .set_name ("MultiLineRun");
+
+ Rule inline_taglet =
+ Rule.seq ({
+ TokenType.OPEN_BRACE,
+ Rule.option ({
+ TokenType.AROBASE,
+ TokenType.any_word ().action ((token) => {
+ var taglet = _factory.create_taglet (token.to_string ());
+ if (!(taglet is Inline)) {
+ _parser.error (null, "Invalid taglet in this context: %s".printf (token.to_string ()));
+ }
+ push (taglet);
+ Rule? taglet_rule = taglet.get_parser_rule (multiline_run);
+ if (taglet_rule != null) {
+ _parser.push_rule (Rule.seq ({ TokenType.SPACE, taglet_rule }));
+ }
+ }),
+ TokenType.CLOSED_BRACE
+ })
+ .set_skip (() => { add_content_string ("{"); })
+ })
+ .set_name ("InlineTaglet");
+
+ //TODO: Find a nicer way to allow empty tags (''run?'' won't work)
+ Rule bold =
+ Rule.seq ({
+ TokenType.SINGLE_QUOTE_2,
+ Rule.one_of ({
+ TokenType.SINGLE_QUOTE_2,
+ Rule.seq ({ optional_spaces, run, TokenType.SINGLE_QUOTE_2 })
+ })
+ })
+ .set_name ("Bold")
+ .set_start (() => { push (_factory.create_run (Run.Style.BOLD)); });
+
+ Rule italic =
+ Rule.seq ({
+ TokenType.SLASH_2,
+ Rule.one_of ({
+ TokenType.SLASH_2,
+ Rule.seq ({ optional_spaces, run, TokenType.SLASH_2 })
+ })
+ })
+ .set_name ("Italic")
+ .set_start (() => { push (_factory.create_run (Run.Style.ITALIC)); });
+
+ Rule underlined =
+ Rule.seq ({
+ TokenType.UNDERSCORE_2,
+ Rule.one_of ({
+ TokenType.UNDERSCORE_2,
+ Rule.seq ({ optional_spaces, run, TokenType.UNDERSCORE_2 })
+ })
+ })
+ .set_name ("Underlined")
+ .set_start (() => { push (_factory.create_run (Run.Style.UNDERLINED)); });
+
+ Rule monospace =
+ Rule.seq ({
+ TokenType.BACK_QUOTE_2,
+ Rule.one_of ({
+ TokenType.BACK_QUOTE_2,
+ Rule.seq ({ optional_spaces, run, TokenType.BACK_QUOTE_2 })
+ })
+ })
+ .set_name ("Monospace")
+ .set_start (() => { push (_factory.create_run (Run.Style.MONOSPACED)); });
+
+ Rule embedded =
+ Rule.seq ({
+ 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 (() => { ((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 (() => { ((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 (() => { ((WikiScanner) _scanner).set_url_escape_mode (true); }),
+ TokenType.any_word ().action ((token) => {
+ var url = token.to_string ();
+ if (url.has_suffix (".valadoc")) {
+ var link = _factory.create_wiki_link ();
+ link.name = url;
+ push (link);
+ } else {
+ var link = _factory.create_link ();
+ link.url = url;
+ push (link);
+ }
+ }),
+ Rule.option ({
+ TokenType.PIPE.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); }),
+ run
+ }),
+ TokenType.DOUBLE_CLOSED_BRACKET.action (() => { ((WikiScanner) _scanner).set_url_escape_mode (false); })
+ })
+ .set_name ("Link");
+ Rule source_code =
+ Rule.seq ({
+ 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) => { ((WikiScanner) _scanner).set_code_escape_mode (false); })
+ })
+ .set_name ("SourceCode")
+ .set_start (() => { push (_factory.create_source_code ()); });
+
+ Rule.Action append_head_to_head2 = () => {
+ var head = (Inline) pop ();
+ ((InlineContent) peek ()).content.add (head);
+ };
+
+ Rule run_subrules =
+ Rule.one_of ({
+ Rule.seq ({
+ text
+ })
+ .set_reduce (append_head_to_head2),
+ Rule.seq ({
+ Rule.one_of ({
+ inline_taglet, bold, italic, underlined, monospace, embedded, link, source_code
+ })
+ .set_reduce (append_head_to_head2),
+ optional_spaces
+ })
+ });
+
+ Rule run_arobase =
+ Rule.seq ({
+ TokenType.AROBASE.action (add_text)
+ })
+ .set_reduce (append_head_to_head2);
+
+ run.set_rule (
+ Rule.seq ({
+ run_subrules,
+ optional_spaces,
+ Rule.option ({
+ Rule.many ({
+ Rule.one_of ({
+ run_arobase,
+ run_subrules,
+ optional_spaces
+ })
+ })
+ })
+ })
+ .set_name ("Run")
+ );
+
+
+ // Block rules
+
+ Rule paragraph =
+ Rule.seq ({
+ Rule.option ({
+ Rule.one_of ({
+ TokenType.ALIGN_CENTER.action (() => { ((Paragraph) peek ()).horizontal_align = HorizontalAlign.CENTER; }),
+ TokenType.ALIGN_RIGHT.action (() => { ((Paragraph) peek ()).horizontal_align = HorizontalAlign.RIGHT; })
+ })
+ }),
+ Rule.many ({
+ run,
+ TokenType.EOL.action (() => { add_content_space (); })
+ })
+ })
+ .set_name ("Paragraph")
+ .set_start (() => { push (_factory.create_paragraph ()); })
+ .set_reduce (() => {
+ var head = (Paragraph) pop ();
+ ((BlockContent) peek ()).content.add (head);
+
+ Text last_element = head.content.last () as Text;
+ if (last_element != null) {
+ last_element.content._chomp ();
+ }
+ });
+
+ Rule warning =
+ Rule.seq ({
+ TokenType.str ("Warning:"),
+ optional_invisible_spaces,
+ Rule.many ({
+ Rule.seq({optional_invisible_spaces, run}),
+ TokenType.EOL.action (() => { add_content_space (); })
+ })
+ })
+ .set_name ("Warning")
+ .set_start (() => { push (_factory.create_paragraph ()); })
+ .set_reduce (() => {
+ var head = _factory.create_warning ();
+ head.content.add ((Paragraph) pop ());
+ ((BlockContent) peek ()).content.add (head);
+
+ Text last_element = head.content.last () as Text;
+ if (last_element != null) {
+ last_element.content._chomp ();
+ }
+ });
+
+ Rule note =
+ Rule.seq ({
+ TokenType.str ("Note:"),
+ optional_invisible_spaces,
+ Rule.many ({
+ Rule.seq({optional_invisible_spaces, run}),
+ TokenType.EOL.action (() => { add_content_space (); })
+ })
+ })
+ .set_name ("Note")
+ .set_start (() => { push (_factory.create_paragraph ()); })
+ .set_reduce (() => {
+ var head = _factory.create_note ();
+ head.content.add ((Paragraph) pop ());
+ ((BlockContent) peek ()).content.add (head);
+
+ Text last_element = head.content.last () as Text;
+ if (last_element != null) {
+ last_element.content._chomp ();
+ }
+ });
+
+ Rule indented_item =
+ Rule.seq ({
+ Rule.many ({
+ TokenType.SPACE.action ((token) => { current_level++; })
+ }),
+ Rule.option ({
+ Rule.one_of ({
+ TokenType.str (".").action ((token) => { new_list_item (Content.List.Bullet.NONE); }),
+ TokenType.str ("*").action ((token) => { new_list_item (Content.List.Bullet.UNORDERED); }),
+ TokenType.str ("#").action ((token) => { new_list_item (Content.List.Bullet.ORDERED); }),
+ TokenType.str ("1.").action ((token) => { new_list_item (Content.List.Bullet.ORDERED_NUMBER); }),
+ TokenType.str ("a.").action ((token) => { new_list_item (Content.List.Bullet.ORDERED_LOWER_CASE_ALPHA); }),
+ TokenType.str ("A.").action ((token) => { new_list_item (Content.List.Bullet.ORDERED_UPPER_CASE_ALPHA); }),
+ TokenType.str ("i.").action ((token) => { new_list_item (Content.List.Bullet.ORDERED_LOWER_CASE_ROMAN); }),
+ TokenType.str ("I.").action ((token) => { new_list_item (Content.List.Bullet.ORDERED_UPPER_CASE_ROMAN); })
+ }),
+ optional_invisible_spaces
+ })
+ .set_skip (() => { new_list_item (Content.List.Bullet.NONE); }),
+ Rule.seq ({ run })
+ .set_start (() => {
+ var content = _factory.create_paragraph ();
+ ((ListItem) peek ()).content.add (content);
+ push (content);
+ })
+ .set_reduce (() => { pop (); }),
+ TokenType.EOL
+ })
+ .set_name ("IndentedItem")
+ .set_start (() => { current_level = 0; })
+ .set_reduce (() => {
+ var content_list = ((ListItem) peek ()).content;
+ if (content_list.size > 0 && content_list.last () is Text) {
+ ((Text) content_list.last ()).content._chomp ();
+ }
+ });
+
+ Rule indented_blocks =
+ Rule.many ({
+ indented_item
+ })
+ .set_name ("IndentedBlocks")
+ .set_reduce (() => { finish_list (); });
+
+ Rule table_cell_attributes =
+ Rule.seq ({
+ TokenType.LESS_THAN,
+ Rule.option ({
+ Rule.one_of ({
+ Rule.seq ({
+ Rule.option ({
+ Rule.one_of ({
+ TokenType.ALIGN_RIGHT.action ((token) => { ((TableCell) peek ()).horizontal_align = HorizontalAlign.RIGHT; }),
+ TokenType.ALIGN_CENTER.action ((token) => { ((TableCell) peek ()).horizontal_align = HorizontalAlign.CENTER; })
+ })
+ }),
+ Rule.option ({
+ Rule.one_of ({
+ TokenType.ALIGN_TOP.action ((token) => { ((TableCell) peek ()).vertical_align = VerticalAlign.TOP; }),
+ TokenType.ALIGN_BOTTOM.action ((token) => { ((TableCell) peek ()).vertical_align = VerticalAlign.BOTTOM; })
+ })
+ })
+ }),
+ TokenType.any_word ().action ((token) => { ((TableCell) peek ()).style = token.to_string (); })
+ })
+ }),
+ Rule.option ({
+ Rule.one_of ({
+ Rule.seq ({
+ TokenType.PIPE,
+ TokenType.any_number ().action ((token) => { ((TableCell) peek ()).rowspan = token.to_int (); })
+ }),
+ Rule.seq ({
+ TokenType.MINUS,
+ TokenType.any_number ().action ((token) => { ((TableCell) peek ()).colspan = token.to_int (); })
+ })
+ })
+ }),
+ TokenType.GREATER_THAN
+ })
+ .set_name ("CellAttributes");
+ Rule table_cell =
+ Rule.seq ({
+ Rule.seq ({
+ Rule.option ({
+ table_cell_attributes
+ }),
+ optional_invisible_spaces,
+ run
+ }),
+ TokenType.DOUBLE_PIPE
+ })
+ .set_name ("Cell")
+ .set_start (() => { push (_factory.create_table_cell ()); })
+ .set_reduce (() => {
+ var head = (TableCell) pop ();
+ ((TableRow) peek ()).cells.add (head);
+
+ if (head.content.size > 0 && head.content.last () is Text) {
+ ((Text) head.content.last ()).content._chomp ();
+ }
+ });
+ Rule table_row =
+ Rule.seq ({
+ TokenType.DOUBLE_PIPE,
+ Rule.many ({
+ table_cell
+ }),
+ TokenType.EOL
+ })
+ .set_name ("Row")
+ .set_start (() => { push (_factory.create_table_row ()); })
+ .set_reduce (() => {
+ var head = (TableRow) pop ();
+ ((Table) peek ()).rows.add (head);
+ });
+ Rule table =
+ Rule.seq ({
+ Rule.many ({
+ table_row
+ })
+ })
+ .set_name ("Table")
+ .set_start (() => { push (_factory.create_table ()); })
+ .set_reduce (() => {
+ var head = (Block) pop ();
+ ((BlockContent) peek ()).content.add (head);
+ });
+
+ Rule headline =
+ Rule.one_of ({
+ Rule.seq ({
+ TokenType.EQUAL_1.action ((token) => { ((Headline) peek ()).level = 1; }),
+ optional_invisible_spaces,
+ run,
+ optional_invisible_spaces,
+ TokenType.EQUAL_1,
+ TokenType.EOL
+ }),
+ Rule.seq ({
+ TokenType.EQUAL_2.action ((token) => { ((Headline) peek ()).level = 2; }),
+ optional_invisible_spaces,
+ run,
+ optional_invisible_spaces,
+ TokenType.EQUAL_2,
+ TokenType.EOL
+ }),
+ Rule.seq ({
+ TokenType.EQUAL_3.action ((token) => { ((Headline) peek ()).level = 3; }),
+ optional_invisible_spaces,
+ run,
+ optional_invisible_spaces,
+ TokenType.EQUAL_3,
+ TokenType.EOL
+ }),
+ Rule.seq ({
+ TokenType.EQUAL_4.action ((token) => { ((Headline) peek ()).level = 4; }),
+ optional_invisible_spaces,
+ run,
+ optional_invisible_spaces,
+ TokenType.EQUAL_4,
+ TokenType.EOL
+ }),
+ Rule.seq ({
+ TokenType.EQUAL_5.action ((token) => { ((Headline) peek ()).level = 5; }),
+ optional_invisible_spaces,
+ run,
+ optional_invisible_spaces,
+ TokenType.EQUAL_5,
+ TokenType.EOL
+ })
+ })
+ .set_name ("Headline")
+ .set_start (() => { push (_factory.create_headline ()); })
+ .set_reduce (() => {
+ var head = (Block) pop ();
+ ((BlockContent) peek ()).content.add (head);
+ });
+
+ Rule blocks =
+ Rule.one_of ({
+ indented_blocks,
+ table,
+ headline,
+ warning,
+ note,
+ paragraph
+ })
+ .set_name ("Blocks");
+
+ Rule page =
+ Rule.seq ({
+ blocks,
+ Rule.option ({
+ Rule.many ({
+ TokenType.EOL,
+ Rule.option ({ blocks })
+ })
+ })
+ })
+ .set_name ("Page")
+ .set_start (() => { push (_factory.create_page ()); });
+
+ Rule description =
+ Rule.seq ({
+ blocks,
+ Rule.option ({
+ Rule.many ({
+ TokenType.EOL,
+ Rule.option ({ blocks })
+ })
+ })
+ })
+ .set_name ("Description");
+
+ multiline_block_run =
+ Rule.seq ({
+ multiline_run
+ })
+ .set_start (() => { push (_factory.create_paragraph ()); })
+ .set_reduce (() => {
+ Paragraph p = (Paragraph) pop ();
+ ((BlockContent) peek ()).content.add (p);
+ })
+ .set_name ("BlockMultilineRun");
+
+ Rule taglet =
+ Rule.seq ({
+ TokenType.AROBASE,
+ TokenType.any_word ().action ((token) => {
+
+ string tag_name = token.to_string ();
+ var taglet = _factory.create_taglet (tag_name);
+ if (!(taglet is Block)) {
+ _parser.error (token, "Invalid taglet in this context");
+ }
+ push (taglet);
+
+ Rule? taglet_rule;
+ if (taglet is BlockContent) {
+ taglet_rule = taglet.get_parser_rule (multiline_block_run);
+ } else {
+ taglet_rule = taglet.get_parser_rule (multiline_run);
+ }
+
+ if (taglet_rule != null) {
+ _parser.push_rule (Rule.seq ({ TokenType.SPACE, taglet_rule }));
+ }
+ }),
+ Rule.option ({
+ Rule.many ({ TokenType.EOL })
+ })
+ })
+ .set_name ("Taglet")
+ .set_reduce (() => {
+ var head = (Taglet) pop ();
+ ((Comment) peek ()).taglets.add (head);
+ });
+
+ Rule comment =
+ Rule.seq ({
+ TokenType.EOL,
+ Rule.option ({
+ description
+ }),
+ Rule.option ({
+ Rule.many ({ taglet })
+ })
+ })
+ .set_name ("Comment")
+ .set_start (() => { push (_factory.create_comment ()); });
+
+ _comment_parser.set_root_rule (comment);
+ _wiki_parser.set_root_rule (page);
+ }
+
+#if DEBUG
+ private void dump_stack (string title) {
+ message ("=== Dumping stack: %s ===", title);
+ foreach (Object object in _stack) {
+ message ("%s", object.get_type ().name ());
+ }
+ }
+#endif
+}
diff --git a/libvaladoc/documentation/girmetadata.vala b/libvaladoc/documentation/girmetadata.vala
new file mode 100644
index 000000000..2dbae65e4
--- /dev/null
+++ b/libvaladoc/documentation/girmetadata.vala
@@ -0,0 +1,156 @@
+/* girmetadata.vala
+ *
+ * Copyright (C) 2012-2014 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+using Gee;
+
+
+/**
+ * Metadata reader for GIR files
+ */
+public class Valadoc.GirMetaData : Object {
+ private string? metadata_path = null;
+ private string? resource_dir = null;
+
+
+ public bool is_docbook { private set; get; default = false; }
+ public string index_sgml { private set; get; default = null; }
+ public string index_sgml_online { private set; get; default = null; }
+
+ /**
+ * Used to manipulate paths to resources inside gir-files
+ */
+ public string get_resource_path (string resource) {
+ if (resource_dir == null || metadata_path == null) {
+ return resource;
+ }
+
+ if (Path.is_absolute (resource_dir)) {
+ return Path.build_filename (resource_dir, resource);
+ }
+
+ return Path.build_filename (Path.get_dirname (metadata_path), resource_dir, resource);
+ }
+
+ private string? get_metadata_file_name (string gir_file_path) {
+ string metadata_file_name = Path.get_basename (gir_file_path);
+ int last_dot_pos = metadata_file_name.last_index_of (".");
+ if (last_dot_pos < 0) {
+ return null;
+ }
+
+ metadata_file_name = metadata_file_name.substring (0, last_dot_pos);
+ return metadata_file_name + ".valadoc.metadata";
+ }
+
+ private string? get_metadata_path (string gir_file_path, string[] metadata_dirs) {
+ string? metadata_file_name = get_metadata_file_name (gir_file_path);
+ if (metadata_file_name == null) {
+ return null;
+ }
+
+ // search for metatada at the same location as the gir file
+ string metadata_path = Path.build_filename (Path.get_dirname (gir_file_path), metadata_file_name);
+ if (FileUtils.test (metadata_path, FileTest.IS_REGULAR)) {
+ return metadata_path;
+ }
+
+ foreach (string metadata_dir in metadata_dirs) {
+ metadata_path = Path.build_filename (metadata_dir, metadata_file_name);
+ if (FileUtils.test (metadata_path, FileTest.IS_REGULAR)) {
+ return metadata_path;
+ }
+ }
+
+ return null;
+ }
+
+ private void load_general_metadata (KeyFile key_file, ErrorReporter reporter) throws KeyFileError {
+ foreach (string key in key_file.get_keys ("General")) {
+ switch (key) {
+ case "resources":
+ this.resource_dir = key_file.get_string ("General", "resources");
+ break;
+
+ case "is_docbook":
+ this.is_docbook = key_file.get_boolean ("General", "is_docbook");
+ break;
+
+ case "index_sgml":
+ string tmp = key_file.get_string ("General", "index_sgml");
+ this.index_sgml = Path.build_filename (Path.get_dirname (metadata_path), tmp);
+ break;
+
+ case "index_sgml_online":
+ this.index_sgml_online = key_file.get_string ("General", "index_sgml_online");
+ break;
+
+ default:
+ reporter.simple_warning (metadata_path, "Unknown key 'General.%s'", key);
+ break;
+ }
+ }
+ }
+
+ public GirMetaData (string gir_file_path, string[] metadata_dirs, ErrorReporter reporter) {
+ if (!FileUtils.test (gir_file_path, FileTest.IS_REGULAR)) {
+ return ;
+ }
+
+ metadata_path = get_metadata_path (gir_file_path, metadata_dirs);
+ if (metadata_path == null) {
+ return ;
+ }
+
+ KeyFile key_file;
+
+ try {
+ key_file = new KeyFile ();
+ key_file.load_from_file (metadata_path, KeyFileFlags.NONE);
+ } catch (KeyFileError e) {
+ reporter.simple_error (metadata_path, "%s", e.message);
+ return ;
+ } catch (FileError e) {
+ reporter.simple_error (metadata_path, "%s", e.message);
+ return ;
+ }
+
+ try {
+ foreach (string group in key_file.get_groups ()) {
+ switch (group) {
+ case "General":
+ load_general_metadata (key_file, reporter);
+ break;
+
+ default:
+ reporter.simple_warning (metadata_path, "Unknown group '%s'", group);
+ break;
+ }
+ }
+ } catch (KeyFileError e) {
+ reporter.simple_error (null, "Unable to read file '%s': %s", metadata_path, e.message);
+ }
+
+
+ // Load internal link lut:
+ }
+}
+
diff --git a/libvaladoc/documentation/gtkdoccommentparser.vala b/libvaladoc/documentation/gtkdoccommentparser.vala
new file mode 100644
index 000000000..81dc52a8f
--- /dev/null
+++ b/libvaladoc/documentation/gtkdoccommentparser.vala
@@ -0,0 +1,1668 @@
+/* gtkcommentparser.vala
+ *
+ * Copyright (C) 2011-2014 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.Content;
+using Valadoc.Gtkdoc;
+using Gee;
+
+
+
+public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
+ private Scanner scanner = new Scanner ();
+ 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;
+ private Settings settings;
+ private Api.Tree tree;
+ private Api.Node? element;
+
+ private bool show_warnings;
+ private Api.SourceComment comment;
+ private unowned string instance_param_name;
+
+ private string[]? comment_lines;
+
+ private Regex? is_numeric_regex = null;
+ private Regex? normalize_regex = null;
+ private Regex regex_source_lang = null;
+
+ private Importer.InternalIdRegistrar id_registrar = null;
+ private GirMetaData? current_metadata = null;
+
+ private inline string fix_resource_path (string path) {
+ return this.current_metadata.get_resource_path (path);
+ }
+
+ private void reset (Api.SourceComment comment) {
+ this.scanner.reset (comment.content);
+ this.show_warnings = !comment.file.package.is_package;
+ this.comment_lines = null;
+ this.footnotes.clear ();
+ this.comment = comment;
+ this.current = null;
+ this.stack.clear ();
+ }
+
+ private string normalize (string text) {
+ try {
+ return normalize_regex.replace (text, -1, 0, " ");
+ } catch (RegexError e) {
+ assert_not_reached ();
+ }
+ }
+
+ private bool is_numeric (string str) {
+ return is_numeric_regex.match (str);
+ }
+
+ private void report_unexpected_token (Token got, string expected) {
+ report_warning (got, "Unexpected Token: %s (Expected: %s)".printf (got.to_string (), expected));
+ }
+
+ private void report_warning (Token got, string message) {
+ if (!this.show_warnings) {
+ return ;
+ }
+
+ int startpos = (got.line == 0)? comment.first_column + got.first_column : got.first_column;
+ int endpos = (got.line == 0)? comment.first_column + got.last_column : got.last_column;
+
+ if (this.comment_lines == null) {
+ this.comment_lines = this.comment.content.split ("\n");
+ }
+
+ this.reporter.warning (this.comment.file.get_name (),
+ comment.first_line + got.line,
+ startpos + 1,
+ endpos + 1,
+ this.comment_lines[got.line],
+ message);
+ }
+
+ public Parser (Settings settings, ErrorReporter reporter, Api.Tree tree, ModuleLoader modules) {
+ this.factory = new ContentFactory (settings, this, modules);
+ this.reporter = reporter;
+ this.settings = settings;
+ this.tree = tree;
+
+ try {
+ is_numeric_regex = new Regex ("^[+-]?([0-9]*\\.?[0-9]+|[0-9]+\\.?[0-9]*)([eE][+-]?[0-9]+)?$",
+ RegexCompileFlags.OPTIMIZE);
+ normalize_regex = new Regex ("( |\n|\t)+", RegexCompileFlags.OPTIMIZE);
+ regex_source_lang = new Regex ("^<!--[ \t]+language=\"([A-Za-z]*)\"[ \t]+-->");
+ } catch (RegexError e) {
+ assert_not_reached ();
+ }
+ }
+
+ private Note? _parse_note (Api.SourceComment comment) {
+ Comment? cmnt = parse_root_content (comment);
+ if (cmnt == null) {
+ return null;
+ }
+
+ Note note = factory.create_note ();
+ note.content.add_all (cmnt.content);
+
+ return note;
+ }
+
+ private void add_note (ref Comment? comment, Note? note) {
+ if (note == null) {
+ return ;
+ }
+
+ if (comment == null) {
+ comment = factory.create_comment ();
+ }
+
+ if (comment.content.size == 0) {
+ comment.content.add (factory.create_paragraph ());
+ }
+
+ comment.content.insert (1, note);
+ }
+
+ private void add_taglet (ref Comment? comment, Taglet? taglet) {
+ if (taglet == null) {
+ return ;
+ }
+
+ if (comment == null) {
+ comment = factory.create_comment ();
+ }
+
+ comment.taglets.add (taglet);
+ }
+
+ public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment, GirMetaData gir_metadata, Importer.InternalIdRegistrar id_registrar) {
+ this.instance_param_name = gir_comment.instance_param_name;
+ this.current_metadata = gir_metadata;
+ this.id_registrar = id_registrar;
+ this.element = element;
+
+
+ Comment? cmnt = parse_root_content (gir_comment);
+ if (cmnt != null) {
+ ImporterHelper.extract_short_desc (cmnt, factory);
+ }
+
+
+ // deprecated:
+ if (gir_comment.deprecated_comment != null) {
+ Note? note = _parse_note (gir_comment.deprecated_comment);
+ add_note (ref cmnt, note);
+ }
+
+
+ // version:
+ if (gir_comment.version_comment != null) {
+ Note? note = _parse_note (gir_comment.version_comment);
+ add_note (ref cmnt, note);
+ }
+
+ // stability:
+ if (gir_comment.stability_comment != null) {
+ Note? note = _parse_note (gir_comment.stability_comment);
+ add_note (ref cmnt, note);
+ }
+
+
+ // return:
+ if (gir_comment.return_comment != null) {
+ Taglet? taglet = parse_block_taglet (gir_comment.return_comment, "return");
+ add_taglet (ref cmnt, taglet);
+ }
+
+
+ // parameters:
+ MapIterator<string, Api.SourceComment> iter = gir_comment.parameter_iterator ();
+ for (bool has_next = iter.next (); has_next; has_next = iter.next ()) {
+ Taglets.Param? taglet = parse_block_taglet (iter.get_value (), "param") as Taglets.Param;
+ string param_name = iter.get_key ();
+
+ taglet.is_c_self_param = (param_name == gir_comment.instance_param_name);
+ taglet.parameter_name = param_name;
+ add_taglet (ref cmnt, 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 ();
+ cmnt.content.add (p);
+ }
+
+ p.content.insert (0, factory.create_text ("\n"));
+ }
+ cmnt.content.add_all (note);
+ first = false;
+ }
+
+ return cmnt;
+ }
+
+ private Taglet? parse_block_taglet (Api.SourceComment gir_comment, string taglet_name) {
+ this.reset (gir_comment);
+ current = null;
+ next ();
+
+ parse_docbook_spaces (false);
+ var ic = parse_inline_content ();
+ parse_docbook_spaces (false);
+
+ if (current.type != TokenType.EOF) {
+ this.report_unexpected_token (current, "<EOF>");
+ return null;
+ }
+
+ BlockContent? taglet = factory.create_taglet (taglet_name) as BlockContent;
+ assert (taglet != null);
+ Paragraph paragraph = factory.create_paragraph ();
+ paragraph.content.add (ic);
+ taglet.content.add (paragraph);
+ return taglet as Taglet;
+ }
+
+ private Comment? parse_root_content (Api.SourceComment gir_comment) {
+ this.reset (gir_comment);
+ current = null;
+
+ next ();
+
+ Token tmp = null;
+ parse_docbook_spaces (false);
+
+ Comment comment = factory.create_comment ();
+ while (current.type != TokenType.EOF && tmp != current) {
+ tmp = current;
+ var ic = parse_inline_content ();
+ if (ic != null && ic.content.size > 0) {
+ Paragraph p = factory.create_paragraph ();
+ p.content.add (ic);
+ comment.content.add (p);
+ }
+
+ var bc = parse_block_content ();
+ if (bc != null && bc.size > 0) {
+ comment.content.add_all (bc);
+ }
+ }
+
+ if (current.type != TokenType.EOF) {
+ this.report_unexpected_token (current, "<INLINE|BLOCK>");
+ return null;
+ }
+
+ ImporterHelper.extract_short_desc (comment, factory);
+
+ return comment;
+ }
+
+
+
+ //
+ // Common:
+ //
+
+ private Token next () {
+ current = scanner.next ();
+ return current;
+ }
+
+ private bool ignore_current_xml_close () {
+ if (current.type != TokenType.XML_CLOSE) {
+ return false;
+ }
+
+ string name = current.content;
+ if ((name in stack) == false) {
+ return true;
+ }
+
+ return false;
+ }
+
+ private bool check_xml_open_tag (string tagname) {
+ if ((current.type == TokenType.XML_OPEN && current.content != tagname)
+ || current.type != TokenType.XML_OPEN)
+ {
+ return false;
+ }
+
+ stack.offer_head (tagname);
+ return true;
+ }
+
+ private bool check_xml_close_tag (string tagname) {
+ if ((current.type == TokenType.XML_CLOSE && current.content != tagname)
+ || current.type != TokenType.XML_CLOSE)
+ {
+ return false;
+ }
+
+ if (stack.poll_head () == tagname) {
+ stack.peek_head ();
+ }
+
+ return true;
+ }
+
+
+ private void parse_docbook_spaces (bool accept_paragraphs = true) {
+ while (true) {
+ if (current.type == TokenType.SPACE) {
+ next ();
+ } else if (current.type == TokenType.NEWLINE) {
+ next ();
+ } else if (accept_paragraphs && current.type == TokenType.GTKDOC_PARAGRAPH) {
+ next ();
+ } else {
+ break;
+ }
+ }
+ }
+
+
+
+ //
+ // Rules, Ground:
+ //
+
+ private Inline? parse_docbook_link_tempalte (string tagname, bool is_internal) {
+ if (!check_xml_open_tag (tagname)) {
+ this.report_unexpected_token (current, "<%s>".printf (tagname));
+ return null;
+ }
+
+ StringBuilder builder = new StringBuilder ();
+ string url = current.attributes.get ("linkend");
+ next ();
+
+ // TODO: check xml
+ 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) {
+ } else {
+ builder.append (current.content);
+ }
+
+ next ();
+ }
+
+ var link = factory.create_link ();
+ if (is_internal) {
+ link.id_registrar = id_registrar;
+ }
+ link.url = url;
+
+ if (builder.len == 0) {
+ link.content.add (factory.create_text (url));
+ } else {
+ link.content.add (factory.create_text (normalize (builder.str)));
+ }
+
+ if (!check_xml_close_tag (tagname)) {
+ this.report_unexpected_token (current, "</%s>".printf (tagname));
+ return link;
+ }
+
+ next ();
+ return link;
+ }
+
+ private InlineTaglet? parse_symbol_link (string tagname) {
+ if (!check_xml_open_tag (tagname)) {
+ this.report_unexpected_token (current, "<%s>".printf (tagname));
+ return null;
+ }
+
+ if (next ().type == TokenType.SPACE) {
+ next ();
+ }
+
+ InlineTaglet? taglet = null;
+
+ if (current.type == TokenType.WORD && current.content == "struct") {
+ next ();
+
+ if (next ().type == TokenType.SPACE) {
+ next ();
+ }
+ }
+
+
+ if (current.type == TokenType.GTKDOC_FUNCTION || current.type == TokenType.GTKDOC_CONST
+ || current.type == TokenType.GTKDOC_TYPE || current.type == TokenType.WORD
+ || current.type == TokenType.GTKDOC_PROPERTY || current.type == TokenType.GTKDOC_SIGNAL)
+ {
+ taglet = this.create_type_link (current.content) as InlineTaglet;
+ assert (taglet != null);
+ }
+
+ if (next ().type == TokenType.SPACE) {
+ next ();
+ }
+
+ if (!check_xml_close_tag (tagname)) {
+ this.report_unexpected_token (current, "</%s>".printf (tagname));
+ return taglet;
+ }
+
+ next ();
+ return taglet;
+ }
+
+ private void parse_anchor () {
+ if (!check_xml_open_tag ("anchor")) {
+ this.report_unexpected_token (current, "<anchor>");
+ return;
+ }
+
+ string id = current.attributes.get ("id");
+ if (id != null) {
+ id_registrar.register_symbol (id, element);
+ }
+ next ();
+
+ if (!check_xml_close_tag ("anchor")) {
+ this.report_unexpected_token (current, "</anchor>");
+ return;
+ }
+
+ next ();
+ }
+
+ private Link? parse_xref () {
+ if (!check_xml_open_tag ("xref")) {
+ this.report_unexpected_token (current, "<xref>");
+ return null;
+ }
+
+ string linkend = current.attributes.get ("linkend");
+ next ();
+
+ Link link = factory.create_link ();
+ link.content.add (factory.create_text (linkend));
+ link.id_registrar = id_registrar;
+ link.url = linkend;
+
+ if (!check_xml_close_tag ("xref")) {
+ this.report_unexpected_token (current, "</xref>");
+ return link;
+ }
+
+ next ();
+ return link;
+ }
+
+ private Run? parse_highlighted_template (string tag_name, Run.Style style) {
+ if (!check_xml_open_tag (tag_name)) {
+ this.report_unexpected_token (current, "<%s>".printf (tag_name));
+ return null;
+ }
+
+ next ();
+ Run run = parse_inline_content ();
+ if (run.style != Run.Style.NONE && run.style != style) {
+ Run tmp = factory.create_run (style);
+ tmp.content.add (run);
+ run = tmp;
+ } else {
+ run.style = style;
+ }
+
+ if (!check_xml_close_tag (tag_name)) {
+ this.report_unexpected_token (current, "</%s>".printf (tag_name));
+ return run;
+ }
+
+ next ();
+ return run;
+ }
+
+ private ListItem? parse_docbook_listitem () {
+ if (!check_xml_open_tag ("listitem")) {
+ this.report_unexpected_token (current, "<listitem>");
+ return null;
+ }
+
+ next ();
+
+ ListItem item = factory.create_list_item ();
+
+ item.content.add_all (parse_mixed_content ());
+
+ if (!check_xml_close_tag ("listitem")) {
+ this.report_unexpected_token (current, "</listitem>");
+ return item;
+ }
+
+ next ();
+ return item;
+ }
+
+ private BlockContent? parse_docbook_information_box_template (string tagname, BlockContent container) {
+ if (!check_xml_open_tag (tagname)) {
+ this.report_unexpected_token (current, "<%s>".printf (tagname));
+ return null;
+ }
+
+ next ();
+ parse_docbook_spaces ();
+
+ Token tmp = null;
+ while (current.type != TokenType.XML_CLOSE && current.type != TokenType.EOF) {
+ tmp = current;
+ var ic = parse_inline_content ();
+ if (ic != null && ic.content.size > 0) {
+ Paragraph p = factory.create_paragraph ();
+ p.content.add (ic);
+ container.content.add (p);
+ }
+
+ var bc = parse_block_content ();
+ if (bc != null && bc.size > 0) {
+ container.content.add_all (bc);
+ }
+ }
+
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag (tagname)) {
+ this.report_unexpected_token (current, "</%s>".printf (tagname));
+ return container;
+ }
+
+ next ();
+ return container;
+ }
+
+ private Note? parse_docbook_important () {
+ return (Note?) parse_docbook_information_box_template ("important", factory.create_note ());
+ }
+
+ private Note? parse_docbook_note () {
+ return (Note?) parse_docbook_information_box_template ("note", factory.create_note ());
+ }
+
+ private Warning? parse_docbook_warning () {
+ return (Warning?) parse_docbook_information_box_template ("warning", factory.create_warning ());
+ }
+
+ private inline LinkedList<Block>? parse_docbook_orderedlist () {
+ return parse_docbook_itemizedlist ("orderedlist", Content.List.Bullet.ORDERED);
+ }
+
+ private LinkedList<Block>? parse_docbook_itemizedlist (string tag_name = "itemizedlist",
+ Content.List.Bullet bullet_type = Content.List.Bullet.UNORDERED)
+ {
+ if (!check_xml_open_tag (tag_name)) {
+ this.report_unexpected_token (current, "<%s>".printf (tag_name));
+ return null;
+ }
+ next ();
+
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+ parse_docbook_spaces ();
+
+ if (current.type == TokenType.XML_OPEN && current.content == "title") {
+ append_block_content_not_null (content, parse_docbook_title ());
+ parse_docbook_spaces ();
+ }
+
+ Content.List list = factory.create_list ();
+ list.bullet = bullet_type;
+ content.add (list);
+
+ while (current.type == TokenType.XML_OPEN) {
+ if (current.content == "listitem") {
+ list.items.add (parse_docbook_listitem ());
+ } else {
+ break;
+ }
+
+ parse_docbook_spaces ();
+ }
+
+ if (!check_xml_close_tag (tag_name)) {
+ this.report_unexpected_token (current, "</%s>".printf (tag_name));
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private Paragraph? parse_gtkdoc_paragraph () {
+ if (current.type != TokenType.GTKDOC_PARAGRAPH) {
+ this.report_unexpected_token (current, "<GTKDOC-PARAGRAPH>");
+ return null;
+ }
+
+ next ();
+
+ Paragraph p = factory.create_paragraph ();
+
+ Run? run = parse_inline_content ();
+ p.content.add (run);
+ return p;
+ }
+
+ private LinkedList<Block> parse_mixed_content () {
+ LinkedList<Block> content = new LinkedList<Block> ();
+ 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 && lst.size > 0) {
+ content.add_all (lst);
+ continue;
+ }
+ }
+
+ return content;
+ }
+
+ private inline LinkedList<Block>? parse_docbook_simpara () {
+ return parse_docbook_para ("simpara");
+ }
+
+ private LinkedList<Block>? parse_docbook_para (string tag_name = "para") {
+ if (!check_xml_open_tag (tag_name)) {
+ this.report_unexpected_token (current, "<%s>".printf (tag_name));
+ return null;
+ }
+
+ next ();
+
+ LinkedList<Block> content = parse_mixed_content ();
+
+ // ignore missing </para> to match gtkdocs behaviour
+ if (!check_xml_close_tag (tag_name) && current.type != TokenType.EOF) {
+ this.report_unexpected_token (current, "</%s>".printf (tag_name));
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private Paragraph? parse_gtkdoc_source () {
+ if (current.type != TokenType.GTKDOC_SOURCE_OPEN) {
+ this.report_unexpected_token (current, "|[");
+ return null;
+ }
+
+ StringBuilder builder = new StringBuilder ();
+ Token source_token = current;
+
+ for (next (); current.type != TokenType.EOF && current.type != TokenType.GTKDOC_SOURCE_CLOSE; next ()) {
+ if (current.type == TokenType.WORD) {
+ builder.append (current.content);
+ } else if (current.type != TokenType.XML_COMMENT) {
+ builder.append_len (current.start, current.length);
+ }
+ }
+
+ SourceCode code = factory.create_source_code ();
+ MatchInfo info;
+
+ unowned string source = builder.str;
+ if (regex_source_lang.match (source, 0, out info)) {
+ string lang_name = info.fetch (1).down ();
+ SourceCode.Language? lang = SourceCode.Language.from_string (lang_name);
+ code.language = lang;
+
+ if (lang == null) {
+ report_warning (source_token, "Unknown language `%s' in source code block |[<!-- language=\"\"".printf (lang_name));
+ }
+
+ source = source.offset (source.index_of_char ('>') + 1);
+ } else {
+ code.language = (Highlighter.XmlScanner.is_xml (source))
+ ? SourceCode.Language.XML
+ : SourceCode.Language.C;
+ }
+ code.code = source;
+
+ Paragraph p = factory.create_paragraph ();
+ p.content.add (code);
+
+ if (current.type != TokenType.GTKDOC_SOURCE_CLOSE) {
+ this.report_unexpected_token (current, "|]");
+ return p;
+ }
+
+ next ();
+ return p;
+ }
+
+ private Paragraph? parse_docbook_title () {
+ if (!check_xml_open_tag ("title")) {
+ this.report_unexpected_token (current, "<title>");
+ return null;
+ }
+
+ next ();
+
+ Paragraph p = factory.create_paragraph ();
+ Run content = parse_inline_content ();
+ content.content.add (factory.create_text (":"));
+ content.style = Run.Style.BOLD;
+ p.content.add (content);
+
+ if (!check_xml_close_tag ("title")) {
+ this.report_unexpected_token (current, "</title>");
+ return p;
+ }
+
+ next ();
+ return p;
+ }
+
+ private Paragraph? parse_docbook_graphic () {
+ var tmp = parse_docbook_inlinegraphic ("graphic");
+ if (tmp == null) {
+ return null;
+ }
+
+ Paragraph? p = factory.create_paragraph ();
+ p.content.add (tmp);
+ return p;
+ }
+
+ private Embedded? parse_docbook_inlinegraphic (string tag_name = "inlinegraphic") {
+ if (!check_xml_open_tag (tag_name)) {
+ this.report_unexpected_token (current, "<%s>".printf (tag_name));
+ return null;
+ }
+
+ Embedded e = factory.create_embedded ();
+ e.url = fix_resource_path (current.attributes.get ("fileref"));
+
+ next ();
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag (tag_name)) {
+ this.report_unexpected_token (current, "</%s>".printf (tag_name));
+ return e;
+ }
+
+ next ();
+ return e;
+ }
+
+ private Paragraph? parse_docbook_programlisting () {
+ if (!check_xml_open_tag ("programlisting")) {
+ this.report_unexpected_token (current, "<programlisting>");
+ return null;
+ }
+
+ StringBuilder builder = new StringBuilder ();
+
+ for (next (); current.type != TokenType.EOF && !(current.type == TokenType.XML_CLOSE
+ && current.content == "programlisting"); next ())
+ {
+ if (current.type == TokenType.WORD) {
+ builder.append (current.content);
+ } else if (current.type != TokenType.XML_COMMENT) {
+ builder.append_len (current.start, current.length);
+ }
+ }
+
+ SourceCode src = factory.create_source_code ();
+ src.language = SourceCode.Language.C;
+ src.code = builder.str;
+
+ Paragraph p = factory.create_paragraph ();
+ p.content.add (src);
+
+ if (!check_xml_close_tag ("programlisting")) {
+ this.report_unexpected_token (current, "</programlisting>");
+ return p;
+ }
+
+ next ();
+ return p;
+ }
+
+/*
+ private LinkedList<Block>? parse_docbook_informalexample () {
+ if (!check_xml_open_tag ("informalexample")) {
+ this.report_unexpected_token (current, "<informalexample>");
+ return null;
+ }
+
+ next ();
+
+ parse_docbook_spaces ();
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+
+ if (current.type == TokenType.XML_OPEN && current.content == "title") {
+ append_block_content_not_null (content, parse_docbook_title ());
+ parse_docbook_spaces ();
+ }
+
+ 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 == "inlinegraphic") {
+ Embedded? img = parse_docbook_inlinegraphic ();
+ Paragraph p = factory.create_paragraph ();
+ append_block_content_not_null (content, p);
+ p.content.add (img);
+
+ }
+
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag ("informalexample")) {
+ this.report_unexpected_token (current, "</informalexample>");
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+*/
+
+ private inline LinkedList<Block>? parse_docbook_informalexample () {
+ return parse_docbook_example ("informalexample");
+ }
+
+ private LinkedList<Block>? parse_docbook_example (string tag_name = "example") {
+ if (!check_xml_open_tag (tag_name)) {
+ this.report_unexpected_token (current, "<%s>".printf (tag_name));
+ return null;
+ }
+
+ next ();
+
+ parse_docbook_spaces ();
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+
+ content.add_all (parse_mixed_content ());
+
+ /*
+ while (current.type == TokenType.XML_OPEN) {
+ if (current.type == TokenType.XML_OPEN && current.content == "inlinegraphic") {
+ Paragraph p = factory.create_paragraph ();
+ while (current.type == TokenType.XML_OPEN && current.content == "inlinegraphic") {
+ p.content.add (parse_docbook_inlinegraphic ());
+ parse_docbook_spaces ();
+ }
+ } else 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 == "para") {
+ this.append_block_content_not_null_all (content, parse_docbook_para ());
+ } else {
+ break;
+ }
+
+ parse_docbook_spaces ();
+ } */
+
+ if (!check_xml_close_tag (tag_name)) {
+ this.report_unexpected_token (current, "</%s>".printf (tag_name));
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private LinkedList<Block>? parse_docbook_refsect2 (int nr = 2) {
+ if (!check_xml_open_tag ("refsect%d".printf (nr))) {
+ this.report_unexpected_token (current, "<refsect%d>".printf (nr));
+ return null;
+ }
+
+ string id = current.attributes.get ("id");
+ if (id != null) {
+ id_registrar.register_symbol (id, element);
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+
+ this.append_block_content_not_null_all (content, parse_mixed_content ());
+
+ if (!check_xml_close_tag ("refsect%d".printf (nr))) {
+ this.report_unexpected_token (current, "</refsect%d>".printf (nr));
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private LinkedList<Block>? parse_docbook_figure () {
+ if (!check_xml_open_tag ("figure")) {
+ this.report_unexpected_token (current, "<figure>");
+ return null;
+ }
+ next ();
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+ parse_docbook_spaces ();
+
+ if (current.type == TokenType.XML_OPEN && current.content == "title") {
+ append_block_content_not_null (content, parse_docbook_title ());
+ parse_docbook_spaces ();
+ }
+
+ while (current.type == TokenType.XML_OPEN) {
+ if (current.content == "inlinegraphic") {
+ Paragraph p = (content.size > 0)? content[0] as Paragraph : null;
+ if (p == null) {
+ p = factory.create_paragraph ();
+ }
+
+ while (current.type == TokenType.XML_OPEN && current.content == "inlinegraphic") {
+ p.content.add (parse_docbook_inlinegraphic ());
+ parse_docbook_spaces ();
+ }
+ } else if (current.content == "graphic") {
+ append_block_content_not_null (content, parse_docbook_graphic ());
+ } else {
+ break;
+ }
+
+ parse_docbook_spaces ();
+ }
+
+ if (!check_xml_close_tag ("figure")) {
+ this.report_unexpected_token (current, "</figure>");
+ return content;
+ }
+
+ next ();
+ 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);
+
+ content.add_all (parse_mixed_content ());
+
+ Paragraph? first = (content.is_empty)? null : 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);
+ }
+ }
+
+ private inline void append_block_content_not_null (LinkedList<Block> run, Block? element) {
+ if (element != null) {
+ run.add (element);
+ }
+ }
+
+ private TableRow? parse_docbook_thead () {
+ if (!check_xml_open_tag ("thead")) {
+ this.report_unexpected_token (current, "<thead>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+ TableRow? row = parse_docbook_row (Run.Style.BOLD);
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag ("thead")) {
+ this.report_unexpected_token (current, "</thead>");
+ return row;
+ }
+
+ next ();
+ return row;
+ }
+
+ private TableCell? parse_docbook_entry (Run.Style default_style = Run.Style.NONE) {
+ if (!check_xml_open_tag ("entry")) {
+ this.report_unexpected_token (current, "<entry>");
+ return null;
+ }
+ next ();
+
+ TableCell cell = factory.create_table_cell ();
+ Run run = factory.create_run (default_style);
+ run.content.add (parse_inline_content ());
+ cell.content.add (run);
+
+ if (!check_xml_close_tag ("entry")) {
+ this.report_unexpected_token (current, "</entry>");
+ return cell;
+ }
+
+ next ();
+ return cell;
+ }
+
+ private TableRow? parse_docbook_row (Run.Style default_style = Run.Style.NONE) {
+ if (!check_xml_open_tag ("row")) {
+ this.report_unexpected_token (current, "<row>");
+ return null;
+ }
+ next ();
+
+ TableRow row = factory.create_table_row ();
+ parse_docbook_spaces ();
+
+ while (current.type == TokenType.XML_OPEN && current.content == "entry") {
+ TableCell? table_cell = parse_docbook_entry (default_style);
+ if (table_cell == null) {
+ break;
+ }
+
+ row.cells.add (table_cell);
+ parse_docbook_spaces ();
+ }
+
+ if (!check_xml_close_tag ("row")) {
+ this.report_unexpected_token (current, "</row>");
+ return row;
+ }
+
+ next ();
+ return row;
+ }
+
+ private LinkedList<TableRow>? parse_docbook_tbody () {
+ if (!check_xml_open_tag ("tbody")) {
+ this.report_unexpected_token (current, "<tbody>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ LinkedList<TableRow> rows = new LinkedList<TableRow> ();
+ while (current.type == TokenType.XML_OPEN && current.content == "row") {
+ TableRow? row = parse_docbook_row ();
+ if (row == null) {
+ break;
+ }
+
+ parse_docbook_spaces ();
+ rows.add (row);
+ }
+
+
+ if (!check_xml_close_tag ("tbody")) {
+ this.report_unexpected_token (current, "</tbody>");
+ return rows;
+ }
+
+ next ();
+ return rows;
+ }
+
+ private Table? parse_docbook_tgroup () {
+ if (!check_xml_open_tag ("tgroup")) {
+ this.report_unexpected_token (current, "<tgroup>");
+ return null;
+ }
+ next ();
+
+ Table table = factory.create_table ();
+ parse_docbook_spaces ();
+
+ if (current.type == TokenType.XML_OPEN && current.content == "thead") {
+ TableRow? row = parse_docbook_thead ();
+ if (row != null) {
+ parse_docbook_spaces ();
+ table.rows.add (row);
+ }
+
+ parse_docbook_spaces ();
+ }
+
+ if (current.type == TokenType.XML_OPEN && current.content == "tbody") {
+ LinkedList<TableRow>? rows = parse_docbook_tbody ();
+ if (rows != null) {
+ table.rows.add_all (rows);
+ }
+
+ parse_docbook_spaces ();
+ }
+
+ if (!check_xml_close_tag ("tgroup")) {
+ this.report_unexpected_token (current, "</tgroup>");
+ return table;
+ }
+
+ next ();
+ return table;
+ }
+
+ private Table? parse_docbook_informaltable () {
+ if (!check_xml_open_tag ("informaltable")) {
+ this.report_unexpected_token (current, "<informaltable>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+ Table? table = this.parse_docbook_tgroup ();
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag ("informaltable")) {
+ this.report_unexpected_token (current, "</informaltable>");
+ return table;
+ }
+
+ next ();
+ return table;
+ }
+
+ private LinkedList<Block>? parse_docbook_section () {
+ if (!check_xml_open_tag ("section")) {
+ this.report_unexpected_token (current, "<section>");
+ return null;
+ }
+
+ string id = current.attributes.get ("id");
+ if (id != null) {
+ id_registrar.register_symbol (id, element);
+ }
+ next ();
+
+ LinkedList<Block> content = parse_mixed_content ();
+
+ if (!check_xml_close_tag ("section")) {
+ this.report_unexpected_token (current, "</section>");
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private ListItem? parse_docbook_member () {
+ if (!check_xml_open_tag ("member")) {
+ this.report_unexpected_token (current, "<member>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ ListItem item = factory.create_list_item ();
+ Paragraph para = factory.create_paragraph ();
+ item.content.add (para);
+
+ para.content.add (parse_inline_content ());
+
+ parse_docbook_spaces ();
+
+ if (!check_xml_close_tag ("member")) {
+ this.report_unexpected_token (current, "</member>");
+ return item;
+ }
+
+ next ();
+ return item;
+ }
+
+ private Content.List? parse_docbook_simplelist () {
+ if (!check_xml_open_tag ("simplelist")) {
+ this.report_unexpected_token (current, "<simplelist>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ Content.List list = factory.create_list ();
+
+ while (current.type == TokenType.XML_OPEN && current.content == "member") {
+ ListItem item = parse_docbook_member ();
+ if (item == null) {
+ break;
+ }
+
+ list.items.add (item);
+ parse_docbook_spaces ();
+ }
+
+
+ if (!check_xml_close_tag ("simplelist")) {
+ this.report_unexpected_token (current, "</simplelist>");
+ return list;
+ }
+
+ next ();
+ return list;
+ }
+
+ private Paragraph? parse_docbook_term () {
+ if (!check_xml_open_tag ("term")) {
+ this.report_unexpected_token (current, "<term>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ Paragraph? p = factory.create_paragraph ();
+ Run run = parse_inline_content ();
+ run.style = Run.Style.ITALIC;
+ p.content.add (run);
+
+ if (!check_xml_close_tag ("term")) {
+ this.report_unexpected_token (current, "</term>");
+ return p;
+ }
+
+ next ();
+ return p;
+ }
+
+ private ListItem? parse_docbook_varlistentry () {
+ if (!check_xml_open_tag ("varlistentry")) {
+ this.report_unexpected_token (current, "<varlistentry>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ if (current.type != TokenType.XML_OPEN || current.content != "term") {
+ return null;
+ }
+
+ Paragraph? term = parse_docbook_term ();
+ if (term == null) {
+ return null;
+ }
+
+ parse_docbook_spaces ();
+ ListItem? desc = parse_docbook_listitem ();
+ if (desc == null) {
+ return null;
+ }
+
+ parse_docbook_spaces ();
+
+ Content.ListItem listitem = factory.create_list_item ();
+ Content.List list = factory.create_list ();
+
+ listitem.content.add (term);
+ listitem.content.add (list);
+ list.items.add (desc);
+
+ if (!check_xml_close_tag ("varlistentry")) {
+ this.report_unexpected_token (current, "</varlistentry>");
+ return listitem;
+ }
+
+ next ();
+ return listitem;
+ }
+
+ private LinkedList<Block>? parse_docbook_variablelist () {
+ if (!check_xml_open_tag ("variablelist")) {
+ this.report_unexpected_token (current, "<variablelist>");
+ return null;
+ }
+ next ();
+
+ parse_docbook_spaces ();
+
+ LinkedList<Block> content = new LinkedList<Block> ();
+
+ if (current.type == TokenType.XML_OPEN && current.content == "title") {
+ append_block_content_not_null (content, parse_docbook_title ());
+ parse_docbook_spaces ();
+ }
+
+ Content.List list = factory.create_list ();
+ content.add (list);
+
+ while (current.type == TokenType.XML_OPEN && current.content == "varlistentry") {
+ ListItem item = parse_docbook_varlistentry ();
+ if (item == null) {
+ break;
+ }
+
+ list.items.add (item);
+ parse_docbook_spaces ();
+ }
+
+ if (!check_xml_close_tag ("variablelist")) {
+ this.report_unexpected_token (current, "</variablelist>");
+ return content;
+ }
+
+ next ();
+ return content;
+ }
+
+ private LinkedList<Block> parse_block_content () {
+ LinkedList<Block> content = new LinkedList<Block> ();
+
+ while (current.type != TokenType.EOF) {
+ parse_docbook_spaces (false);
+
+ if (current.type == TokenType.XML_OPEN && current.content == "itemizedlist") {
+ this.append_block_content_not_null_all (content, parse_docbook_itemizedlist ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "orderedlist") {
+ this.append_block_content_not_null_all (content, parse_docbook_orderedlist ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "variablelist") {
+ this.append_block_content_not_null_all (content, parse_docbook_variablelist ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "simplelist") {
+ this.append_block_content_not_null (content, parse_docbook_simplelist ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "informaltable") {
+ this.append_block_content_not_null (content, parse_docbook_informaltable ());
+ } 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 == "simpara") {
+ this.append_block_content_not_null_all (content, parse_docbook_simpara ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "informalexample") {
+ this.append_block_content_not_null_all (content, parse_docbook_informalexample ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "example") {
+ this.append_block_content_not_null_all (content, parse_docbook_example ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "warning") {
+ this.append_block_content_not_null (content, parse_docbook_warning ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "note") {
+ this.append_block_content_not_null (content, parse_docbook_note ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "important") {
+ this.append_block_content_not_null (content, parse_docbook_important ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "refsect3") {
+ this.append_block_content_not_null_all (content, parse_docbook_refsect2 (3));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "refsect2") {
+ this.append_block_content_not_null_all (content, parse_docbook_refsect2 ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "figure") {
+ this.append_block_content_not_null_all (content, parse_docbook_figure ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "title") {
+ this.append_block_content_not_null (content, parse_docbook_title ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "section") {
+ this.append_block_content_not_null_all (content, parse_docbook_section ());
+ } else if (current.type == TokenType.GTKDOC_PARAGRAPH) {
+ this.append_block_content_not_null (content, parse_gtkdoc_paragraph ());
+ } else if (current.type == TokenType.GTKDOC_SOURCE_OPEN) {
+ this.append_block_content_not_null (content, parse_gtkdoc_source ());
+ } else {
+ break;
+ }
+ }
+
+ 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;
+
+ if (run.content.size > 0) {
+ last_as_text = run.content.last () as Text;
+ }
+
+ if (last_as_text == null) {
+ run.content.add (factory.create_text (current));
+ } else if (current.has_prefix (" ") && last_as_text.content.has_suffix (" ")) {
+ last_as_text.content += current.chug ();
+ } else {
+ last_as_text.content += current;
+ }
+ }
+
+ private Inline create_type_link (string name, bool c_accept_plural = false) {
+ if (name == "TRUE" || name == "FALSE" || name == "NULL" || is_numeric (name)) {
+ var monospaced = factory.create_run (Run.Style.MONOSPACED);
+ monospaced.content.add (factory.create_text (name.down ()));
+ return monospaced;
+ } else {
+ Taglets.Link? taglet = factory.create_taglet ("link") as Taglets.Link;
+ assert (taglet != null);
+ taglet.c_accept_plural = c_accept_plural;
+ taglet.symbol_name = "c::"+name;
+ return taglet;
+ }
+ }
+
+ private inline void append_inline_content_not_null (Run run, Inline element) {
+ if (element != null) {
+ run.content.add (element);
+ }
+ }
+
+ private Run parse_inline_content () {
+ Run run = factory.create_run (Run.Style.NONE);
+
+ 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 == "abbrev") {
+ append_inline_content_not_null (run, parse_highlighted_template ("abbrev", 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 == "literallayout") {
+ append_inline_content_not_null (run, parse_highlighted_template ("literallayout", Run.Style.MONOSPACED));
+ } 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 == "varname") {
+ append_inline_content_not_null (run, parse_highlighted_template ("varname", Run.Style.MONOSPACED));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "computeroutput") {
+ append_inline_content_not_null (run, parse_highlighted_template ("computeroutput", 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") {
+ append_inline_content_not_null (run, parse_highlighted_template ("option", Run.Style.MONOSPACED));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "keycap") {
+ append_inline_content_not_null (run, parse_highlighted_template ("keycap", Run.Style.MONOSPACED));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "keycombo") {
+ append_inline_content_not_null (run, parse_highlighted_template ("keycombo", Run.Style.MONOSPACED));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "envar") {
+ 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 == "quote") {
+ run.content.add (factory.create_text ("“"));
+ append_inline_content_not_null (run, parse_highlighted_template ("quote", Run.Style.NONE));
+ run.content.add (factory.create_text ("”"));
+ } 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") {
+ append_inline_content_not_null (run, parse_symbol_link ("function"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "classname") {
+ append_inline_content_not_null (run, parse_symbol_link ("classname"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "structname") {
+ append_inline_content_not_null (run, parse_symbol_link ("structname"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "structfield") {
+ append_inline_content_not_null (run, parse_symbol_link ("structfield"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "errorcode") {
+ append_inline_content_not_null (run, parse_symbol_link ("errorcode"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "constant") {
+ append_inline_content_not_null (run, parse_symbol_link ("constant"));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "inlinegraphic") {
+ append_inline_content_not_null (run, parse_docbook_inlinegraphic ());
+ } else if (current.type == TokenType.XML_OPEN && current.content == "anchor") {
+ parse_anchor ();
+ } else if (current.type == TokenType.XML_OPEN && current.content == "link") {
+ append_inline_content_not_null (run, parse_docbook_link_tempalte ("link", true));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "ulink") {
+ append_inline_content_not_null (run, parse_docbook_link_tempalte ("ulink", false));
+ } else if (current.type == TokenType.XML_OPEN && current.content == "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 ();
+ } else if (current.type == TokenType.GTKDOC_PARAM) {
+ if (current.content == instance_param_name) {
+ Content.Run keyword_run = factory.create_run (Content.Run.Style.LANG_KEYWORD);
+ Content.Text text = factory.create_text ("this");
+ keyword_run.content.add (text);
+ run.content.add (keyword_run);
+ } else {
+ string? param_array_name;
+ bool is_return_type_len;
+ string? param_name;
+
+ string? cname = ImporterHelper.resolve_parameter_ctype (
+ this.tree,
+ this.element,
+ current.content,
+ out param_name,
+ out param_array_name,
+ out is_return_type_len);
+
+ Run current_run = factory.create_run (Run.Style.MONOSPACED);
+ run.content.add (current_run);
+
+ if (is_return_type_len) {
+ Run keyword_run = factory.create_run (Run.Style.LANG_KEYWORD);
+ keyword_run.content.add (factory.create_text ("return"));
+ current_run.content.add (keyword_run);
+
+ current_run.content.add (factory.create_text (".length"));
+ } else if (param_array_name != null) {
+ current_run.content.add (factory.create_text (param_array_name + ".length"));
+ } else {
+ current_run.content.add (factory.create_text (param_name));
+ }
+
+ if (cname != null) {
+ run.content.add (factory.create_text ("."));
+
+ Taglets.Link link = factory.create_taglet ("link") as Taglets.Link;
+ link.symbol_name = cname;
+ run.content.add (link);
+ }
+ }
+ next ();
+ } else if (current.type == TokenType.GTKDOC_SIGNAL) {
+ run.content.add (this.create_type_link ("::" + current.content, true));
+ next ();
+ } else if (current.type == TokenType.GTKDOC_PROPERTY) {
+ run.content.add (this.create_type_link (":" + current.content, true));
+ next ();
+ } else if (current.type == TokenType.GTKDOC_CONST) {
+ run.content.add (this.create_type_link (current.content, true));
+ next ();
+ } else if (current.type == TokenType.GTKDOC_TYPE) {
+ run.content.add (this.create_type_link (current.content, true));
+ next ();
+ } else if (current.type == TokenType.NEWLINE || current.type == TokenType.SPACE) {
+ append_inline_content_string (run, " ");
+ next ();
+ } else if (current.type == TokenType.WORD) {
+ append_inline_content_string (run, current.content);
+ next ();
+ } else if (current.type == TokenType.XML_CLOSE && ignore_current_xml_close ()) {
+ next ();
+ } else if (current.type == TokenType.XML_COMMENT) {
+ next ();
+ } else {
+ break;
+ }
+ }
+
+ return run;
+ }
+
+
+
+ //
+ // Resource Locator:
+ //
+
+ public string resolve (string path) {
+ return path;
+ }
+}
+
+
diff --git a/libvaladoc/documentation/gtkdoccommentscanner.vala b/libvaladoc/documentation/gtkdoccommentscanner.vala
new file mode 100644
index 000000000..75f2d58ed
--- /dev/null
+++ b/libvaladoc/documentation/gtkdoccommentscanner.vala
@@ -0,0 +1,890 @@
+/* gtkcommentscanner.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+
+using Valadoc.Gtkdoc;
+using Gee;
+
+
+
+public enum Valadoc.Gtkdoc.TokenType {
+ XML_OPEN,
+ XML_CLOSE,
+ XML_COMMENT,
+ GTKDOC_FUNCTION,
+ GTKDOC_CONST,
+ GTKDOC_TYPE,
+ GTKDOC_PARAM,
+ GTKDOC_SOURCE_OPEN,
+ GTKDOC_SOURCE_CLOSE,
+ GTKDOC_SIGNAL,
+ GTKDOC_PROPERTY,
+ GTKDOC_PARAGRAPH,
+ NEWLINE,
+ SPACE,
+ WORD,
+ EOF
+}
+
+
+public class Valadoc.Gtkdoc.Token {
+ public TokenType type;
+ public string content;
+ public HashMap<string, string>? attributes;
+ public unowned string start;
+ public int length;
+ public int line;
+ public int first_column;
+ public int last_column;
+
+ public Token (TokenType type, string content, HashMap<string, string>? attributes, string start,
+ int length, int line, int first_column, int last_column)
+ {
+ this.attributes = attributes;
+ this.content = content;
+ this.length = length;
+ this.start = start;
+ this.type = type;
+ this.line = line;
+ this.first_column = first_column;
+ this.last_column = last_column;
+ }
+
+ public string to_string () {
+ switch (this.type) {
+ case TokenType.XML_OPEN:
+ return "`<%s>'".printf (this.content);
+
+ case TokenType.XML_CLOSE:
+ return "`</%s>'".printf (this.content);
+
+ case TokenType.XML_COMMENT:
+ return "<XML-COMMENT>";
+
+ case TokenType.GTKDOC_FUNCTION:
+ return "`%s ()'".printf (this.content);
+
+ case TokenType.GTKDOC_CONST:
+ return "`%%%s'".printf (this.content);
+
+ case TokenType.GTKDOC_TYPE:
+ return "`#%s'".printf (this.content);
+
+ case TokenType.GTKDOC_PARAM:
+ return "<GTKDOC-PARAM>";
+
+ case TokenType.GTKDOC_SOURCE_OPEN:
+ return "[|";
+
+ case TokenType.GTKDOC_SOURCE_CLOSE:
+ return "|]";
+
+ case TokenType.GTKDOC_SIGNAL:
+ return "`::%s'".printf (this.content);
+
+ case TokenType.GTKDOC_PROPERTY:
+ return "`:%s'".printf (this.content);
+
+ case TokenType.GTKDOC_PARAGRAPH:
+ return "<GKTDOC-PARAGRAPH>";
+
+ case TokenType.NEWLINE:
+ return "<NEWLNIE>";
+
+ case TokenType.SPACE:
+ return "<SPACE>";
+
+ case TokenType.WORD:
+ return "`%s'".printf (this.content);
+
+ case TokenType.EOF:
+ return "<EOF>";
+
+ default:
+ assert_not_reached ();
+ }
+ }
+}
+
+
+public class Valadoc.Gtkdoc.Scanner {
+ private unowned string content;
+ private unowned string pos;
+ private int column;
+ private int line;
+ private Token tmp_token;
+
+ public Scanner () {
+ }
+
+ public static string unescape (string txt) {
+ StringBuilder builder = new StringBuilder ();
+ unowned string start = txt;
+ unowned string pos;
+ unichar c;
+
+ for (pos = txt; (c = pos.get_char ()) != '\0'; pos = pos.next_char ()) {
+ if (c == '&') {
+ if (pos.has_prefix ("&solidus;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 9);
+ pos = (string) ((char*) pos + 8);
+ builder.append_unichar ('⁄');
+ } else if (pos.has_prefix ("&percnt;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 8);
+ pos = (string) ((char*) pos + 7);
+ builder.append_c ('%');
+ } else if (pos.has_prefix ("&commat;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 8);
+ pos = (string) ((char*) pos + 7);
+ builder.append_c ('@');
+ } else if (pos.has_prefix ("&nbsp;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 6);
+ pos = (string) ((char*) pos + 5);
+ builder.append_c (' ');
+ } else if (pos.has_prefix ("&quot;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 6);
+ pos = (string) ((char*) pos + 5);
+ builder.append_c ('"');
+ } else if (pos.has_prefix ("&apos;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 6);
+ pos = (string) ((char*) pos + 5);
+ builder.append_c ('\'');
+ } else if (pos.has_prefix ("&lpar;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 6);
+ pos = (string) ((char*) pos + 5);
+ builder.append_c ('(');
+ } else if (pos.has_prefix ("&rpar;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 6);
+ pos = (string) ((char*) pos + 5);
+ builder.append_c (')');
+ } else if (pos.has_prefix ("&num;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 5);
+ pos = (string) ((char*) pos + 4);
+ builder.append_c ('#');
+ } else if (pos.has_prefix ("&amp;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 5);
+ pos = (string) ((char*) pos + 4);
+ builder.append_c ('&');
+ } else if (pos.has_prefix ("&ast;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 5);
+ pos = (string) ((char*) pos + 4);
+ builder.append_c ('*');
+ } else if (pos.has_prefix ("&pi;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 4);
+ pos = (string) ((char*) pos + 3);
+ builder.append_unichar ('π');
+ } else if (pos.has_prefix ("&lt;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 4);
+ pos = (string) ((char*) pos + 3);
+ builder.append_c ('<');
+ } else if (pos.has_prefix ("&gt;")) {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ start = (string) ((char*) pos + 4);
+ pos = (string) ((char*) pos + 3);
+ builder.append_c ('>');
+ }
+ }
+ }
+
+ if (&txt == &start) {
+ return txt;
+ } else {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ return (owned) builder.str;
+ }
+ }
+
+ public void reset (string content) {
+ this.content = content;
+ this.tmp_token = null;
+ this.pos = content;
+ this.column = 0;
+ this.line = 0;
+ }
+
+ private inline unichar next_char () {
+ this.pos = this.pos.next_char ();
+ this.column++;
+
+ return this.pos.get_char ();
+ }
+
+ private inline unichar get () {
+ return this.pos.get_char ();
+ }
+
+ private inline bool letter (unichar c) {
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z');
+ }
+
+ private inline bool letter_or_number (unichar c) {
+ return (c >= 'a' && c <= 'z')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= '0' && c <= '9');
+ }
+
+ private inline bool space (unichar c) {
+ return c == ' ' || c == '\t';
+ }
+
+ private inline bool space_or_newline (unichar c) {
+ if (c == '\n') {
+ this.line++;
+ this.column = 0;
+ return true;
+ }
+
+ return space (c);
+ }
+
+ private inline int offset (string a, string b) {
+ return (int) ((char*) a - (char*) b);
+ }
+
+ private inline int vararg_prefix () {
+ if (this.pos.has_prefix ("...")) {
+ next_char ();
+ next_char ();
+ next_char ();
+ return 3;
+ }
+
+ return 0;
+ }
+
+ private inline int id_prefix () {
+ unichar c = get ();
+
+ if (!letter (c) && c != '_') {
+ return 0;
+ }
+
+ int start = this.column;
+ while ((c = next_char ()) == '_' || letter_or_number (c));
+ return this.column - start;
+ }
+
+ private inline int g_id_prefix () {
+ unowned string start = this.pos;
+ unichar c = get ();
+
+ if (!letter (c)) {
+ return 0;
+ }
+
+ while ((c = next_char ()) == '_' || c == '-' || letter_or_number (c));
+ return offset (this.pos, start);
+ }
+
+ private inline int skip_spaces_and_newlines () {
+ unowned string start = this.pos;
+ if (space_or_newline (get ())) {
+ while (space_or_newline (next_char ()));
+ }
+
+ return offset (this.pos, start);
+ }
+
+ private inline Token? function_prefix () {
+ unowned string start = this.pos;
+ int column_start = this.column;
+ int id_len = 0;
+
+ if ((id_len = id_prefix ()) == 0) {
+ return null;
+ }
+
+ space_prefix ();
+
+ if (get () != '(') {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ next_char ();
+ space_prefix ();
+
+ if (get () != ')') {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ next_char ();
+ return new Token (TokenType.GTKDOC_FUNCTION,
+ start.substring (0, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private inline Token? gtkdoc_symbolic_link_prefix (unichar c, TokenType type) {
+ if (get () != c) {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int column_start = this.column;
+ next_char ();
+
+ int id_len = 0;
+
+ if ((id_len = id_prefix ()) == 0) {
+ if (type == TokenType.GTKDOC_PARAM && (id_len = vararg_prefix ()) == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+ }
+
+ unowned string separator = this.pos;
+ if (get () == ':') {
+ int separator_len = 1;
+ if (next_char () == ':') {
+ next_char ();
+ separator_len++;
+ }
+
+ int id_len2;
+ if ((id_len2 = g_id_prefix ()) == 0) {
+ this.pos = separator;
+ } else {
+ id_len += id_len2 + separator_len;
+ }
+ } else if (this.pos.has_prefix ("->") || this.pos.has_prefix (".")) {
+ unowned string sep_start = this.pos;
+ int sep_column_start = this.column;
+ int separator_len = 1;
+
+ if (this.pos.has_prefix ("->")) {
+ separator_len = 2;
+ next_char ();
+ }
+
+ next_char ();
+
+ Token? func_token = function_prefix ();
+ if (func_token == null) {
+ int id_len2;
+
+ if ((id_len2 = id_prefix ()) > 0) {
+ id_len += separator_len + id_len2;
+ } else {
+ this.column = sep_column_start;
+ this.pos = sep_start;
+ }
+ } else {
+ id_len += separator_len + func_token.content.length;
+ }
+ }
+
+ return new Token (type,
+ start.substring (1, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private inline Token? gtkdoc_property_prefix () {
+ if (get () != ':') {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int column_start = this.column;
+ next_char ();
+
+ int id_len = 0;
+
+ if ((id_len = g_id_prefix ()) == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ return new Token (TokenType.GTKDOC_PROPERTY,
+ start.substring (1, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private inline Token? gtkdoc_signal_prefix () {
+ if (get () != ':') {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int column_start = this.column;
+ if (next_char () != ':') {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+
+ start = this.pos;
+ next_char ();
+
+ int id_len = 0;
+
+ if ((id_len = g_id_prefix ()) == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ return new Token (TokenType.GTKDOC_SIGNAL,
+ start.substring (1, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private inline Token? gtkdoc_const_prefix () {
+ return gtkdoc_symbolic_link_prefix ('%', TokenType.GTKDOC_CONST);
+ }
+
+ private inline Token? gtkdoc_param_prefix () {
+ return gtkdoc_symbolic_link_prefix ('@', TokenType.GTKDOC_PARAM);
+ }
+
+ private inline Token? gtkdoc_type_prefix () {
+ return gtkdoc_symbolic_link_prefix ('#', TokenType.GTKDOC_TYPE);
+ }
+
+ private inline Token? xml_prefix () {
+ if (get () != '<') {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int line_start = this.line;
+ int column_start = this.column;
+ next_char ();
+
+ if (get () == '!') {
+ // comment
+ if (next_char () == '-') {
+ if (next_char () != '-') {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ for (unichar c = next_char (); c != '\0'; c = next_char ()) {
+ if (c == '\n') {
+ this.line++;
+ this.column = 0;
+ } else if (this.pos.has_prefix ("-->")) {
+ next_char ();
+ next_char ();
+ next_char ();
+ return new Token (TokenType.XML_COMMENT,
+ "",
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+ }
+ } else if (this.pos.has_prefix ("[CDATA[")) {
+ next_char ();
+ next_char ();
+ next_char ();
+ next_char ();
+ next_char ();
+ next_char ();
+
+ for (unichar c = next_char (); c != '\0'; c = next_char ()) {
+ if (c == '\n') {
+ this.line++;
+ this.column = 0;
+ } else if (this.pos.has_prefix ("]]>")) {
+ string content = start.substring (9, offset (this.pos, start) - 9);
+ next_char ();
+ next_char ();
+ next_char ();
+ return new Token (TokenType.WORD,
+ unescape (content),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+ }
+ }
+
+ this.pos = start;
+ this.column = column_start;
+ this.line = line_start;
+ return null;
+ }
+
+ bool close = false;
+ if (get () == '/') {
+ next_char ();
+ close = true;
+ }
+
+ unowned string id_start = this.pos;
+
+ int id_len = 0;
+ if ((id_len = id_prefix ()) == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ HashMap<string, string> map = new HashMap<string, string> ();
+
+ while (close == false && skip_spaces_and_newlines () > 0) {
+ string name;
+ string val;
+
+ unowned string att_pos = this.pos;
+ int att_id_len = 0;
+ if ((att_id_len = id_prefix ()) == 0) {
+ break;
+ }
+
+ name = att_pos.substring (0, att_id_len);
+
+ if (get() != '=') {
+ break;
+ }
+
+ next_char ();
+ skip_spaces_and_newlines ();
+
+ if (get() != '"') {
+ break;
+ }
+
+ unichar c = next_char ();
+ att_pos = this.pos;
+ for (; c != '\0' && c != '\n' && c != '"' ; c = next_char ());
+
+ val = att_pos.substring (0, offset (this.pos, att_pos));
+
+ if (get() != '"') {
+ break;
+ }
+
+ next_char ();
+
+ map.set (name, val);
+ }
+
+ skip_spaces_and_newlines ();
+
+ bool open_and_close = false;
+
+ if (!close && get () == '/') {
+ open_and_close = true;
+ next_char ();
+ }
+
+ if (get () != '>') {
+ this.line = line_start;
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ next_char ();
+
+ if (open_and_close) {
+ this.tmp_token = new Token (TokenType.XML_CLOSE,
+ id_start.substring (0, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ if (close) {
+ return new Token (TokenType.XML_CLOSE,
+ id_start.substring (0, id_len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ } else {
+ return new Token (TokenType.XML_OPEN,
+ id_start.substring (0, id_len),
+ map,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+ }
+
+ private Token? newline_prefix () {
+ if (get () != '\n') {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ this.line++;
+ this.column = 0;
+
+ for (unichar c = next_char (); c == ' ' || c == '\t' ; c = next_char ());
+
+ if (get () == '\n') {
+ next_char ();
+ this.line++;
+ this.column = 0;
+ return new Token (TokenType.GTKDOC_PARAGRAPH,
+ "\n\n",
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ this.column,
+ this.column);
+ } else {
+ return new Token (TokenType.NEWLINE,
+ "\n",
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ this.column,
+ this.column);
+ }
+ }
+
+ private Token? eof_prefix () {
+ if (get () != '\0') {
+ return null;
+ }
+
+ return new Token (TokenType.EOF,
+ "",
+ null,
+ this.pos,
+ 1,
+ this.line,
+ this.column,
+ this.column);
+ }
+
+ private Token? space_prefix () {
+ unowned string start = this.pos;
+ int column_start = this.column;
+ for (unichar c = get (); c == ' ' || c == '\t'; c = next_char ());
+ int len = offset (this.pos, start);
+ if (len == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ return new Token (TokenType.SPACE,
+ start.substring (0, len),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private Token? word_prefix () {
+ unowned string start = this.pos;
+ int column_start = this.column;
+ unichar c = get ();
+ if (c == '<' || c == '@') {
+ next_char ();
+ }
+
+ for (c = get (); c != ' ' && c != '\t' && c != '\n' && c != '\0' && c != '<' && c != '@'; c = next_char ());
+ int len = offset (this.pos, start);
+ if (len == 0) {
+ this.column = column_start;
+ this.pos = start;
+ return null;
+ }
+
+ return new Token (TokenType.WORD,
+ unescape (start.substring (0, len)),
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private Token? gtkdoc_source_open_prefix () {
+ if (!this.pos.has_prefix ("|[")) {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int column_start = this.column;
+ next_char ();
+ next_char ();
+
+ return new Token (TokenType.GTKDOC_SOURCE_OPEN,
+ "|[",
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ private Token? gtkdoc_source_close_prefix () {
+ if (!this.pos.has_prefix ("]|")) {
+ return null;
+ }
+
+ unowned string start = this.pos;
+ int column_start = this.column;
+ next_char ();
+ next_char ();
+
+ return new Token (TokenType.GTKDOC_SOURCE_CLOSE, "]|",
+ null,
+ start,
+ offset (this.pos, start),
+ this.line,
+ column_start,
+ this.column);
+ }
+
+ public Token next () {
+ if (tmp_token != null) {
+ var tmp = tmp_token;
+ tmp_token = null;
+ return tmp;
+ }
+
+ Token? token = function_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = xml_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_param_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_const_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_type_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = space_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = newline_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_signal_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_property_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_source_open_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = gtkdoc_source_close_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = eof_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ token = word_prefix ();
+ if (token != null) {
+ return token;
+ }
+
+ assert_not_reached ();
+ }
+}
+
diff --git a/libvaladoc/documentation/gtkdocmarkdownparser.vala b/libvaladoc/documentation/gtkdocmarkdownparser.vala
new file mode 100644
index 000000000..ff52e9542
--- /dev/null
+++ b/libvaladoc/documentation/gtkdocmarkdownparser.vala
@@ -0,0 +1,840 @@
+/* gtkdocmarkdownparser.vala
+ *
+ * Copyright (C) 2014 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.Content;
+using Valadoc;
+using Gee;
+
+
+
+public class Valadoc.Gtkdoc.MarkdownParser : Object, ResourceLocator {
+ private Valadoc.Parser parser;
+ private Content.ContentFactory _factory;
+
+ private Settings _settings;
+ private ErrorReporter _reporter;
+ private Api.Tree _tree;
+
+ private ArrayList<Object> _stack = new ArrayList<Object> ();
+
+ private Valadoc.Token preserved_token = null;
+ private Regex regex_source_lang;
+
+ private Importer.InternalIdRegistrar id_registrar;
+ private GirMetaData metadata;
+ private Api.GirSourceComment gir_comment;
+ private Api.Node element;
+
+
+ public MarkdownParser (Settings settings, ErrorReporter reporter, Api.Tree? tree, ModuleLoader _modules) {
+ MarkdownScanner scanner = new MarkdownScanner (settings);
+ parser = new Valadoc.Parser (settings, scanner, reporter);
+ scanner.set_parser (parser);
+
+
+ _factory = new Content.ContentFactory (settings, this, _modules);
+ _settings = settings;
+ _reporter = reporter;
+ _tree = tree;
+
+ init_rules ();
+
+ try {
+ regex_source_lang = new Regex ("^<!--[ \t]+language=\"([A-Za-z]*)\"[ \t]+-->");
+ } catch (Error e) {
+ assert_not_reached ();
+ }
+ }
+
+ public void init_rules () {
+ Valadoc.TokenType word = Valadoc.TokenType.any_word ().action (add_text);
+
+ StubRule content = new StubRule ();
+ content.set_name ("Content");
+
+ StubRule run = new StubRule ();
+ run.set_name ("Run");
+
+
+ Rule param = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_PARAMETER.action ((token) => {
+ Run _run = null;
+
+ if (token.value == gir_comment.instance_param_name) {
+ _run = _factory.create_run (Run.Style.LANG_KEYWORD);
+ _run.content.add (_factory.create_text ("this"));
+ } else if (is_error_parameter (token.value)) {
+ _run = _factory.create_run (Run.Style.LANG_KEYWORD);
+ _run.content.add (_factory.create_text ("throws"));
+ } else {
+ string? param_name;
+ string? param_array_name;
+ bool is_return_type_len;
+
+ ImporterHelper.resolve_parameter_ctype (
+ this._tree,
+ this.element,
+ token.value,
+ out param_name,
+ out param_array_name,
+ out is_return_type_len);
+
+ _run = _factory.create_run (Run.Style.MONOSPACED);
+
+ if (is_return_type_len) {
+ Run keyword_run = _factory.create_run (Run.Style.LANG_KEYWORD);
+ keyword_run.content.add (_factory.create_text ("return"));
+ _run.content.add (keyword_run);
+
+ _run.content.add (_factory.create_text (".length"));
+ } else if (param_array_name != null) {
+ _run.content.add (_factory.create_text (param_array_name + ".length"));
+ } else {
+ _run.content.add (_factory.create_text (param_name));
+ }
+
+
+ }
+
+ push (_run);
+ })
+ })
+ .set_name ("Parameter");
+
+
+ Rule constant = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_CONSTANT.action ((token) => {
+ if (is_literal (token.value)) {
+ var _run = _factory.create_run (Run.Style.LANG_LITERAL);
+ _run.content.add (_factory.create_text (token.value.down ()));
+ push (_run);
+ } else {
+ add_symbol_link ("c::" + token.value, true);
+ }
+ })
+ })
+ .set_name ("Constant");
+
+
+ Rule gmember = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_LOCAL_GMEMBER.action ((token) => {
+ Api.Item gtype = element;
+ while (gtype is Api.Class == false && gtype is Api.Interface == false && gtype != null) {
+ gtype = gtype.parent;
+ }
+
+ string parent_cname;
+ if (gtype is Api.Class) {
+ parent_cname = ((Api.Class) gtype).get_cname ();
+ } else if (gtype is Api.Interface) {
+ parent_cname = ((Api.Interface) gtype).get_cname ();
+ } else {
+ parent_cname = "";
+ }
+
+ add_symbol_link ("c::" + parent_cname + token.value, true);
+ })
+ })
+ .set_name ("GLocalMember");
+
+
+ Rule symbol = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_SYMBOL.action ((token) => {
+ add_symbol_link ("c::" + token.value, true);
+ })
+ })
+ .set_name ("Symbol");
+
+
+ Rule function = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_FUNCTION.action ((token) => {
+ add_symbol_link ("c::" + token.value, false);
+ })
+ })
+ .set_name ("Function");
+
+
+ Rule link_short = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_LESS_THAN,
+ Rule.option ({
+ Rule.one_of ({
+ Valadoc.TokenType.MARKDOWN_MAIL.action (preserve_token),
+ Valadoc.TokenType.MARKDOWN_LINK.action (preserve_token)
+ }),
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_GREATER_THAN,
+ })
+ .set_reduce (() => {
+ Link url = _factory.create_link ();
+ url.url = pop_preserved_link ();
+ push (url);
+ })
+ .set_skip (() => {
+ add_content_string ("<");
+ add_value (preserved_token);
+ preserved_token = null;
+ })
+ })
+ .set_skip (() => {
+ add_content_string ("<");
+ })
+ })
+ .set_name ("Link");
+
+
+ Rule link = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_OPEN_BRACKET,
+ Rule.option ({
+ Rule.option ({
+ run
+ }),
+ Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET,
+ Rule.option ({
+ Rule.one_of ({
+ // External link:
+ Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_OPEN_PARENS,
+ Rule.option ({
+ Rule.one_of ({
+ Valadoc.TokenType.MARKDOWN_LINK.action (preserve_token),
+ Valadoc.TokenType.MARKDOWN_MAIL.action (preserve_token)
+ }),
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_CLOSE_PARENS
+ })
+ .set_reduce (() => {
+ Link url = _factory.create_link ();
+ url.url = pop_preserved_link ();
+
+ Run label = (Run) peek ();
+ url.content.add_all (label.content);
+ label.content.clear ();
+ label.content.add (url);
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+ _run.content.add (_factory.create_text ("](" + pop_preserved_link ()));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+ _run.content.add (_factory.create_text ("]("));
+ })
+ }),
+ // Internal link:
+ Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_OPEN_BRACKET,
+ Rule.option ({
+ Valadoc.TokenType.any_word ().action (preserve_token),
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET
+ })
+ .set_reduce (() => {
+ Link url = _factory.create_link ();
+ url.url = pop_preserved_link ();
+ url.id_registrar = id_registrar;
+
+ Run label = (Run) peek ();
+ url.content.add_all (label.content);
+ label.content.clear ();
+ label.content.add (url);
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+
+ _run.content.add (_factory.create_text ("][" + pop_preserved_link ()));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+ _run.content.add (_factory.create_text ("]["));
+ })
+ })
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+ _run.content.add (_factory.create_text ("]"));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("["));
+ })
+ })
+ .set_start (() => { push (_factory.create_run (Run.Style.NONE)); })
+ .set_name ("Link");
+
+
+ Rule image = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_EXCLAMATION_MARK,
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_OPEN_BRACKET,
+ Rule.option ({
+ run
+ }),
+ Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET,
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_OPEN_BRACKET,
+ Rule.option ({
+ Rule.one_of ({
+ Valadoc.TokenType.any_word ().action (preserve_token),
+ Valadoc.TokenType.MARKDOWN_LINK.action (preserve_token),
+ Valadoc.TokenType.MARKDOWN_MAIL.action (preserve_token)
+ }),
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET,
+ })
+ .set_reduce (() => {
+ Run label = (Run) peek ();
+
+ string label_str;
+ try {
+ label_str = run_to_string (label, "<image>");
+ } catch (Error e) {
+ parser.warning (preserved_token, e.message);
+ label_str = null;
+ }
+
+ Embedded embedded = _factory.create_embedded ();
+ embedded.url = fix_resource_path (pop_preserved_path ());
+ embedded.caption = label_str;
+
+ label.content.clear ();
+ label.content.add (embedded);
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("!["));
+ _run.content.add (_factory.create_text ("][" + pop_preserved_link ()));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("!["));
+ _run.content.add (_factory.create_text ("]["));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("!["));
+ _run.content.add (_factory.create_text ("]"));
+ })
+ })
+ .set_skip (() => {
+ Run _run = (Run) peek ();
+ _run.content.insert (0, _factory.create_text ("!"));
+ })
+ })
+ .set_start (() => { push (_factory.create_run (Run.Style.NONE)); })
+ .set_name ("Image");
+
+
+ Rule source = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_SOURCE.action ((token) => {
+ SourceCode code = _factory.create_source_code ();
+ MatchInfo info;
+
+ unowned string source = token.value;
+ if (regex_source_lang.match (source, 0, out info)) {
+ string lang_name = info.fetch (1).down ();
+ SourceCode.Language? lang = SourceCode.Language.from_string (lang_name);
+ code.language = lang;
+
+ if (lang == null) {
+ parser.warning (token, "Unknown language `%s' in source code block |[<!-- language=\"\"".printf (lang_name));
+ }
+
+ source = source.offset (source.index_of_char ('>') + 1);
+ } else {
+ code.language = (Highlighter.XmlScanner.is_xml (source))
+ ? SourceCode.Language.XML
+ : SourceCode.Language.C;
+ }
+
+ code.code = source;
+ push (code);
+ })
+ })
+ .set_name ("Source");
+
+
+ Rule text = Rule.many ({
+ Rule.one_of ({
+ word,
+ Valadoc.TokenType.MARKDOWN_SPACE.action (add_text),
+ Valadoc.TokenType.MARKDOWN_MAIL.action (add_value),
+ Valadoc.TokenType.MARKDOWN_LINK.action (add_value),
+ Valadoc.TokenType.MARKDOWN_OPEN_PARENS.action (add_text),
+ Valadoc.TokenType.MARKDOWN_CLOSE_PARENS.action (add_text),
+ Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET.action (add_text),
+ Valadoc.TokenType.MARKDOWN_GREATER_THAN.action (add_text)
+ })
+ })
+ .set_start (() => { push (_factory.create_text ()); })
+ .set_name ("Text");
+
+
+ run.set_rule (
+ Rule.many ({
+ Rule.one_of ({
+ text,
+ link,
+ link_short,
+ image,
+ function,
+ constant,
+ param,
+ symbol,
+ gmember,
+ source
+ })
+ .set_reduce (() => {
+ var head = (Inline) pop ();
+ ((InlineContent) peek ()).content.add (head);
+ })
+ })
+ );
+
+
+ Rule unordered_list = Rule.seq ({
+ Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_UNORDERED_LIST_ITEM_START,
+ content,
+ Valadoc.TokenType.MARKDOWN_UNORDERED_LIST_ITEM_END
+ })
+ .set_start (() => { push (_factory.create_list_item ()); })
+ .set_reduce (() => {
+ var head = (ListItem) pop ();
+ ((Content.List) peek ()).items.add (head);
+ })
+ })
+ .set_start (() => {
+ var siblings = ((BlockContent) peek ()).content;
+ if (siblings.size > 0 && siblings.last () is Content.List) {
+ push (siblings.last ());
+ } else {
+ Content.List list = _factory.create_list ();
+ list.bullet = Content.List.Bullet.UNORDERED;
+ siblings.add (list);
+ push (list);
+ }
+ })
+ .set_reduce (() => {
+ (Content.List) pop ();
+ })
+ .set_name ("UnorderedList");
+
+
+ Rule ordered_list = Rule.seq ({
+ Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_ORDERED_LIST_ITEM_START,
+ content,
+ Valadoc.TokenType.MARKDOWN_ORDERED_LIST_ITEM_END
+ })
+ .set_start (() => { push (_factory.create_list_item ()); })
+ .set_reduce (() => {
+ var head = (ListItem) pop ();
+ ((Content.List) peek ()).items.add (head);
+ })
+ })
+ .set_start (() => {
+ var siblings = ((BlockContent) peek ()).content;
+ if (siblings.size > 0 && siblings.last () is Content.List) {
+ push (siblings.last ());
+ } else {
+ Content.List list = _factory.create_list ();
+ list.bullet = Content.List.Bullet.ORDERED_NUMBER;
+ siblings.add (list);
+ push (list);
+ }
+ })
+ .set_reduce (() => {
+ (Content.List) pop ();
+ })
+ .set_name ("OrderedList");
+
+
+ Rule paragraph = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_PARAGRAPH,
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_SPACE
+ }),
+ Rule.option ({
+ run
+ })
+ })
+ .set_start (() => { push (_factory.create_paragraph ()); })
+ .set_reduce (() => {
+ var head = (Paragraph) pop ();
+ ((BlockContent) peek ()).content.add (head);
+ })
+ .set_name ("Paragraph");
+
+
+ Rule block = Rule.seq ({
+ Valadoc.TokenType.MARKDOWN_BLOCK_START,
+ content,
+ Valadoc.TokenType.MARKDOWN_BLOCK_END
+ })
+ .set_start (() => { push (_factory.create_note ()); })
+ .set_reduce (() => {
+ var head = (Note) pop ();
+ ((BlockContent) peek ()).content.add (head);
+ })
+ .set_name ("Block");
+
+
+ Rule headline = Rule.seq ({
+ Rule.one_of ({
+ Valadoc.TokenType.MARKDOWN_HEADLINE_1.action ((token) => {
+ Headline h = (Headline) peek ();
+ h.level = 1;
+ }),
+ Valadoc.TokenType.MARKDOWN_HEADLINE_2.action ((token) => {
+ Headline h = (Headline) peek ();
+ h.level = 2;
+ })
+ }),
+ run,
+ Rule.option ({
+ Valadoc.TokenType.MARKDOWN_HEADLINE_HASH.action ((token) => {
+ id_registrar.register_symbol (token.value, element);
+ })
+ }),
+ Valadoc.TokenType.MARKDOWN_HEADLINE_END
+ })
+ .set_start (() => { push (_factory.create_headline ()); })
+ .set_reduce (() => {
+ Headline h = (Headline) pop ();
+ ((BlockContent) peek ()).content.add (h);
+ })
+ .set_name ("Headline");
+
+ content.set_rule (
+ Rule.many ({
+ Rule.one_of ({
+ paragraph,
+ unordered_list,
+ ordered_list,
+ headline,
+ block
+ })
+ })
+ );
+
+
+ Rule comment = Rule.seq ({
+ content,
+ Valadoc.TokenType.MARKDOWN_EOC
+ })
+ .set_start (() => { push (_factory.create_comment ()); })
+ .set_name ("Comment");
+
+ parser.set_root_rule (comment);
+ }
+
+ private Comment? _parse (Api.SourceComment comment) {
+ try {
+ _stack.clear ();
+ parser.parse (comment.content, comment.file.get_name (), comment.first_line, comment.first_column);
+ return (Comment) pop ();
+ } catch (ParserError e) {
+ return null;
+ }
+ }
+
+ private Taglet? _parse_block_taglet (Api.SourceComment comment, string taglet_name) {
+ Comment? cmnt = _parse (comment);
+ if (cmnt == null) {
+ return null;
+ }
+
+ Taglet? taglet = _factory.create_taglet (taglet_name);
+ BlockContent block = (BlockContent) taglet;
+ assert (taglet != null && block != null);
+
+ block.content.add_all (cmnt.content);
+
+ return taglet;
+ }
+
+ private Note? _parse_note (Api.SourceComment comment) {
+ Comment? cmnt = _parse (comment);
+ if (cmnt == null) {
+ return null;
+ }
+
+ Note note = _factory.create_note ();
+ note.content.add_all (cmnt.content);
+
+ return note;
+ }
+
+ private void add_taglet (ref Comment? comment, Taglet? taglet) {
+ if (taglet == null) {
+ return ;
+ }
+
+ if (comment == null) {
+ comment = _factory.create_comment ();
+ }
+
+ comment.taglets.add (taglet);
+ }
+
+ private void add_note (ref Comment? comment, Note? note) {
+ if (note == null) {
+ return ;
+ }
+
+ if (comment == null) {
+ comment = _factory.create_comment ();
+ }
+
+ if (comment.content.size == 0) {
+ comment.content.add (_factory.create_paragraph ());
+ }
+
+ comment.content.insert (1, note);
+ }
+
+ public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment, GirMetaData metadata, Importer.InternalIdRegistrar id_registrar, string? this_name = null) {
+ this.metadata = metadata;
+ this.id_registrar = id_registrar;
+ this.gir_comment = gir_comment;
+ this.element = element;
+
+ // main:
+ Comment? cmnt = _parse (gir_comment);
+ if (cmnt != null) {
+ ImporterHelper.extract_short_desc (cmnt, _factory);
+ }
+
+
+ // deprecated:
+ if (gir_comment.deprecated_comment != null) {
+ Note? note = _parse_note (gir_comment.deprecated_comment);
+ add_note (ref cmnt, note);
+ }
+
+
+ // version:
+ if (gir_comment.version_comment != null) {
+ Note? note = _parse_note (gir_comment.version_comment);
+ add_note (ref cmnt, note);
+ }
+
+
+ // stability:
+ if (gir_comment.stability_comment != null) {
+ Note? note = _parse_note (gir_comment.stability_comment);
+ add_note (ref cmnt, note);
+ }
+
+
+ // return:
+ if (gir_comment.return_comment != null) {
+ Taglet? taglet = _parse_block_taglet (gir_comment.return_comment, "return");
+ add_taglet (ref cmnt, taglet);
+ }
+
+
+ // parameters:
+ MapIterator<string, Api.SourceComment> iter = gir_comment.parameter_iterator ();
+ for (bool has_next = iter.next (); has_next; has_next = iter.next ()) {
+ Taglets.Param? taglet = _parse_block_taglet (iter.get_value (), "param") as Taglets.Param;
+ string param_name = iter.get_key ();
+
+ taglet.is_c_self_param = (param_name == gir_comment.instance_param_name);
+ taglet.parameter_name = param_name;
+ add_taglet (ref cmnt, taglet);
+ }
+
+
+ this.metadata = null;
+ this.gir_comment = null;
+ this.id_registrar = null;
+ this.element = null;
+
+ return cmnt;
+ }
+
+
+ private void add_text (Valadoc.Token token) {
+ add_content_string (token.to_string ());
+ }
+
+ private void add_value (Valadoc.Token token) {
+ assert (token.value != null);
+
+ add_content_string (token.value);
+ }
+
+ private void add_content_string (string str) {
+ var text = peek () as Text;
+ if (text == null) {
+ push (text = _factory.create_text ());
+ }
+
+ text.content += str;
+ }
+
+ private void add_symbol_link (string symbol, bool accept_plural) {
+ var taglet = new Taglets.Link ();
+ taglet.c_accept_plural = accept_plural;
+ taglet.symbol_name = symbol;
+
+ var run = _factory.create_run (Run.Style.NONE);
+ run.content.add (taglet);
+
+ push (run);
+ }
+
+ private void preserve_token (Valadoc.Token token) {
+ assert (preserved_token == null);
+ preserved_token = token;
+ }
+
+ private string pop_preserved_link () {
+ assert (preserved_token != null);
+
+ Valadoc.Token _link_token = (owned) preserved_token;
+
+ // email:
+ if (_link_token.token_type == Valadoc.TokenType.MARKDOWN_MAIL) {
+ return "mailto:" + _link_token.value;
+ }
+
+ // http or https link:
+ if (_link_token.value != null) {
+ return _link_token.value;
+ }
+
+ // GTKDOC-ID:
+ return _link_token.word;
+ }
+
+ private string pop_preserved_path () {
+ assert (preserved_token != null);
+
+ Valadoc.Token _path_token = (owned) preserved_token;
+ return _path_token.word ?? _path_token.value;
+ }
+
+ private inline string run_to_string (Run run, string rule_name) throws Error {
+ StringBuilder builder = new StringBuilder ();
+ inline_to_string (run, rule_name, builder);
+ return (owned) builder.str;
+ }
+
+ private void inline_to_string (Inline element, string rule_name, StringBuilder? builder) throws Error {
+ if (element is Run) {
+ Run run = (Run) element;
+
+ foreach (Inline item in run.content) {
+ inline_to_string (item, rule_name, builder);
+ }
+ } else if (element is Text) {
+ Text text = (Text) element;
+ builder.append (text.content);
+ } else if (element is Embedded) {
+ throw new ContentToStringError.UNEXPECTED_ELEMENT ("Unexpected tag: <image> in `%s'", rule_name);
+ } else if (element is Link) {
+ throw new ContentToStringError.UNEXPECTED_ELEMENT ("Unexpected tag: <link> in `%s'", rule_name);
+ } else if (element is SourceCode) {
+ throw new ContentToStringError.UNEXPECTED_ELEMENT ("Unexpected tag: `|[' in `%s'", rule_name);
+ } else {
+ throw new ContentToStringError.UNEXPECTED_ELEMENT ("Unexpected tag in `%s''", rule_name);
+ }
+ }
+
+ private bool is_literal (string str) {
+ if (str == "TRUE") {
+ return true;
+ }
+
+ if (str == "FALSE") {
+ return true;
+ }
+
+ if (str == "NULL") {
+ return true;
+ }
+
+ if (str[0].isdigit ()) {
+ return true;
+ }
+
+ return true;
+ }
+
+ private bool is_error_parameter (string name) {
+ if (element == null || name != "error") {
+ return false;
+ }
+
+ if (!(element is Api.Method || element is Api.Delegate)) {
+ return false;
+ }
+
+ return element.get_children_by_types ({
+ Api.NodeType.ERROR_DOMAIN,
+ Api.NodeType.CLASS}).size > 0;
+ }
+
+
+ public string resolve (string path) {
+ return path;
+ }
+
+ private void push (Object element) {
+ _stack.add (element);
+ }
+
+ private Object peek (int offset = -1) {
+ assert (_stack.size >= - offset);
+ return _stack.get (_stack.size + offset);
+ }
+
+ private Object pop () {
+ Object node = peek ();
+ _stack.remove_at (_stack.size - 1);
+ return node;
+ }
+
+ private inline string fix_resource_path (string path) {
+ return metadata.get_resource_path (path);
+ }
+}
+
+
+private errordomain Valadoc.Gtkdoc.ContentToStringError {
+ UNEXPECTED_ELEMENT
+}
+
diff --git a/libvaladoc/documentation/gtkdocmarkdownscanner.vala b/libvaladoc/documentation/gtkdocmarkdownscanner.vala
new file mode 100644
index 000000000..1908957d6
--- /dev/null
+++ b/libvaladoc/documentation/gtkdocmarkdownscanner.vala
@@ -0,0 +1,761 @@
+/* gtkdocmarkdownscanner.vala
+ *
+ * Copyright (C) 2014 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.Content;
+using Valadoc;
+using Gee;
+
+
+
+public class Valadoc.Gtkdoc.MarkdownScanner : GLib.Object, Valadoc.Scanner {
+ private enum State {
+ NORMAL,
+ UNORDERED_LIST,
+ ORDERED_LIST,
+ BLOCK
+ }
+
+ private Settings _settings;
+ private Valadoc.Parser parser;
+
+ private unowned string _content;
+ private int _skip;
+
+ private StringBuilder _current_string = new StringBuilder ();
+ private unowned string _index;
+ private bool contains_at;
+
+ private int _line;
+ private int _column;
+ private int _last_line;
+ private int _last_column;
+ private bool _stop;
+
+ private string? headline_end;
+
+ private Regex regex_mail;
+
+ private LinkedList<State> states = new LinkedList<State> ();
+
+ private inline void push_state (State state) {
+ states.offer_head (state);
+ }
+
+ private inline State pop_state () {
+ return states.poll_head ();
+ }
+
+ private inline State peek_state () {
+ return states.peek_head ();
+ }
+
+
+ public MarkdownScanner (Settings settings) {
+ _settings = settings;
+
+ try {
+ regex_mail = new Regex ("^[A-Za-z0-9._-]+@[A-Za-z0-9._-]+$");
+ } catch (Error e) {
+ assert_not_reached ();
+ }
+ }
+
+ public void set_parser (Valadoc.Parser parser) {
+ this.parser = parser;
+ }
+
+ public void reset () {
+ _stop = false;
+ _last_line = 0;
+ _last_column = 0;
+ _line = 0;
+ _column = 0;
+ _skip = 0;
+ _current_string.erase (0, -1);
+ contains_at = false;
+
+ states.clear ();
+ push_state (State.NORMAL);
+ }
+
+ public void scan (string content) throws ParserError {
+ _content = content;
+ _index = _content;
+
+
+ // Accept block taglets:
+ if (handle_newline (_index, true)) {
+ _index = _index.next_char ();
+ } else {
+ // Empty string
+ emit_token (Valadoc.TokenType.MARKDOWN_PARAGRAPH);
+ }
+
+
+ while (!_stop && _index.get_char () != 0) {
+ unichar c = _index.get_char ();
+ accept (c);
+
+ _index = _index.next_char ();
+ }
+
+
+ // Close open blocks:
+ while (peek_state () != State.NORMAL) {
+ if (peek_state () == State.BLOCK) {
+ emit_token (Valadoc.TokenType.MARKDOWN_BLOCK_END);
+ pop_state ();
+ } else {
+ close_block ();
+ }
+ }
+
+
+ emit_token (Valadoc.TokenType.MARKDOWN_EOC);
+ }
+
+ private void accept (unichar c) throws ParserError {
+ _column++;
+ if (_skip > 0) {
+ _skip--;
+ return ;
+ }
+
+ // In headline:
+ string? hash = null;
+
+ if (headline_end != null && is_headline_end (ref _index, headline_end, out hash)) {
+ if (hash != null) {
+ emit_token (Valadoc.TokenType.MARKDOWN_HEADLINE_HASH, hash);
+ }
+ emit_token (Valadoc.TokenType.MARKDOWN_HEADLINE_END);
+ headline_end = null;
+
+ handle_newline (_index, true);
+
+ return ;
+ }
+
+ switch (c) {
+ case '\\':
+ switch (get_next_char ()) {
+ case '(':
+ if (get_next_char (2) == ')') {
+ _current_string.append ("()");
+ _skip += 2;
+ break;
+ }
+
+ _current_string.append ("\\(");
+ _skip++;
+ break;
+
+ case '<':
+ append_char ('<');
+ _skip++;
+ break;
+
+ case '>':
+ append_char ('>');
+ _skip++;
+ break;
+
+ case '@':
+ append_char ('@');
+ _skip++;
+ break;
+
+ case '%':
+ append_char ('%');
+ _skip++;
+ break;
+
+ case '#':
+ append_char ('#');
+ _skip++;
+ break;
+
+ default:
+ append_char ('\\');
+ break;
+ }
+
+ break;
+
+ case ':':
+ unichar next_char = get_next_char ();
+ unichar next2_char = get_next_char (2);
+
+ // :id or ::id
+ if ((_current_string.len == 0 || !_current_string.str[_current_string.len - 1].isalpha ())
+ && (next_char.isalpha () || (next_char == ':' && next2_char.isalpha ()))) {
+
+ unowned string _iter;
+ if (next_char == ':') {
+ _iter = _index.offset (2);
+ _skip++;
+ } else {
+ _iter = _index.offset (1);
+ }
+
+ while (_iter[0].isalnum () || _iter[0] == '_' || (_iter[0] == '-' && _iter[1].isalnum ())) {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ emit_token (Valadoc.TokenType.MARKDOWN_LOCAL_GMEMBER, _index.substring (0, _skip + 1));
+ break;
+ }
+
+ append_char (c);
+ break;
+
+ case '%':
+ // " %foo", "-%foo" but not " %", "a%foo", ...
+ if ((_current_string.len == 0 || !_current_string.str[_current_string.len - 1].isalpha ()) && get_next_char ().isalpha ()) {
+ unowned string _iter = _index.offset (1);
+
+ while (_iter[0].isalnum () || _iter[0] == '_') {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ emit_token (Valadoc.TokenType.MARKDOWN_CONSTANT, _index.substring (1, _skip));
+ break;
+ }
+ // %numeric:
+ if ((_current_string.len == 0 || !_current_string.str[_current_string.len - 1].isalpha ()) && get_next_char ().isdigit ()) {
+ unowned string _iter = _index.offset (1);
+
+ while (_iter[0].isdigit ()) {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ // Integers:
+ if (_iter[0].tolower () == 'u' && _iter[0].tolower () == 'l') {
+ _iter = _iter.offset (1);
+ _skip += 2;
+
+ emit_token (Valadoc.TokenType.MARKDOWN_CONSTANT, _index.substring (1, _skip));
+ break;
+ } else if (_iter[0].tolower () == 'u' || _iter[0].tolower () == 'l') {
+ _iter = _iter.offset (1);
+ _skip++;
+
+ emit_token (Valadoc.TokenType.MARKDOWN_CONSTANT, _index.substring (1, _skip));
+ break;
+ }
+
+
+ // Float, double:
+ if (_iter[0] == '.' && _iter[1].isdigit ()) {
+ _iter = _iter.offset (2);
+ _skip += 2;
+ }
+
+ while (_iter[0].isdigit ()) {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ if (_iter[0].tolower () == 'f' || _iter[0].tolower () == 'l') {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ emit_token (Valadoc.TokenType.MARKDOWN_CONSTANT, _index.substring (1, _skip));
+ break;
+ }
+
+ append_char (c);
+ break;
+
+ case '#':
+ // " #foo", "-#foo" but not " #"", "a#""foo", ...
+ if ((_current_string.len == 0 || !_current_string.str[_current_string.len - 1].isalpha ()) && get_next_char ().isalpha ()) {
+ unowned string _iter = _index.offset (1);
+
+ while (_iter[0].isalnum () || _iter[0] == '_') {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ // signals, fields, properties
+ bool is_field = false;
+ if (((_iter[0] == ':' || _iter[0] == '.') && _iter[1].isalpha ())
+ || (_iter.has_prefix ("::") && _iter[2].isalpha ())) {
+
+ is_field = (_iter[0] == '.');
+ _iter = _iter.offset (2);
+ _skip += 2;
+
+ while (_iter[0].isalnum () || _iter[0] == '_' || (!is_field && _iter[0] == '-')) {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+ }
+
+ if (is_field && _iter.has_prefix ("()")) {
+ _skip += 2;
+
+ emit_token (Valadoc.TokenType.MARKDOWN_SYMBOL, _index.substring (1, _skip - 2));
+ } else {
+ emit_token (Valadoc.TokenType.MARKDOWN_SYMBOL, _index.substring (1, _skip));
+ }
+
+ break;
+ }
+
+ append_char (c);
+ break;
+
+ case '@':
+ // " @foo", "-@foo" but not " @", "a@foo", ...
+ if ((_current_string.len == 0 || !_current_string.str[_current_string.len - 1].isalpha ())) {
+ if (get_next_char ().isalpha ()) {
+ unowned string _iter = _index.offset (1);
+
+ while (_iter[0].isalnum () || _iter[0] == '_') {
+ _iter = _iter.offset (1);
+ _skip++;
+ }
+
+ emit_token (Valadoc.TokenType.MARKDOWN_PARAMETER, _index.substring (1, _skip));
+ break;
+ } else if (_index.has_prefix ("@...")) {
+ _skip += 3;
+ emit_token (Valadoc.TokenType.MARKDOWN_PARAMETER, "...");
+ break;
+ }
+ }
+
+ append_char (c);
+ contains_at = true;
+ break;
+
+ case '(':
+ if (get_next_char () == ')' && is_id ()) {
+ string id = _current_string.str;
+ _current_string.erase (0, -1);
+ contains_at = false;
+
+ emit_token (Valadoc.TokenType.MARKDOWN_FUNCTION, id);
+ _skip++;
+ break;
+ }
+
+ emit_token (Valadoc.TokenType.MARKDOWN_OPEN_PARENS);
+ break;
+
+ case ')':
+ emit_token (Valadoc.TokenType.MARKDOWN_CLOSE_PARENS);
+ break;
+
+ case '[':
+ unowned string iter = _index;
+ int count = 1;
+ while (iter[0] != '\n' && iter[0] != '\0' && count > 0) {
+ iter = iter.offset (1);
+ switch (iter[0]) {
+ case '[':
+ count++;
+ break;
+
+ case ']':
+ count--;
+ break;
+ }
+ }
+
+ if (iter[0] == ']') {
+ emit_token (Valadoc.TokenType.MARKDOWN_OPEN_BRACKET);
+ } else {
+ append_char ('[');
+ }
+ break;
+
+ case ']':
+ emit_token (Valadoc.TokenType.MARKDOWN_CLOSE_BRACKET);
+ break;
+
+ case '<':
+ emit_token (Valadoc.TokenType.MARKDOWN_LESS_THAN);
+ break;
+
+ case '>':
+ emit_token (Valadoc.TokenType.MARKDOWN_GREATER_THAN);
+ break;
+
+ case '!':
+ emit_token (Valadoc.TokenType.MARKDOWN_EXCLAMATION_MARK);
+ break;
+
+ case '|':
+ if (get_next_char () == '[') {
+ unowned string _iter = _index.offset (2);
+ int end = _iter.index_of ("]|");
+ if (end < 0) {
+ append_char ('|');
+ } else {
+ emit_token (Valadoc.TokenType.MARKDOWN_SOURCE, _index.substring (2, end));
+ _skip = end + 3;
+ }
+
+ break;
+ }
+
+ append_char (c);
+ break;
+
+ case '\t':
+ case ' ':
+ unowned string _iter = _index.offset (1);
+ _skip += skip_spaces (ref _iter);
+
+ if (_iter[0] != '\n' && _iter[0] != '\0') {
+ emit_token (Valadoc.TokenType.MARKDOWN_SPACE);
+ }
+ break;
+
+ case '\r':
+ // Ignore
+ break;
+
+ case '\n':
+ unowned string _iter = _index.offset (1);
+
+ _line++;
+ _column = 0;
+ _last_column = 0;
+ handle_newline (_iter, false);
+ break;
+
+ default:
+ append_char (c);
+ break;
+ }
+ }
+
+ private bool handle_newline (string _iter, bool is_paragraph) throws ParserError {
+ int leading_spaces;
+
+ leading_spaces = skip_spaces (ref _iter);
+
+ if (_iter[0] == '\0') {
+ return false;
+ }
+
+ // Do not emit paragraphs twice:
+ if (is_paragraph) {
+ while (_iter[0] == '\n') {
+ _line++;
+ _iter = _iter.offset (1);
+ leading_spaces = skip_spaces (ref _iter);
+ }
+ }
+
+ bool in_block = states.contains (State.BLOCK);
+ if (_iter[0] == '>') {
+ if (!in_block) {
+ close_block ();
+
+ if (is_paragraph) {
+ _column += (int) ((char*) _iter - (char*) _index);
+ _index = _iter.offset (1);
+ emit_token (Valadoc.TokenType.MARKDOWN_BLOCK_START);
+ push_state (State.BLOCK);
+ }
+ }
+
+ if (in_block || is_paragraph) {
+ _column++;
+ _index = _iter;
+
+ _iter = _iter.offset (1);
+ skip_spaces (ref _iter);
+ }
+ } else if (in_block && is_paragraph) {
+ _column += (int) ((char*) _iter - (char*) _index);
+ _index = _iter;
+
+ close_block ();
+
+ emit_token (Valadoc.TokenType.MARKDOWN_BLOCK_END);
+ pop_state ();
+ }
+
+
+ int list_token_len = 0;
+ bool is_unsorted_list = _iter[0] == '-' && _iter[1].isspace ();
+ bool is_sorted_list = is_ordered_list (_iter, out list_token_len);
+ if ((is_unsorted_list || is_sorted_list) && (is_paragraph || states.contains (State.UNORDERED_LIST) || states.contains (State.ORDERED_LIST))) {
+ Valadoc.TokenType start_token = Valadoc.TokenType.MARKDOWN_ORDERED_LIST_ITEM_START;
+ State new_state = State.ORDERED_LIST;
+
+ if (is_unsorted_list) {
+ start_token = Valadoc.TokenType.MARKDOWN_UNORDERED_LIST_ITEM_START;
+ new_state = State.UNORDERED_LIST;
+ list_token_len = 2;
+ }
+
+
+ _iter = _iter.offset (list_token_len);
+ close_block ();
+
+ skip_spaces (ref _iter);
+
+ _column += (int) ((char*) _iter - (char*) _index);
+ _index = _iter.offset (-1);
+ emit_token (start_token);
+ push_state (new_state);
+
+ emit_token (Valadoc.TokenType.MARKDOWN_PARAGRAPH);
+ return true;
+ }
+
+ if ((_iter[0] == '#' && _iter[1].isspace ()) || (_iter[0] == '#' && _iter[1] == '#' && _iter[2].isspace ()) && is_paragraph) {
+ close_block ();
+
+ if (_iter[1] != '#') {
+ _iter = _iter.offset (1);
+ emit_token (Valadoc.TokenType.MARKDOWN_HEADLINE_1);
+ headline_end = "#";
+ } else {
+ emit_token (Valadoc.TokenType.MARKDOWN_HEADLINE_2);
+ _iter = _iter.offset (2);
+ headline_end = "##";
+ }
+
+ _column += (int) ((char*) _iter - (char*) _index);
+ _index = _iter.offset (-1);
+
+ return true;
+ }
+
+ if (is_paragraph) {
+ if (leading_spaces == 0) {
+ close_block ();
+ }
+
+ _column += (int) ((char*) _iter - (char*) _index);
+ _index = _iter.offset (-1);
+ emit_token (Valadoc.TokenType.MARKDOWN_PARAGRAPH);
+ } else if (_iter[0] == '\n') {
+ _line++;
+ _column = 0;
+ _last_column = 0;
+
+ handle_newline (_iter.offset (1), true);
+ } else {
+ emit_token (Valadoc.TokenType.MARKDOWN_SPACE);
+ }
+
+ return true;
+ }
+
+ private bool is_headline_end (ref unowned string iter, string separator, out string? hash) {
+ unowned string _iter = iter;
+ hash = null;
+
+
+ if (_iter[0] == '\n' || _iter[0] == '\0') {
+ _line++;
+ return true;
+ }
+ if (!_iter.has_prefix (separator)) {
+ return false;
+ }
+
+ _iter = _iter.offset (separator.length);
+
+
+ skip_spaces (ref _iter);
+ if (_iter[0] == '\n' || _iter[0] == '\0') {
+ iter = _iter;
+ _line++;
+ return true;
+ } else if (!_iter.has_prefix ("{#")) {
+ return false;
+ }
+ _iter = _iter.offset (2);
+
+ unowned string id_start = _iter;
+ int hash_len = 0;
+
+ while (_iter[0] != '}' && _iter[0] != '\n' && _iter[0] != '\0') {
+ _iter = _iter.offset (1);
+ hash_len++;
+ }
+
+ if (_iter[0] != '}') {
+ return false;
+ }
+
+ _iter = _iter.offset (1);
+
+ skip_spaces (ref _iter);
+
+ if (_iter[0] == '\n' || _iter[0] == '\0') {
+ hash = id_start.substring (0, hash_len);
+ iter = _iter;
+ _line++;
+ return true;
+ }
+
+ return false;
+ }
+
+ private bool is_ordered_list (string iter, out int numeric_prefix_count) {
+ numeric_prefix_count = 0;
+ while (iter[0] >= '0' && iter[0] <= '9') {
+ numeric_prefix_count++;
+ iter = iter.offset (1);
+ }
+
+ if (numeric_prefix_count > 0 && iter[0] == '.' && iter[1].isspace ()) {
+ numeric_prefix_count++;
+ return true;
+ }
+
+ return false;
+ }
+
+ private inline int skip_spaces (ref unowned string _iter) {
+ int count = 0;
+ while (_iter[0] == ' ' || _iter[0] == '\t' || _iter[0] == '\r') {
+ _iter = _iter.offset (1);
+ count++;
+ }
+
+ return count;
+ }
+
+ private bool close_block () throws ParserError {
+ if (states.peek () == State.UNORDERED_LIST) {
+ emit_token (Valadoc.TokenType.MARKDOWN_UNORDERED_LIST_ITEM_END);
+ pop_state ();
+ return true;
+ } else if (states.peek () == State.ORDERED_LIST) {
+ emit_token (Valadoc.TokenType.MARKDOWN_ORDERED_LIST_ITEM_END);
+ pop_state ();
+ return true;
+ }
+
+ return false;
+ }
+
+ public void end () throws ParserError {
+ emit_token (Valadoc.TokenType.EOF);
+ }
+
+ public void stop () {
+ _stop = true;
+ }
+
+ public string get_line_content () {
+ StringBuilder builder = new StringBuilder ();
+ weak string line_start = _index;
+ unichar c;
+
+ while ((char*) line_start > (char*) _content && line_start.prev_char ().get_char () != '\n') {
+ line_start = line_start.prev_char ();
+ }
+
+ while ((c = line_start.get_char ()) != '\n' && c != '\0') {
+ if (c == '\t') {
+ builder.append_c (' ');
+ } else {
+ builder.append_unichar (c);
+ }
+ line_start = line_start.next_char ();
+ }
+
+ return builder.str;
+ }
+
+ private void emit_token (Valadoc.TokenType type, string? value = null) throws ParserError {
+ emit_current_word ();
+
+ parser.accept_token (new Valadoc.Token.from_type (type, get_begin (), get_end (_skip), value));
+ }
+
+ private void emit_current_word () throws ParserError {
+ if (_current_string.len > 0) {
+ if (is_mail ()) {
+ parser.accept_token (new Valadoc.Token.from_type (Valadoc.TokenType.MARKDOWN_MAIL, get_begin (), get_end (_skip), _current_string.str));
+ } else if (_current_string.str.has_prefix ("http://") || _current_string.str.has_prefix ("https://")) {
+ // TODO: (https?:[\/]{2}[^\s]+?)
+ parser.accept_token (new Valadoc.Token.from_type (Valadoc.TokenType.MARKDOWN_LINK, get_begin (), get_end (_skip), _current_string.str));
+ } else {
+ parser.accept_token (new Valadoc.Token.from_word (_current_string.str, get_begin (), get_end (-1)));
+ }
+
+ _current_string.erase (0, -1);
+ contains_at = false;
+ }
+ }
+
+ 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);
+ }
+
+ public int get_line_start_column () {
+ return 0;
+ }
+
+ private void append_char (unichar c) {
+ _current_string.append_unichar (c);
+ }
+
+ private unichar get_next_char (int offset = 1) {
+ return _index.get_char (_index.index_of_nth_char (offset));
+ }
+
+ private inline bool is_mail () {
+ return contains_at && regex_mail.match (_current_string.str);
+ }
+
+ private bool is_id () {
+ if (_current_string.len == 0) {
+ return false;
+ }
+
+ if (_current_string.str[0].isalpha () == false && _current_string.str[0] != '_') {
+ return false;
+ }
+
+ for (int i = 1; i < _current_string.len ; i++) {
+ if (_current_string.str[i].isalnum () == false && _current_string.str[i] != '_') {
+ return false;
+ }
+ }
+
+ return true;
+ }
+}
+
diff --git a/libvaladoc/documentation/importerhelper.vala b/libvaladoc/documentation/importerhelper.vala
new file mode 100644
index 000000000..3f7501836
--- /dev/null
+++ b/libvaladoc/documentation/importerhelper.vala
@@ -0,0 +1,266 @@
+/* importhelper.vala
+ *
+ * Copyright (C) 2014 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.Content;
+using Gee;
+
+
+namespace Valadoc.ImporterHelper {
+
+ //
+ // resolve-parameter-ctype:
+ //
+
+ internal string? resolve_parameter_ctype (Api.Tree tree, Api.Node element, string parameter_name,
+ out string? param_name, out string? param_array_name, out bool is_return_type_len)
+ {
+ string[]? parts = split_type_name (parameter_name);
+ is_return_type_len = false;
+ param_array_name = null;
+
+ Api.FormalParameter? param = null; // type parameter or formal parameter
+ foreach (Api.Node node in element.get_children_by_type (Api.NodeType.FORMAL_PARAMETER, false)) {
+ if (node.name == parts[0]) {
+ param = node as Api.FormalParameter;
+ break;
+ }
+
+ if (((Api.FormalParameter) node).implicit_array_length_cparameter_name == parts[0]) {
+ param_array_name = ((Api.FormalParameter) node).name;
+ break;
+ }
+ }
+
+ if (element is Api.Callable
+ && ((Api.Callable) element).implicit_array_length_cparameter_name == parts[0])
+ {
+ is_return_type_len = true;
+ }
+
+ if (parts.length == 1) {
+ param_name = parameter_name;
+ return null;
+ }
+
+
+ Api.Item? inner = null;
+
+ if (param_array_name != null || is_return_type_len) {
+ inner = tree.search_symbol_str (null, "int");
+ } else if (param != null) {
+ inner = param.parameter_type;
+ }
+
+ while (inner != null) {
+ if (inner is Api.TypeReference) {
+ inner = ((Api.TypeReference) inner).data_type;
+ } else if (inner is Api.Pointer) {
+ inner = ((Api.Pointer) inner).data_type;
+ } else if (inner is Api.Array) {
+ inner = ((Api.Array) inner).data_type;
+ } else {
+ break ;
+ }
+ }
+
+
+ if (inner == null) {
+ param_name = parameter_name;
+ return null;
+ }
+
+ string? cname = null;
+ if (inner is Api.ErrorDomain) {
+ cname = ((Api.ErrorDomain) inner).get_cname ();
+ } else if (inner is Api.Struct) {
+ cname = ((Api.Struct) inner).get_cname ();
+ } else if (inner is Api.Class) {
+ cname = ((Api.Class) inner).get_cname ();
+ } else if (inner is Api.Enum) {
+ cname = ((Api.Enum) inner).get_cname ();
+ } else {
+ assert_not_reached ();
+ }
+
+ param_name = (owned) parts[0];
+ return "c::" + cname + parts[1] + parts[2];
+ }
+
+
+ private string[]? split_type_name (string id) {
+ unichar c;
+
+ for (unowned string pos = id; (c = pos.get_char ()) != '\0'; pos = pos.next_char ()) {
+ switch (c) {
+ case '-': // ->
+ return {id.substring (0, (long) (((char*) pos) - ((char*) id))), "->", (string) (((char*) pos) + 2)};
+
+ case ':': // : or ::
+ string sep = (pos.next_char ().get_char () == ':')? "::" : ":";
+ return {id.substring (0, (long) (((char*) pos) - ((char*) id))), sep, (string) (((char*) pos) + sep.length)};
+
+ case '.':
+ return {id.substring (0, (long) (((char*) pos) - ((char*) id))), ".", (string) (((char*) pos) + 1)};
+ }
+ }
+
+ return {id};
+ }
+
+
+
+ //
+ // extract-short-desc:
+ //
+
+ internal void extract_short_desc (Comment comment, ContentFactory factory) {
+ if (comment.content.size == 0) {
+ return ;
+ }
+
+ Paragraph? first_paragraph = comment.content[0] as Paragraph;
+ if (first_paragraph == null) {
+ // add empty paragraph to avoid non-text as short descriptions
+ comment.content.insert (1, factory.create_paragraph ());
+ return ;
+ }
+
+
+ // avoid fancy stuff in short descriptions:
+ first_paragraph.horizontal_align = null;
+ first_paragraph.vertical_align = null;
+ first_paragraph.style = null;
+
+
+ Paragraph? second_paragraph = split_paragraph (first_paragraph, factory);
+ if (second_paragraph == null) {
+ return ;
+ }
+
+ if (second_paragraph.is_empty () == false) {
+ comment.content.insert (1, second_paragraph);
+ }
+ }
+
+ private inline Text? split_text (Text text, ContentFactory factory) {
+ int offset = 0;
+ while ((offset = text.content.index_of_char ('.', offset)) >= 0) {
+ if (offset >= 2) {
+ // ignore "e.g."
+ unowned string cmp4 = ((string) (((char*) text.content) + offset - 2));
+ if (cmp4.has_prefix (" e.g.") || cmp4.has_prefix ("(e.g.")) {
+ offset = offset + 3;
+ continue;
+ }
+
+ // ignore "i.e."
+ if (cmp4.has_prefix (" i.e.") || cmp4.has_prefix ("(i.e.")) {
+ offset = offset + 3;
+ continue;
+ }
+ }
+
+ unowned string cmp0 = ((string) (((char*) text.content) + offset));
+
+ // ignore ... (varargs)
+ if (cmp0.has_prefix ("...")) {
+ offset = offset + 3;
+ continue;
+ }
+
+ // ignore numbers
+ if (cmp0.get (1).isdigit ()) {
+ offset = offset + 2;
+ continue;
+ }
+
+
+ Text sec = factory.create_text (text.content.substring (offset+1, -1));
+ text.content = text.content.substring (0, offset+1);
+ return sec;
+ }
+
+ return null;
+ }
+
+ private inline Run? split_run (Run run, ContentFactory factory) {
+ if (run.style != Run.Style.NONE) {
+ return null;
+ }
+
+ Run? sec = null;
+
+
+ Iterator<Inline> iter = run.content.iterator ();
+ for (bool has_next = iter.next (); has_next; has_next = iter.next ()) {
+ Inline item = iter.get ();
+ if (sec == null) {
+ Inline? tmp = split_inline (item, factory);
+ if (tmp != null) {
+ sec = factory.create_run (run.style);
+ sec.content.add (tmp);
+ }
+ } else {
+ sec.content.add (item);
+ iter.remove ();
+ }
+ }
+
+ return sec;
+ }
+
+ private inline Inline? split_inline (Inline item, ContentFactory factory) {
+ if (item is Text) {
+ return split_text ((Text) item, factory);
+ } else if (item is Run) {
+ return split_run ((Run) item, factory);
+ }
+
+ return null;
+ }
+
+ private inline Paragraph? split_paragraph (Paragraph p, ContentFactory factory) {
+ Paragraph? sec = null;
+
+ Iterator<Inline> iter = p.content.iterator ();
+ for (bool has_next = iter.next (); has_next; has_next = iter.next ()) {
+ Inline item = iter.get ();
+ if (sec == null) {
+ Inline? tmp = split_inline (item, factory);
+ if (tmp != null) {
+ sec = factory.create_paragraph ();
+ sec.horizontal_align = p.horizontal_align;
+ sec.vertical_align = p.vertical_align;
+ sec.style = p.style;
+ sec.content.add (tmp);
+ }
+ } else {
+ sec.content.add (item);
+ iter.remove ();
+ }
+ }
+
+ return sec;
+ }
+
+}
diff --git a/libvaladoc/documentation/wiki.vala b/libvaladoc/documentation/wiki.vala
new file mode 100644
index 000000000..0f8f4929e
--- /dev/null
+++ b/libvaladoc/documentation/wiki.vala
@@ -0,0 +1,159 @@
+/* wiki.vala
+ *
+ * Copyright (C) 2008-2009 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 Gee;
+
+
+public class Valadoc.WikiPage : Object, Documentation {
+ public Content.Page documentation {
+ protected set;
+ get;
+ }
+
+ public string documentation_str {
+ private set;
+ get;
+ }
+
+ public string path {
+ private set;
+ get;
+ }
+
+ public string name {
+ private set;
+ get;
+ }
+
+
+ public Api.Package? package {
+ get {
+ return _package;
+ }
+ }
+
+ private Api.Package _package;
+
+ /**
+ * The corresponding file name
+ */
+ public string? get_filename () {
+ return Path.get_basename(this.path);
+ }
+
+ public WikiPage (string name, string path, Api.Package package) {
+ this._package = package;
+ this.name = name;
+ this.path = path;
+ }
+
+ public void read (ErrorReporter reporter) {
+ try {
+ string content;
+ FileUtils.get_contents (this.path, out content);
+ this.documentation_str = content;
+ } catch (FileError err) {
+ reporter.simple_error (null, "Unable to read file '%s': %s", this.path, err.message);
+ }
+ }
+
+ public void parse (DocumentationParser docparser, Api.Package pkg) {
+ documentation = docparser.parse_wikipage (pkg, this);
+ }
+}
+
+
+public class Valadoc.WikiPageTree : Object {
+ private ArrayList<WikiPage> wikipages;
+
+
+ public WikiPageTree () {
+ }
+
+ public Collection<WikiPage> get_pages () {
+ return this.wikipages == null? Collection.empty<WikiPage> () : this.wikipages.read_only_view;
+ }
+
+ public WikiPage? search (string name) {
+ if (this.wikipages == null) {
+ return null;
+ }
+
+ foreach (WikiPage page in this.wikipages ) {
+ if (page.name == name) {
+ return page;
+ }
+ }
+ return null;
+ }
+
+ private void create_tree_from_path (DocumentationParser docparser, Api.Package package,
+ ErrorReporter reporter, string path, string? nameoffset = null)
+ {
+ try {
+ Dir dir = Dir.open (path);
+
+ for (string? curname = dir.read_name (); curname!=null ; curname = dir.read_name ()) {
+ string filename = Path.build_filename (path, curname);
+ if (curname.has_suffix (".valadoc") && FileUtils.test (filename, FileTest.IS_REGULAR)) {
+ WikiPage wikipage = new WikiPage ((nameoffset!=null)
+ ? Path.build_filename (nameoffset, curname)
+ : curname, filename, package);
+ this.wikipages.add(wikipage);
+ wikipage.read (reporter);
+ } else if (FileUtils.test (filename, FileTest.IS_DIR)) {
+ this.create_tree_from_path (docparser, package, reporter, filename, (nameoffset!=null)
+ ? Path.build_filename (nameoffset, curname)
+ : curname);
+ }
+ }
+ } catch (FileError err) {
+ reporter.simple_error (null, "Unable to open directory '%s': %s", path, err.message);
+ }
+ }
+
+ public void parse (Settings settings, DocumentationParser docparser, Api.Package package, ErrorReporter reporter) {
+ weak string path = settings.wiki_directory;
+ if (path == null) {
+ return ;
+ }
+
+ this.wikipages = new ArrayList<WikiPage> ();
+ this.create_tree_from_path (docparser, package, reporter, path);
+
+ foreach (WikiPage page in this.wikipages) {
+ page.parse (docparser, package);
+ }
+ }
+
+ public void check (Settings settings, DocumentationParser docparser, Api.Package pkg) {
+ if (this.wikipages == null) {
+ return ;
+ }
+
+ foreach (WikiPage page in this.wikipages) {
+ docparser.check_wikipage (pkg, page);
+ }
+ }
+}
+
+
diff --git a/libvaladoc/documentation/wikiscanner.vala b/libvaladoc/documentation/wikiscanner.vala
new file mode 100644
index 000000000..81f6ae8e2
--- /dev/null
+++ b/libvaladoc/documentation/wikiscanner.vala
@@ -0,0 +1,395 @@
+/* wikiscanner.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+public class Valadoc.WikiScanner : Object, Scanner {
+
+ public WikiScanner (Settings settings) {
+ _settings = settings;
+ }
+
+ private Settings _settings;
+ private Parser _parser;
+
+ private string _content;
+ private unowned string _index;
+ private bool _stop;
+ private int _last_line;
+ private int _last_column;
+ private int _line;
+ private int _column;
+ private bool _url_escape_mode;
+ private bool _code_escape_mode;
+ private unichar _last_char;
+ private int _skip;
+ private StringBuilder _current_string = new StringBuilder ();
+
+ public void set_parser (Parser parser) {
+ _parser = parser;
+ }
+
+ public virtual void reset () {
+ _stop = false;
+ _last_line = 0;
+ _last_column = 0;
+ _line = 0;
+ _column = 0;
+ _url_escape_mode = false;
+ _code_escape_mode = false;
+ _last_char = 0;
+ _skip = 0;
+ _current_string.erase (0, -1);
+ }
+
+ public void scan (string content) throws ParserError {
+ this._content = content;
+
+ for (_index = _content; !_stop && _index.get_char () != 0; _index = _index.next_char ()) {
+ unichar c = _index.get_char ();
+ accept (c);
+ }
+ }
+
+ public void end () throws ParserError {
+ emit_token (TokenType.EOF);
+ }
+
+ public virtual void stop () {
+ _stop = true;
+ }
+
+ public void set_url_escape_mode (bool escape_mode) {
+ _url_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 () {
+ StringBuilder builder = new StringBuilder ();
+ weak string line_start = _index;
+ unichar c;
+
+ while ((char*) line_start > (char*) _content && line_start.prev_char ().get_char () != '\n') {
+ line_start = line_start.prev_char ();
+ }
+
+ while ((c = line_start.get_char ()) != '\n' && c != '\0') {
+ if (c == '\t') {
+ builder.append_c (' ');
+ } else {
+ builder.append_unichar (c);
+ }
+ line_start = line_start.next_char ();
+ }
+
+ return builder.str;
+ }
+
+ protected unichar get_next_char (int offset = 1) {
+ return _index.get_char (_index.index_of_nth_char (offset));
+ }
+
+ protected virtual void accept (unichar c) throws ParserError {
+ _column++;
+ if (_skip == 0) {
+ if (_code_escape_mode) {
+ if (c == '}' && get_next_char (1) == '}' && get_next_char (2) == '}') {
+ _code_escape_mode = false; // This is a temporary hack
+ emit_token (TokenType.TRIPLE_CLOSED_BRACE);
+ _skip = 2;
+ } else {
+ append_char (c);
+ }
+ return;
+ } else if (_url_escape_mode) {
+ switch (c) {
+ // Reserved characters
+ case ';':
+ case '/':
+ case '?':
+ case ':':
+ case '@':
+ case '#':
+ case '=':
+ case '&':
+ // Special characters
+ case '$':
+ case '-':
+ case '_':
+ case '.':
+ case '+':
+ case '!':
+ case '*':
+ case '\'':
+ case '(':
+ case ')':
+ case ',':
+ append_char (c);
+ return;
+ default:
+ break;
+ }
+ }
+
+ switch (c) {
+ case '@':
+ emit_token (TokenType.AROBASE);
+ break;
+
+ case '{':
+ look_for_three (c,
+ TokenType.OPEN_BRACE,
+ TokenType.DOUBLE_OPEN_BRACE,
+ TokenType.TRIPLE_OPEN_BRACE);
+ break;
+
+ case '}':
+ look_for_three (c,
+ TokenType.CLOSED_BRACE,
+ TokenType.DOUBLE_CLOSED_BRACE,
+ TokenType.TRIPLE_CLOSED_BRACE);
+ break;
+
+ case '[':
+ look_for_two_or_append (c, TokenType.DOUBLE_OPEN_BRACKET);
+ break;
+
+ case ']':
+ look_for_two_or_append (c, TokenType.DOUBLE_CLOSED_BRACKET);
+ break;
+
+ case '|':
+ look_for_two (c,
+ TokenType.PIPE,
+ TokenType.DOUBLE_PIPE);
+ break;
+
+ case ')':
+ if (get_next_char () == ')') {
+ emit_token (TokenType.ALIGN_RIGHT);
+ _skip = 1;
+ } else if (get_next_char () == '(') {
+ emit_token (TokenType.ALIGN_CENTER);
+ _skip = 1;
+ } else {
+ append_char (c);
+ }
+ break;
+
+ case '-':
+ emit_token (TokenType.MINUS);
+ break;
+
+ case '=':
+ look_for_five (c,
+ TokenType.EQUAL_1,
+ TokenType.EQUAL_2,
+ TokenType.EQUAL_3,
+ TokenType.EQUAL_4,
+ TokenType.EQUAL_5);
+ break;
+
+ case '<':
+ if (!look_for ("<<BR>>", TokenType.BREAK)) {
+ emit_token (TokenType.LESS_THAN);
+ }
+ break;
+
+ case '>':
+ emit_token (TokenType.GREATER_THAN);
+ break;
+
+ case '^':
+ emit_token (TokenType.ALIGN_TOP);
+ break;
+
+ case 'v':
+ unichar next_char = get_next_char ();
+ if (_last_char.isalnum () || _last_char == ' '
+ || next_char.isalnum () || next_char == ' ') {
+ append_char (c);
+ } else {
+ emit_token (TokenType.ALIGN_BOTTOM);
+ }
+ break;
+
+ case '\'':
+ look_for_two_or_append (c, TokenType.SINGLE_QUOTE_2);
+ break;
+
+ case '/':
+ look_for_two_or_append (c, TokenType.SLASH_2);
+ break;
+
+ case '_':
+ look_for_two_or_append (c, TokenType.UNDERSCORE_2);
+ break;
+
+ case '`':
+ if (get_next_char () == '`') {
+ emit_token (TokenType.BACK_QUOTE_2);
+ _skip = 1;
+ } else {
+ append_char (c);
+ }
+ break;
+
+ case '\t':
+ emit_token (TokenType.TAB);
+ break;
+
+ case ' ':
+ emit_token (TokenType.SPACE);
+ break;
+
+ case '\r':
+ break;
+
+ case '\n':
+ emit_token (TokenType.EOL);
+ _line++;
+ _column = 0;
+ _last_column = 0;
+ break;
+
+ default:
+ append_char (c);
+ break;
+ }
+ } else {
+ _skip--;
+ }
+ _last_char = c;
+ }
+
+ private void append_char (unichar c) {
+ _current_string.append_unichar (c);
+ }
+
+ public virtual 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_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_line = _line;
+ _last_column = _column;
+ }
+
+ private void look_for_two_or_append (unichar c, TokenType type) throws ParserError {
+ if (get_next_char () == c) {
+ emit_token (type);
+ _skip = 1;
+ } else {
+ append_char (c);
+ }
+ }
+
+ private void look_for_two (unichar c, TokenType one, TokenType two) throws ParserError {
+ if (get_next_char (1) == c) {
+ emit_token (two);
+ _skip = 1;
+ } else {
+ emit_token (one);
+ }
+ }
+
+ private void look_for_three (unichar c, TokenType one, TokenType two, TokenType three)
+ throws ParserError
+ {
+ if (get_next_char (1) == c) {
+ if (get_next_char (2) == c) {
+ emit_token (three);
+ _skip = 2;
+ } else {
+ emit_token (two);
+ _skip = 1;
+ }
+ } else {
+ emit_token (one);
+ }
+ }
+
+ private void look_for_five (unichar c, TokenType one, TokenType two, TokenType three,
+ TokenType four, TokenType five) throws ParserError
+ {
+ if (get_next_char (1) == c) {
+ if (get_next_char (2) == c) {
+ if (get_next_char (3) == c) {
+ if (get_next_char (4) == c) {
+ emit_token (five);
+ _skip = 4;
+ } else {
+ emit_token (four);
+ _skip = 3;
+ }
+ } else {
+ emit_token (three);
+ _skip = 2;
+ }
+ } else {
+ emit_token (two);
+ _skip = 1;
+ }
+ } else {
+ emit_token (one);
+ }
+ }
+
+ private bool look_for (string str, TokenType type) throws ParserError {
+ for (int i = 1; i < str.length; i++) {
+ if (get_next_char (i) != str[i]) {
+ return false;
+ }
+ }
+
+ emit_token (type);
+ _skip = (int) (str.length - 1);
+ return true;
+ }
+}
diff --git a/libvaladoc/errorreporter.vala b/libvaladoc/errorreporter.vala
new file mode 100644
index 000000000..5b9543e62
--- /dev/null
+++ b/libvaladoc/errorreporter.vala
@@ -0,0 +1,392 @@
+/* errorreporter.vala
+ *
+ * Copyright (C) 2008-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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+using Gee;
+
+
+public class Valadoc.ErrorReporter : Object {
+ private int _warnings = 0;
+ private int _errors = 0;
+
+ /**
+ * SGR end tag
+ */
+ private const string ANSI_COLOR_END = "\x1b[0m";
+
+ /**
+ * SGR start tag for source location
+ */
+ private string locus_color_start = "";
+
+ /**
+ * SGR end tag for source location
+ */
+ private unowned string locus_color_end = "";
+
+ /**
+ * SGR start tag for warning titles
+ */
+ private string warning_color_start = "";
+
+ /**
+ * SGR end tag for warning titles
+ */
+ private unowned string warning_color_end = "";
+
+ /**
+ * SGR start tag for error titles
+ */
+ private string error_color_start = "";
+
+ /**
+ * SGR end tag for error titles
+ */
+ private unowned string error_color_end = "";
+
+ /**
+ * SGR start tag for note titles
+ */
+ private string note_color_start = "";
+
+ /**
+ * SGR end tag for note titles
+ */
+ private unowned string note_color_end = "";
+
+ /**
+ * SGR start tag for caret line (^^^)
+ */
+ private string caret_color_start = "";
+
+ /**
+ * SGR end tag for caret line (^^^)
+ */
+ private unowned string caret_color_end = "";
+
+ /**
+ * SGR start tag for quotes line ('', ``, `')
+ */
+ private string quote_color_start = "";
+
+ /**
+ * SGR end tag for quotes line ('', ``, `')
+ */
+ private unowned string quote_color_end = "";
+
+
+ public int warnings_offset {
+ get;
+ set;
+ }
+
+ public int errors_offset {
+ get;
+ set;
+ }
+
+ public unowned GLib.FileStream stream {
+ get;
+ set;
+ }
+
+ public Settings? settings {
+ get;
+ set;
+ }
+
+ public int errors {
+ get {
+ return this._errors + errors_offset;
+ }
+ }
+
+ public int warnings {
+ get {
+ return this._warnings + warnings_offset;
+ }
+ }
+
+
+ public ErrorReporter (Settings? settings = null) {
+ this.stream = GLib.stderr;
+ this.settings = settings;
+ }
+
+ /**
+ * Set all colors by string
+ *
+ * {{{
+ * "error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01"
+ * }}}
+ */
+ public bool set_colors (string str) {
+ Regex val_regex;
+ try {
+ val_regex = new Regex ("^\\s*[0-9]+(;[0-9]*)*\\s*$");
+ } catch (RegexError e) {
+ assert_not_reached ();
+ }
+
+ string error_color = null;
+ string warning_color = null;
+ string note_color = null;
+ string caret_color = null;
+ string locus_color = null;
+ string quote_color = null;
+
+ string[] fragments = str.split (":");
+ foreach (unowned string fragment in fragments) {
+ string[] eq = fragment.split ("=", 2);
+ if (eq.length != 2) {
+ return false;
+ }
+
+ if (!val_regex.match (eq[1])) {
+ return false;
+ }
+
+
+ unowned string checked_value = eq[1]._strip ();
+ switch (eq[0]._strip ()) {
+ case "error":
+ error_color = checked_value;
+ break;
+
+ case "warning":
+ warning_color = checked_value;
+ break;
+
+ case "note":
+ note_color = checked_value;
+ break;
+
+ case "caret":
+ caret_color = checked_value;
+ break;
+
+ case "locus":
+ locus_color = checked_value;
+ break;
+
+ case "quote":
+ quote_color = checked_value;
+ break;
+
+ default:
+ return false;
+ }
+ }
+
+ if (is_atty (this.stream.fileno ())) {
+ if (error_color != null) {
+ this.error_color_start = "\x1b[0" + error_color + "m";
+ this.error_color_end = ANSI_COLOR_END;
+ }
+
+ if (warning_color != null) {
+ this.warning_color_start = "\x1b[0" + warning_color + "m";
+ this.warning_color_end = ANSI_COLOR_END;
+ }
+
+ if (note_color != null) {
+ this.note_color_start = "\x1b[0" + note_color + "m";
+ this.note_color_end = ANSI_COLOR_END;
+ }
+
+ if (caret_color != null) {
+ this.caret_color_start = "\x1b[0" + caret_color + "m";
+ this.caret_color_end = ANSI_COLOR_END;
+ }
+
+ if (locus_color != null) {
+ this.locus_color_start = "\x1b[0" + locus_color + "m";
+ this.locus_color_end = ANSI_COLOR_END;
+ }
+
+ if (quote_color != null) {
+ this.quote_color_start = "\x1b[0" + quote_color + "m";
+ this.quote_color_end = ANSI_COLOR_END;
+ }
+ }
+ return true;
+ }
+
+ [CCode (has_target = false)]
+ private delegate int AttyFunc (int fd);
+
+ private bool is_atty (int fd) {
+ Module module = Module.open (null, ModuleFlags.BIND_LAZY);
+ if (module == null) {
+ return false;
+ }
+
+ void* _func;
+ module.symbol ("isatty", out _func);
+ if (_func == null) {
+ return false;
+ }
+
+ AttyFunc? func = (AttyFunc) _func;
+ return func (fd) == 1;
+ }
+
+ [PrintfFormat]
+ private inline void msg (string type, string type_color_start, string type_color_end, string file, long line, long startpos, long endpos,
+ string errline, string msg_format, va_list args)
+ {
+ this.stream.printf ("%s%s:%lu.%lu-%lu.%lu:%s %s%s:%s ",
+ locus_color_start, file, line, startpos, line, endpos, locus_color_end,
+ type_color_start, type, type_color_end);
+ print_highlighted_message (msg_format.vprintf (args));
+ this.stream.putc ('\n');
+
+ if (startpos <= endpos) {
+ this.stream.printf ("%s\n", errline);
+
+ this.stream.puts (caret_color_start);
+ for (int i = 0; i < errline.char_count ()+1; i++) {
+ if (errline[i] == '\t') {
+ this.stream.printf ("\t");
+ } else if (i >= startpos - 1 && i < endpos - 1) {
+ this.stream.printf ("^");
+ } else {
+ this.stream.printf (" ");
+ }
+ }
+ this.stream.puts (caret_color_end);
+ this.stream.printf ("\n");
+ }
+ }
+
+ private void print_highlighted_message (string message) {
+ int start = 0;
+ int cur = 0;
+
+ while (message[cur] != '\0') {
+ if (message[cur] == '\'' || message[cur] == '`') {
+ unowned string end_chars = (message[cur] == '`')? "`'" : "'";
+ this.stream.puts (message.substring (start, cur - start));
+ start = cur;
+ cur++;
+
+ while (message[cur] != '\0' && end_chars.index_of_char (message[cur]) < 0) {
+ cur++;
+ }
+ if (message[cur] == '\0') {
+ this.stream.puts (message.substring (start, cur - start));
+ start = cur;
+ } else {
+ cur++;
+ this.stream.printf ("%s%s%s", quote_color_start, message.substring (start, cur - start), quote_color_end);
+ start = cur;
+ }
+ } else {
+ cur++;
+ }
+ }
+
+ this.stream.puts (message.offset (start));
+ }
+
+ [PrintfFormat]
+ public void simple_warning (string? location, string msg_format, ...) {
+ var args = va_list();
+
+ if (location != null) {
+ this.stream.puts (locus_color_start);
+ this.stream.puts (location);
+ this.stream.puts (": ");
+ this.stream.puts (locus_color_end);
+ }
+
+ this.stream.puts (warning_color_start);
+ this.stream.puts ("warning: ");
+ this.stream.puts (warning_color_end);
+
+ print_highlighted_message (msg_format.vprintf (args));
+ this.stream.putc ('\n');
+ this._warnings++;
+ }
+
+ [PrintfFormat]
+ public void simple_error (string? location, string msg_format, ...) {
+ var args = va_list();
+
+ if (location != null) {
+ this.stream.puts (locus_color_start);
+ this.stream.puts (location);
+ this.stream.puts (": ");
+ this.stream.puts (locus_color_end);
+ this.stream.putc (' ');
+ }
+
+ this.stream.puts (error_color_start);
+ this.stream.puts ("error: ");
+ this.stream.puts (error_color_end);
+
+ print_highlighted_message (msg_format.vprintf (args));
+ this.stream.putc ('\n');
+ this._errors++;
+ }
+
+ [PrintfFormat]
+ public void simple_note (string? location, string msg_format, ...) {
+ if (_settings == null || _settings.verbose) {
+ var args = va_list();
+
+ if (location != null) {
+ this.stream.puts (locus_color_start);
+ this.stream.puts (location);
+ this.stream.puts (": ");
+ this.stream.puts (locus_color_end);
+ this.stream.putc (' ');
+ }
+
+ this.stream.puts (note_color_start);
+ this.stream.puts ("note: ");
+ this.stream.puts (note_color_end);
+
+ print_highlighted_message (msg_format.vprintf (args));
+ this.stream.putc ('\n');
+ this._warnings++;
+ }
+ }
+
+ [PrintfFormat]
+ public void error (string file, long line, long startpos, long endpos, string errline,
+ string msg_format, ...)
+ {
+ var args = va_list();
+ this.msg ("error", error_color_start, error_color_end, file, line, startpos, endpos, errline, msg_format, args);
+ this._errors++;
+ }
+
+ [PrintfFormat]
+ public void warning (string file, long line, long startpos, long endpos, string errline,
+ string msg_format, ...)
+ {
+ var args = va_list();
+ this.msg ("warning", warning_color_start, warning_color_end, file, line, startpos, endpos, errline, msg_format, args);
+ this._warnings++;
+ }
+}
+
diff --git a/libvaladoc/filehelper.vala b/libvaladoc/filehelper.vala
new file mode 100644
index 000000000..bc2369b36
--- /dev/null
+++ b/libvaladoc/filehelper.vala
@@ -0,0 +1,200 @@
+/* filehelper.vala
+ *
+ * Copyright (C) 2008-2009 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+using Gee;
+
+
+namespace Valadoc {
+ [CCode (cprefix = "", cname = "PACKAGE_ICONDIR")]
+ public extern const string icons_dir;
+
+ /**
+ * Makes a copy of the file src to dest.
+ *
+ * @param src the file to copy
+ * @param dest the destination path
+ */
+ public bool copy_file (string src, string dest) {
+ GLib.FileStream fsrc = GLib.FileStream.open (src, "rb");
+ if (fsrc == null) {
+ return false;
+ }
+
+ GLib.FileStream fdest = GLib.FileStream.open (dest, "wb");
+ if (fdest == null) {
+ return false;
+ }
+
+ for (int c = fsrc.getc() ; !fsrc.eof() ; c = fsrc.getc()) {
+ fdest.putc ((char)c);
+ }
+
+ return true;
+ }
+
+ /**
+ * Makes a copy of the directory src to dest.
+ *
+ * @param src the directory to copy
+ * @param dest the destination path
+ */
+ public bool copy_directory (string src, string dest) {
+ try {
+ GLib.Dir dir = GLib.Dir.open (src);
+ for (string? file = dir.read_name (); file != null; file = dir.read_name ()) {
+ string src_file_path = GLib.Path.build_filename (src, file);
+ string dest_file_path = GLib.Path.build_filename (dest, file);
+ if (GLib.FileUtils.test (src_file_path, GLib.FileTest.IS_DIR)) {
+ GLib.DirUtils.create (dest_file_path, 0755); // mkdir if necessary
+ if (!copy_directory (src_file_path, dest_file_path)) { // copy directories recursively
+ return false;
+ }
+ } else {
+ if (!copy_file (src_file_path, dest_file_path)) {
+ return false;
+ }
+ }
+ }
+ }
+ catch (GLib.FileError err) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * A recursive directory delete function
+ *
+ * @param rpath the directory to remove
+ */
+ public bool remove_directory (string rpath) {
+ try {
+ GLib.Dir dir = GLib.Dir.open ( rpath );
+ if (dir == null)
+ return false;
+
+ for (weak string entry = dir.read_name(); entry != null ; entry = dir.read_name()) {
+ string path = rpath + entry;
+
+ bool is_dir = GLib.FileUtils.test (path, GLib.FileTest.IS_DIR);
+ if (is_dir == true) {
+ bool tmp = remove_directory (path);
+ if (tmp == false) {
+ return false;
+ }
+ } else {
+ int tmp = GLib.FileUtils.unlink (path);
+ if (tmp > 0) {
+ return false;
+ }
+ }
+ }
+ } catch (GLib.FileError err) {
+ return false;
+ }
+
+ return true;
+ }
+
+
+ private inline bool ends_with_dir_separator (string s) {
+ // --- ported from libvala ---
+ return Path.is_dir_separator (s.get_char (s.length - 1));
+ }
+
+ /**
+ * Returns canonicalized absolute pathname
+ *
+ * @param name the path being checked
+ * @return a canonicalized absolute pathname
+ */
+ public string realpath (string name) {
+ // --- ported from libvala ---
+
+ string rpath;
+
+ // start of path component
+ weak string start;
+ // end of path component
+ weak string end;
+
+ if (!Path.is_absolute (name)) {
+ // relative path
+ rpath = Environment.get_current_dir ();
+
+ start = end = name;
+ } else {
+ // set start after root
+ start = end = Path.skip_root (name);
+
+ // extract root
+ rpath = name.substring (0, (int) ((char*) start - (char*) name));
+ }
+
+ long root_len = (long) ((char*) Path.skip_root (rpath) - (char*) rpath);
+
+ for (; start.get_char () != 0; start = end) {
+ // skip sequence of multiple path-separators
+ while (Path.is_dir_separator (start.get_char ())) {
+ start = start.next_char ();
+ }
+
+ // find end of path component
+ long len = 0;
+ for (end = start; end.get_char () != 0 && !Path.is_dir_separator (end.get_char ()); end = end.next_char ()) {
+ len++;
+ }
+
+ if (len == 0) {
+ break;
+ } else if (len == 1 && start.get_char () == '.') {
+ // do nothing
+ } else if (len == 2 && start.has_prefix ("..")) {
+ // back up to previous component, ignore if at root already
+ if (rpath.length > root_len) {
+ do {
+ rpath = rpath.substring (0, rpath.length - 1);
+ } while (!ends_with_dir_separator (rpath));
+ }
+ } else {
+ if (!ends_with_dir_separator (rpath)) {
+ rpath += Path.DIR_SEPARATOR_S;
+ }
+
+ rpath += start.substring (0, len);
+ }
+ }
+
+ if (rpath.length > root_len && ends_with_dir_separator (rpath)) {
+ rpath = rpath.substring (0, rpath.length - 1);
+ }
+
+ if (Path.DIR_SEPARATOR != '/') {
+ // don't use backslashes internally,
+ // to avoid problems in #include directives
+ string[] components = rpath.split ("\\");
+ rpath = string.joinv ("/", components);
+ }
+
+ return rpath;
+ }
+}
+
diff --git a/libvaladoc/gtkdocmarkupwriter.vala b/libvaladoc/gtkdocmarkupwriter.vala
new file mode 100644
index 000000000..1e7276789
--- /dev/null
+++ b/libvaladoc/gtkdocmarkupwriter.vala
@@ -0,0 +1,73 @@
+/* gtkdocmarkupwriter.vala
+ *
+ * Copyright (C) 2012 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>
+ */
+
+
+
+public class Valadoc.GtkDocMarkupWriter : Valadoc.MarkupWriter {
+ private unowned StringBuilder builder;
+
+ public void reset () {
+ last_was_tag = true;
+ current_column = 0;
+ builder.erase ();
+ indent = -1;
+ }
+
+ public unowned string content {
+ get { return builder.str; }
+ }
+
+ public GtkDocMarkupWriter () {
+ StringBuilder builder = new StringBuilder ();
+ base ((str) => { builder.append (str); }, false);
+ this.builder = builder;
+ }
+
+ protected override bool inline_element (string name) {
+ return name != "para"
+ && name != "programlisting"
+ && name != "table"
+ && name != "example"
+ && name != "figure"
+ && name != "tr"
+ && name != "td"
+ && name != "mediaobject"
+ && name != "imageobject"
+ && name != "textobject"
+ && name != "listitem"
+ && name != "orderedlist"
+ && name != "itemizedlist"
+ && name != "title";
+ }
+
+ protected override bool content_inline_element (string name) {
+ return name == "para"
+ || name == "programlisting"
+ || name == "emphasis"
+ || name == "blockquote"
+ || name == "ulink"
+ || name == "listitem"
+ || name == "title";
+ }
+}
+
+
diff --git a/libvaladoc/gtkdocrenderer.vala b/libvaladoc/gtkdocrenderer.vala
new file mode 100644
index 000000000..877d7c5c9
--- /dev/null
+++ b/libvaladoc/gtkdocrenderer.vala
@@ -0,0 +1,503 @@
+/* gtkdocrenderer.vala
+ *
+ * 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:
+ * Florian Brosch <flo.brosch@gmail.com>
+ */
+
+using GLib;
+using Valadoc.Content;
+
+public class Valadoc.GtkdocRenderer : ContentRenderer {
+ private GtkDocMarkupWriter writer = new GtkDocMarkupWriter ();
+ protected Settings settings;
+ private bool separated;
+
+ private string? get_cname (Api.Item item) {
+ if (item is Api.Method) {
+ return ((Api.Method)item).get_cname ();
+ } else if (item is Api.FormalParameter) {
+ return ((Api.FormalParameter)item).name;
+ } else if (item is Api.Constant) {
+ return ((Api.Constant)item).get_cname ();
+ } else if (item is Api.Property) {
+ return ((Api.Property)item).get_cname ();
+ } else if (item is Api.Signal) {
+ var name = ((Api.Signal)item).get_cname ();
+ return name.replace ("_", "-");
+ } else if (item is Api.Class) {
+ return ((Api.Class)item).get_cname ();
+ } else if (item is Api.Struct) {
+ return ((Api.Struct)item).get_cname ();
+ } else if (item is Api.Interface) {
+ return ((Api.Interface)item).get_cname ();
+ } else if (item is Api.ErrorDomain) {
+ return ((Api.ErrorDomain)item).get_cname ();
+ } else if (item is Api.ErrorCode) {
+ return ((Api.ErrorCode)item).get_cname ();
+ } else if (item is Api.Delegate) {
+ return ((Api.Delegate)item).get_cname ();
+ } else if (item is Api.Enum) {
+ return ((Api.Enum)item).get_cname ();
+ } else if (item is Api.EnumValue) {
+ return ((Api.EnumValue)item).get_cname ();
+ }
+
+ return null;
+ }
+
+ public void write_docbook_link (Api.Item item) {
+ writer.set_wrap (false);
+
+ if (item is Api.Method) {
+ writer.start_tag ("function")
+ .text (((Api.Method)item).get_cname ())
+ .end_tag ("function");
+ } else if (item is Api.FormalParameter) {
+ writer.start_tag ("parameter").
+ text (((Api.FormalParameter)item).name ?? "...")
+ .end_tag ("parameter");
+ } else if (item is Api.Constant) {
+ writer.start_tag ("constant").text (((Api.Constant)item)
+ .get_cname ())
+ .end_tag ("constant");
+ } else if (item is Api.Property) {
+ // TODO: use docbook-tags instead
+ writer.text ("#").text (get_cname(item.parent))
+ .text (":")
+ .text (((Api.Property)item)
+ .get_cname ().replace ("_", "-"));
+ } else if (item is Api.Signal) {
+ // TODO: use docbook-tags instead
+ writer.text ("#").text (get_cname(item.parent))
+ .text ("::")
+ .text (((Api.Signal)item).get_cname ().replace ("_", "-"));
+ } else if (item is Api.Namespace) {
+ writer.text (((Api.Namespace) item).get_full_name ());
+ } else {
+ writer.start_tag ("type")
+ .text (get_cname (item))
+ .end_tag ("type");
+ }
+
+ writer.set_wrap (true);
+ }
+
+ public GtkdocRenderer () {
+ }
+
+ public override void render (ContentElement element) {
+ reset ();
+ element.accept (this);
+ }
+
+ public void render_symbol (Content.Comment? documentation) {
+ render (documentation);
+
+ append_exceptions (documentation.find_taglets (null, typeof(Taglets.Throws)));
+ append_see (documentation.find_taglets (null, typeof(Taglets.See)));
+ append_since (documentation.find_taglets (null, typeof(Taglets.Since)));
+ }
+
+ public override void render_children (ContentElement element) {
+ reset ();
+ element.accept_children (this);
+ }
+
+ private void reset () {
+ separated = false;
+ writer.reset ();
+ }
+
+ public unowned string content {
+ get {
+ if (writer.content.has_prefix ("\n")) {
+ return writer.content.next_char ();
+ }
+
+ return writer.content;
+ }
+ }
+
+ public override void visit_comment (Comment element) {
+ element.accept_children (this);
+ }
+
+ public override void visit_embedded (Embedded element) {
+ writer.start_tag ("figure");
+ if (element.caption != null) {
+ writer.start_tag ("title")
+ .text (element.caption)
+ .end_tag ("title");
+ }
+
+ writer.start_tag ("mediaobject");
+
+ writer.start_tag ("imageobject")
+ .simple_tag ("imagedata", {"fileref", element.url})
+ .end_tag ("imageobject");
+
+ if (element.caption != null) {
+ writer.start_tag ("textobject")
+ .start_tag ("phrase")
+ .text (element.caption)
+ .end_tag ("phrase")
+ .end_tag ("textobject");
+ }
+
+ writer.end_tag ("mediaobject");
+ writer.end_tag ("figure");
+ }
+
+ public override void visit_headline (Headline element) {
+ assert_not_reached ();
+ }
+
+ public override void visit_wiki_link (WikiLink element) {
+ // wiki pages are not supported by gir
+ if (element.content.size > 0) {
+ element.accept_children (this);
+ } else {
+ write_string (element.name);
+ }
+ }
+
+ public override void visit_link (Link element) {
+ writer.start_tag ("ulink", {"url", element.url});
+ element.accept_children (this);
+ writer.end_tag ("ulink");
+ }
+
+ public override void visit_symbol_link (SymbolLink element) {
+ if (element.content.size > 0) {
+ writer.text ("\"");
+ element.accept_children (this);
+ writer.text ("\" (");
+ visit_symbol_link (element);
+ writer.text (")");
+ } else {
+ visit_symbol_link (element);
+ }
+ }
+
+ public void write_symbol_link (SymbolLink element) {
+ if (element.symbol == null) {
+ writer.text (element.given_symbol_name);
+ } else {
+ write_docbook_link (element.symbol);
+ }
+ }
+
+ public override void visit_list (Content.List element) {
+ string tag = "orderedlist";
+ switch (element.bullet) {
+ case Content.List.Bullet.NONE:
+ writer.start_tag ("itemizedlist", {"mark", "none"});
+ tag = "itemizedlist";
+ break;
+
+ case Content.List.Bullet.UNORDERED:
+ writer.start_tag ("itemizedlist");
+ tag = "itemizedlist";
+ break;
+
+ case Content.List.Bullet.ORDERED:
+ writer.start_tag ("orderedlist");
+ break;
+
+ case Content.List.Bullet.ORDERED_NUMBER:
+ writer.start_tag ("orderedlist", {"numeration", "arabic"});
+ break;
+
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ALPHA:
+ writer.start_tag ("orderedlist", {"numeration", "loweralpha"});
+ break;
+
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ALPHA:
+ writer.start_tag ("orderedlist", {"numeration", "upperalpha"});
+ break;
+
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ROMAN:
+ writer.start_tag ("orderedlist", {"numeration", "lowerroman"});
+ break;
+
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ROMAN:
+ writer.start_tag ("orderedlist", {"numeration", "upperroman"});
+ break;
+
+ default:
+ assert_not_reached ();
+ }
+
+ element.accept_children (this);
+
+ writer.end_tag (tag);
+ }
+
+ public override void visit_list_item (ListItem element) {
+ writer.start_tag ("listitem");
+ element.accept_children (this);
+ writer.end_tag ("listitem");
+ }
+
+ public override void visit_page (Page element) {
+ element.accept_children (this);
+ }
+
+ public override void visit_paragraph (Paragraph element) {
+ writer.start_tag ("para");
+ element.accept_children (this);
+ writer.end_tag ("para");
+ }
+
+ public override void visit_warning (Warning element) {
+ writer.start_tag ("warning");
+ element.accept_children (this);
+ writer.end_tag ("warning");
+ }
+
+ public override void visit_note (Note element) {
+ writer.start_tag ("note");
+ element.accept_children (this);
+ writer.end_tag ("note");
+ }
+
+ public override void visit_run (Run element) {
+ string? tag = null;
+
+ switch (element.style) {
+ case Run.Style.BOLD:
+ writer.start_tag ("emphasis", {"role", "bold"});
+ tag = "emphasis";
+ break;
+
+ case Run.Style.ITALIC:
+ writer.start_tag ("emphasis");
+ tag = "emphasis";
+ break;
+
+ case Run.Style.UNDERLINED:
+ writer.start_tag ("emphasis", {"role", "underline"});
+ tag = "emphasis";
+ break;
+
+ case Run.Style.MONOSPACED:
+ writer.start_tag ("blockquote");
+ tag = "blockquote";
+ break;
+ }
+
+ element.accept_children (this);
+
+ if (tag != null) {
+ writer.end_tag (tag);
+ }
+ }
+
+ public override void visit_source_code (SourceCode element) {
+ writer.start_tag ("example")
+ .start_tag ("programlisting");
+ writer.text (element.code);
+ writer.end_tag ("programlisting")
+ .end_tag ("example");
+ }
+
+ public override void visit_table (Table element) {
+ writer.start_tag ("table", {"align", "center"});
+ element.accept_children (this);
+ writer.end_tag ("table");
+ }
+
+ public override void visit_table_cell (TableCell element) {
+ writer.start_tag ("td", {"colspan", element.colspan.to_string (), "rowspan", element.rowspan.to_string ()});
+ element.accept_children (this);
+ writer.end_tag ("td");
+ }
+
+ public override void visit_table_row (TableRow element) {
+ writer.start_tag ("tr");
+ element.accept_children (this);
+ writer.end_tag ("tr");
+ }
+
+ public override void visit_text (Text element) {
+ write_string (element.content);
+ }
+
+ private void write_string (string content) {
+ unichar chr = content[0];
+ long lpos = 0;
+ int i = 0;
+
+ for (i = 0; chr != '\0' ; i++, chr = content[i]) {
+ switch (chr) {
+ case '<':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&lt;");
+ lpos = i+1;
+ break;
+
+ case '>':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&gt;");
+ lpos = i+1;
+ break;
+
+ case '"':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&quot;");
+ lpos = i+1;
+ break;
+
+ case '\'':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&apos;");
+ lpos = i+1;
+ break;
+
+ case '&':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&amp;");
+ lpos = i+1;
+ break;
+
+ case '#':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&num;");
+ lpos = i+1;
+ break;
+
+ case '%':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&percnt;");
+ lpos = i+1;
+ break;
+
+ case '@':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&commat;");
+ lpos = i+1;
+ break;
+
+ case '(':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&lpar;");
+ lpos = i+1;
+ break;
+
+ case ')':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.raw_text ("&rpar;");
+ lpos = i+1;
+ break;
+
+ case '\n':
+ writer.raw_text (content.substring (lpos, i-lpos));
+ writer.simple_tag ("br");
+ lpos = i+1;
+ break;
+ }
+ }
+
+ writer.raw_text (content.substring (lpos, i-lpos));
+ }
+
+ public void append_since (Gee.List<Content.Taglet> taglets) {
+ foreach (Content.Taglet _taglet in taglets) {
+ Taglets.Since taglet = _taglet as Taglets.Since;
+ if (taglet == null || taglet.version == null) {
+ // ignore unexpected taglets
+ continue ;
+ }
+
+ if (separated == false) {
+ writer.text ("\n");
+ }
+
+ writer.set_wrap (false);
+ writer.text ("\nSince: ")
+ .text (taglet.version);
+ writer.set_wrap (true);
+ separated = true;
+
+ // ignore multiple occurrences
+ return ;
+ }
+ }
+
+ public void append_see (Gee.List<Content.Taglet> taglets) {
+ bool first = true;
+ foreach (Content.Taglet _taglet in taglets) {
+ Taglets.See taglet = _taglet as Taglets.See;
+ if (taglet == null || taglet.symbol == null) {
+ // ignore unexpected taglets
+ continue ;
+ }
+
+ if (first) {
+ writer.start_tag ("para").text ("See also: ");
+ } else {
+ writer.text (", ");
+ }
+
+ write_docbook_link (taglet.symbol);
+ first = false;
+ }
+
+ if (first == false) {
+ writer.end_tag ("para");
+ }
+ }
+
+ public void append_exceptions (Gee.List<Content.Taglet> taglets) {
+ bool first = true;
+ foreach (Content.Taglet _taglet in taglets) {
+ Taglets.Throws taglet = _taglet as Taglets.Throws;
+ if (taglet == null || taglet.error_domain == null) {
+ // ignore unexpected taglets
+ continue ;
+ }
+
+ if (first) {
+ writer.start_tag ("para")
+ .text ("This function may throw:")
+ .end_tag ("para");
+ writer.start_tag ("table");
+ }
+
+ writer.start_tag ("tr");
+
+ writer.start_tag ("td");
+ write_docbook_link (taglet.error_domain);
+ writer.end_tag ("td");
+
+ writer.start_tag ("td");
+ taglet.accept_children (this);
+ writer.end_tag ("td");
+
+ writer.end_tag ("tr");
+
+ first = false;
+ }
+
+ if (first == false) {
+ writer.end_tag ("table");
+ }
+ }
+}
+
diff --git a/libvaladoc/highlighter/codescanner.vala b/libvaladoc/highlighter/codescanner.vala
new file mode 100644
index 000000000..8b15ee755
--- /dev/null
+++ b/libvaladoc/highlighter/codescanner.vala
@@ -0,0 +1,572 @@
+/* codescanner.vala
+ *
+ * Copyright (C) 2015 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 GLib;
+
+
+/**
+ * A cheap scanner used to highlight C and Vala source code.
+ */
+public class Valadoc.Highlighter.CodeScanner : Object, Scanner {
+ private Gee.HashMap<string, CodeTokenType?> keywords;
+ private bool enable_string_templates;
+ private bool enabel_verbatim_string;
+ private bool enable_preprocessor_define;
+ private bool enable_preprocessor_include;
+ private bool enable_keyword_escape;
+
+
+ private Queue<CodeToken> token_queue = new Queue<CodeToken> ();
+ private unowned string content;
+ private unowned string pos;
+
+
+ public CodeScanner (string content, bool enable_string_templates, bool enabel_verbatim_string,
+ bool enable_preprocessor_define, bool enable_preprocessor_include, bool enable_keyword_escape,
+ Gee.HashMap<string, CodeTokenType?> keywords)
+ {
+ this.content = content;
+ this.pos = content;
+
+ this.enable_string_templates = enable_string_templates;
+ this.enabel_verbatim_string = enabel_verbatim_string;
+ this.enable_preprocessor_define = enable_preprocessor_define;
+ this.enable_preprocessor_include = enable_preprocessor_include;
+ this.enable_keyword_escape = enable_keyword_escape;
+
+ this.keywords = keywords;
+ }
+
+ public CodeToken next () {
+ if (!token_queue.is_empty ()) {
+ return token_queue.pop_head ();
+ }
+
+
+ unowned string start;
+
+ for (start = pos; pos[0] != '\0'; pos = pos.next_char ()) {
+ if (((char*) pos) == ((char*) content) || pos[0] == '\n') {
+ unowned string line_start = pos;
+
+ while (pos[0] == ' ' || pos[0] == '\t' || pos[0] == '\n') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == '\0') {
+ break;
+ } else if (enable_preprocessor_include && pos.has_prefix ("#include")) {
+ unowned string end = pos;
+ if (queue_c_include ()) {
+ return dispatch (start, end);
+ } else {
+ pos = line_start;
+ continue;
+ }
+ } else if (pos.has_prefix ("#if") || pos.has_prefix ("#else") || pos.has_prefix ("#elif") || pos.has_prefix ("#endif")
+ || (enable_preprocessor_define && (pos.has_prefix ("#defined") || pos.has_prefix ("#ifdef")))) {
+
+ unowned string end = pos;
+ queue_until ('\n', CodeTokenType.PREPROCESSOR);
+ return dispatch (start, end);
+ }
+ }
+
+ if (pos[0] == '\'') {
+ unowned string end = pos;
+ queue_string_literal ("\'");
+ return dispatch (start, end);
+ }
+
+ if (pos[0] == '"' || (enable_string_templates && pos[0] == '@' && pos[1] == '"')) {
+ unowned string end = pos;
+ if (enabel_verbatim_string && (pos.has_prefix ("\"\"\"") || (enable_string_templates && pos.has_prefix ("@\"\"\"")))) {
+ queue_string_literal ("\"\"\"");
+ } else {
+ queue_string_literal ("\"");
+ }
+ return dispatch (start, end);
+ }
+
+ if (pos[0] >= '0' && pos[0] <= '9') {
+ unowned string end = pos;
+ queue_numeric_literal ();
+ return dispatch (start, end);
+ }
+
+ if (pos.has_prefix ("/*")) {
+ unowned string end = pos;
+ queue_multiline_comment ();
+ return dispatch (start, end);
+ }
+
+ if (pos.has_prefix ("//")) {
+ unowned string end = pos;
+ queue_until ('\n', CodeTokenType.COMMENT);
+ return dispatch (start, end);
+ }
+
+ if ((((char*) pos) == ((char*) content) || !isidstartchar (pos[-1])) && isidstartchar (pos[0])) {
+ unowned string end = pos;
+ if (queue_keyword ()) {
+ return dispatch (start, end);
+ } else {
+ continue;
+ }
+ }
+ }
+
+ token_queue.push_tail (new CodeToken (CodeTokenType.EOF, ""));
+ return dispatch (start, pos);
+ }
+
+ private bool queue_c_include () {
+ unowned string include_start = pos;
+ unowned string start = pos;
+ pos = pos.offset (8);
+
+ while (pos[0] == ' ' || pos[0] == '\t') {
+ pos = pos.offset (1);
+ }
+
+ char? end_char = null;
+ if (pos[0] == '"') {
+ end_char = '"';
+ } else if (pos[0] == '<') {
+ end_char = '>';
+ }
+
+ if (end_char != null) {
+ queue_token (start, pos, CodeTokenType.PREPROCESSOR);
+
+ unowned string literal_start = pos;
+ pos = pos.offset (1);
+
+ while (pos[0] != end_char && pos[0] != '\n' && pos[0] != '\0') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == end_char) {
+ pos = pos.offset (1);
+
+ queue_token (literal_start, pos, CodeTokenType.LITERAL);
+ start = pos;
+ } else {
+ pos = include_start;
+ token_queue.clear ();
+ return false;
+ }
+ }
+
+ while (pos[0] == ' ' || pos[0] == '\t') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == '\n' || pos[0] == '\0') {
+ queue_token (start, pos, CodeTokenType.PREPROCESSOR);
+ return true;
+ } else {
+ pos = include_start;
+ token_queue.clear ();
+ return false;
+ }
+ }
+
+ private bool queue_keyword () {
+ unowned string start = pos;
+ if (pos[0] == '@') {
+ pos = pos.offset (1);
+ }
+ while (isidchar (pos[0])) {
+ pos = pos.offset (1);
+ }
+
+ long length = start.pointer_to_offset (pos);
+ string word = start.substring (0, length);
+ CodeTokenType? token_type = keywords.get (word);
+ if (token_type == null) {
+ pos = start;
+ return false;
+ }
+
+ token_queue.push_tail (new CodeToken (token_type, word));
+ return true;
+ }
+
+ private void queue_multiline_comment () {
+ unowned string start = pos;
+ pos = pos.offset (2);
+
+ while (!(pos[0] == '*' && pos[1] == '/') && pos[0] != '\0') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] != '\0') {
+ pos = pos.offset (2);
+ }
+
+ queue_token (start, pos, CodeTokenType.COMMENT);
+ }
+
+ private void queue_until (char end_char, CodeTokenType token_type) {
+ unowned string start = pos;
+ pos = pos.offset (1);
+
+ while (pos[0] != end_char && pos[0] != '\0') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] != '\0' && pos[0] != '\n') {
+ pos = pos.offset (1);
+ }
+
+ queue_token (start, pos, token_type);
+ }
+
+ private void queue_string_literal (string end_chars) {
+ unowned string start = pos;
+ bool is_template = false;
+
+ if (pos[0] == '@') {
+ pos = pos.offset (end_chars.length + 1);
+ is_template = true;
+ } else {
+ pos = pos.offset (end_chars.length);
+ }
+
+ while (!pos.has_prefix (end_chars) && pos[0] != '\0') {
+ long skip = 0;
+
+ if ((pos[0] == '%' && has_printf_format_prefix (out skip))
+ || (pos[0] == '\\' && has_escape_prefix (out skip))
+ || (is_template && pos[0] == '$' && has_template_literal_prefix (out skip)))
+ {
+ queue_token (start, pos, CodeTokenType.LITERAL);
+
+ unowned string sub_start = pos;
+ pos = pos.offset (skip);
+ queue_token (sub_start, pos, CodeTokenType.ESCAPE);
+ start = pos;
+ } else {
+ pos = pos.offset (1);
+ }
+ }
+
+ if (pos[0] != '\0') {
+ pos = pos.offset (end_chars.length);
+ }
+
+ queue_token (start, pos, CodeTokenType.LITERAL);
+ }
+
+ private bool has_template_literal_prefix (out long skip) {
+ if (isidchar (pos[1])) {
+ skip = 1;
+ while (isidchar (pos[skip])) {
+ skip++;
+ }
+ return true;
+ }
+
+ if (pos[1] == '(') {
+ int level = 1;
+ skip = 2;
+
+ while (level > 0) {
+ switch (pos[skip]) {
+ case '(':
+ level++;
+ break;
+ case ')':
+ level--;
+ break;
+ case '\0':
+ skip = 0;
+ return false;
+ }
+ skip++;
+ }
+ return true;
+ }
+
+ skip = 0;
+ return false;
+ }
+
+ private bool has_escape_prefix (out long skip) {
+ switch (pos[1]) {
+ case 'a':
+ case 'b':
+ case 'f':
+ case 'n':
+ case 'r':
+ case 't':
+ case 'v':
+ case '\\':
+ case '\'':
+ case '\"':
+ case '?':
+ skip = 2;
+ return true;
+
+ case 'x':
+ if (pos[2].isxdigit ()) {
+ for (skip = 2; pos[skip].isxdigit (); skip++) {
+ skip++;
+ }
+
+ skip++;
+ return true;
+ }
+
+ skip = 0;
+ return false;
+
+ default:
+ if (pos[1].isdigit ()) {
+ skip = 2;
+
+ if (pos[2].isdigit ()) {
+ skip++;
+
+ if (pos[3].isdigit ()) {
+ skip++;
+ }
+ }
+
+ return true;
+ }
+
+ skip = 0;
+ return false;
+ }
+ }
+
+ private bool has_printf_format_prefix (out long skip) {
+ // %[flag][min width][precision][length modifier][conversion specifier]
+ unowned string pos = this.pos;
+ unowned string start = pos;
+
+ // '%'
+ pos = pos.offset (1);
+
+ if (pos[0] == '%') {
+ pos = pos.offset (1);
+ skip = 2;
+ return true;
+ }
+
+
+ // flags:
+ while ("#0+- ".index_of_char (pos[0]) > 0) {
+ pos = pos.offset (1);
+ }
+
+ // min width:
+ while (pos[0].isdigit ()) {
+ pos = pos.offset (1);
+ }
+
+ // precision
+ if (pos[0] == '.' && pos[1].isdigit ()) {
+ pos = pos.offset (2);
+ while (pos[0].isdigit ()) {
+ pos = pos.offset (1);
+ }
+ }
+
+ // length:
+ switch (pos[0]) {
+ case 'h':
+ pos = pos.offset (1);
+ if (pos[0] == 'h') {
+ pos = pos.offset (1);
+ }
+ break;
+
+ case 'l':
+ pos = pos.offset (1);
+ if (pos[0] == 'l') {
+ pos = pos.offset (1);
+ }
+ break;
+
+ case 'j':
+ case 'z':
+ case 't':
+ case 'L':
+ pos = pos.offset (1);
+ break;
+ }
+
+ // conversion specifier:
+ switch (pos[0]) {
+ case 'd':
+ case 'i':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G':
+ case 'a':
+ case 'A':
+ case 'c':
+ case 's':
+ case 'p':
+ case 'n':
+ pos = pos.offset (1);
+ break;
+
+ default:
+ skip = 0;
+ return false;
+ }
+
+ skip = start.pointer_to_offset (pos);
+ return true;
+ }
+
+ private enum NumericType {
+ INTEGER,
+ REAL,
+ NONE
+ }
+
+ // based on libvala
+ private void queue_numeric_literal () {
+ NumericType numeric_type = NumericType.INTEGER;
+ unowned string start = pos;
+
+
+ // integer part
+ if (pos[0] == '0' && pos[1] == 'x' && pos[2].isxdigit ()) {
+ // hexadecimal integer literal
+ pos = pos.offset (2);
+ while (pos[0].isxdigit ()) {
+ pos = pos.offset (1);
+ }
+ } else {
+ // decimal number
+ while (pos[0].isdigit ()) {
+ pos = pos.offset (1);
+ }
+ }
+
+
+ // fractional part
+ if (pos[0] == '.' && pos[1].isdigit ()) {
+ numeric_type = NumericType.REAL;
+ pos = pos.offset (1);
+ while (pos[0].isdigit ()) {
+ pos = pos.offset (1);
+ }
+ }
+
+
+ // exponent part
+ if (pos[0] == 'e' || pos[0] == 'E') {
+ numeric_type = NumericType.REAL;
+ pos = pos.offset (1);
+ if (pos[0] == '+' || pos[0] == '-') {
+ pos = pos.offset (1);
+ }
+ while (pos[0].isdigit ()) {
+ pos = pos.offset (1);
+ }
+ }
+
+
+ // type suffix
+ switch (pos[0]) {
+ case 'l':
+ case 'L':
+ if (numeric_type == NumericType.INTEGER) {
+ pos = pos.offset (1);
+ if (pos[0] == 'l' || pos[0] == 'L') {
+ pos = pos.offset (1);
+ }
+ }
+ break;
+
+ case 'u':
+ case 'U':
+ if (numeric_type == NumericType.INTEGER) {
+ pos = pos.offset (1);
+ if (pos[0] == 'l' || pos[0] == 'L') {
+ pos = pos.offset (1);
+ if (pos[0] == 'l' || pos[0] == 'L') {
+ pos = pos.offset (1);
+ }
+ }
+ }
+ break;
+
+ case 'f':
+ case 'F':
+ case 'd':
+ case 'D':
+ numeric_type = NumericType.REAL;
+ pos = pos.offset (1);
+ break;
+ }
+
+ if (pos[0].isalnum ()) {
+ numeric_type = NumericType.NONE;
+ }
+
+ queue_token (start, pos, (numeric_type != NumericType.NONE)
+ ? CodeTokenType.LITERAL
+ : CodeTokenType.PLAIN);
+ }
+
+ private CodeToken dispatch (string start, string end) {
+ assert (token_queue.is_empty () == false);
+
+ if (((char*) start) == ((char*) end)) {
+ return token_queue.pop_head ();
+ }
+
+ long length = start.pointer_to_offset (end);
+ string content = start.substring (0, length);
+ return new CodeToken (CodeTokenType.PLAIN, content);
+ }
+
+ private void queue_token (string start, string end, CodeTokenType token_type) {
+ long length = start.pointer_to_offset (end);
+ string content = start.substring (0, length);
+ token_queue.push_tail (new CodeToken (token_type, content));
+ }
+
+ private inline bool isidchar (char c) {
+ return c.isalnum () || c == '_';
+ }
+
+ private inline bool isidstartchar (char c) {
+ return c.isalnum () || c == '_' || (c == '@' && enable_keyword_escape);
+ }
+}
+
diff --git a/libvaladoc/highlighter/codetoken.vala b/libvaladoc/highlighter/codetoken.vala
new file mode 100644
index 000000000..1a02195ea
--- /dev/null
+++ b/libvaladoc/highlighter/codetoken.vala
@@ -0,0 +1,58 @@
+/* codetoken.vala
+ *
+ * Copyright (C) 2015 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>
+ */
+
+
+public class Valadoc.Highlighter.CodeToken {
+ public CodeTokenType token_type { get; private set; }
+ public string content { get; private set;}
+
+ public CodeToken (CodeTokenType type, string content) {
+ this.token_type = type;
+ this.content = content;
+ }
+}
+
+
+public enum Valadoc.Highlighter.CodeTokenType {
+ XML_ESCAPE,
+ XML_ELEMENT,
+ XML_ATTRIBUTE,
+ XML_ATTRIBUTE_VALUE,
+ XML_COMMENT,
+ XML_CDATA,
+
+ PREPROCESSOR,
+ COMMENT,
+ KEYWORD,
+ LITERAL,
+ ESCAPE,
+ PLAIN,
+ TYPE,
+ EOF;
+
+ public unowned string to_string () {
+ EnumClass enumc = (EnumClass) typeof (CodeTokenType).class_ref ();
+ unowned EnumValue? eval = enumc.get_value (this);
+ return_val_if_fail (eval != null, null);
+ return eval.value_nick;
+ }
+}
diff --git a/libvaladoc/highlighter/highlighter.vala b/libvaladoc/highlighter/highlighter.vala
new file mode 100644
index 000000000..3c2578033
--- /dev/null
+++ b/libvaladoc/highlighter/highlighter.vala
@@ -0,0 +1,366 @@
+/* codehighlighter.vala
+ *
+ * Copyright (C) 2015 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 GLib;
+using Valadoc.Content;
+
+
+public class Valadoc.Highlighter.Highlighter : Object {
+ private Gee.HashMap<string, CodeTokenType?> vala_keywords;
+ private Gee.HashMap<string, CodeTokenType?> c_keywords;
+
+
+ /**
+ * Used to highlight vala source code.
+ */
+ public Run highlight_vala (string source_code) {
+ if (vala_keywords == null) {
+ vala_keywords = new Gee.HashMap<string, CodeTokenType?> ();
+
+ // ** Types: **
+ vala_keywords.set ("string", CodeTokenType.TYPE);
+ vala_keywords.set ("bool", CodeTokenType.TYPE);
+ vala_keywords.set ("void", CodeTokenType.TYPE);
+
+ vala_keywords.set ("double", CodeTokenType.TYPE);
+ vala_keywords.set ("float", CodeTokenType.TYPE);
+
+ vala_keywords.set ("char", CodeTokenType.TYPE);
+ vala_keywords.set ("uchar", CodeTokenType.TYPE);
+ vala_keywords.set ("unichar", CodeTokenType.TYPE);
+
+ vala_keywords.set ("short", CodeTokenType.TYPE);
+ vala_keywords.set ("ushort", CodeTokenType.TYPE);
+
+ vala_keywords.set ("long", CodeTokenType.TYPE);
+ vala_keywords.set ("ulong", CodeTokenType.TYPE);
+
+ vala_keywords.set ("size_t", CodeTokenType.TYPE);
+ vala_keywords.set ("ssize_t", CodeTokenType.TYPE);
+
+ vala_keywords.set ("int", CodeTokenType.TYPE);
+ vala_keywords.set ("int8", CodeTokenType.TYPE);
+ vala_keywords.set ("int16", CodeTokenType.TYPE);
+ vala_keywords.set ("int32", CodeTokenType.TYPE);
+ vala_keywords.set ("int64", CodeTokenType.TYPE);
+
+ vala_keywords.set ("uint", CodeTokenType.TYPE);
+ vala_keywords.set ("uint8", CodeTokenType.TYPE);
+ vala_keywords.set ("uint16", CodeTokenType.TYPE);
+ vala_keywords.set ("uint32", CodeTokenType.TYPE);
+ vala_keywords.set ("uint64", CodeTokenType.TYPE);
+
+
+ // ** Literals: **
+ vala_keywords.set ("null", CodeTokenType.LITERAL);
+ vala_keywords.set ("true", CodeTokenType.LITERAL);
+ vala_keywords.set ("false", CodeTokenType.LITERAL);
+
+
+ // ** Keywords: **
+ vala_keywords.set ("return", CodeTokenType.KEYWORD);
+ vala_keywords.set ("lock", CodeTokenType.KEYWORD);
+ vala_keywords.set ("var", CodeTokenType.KEYWORD);
+ vala_keywords.set ("yield", CodeTokenType.KEYWORD);
+ vala_keywords.set ("global", CodeTokenType.KEYWORD);
+ vala_keywords.set ("construct", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("value", CodeTokenType.KEYWORD);
+ vala_keywords.set ("get", CodeTokenType.KEYWORD);
+ vala_keywords.set ("set", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("owned", CodeTokenType.KEYWORD);
+ vala_keywords.set ("unowned", CodeTokenType.KEYWORD);
+ vala_keywords.set ("const", CodeTokenType.KEYWORD);
+ vala_keywords.set ("weak", CodeTokenType.KEYWORD);
+ vala_keywords.set ("dynamic", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("out", CodeTokenType.KEYWORD);
+ vala_keywords.set ("ref", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("break", CodeTokenType.KEYWORD);
+ vala_keywords.set ("continue", CodeTokenType.KEYWORD);
+ vala_keywords.set ("return", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("if", CodeTokenType.KEYWORD);
+ vala_keywords.set ("else", CodeTokenType.KEYWORD);
+ vala_keywords.set ("switch", CodeTokenType.KEYWORD);
+ vala_keywords.set ("case", CodeTokenType.KEYWORD);
+ vala_keywords.set ("default", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("do", CodeTokenType.KEYWORD);
+ vala_keywords.set ("while", CodeTokenType.KEYWORD);
+ vala_keywords.set ("for", CodeTokenType.KEYWORD);
+ vala_keywords.set ("foreach", CodeTokenType.KEYWORD);
+ vala_keywords.set ("in", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("try", CodeTokenType.KEYWORD);
+ vala_keywords.set ("catch", CodeTokenType.KEYWORD);
+ vala_keywords.set ("finally", CodeTokenType.KEYWORD);
+ vala_keywords.set ("throw", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("class", CodeTokenType.KEYWORD);
+ vala_keywords.set ("interface", CodeTokenType.KEYWORD);
+ vala_keywords.set ("struct", CodeTokenType.KEYWORD);
+ vala_keywords.set ("enum", CodeTokenType.KEYWORD);
+ vala_keywords.set ("delegate", CodeTokenType.KEYWORD);
+ vala_keywords.set ("errordomain", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("abstract", CodeTokenType.KEYWORD);
+ vala_keywords.set ("virtual", CodeTokenType.KEYWORD);
+ vala_keywords.set ("override", CodeTokenType.KEYWORD);
+ vala_keywords.set ("signal", CodeTokenType.KEYWORD);
+ vala_keywords.set ("extern", CodeTokenType.KEYWORD);
+ vala_keywords.set ("static", CodeTokenType.KEYWORD);
+ vala_keywords.set ("async", CodeTokenType.KEYWORD);
+ vala_keywords.set ("inline", CodeTokenType.KEYWORD);
+ vala_keywords.set ("new", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("public", CodeTokenType.KEYWORD);
+ vala_keywords.set ("private", CodeTokenType.KEYWORD);
+ vala_keywords.set ("protected", CodeTokenType.KEYWORD);
+ vala_keywords.set ("internal", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("throws", CodeTokenType.KEYWORD);
+ vala_keywords.set ("requires", CodeTokenType.KEYWORD);
+ vala_keywords.set ("ensures", CodeTokenType.KEYWORD);
+ vala_keywords.set ("assert", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("namespace", CodeTokenType.KEYWORD);
+ vala_keywords.set ("using", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("as", CodeTokenType.KEYWORD);
+ vala_keywords.set ("is", CodeTokenType.KEYWORD);
+ vala_keywords.set ("in", CodeTokenType.KEYWORD);
+ vala_keywords.set ("new", CodeTokenType.KEYWORD);
+ vala_keywords.set ("delete", CodeTokenType.KEYWORD);
+ vala_keywords.set ("sizeof", CodeTokenType.KEYWORD);
+ vala_keywords.set ("typeof", CodeTokenType.KEYWORD);
+
+ vala_keywords.set ("this", CodeTokenType.KEYWORD);
+ vala_keywords.set ("base", CodeTokenType.KEYWORD);
+ }
+
+ bool enable_string_templates = true;
+ bool enable_preprocessor_define = false;
+ bool enable_preprocessor_include = false;
+ bool enable_keyword_escape = true;
+ bool enabel_verbatim_string = true;
+
+ CodeScanner scanner = new CodeScanner (source_code, enable_string_templates, enabel_verbatim_string,
+ enable_preprocessor_define, enable_preprocessor_include, enable_keyword_escape,
+ vala_keywords);
+
+ return highlight_code (scanner);
+ }
+
+ /**
+ * Used to highlight C source code.
+ */
+ public Run highlight_c (string source_code) {
+ if (c_keywords == null) {
+ c_keywords = new Gee.HashMap<string, CodeTokenType?> ();
+
+ // ** Types: **
+ c_keywords.set ("auto", CodeTokenType.TYPE);
+ c_keywords.set ("char", CodeTokenType.TYPE);
+ c_keywords.set ("const", CodeTokenType.TYPE);
+ c_keywords.set ("double", CodeTokenType.TYPE);
+ c_keywords.set ("extern", CodeTokenType.TYPE);
+ c_keywords.set ("int", CodeTokenType.TYPE);
+ c_keywords.set ("float", CodeTokenType.TYPE);
+ c_keywords.set ("long", CodeTokenType.TYPE);
+ c_keywords.set ("register", CodeTokenType.TYPE);
+ c_keywords.set ("short", CodeTokenType.TYPE);
+ c_keywords.set ("signed", CodeTokenType.TYPE);
+ c_keywords.set ("static", CodeTokenType.TYPE);
+ c_keywords.set ("unsigned", CodeTokenType.TYPE);
+ c_keywords.set ("void", CodeTokenType.TYPE);
+ c_keywords.set ("volatile", CodeTokenType.TYPE);
+
+ c_keywords.set ("gboolean", CodeTokenType.TYPE);
+ c_keywords.set ("gpointer", CodeTokenType.TYPE);
+ c_keywords.set ("gconstpointer", CodeTokenType.TYPE);
+ c_keywords.set ("gchar", CodeTokenType.TYPE);
+ c_keywords.set ("guchar", CodeTokenType.TYPE);
+ c_keywords.set ("gint", CodeTokenType.TYPE);
+ c_keywords.set ("guint", CodeTokenType.TYPE);
+ c_keywords.set ("gshort", CodeTokenType.TYPE);
+ c_keywords.set ("gushort", CodeTokenType.TYPE);
+ c_keywords.set ("glong", CodeTokenType.TYPE);
+ c_keywords.set ("gulong", CodeTokenType.TYPE);
+ c_keywords.set ("gint8", CodeTokenType.TYPE);
+ c_keywords.set ("guint8", CodeTokenType.TYPE);
+ c_keywords.set ("gint16", CodeTokenType.TYPE);
+ c_keywords.set ("guint16", CodeTokenType.TYPE);
+ c_keywords.set ("gint32", CodeTokenType.TYPE);
+ c_keywords.set ("guint32", CodeTokenType.TYPE);
+ c_keywords.set ("gint64", CodeTokenType.TYPE);
+ c_keywords.set ("guint64", CodeTokenType.TYPE);
+ c_keywords.set ("gfloat", CodeTokenType.TYPE);
+ c_keywords.set ("gdouble", CodeTokenType.TYPE);
+ c_keywords.set ("gsize", CodeTokenType.TYPE);
+ c_keywords.set ("gssize", CodeTokenType.TYPE);
+ c_keywords.set ("goffset", CodeTokenType.TYPE);
+ c_keywords.set ("gintptr", CodeTokenType.TYPE);
+ c_keywords.set ("guintptr", CodeTokenType.TYPE);
+
+
+ // ** Literals: **
+ c_keywords.set ("NULL", CodeTokenType.LITERAL);
+ c_keywords.set ("TRUE", CodeTokenType.LITERAL);
+ c_keywords.set ("FALSE", CodeTokenType.LITERAL);
+
+
+ // ** Keywords: **
+ c_keywords.set ("break", CodeTokenType.KEYWORD);
+ c_keywords.set ("case", CodeTokenType.KEYWORD);
+ c_keywords.set ("continue", CodeTokenType.KEYWORD);
+ c_keywords.set ("default", CodeTokenType.KEYWORD);
+ c_keywords.set ("do", CodeTokenType.KEYWORD);
+ c_keywords.set ("else", CodeTokenType.KEYWORD);
+ c_keywords.set ("enum", CodeTokenType.KEYWORD);
+ c_keywords.set ("for", CodeTokenType.KEYWORD);
+ c_keywords.set ("goto", CodeTokenType.KEYWORD);
+ c_keywords.set ("if", CodeTokenType.KEYWORD);
+ c_keywords.set ("return", CodeTokenType.KEYWORD);
+ c_keywords.set ("sizeof", CodeTokenType.KEYWORD);
+ c_keywords.set ("struct", CodeTokenType.KEYWORD);
+ c_keywords.set ("switch", CodeTokenType.KEYWORD);
+ c_keywords.set ("typedef", CodeTokenType.KEYWORD);
+ c_keywords.set ("union", CodeTokenType.KEYWORD);
+ c_keywords.set ("while", CodeTokenType.KEYWORD);
+ c_keywords.set ("assert", CodeTokenType.KEYWORD);
+ }
+
+ bool enable_string_templates = false;
+ bool enable_preprocessor_define = true;
+ bool enable_preprocessor_include = true;
+ bool enable_keyword_escape = false;
+ bool enabel_verbatim_string = false;
+
+ CodeScanner scanner = new CodeScanner (source_code, enable_string_templates, enabel_verbatim_string,
+ enable_preprocessor_define, enable_preprocessor_include, enable_keyword_escape,
+ c_keywords);
+
+ return highlight_code (scanner);
+ }
+
+ /**
+ * Used to highlight C source code.
+ */
+ public Run highlight_xml (string source_code) {
+ XmlScanner scanner = new XmlScanner (source_code);
+ return highlight_code (scanner);
+ }
+
+ /**
+ * Used to highlight source code.
+ */
+ private Run highlight_code (Scanner scanner) {
+ Run code = new Run (Run.Style.MONOSPACED);
+
+ for (CodeToken token = scanner.next (); token.token_type != CodeTokenType.EOF; token = scanner.next ()) {
+ switch (token.token_type) {
+ case CodeTokenType.PREPROCESSOR:
+ Run run = new Run (Run.Style.LANG_PREPROCESSOR);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.COMMENT:
+ Run run = new Run (Run.Style.LANG_COMMENT);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.KEYWORD:
+ Run run = new Run (Run.Style.LANG_KEYWORD);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.LITERAL:
+ Run run = new Run (Run.Style.LANG_LITERAL);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.TYPE:
+ Run run = new Run (Run.Style.LANG_BASIC_TYPE);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.ESCAPE:
+ Run run = new Run (Run.Style.LANG_ESCAPE);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_ESCAPE:
+ Run run = new Run (Run.Style.XML_ESCAPE);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_ELEMENT:
+ Run run = new Run (Run.Style.XML_ELEMENT);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_ATTRIBUTE:
+ Run run = new Run (Run.Style.XML_ATTRIBUTE);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_ATTRIBUTE_VALUE:
+ Run run = new Run (Run.Style.XML_ATTRIBUTE_VALUE);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_COMMENT:
+ Run run = new Run (Run.Style.XML_COMMENT);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ case CodeTokenType.XML_CDATA:
+ Run run = new Run (Run.Style.XML_CDATA);
+ run.content.add (new Text (token.content));
+ code.content.add (run);
+ break;
+
+ default:
+ code.content.add (new Text (token.content));
+ break;
+ }
+ }
+
+ return code;
+ }
+}
+
+
diff --git a/libvaladoc/highlighter/scanner.vala b/libvaladoc/highlighter/scanner.vala
new file mode 100644
index 000000000..20eedcfb2
--- /dev/null
+++ b/libvaladoc/highlighter/scanner.vala
@@ -0,0 +1,32 @@
+/* scanner.vala
+ *
+ * Copyright (C) 2015 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 GLib;
+
+
+/**
+ * Scanner interface used to highlight source code.
+ */
+public interface Valadoc.Highlighter.Scanner : Object {
+
+ public abstract CodeToken next ();
+}
diff --git a/libvaladoc/highlighter/xmlscanner.vala b/libvaladoc/highlighter/xmlscanner.vala
new file mode 100644
index 000000000..38b87c5ee
--- /dev/null
+++ b/libvaladoc/highlighter/xmlscanner.vala
@@ -0,0 +1,374 @@
+/* xmlscanner.vala
+ *
+ * Copyright (C) 2015 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 GLib;
+
+
+/**
+ * A cheap scanner used to highlight XML.
+ */
+public class Valadoc.Highlighter.XmlScanner : Object, Scanner {
+ private Queue<CodeToken> token_queue = new Queue<CodeToken> ();
+ private unowned string content;
+ private unowned string pos;
+
+
+ public XmlScanner (string content) {
+ this.content = content;
+ this.pos = content;
+ }
+
+ public CodeToken next () {
+ if (!token_queue.is_empty ()) {
+ return token_queue.pop_head ();
+ }
+
+ unowned string start;
+
+ for (start = pos; pos[0] != '\0'; pos = pos.next_char ()) {
+ if (pos[0] == '&') {
+ unowned string begin = pos;
+ if (queue_escape ()) {
+ return dispatch (start, begin);
+ }
+ } else if (pos[0] == '<') {
+ if (pos[1] == '/') {
+ unowned string end = pos;
+ if (queue_end_element ()) {
+ return dispatch (start, end);
+ }
+ } else if (pos[1] == '!' && pos[2] == '-' && pos[3] == '-') {
+ unowned string end = pos;
+ if (queue_comment ()) {
+ return dispatch (start, end);
+ }
+ } else if (pos[1] == '!' && pos[2] == '[' && pos[3] == 'C' && pos[4] == 'D' && pos[5] == 'A' && pos[6] == 'T' && pos[7] == 'A' && pos[8] == '[') {
+ unowned string end = pos;
+ pos = pos.offset (9);
+ token_queue.push_tail (new CodeToken (CodeTokenType.XML_CDATA, "<![CDATA["));
+ return dispatch (start, end);
+ } else {
+ unowned string end = pos;
+ if (queue_start_element (start, pos[1] == '?')) {
+ return dispatch (start, end);
+ } else {
+ continue;
+ }
+ }
+ } else if (pos[0] == ']' && pos[1] == ']' && pos[2] == '>') {
+ unowned string end = pos;
+ pos = pos.offset (3);
+ token_queue.push_tail (new CodeToken (CodeTokenType.XML_CDATA, "]]>"));
+ return dispatch (start, end);
+ }
+ }
+
+ token_queue.push_tail (new CodeToken (CodeTokenType.EOF, ""));
+ return dispatch (start, pos);
+ }
+
+ private bool queue_start_element (string dispatch_start, bool xml_decl) {
+ assert (token_queue.is_empty ());
+
+ unowned string element_start = pos;
+ if (xml_decl) {
+ pos = pos.offset (2);
+ } else {
+ pos = pos.offset (1);
+ }
+
+ skip_optional_spaces (ref pos);
+
+ if (skip_id (ref pos) == false) {
+ token_queue.clear ();
+ pos = element_start;
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ queue_token (element_start, pos, CodeTokenType.XML_ELEMENT);
+
+ if (queue_attributes () == false) {
+ token_queue.clear ();
+ pos = element_start;
+ return false;
+ }
+
+ unowned string element_end_start = pos;
+
+ if (!xml_decl && pos[0] == '>') {
+ pos = pos.offset (1);
+ } else if (!xml_decl && pos[0] == '/' && pos[1] == '>') {
+ pos = pos.offset (2);
+ } else if (xml_decl && pos[0] == '?' && pos[1] == '>') {
+ pos = pos.offset (2);
+ } else {
+ token_queue.clear ();
+ pos = element_start;
+ return false;
+ }
+
+ queue_token (element_end_start, pos, CodeTokenType.XML_ELEMENT);
+ return true;
+ }
+
+ private bool queue_attributes () {
+ while (is_id_char (pos[0])) {
+ unowned string begin = pos;
+
+ if (skip_id (ref pos) == false) {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ if (pos[0] == '=') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ queue_token (begin, pos, CodeTokenType.XML_ATTRIBUTE);
+ begin = pos;
+
+ if (pos[0] == '"') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ while (pos[0] != '"' && pos[0] != '\0') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == '"') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ queue_token (begin, pos, CodeTokenType.XML_ATTRIBUTE_VALUE);
+ }
+
+ return true;
+ }
+
+ private bool queue_end_element () {
+ unowned string start = pos;
+ pos = pos.offset (2);
+
+ skip_optional_spaces (ref pos);
+
+ if (skip_id (ref pos) == false) {
+ pos = start;
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ if (pos[0] == '>') {
+ pos = pos.offset (1);
+ } else {
+ pos = start;
+ return false;
+ }
+
+ queue_token (start, pos, CodeTokenType.XML_ELEMENT);
+ return true;
+ }
+
+ private bool queue_escape () {
+ unowned string start = pos;
+ pos = pos.offset (1);
+
+ if (skip_id (ref pos) == false) {
+ pos = start;
+ return false;
+ }
+
+ if (pos[0] == ';') {
+ pos = pos.offset (1);
+ } else {
+ pos = start;
+ return false;
+ }
+
+ queue_token (start, pos, CodeTokenType.XML_ESCAPE);
+ return true;
+ }
+
+ private bool queue_comment () {
+ unowned string start = pos;
+ pos = pos.offset (4);
+
+ while (pos[0] != '>' && pos[0] != '\0') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == '>') {
+ pos = pos.offset (1);
+ } else {
+ pos = start;
+ return false;
+ }
+
+ queue_token (start, pos, CodeTokenType.XML_COMMENT);
+ return true;
+ }
+
+ private static bool skip_id (ref unowned string pos) {
+ bool has_next_segment = true;
+ bool has_id = false;
+
+ while (has_next_segment) {
+ has_id = false;
+
+ while (is_id_char (pos[0])) {
+ pos = pos.offset (1);
+ has_id = true;
+ }
+
+ if (pos[0] == ':' && has_id) {
+ has_next_segment = true;
+ pos = pos.offset (1);
+ } else {
+ has_next_segment = false;
+ }
+ }
+
+ return has_id;
+ }
+
+ private static bool skip_optional_spaces (ref unowned string pos) {
+ bool skipped = false;
+
+ while (pos[0].isspace ()) {
+ pos = pos.offset (1);
+ skipped = true;
+ }
+
+ return skipped;
+ }
+
+ private CodeToken dispatch (string start, string end) {
+ assert (token_queue.is_empty () == false);
+
+ if (((char*) start) == ((char*) end)) {
+ return token_queue.pop_head ();
+ }
+
+ long length = start.pointer_to_offset (end);
+ string content = start.substring (0, length);
+ return new CodeToken (CodeTokenType.PLAIN, content);
+ }
+
+ private void queue_token (string start, string end, CodeTokenType token_type) {
+ long length = start.pointer_to_offset (end);
+ string content = start.substring (0, length);
+ token_queue.push_tail (new CodeToken (token_type, content));
+ }
+
+ private static inline bool is_id_char (char c) {
+ return c.isalnum () || c == '_' || c == '-';
+ }
+
+ internal static bool is_xml (string source) {
+ unowned string pos = source;
+
+ skip_optional_spaces (ref pos);
+
+ if (pos[0] == '<') {
+ // Comment:
+ if (pos.has_prefix ("<!--")) {
+ return true;
+ }
+
+ // CDATA:
+ if (pos.has_prefix ("<![CDATA[")) {
+ return true;
+ }
+
+
+ // Start Tag:
+ bool proc_instr = false;
+ pos = pos.offset (1);
+
+ if (pos[0] == '?') {
+ pos = pos.offset (1);
+ proc_instr = true;
+ }
+
+ // ID:
+ if (skip_id (ref pos) == false) {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ while (skip_id (ref pos)) {
+ if (pos[0] == '=') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+
+ if (pos[0] == '"') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ while (pos[0] != '\0' && pos[0] != '\n' && pos[0] != '"') {
+ pos = pos.offset (1);
+ }
+
+ if (pos[0] == '"') {
+ pos = pos.offset (1);
+ } else {
+ return false;
+ }
+
+ skip_optional_spaces (ref pos);
+ }
+
+ if (proc_instr && pos[0] == '?' && pos[1] == '>') {
+ return true;
+ }
+
+ if (!proc_instr && (pos[0] == '>' || (pos[0] == '/' && pos[1] == '>'))) {
+ return true;
+ }
+
+ return false;
+ } else {
+ return false;
+ }
+ }
+}
+
diff --git a/libvaladoc/html/basicdoclet.vala b/libvaladoc/html/basicdoclet.vala
new file mode 100644
index 000000000..8e51234a2
--- /dev/null
+++ b/libvaladoc/html/basicdoclet.vala
@@ -0,0 +1,1159 @@
+/* basicdoclet.vala
+ *
+ * Copyright (C) 2008-2012 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.Content;
+using Valadoc.Api;
+
+
+
+public abstract class Valadoc.Html.BasicDoclet : Api.Visitor, Doclet {
+ public Html.LinkHelper linker {
+ protected set;
+ get;
+ }
+
+ public Settings settings {
+ protected set;
+ get;
+ }
+
+ public string wiki_index_name {
+ default = "index.valadoc";
+ protected set;
+ get;
+ }
+
+ protected Api.Tree tree;
+ protected HtmlRenderer _renderer;
+ protected Html.MarkupWriter writer;
+ protected Html.CssClassResolver cssresolver;
+ protected Charts.Factory image_factory;
+ protected ErrorReporter reporter;
+ protected string package_list_link = "../index.html";
+
+ // CSS:
+ private const string css_inline_navigation = "navi_inline";
+ private const string css_package_index = "package_index";
+ private const string css_brief_description = "brief_description";
+ private const string css_description = "description";
+ private const string css_known_list = "known_nodes";
+ private const string css_leaf_brief_description = "leaf_brief_description";
+ private const string css_leaf_code_definition = "leaf_code_definition";
+
+ private const string css_box_headline_text = "text";
+ private const string css_box_headline_toggle = "toggle";
+ private const string css_box_headline = "headline";
+ private const string css_box_content = "content";
+ private const string css_box_column = "column";
+ private const string css_box = "box";
+
+ private const string css_namespace_note = "namespace_note";
+ private const string css_package_note = "package_note";
+
+ private const string css_site_header = "site_header";
+ private const string css_navi = "navi_main";
+ private const string css_navi_hr = "navi_hr";
+ private const string css_errordomain_table_name = "main_errordomain_table_name";
+ private const string css_errordomain_table_text = "main_errordomain_table_text";
+ private const string css_errordomain_table = "main_errordomain_table";
+ private const string css_enum_table_name = "main_enum_table_name";
+ private const string css_enum_table_text = "main_enum_table_text";
+ private const string css_enum_table = "main_enum_table";
+ private const string css_diagram = "main_diagram";
+ private const string css_see_list = "main_see_list";
+ private const string css_wiki_table = "main_table";
+ private const string css_notification_area = "main_notification";
+ private const string css_source_sample = "main_sourcesample";
+ private const string css_exception_table = "main_parameter_table";
+ private const string css_parameter_table_text = "main_parameter_table_text";
+ private const string css_parameter_table_name = "main_parameter_table_name";
+ private const string css_parameter_table = "main_parameter_table";
+ private const string css_title = "main_title";
+ private const string css_other_type = "main_other_type";
+ private const string css_basic_type = "main_basic_type";
+ private const string css_keyword = "main_keyword";
+ private const string css_optional_parameter = "main_optional_parameter";
+ private const string css_code_definition = "main_code_definition";
+ private const string css_headline_hr = "main_hr";
+ private const string css_hr = "main_hr";
+ private const string css_list_errdom = "main_list_errdom";
+ private const string css_list_en = "main_list_en";
+ private const string css_list_ns = "main_list_ns";
+ private const string css_list_cl = "main_list_cl";
+ private const string css_list_iface = "main_list_iface";
+ private const string css_list_stru = "main_list_stru";
+ private const string css_list_field = "main_list_field";
+ private const string css_list_prop = "main_list_prop";
+ private const string css_list_del = "main_list_del";
+ private const string css_list_sig = "main_list_sig";
+ private const string css_list_m = "main_list_m";
+ private const string css_style_navigation = "site_navigation";
+ private const string css_style_content = "site_content";
+ private const string css_style_body = "site_body";
+ private const string css_deprecated = "deprecated";
+
+ public virtual void process (Settings settings, Api.Tree tree, ErrorReporter reporter) {
+ this.reporter = reporter;
+ this.settings = settings;
+ this.tree = tree;
+
+ this.cssresolver = new CssClassResolver ();
+ this.linker = new LinkHelper ();
+
+ _renderer = new HtmlRenderer (settings, this.linker, this.cssresolver);
+ this.image_factory = new SimpleChartFactory (settings, linker);
+ }
+
+
+ // paths:
+ protected string? get_link (Api.Node to, Api.Node from) {
+ return linker.get_relative_link (from, to, settings);
+ }
+
+ protected virtual string get_img_path_html (Api.Node element, string type) {
+ return Path.build_filename ("img", element.get_full_name () + "." + type);
+ }
+
+ protected virtual string get_img_path (Api.Node element, string type) {
+ return Path.build_filename (settings.path, element.package.name, "img",
+ element.get_full_name () + "." + type);
+ }
+
+ protected virtual string get_icon_directory () {
+ return "..";
+ }
+
+
+ private TypeSymbol? unpack_type_reference (TypeReference? type_reference) {
+ Api.Item pos = type_reference;
+
+ while (pos != null) {
+ if (pos is TypeReference) {
+ pos = ((TypeReference) pos).data_type;
+ } else if (pos is Api.Array) {
+ pos = ((Api.Array) pos).data_type;
+ } else if (pos is Pointer) {
+ pos = ((Pointer) pos).data_type;
+ } else {
+ assert (pos is TypeSymbol);
+ return (TypeSymbol) pos;
+ }
+ }
+
+ return null;
+ }
+
+
+ protected void write_navi_entry_html_template (string style, string content, bool is_deprecated) {
+ writer.start_tag ("li", {"class", style});
+
+ if (is_deprecated) {
+ writer.start_tag ("span", {"class", css_deprecated});
+ writer.text (content);
+ writer.end_tag ("span");
+ } else {
+ writer.text (content);
+ }
+
+ writer.end_tag ("li");
+ }
+
+ protected void write_navi_entry_html_template_with_link (string style, string link,
+ string content, bool is_deprecated)
+ {
+ writer.start_tag ("li", {"class", style});
+
+ if (is_deprecated) {
+ writer.start_tag ("span", {"class", css_deprecated});
+ writer.link (link, content);
+ writer.end_tag ("span");
+ } else {
+ writer.link (link, content);
+ }
+
+ writer.end_tag ("li");
+ }
+
+ protected void write_navi_entry (Api.Node element, Api.Node? pos, string style,
+ bool link, bool full_name = false)
+ {
+ string name;
+
+ if (full_name == true && element is Namespace) {
+ string tmp = element.get_full_name();
+ name = (tmp == null)? "Global Namespace" : tmp;
+ } else {
+ string tmp = element.name;
+ name = (tmp == null)? "Global Namespace" : tmp;
+ }
+
+ bool is_deprecated = element is Symbol && ((Symbol) element).is_deprecated;
+
+ if (link == true) {
+ this.write_navi_entry_html_template_with_link (style,
+ this.get_link (element, pos),
+ name,
+ is_deprecated);
+ } else {
+ this.write_navi_entry_html_template (style, name, is_deprecated);
+ }
+ }
+
+ protected void write_wiki_pages (Api.Tree tree, string css_path_wiki, string js_path_wiki,
+ string contentp)
+ {
+ if (tree.wikitree == null) {
+ return ;
+ }
+
+ if (tree.wikitree == null) {
+ return ;
+ }
+
+ Gee.Collection<WikiPage> pages = tree.wikitree.get_pages();
+ if (pages.size == 0) {
+ return ;
+ }
+
+ DirUtils.create (contentp, 0777);
+
+ DirUtils.create (Path.build_filename (contentp, "img"), 0777);
+
+ foreach (WikiPage page in pages) {
+ if (page.name != wiki_index_name) {
+ write_wiki_page (page, contentp, css_path_wiki, js_path_wiki, this.settings.pkg_name);
+ }
+ }
+ }
+
+ protected virtual void write_wiki_page (WikiPage page, string contentp, string css_path,
+ string js_path, string pkg_name)
+ {
+ GLib.FileStream file = GLib.FileStream.open (
+ Path.build_filename (contentp, page.name.substring (0, page.name.length-7).replace ("/", ".")+"htm"),
+ "w");
+
+ writer = new MarkupWriter (file);
+ _renderer.set_writer (writer);
+ this.write_file_header (css_path, js_path, pkg_name);
+ _renderer.set_container (page);
+ _renderer.render (page.documentation);
+ this.write_file_footer ();
+ }
+
+ protected void write_navi_top_entry (Api.Node element, Api.Node? parent) {
+ string style = cssresolver.resolve (element);
+
+ writer.start_tag ("ul", {"class", css_navi});
+
+ if (element == parent || parent == null) {
+ this.write_navi_entry (element, parent, style, false);
+ } else {
+ this.write_navi_entry (element, parent, style, true);
+ }
+
+ writer.end_tag ("ul");
+ writer.simple_tag ("hr", {"class", css_navi_hr});
+ }
+
+ protected void write_top_element_template (string link) {
+ writer.start_tag ("ul", {"class", css_navi});
+ writer.start_tag ("li", {"class", css_package_index});
+ writer.link (link, "Packages");
+ writer.end_tag ("li");
+ writer.end_tag ("ul");
+ writer.simple_tag ("hr", {"class", css_navi_hr});
+ }
+
+ protected void write_top_elements (Api.Node element, Api.Node? parent) {
+ Gee.ArrayList<Api.Node> lst = new Gee.ArrayList<Api.Node> ();
+ Api.Node pos = element;
+
+ this.write_top_element_template (package_list_link);
+
+ while (pos != null) {
+ lst.add (pos);
+ pos = (Api.Node)pos.parent;
+ }
+
+ for (int i = lst.size-1; i >= 0 ; i--) {
+ Api.Node el = lst.get (i);
+
+ if (el.name != null) {
+ this.write_navi_top_entry (el, parent);
+ }
+ }
+ }
+
+ protected void fetch_subnamespace_names (Api.Node node, Gee.ArrayList<Namespace> namespaces) {
+ Gee.ArrayList<Api.Node> sorted_list = new Gee.ArrayList<Api.Node> ();
+ sorted_list.add_all (node.get_children_by_type (Api.NodeType.NAMESPACE));
+ sorted_list.sort ();
+
+ foreach (Api.Node child in sorted_list) {
+ namespaces.add ((Namespace) child);
+ this.fetch_subnamespace_names (child, namespaces);
+ }
+ }
+
+ protected void write_navi_package (Package package) {
+ Gee.ArrayList<Namespace> ns_list = new Gee.ArrayList<Namespace> ();
+ this.fetch_subnamespace_names (package, ns_list);
+
+ writer.start_tag ("div", {"class", css_style_navigation});
+ write_top_elements (package, package);
+ writer.start_tag ("ul", {"class", css_navi});
+
+ Namespace globals = null;
+
+ foreach (Namespace ns in ns_list) {
+ if (ns.name == null) {
+ globals = ns;
+ } else {
+ this.write_navi_entry (ns, package, cssresolver.resolve (ns), true, true);
+ }
+ }
+
+ if (globals != null) {
+ write_navi_children (globals, Api.NodeType.ERROR_CODE, package);
+ write_navi_children (globals, Api.NodeType.ENUM_VALUE, package);
+ write_navi_children (globals, Api.NodeType.ENUM, package);
+ write_navi_children (globals, Api.NodeType.INTERFACE, package);
+ write_navi_children (globals, Api.NodeType.CLASS, package);
+ write_navi_children (globals, Api.NodeType.STRUCT, package);
+ write_navi_children (globals, Api.NodeType.CONSTANT, package);
+ write_navi_children (globals, Api.NodeType.PROPERTY, package);
+ write_navi_children (globals, Api.NodeType.DELEGATE, package);
+ write_navi_children (globals, Api.NodeType.STATIC_METHOD, package);
+ write_navi_children (globals, Api.NodeType.CREATION_METHOD, package);
+ write_navi_children (globals, Api.NodeType.METHOD, package);
+ write_navi_children (globals, Api.NodeType.SIGNAL, package);
+ write_navi_children (globals, Api.NodeType.FIELD, package);
+ }
+
+ writer.end_tag ("ul");
+ writer.end_tag ("div");
+ }
+
+ protected void write_navi_symbol (Api.Node node) {
+ writer.start_tag ("div", {"class", css_style_navigation});
+ write_top_elements (node, node);
+ write_navi_symbol_inline (node, node);
+ writer.end_tag ("div");
+ }
+
+ protected void write_navi_leaf_symbol (Api.Node node) {
+ writer.start_tag ("div", {"class", css_style_navigation});
+ write_top_elements ((Api.Node) node.parent, node);
+ write_navi_symbol_inline ((Api.Node) node.parent, node);
+ writer.end_tag ("div");
+ }
+
+ protected void write_navi_symbol_inline (Api.Node node, Api.Node? parent) {
+ writer.start_tag ("ul", {"class", css_navi});
+ write_navi_children (node, Api.NodeType.NAMESPACE, parent);
+ write_navi_children (node, Api.NodeType.ERROR_CODE, parent);
+ write_navi_children (node, Api.NodeType.ENUM_VALUE, parent);
+ write_navi_children (node, Api.NodeType.ENUM, parent);
+ write_navi_children (node, Api.NodeType.INTERFACE, parent);
+ write_navi_children (node, Api.NodeType.CLASS, parent);
+ write_navi_children (node, Api.NodeType.STRUCT, parent);
+ write_navi_children (node, Api.NodeType.CONSTANT, parent);
+ write_navi_children (node, Api.NodeType.PROPERTY, parent);
+ write_navi_children (node, Api.NodeType.DELEGATE, parent);
+ write_navi_children (node, Api.NodeType.STATIC_METHOD, parent);
+ write_navi_children (node, Api.NodeType.CREATION_METHOD, parent);
+ write_navi_children (node, Api.NodeType.METHOD, parent);
+ write_navi_children (node, Api.NodeType.SIGNAL, parent);
+ write_navi_children (node, Api.NodeType.FIELD, parent);
+ writer.end_tag ("ul");
+ }
+
+ protected void write_navi_children (Api.Node node, Api.NodeType type, Api.Node? parent) {
+ var children = node.get_children_by_type (type);
+ children.sort ();
+ foreach (Api.Node child in children) {
+ write_navi_entry (child, parent, cssresolver.resolve (child), child != parent);
+ }
+ }
+
+ protected void write_package_note (Api.Node element) {
+ string package = element.package.name;
+ if (package == null) {
+ return;
+ }
+
+ writer.start_tag ("div", {"class", css_package_note});
+ writer.start_tag ("b")
+ .text ("Package:")
+ .end_tag ("b");
+ writer.text (" ")
+ .start_tag ("a", {"href", get_link (element.package, element)})
+ .text (package)
+ .end_tag ("a");
+ writer.end_tag ("div");
+ }
+
+ protected void write_namespace_note (Api.Node element) {
+ Namespace? ns = element.nspace;
+ if (ns == null) {
+ return;
+ }
+
+ if (ns.name == null) {
+ return;
+ }
+
+ writer.start_tag ("div", {"class", css_namespace_note});
+ writer.start_tag ("b")
+ .text ("Namespace:")
+ .end_tag ("b");
+ writer.text (" ")
+ .start_tag ("a", {"href", get_link (ns, element)})
+ .text (ns.get_full_name())
+ .end_tag ("a");
+ writer.end_tag ("div");
+ }
+
+ private bool has_brief_description (Api.Node element) {
+ return element.documentation != null;
+ }
+
+ private void write_brief_description (Api.Node element , Api.Node? pos) {
+ Content.Comment? doctree = element.documentation;
+ if (doctree == null) {
+ return;
+ }
+
+ Gee.List<Block> description = doctree.content;
+ if (description.size > 0) {
+ writer.start_tag ("span", {"class", css_brief_description});
+
+ _renderer.set_container (pos);
+ _renderer.set_owner (element);
+ _renderer.render_children (description.get (0));
+ _renderer.set_owner (null);
+
+ writer.end_tag ("span");
+ }
+ }
+
+ private void write_documentation (Api.Node element , Api.Node? pos) {
+ Content.Comment? doctree = element.documentation;
+ bool is_deprecated = (element is Symbol && ((Symbol) element).is_deprecated);
+
+ // avoid empty divs
+ if (doctree == null && !is_deprecated) {
+ return;
+ }
+
+
+ writer.start_tag ("div", {"class", css_description});
+ _renderer.set_owner (element);
+
+ // deprecation warning:
+ if (is_deprecated) {
+ Symbol symbol = (Symbol) element;
+ Attribute? version;
+ Attribute? deprecated;
+ AttributeArgument? replacement;
+ AttributeArgument? since;
+ if ((version = symbol.get_attribute ("Version")) != null) {
+ replacement = version.get_argument ("replacement");
+ since = version.get_argument ("deprecated_since");
+ } else if ((deprecated = symbol.get_attribute ("Deprecated")) != null) {
+ replacement = deprecated.get_argument ("replacement");
+ since = deprecated.get_argument ("version");
+ } else {
+ assert_not_reached ();
+ }
+
+ writer.start_tag ("p");
+ writer.start_tag ("b");
+ writer.text ("Warning:");
+ writer.end_tag ("b");
+ writer.text (" %s is deprecated".printf (element.name));
+
+ if (since != null) {
+ writer.text (" since %s".printf (since.get_value_as_string ()));
+ }
+
+ writer.text (".");
+
+ if (replacement != null) {
+ string replacement_name = replacement.get_value_as_string ();
+ Api.Node? replacement_node = tree.search_symbol_str (pos,
+ replacement_name.substring (1, replacement_name.length - 2));
+
+ writer.text (" Use ");
+ if (replacement_node == null) {
+ writer.text (replacement_name);
+ } else {
+ string? link = get_link (replacement_node, pos);
+ if (link != null) {
+ string css = cssresolver.resolve (replacement_node);
+ writer.link (link, replacement_node.get_full_name (), css);
+ } else {
+ writer.start_tag ("code")
+ .text (replacement_node.get_full_name ())
+ .end_tag ("code");
+ }
+ }
+ writer.text (".");
+ }
+
+ writer.end_tag ("p");
+ }
+
+ if (doctree != null) {
+ _renderer.set_container (pos);
+ _renderer.render (doctree);
+ }
+
+
+ _renderer.set_owner (null);
+ writer.end_tag ("div");
+ }
+
+ private void write_attributes (Api.Symbol element, Api.Node? pos) {
+ writer.set_wrap (false);
+ _renderer.set_container (pos);
+ foreach (Attribute att in element.get_attributes ()) {
+ _renderer.render (att.signature);
+ writer.simple_tag ("br");
+ }
+ writer.set_wrap (true);
+ }
+
+ private void write_signature (Api.Node element , Api.Node? pos) {
+ writer.set_wrap (false);
+ _renderer.set_container (pos);
+ _renderer.render (element.signature);
+ writer.set_wrap (true);
+ }
+
+ protected bool is_internal_node (Api.Node node) {
+ return node is Package
+ || node is Api.Namespace
+ || node is Api.Interface
+ || node is Api.Class
+ || node is Api.Struct
+ || node is Api.Enum
+ || node is Api.EnumValue
+ || node is Api.ErrorDomain
+ || node is Api.ErrorCode;
+ }
+
+ public void write_navi_packages_inline (Api.Tree tree) {
+ writer.start_tag ("ul", {"class", css_navi});
+ foreach (Package pkg in tree.get_package_list()) {
+ if (pkg.is_browsable (settings)) {
+ writer.start_tag ("li", {"class", cssresolver.resolve (pkg)});
+ writer.link (linker.get_package_link (pkg, settings), pkg.name);
+ // brief description
+ writer.end_tag ("li");
+ } else {
+ writer.start_tag ("li", {"class", cssresolver.resolve (pkg)});
+ writer.text (pkg.name);
+ writer.end_tag ("li");
+ }
+ }
+ writer.end_tag ("ul");
+ }
+
+ public void write_navi_packages (Api.Tree tree) {
+ writer.start_tag ("div", {"class", css_style_navigation});
+ this.write_navi_packages_inline (tree);
+ writer.end_tag ("div");
+ }
+
+ public void write_package_index_content (Api.Tree tree) {
+ writer.start_tag ("div", {"class", css_style_content});
+ writer.start_tag ("h1", {"class", css_title})
+ .text ("Packages:")
+ .end_tag ("h1");
+ writer.simple_tag ("hr", {"class", css_headline_hr});
+
+ WikiPage? wikiindex = (tree.wikitree == null)
+ ? null
+ : tree.wikitree.search (wiki_index_name);
+ if (wikiindex != null) {
+ _renderer.set_container (wikiindex);
+ _renderer.render (wikiindex.documentation);
+ }
+
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Content:")
+ .end_tag ("h2");
+ writer.start_tag ("h3", {"class", css_title})
+ .text ("Packages:")
+ .end_tag ("h3");
+ this.write_navi_packages_inline (tree);
+ writer.end_tag ("div");
+ }
+
+ private uint html_id_counter = 0;
+
+ private inline Gee.Collection<Api.Node> get_accessible_nodes_from_list (Gee.Collection<Api.Node> nodes) {
+ var list = new Gee.ArrayList<Api.Node> ();
+
+ foreach (var node in nodes) {
+ if (node.is_browsable(_settings)) {
+ list.add (node);
+ }
+ }
+
+ return list;
+ }
+
+ private void write_known_symbols_note (Gee.Collection<Api.Node> nodes2, Api.Node container, string headline) {
+ var nodes = get_accessible_nodes_from_list (nodes2);
+ if (nodes.size == 0) {
+ return ;
+ }
+
+ // Box:
+ var html_id = "box-content-" + html_id_counter.to_string ();
+ html_id_counter++;
+
+
+ writer.start_tag ("div", {"class", css_box});
+
+ // headline:
+ writer.start_tag ("div", {"class", css_box_headline, "onclick", "toggle_box (this, '%s')".printf (html_id)})
+ .text (headline)
+ .end_tag ("div");
+ //writer.start_tag ("div", {"class", css_box_headline_text, "onclick", "toggle_box (this, '%s')".printf (html_id)})
+ // .text (headline)
+ // .end_tag ("div");
+ //writer.start_tag ("div", {"class", css_box_headline_toggle});
+ //writer.start_tag ("img", {"onclick",
+ // "toggle_box (this, '" + html_id + "')",
+ // "src",
+ // Path.build_filename (get_icon_directory (),
+ // "coll_open.png")});
+ //writer.raw_text ("&nbsp;");
+ //writer.end_tag ("div");
+ //writer.end_tag ("div");
+
+
+ // content:
+ int[] list_sizes = {0, 0, 0};
+ list_sizes[0] = nodes.size;
+ list_sizes[2] = list_sizes[0]/3;
+ list_sizes[0] -= list_sizes[2];
+ list_sizes[1] = list_sizes[0]/2;
+ list_sizes[0] -= list_sizes[1];
+
+ writer.start_tag ("div", {"class", css_box_content, "id", html_id});
+
+ var iter = nodes.iterator ();
+
+ for (int i = 0; i < list_sizes.length; i++) {
+ writer.start_tag ("div", {"class", css_box_column});
+ writer.start_tag ("ul", {"class", css_inline_navigation});
+
+ for (int p = 0; p < list_sizes[i] && iter.next (); p++) {
+ var node = iter.get ();
+ writer.start_tag ("li", {"class", cssresolver.resolve (node)});
+ string link = get_link (node, container);
+ if (link == null) {
+ writer.text (node.name);
+ } else {
+ writer.link (link, node.name);
+ }
+ writer.end_tag ("li");
+ }
+
+ writer.end_tag ("ul");
+ writer.end_tag ("div");
+ }
+
+ writer.end_tag ("div"); // end content
+
+ writer.end_tag ("div"); // end box
+ }
+
+ public void write_symbol_content (Api.Node node) {
+ writer.start_tag ("div", {"class", css_style_content});
+ writer.start_tag ("h1", {"class", css_title})
+ .text (node.name)
+ .end_tag ("h1");
+ writer.simple_tag ("hr", {"class", css_headline_hr});
+ this.write_image_block (node);
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Description:")
+ .end_tag ("h2");
+ writer.start_tag ("div", {"class", css_code_definition});
+ if (node is Symbol) {
+ this.write_attributes ((Symbol) node, node);
+ }
+ this.write_signature (node, node);
+ writer.end_tag ("div");
+ this.write_documentation (node, node);
+
+ if (node is Class) {
+ var cl = node as Class;
+ write_known_symbols_note (cl.get_known_child_classes (),
+ cl,
+ "All known sub-classes:");
+ write_known_symbols_note (cl.get_known_derived_interfaces (),
+ cl,
+ "Required by:");
+ } else if (node is Interface) {
+ var iface = node as Interface;
+ write_known_symbols_note (iface.get_known_implementations (),
+ iface,
+ "All known implementing classes:");
+ write_known_symbols_note (iface.get_known_related_interfaces (),
+ iface,
+ "All known sub-interfaces:");
+ } else if (node is Struct) {
+ var stru = node as Struct;
+ write_known_symbols_note (stru.get_known_child_structs (),
+ stru,
+ "All known sub-structs:");
+ }
+
+ if (node.parent is Namespace) {
+ writer.simple_tag ("br");
+ write_namespace_note (node);
+ write_package_note (node);
+ }
+
+ if (!(node is Method || node is Delegate || node is Api.Signal)) {
+ // avoids exception listings & implementations
+
+ if (node.has_children ({
+ Api.NodeType.ERROR_CODE,
+ Api.NodeType.ENUM_VALUE,
+ Api.NodeType.CREATION_METHOD,
+ Api.NodeType.STATIC_METHOD,
+ Api.NodeType.CLASS,
+ Api.NodeType.STRUCT,
+ Api.NodeType.ENUM,
+ Api.NodeType.DELEGATE,
+ Api.NodeType.METHOD,
+ Api.NodeType.SIGNAL,
+ Api.NodeType.PROPERTY,
+ Api.NodeType.FIELD,
+ Api.NodeType.CONSTANT
+ }))
+ {
+ writer.start_tag ("h2", {"class", css_title}).text ("Content:").end_tag ("h2");
+ write_children (node, Api.NodeType.ERROR_CODE, "Error codes", node);
+ write_children (node, Api.NodeType.ENUM_VALUE, "Enum values", node);
+ write_children (node, Api.NodeType.CLASS, "Classes", node);
+ write_children (node, Api.NodeType.STRUCT, "Structs", node);
+ write_children (node, Api.NodeType.ENUM, "Enums", node);
+ write_children (node, Api.NodeType.CONSTANT, "Constants", node);
+ write_children (node, Api.NodeType.PROPERTY, "Properties", node);
+ write_children (node, Api.NodeType.DELEGATE, "Delegates", node);
+ write_children (node, Api.NodeType.STATIC_METHOD, "Static methods", node);
+ write_children (node, Api.NodeType.CREATION_METHOD, "Creation methods", node);
+ write_children (node, Api.NodeType.METHOD, "Methods", node);
+ write_children (node, Api.NodeType.SIGNAL, "Signals", node);
+ write_children (node, Api.NodeType.FIELD, "Fields", node);
+ }
+ }
+
+ if (node is Class) {
+ write_inherited_symbols_note_for_class ((Class) node, node);
+ } else if (node is Interface) {
+ write_inherited_symbols_note_for_interface ((Interface) node, node);
+ } else if (node is Struct) {
+ write_inherited_symbols_note_for_struct ((Struct) node, node);
+ }
+
+ writer.end_tag ("div");
+ }
+
+ private static NodeType[] inheritable_members = {
+ NodeType.CONSTANT,
+ NodeType.PROPERTY,
+ NodeType.DELEGATE,
+ NodeType.STATIC_METHOD,
+ NodeType.METHOD,
+ NodeType.SIGNAL,
+ NodeType.FIELD
+ };
+
+ private inline bool has_visible_inheritable_children (TypeSymbol symbol) {
+ return symbol.has_visible_children_by_types (inheritable_members, _settings);
+ }
+
+ private void write_inherited_members_headline () {
+ writer.start_tag ("h3", {"class", css_title})
+ .text ("Inherited Members:")
+ .end_tag ("h3");
+ }
+
+ private void write_inherited_symbols_note_for_class (Class cl, Api.Node container) {
+ bool headline_printed = false;
+
+ // class hierarchy:
+ Class base_class = unpack_type_reference (cl.base_type) as Class;
+ while (base_class != null) {
+ if (!headline_printed && has_visible_inheritable_children (base_class)) {
+ write_inherited_members_headline ();
+ headline_printed = true;
+ }
+
+ write_inherited_symbols_note (base_class, "class", container);
+ base_class = unpack_type_reference (base_class.base_type) as Class;
+ }
+
+
+ // implemented interfaces
+ Gee.LinkedList<Interface> printed_interfaces = new Gee.LinkedList<Interface> ();
+ foreach (TypeReference iface_ref in cl.get_full_implemented_interface_list ()) {
+ Interface iface = (Interface) unpack_type_reference (iface_ref);
+
+ if (!headline_printed && has_visible_inheritable_children (iface)) {
+ write_inherited_members_headline ();
+ headline_printed = true;
+ } else if (printed_interfaces.contains (iface)) {
+ continue ;
+ }
+
+ write_inherited_symbols_note (iface, "interface", container);
+ printed_interfaces.add (iface);
+ }
+ }
+
+ private void write_inherited_symbols_note_for_interface (Interface iface, Api.Node container) {
+ bool headline_printed = false;
+
+ // class hierarchy:
+ Class base_class = unpack_type_reference (iface.base_type) as Class;
+ while (base_class != null) {
+ if (!headline_printed && has_visible_inheritable_children (base_class)) {
+ write_inherited_members_headline ();
+ headline_printed = true;
+ }
+
+ write_inherited_symbols_note (base_class, "class", container);
+ base_class = unpack_type_reference (base_class.base_type) as Class;
+ }
+
+
+ // interfaces:
+ Gee.LinkedList<Interface> printed_interfaces = new Gee.LinkedList<Interface> ();
+ foreach (TypeReference pre_ref in iface.get_full_implemented_interface_list ()) {
+ Interface pre = (Interface) unpack_type_reference (pre_ref);
+
+ if (!headline_printed && has_visible_inheritable_children (pre)) {
+ write_inherited_members_headline ();
+ headline_printed = true;
+ } else if (printed_interfaces.contains (pre)) {
+ continue ;
+ }
+
+ write_inherited_symbols_note (pre, "interface", container);
+ printed_interfaces.add (pre);
+ }
+ }
+
+ private void write_inherited_symbols_note_for_struct (Struct str, Api.Node container) {
+ Struct base_struct = unpack_type_reference (str.base_type) as Struct;
+ if (base_struct != null && has_visible_inheritable_children (base_struct)) {
+ write_inherited_members_headline ();
+ write_inherited_symbols_note (base_struct, "struct", container);
+ }
+ }
+
+ private void write_inherited_symbols_note (TypeSymbol symbol, string type, Api.Node container) {
+ write_known_symbols_note (symbol.get_children_by_types (inheritable_members, false),
+ container,
+ "All known members inherited from %s %s".printf (type, symbol.get_full_name ()));
+
+ /*
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.CONSTANT, false),
+ container,
+ "All known constants inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.PROPERTY, false),
+ container,
+ "All known properties inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.DELEGATE, false),
+ container,
+ "All known delegates inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.STATIC_METHOD, false),
+ container,
+ "All known static methods inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.METHOD, false),
+ container,
+ "All known methods inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.SIGNAL, false),
+ container,
+ "All known signals inherited from %s %s".printf (type, symbol.get_full_name ()));
+ write_known_symbols_note (symbol.get_children_by_type (NodeType.FIELD, false),
+ container,
+ "All known fields inherited from %s %s".printf (type, symbol.get_full_name ()));
+ */
+ }
+
+ protected void write_child_namespaces (Api.Node node, Api.Node? parent) {
+ Gee.ArrayList<Namespace> namespaces = new Gee.ArrayList<Namespace> ();
+ this.fetch_subnamespace_names (node, namespaces);
+
+ if (namespaces.size == 0) {
+ return;
+ }
+
+ if (namespaces.size == 1) {
+ if (namespaces.get(0).name == null) {
+ return;
+ }
+ }
+
+ bool with_childs = parent != null && parent is Package;
+
+ writer.start_tag ("h3", {"class", css_title})
+ .text ("Namespaces:")
+ .end_tag ("h3");
+ writer.start_tag ("ul", {"class", css_inline_navigation});
+ foreach (Namespace child in namespaces) {
+ if (child.name != null) {
+ writer.start_tag ("li", {"class", cssresolver.resolve (child)});
+ writer.link (get_link (child, parent), child.name);
+ if (has_brief_description (child)) {
+ writer.text (" - ");
+ this.write_brief_description (child, parent);
+ }
+ writer.end_tag ("li");
+ if (with_childs == true) {
+ write_children (child, Api.NodeType.INTERFACE, "Interfaces", parent);
+ write_children (child, Api.NodeType.CLASS, "Classes", parent);
+ write_children (child, Api.NodeType.STRUCT, "Structs", parent);
+ write_children (child, Api.NodeType.ENUM, "Enums", parent);
+ write_children (child, Api.NodeType.ERROR_DOMAIN, "Error domains", parent);
+ write_children (child, Api.NodeType.CONSTANT, "Constants", parent);
+ write_children (child, Api.NodeType.DELEGATE, "Delegates", parent);
+ write_children (child, Api.NodeType.METHOD, "Methods", parent);
+ write_children (child, Api.NodeType.FIELD, "Fields", parent);
+ }
+ }
+ }
+ writer.end_tag ("ul");
+ }
+
+ protected void write_child_dependencies (Package package, Api.Node? parent) {
+ Gee.Collection<Package>? deps = package.get_full_dependency_list ();
+ if (deps.size == 0) {
+ return;
+ }
+
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Dependencies:")
+ .end_tag ("h2");
+ writer.start_tag ("ul", {"class", css_inline_navigation});
+ foreach (Package p in deps) {
+ string? link = this.get_link (p, parent);
+ if (link == null) {
+ writer.start_tag ("li", {"class", cssresolver.resolve (p), "id", p.name})
+ .text (p.name)
+ .end_tag ("li");
+ } else {
+ writer.start_tag ("li", {"class", cssresolver.resolve (p)});
+ writer.link (get_link (p, parent), p.name);
+ writer.end_tag ("li");
+ }
+ }
+ writer.end_tag ("ul");
+ }
+
+ protected void write_children (Api.Node node, Api.NodeType type, string type_string, Api.Node? container) {
+ var children = node.get_children_by_type (type);
+ if (children.size > 0) {
+ writer.start_tag ("h3", {"class", css_title})
+ .text (type_string)
+ .text (":")
+ .end_tag ("h3");
+ writer.start_tag ("ul", {"class", css_inline_navigation});
+ foreach (Api.Node child in children) {
+ writer.start_tag ("li", {"class", cssresolver.resolve (child)});
+ if (is_internal_node (child)) {
+ if (child is Symbol && ((Symbol) child).is_deprecated) {
+ writer.start_tag ("span", {"class", css_deprecated});
+ writer.link (get_link (child, container), child.name);
+ writer.end_tag ("span");
+ } else {
+ writer.link (get_link (child, container), child.name);
+ }
+ if (has_brief_description (child)) {
+ writer.text (" - ");
+ write_brief_description (child, container);
+ }
+ } else {
+ writer.start_tag ("span", {"class", css_leaf_code_definition});
+ if (child is Symbol && ((Symbol) child).is_deprecated) {
+ writer.start_tag ("span", {"class", css_deprecated});
+ write_signature (child, container);
+ writer.end_tag ("span");
+ } else {
+ write_signature (child, container);
+ }
+ writer.end_tag ("span");
+
+ writer.start_tag ("div", {"class", css_leaf_brief_description});
+ write_brief_description (child, container);
+ writer.end_tag ("div");
+ }
+ writer.end_tag ("li");
+ }
+ writer.end_tag ("ul");
+ }
+ }
+
+ protected void write_image_block (Api.Node element) {
+ if (element is Class || element is Interface || element is Struct) {
+ unowned string format = (settings.use_svg_images ? "svg" : "png");
+ var chart = new Charts.Hierarchy (image_factory, element);
+ chart.save (this.get_img_path (element, format), format);
+
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Object Hierarchy:")
+ .end_tag ("h2");
+
+ writer.simple_tag ("img", {"class",
+ css_diagram,
+ "usemap",
+ "#"+element.get_full_name (),
+ "alt",
+ "Object hierarchy for %s".printf (element.name),
+ "src",
+ this.get_img_path_html (element, format)});
+ writer.add_usemap (chart);
+ }
+ }
+
+ public void write_namespace_content (Namespace node, Api.Node? parent) {
+ writer.start_tag ("div", {"class", css_style_content});
+ writer.start_tag ("h1", {"class", css_title})
+ .text (node.name == null ? "Global Namespace" : node.get_full_name ())
+ .end_tag ("h1");
+ writer.simple_tag ("hr", {"class", css_hr});
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Description:")
+ .end_tag ("h2");
+
+ this.write_documentation (node, parent);
+
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Content:")
+ .end_tag ("h2");
+
+ if (node.name == null) {
+ this.write_child_namespaces ((Package) node.parent, parent);
+ } else {
+ this.write_child_namespaces (node, parent);
+ }
+
+ write_children (node, Api.NodeType.INTERFACE, "Interfaces", parent);
+ write_children (node, Api.NodeType.CLASS, "Classes", parent);
+ write_children (node, Api.NodeType.STRUCT, "Structs", parent);
+ write_children (node, Api.NodeType.ENUM, "Enums", parent);
+ write_children (node, Api.NodeType.ERROR_DOMAIN, "Error domains", parent);
+ write_children (node, Api.NodeType.CONSTANT, "Constants", parent);
+ write_children (node, Api.NodeType.DELEGATE, "Delegates", parent);
+ write_children (node, Api.NodeType.METHOD, "Functions", parent);
+ write_children (node, Api.NodeType.FIELD, "Fields", parent);
+ writer.end_tag ("div");
+ }
+
+ protected void write_package_content (Package node, Api.Node? parent) {
+ writer.start_tag ("div", {"class", css_style_content});
+ writer.start_tag ("h1", {"class", css_title, "id", node.name})
+ .text (node.name)
+ .end_tag ("h1");
+ writer.simple_tag ("hr", {"class", css_headline_hr});
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Description:")
+ .end_tag ("h2");
+
+
+ WikiPage? wikipage = (tree.wikitree == null)? null : tree.wikitree.search (wiki_index_name);
+ if (wikipage != null) {
+ _renderer.set_container (parent);
+ _renderer.render (wikipage.documentation);
+ }
+
+ writer.start_tag ("h2", {"class", css_title})
+ .text ("Content:")
+ .end_tag ("h2");
+
+ this.write_child_namespaces (node, parent);
+
+ foreach (Api.Node child in node.get_children_by_type (Api.NodeType.NAMESPACE)) {
+ if (child.name == null) {
+ write_children (child, Api.NodeType.INTERFACE, "Interfaces", parent);
+ write_children (child, Api.NodeType.CLASS, "Classes", parent);
+ write_children (child, Api.NodeType.STRUCT, "Structs", parent);
+ write_children (child, Api.NodeType.ENUM, "Enums", parent);
+ write_children (child, Api.NodeType.ERROR_DOMAIN, "Error domains", parent);
+ write_children (child, Api.NodeType.CONSTANT, "Constants", parent);
+ write_children (child, Api.NodeType.DELEGATE, "Delegates", parent);
+ write_children (child, Api.NodeType.METHOD, "Functions", parent);
+ write_children (child, Api.NodeType.FIELD, "Fields", parent);
+ }
+ }
+
+ this.write_child_dependencies (node, parent);
+ writer.end_tag ("div");
+ }
+
+ protected void write_file_header (string css, string js, string? title) {
+ writer.start_tag ("html");
+ writer.start_tag ("head");
+ writer.simple_tag ("meta", {"charset", "UTF-8"});
+ if (title == null) {
+ writer.start_tag ("title")
+ .text ("Vala Binding Reference")
+ .end_tag ("title");
+ } else {
+ writer.start_tag ("title")
+ .text (title)
+ .text (" &ndash; Vala Binding Reference")
+ .end_tag ("title");
+ }
+ writer.stylesheet_link (css);
+ writer.javascript_link (js);
+ writer.end_tag ("head");
+ writer.start_tag ("body");
+ writer.start_tag ("div", {"class", css_site_header});
+ writer.text ("%s Reference Manual".printf (title == null ? "" : title));
+ writer.end_tag ("div");
+ writer.start_tag ("div", {"class", css_style_body});
+ }
+
+ protected void write_file_footer () {
+ writer.end_tag ("div");
+ writer.simple_tag ("br");
+ writer.start_tag ("div", {"class", "site_footer"});
+ writer.text ("Generated by ");
+ writer.link ("http://www.valadoc.org/", "Valadoc");
+ writer.end_tag ("div");
+ writer.end_tag ("body");
+ writer.end_tag ("html");
+ }
+}
+
diff --git a/libvaladoc/html/cssclassresolver.vala b/libvaladoc/html/cssclassresolver.vala
new file mode 100644
index 000000000..e8961aeeb
--- /dev/null
+++ b/libvaladoc/html/cssclassresolver.vala
@@ -0,0 +1,117 @@
+/* globals.vala
+ *
+ * Copyright (C) 2008-2009 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.Api;
+
+
+namespace Valadoc.Html {
+ public class CssClassResolver : Api.Visitor {
+ private string? css_class = null;
+
+ public string resolve (Api.Node node) {
+ node.accept (this);
+ return (owned) css_class;
+ }
+
+ public override void visit_package (Api.Package item) {
+ css_class = "package";
+ }
+
+ public override void visit_namespace (Api.Namespace item) {
+ css_class = "namespace";
+ }
+
+ public override void visit_interface (Api.Interface item) {
+ css_class = "interface";
+ }
+
+ public override void visit_class (Api.Class item) {
+ if (item.is_abstract) {
+ css_class = "abstract_class";
+ } else {
+ css_class = "class";
+ }
+ }
+
+ public override void visit_struct (Api.Struct item) {
+ css_class = "struct";
+ }
+
+ public override void visit_property (Api.Property item) {
+ if (item.is_virtual || item.is_override) {
+ css_class = "virtual_property";
+ } else if (item.is_abstract) {
+ css_class = "abstract_property";
+ } else {
+ css_class = "property";
+ }
+ }
+
+ public override void visit_field (Api.Field item) {
+ css_class = "field";
+ }
+
+ public override void visit_constant (Api.Constant item) {
+ css_class = "constant";
+ }
+
+ public override void visit_delegate (Api.Delegate item) {
+ css_class = "delegate";
+ }
+
+ public override void visit_signal (Api.Signal item) {
+ css_class = "signal";
+ }
+
+ public override void visit_method (Api.Method item) {
+ if (item.is_static) {
+ css_class = "static_method";
+ } else if (item.is_abstract) {
+ css_class = "abstract_method";
+ } else if (item.is_virtual || item.is_override) {
+ css_class = "virtual_method";
+ } else if (item.is_constructor) {
+ css_class = "creation_method";
+ } else {
+ css_class = "method";
+ }
+ }
+
+ public override void visit_error_domain (Api.ErrorDomain item) {
+ css_class = "errordomain";
+ }
+
+ public override void visit_error_code (Api.ErrorCode item) {
+ css_class = "errorcode";
+ }
+
+ public override void visit_enum (Api.Enum item) {
+ css_class = "enum";
+ }
+
+ public override void visit_enum_value (Api.EnumValue item) {
+ css_class = "enumvalue";
+ }
+ }
+}
+
+
diff --git a/libvaladoc/html/htmlchartfactory.vala b/libvaladoc/html/htmlchartfactory.vala
new file mode 100644
index 000000000..1b63b4e13
--- /dev/null
+++ b/libvaladoc/html/htmlchartfactory.vala
@@ -0,0 +1,54 @@
+/* simplechartfactory.vala
+ *
+ * Copyright (C) 2008 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>
+ */
+
+
+
+public class Valadoc.Html.SimpleChartFactory : Charts.SimpleFactory {
+ private Settings _settings;
+ private Api.Node _container;
+ private LinkHelper _linker;
+
+ public SimpleChartFactory (Settings settings, LinkHelper linker) {
+ _settings = settings;
+ _linker = linker;
+ }
+
+ public override Gvc.Graph create_graph (Api.Node item) {
+ var graph = base.create_graph (item);
+ _container = item;
+ return graph;
+ }
+
+ protected override Gvc.Node configure_type (Gvc.Node node, Api.Node item) {
+ base.configure_type (node, item);
+
+ if (_container != null) {
+ var link = _linker.get_relative_link (_container, item, _settings);
+ if (link != null) {
+ node.safe_set ("URL", link, "");
+ }
+ }
+
+ return node;
+ }
+}
+
diff --git a/libvaladoc/html/htmlmarkupwriter.vala b/libvaladoc/html/htmlmarkupwriter.vala
new file mode 100644
index 000000000..15ed9efd1
--- /dev/null
+++ b/libvaladoc/html/htmlmarkupwriter.vala
@@ -0,0 +1,132 @@
+/* markupwriter.vala
+ *
+ * Copyright (C) 2008-2014 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+using Valadoc.Content;
+
+public class Valadoc.Html.MarkupWriter : Valadoc.MarkupWriter {
+
+ public MarkupWriter (FileStream stream, bool xml_declaration = true) {
+ // avoid broken implicit copy
+ unowned FileStream _stream = stream;
+
+ base ((str) => {
+ _stream.printf (str);
+ }, xml_declaration);
+ }
+
+ public MarkupWriter.builder (StringBuilder builder, bool xml_declaration = true) {
+ // avoid broken implicit copy
+ unowned StringBuilder _builder = builder;
+
+ base ((str) => {
+ _builder.append (str);
+ }, xml_declaration);
+ }
+
+ public MarkupWriter add_usemap (Charts.Chart chart) {
+ string? buf = (string?) chart.write_buffer ("cmapx");
+ if (buf != null) {
+ raw_text ("\n");
+ raw_text ((!) buf);
+ }
+
+ return this;
+ }
+
+ // edit
+ public MarkupWriter link (string url, string label, string? css_class = null) {
+ if (css_class == null) {
+ start_tag ("a", {"href", url});
+ } else {
+ start_tag ("a", {"href", url, "class", css_class});
+ }
+
+ text (label);
+ end_tag ("a");
+ return this;
+ }
+
+ public MarkupWriter image (string src, string? caption = null, string? css_class = null) {
+ if (css_class == null) {
+ simple_tag ("img", {"src", src, "alt", caption});
+ } else {
+ simple_tag ("img", {"src", src, "alt", caption, "class", css_class});
+ }
+ return this;
+ }
+
+ public MarkupWriter stylesheet_link (string url) {
+ simple_tag ("link", {"href", url, "rel", "stylesheet", "type", "text/css"});
+ return this;
+ }
+
+ public MarkupWriter javascript_link (string url) {
+ start_tag ("script", {"src", url, "type", "text/javascript"});
+ end_tag ("script");
+ return this;
+ }
+
+ protected override bool inline_element (string name) {
+ return name != "html"
+ && name != "head"
+ && name != "title"
+ && name != "meta"
+ && name != "link"
+ && name != "body"
+ && name != "div"
+ && name != "p"
+ && name != "table"
+ && name != "tr"
+ && name != "td"
+ && name != "ul"
+ && name != "ol"
+ && name != "li"
+ && name != "h1"
+ && name != "h2"
+ && name != "h3"
+ && name != "h4"
+ && name != "h5"
+ && name != "hr"
+ && name != "img";
+ }
+
+ protected override bool content_inline_element (string name) {
+ return name == "title"
+ || name == "meta"
+ || name == "p"
+ || name == "a"
+ || name == "h1"
+ || name == "h2"
+ || name == "h3"
+ || name == "h4"
+ || name == "h5"
+ || name == "li"
+ || name == "span"
+ || name == "code"
+ || name == "b"
+ || name == "i"
+ || name == "u"
+ || name == "stoke";
+ }
+}
+
diff --git a/libvaladoc/html/htmlrenderer.vala b/libvaladoc/html/htmlrenderer.vala
new file mode 100644
index 000000000..bdd78a09d
--- /dev/null
+++ b/libvaladoc/html/htmlrenderer.vala
@@ -0,0 +1,632 @@
+/* htmlrenderer.vala
+ *
+ * Copyright (C) 2008-20014 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using GLib;
+using Valadoc.Content;
+
+public class Valadoc.Html.HtmlRenderer : ContentRenderer {
+
+ protected Documentation? _container;
+ protected Documentation? _owner;
+ protected unowned MarkupWriter writer;
+ protected Html.CssClassResolver cssresolver;
+ protected LinkHelper linker;
+ protected Settings settings;
+
+ public HtmlRenderer (Settings settings, LinkHelper linker, CssClassResolver cssresolver) {
+ this.cssresolver = cssresolver;
+ this.settings = settings;
+ this.linker = linker;
+ }
+
+ public void set_container (Documentation? container) {
+ _container = container;
+ }
+
+ public void set_owner (Documentation? owner) {
+ _owner = owner;
+ }
+
+ public void set_writer (MarkupWriter writer) {
+ this.writer = writer;
+ }
+
+ public override void render (ContentElement element) {
+ element.accept (this);
+ }
+
+ public override void render_children (ContentElement element) {
+ element.accept_children (this);
+ }
+
+ private string get_url (Documentation symbol) {
+ return linker.get_relative_link (_container, symbol, settings);
+ }
+
+ private void write_unresolved_symbol_link (string given_symbol_name, InlineContent? label_owner = null) {
+ if (label_owner == null || label_owner.content.size == 0) {
+ writer.start_tag ("code");
+ writer.text (given_symbol_name);
+ writer.end_tag ("code");
+ } else {
+ writer.start_tag ("i");
+ label_owner.accept_children (this);
+ writer.end_tag ("i");
+ }
+ }
+
+ private void write_resolved_symbol_link (Api.Node symbol, string? given_symbol_name, InlineContent? label_owner = null) {
+ var symbol_name = (given_symbol_name == null || given_symbol_name == "") ? symbol.get_full_name () : given_symbol_name;
+ string href = (symbol == _container || symbol == _owner)? null : get_url (symbol);
+ string css_class = cssresolver.resolve (symbol);
+ string end_tag_name;
+
+
+ // Start Tag:
+ if (href != null) {
+ writer.start_tag ("a", {"href", href, "class", css_class});
+ end_tag_name = "a";
+ } else {
+ writer.start_tag ("span", {"class", css_class});
+ end_tag_name = "span";
+ }
+
+
+ // Content:
+ if (label_owner != null && label_owner.content.size > 0) {
+ label_owner.accept_children (this);
+ } else {
+ writer.text (symbol_name);
+ }
+
+
+ // End Tag:
+ writer.end_tag (end_tag_name);
+ }
+
+ private delegate void Write ();
+ private delegate void TagletWrite (Taglet taglet);
+
+ private void write_taglets (Write header, Write footer, Write separator,
+ Gee.List<Taglet> taglets, TagletWrite write) {
+ if (taglets.size > 0) {
+ header ();
+ bool first = true;
+ foreach (var taglet in taglets) {
+ if (!first) {
+ separator ();
+ }
+ write (taglet);
+ first = false;
+ }
+ footer ();
+ }
+ }
+
+ public override void visit_comment (Comment element) {
+ Gee.List<Taglet> taglets;
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.Deprecated));
+ write_taglets (
+ () => {
+ writer.start_tag ("p", {"class", "main_title"});
+ writer.start_tag ("b")
+ .text ("Deprecated: ")
+ .end_tag ("b");
+ },
+ () => {
+ writer.end_tag ("p");
+ },
+ () => {},
+ taglets,
+ (taglet) => {
+ var deprecated = taglet as Taglets.Deprecated;
+ deprecated.accept_children (this);
+ });
+
+ // Write description
+ element.accept_children (this);
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.Param));
+ taglets.sort ((_a, _b) => {
+ Taglets.Param a = _a as Taglets.Param;
+ Taglets.Param b = _b as Taglets.Param;
+
+ if (a.position < 0 && b.position < 0) {
+ int cmp = a.parameter_name.ascii_casecmp (b.parameter_name);
+ if (cmp == 0) {
+ return 0;
+ }
+
+ if (a.parameter_name == "...") {
+ return 1;
+ }
+
+ if (b.parameter_name == "...") {
+ return -1;
+ }
+
+ return cmp;
+ }
+
+ if (a.position < 0) {
+ return 1;
+ }
+
+ if (b.position < 0) {
+ return -1;
+ }
+
+ return a.position - b.position;
+ });
+
+ write_taglets (
+ () => {
+ writer.start_tag ("h2", {"class", "main_title"})
+ .text ("Parameters:")
+ .end_tag ("h2");
+ writer.start_tag ("table", {"class", "main_parameter_table"});
+ },
+ () => {
+ writer.end_tag ("table");
+ },
+ () => {},
+ taglets,
+ (taglet) => {
+ var param = taglet as Taglets.Param;
+ string[]? unknown_parameter_css = null;
+ if (param.parameter == null && !param.is_this) {
+ unknown_parameter_css = {"class", "main_parameter_table_unknown_parameter"};
+ }
+
+ writer.start_tag ("tr", unknown_parameter_css);
+ writer.start_tag ("td", {"class", "main_parameter_table_name"})
+ .text (param.parameter_name)
+ .end_tag ("td");
+ writer.start_tag ("td");
+ param.accept_children (this);
+ writer.end_tag ("td");
+ writer.end_tag ("tr");
+ });
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.Return));
+ write_taglets (
+ () => {
+ writer.start_tag ("h2", {"class", "main_title"})
+ .text ("Returns:")
+ .end_tag ("h2");
+ writer.start_tag ("table", {"class", "main_parameter_table"});
+ },
+ () => {
+ writer.end_tag ("table");
+ },
+ () => {},
+ taglets,
+ (taglet) => {
+ var param = taglet as Taglets.Return;
+ writer.start_tag ("tr");
+ writer.start_tag ("td");
+ param.accept_children (this);
+ writer.end_tag ("td");
+ writer.end_tag ("tr");
+ });
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.Throws));
+ write_taglets (
+ () => {
+ writer.start_tag ("h2", {"class", "main_title"})
+ .text ("Exceptions:")
+ .end_tag ("h2");
+ writer.start_tag ("table", {"class", "main_parameter_table"});
+ },
+ () => {
+ writer.end_tag ("table");
+ },
+ () => {},
+ taglets,
+ (taglet) => {
+ var exception = taglet as Taglets.Throws;
+ writer.start_tag ("tr");
+ writer.start_tag ("td", {"class", "main_parameter_table_name"})
+ .text (exception.error_domain_name)
+ .end_tag ("td");
+ writer.start_tag ("td");
+ exception.accept_children (this);
+ writer.end_tag ("td");
+ writer.end_tag ("tr");
+ });
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.Since));
+ write_taglets (
+ () => {
+ writer.start_tag ("h2", {"class", "main_title"})
+ .text ("Since:")
+ .end_tag ("h2");
+ writer.start_tag ("p");
+ },
+ () => {
+ writer.end_tag ("p");
+ },
+ () => {},
+ taglets,
+ (taglet) => {
+ var since = taglet as Taglets.Since;
+ writer.text (since.version);
+ });
+
+ taglets = element.find_taglets ((Api.Node) _container, typeof (Taglets.See));
+ write_taglets (
+ () => {
+ writer.start_tag ("h2", {"class", "main_title"})
+ .text ("See also:")
+ .end_tag ("h2");
+ writer.start_tag ("p");
+ },
+ () => {
+ writer.end_tag ("p");
+ },
+ () => {
+ writer.text (", ");
+ },
+ taglets,
+ (taglet) => {
+ var see = taglet as Taglets.See;
+ if (see.symbol == null) {
+ write_unresolved_symbol_link (see.symbol_name);
+ } else {
+ write_resolved_symbol_link (see.symbol, see.symbol_name);
+ }
+ });
+ }
+
+ public override void visit_embedded (Embedded element) {
+ var caption = element.caption;
+
+ var absolute_path = Path.build_filename (settings.path, element.package.name, "img",
+ Path.get_basename (element.url));
+ var relative_path = Path.build_filename ("img", Path.get_basename (element.url));
+
+ copy_file (element.url, absolute_path);
+
+ writer.image (relative_path, (caption == null || caption == "") ? "" : caption);
+ }
+
+ public override void visit_headline (Headline element) {
+ writer.start_tag ("h%d".printf (element.level));
+ element.accept_children (this);
+ writer.end_tag ("h%d".printf (element.level));
+ }
+
+ public override void visit_wiki_link (WikiLink element) {
+ if (element.page != null) {
+ writer.start_tag ("a", {"href", get_url (element.page)});
+ }
+
+ if (element.content.size > 0) {
+ element.accept_children (this);
+ } else {
+ writer.text (element.name.substring (0, element.name.last_index_of_char ('.')));
+ }
+
+ if (element.page != null) {
+ writer.end_tag ("a");
+ }
+ }
+
+ public override void visit_link (Link element) {
+ if (Uri.parse_scheme (element.url) != null) {
+ writer.start_tag ("a", {"href", element.url, "target", "_blank"});
+ } else {
+ writer.start_tag ("a", {"href", element.url});
+ }
+
+ if (element.content.size > 0) {
+ element.accept_children (this);
+ } else {
+ writer.text (element.url);
+ }
+
+ writer.end_tag ("a");
+ }
+
+ public override void visit_symbol_link (SymbolLink element) {
+ if (element.symbol == null) {
+ write_unresolved_symbol_link (element.given_symbol_name, element);
+ } else {
+ write_resolved_symbol_link (element.symbol, element.given_symbol_name, element);
+ }
+ }
+
+ public override void visit_list (Content.List element) {
+ string list_type = null;
+ string bullet_type = null;
+ string css_class = null;
+ switch (element.bullet) {
+ case Content.List.Bullet.NONE:
+ list_type = "ul";
+ css_class = "no_bullet";
+ break;
+ case Content.List.Bullet.UNORDERED:
+ list_type = "ul";
+ break;
+ case Content.List.Bullet.ORDERED:
+ list_type = "ol";
+ break;
+ case Content.List.Bullet.ORDERED_NUMBER:
+ list_type = "ol";
+ bullet_type = "1";
+ break;
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ALPHA:
+ list_type = "ol";
+ bullet_type = "a";
+ break;
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ALPHA:
+ list_type = "ol";
+ bullet_type = "A";
+ break;
+ case Content.List.Bullet.ORDERED_LOWER_CASE_ROMAN:
+ list_type = "ol";
+ bullet_type = "i";
+ break;
+ case Content.List.Bullet.ORDERED_UPPER_CASE_ROMAN:
+ list_type = "ol";
+ bullet_type = "I";
+ break;
+ }
+ writer.start_tag (list_type, {"class", css_class, "type", bullet_type});
+ element.accept_children (this);
+ writer.end_tag (list_type);
+ }
+
+ public override void visit_list_item (ListItem element) {
+ writer.start_tag ("li");
+ Paragraph? first_para = (element.content.size > 0)? element.content[0] as Paragraph : null;
+ if (first_para != null) {
+ // We do not pick up alignments in gir-files.
+ first_para.accept_children (this);
+ bool first_entry = true;
+ foreach (var item in element.content) {
+ if (!first_entry) {
+ item.accept (this);
+ }
+ first_entry = false;
+ }
+ } else {
+ element.accept_children (this);
+ }
+ writer.end_tag ("li");
+ }
+
+ public override void visit_page (Page element) {
+ element.accept_children (this);
+ }
+
+ public override void visit_paragraph (Paragraph element) {
+ //FIXME: the extra-field is just a workarround for the current codegen ...
+ if (element.horizontal_align == null) {
+ writer.start_tag ("p");
+ } else {
+ HorizontalAlign tmp = element.horizontal_align;
+ switch (tmp) {
+ case HorizontalAlign.CENTER:
+ writer.start_tag ("p", {"style", "text-align: center;"});
+ break;
+
+ case HorizontalAlign.RIGHT:
+ writer.start_tag ("p", {"style", "text-align: right;"});
+ break;
+
+ default:
+ writer.start_tag ("p");
+ break;
+ }
+ }
+ element.accept_children (this);
+ writer.end_tag ("p");
+ }
+
+ private void visit_notification_block (BlockContent element, string headline) {
+ writer.start_tag ("div", {"class", "main_notification_block"});
+ writer.start_tag ("span", {"class", "main_block_headline"})
+ .text (headline)
+ .end_tag ("span")
+ .text (" ");
+ writer.start_tag ("div", {"class", "main_block_content"});
+ element.accept_children (this);
+ writer.end_tag ("div");
+ writer.end_tag ("div");
+ }
+
+ public override void visit_warning (Warning element) {
+ visit_notification_block (element, "Warning:");
+ }
+
+ public override void visit_note (Note element) {
+ visit_notification_block (element, "Note:");
+ }
+
+ public override void visit_run (Run element) {
+ string tag = null;
+ string css_type = null;
+ switch (element.style) {
+ case Run.Style.BOLD:
+ tag = "b";
+ break;
+ case Run.Style.ITALIC:
+ tag = "i";
+ break;
+ case Run.Style.UNDERLINED:
+ tag = "u";
+ break;
+ case Run.Style.MONOSPACED:
+ tag = "code";
+ break;
+ case Run.Style.STROKE:
+ tag = "stroke";
+ break;
+ case Run.Style.LANG_KEYWORD:
+ tag = "span";
+ css_type = "main_keyword";
+ break;
+ case Run.Style.LANG_ESCAPE:
+ tag = "span";
+ css_type = "main_escape";
+ break;
+ case Run.Style.LANG_LITERAL:
+ tag = "span";
+ css_type = "main_literal";
+ break;
+ case Run.Style.LANG_BASIC_TYPE:
+ tag = "span";
+ css_type = "main_basic_type";
+ break;
+ case Run.Style.LANG_TYPE:
+ tag = "span";
+ css_type = "main_type";
+ break;
+ case Run.Style.LANG_COMMENT:
+ tag = "span";
+ css_type = "main_comment";
+ break;
+ case Run.Style.LANG_PREPROCESSOR:
+ tag = "span";
+ css_type = "main_preprocessor";
+ break;
+
+ case Run.Style.XML_ESCAPE:
+ tag = "span";
+ css_type = "xml_escape";
+ break;
+
+ case Run.Style.XML_ELEMENT:
+ tag = "span";
+ css_type = "xml_element";
+ break;
+
+ case Run.Style.XML_ATTRIBUTE:
+ tag = "span";
+ css_type = "xml_attribute";
+ break;
+
+ case Run.Style.XML_ATTRIBUTE_VALUE:
+ tag = "span";
+ css_type = "xml_attribute_value";
+ break;
+
+ case Run.Style.XML_COMMENT:
+ tag = "span";
+ css_type = "xml_comment";
+ break;
+
+ case Run.Style.XML_CDATA:
+ tag = "span";
+ css_type = "xml_cdata";
+ break;
+ }
+ if (tag != null) {
+ writer.start_tag (tag, {"class", css_type});
+ }
+ element.accept_children (this);
+ if (tag != null) {
+ writer.end_tag (tag);
+ }
+ }
+
+ public override void visit_source_code (SourceCode element) {
+ writer.set_wrap (false);
+ writer.start_tag ("pre", {"class", "main_source"});
+ element.accept_children (this);
+ writer.end_tag ("pre");
+ writer.set_wrap (true);
+ }
+
+ public override void visit_table (Table element) {
+ writer.start_tag ("table", {"class", "main_table"});
+ element.accept_children (this);
+ writer.end_tag ("table");
+ }
+
+ public override void visit_table_cell (TableCell element) {
+ string style = "";
+
+ if (element.horizontal_align != null) {
+ style += "text-align: "+element.horizontal_align.to_string ()+"; ";
+ }
+
+ if (element.vertical_align != null) {
+ style += "vertical-align: "+element.vertical_align.to_string ()+"; ";
+ }
+
+ writer.start_tag ("td", {"class", "main_table",
+ "colspan", element.colspan.to_string (),
+ "rowspan", element.rowspan.to_string (),
+ "style", style});
+ element.accept_children (this);
+ writer.end_tag ("td");
+ }
+
+ public override void visit_table_row (TableRow element) {
+ writer.start_tag ("tr");
+ element.accept_children (this);
+ writer.end_tag ("tr");
+ }
+
+ public override void visit_taglet (Taglet element) {
+ }
+
+ public override void visit_text (Text element) {
+ write_string (element.content);
+ }
+
+ private void write_string (string content) {
+ unichar chr = content[0];
+ long lpos = 0;
+ int i = 0;
+
+ for (i = 0; chr != '\0' ; i++, chr = content[i]) {
+ switch (chr) {
+ case '\n':
+ writer.text (content.substring (lpos, i-lpos));
+ writer.simple_tag ("br");
+ lpos = i+1;
+ break;
+ case '<':
+ writer.text (content.substring (lpos, i-lpos));
+ writer.text ("&lt;");
+ lpos = i+1;
+ break;
+ case '>':
+ writer.text (content.substring (lpos, i-lpos));
+ writer.text ("&gt;");
+ lpos = i+1;
+ break;
+ case '&':
+ writer.text (content.substring (lpos, i-lpos));
+ writer.text ("&amp;");
+ lpos = i+1;
+ break;
+ }
+ }
+ writer.text (content.substring (lpos, i-lpos));
+ }
+}
+
diff --git a/libvaladoc/html/linkhelper.vala b/libvaladoc/html/linkhelper.vala
new file mode 100644
index 000000000..0f990bb43
--- /dev/null
+++ b/libvaladoc/html/linkhelper.vala
@@ -0,0 +1,189 @@
+/* linkhelper.vala
+ *
+ * Copyright (C) 2008-2012 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 Gee;
+
+
+
+public class Valadoc.Html.LinkHelper : Object {
+ protected Settings _settings = null;
+
+ public bool enable_browsable_check {
+ default = true;
+ get;
+ set;
+ }
+
+ public virtual string? get_package_link (Api.Package package, Settings settings) {
+ if (enable_browsable_check && !package.is_browsable (settings)) {
+ return null;
+ }
+
+ return Path.build_filename (package.name, "index.htm");
+ }
+
+ public string? get_relative_link (Documentation from, Documentation to, Settings settings) {
+ _settings = settings;
+
+ //TODO: find a better solution which does not require too much code ...
+ if (from is Api.Package) {
+ if (to is Api.Package) {
+ return from_package_to_package ((Api.Package) from, (Api.Package) to);
+ } else if (to is Api.Node) {
+ return from_package_to_node ((Api.Package) from, (Api.Node) to);
+ } else if (to is WikiPage) {
+ return from_package_to_wiki ((Api.Package) from, (WikiPage) to);
+ } else {
+ assert (true);
+ }
+ } else if (from is Api.Node) {
+ if (to is Api.Package) {
+ return from_node_to_package ((Api.Node) from, (Api.Package) to);
+ } else if (to is Api.Node) {
+ return from_node_to_node ((Api.Node) from, (Api.Node) to);
+ } else if (to is WikiPage) {
+ return from_node_to_wiki ((Api.Node) from, (WikiPage) to);
+ } else {
+ assert (true);
+ }
+ } else if (from is WikiPage) {
+ if (to is Api.Package) {
+ return from_wiki_to_package ((WikiPage) from, (Api.Package) to);
+ } else if (to is Api.Node) {
+ return from_wiki_to_node ((WikiPage) from, (Api.Node) to);
+ } else if (to is WikiPage) {
+ return from_wiki_to_wiki ((WikiPage) from, (WikiPage) to);
+ } else {
+ assert (true);
+ }
+ } else {
+ assert (true);
+ }
+
+ return null;
+ }
+
+ protected string translate_wiki_name (WikiPage page) {
+ var name = page.name;
+ return name.substring (0, name.last_index_of_char ('.')).replace ("/", ".") + ".htm";
+ }
+
+
+
+
+ protected virtual string? from_package_to_package (Api.Package from, Api.Package to) {
+ if (enable_browsable_check && !to.is_browsable(_settings)) {
+ return null;
+ }
+
+ if (from == to) {
+ return "#";
+ } else {
+ return Path.build_filename ("..", to.name, "index.htm");
+ }
+ }
+
+ protected virtual string? from_package_to_wiki (Api.Package from, WikiPage to) {
+ if (from.is_package) {
+ return Path.build_filename ("..", _settings.pkg_name, translate_wiki_name (to));
+ } else {
+ return translate_wiki_name (to);
+ }
+ }
+
+ protected virtual string? from_package_to_node (Api.Package from, Api.Node to) {
+ if (enable_browsable_check && (!to.is_browsable(_settings) || !to.package.is_browsable (_settings))) {
+ return null;
+ }
+
+ if (from == to.package) {
+ return Path.build_filename (to.get_full_name () + ".html");
+ } else {
+ return Path.build_filename ("..", to.package.name, to.get_full_name () + ".html");
+ }
+ }
+
+
+
+ protected virtual string? from_wiki_to_package (WikiPage from, Api.Package to) {
+ if (enable_browsable_check && !to.is_browsable(_settings)) {
+ return null;
+ }
+
+ if (to.is_package) {
+ return Path.build_filename ("..", to.name, "index.htm");
+ } else {
+ return "index.htm";
+ }
+ }
+
+ protected virtual string? from_wiki_to_wiki (WikiPage from, WikiPage to) {
+ return translate_wiki_name (to);
+ }
+
+ protected virtual string? from_wiki_to_node (WikiPage from, Api.Node to) {
+ if (enable_browsable_check && (!to.is_browsable(_settings) || !to.package.is_browsable (_settings))) {
+ return null;
+ }
+
+ if (to.package.is_package) {
+ return Path.build_filename ("..", to.package.name, to.get_full_name () + ".html");
+ } else {
+ return to.get_full_name () + ".html";
+ }
+ }
+
+
+
+ protected virtual string? from_node_to_package (Api.Node from, Api.Package to) {
+ if (enable_browsable_check && !to.is_browsable (_settings)) {
+ return null;
+ }
+
+ if (from.package == to) {
+ return "index.htm";
+ } else {
+ return Path.build_filename ("..", to.name, "index.htm");
+ }
+ }
+
+ protected virtual string? from_node_to_wiki (Api.Node from, WikiPage to) {
+ if (from.package.is_package) {
+ return Path.build_filename ("..", _settings.pkg_name, translate_wiki_name (to));
+ } else {
+ return translate_wiki_name (to);
+ }
+ }
+
+ protected virtual string? from_node_to_node (Api.Node from, Api.Node to) {
+ if (enable_browsable_check && (!to.is_browsable(_settings) || !to.package.is_browsable (_settings))) {
+ return null;
+ }
+
+ if (from.package == to.package) {
+ return Path.build_filename (to.get_full_name() + ".html");
+ } else {
+ return Path.build_filename ("..", to.package.name, to.get_full_name() + ".html");
+ }
+ }
+ }
+
diff --git a/libvaladoc/importer/documentationimporter.vala b/libvaladoc/importer/documentationimporter.vala
new file mode 100644
index 000000000..1a0f0bab5
--- /dev/null
+++ b/libvaladoc/importer/documentationimporter.vala
@@ -0,0 +1,47 @@
+/* resourcelocator.vala
+ *
+ * Copyright (C) 2008-2009 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 Gee;
+
+
+public abstract class Valadoc.Importer.DocumentationImporter : Object, ResourceLocator {
+ protected ModuleLoader modules;
+ protected Settings settings;
+ protected Api.Tree tree;
+
+ public abstract string file_extension { get; }
+
+ public DocumentationImporter (Api.Tree tree, ModuleLoader modules, Settings settings) {
+ this.settings = settings;
+ this.modules = null;
+ this.tree = tree;
+ }
+
+ public virtual string resolve (string path) {
+ return path;
+ }
+
+ public abstract void process (string filename);
+}
+
+
diff --git a/libvaladoc/importer/girdocumentationimporter.vala b/libvaladoc/importer/girdocumentationimporter.vala
new file mode 100644
index 000000000..3228dbec1
--- /dev/null
+++ b/libvaladoc/importer/girdocumentationimporter.vala
@@ -0,0 +1,863 @@
+/* girdocumentationimporter.vala
+ *
+ * Copyright (C) 2008-2010 Jürg Billeter
+ * Copyright (C) 2011 Luca Bruno
+ * Copyright (C) 2011-2014 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;
+using Gee;
+
+
+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;
+
+ private struct ImplicitParameterPos {
+ public int parameter;
+ public int position;
+
+ public ImplicitParameterPos (int parameter, int position) {
+ this.parameter = parameter;
+ this.position = position;
+ }
+ }
+
+ 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, null);
+ this.reader = new MarkupReader (source_file, reporter);
+
+ // xml prolog
+ next ();
+ next ();
+
+ next ();
+ parse_repository ();
+
+ reader = null;
+ file = null;
+ }
+
+ private Api.FormalParameter? find_parameter (Api.Node node, string name) {
+ Gee.List<Api.Node> parameters = node.get_children_by_type (Api.NodeType.FORMAL_PARAMETER, false);
+ foreach (Api.Node param in parameters) {
+ if (((Api.FormalParameter) param).name == name) {
+ return (Api.FormalParameter) param;
+ }
+ }
+
+ return null;
+ }
+
+ private inline string? get_cparameter_name (string[] param_names, int length_pos) {
+ if (length_pos < 0 || param_names.length < length_pos) {
+ return null;
+ }
+
+ return param_names[length_pos];
+ }
+
+ private void attach_comment (string cname,
+ Api.GirSourceComment? comment,
+ string[]? param_names = null,
+ ImplicitParameterPos[]? destroy_notifies = null,
+ ImplicitParameterPos[]? closures = null,
+ ImplicitParameterPos[]? array_lengths = null,
+ int array_length_ret = -1)
+ {
+ if (comment == null) {
+ return ;
+ }
+
+ Api.Node? node = this.tree.search_symbol_cstr (null, cname);
+ if (node == null) {
+ return;
+ }
+
+ if (param_names != null) {
+ foreach (ImplicitParameterPos pos in destroy_notifies) {
+ Api.FormalParameter? param = find_parameter (node, param_names[pos.parameter]);
+ if (param == null) {
+ continue ;
+ }
+
+ param.implicit_destroy_cparameter_name
+ = get_cparameter_name (param_names, pos.position);
+ }
+
+ foreach (ImplicitParameterPos pos in closures) {
+ Api.FormalParameter? param = find_parameter (node, param_names[pos.parameter]);
+ if (param == null) {
+ continue ;
+ }
+
+ param.implicit_closure_cparameter_name
+ = get_cparameter_name (param_names, pos.position);
+ }
+
+ foreach (ImplicitParameterPos pos in array_lengths) {
+ Api.FormalParameter? param = find_parameter (node, param_names[pos.parameter]);
+ if (param == null) {
+ continue ;
+ }
+
+ param.implicit_array_length_cparameter_name
+ = get_cparameter_name (param_names, pos.position);
+ }
+
+ if (node is Api.Callable) {
+ ((Api.Callable) node).implicit_array_length_cparameter_name
+ = get_cparameter_name (param_names, array_length_ret);
+ }
+ }
+
+ Content.Comment? content = this.parser.parse (node, comment);
+ if (content == null) {
+ return;
+ }
+
+ node.documentation = content;
+ }
+
+ private void warning (string message) {
+ reporter.warning (this.file.relative_path, this.begin.line, this.begin.column, this.end.column,
+ this.reader.get_line_content (this.begin.line), message);
+ }
+
+ 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);
+
+ // Skip <annotation /> (only generated by valac) and <attribute />
+ if (current_token == MarkupTokenType.START_ELEMENT
+ && (reader.name == "annotation" || reader.name == "attribute")) {
+ next (); // MarkupTokenType.END_ELEMENT, annotation / attribute
+ next ();
+ }
+ }
+
+ 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 () {
+ Api.GirSourceComment? comment = null;
+
+ if (reader.name == "doc") {
+ start_element ("doc");
+ next ();
+
+
+ if (current_token == MarkupTokenType.TEXT) {
+ comment = new Api.GirSourceComment (reader.content, file, begin.line,
+ begin.column, end.line, end.column);
+ next ();
+ }
+
+ end_element ("doc");
+ }
+
+ while (true) {
+ if (reader.name == "doc-deprecated") {
+ Api.SourceComment? doc_deprecated = parse_doc ("doc-deprecated");
+ if (doc_deprecated != null) {
+ if (comment == null) {
+ comment = new Api.GirSourceComment ("", file, begin.line, end.line,
+ begin.line, end.line);
+ }
+
+ comment.deprecated_comment = doc_deprecated;
+ }
+ } else if (reader.name == "doc-version") {
+ Api.SourceComment? doc_version = parse_doc ("doc-version");
+ if (doc_version != null) {
+ if (comment == null) {
+ comment = new Api.GirSourceComment ("", file, begin.line, end.line,
+ begin.line, end.line);
+ }
+
+ comment.version_comment = doc_version;
+ }
+ } else if (reader.name == "doc-stability") {
+ Api.SourceComment? doc_stability = parse_doc ("doc-stability");
+ if (doc_stability != null) {
+ if (comment == null) {
+ comment = new Api.GirSourceComment ("", file, begin.line, end.line,
+ begin.line, end.line);
+ }
+
+ comment.stability_comment = doc_stability;
+ }
+ } else {
+ break;
+ }
+ }
+
+ return comment;
+ }
+
+ private Api.SourceComment? parse_doc (string element_name = "doc") {
+ if (reader.name != element_name) {
+ return null;
+ }
+
+ start_element (element_name);
+ 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 (element_name);
+ 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, out int array_length_ret) {
+ start_element ("return-value");
+ next ();
+
+ comment = parse_doc ();
+
+ parse_type (out array_length_ret);
+
+ end_element ("return-value");
+ }
+
+ private void parse_parameter (out Api.SourceComment? comment, out string param_name,
+ out int destroy_pos,
+ out int closure_pos, out int array_length_pos) {
+ start_element ("parameter");
+ param_name = reader.get_attribute ("name");
+ array_length_pos = -1;
+ destroy_pos = -1;
+ closure_pos = -1;
+
+ string? closure = reader.get_attribute ("closure");
+ if (closure != null) {
+ closure_pos = int.parse (closure);
+ if (closure_pos < 0) {
+ warning ("invalid closure position");
+ }
+ }
+
+ string? destroy = reader.get_attribute ("destroy");
+ if (destroy != null) {
+ destroy_pos = int.parse (destroy);
+ if (destroy_pos < 0) {
+ warning ("invalid destroy position");
+ }
+ }
+ next ();
+
+ comment = parse_doc ();
+
+ if (reader.name == "varargs") {
+ start_element ("varargs");
+ param_name = "...";
+ next ();
+
+ end_element ("varargs");
+ } else {
+ parse_type (out array_length_pos);
+ }
+
+ end_element ("parameter");
+ }
+
+ private void parse_type (out int array_length_pos = null) {
+ array_length_pos = -1;
+
+ if (reader.name == "array") {
+ string? length = reader.get_attribute ("length");
+ if (length != null) {
+ array_length_pos = int.parse (length);
+ if (array_length_pos < 0) {
+ warning ("invalid array lenght position");
+ }
+ }
+
+ skip_element ();
+ } else {
+ 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 ;
+ }
+
+ bool is_type_struct = (reader.get_attribute ("glib:is-gtype-struct-for") != null);
+ next ();
+
+ Api.GirSourceComment? comment = parse_symbol_doc ();
+ if (is_type_struct == false) {
+ 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 () {
+ parse_function ("callback");
+ }
+
+ 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 "callback":
+ c_identifier = reader.get_attribute ("c:type");
+ 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 ();
+
+ ImplicitParameterPos[] destroy_notifies = new ImplicitParameterPos[0];
+ ImplicitParameterPos[] array_lengths = new ImplicitParameterPos[0];
+ ImplicitParameterPos[] closures = new ImplicitParameterPos[0];
+ string[] param_names = new string[0];
+ int array_length_ret = -1;
+
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "return-value") {
+ Api.SourceComment? return_comment;
+ parse_return_value (out return_comment, out array_length_ret);
+ 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 ();
+
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "instance-parameter") {
+ string instance_param_name = reader.get_attribute ("name");
+ next ();
+
+ Api.SourceComment? param_comment = parse_doc ();
+ parse_type (null);
+ end_element ("instance-parameter");
+
+ if (param_comment != null) {
+ if (comment == null) {
+ comment = new Api.GirSourceComment ("", file, begin.line, begin.column,
+ end.line, end.column);
+ }
+
+ comment.add_parameter_content (instance_param_name, param_comment);
+ comment.instance_param_name = instance_param_name;
+ }
+ }
+
+ for (int pcount = 0; current_token == MarkupTokenType.START_ELEMENT; pcount++) {
+ Api.SourceComment? param_comment;
+ int array_length_pos;
+ int destroy_pos;
+ int closure_pos;
+ string? param_name;
+
+ parse_parameter (out param_comment, out param_name, out destroy_pos,
+ out closure_pos, out array_length_pos);
+ param_names += param_name;
+
+ if (destroy_pos >= 0 && pcount != destroy_pos) {
+ destroy_notifies += ImplicitParameterPos (pcount, destroy_pos);
+ }
+
+ if (closure_pos >= 0 && pcount != closure_pos) {
+ closures += ImplicitParameterPos (pcount, closure_pos);
+ }
+
+ if (array_length_pos >= 0 && pcount != destroy_pos) {
+ array_lengths += ImplicitParameterPos (pcount, array_length_pos);
+ }
+
+ 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, param_names, destroy_notifies, closures,
+ array_lengths, array_length_ret);
+
+ 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");
+ if (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 == "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/libvaladoc/importer/internalidregistrar.vala b/libvaladoc/importer/internalidregistrar.vala
new file mode 100644
index 000000000..a9ece0117
--- /dev/null
+++ b/libvaladoc/importer/internalidregistrar.vala
@@ -0,0 +1,88 @@
+/* gtkdocindexsgmlreader.vala
+ *
+ * Copyright (C) 2014 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;
+
+
+public class Valadoc.Importer.InternalIdRegistrar {
+ private HashMap<string, Api.Node> symbol_map;
+ private HashMap<string, string> map;
+
+
+ public InternalIdRegistrar () {
+ map = new HashMap<string, string> ();
+ symbol_map = new HashMap<string, Api.Node> ();
+ }
+
+
+ public void register_symbol (string id, Api.Node symbol) {
+ this.symbol_map.set (id, symbol);
+ }
+
+ public string? map_url_id (string id) {
+ return map.get (id);
+ }
+
+ public Api.Node? map_symbol_id (string id) {
+ return symbol_map.get (id);
+ }
+
+
+ public void read_index_sgml_file (string filename, string? index_sgml_online, ErrorReporter reporter) {
+ MarkupSourceLocation begin;
+ MarkupSourceLocation end;
+ MarkupTokenType token;
+
+ string base_path = index_sgml_online ?? realpath (filename);
+ var reader = new MarkupReader (filename, reporter);
+
+ while ((token = reader.read_token (out begin, out end)) != MarkupTokenType.EOF) {
+ if (token == MarkupTokenType.START_ELEMENT && reader.name == "ONLINE") {
+ if (index_sgml_online == null) {
+ base_path = reader.get_attribute ("href");
+ if (base_path == null) {
+ reporter.error (filename, begin.line, begin.column, end.column, reader.get_line_content (begin.line), "missing attribute `href' in <ONLINE>");
+ }
+ }
+ } else if (token == MarkupTokenType.START_ELEMENT && reader.name == "ANCHOR") {
+ string id = reader.get_attribute ("id");
+ if (id == null) {
+ reporter.error (filename, begin.line, begin.column, end.column, reader.get_line_content (begin.line), "missing attribute `id' in <ANCHOR>");
+ }
+
+ string href = reader.get_attribute ("href");
+ if (href == null) {
+ reporter.error (filename, begin.line, begin.column, end.column, reader.get_line_content (begin.line), "missing attribute `href' in <ANCHOR>");
+ } else if (index_sgml_online != null) {
+ href = Path.get_basename (href);
+ }
+
+ map.set (id, Path.build_path ("/", base_path, href));
+ } else {
+ reporter.error (filename, begin.line, begin.column, end.column, reader.get_line_content (begin.line), "expected element of <ONLINE> or <ANCHOR>");
+ }
+ }
+ }
+}
+
+
diff --git a/libvaladoc/importer/valadocdocumentationimporter.vala b/libvaladoc/importer/valadocdocumentationimporter.vala
new file mode 100644
index 000000000..b74b430f6
--- /dev/null
+++ b/libvaladoc/importer/valadocdocumentationimporter.vala
@@ -0,0 +1,199 @@
+/* resourcelocator.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 Gee;
+using Valadoc;
+using Valadoc.Content;
+
+public class Valadoc.Importer.ValadocDocumentationImporter : DocumentationImporter, ResourceLocator {
+ public override string file_extension { get { return "valadoc"; } }
+
+ private ValadocDocumentationScanner _scanner;
+ private DocumentationParser _doc_parser;
+ private Parser _parser;
+
+ private MappedFile _mapped_file;
+ private string _filename;
+ 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 ValadocDocumentationScanner (settings);
+ _doc_parser = parser;
+
+ _scanner = new ValadocDocumentationScanner (settings);
+ _parser = new Parser (settings, _scanner, reporter);
+ _scanner.set_parser (_parser);
+
+ _comment = new StringBuilder ();
+
+ // init parser rules:
+ Rule unprinted_spaces = Rule.many ({
+ Rule.one_of ({
+ TokenType.VALADOC_SPACE,
+ TokenType.VALADOC_TAB
+ })
+ });
+
+ Rule empty_lines = Rule.many ({
+ Rule.one_of ({
+ unprinted_spaces,
+ TokenType.VALADOC_EOL
+ })
+ })
+ .set_name ("EmptyLines");
+
+ Rule optional_empty_lines = Rule.option ({
+ empty_lines
+ });
+
+ Rule documentation = Rule.one_of ({
+ Rule.seq ({
+ TokenType.VALADOC_COMMENT_START.action ((token) => { _comment_location = token.end; }),
+ Rule.many ({
+ Rule.one_of ({
+ TokenType.ANY_WORD.action ((token) => { _comment.append (token.to_string ()); }),
+ TokenType.VALADOC_COMMENT_START.action ((token) => { _comment.append (token.to_string ()); }),
+ TokenType.VALADOC_SPACE.action ((token) => { _comment.append (token.to_string ()); }),
+ TokenType.VALADOC_TAB.action ((token) => { _comment.append (token.to_string ()); }),
+ TokenType.VALADOC_EOL.action ((token) => { _comment.append (token.to_string ()); })
+ })
+ }),
+ TokenType.VALADOC_COMMENT_END,
+ optional_empty_lines,
+ TokenType.ANY_WORD.action ((token) => { _cname = token.to_string (); })
+ })
+ .set_reduce (() => {
+ add_documentation (_cname, _comment, _filename, _comment_location);
+ _comment.erase ();
+ _cname = null;
+ }),
+
+ TokenType.ANY_WORD.action ((token) => {
+ add_documentation (token.to_string (), null, _filename, _comment_location);
+ })
+ })
+ .set_name ("Documentation");
+
+ Rule file = Rule.many ({
+ Rule.one_of ({
+ documentation,
+ optional_empty_lines
+ })
+ })
+ .set_name ("ValadocFile");
+
+ _parser.set_root_rule (file);
+ }
+
+ private enum InsertionMode {
+ APPEND,
+ PREPEND,
+ REPLACE
+ }
+
+ private void add_documentation (string _symbol_name, StringBuilder? comment, string filename,
+ SourceLocation src_ref)
+ {
+ Api.Node? symbol = null;
+
+ InsertionMode insertion_mode;
+ string symbol_name;
+ if (_symbol_name.has_suffix ("::append")) {
+ symbol_name = _symbol_name.substring (0, _symbol_name.length - 8);
+ insertion_mode = InsertionMode.APPEND;
+ } else if (_symbol_name.has_suffix ("::prepend")) {
+ symbol_name = _symbol_name.substring (0, _symbol_name.length - 9);
+ insertion_mode = InsertionMode.PREPEND;
+ } else {
+ symbol_name = _symbol_name;
+ insertion_mode = InsertionMode.REPLACE;
+ }
+
+ if (symbol_name.has_prefix ("c::")) {
+ symbol = tree.search_symbol_cstr (null, symbol_name.substring (3));
+ } else {
+ symbol = tree.search_symbol_str (null, symbol_name);
+ }
+
+ if (symbol == null) {
+ if (settings.verbose) {
+ reporter.simple_warning (filename, "Node `%s' does not exist", symbol_name);
+ }
+
+ return ;
+ }
+
+ if (comment != null) {
+ var docu = _doc_parser.parse_comment_str (symbol, comment.str, filename, src_ref.line, src_ref.column);
+ if (docu != null) {
+ docu.check (tree, symbol, filename, reporter, settings);
+
+ if (symbol.documentation == null || insertion_mode == InsertionMode.REPLACE) {
+ if (insertion_mode == InsertionMode.APPEND) {
+ docu.content.insert (0, factory.create_paragraph ());
+ }
+ symbol.documentation = docu;
+ } else if (insertion_mode == InsertionMode.APPEND) {
+ symbol.documentation.content.add_all (docu.content);
+ merge_taglets (symbol.documentation, docu);
+ } else if (insertion_mode == InsertionMode.PREPEND) {
+ symbol.documentation.content.insert_all (0, docu.content);
+ merge_taglets (symbol.documentation, docu);
+ }
+ }
+ }
+ }
+
+ private void merge_taglets (Comment comment, Comment imported) {
+ foreach (Taglet taglet in imported.taglets) {
+ imported.taglets.add (taglet);
+ }
+ }
+
+ public override void process (string filename) {
+ try {
+ _filename = filename;
+ _mapped_file = new MappedFile (filename, false);
+ var content = _mapped_file.get_contents ();
+ if (content != null) {
+ _parser.parse ((string) content, filename, 0, 0);
+ }
+ } catch (FileError err) {
+ reporter.simple_error (null, "Unable to map file `%s': %s", filename, err.message);
+ } catch (ParserError err) {
+ }
+ }
+}
+
diff --git a/libvaladoc/importer/valadocdocumentationimporterscanner.vala b/libvaladoc/importer/valadocdocumentationimporterscanner.vala
new file mode 100644
index 000000000..5c4a4428d
--- /dev/null
+++ b/libvaladoc/importer/valadocdocumentationimporterscanner.vala
@@ -0,0 +1,187 @@
+/* valadodocumentationscanner.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>
+ */
+
+public class Valadoc.Importer.ValadocDocumentationScanner : Object, Scanner {
+
+ public ValadocDocumentationScanner (Settings settings) {
+ _settings = settings;
+ }
+
+ private Settings _settings;
+ private Parser _parser;
+
+ private string _content;
+ private unowned string _index;
+ private bool _stop;
+ private int _last_line;
+ private int _last_column;
+ private int _line;
+ private int _column;
+ private unichar _last_char;
+ private int _skip;
+ private StringBuilder _current_string = new StringBuilder ();
+
+ public void set_parser (Parser parser) {
+ _parser = parser;
+ }
+
+ public virtual void reset () {
+ _stop = false;
+ _last_line = 0;
+ _last_column = 0;
+ _line = 0;
+ _column = 0;
+ _last_char = 0;
+ _skip = 0;
+ _current_string.erase (0, -1);
+ }
+
+ public void scan (string content) throws ParserError {
+ this._content = content;
+
+ for (_index = _content; !_stop && _index.get_char () != 0; _index = _index.next_char ()) {
+ unichar c = _index.get_char ();
+ accept (c);
+ }
+ }
+
+ public void end () throws ParserError {
+ emit_token (TokenType.EOF);
+ }
+
+ public virtual void stop () {
+ _stop = true;
+ }
+
+ public int get_line () {
+ return _line;
+ }
+
+ public virtual string get_line_content () {
+ StringBuilder builder = new StringBuilder ();
+ weak string line_start = _index;
+ unichar c;
+
+ while ((char*) line_start > (char*) _content && line_start.prev_char ().get_char () != '\n') {
+ line_start = line_start.prev_char ();
+ }
+
+ while ((c = line_start.get_char ()) != '\n' && c != '\0') {
+ if (c == '\t') {
+ builder.append_c (' ');
+ } else {
+ builder.append_unichar (c);
+ }
+ line_start = line_start.next_char ();
+ }
+
+ return builder.str;
+ }
+
+ protected unichar get_next_char (int offset = 1) {
+ return _index.get_char (_index.index_of_nth_char (offset));
+ }
+
+
+ protected void accept (unichar c) throws ParserError {
+ _column++;
+ if (_skip == 0) {
+ switch (c) {
+ case '/':
+ if (get_next_char (1) == '*') {
+ emit_token (TokenType.VALADOC_COMMENT_START);
+ _skip = 1;
+ } else {
+ append_char (c);
+ }
+ break;
+
+ case '*':
+ if (get_next_char (1) == '/') {
+ emit_token (TokenType.VALADOC_COMMENT_END);
+ _skip = 1;
+ } else {
+ append_char (c);
+ }
+ break;
+
+ case '\t':
+ emit_token (TokenType.VALADOC_TAB);
+ break;
+
+ case ' ':
+ emit_token (TokenType.VALADOC_SPACE);
+ break;
+
+ case '\n':
+ emit_token (TokenType.VALADOC_EOL);
+ _line++;
+ _column = 0;
+ _last_column = 0;
+ break;
+
+ default:
+ append_char (c);
+ break;
+ }
+ } else {
+ _skip--;
+ }
+ _last_char = c;
+ }
+
+ private void append_char (unichar c) {
+ _current_string.append_unichar (c);
+ }
+
+ public virtual 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_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_line = _line;
+ _last_column = _column;
+ }
+
+}
diff --git a/libvaladoc/markupreader.vala b/libvaladoc/markupreader.vala
new file mode 100644
index 000000000..9f24177e4
--- /dev/null
+++ b/libvaladoc/markupreader.vala
@@ -0,0 +1,337 @@
+/* markupreader.vala
+ *
+ * Copyright (C) 2008-2009 Jürg Billeter
+ * 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>
+ */
+
+using GLib;
+using Gee;
+
+
+/**
+ * Simple reader for a subset of XML.
+ */
+public class Valadoc.MarkupReader : Object {
+ public string filename {
+ private set;
+ get;
+ }
+
+ public string name {
+ private set;
+ get;
+ }
+
+ public string content {
+ private set;
+ get;
+ }
+
+ private MappedFile mapped_file;
+
+ private string[] lines;
+ private char* begin;
+ private char* current;
+ private char* end;
+
+ private int line;
+ private int column;
+
+ private Map<string, string> attributes = new HashMap<string, string> ();
+ private bool empty_element;
+
+ private ErrorReporter reporter;
+
+ public MarkupReader.from_string (string filename, string content, ErrorReporter reporter) {
+ this.filename = filename;
+ this.reporter = reporter;
+
+ lines = content.split ("\n");
+ begin = content;
+ end = begin + content.length;
+ current = begin;
+
+ column = 1;
+ line = 1;
+ }
+
+ public MarkupReader (string filename, ErrorReporter reporter) {
+ this.filename = filename;
+ this.reporter = reporter;
+
+ 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;
+
+ line = 1;
+ column = 1;
+ } catch (FileError e) {
+ reporter.simple_error (null, "Unable to map file '%s': %s", filename, e.message);
+ }
+ }
+
+ 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];
+ }
+
+ /*
+ * Returns a copy of the current attributes.
+ *
+ * @return map of current attributes
+ */
+ public Map<string,string> get_attributes () {
+ var result = new HashMap<string, string> ();
+ foreach (var key in attributes.keys) {
+ result.set (key, attributes.get (key));
+ }
+ return result;
+ }
+
+ private string read_name () {
+ char* begin = current;
+ while (current < end) {
+ if (current[0] == ' ' || current[0] == '\t' || current[0] == '>'
+ || current[0] == '/' || current[0] == '=' || current[0] == '\n') {
+ break;
+ }
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u != (unichar) (-1)) {
+ current += u.to_utf8 (null);
+ } else {
+ reporter.simple_error ("%s:%d".printf (filename, line),
+ "invalid UTF-8 character");
+ }
+ }
+ if (current == begin) {
+ // syntax error: invalid name
+ }
+ return ((string) begin).substring (0, (int) (current - begin));
+ }
+
+ public MarkupTokenType read_token (out MarkupSourceLocation token_begin, out MarkupSourceLocation token_end) {
+ attributes.clear ();
+
+ if (empty_element) {
+ empty_element = false;
+ token_begin = MarkupSourceLocation (begin, line, column);
+ token_end = MarkupSourceLocation (begin, line, column);
+ return MarkupTokenType.END_ELEMENT;
+ }
+
+ content = null;
+ name = null;
+
+ space ();
+
+ MarkupTokenType type = MarkupTokenType.NONE;
+ char* begin = current;
+ token_begin = MarkupSourceLocation (begin, line, column);
+
+ if (current >= end) {
+ type = MarkupTokenType.EOF;
+ } else if (current[0] == '<') {
+ current++;
+ if (current >= end) {
+ // error
+ } else if (current[0] == '?') {
+ // processing instruction
+ } else if (current[0] == '!') {
+ // comment or doctype
+ current++;
+ if (current < end - 1 && current[0] == '-' && current[1] == '-') {
+ // comment
+ current += 2;
+ while (current < end - 2) {
+ if (current[0] == '-' && current[1] == '-' && current[2] == '>') {
+ // end of comment
+ current += 3;
+ break;
+ } else if (current[0] == '\n') {
+ line++;
+ column = 0;
+ }
+ current++;
+ }
+
+ // ignore comment, read next token
+ return read_token (out token_begin, out token_end);
+ }
+ } else if (current[0] == '/') {
+ type = MarkupTokenType.END_ELEMENT;
+ current++;
+ name = read_name ();
+ if (current >= end || current[0] != '>') {
+ // error
+ }
+ current++;
+ } else {
+ type = MarkupTokenType.START_ELEMENT;
+ name = read_name ();
+ space ();
+ while (current < end && current[0] != '>' && current[0] != '/') {
+ string attr_name = read_name ();
+ if (current >= end || current[0] != '=') {
+ // error
+ }
+ current++;
+ // FIXME allow single quotes
+ if (current >= end || current[0] != '"') {
+ // error
+ }
+ current++;
+
+ string attr_value = text ('"', false);
+
+ if (current >= end || current[0] != '"') {
+ // error
+ }
+ current++;
+ attributes.set (attr_name, attr_value);
+ space ();
+ }
+ if (current[0] == '/') {
+ empty_element = true;
+ current++;
+ space ();
+ } else {
+ empty_element = false;
+ }
+ if (current >= end || current[0] != '>') {
+ // error
+ }
+ current++;
+ }
+ } else {
+ space ();
+
+ if (current[0] != '<') {
+ content = text ('<', true);
+ } else {
+ // no text
+ // read next token
+ return read_token (out token_begin, out token_end);
+ }
+
+ type = MarkupTokenType.TEXT;
+ }
+
+ token_end = MarkupSourceLocation (current, line, column - 1);
+
+ return type;
+ }
+
+ private string text (char end_char, bool rm_trailing_whitespace) {
+ StringBuilder content = new StringBuilder ();
+ char* text_begin = current;
+ char* last_linebreak = current;
+
+ while (current < end && current[0] != end_char) {
+ unichar u = ((string) current).get_char_validated ((long) (end - current));
+ if (u == (unichar) (-1)) {
+ reporter.simple_error ("%s:%d".printf (filename, line),
+ "invalid UTF-8 character");
+ } else if (u == '&') {
+ char* next_pos = current + u.to_utf8 (null);
+ if (((string) next_pos).has_prefix ("amp;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('&');
+ current += 5;
+ text_begin = current;
+ } else if (((string) next_pos).has_prefix ("quot;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('"');
+ current += 6;
+ text_begin = current;
+ } else if (((string) next_pos).has_prefix ("apos;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('\'');
+ current += 6;
+ text_begin = current;
+ } else if (((string) next_pos).has_prefix ("lt;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('<');
+ current += 4;
+ text_begin = current;
+ } else if (((string) next_pos).has_prefix ("gt;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('>');
+ current += 4;
+ text_begin = current;
+ } else if (((string) next_pos).has_prefix ("percnt;")) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ content.append_c ('>');
+ current += 8;
+ text_begin = current;
+ } else {
+ current += u.to_utf8 (null);
+ }
+ } else {
+ if (u == '\n') {
+ line++;
+ column = 0;
+ last_linebreak = current;
+ }
+
+ current += u.to_utf8 (null);
+ column++;
+ }
+ }
+
+ if (text_begin != current) {
+ content.append (((string) text_begin).substring (0, (int) (current - text_begin)));
+ }
+
+ column += (int) (current - last_linebreak);
+
+ // Removes trailing whitespace
+ if (rm_trailing_whitespace) {
+ char* str_pos = ((char*)content.str) + content.len;
+ for (str_pos--; str_pos > ((char*)content.str) && str_pos[0].isspace(); str_pos--);
+ content.erase ((ssize_t) (str_pos-((char*) content.str) + 1), -1);
+ }
+
+ return content.str;
+ }
+
+ private void space () {
+ while (current < end && current[0].isspace ()) {
+ if (current[0] == '\n') {
+ line++;
+ column = 0;
+ }
+ current++;
+ column++;
+ }
+ }
+}
+
+
diff --git a/libvaladoc/markupsourcelocation.vala b/libvaladoc/markupsourcelocation.vala
new file mode 100644
index 000000000..af7dff1b2
--- /dev/null
+++ b/libvaladoc/markupsourcelocation.vala
@@ -0,0 +1,39 @@
+/* valasourcelocation.vala
+ *
+ * Copyright (C) 2008 Jürg Billeter
+ *
+ * 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>
+ */
+
+using GLib;
+
+/**
+ * Represents a position in a source file.
+ */
+public struct Valadoc.MarkupSourceLocation {
+ public char* pos;
+ public int line;
+ public int column;
+
+ public MarkupSourceLocation (char* _pos, int _line, int _column) {
+ pos = _pos;
+ line = _line;
+ column = _column;
+ }
+}
+
diff --git a/libvaladoc/markuptokentype.vala b/libvaladoc/markuptokentype.vala
new file mode 100644
index 000000000..d2dcad74f
--- /dev/null
+++ b/libvaladoc/markuptokentype.vala
@@ -0,0 +1,51 @@
+/* markuptokentype.vala
+ *
+ * Copyright (C) 2008-2009 Jürg Billeter
+ *
+ * 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>
+ */
+
+
+public enum Valadoc.MarkupTokenType {
+ NONE,
+ COMMENT,
+ START_ELEMENT,
+ END_ELEMENT,
+ TEXT,
+ EOF;
+
+ public string to_string () {
+ switch (this) {
+ case START_ELEMENT:
+ return "start element";
+
+ case END_ELEMENT:
+ return "end element";
+
+ case TEXT:
+ return "text";
+
+ case EOF:
+ return "end of file";
+
+ default:
+ return "unknown token type";
+ }
+ }
+}
+
diff --git a/libvaladoc/markupwriter.vala b/libvaladoc/markupwriter.vala
new file mode 100644
index 000000000..28a61ffe7
--- /dev/null
+++ b/libvaladoc/markupwriter.vala
@@ -0,0 +1,272 @@
+/* markupwriter.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+
+/**
+ * Writes markups and text to a file.
+ */
+public class Valadoc.MarkupWriter {
+ protected WriteFunc write;
+ protected int indent;
+
+ protected long current_column = 0;
+ protected bool last_was_tag;
+ private bool wrap = true;
+
+ public static string escape (string txt) {
+ StringBuilder builder = new StringBuilder ();
+ unowned string start = txt;
+ unowned string pos;
+ unichar c;
+
+ for (pos = txt; (c = pos.get_char ()) != '\0'; pos = pos.next_char ()) {
+ switch (c) {
+ case '"':
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ builder.append ("&quot;");
+ start = pos.next_char ();
+ break;
+
+ case '<':
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ builder.append ("&lt;");
+ start = pos.next_char ();
+ break;
+
+ case '>':
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ builder.append ("&gt;");
+ start = pos.next_char ();
+ break;
+
+ case '&':
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ builder.append ("&amp;");
+ start = pos.next_char ();
+ break;
+
+ case '\'':
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ builder.append ("&apos;");
+ start = pos.next_char ();
+ break;
+ }
+ }
+
+ if (&txt == &start) {
+ return txt;
+ } else {
+ builder.append_len (start, (ssize_t) ((char*) pos - (char*) start));
+ return (owned) builder.str;
+ }
+ }
+
+ /**
+ * Writes text to a desination like a {@link GLib.StringBuilder} or a {@link GLib.FileStream}
+ */
+ public delegate void WriteFunc (string text);
+
+ private const int MAX_COLUMN = 150;
+
+ /**
+ * Initializes a new instance of the MarkupWriter
+ *
+ * @param write stream a WriteFunc
+ * @param xml_declaration specifies whether this file starts with an xml-declaration
+ */
+ public MarkupWriter (owned WriteFunc write, bool xml_declaration = true) {
+ this.write = (owned) write;
+ if (xml_declaration) {
+ do_write ("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
+ }
+ indent = -1;
+ last_was_tag = true;
+ }
+
+ /**
+ * Writes an start tag of a markup element to the file
+ *
+ * @param name the name of the markup
+ * @param attributes a list of name/value pairs
+ * @return this
+ */
+ public MarkupWriter start_tag (string name, string[]? attributes=null) {
+ indent++;
+ check_column (name);
+
+ if (attributes.length % 2 != 0) {
+ attributes.resize (attributes.length+1);
+ attributes[attributes.length-1] = "";
+ }
+
+ var content = new StringBuilder ("<");
+ content.append (name);
+ for (int i = 0; i < attributes.length; i=i+2) {
+ if (attributes[i+1] != null) {
+ content.append_printf (" %s=\"%s\"", attributes[i], attributes[i+1]);
+ }
+ }
+ content.append (">");
+
+ do_write (content.str);
+ last_was_tag = true;
+ return this;
+ }
+
+ /**
+ * Writes a simple tag (<name />) to the file
+ *
+ * @param name the name of the markup
+ * @param attributes a list of name/value pairs
+ * @return this
+ */
+ public MarkupWriter simple_tag (string name, string[]? attributes=null) {
+ indent++;
+ check_column (name);
+
+ if (attributes.length % 2 != 0) {
+ attributes.resize (attributes.length+1);
+ attributes[attributes.length-1] = "";
+ }
+
+ var content = new StringBuilder ("<");
+ content.append (name);
+ for (int i = 0; i < attributes.length; i=i+2) {
+ if (attributes[i+1] != null) {
+ content.append_printf (" %s=\"%s\"", attributes[i], attributes[i+1]);
+ }
+ }
+ content.append ("/>");
+
+ do_write (content.str);
+ indent--;
+ last_was_tag = true;
+ return this;
+ }
+
+ /**
+ * Writes an end tag of a markup element to the file
+ *
+ * @param name the name of the markup
+ * @return this
+ */
+ public MarkupWriter end_tag (string name) {
+ check_column (name, true);
+ do_write ("</%s>".printf (name));
+ indent--;
+ last_was_tag = true;
+ return this;
+ }
+
+ /**
+ * Writes the specified string to the output stream
+ *
+ * @see raw_text
+ * @return this
+ */
+ public MarkupWriter text (string text) {
+ if (wrap && text.length + current_column > MAX_COLUMN) {
+ long wrote = 0;
+ while (wrote < text.length) {
+ long space_pos = -1;
+ for (long i = wrote + 1; i < text.length; i++) {
+ if (text[i] == ' ') {
+ if (i - wrote + current_column > MAX_COLUMN) {
+ break;
+ }
+ space_pos = i;
+ }
+ }
+ if (text.length - wrote + current_column <= MAX_COLUMN) {
+ do_write (text.substring (wrote));
+ wrote = text.length + 1;
+ } else if (space_pos == -1) {
+ // Force line break
+ } else {
+ do_write (text.substring (wrote, space_pos - wrote));
+ wrote = space_pos + 1;
+ }
+ if (wrote < text.length) {
+ break_line ();
+ do_write (" ");
+ }
+ }
+ } else {
+ do_write (text);
+ }
+ last_was_tag = false;
+ return this;
+ }
+
+ /**
+ * Writes the specified string to the output stream
+ *
+ * @see text
+ * @return this
+ */
+ public MarkupWriter raw_text (string text) {
+ do_write (text);
+ last_was_tag = false;
+ return this;
+ }
+
+ public void set_wrap (bool wrap) {
+ this.wrap = wrap;
+ }
+
+ private void break_line () {
+ write ("\n");
+ write (string.nfill (indent * 2, ' '));
+ current_column = indent * 2;
+ }
+
+ protected void do_write (string text) {
+ if (wrap && current_column + text.length > MAX_COLUMN) {
+ break_line ();
+ }
+ write (text);
+ current_column += text.length;
+ }
+
+ private void check_column (string name, bool end_tag = false) {
+ if (!wrap) {
+ return;
+ } else if (!end_tag && inline_element (name) /*&& !last_was_tag*/) {
+ return;
+ } else if (end_tag && content_inline_element (name)) {
+ return;
+ } else if (end_tag && !last_was_tag) {
+ return;
+ }
+ break_line ();
+ }
+
+ protected virtual bool inline_element (string name) {
+ return false;
+ }
+
+ protected virtual bool content_inline_element (string name) {
+ return true;
+ }
+}
+
+
diff --git a/libvaladoc/moduleloader.vala b/libvaladoc/moduleloader.vala
new file mode 100644
index 000000000..911be76f7
--- /dev/null
+++ b/libvaladoc/moduleloader.vala
@@ -0,0 +1,254 @@
+/* moduleloader.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch
+ * 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+using Gee;
+
+
+[CCode (has_target = false)]
+public delegate void Valadoc.TagletRegisterFunction (ModuleLoader loader);
+
+
+
+
+public class Valadoc.ModuleLoader : Object {
+ private HashMap<string, ModuleData> doclets = new HashMap<string, ModuleData> ();
+ private HashMap<string, ModuleData> drivers = new HashMap<string, ModuleData> ();
+ private HashMap<string, GLib.Type> taglets = new HashMap<string, GLib.Type> ();
+
+ private static ModuleLoader instance;
+
+ public static ModuleLoader get_instance () {
+ if (instance == null) {
+ instance = new ModuleLoader ();
+ Taglets.init (instance);
+ }
+ return instance;
+ }
+
+ private ModuleLoader () {
+ }
+
+ private class ModuleData : Object {
+ public Module module;
+ public Type type;
+ }
+
+
+ //
+ // driver path helpers:
+ //
+
+ private struct DriverMetaData {
+ public int64[] segments_min;
+ public int64[] segments_max;
+ public string driver_name;
+
+ public DriverMetaData (int64 min_a, int64 min_b, int64 max_a, int64 max_b, string driver_name) {
+ this.segments_min = {min_a, min_b};
+ this.segments_max = {max_a, max_b};
+ this.driver_name = driver_name;
+ }
+ }
+
+ public static bool is_driver (string path) {
+ string library_path = Path.build_filename (path, "libdriver." + Module.SUFFIX);
+ return FileUtils.test (path, FileTest.EXISTS) && FileUtils.test (library_path, FileTest.EXISTS);
+ }
+
+ public static bool is_doclet (string path) {
+ string library_path = Path.build_filename (path, "libdoclet." + Module.SUFFIX);
+ return FileUtils.test (path, FileTest.EXISTS) && FileUtils.test (library_path, FileTest.EXISTS);
+ }
+
+ private static string get_plugin_path (string pluginpath, string pluginsubdir) {
+ if (Path.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 = Path.build_filename (Environment.get_current_dir(), pluginpath);
+ if (is_doclet(local_path)) {
+ return local_path;
+ } else {
+ return Path.build_filename (Config.plugin_dir, pluginsubdir, pluginpath);
+ }
+ }
+
+ return pluginpath;
+ }
+
+ public static string get_doclet_path (string? docletpath, ErrorReporter reporter) {
+ if (docletpath == null) {
+ return Path.build_filename (Config.plugin_dir, "doclets", "html");
+ }
+
+ return get_plugin_path (docletpath, "doclets");
+ }
+
+ public static string? get_driver_path (string? _driverpath, ErrorReporter reporter) {
+ string? driverpath = _driverpath;
+ // no driver selected
+ if (driverpath == null) {
+ driverpath = Config.default_driver;
+ }
+
+
+ // selected string is a plugin directory
+ string extended_driver_path = get_plugin_path (driverpath, "drivers");
+ if (is_driver (extended_driver_path)) {
+ return extended_driver_path;
+ }
+
+
+ // selected string is a `valac --version` number:
+ if (driverpath.has_prefix ("Vala ")) {
+ if (driverpath.has_suffix ("-dirty")) {
+ driverpath = driverpath.substring (5, driverpath.length - 6 - 5);
+ } else {
+ driverpath = driverpath.substring (5);
+ }
+ }
+
+ string[] segments = driverpath.split (".");
+ if (segments.length != 2 && // e.g. 0.20, --pkg-version
+ segments.length != 3 && // e.g. 0.20.3, --version
+ segments.length != 4) // e.g. Vala 0.18.0.60-a4cdb, --version
+ {
+ reporter.simple_error (null, "Invalid driver version format.");
+ return null;
+ }
+
+
+ int64 segment_a;
+ int64 segment_b;
+ int64 segment_c = 0;
+ bool tmp;
+
+ tmp = int64.try_parse (segments[0], out segment_a);
+ tmp &= int64.try_parse (segments[1], out segment_b);
+
+ if (segments.length > 2) {
+ tmp &= int64.try_parse (segments[2], out segment_c);
+ }
+
+ if (!tmp) {
+ reporter.simple_error (null, "Invalid driver version format.");
+ return null;
+ }
+
+ DriverMetaData[] lut = {
+ DriverMetaData (0, 19, 0, 20, "0.20.x"),
+ DriverMetaData (0, 21, 0, 22, "0.22.x"),
+ DriverMetaData (0, 23, 0, 24, "0.24.x"),
+ DriverMetaData (0, 25, 0, 26, "0.26.x"),
+ DriverMetaData (0, 27, 0, 28, "0.28.x"),
+ DriverMetaData (0, 29, 0, 30, "0.30.x"),
+ DriverMetaData (0, 31, 0, 32, "0.32.x"),
+ DriverMetaData (0, 33, 0, 34, "0.34.x"),
+ DriverMetaData (0, 35, 0, 36, "0.36.x")
+ };
+
+
+ for (int i = 0; i < lut.length ; i++) {
+ bool frst_seg = lut[i].segments_min[0] <= segment_a && lut[i].segments_max[0] >= segment_a;
+ bool scnd_seg = lut[i].segments_min[1] <= segment_b && lut[i].segments_max[1] >= segment_b;
+ if (frst_seg && scnd_seg) {
+ return Path.build_filename (Config.plugin_dir, "drivers", lut[i].driver_name);
+ }
+ }
+
+
+ reporter.simple_error (null, "No suitable driver found for libvala version " +
+ "%" + int64.FORMAT_MODIFIER + "d.%" + int64.FORMAT_MODIFIER + "d.%" + int64.FORMAT_MODIFIER + "d. " +
+ "Ensure the selected vala version was installed while building valadoc or use --driver to select another one.",
+ segment_a, segment_b, segment_c);
+ return null;
+ }
+
+ //
+ // Creation methods:
+ //
+
+ public Content.Taglet? create_taglet (string keyword) {
+ return (taglets.has_key (keyword))? (Content.Taglet) GLib.Object.new (taglets.get (keyword)) : null;
+ }
+
+ public void register_taglet (string keyword, Type type) {
+ taglets.set (keyword, type);
+ }
+
+ public Doclet? create_doclet (string _path) {
+ string path = realpath (_path);
+
+ ModuleData? data = doclets.get (path);
+ if (data == null) {
+ void* function;
+
+ Module? module = Module.open (Module.build_path (path, "libdoclet"), ModuleFlags.BIND_LAZY | ModuleFlags.BIND_LOCAL);
+ if (module == null) {
+ return null;
+ }
+
+ module.symbol("register_plugin", out function);
+ if (function == null) {
+ return null;
+ }
+
+ Valadoc.DocletRegisterFunction register_func = (Valadoc.DocletRegisterFunction) function;
+ data = new ModuleData ();
+ doclets.set (path, data);
+
+ data.type = register_func (this);
+ data.module = (owned) module;
+ }
+
+ return (Doclet) GLib.Object.new (data.type);
+ }
+
+ public Driver? create_driver (string _path) {
+ string path = realpath (_path);
+
+ ModuleData? data = drivers.get (path);
+ if (data == null) {
+ void* function;
+
+ Module? module = Module.open (Module.build_path (path, "libdriver"), ModuleFlags.BIND_LAZY | ModuleFlags.BIND_LOCAL);
+ if (module == null) {
+ return null;
+ }
+
+ module.symbol("register_plugin", out function);
+ if (function == null) {
+ return null;
+ }
+
+ Valadoc.DriverRegisterFunction register_func = (Valadoc.DriverRegisterFunction) function;
+ data = new ModuleData ();
+ drivers.set (path, data);
+
+ data.type = register_func (this);
+ data.module = (owned) module;
+ }
+
+ return (Driver) GLib.Object.new (data.type);
+ }
+}
+
diff --git a/libvaladoc/parser/manyrule.vala b/libvaladoc/parser/manyrule.vala
new file mode 100644
index 000000000..093223ac9
--- /dev/null
+++ b/libvaladoc/parser/manyrule.vala
@@ -0,0 +1,112 @@
+/* manyrule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+internal class Valadoc.ManyRule : Rule {
+
+ public ManyRule (Object scheme) {
+ _scheme = scheme;
+ }
+
+ private Object _scheme;
+
+ private class State : Object {
+ public bool started = false;
+ public bool done_one = false;
+ }
+
+ public override bool is_optional () {
+ return is_optional_rule (_scheme);
+ }
+
+ public override bool starts_with_token (Token token) {
+ if (has_start_token (_scheme, token)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override bool accept_token (Token token, ParserCallback parser, Rule.Forward forward)
+ throws ParserError
+ {
+ var state = parser.get_rule_state () as State;
+ if (state == null) {
+ state = new State ();
+ parser.set_rule_state (state);
+ }
+
+ if (!state.started) {
+ do_start (parser);
+ state.started = true;
+ }
+
+ if (state.done_one && parser.would_parent_accept_token (token)) {
+ do_reduce (parser);
+ return false;
+ }
+ if (parser.would_parent_reduce_to_rule (token, this)) {
+ do_reduce (parser);
+ return false;
+ }
+
+ bool handled;
+ if (try_to_apply (_scheme, token, parser, out handled)) {
+ state.done_one = true;
+ return handled;
+ }
+ if (parser.would_parent_accept_token (token)) {
+ do_reduce (parser);
+ return false;
+ }
+
+ if (_scheme is TokenType) {
+ parser.error (null, "expected %s".printf (((TokenType) _scheme).to_pretty_string ()));
+ } else {
+ parser.error (token, "unexpected token");
+ }
+ assert_not_reached ();
+ }
+
+ public override bool would_accept_token (Token token, Object? state) {
+ if (has_start_token (_scheme, token)) {
+ return true;
+ }
+ return false;
+ }
+
+ public override bool would_reduce (Token token, Object? rule_state) {
+ var state = rule_state as State;
+ return state.done_one || is_optional_rule (_scheme);
+ }
+
+ public override string to_string (Object? rule_state) {
+ var state = rule_state as State;
+ if (state == null) {
+ state = new State ();
+ }
+ return "%-15s%-15s(started=%s;done_one=%s)".printf (name != null ? name : " ",
+ "[many]",
+ state.started.to_string (),
+ state.done_one.to_string ());
+ }
+}
diff --git a/libvaladoc/parser/oneofrule.vala b/libvaladoc/parser/oneofrule.vala
new file mode 100644
index 000000000..946335233
--- /dev/null
+++ b/libvaladoc/parser/oneofrule.vala
@@ -0,0 +1,98 @@
+/* oneofrule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+internal class Valadoc.OneOfRule : Rule {
+
+ public OneOfRule (Object[] scheme) {
+ _scheme = scheme;
+ }
+
+ private Object[] _scheme;
+
+ private class State : Object {
+ public int selected = -1;
+ }
+
+ public override bool is_optional () {
+ return false;
+ }
+
+ public override bool starts_with_token (Token token) {
+ foreach (Object? scheme_element in _scheme) {
+ if (has_start_token (scheme_element, token)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public override bool accept_token (Token token, ParserCallback parser, Rule.Forward forward)
+ throws ParserError
+ {
+ var state = parser.get_rule_state () as State;
+ if (state == null) {
+ state = new State ();
+ parser.set_rule_state (state);
+ }
+
+ if (state.selected == -1) {
+ do_start (parser);
+
+ bool handled;
+ for (int i = 0; i < _scheme.length; i++) {
+ Object? scheme_element = _scheme[i];
+ if (try_to_apply (scheme_element, token, parser, out handled)) {
+ state.selected = i;
+ return handled;
+ }
+ }
+ } else {
+ do_reduce (parser);
+ return false;
+ }
+
+ parser.error (token, "unexpected token");
+ assert_not_reached ();
+ }
+
+ public override bool would_accept_token (Token token, Object? state) {
+ return false;
+ }
+
+ public override bool would_reduce (Token token, Object? rule_state) {
+ var state = rule_state as State;
+ return state.selected != -1;
+ }
+
+ public override string to_string (Object? rule_state) {
+ var state = rule_state as State;
+ if (state == null) {
+ state = new State ();
+ }
+ return "%-15s%-15s(selected=%d/%d)".printf (name != null ? name : " ",
+ "[one-of]",
+ state.selected,
+ _scheme.length);
+ }
+}
diff --git a/libvaladoc/parser/optionalrule.vala b/libvaladoc/parser/optionalrule.vala
new file mode 100644
index 000000000..6945afa38
--- /dev/null
+++ b/libvaladoc/parser/optionalrule.vala
@@ -0,0 +1,88 @@
+/* optionalrule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+internal class Valadoc.OptionalRule : Rule {
+
+ public OptionalRule (Object scheme) {
+ _scheme = scheme;
+ }
+
+ private Object _scheme;
+
+ private class State : Object {
+ public bool started = false;
+ }
+
+ public override bool is_optional () {
+ return true;
+ }
+
+ public override bool starts_with_token (Token token) {
+ return has_start_token (_scheme, token);
+ }
+
+ public override bool accept_token (Token token, ParserCallback parser, Rule.Forward forward)
+ throws ParserError
+ {
+ var state = parser.get_rule_state () as State;
+ if (state == null) {
+ state = new State ();
+ parser.set_rule_state (state);
+ }
+
+ if (!state.started) {
+ do_start (parser);
+ state.started = true;
+
+ bool handled;
+ if (try_to_apply (_scheme, token, parser, out handled)) {
+ return handled;
+ } else {
+ do_skip (parser);
+ return false;
+ }
+ } else {
+ do_reduce (parser);
+ return false;
+ }
+ }
+
+ public override bool would_accept_token (Token token, Object? state) {
+ return false;
+ }
+
+ public override bool would_reduce (Token token, Object? state) {
+ return true;
+ }
+
+ public override string to_string (Object? rule_state) {
+ var state = rule_state as State;
+ if (state == null) {
+ state = new State ();
+ }
+ return "%-15s%-15s(started=%s)".printf (name != null ? name : " ",
+ "[option]",
+ state.started.to_string ());
+ }
+}
diff --git a/libvaladoc/parser/parser.vala b/libvaladoc/parser/parser.vala
new file mode 100644
index 000000000..bf3a59889
--- /dev/null
+++ b/libvaladoc/parser/parser.vala
@@ -0,0 +1,306 @@
+/* parser.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public errordomain Valadoc.ParserError {
+ INTERNAL_ERROR,
+ UNEXPECTED_TOKEN
+}
+
+public class Valadoc.Parser : ParserCallback {
+
+ public Parser (Settings settings, Scanner scanner, ErrorReporter reporter) {
+ _settings = settings;
+ _scanner = scanner;
+ _reporter = reporter;
+
+ TokenType.init_token_types ();
+ }
+
+ private Settings _settings;
+ private Scanner _scanner;
+ private ErrorReporter _reporter;
+ private Rule _root_rule;
+
+ private string _filename;
+ private int _first_line;
+ private int _first_column;
+ private Token _current_token;
+
+ private ArrayList<Rule> rule_stack = new ArrayList<Rule> ();
+ private ArrayList<Object?> rule_state_stack = new ArrayList<Object?> ();
+
+ public void set_root_rule (Rule root_rule) {
+ _root_rule = root_rule;
+ }
+
+ public void parse (string content, string filename, int first_line, int first_column)
+ throws ParserError
+ {
+ _filename = filename;
+ _first_line = first_line;
+ _first_column = first_column;
+
+ rule_stack.clear ();
+ rule_state_stack.clear ();
+
+ try {
+ push_rule (_root_rule);
+ _scanner.reset ();
+ _scanner.scan (content);
+ _scanner.end ();
+
+ if (rule_stack.size != 0) {
+ error (null, "Rule stack is not empty!");
+ }
+ } catch (ParserError e) {
+ #if DEBUG
+ log_error (e.message);
+ #endif
+ // Set an in_error boolean, try to recover
+ // And only throw the error at the end of parse ?
+ throw e;
+ }
+ }
+
+ public void accept_token (Token token) throws ParserError {
+ #if HARD_DEBUG
+ debug ("Incomming token: %s", token.to_pretty_string ());
+ #endif
+
+ _current_token = token;
+ int rule_depth = rule_stack.size;
+ Rule.Forward forward = Rule.Forward.NONE;
+ Rule? rule = peek_rule ();
+ if (rule == null) {
+ throw new ParserError.INTERNAL_ERROR ("Rule stack is empty!");
+ }
+ while (rule != null) {
+ if (rule.accept_token (token, this, forward)) {
+ break;
+ }
+
+ // Check for invalid recursion
+ if (rule_depth != rule_stack.size && peek_rule () == rule) {
+ error (null, "Parser state error");
+ break;
+ }
+ rule = peek_rule ();
+
+ // Rule stack size have changed
+ // Check for propagation
+ forward = rule_depth > rule_stack.size ? Rule.Forward.CHILD
+ : Rule.Forward.PARENT;
+ rule_depth = rule_stack.size;
+ }
+ }
+
+ private Rule? peek_rule (int offset = -1) {
+ assert (offset < 0);
+ if (rule_stack.size + offset < 0) {
+ return null;
+ }
+ return rule_stack.get (rule_stack.size + offset);
+ }
+
+ private Rule pop_rule () {
+ int last_index = rule_stack.size - 1;
+ Rule rule = rule_stack.get (last_index);
+ rule_stack.remove_at (last_index);
+ rule_state_stack.remove_at (last_index);
+ return rule;
+ }
+
+ public void push_rule (Rule rule) {
+ rule_stack.add (rule);
+ rule_state_stack.add (null);
+
+ #if HARD_DEBUG
+ debug ("Pushed at %2d: %s", rule_stack.size - 1, rule.to_string (null));
+ #endif
+ }
+
+ private Object? peek_state (int offset = -1) {
+ assert (offset < 0);
+ if (rule_state_stack.size + offset < 0) {
+ return null;
+ }
+ return rule_state_stack.get (rule_state_stack.size + offset);
+ }
+
+ public Object? get_rule_state () {
+ return peek_state ();
+ }
+
+ public void set_rule_state (Object state) {
+ int last_index = rule_stack.size - 1;
+ rule_state_stack.set (last_index, state);
+ }
+
+ public void reduce () {
+ pop_rule ();
+
+ #if HARD_DEBUG
+ Rule? parent_rule = peek_rule ();
+ if (parent_rule != null) {
+ debug ("Reduced to %2d: %s", rule_stack.size - 1,
+ parent_rule.to_string (peek_state ()));
+ }
+ #endif
+ }
+
+ public bool would_parent_accept_token (Token token) {
+ int offset = -2;
+ Rule? parent_rule = peek_rule (offset);
+ Object? state = peek_state (offset);
+ while (parent_rule != null) {
+ #if VERY_HARD_DEBUG
+ debug ("WouldAccept - Offset %d; Index %d: %s", offset,
+ rule_stack.size + offset, parent_rule.to_string (state));
+ #endif
+ if (parent_rule.would_accept_token (token, state)) {
+ #if VERY_HARD_DEBUG
+ debug ("WouldAccept - Yes");
+ #endif
+ return true;
+ }
+ if (!parent_rule.would_reduce (token, state)) {
+ #if VERY_HARD_DEBUG
+ debug ("WouldAccept - No");
+ #endif
+ return false;
+ }
+ offset--;
+ parent_rule = peek_rule (offset);
+ state = peek_state (offset);
+ }
+ #if VERY_HARD_DEBUG
+ debug ("WouldAccept - No");
+ #endif
+ return false;
+ }
+
+ public bool would_parent_reduce_to_rule (Token token, Rule rule) {
+ int offset = -2;
+ Rule? parent_rule = peek_rule (offset);
+ Object? state = peek_state (offset);
+ while (parent_rule != null) {
+ #if VERY_HARD_DEBUG
+ debug ("WouldReduce - Offset %d; Index %d: %s", offset,
+ rule_stack.size + offset, parent_rule.to_string (state));
+ #endif
+ if (!parent_rule.would_reduce (token, state)) {
+ break;
+ }
+ offset--;
+ parent_rule = peek_rule (offset);
+ state = peek_state (offset);
+ }
+ if ((parent_rule != null && parent_rule.would_accept_token (token, state))
+ || (parent_rule == null && TokenType.EOF.matches (token))) {
+ #if VERY_HARD_DEBUG
+ debug ("WouldReduce - Yes");
+ #endif
+ return true;
+ }
+ #if VERY_HARD_DEBUG
+ debug ("WouldReduce - No");
+ #endif
+ return false;
+ }
+
+ public void warning (Token? token, string message) {
+ string error_message;
+
+ if (token != null) {
+ error_message = message + ": " + token.to_pretty_string ();
+ } else {
+ error_message = message;
+ }
+
+ _reporter.warning (_filename,
+ get_line (token),
+ get_start_column (token),
+ get_end_column (token),
+ _scanner.get_line_content (),
+ error_message);
+ }
+
+ public void error (Token? token, string message) throws ParserError {
+ string error_message;
+
+ if (token != null) {
+ error_message = message + ": " + token.to_pretty_string ();
+ } else {
+ error_message = message;
+ }
+
+ _reporter.error (_filename,
+ get_line (token),
+ get_start_column (token),
+ get_end_column (token),
+ _scanner.get_line_content (),
+ error_message);
+
+ throw new ParserError.UNEXPECTED_TOKEN (error_message);
+ }
+
+ private int get_line (Token? token) {
+ if (token == null) {
+ token = _current_token;
+ }
+ return token.begin.line + _first_line;
+ }
+
+ private int get_start_column (Token? token) {
+ if (token == null) {
+ token = _current_token;
+ }
+ if (token.begin.line == 0) {
+ return token.begin.column + _first_column + 1;
+ } else {
+ return token.begin.column + 1;
+ }
+ }
+
+ private int get_end_column (Token? token) {
+ if (token == null) {
+ token = _current_token;
+ }
+ if (token.end.line == 0) {
+ return token.end.column + _first_column + 1;
+ } else {
+ return token.end.column + 1;
+ }
+ }
+
+#if DEBUG
+ private void log_error (string message) {
+ stderr.printf ("An error occured while parsing: %s\n", message);
+ stderr.printf ("\nDumping rule stack:\n");
+ for (int i = 0; i < rule_stack.size; i++) {
+ stderr.printf ("\t%2d: %s\n", i, rule_stack[i].to_string (rule_state_stack[i]));
+ }
+ }
+#endif
+}
diff --git a/libvaladoc/parser/parsercallback.vala b/libvaladoc/parser/parsercallback.vala
new file mode 100644
index 000000000..c6fef181f
--- /dev/null
+++ b/libvaladoc/parser/parsercallback.vala
@@ -0,0 +1,37 @@
+/* parsercallback.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public interface Valadoc.ParserCallback {
+ public abstract Object? get_rule_state ();
+ public abstract void set_rule_state (Object state);
+
+ public abstract void push_rule (Rule rule);
+ public abstract void reduce ();
+
+ public abstract bool would_parent_accept_token (Token token);
+ public abstract bool would_parent_reduce_to_rule (Token token, Rule rule);
+
+ public abstract void warning (Token? token, string message);
+ public abstract void error (Token? token, string message) throws ParserError;
+}
diff --git a/libvaladoc/parser/rule.vala b/libvaladoc/parser/rule.vala
new file mode 100644
index 000000000..7ecbc3563
--- /dev/null
+++ b/libvaladoc/parser/rule.vala
@@ -0,0 +1,173 @@
+/* rule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public abstract class Valadoc.Rule : Object {
+
+ public static Rule seq (Object[] scheme) {
+ return new SequenceRule (scheme);
+ }
+
+ public static Rule one_of (Object[] scheme) {
+ return new OneOfRule (scheme);
+ }
+
+ public static Rule many (Object[] scheme) {
+ if (scheme.length == 1) {
+ return new ManyRule (scheme[0]);
+ } else {
+ return new ManyRule (new SequenceRule (scheme));
+ }
+ }
+
+ public static Rule option (Object[] scheme) {
+ if (scheme.length == 1) {
+ return new OptionalRule (scheme[0]);
+ } else {
+ return new OptionalRule (new SequenceRule (scheme));
+ }
+ }
+
+ protected Rule () {
+ }
+
+ private string? _name = null;
+ private Action _start_action;
+ private Action _reduce_action;
+ private Action _skip_action;
+
+ public string name { get { return _name; } }
+
+ public Rule set_name (string name) {
+ _name = name;
+ return this;
+ }
+
+ public delegate void Action () throws ParserError;
+
+ public Rule set_start (Action action) {
+ //TODO: Ownership Transfer
+ _start_action = () => { action (); };
+ return this;
+ }
+
+ public Rule set_reduce (Action action) {
+ //TODO: Ownership Transfer
+ _reduce_action = () => { action (); };
+ return this;
+ }
+
+ public Rule set_skip (Action action) {
+ //TODO: Ownership Transfer
+ _skip_action = () => { action (); };
+ return this;
+ }
+
+ public enum Forward {
+ NONE,
+ PARENT,
+ CHILD
+ }
+
+ public abstract bool is_optional ();
+ public abstract bool starts_with_token (Token token);
+ public abstract bool accept_token (Token token, ParserCallback parser, Rule.Forward forward) throws ParserError;
+ public abstract bool would_accept_token (Token token, Object? state);
+ public abstract bool would_reduce (Token token, Object? state);
+
+ public abstract string to_string (Object? state);
+
+ protected bool is_optional_rule (Object? scheme_element) {
+ Rule? scheme_rule = scheme_element as Rule;
+ if (scheme_rule != null) {
+ return scheme_rule.is_optional ();
+ }
+ return false;
+ }
+
+ protected bool has_start_token (Object? scheme_element, Token token) {
+ TokenType? scheme_token_type = scheme_element as TokenType;
+ if (scheme_token_type != null) {
+ return scheme_token_type.matches (token);
+ }
+ Rule? scheme_rule = scheme_element as Rule;
+ if (scheme_rule != null) {
+ return scheme_rule.starts_with_token (token);
+ }
+ return false;
+ }
+
+ protected bool try_to_apply (Object? scheme_element, Token token, ParserCallback parser,
+ out bool handled) throws ParserError
+ {
+ #if VERY_HARD_DEBUG
+ {
+ TokenType? scheme_token = scheme_element as TokenType;
+ Rule? scheme_rule = scheme_element as Rule;
+ if (scheme_token != null) {
+ message ("TryToApply: token='%s'; scheme_token='%s'", token.to_string (),
+ scheme_token.to_string ());
+ } else if (scheme_rule != null) {
+ message ("TryToApply: token='%s'; scheme_rule='%s'", token.to_string (),
+ scheme_rule.to_string (parser.get_rule_state ()));
+ } else {
+ assert (scheme_element != null);
+ }
+ }
+ #endif
+ TokenType? scheme_token_type = scheme_element as TokenType;
+ if (scheme_token_type != null && scheme_token_type.matches (token)) {
+ scheme_token_type.do_action (token);
+ handled = true;
+ return true;
+ }
+ Rule? scheme_rule = scheme_element as Rule;
+ if (scheme_rule != null && scheme_rule.starts_with_token (token)) {
+ parser.push_rule (scheme_rule);
+ handled = false;
+ return true;
+ }
+
+ handled = false;
+ return false;
+ }
+
+ protected void do_start (ParserCallback parser) throws ParserError {
+ if (_start_action != null) {
+ _start_action ();
+ }
+ }
+
+ protected void do_reduce (ParserCallback parser) throws ParserError {
+ if (_reduce_action != null) {
+ _reduce_action ();
+ }
+ parser.reduce ();
+ }
+
+ protected void do_skip (ParserCallback parser) throws ParserError {
+ if (_skip_action != null) {
+ _skip_action ();
+ }
+ }
+}
diff --git a/libvaladoc/parser/scanner.vala b/libvaladoc/parser/scanner.vala
new file mode 100644
index 000000000..86acd23af
--- /dev/null
+++ b/libvaladoc/parser/scanner.vala
@@ -0,0 +1,36 @@
+/* scanner.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+public interface Valadoc.Scanner : Object {
+
+ public abstract void set_parser (Parser parser);
+
+ public abstract void reset ();
+
+ public abstract void scan (string content) throws ParserError;
+
+ public abstract void end () throws ParserError;
+
+ public abstract void stop ();
+
+ public abstract string get_line_content ();
+}
diff --git a/libvaladoc/parser/sequencerule.vala b/libvaladoc/parser/sequencerule.vala
new file mode 100644
index 000000000..f14cf070d
--- /dev/null
+++ b/libvaladoc/parser/sequencerule.vala
@@ -0,0 +1,132 @@
+/* sequencerule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+internal class Valadoc.SequenceRule : Rule {
+
+ public SequenceRule (Object[] scheme) {
+ _scheme = scheme;
+ }
+
+ private Object[] _scheme;
+
+ private class State : Object {
+ public int index = 0;
+ }
+
+ public override bool is_optional () {
+ return false;
+ }
+
+ public override bool starts_with_token (Token token) {
+ return test_token (0, token);
+ }
+
+ private bool test_token (int from_index, Token token) {
+ int i = from_index;
+ while (i < _scheme.length) {
+ if (has_start_token (_scheme[i], token)) {
+ return true;
+ }
+ if (!is_optional_rule (_scheme[i])) {
+ break;
+ }
+ i++;
+ }
+ return false;
+ }
+
+ private bool test_reduce (int from_index, Token token) {
+ int i = from_index;
+ while (i < _scheme.length) {
+ if (!is_optional_rule (_scheme[i])) {
+ return false;
+ }
+ i++;
+ }
+ return true;
+ }
+
+ public override bool accept_token (Token token, ParserCallback parser,
+ Rule.Forward forward) throws ParserError
+ {
+ var state = parser.get_rule_state () as State;
+ if (state == null) {
+ state = new State ();
+ parser.set_rule_state (state);
+ }
+
+ if (state.index == 0) {
+ do_start (parser);
+ } else if (state.index == _scheme.length) {
+ do_reduce (parser);
+ return false;
+ }
+
+ Object? scheme_element = null;
+ bool handled;
+ do {
+ scheme_element = _scheme[state.index];
+ if (try_to_apply (scheme_element, token, parser, out handled)) {
+ state.index++;
+ return handled;
+ }
+ if (!is_optional_rule (scheme_element)) {
+ break;
+ } else {
+ ((Rule) scheme_element).do_skip (parser);
+ }
+ state.index++;
+ } while (state.index < _scheme.length);
+
+ if (state.index == _scheme.length) {
+ do_reduce (parser);
+ return false;
+ }
+
+ if (scheme_element is TokenType) {
+ parser.error (token, "expected %s".printf (((TokenType) scheme_element).to_pretty_string ()));
+ } else {
+ parser.error (token, "unexpected token");
+ }
+ assert_not_reached ();
+ }
+
+ public override bool would_accept_token (Token token, Object? rule_state) {
+ var state = rule_state as State;
+ return test_token (state.index, token);
+ }
+
+ public override bool would_reduce (Token token, Object? rule_state) {
+ var state = rule_state as State;
+ return state.index == _scheme.length || test_reduce (state.index, token);
+ }
+
+ public override string to_string (Object? rule_state) {
+ var state = rule_state as State;
+ if (state == null) {
+ state = new State ();
+ }
+ return "%-15s%-15s(index=%d/%d)".printf (name != null ? name : " ", "[seq]", state.index, _scheme.length);
+ }
+}
diff --git a/libvaladoc/parser/sourcelocation.vala b/libvaladoc/parser/sourcelocation.vala
new file mode 100644
index 000000000..51b5bc1f9
--- /dev/null
+++ b/libvaladoc/parser/sourcelocation.vala
@@ -0,0 +1,35 @@
+/* sourcelocation.vala
+ *
+ * Copyright (C) 2008 Jürg Billeter
+ *
+ * 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>
+ */
+
+
+/**
+ * Represents a position in a source file.
+ */
+public struct Valadoc.SourceLocation {
+ public int line;
+ public int column;
+
+ public SourceLocation (int _line, int _column) {
+ line = _line;
+ column = _column;
+ }
+}
diff --git a/libvaladoc/parser/stubrule.vala b/libvaladoc/parser/stubrule.vala
new file mode 100644
index 000000000..0f6f97930
--- /dev/null
+++ b/libvaladoc/parser/stubrule.vala
@@ -0,0 +1,62 @@
+/* stubrule.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public class Valadoc.StubRule : Rule {
+
+ public StubRule () {
+ }
+
+ private Rule _rule;
+
+ public Rule set_rule (Rule rule) {
+ _rule = rule;
+ return this;
+ }
+
+ public override bool is_optional () {
+ return _rule.is_optional ();
+ }
+
+ public override bool starts_with_token (Token token) {
+ return _rule.starts_with_token (token);
+ }
+
+ public override bool accept_token (Token token, ParserCallback parser, Rule.Forward forward)
+ throws ParserError
+ {
+ return _rule.accept_token (token, parser, forward);
+ }
+
+ public override bool would_accept_token (Token token, Object? state) {
+ return _rule.would_accept_token (token, state);
+ }
+
+ public override bool would_reduce (Token token, Object? state) {
+ return _rule.would_reduce (token, state);
+ }
+
+ public override string to_string (Object? state) {
+ return _rule.to_string (state);
+ }
+}
diff --git a/libvaladoc/parser/token.vala b/libvaladoc/parser/token.vala
new file mode 100644
index 000000000..6cbff5ed1
--- /dev/null
+++ b/libvaladoc/parser/token.vala
@@ -0,0 +1,110 @@
+/* token.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public class Valadoc.Token : Object {
+
+ public Token.from_type (TokenType type, SourceLocation begin, SourceLocation end, string? val = null) {
+ _type = type;
+ _begin = begin;
+ _end = end;
+ _value = val;
+ }
+
+ public Token.from_word (string word, SourceLocation begin, SourceLocation end) {
+ _word = word;
+ _begin = begin;
+ _end = end;
+ }
+
+ private TokenType? _type = null;
+ private string? _word = null;
+ private SourceLocation _begin;
+ private SourceLocation _end;
+ private string? _value;
+
+ public bool is_word {
+ get {
+ return _word != null;
+ }
+ }
+
+ public bool is_number {
+ get {
+ if (_word == null || _word.length == 0) {
+ return false;
+ } else if (_word[0] == '0' && _word.length > 1) {
+ return false;
+ }
+ for (int i = 0; i < _word.length; i++) {
+ if (_word[i] < '0' || _word[i] > '9') {
+ return false;
+ }
+ }
+ return true;
+ }
+ }
+
+ public string? word {
+ get {
+ return _word;
+ }
+ }
+
+ public string? value {
+ get {
+ return _value;
+ }
+ }
+
+ public TokenType? token_type {
+ get {
+ return _type;
+ }
+ }
+
+ public SourceLocation begin {
+ get {
+ return _begin;
+ }
+ }
+
+ public SourceLocation end {
+ get {
+ return _end;
+ }
+ }
+
+ public string to_string () {
+ return _word == null ? _type.to_string () : _word;
+ }
+
+ public string to_pretty_string () {
+ return _word == null ? _type.to_pretty_string () : _word;
+ }
+
+ public int to_int () {
+ assert (is_number);
+ return int.parse (_word);
+ }
+}
diff --git a/libvaladoc/parser/tokentype.vala b/libvaladoc/parser/tokentype.vala
new file mode 100644
index 000000000..3cad35ea7
--- /dev/null
+++ b/libvaladoc/parser/tokentype.vala
@@ -0,0 +1,271 @@
+/* tokentype.vala
+ *
+ * Copyright (C) 2008-2009 Florian Brosch, Didier Villevalois
+ *
+ * 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+
+public class Valadoc.TokenType : Object {
+ // valadoc-comments:
+ public static TokenType ANY;
+ public static TokenType ANY_WORD;
+ public static TokenType ANY_NUMBER;
+ public static TokenType EOF;
+ public static TokenType EOL;
+ public static TokenType BREAK;
+ public static TokenType AROBASE;
+ public static TokenType SPACE;
+ public static TokenType TAB;
+ public static TokenType EQUAL_1;
+ public static TokenType EQUAL_2;
+ public static TokenType EQUAL_3;
+ public static TokenType EQUAL_4;
+ public static TokenType EQUAL_5;
+ public static TokenType MINUS;
+ public static TokenType LESS_THAN;
+ public static TokenType GREATER_THAN;
+ public static TokenType ALIGN_TOP;
+ public static TokenType ALIGN_BOTTOM;
+ public static TokenType SINGLE_QUOTE_2;
+ public static TokenType SLASH_2;
+ public static TokenType UNDERSCORE_2;
+ public static TokenType BACK_QUOTE_2;
+ public static TokenType OPEN_BRACE;
+ public static TokenType CLOSED_BRACE;
+ public static TokenType DOUBLE_OPEN_BRACE;
+ public static TokenType DOUBLE_CLOSED_BRACE;
+ public static TokenType TRIPLE_OPEN_BRACE;
+ public static TokenType TRIPLE_CLOSED_BRACE;
+ public static TokenType DOUBLE_OPEN_BRACKET;
+ public static TokenType DOUBLE_CLOSED_BRACKET;
+ public static TokenType PIPE;
+ public static TokenType DOUBLE_PIPE;
+ public static TokenType ALIGN_RIGHT;
+ public static TokenType ALIGN_CENTER;
+
+
+ // .valadoc (importer)
+ public static TokenType VALADOC_COMMENT_START;
+ public static TokenType VALADOC_COMMENT_END;
+ public static TokenType VALADOC_ANY_WORD;
+ public static TokenType VALADOC_SPACE;
+ public static TokenType VALADOC_TAB;
+ public static TokenType VALADOC_EOL;
+
+
+ // markdown:
+ public static TokenType MARKDOWN_PARAGRAPH;
+ public static TokenType MARKDOWN_ANY_WORD;
+ public static TokenType MARKDOWN_SPACE;
+ public static TokenType MARKDOWN_SOURCE;
+ public static TokenType MARKDOWN_PARAMETER;
+ public static TokenType MARKDOWN_CONSTANT;
+ public static TokenType MARKDOWN_SYMBOL;
+ public static TokenType MARKDOWN_LOCAL_GMEMBER;
+ public static TokenType MARKDOWN_FUNCTION;
+ public static TokenType MARKDOWN_MAIL;
+ public static TokenType MARKDOWN_LINK;
+ public static TokenType MARKDOWN_GREATER_THAN;
+ public static TokenType MARKDOWN_LESS_THAN;
+ public static TokenType MARKDOWN_OPEN_BRACKET;
+ public static TokenType MARKDOWN_CLOSE_BRACKET;
+ public static TokenType MARKDOWN_OPEN_PARENS;
+ public static TokenType MARKDOWN_CLOSE_PARENS;
+ public static TokenType MARKDOWN_EXCLAMATION_MARK;
+ public static TokenType MARKDOWN_HEADLINE_1;
+ public static TokenType MARKDOWN_HEADLINE_2;
+ public static TokenType MARKDOWN_HEADLINE_HASH;
+ public static TokenType MARKDOWN_HEADLINE_END;
+ public static TokenType MARKDOWN_UNORDERED_LIST_ITEM_START;
+ public static TokenType MARKDOWN_UNORDERED_LIST_ITEM_END;
+ public static TokenType MARKDOWN_ORDERED_LIST_ITEM_START;
+ public static TokenType MARKDOWN_ORDERED_LIST_ITEM_END;
+ public static TokenType MARKDOWN_BLOCK_START;
+ public static TokenType MARKDOWN_BLOCK_END;
+ public static TokenType MARKDOWN_EOC;
+
+
+ private static bool initialized = false;
+
+ internal static void init_token_types () {
+ if (!initialized) {
+ // valadoc-comments:
+ ANY = new TokenType.basic ("<any>");
+ ANY_WORD = new TokenType.basic ("<any-word>");
+ ANY_NUMBER = new TokenType.basic ("<any-number>");
+ EOF = new TokenType.basic ("\0", "<end-of-file>");
+ EOL = new TokenType.basic ("\n", "<end-of-line>");
+ BREAK = new TokenType.basic ("<<BR>>");
+ AROBASE = new TokenType.basic ("@");
+ SPACE = new TokenType.basic (" ", "<space>");
+ TAB = new TokenType.basic ("\t", "<tab>");
+ EQUAL_1 = new TokenType.basic ("=");
+ EQUAL_2 = new TokenType.basic ("==");
+ EQUAL_3 = new TokenType.basic ("====");
+ EQUAL_4 = new TokenType.basic ("=====");
+ EQUAL_5 = new TokenType.basic ("======");
+ MINUS = new TokenType.basic ("-");
+ LESS_THAN = new TokenType.basic ("<");
+ GREATER_THAN = new TokenType.basic (">");
+ ALIGN_TOP = new TokenType.basic ("^");
+ ALIGN_BOTTOM = new TokenType.basic ("v");
+ SINGLE_QUOTE_2 = new TokenType.basic ("''");
+ SLASH_2 = new TokenType.basic ("//");
+ UNDERSCORE_2 = new TokenType.basic ("__");
+ BACK_QUOTE_2 = new TokenType.basic ("``");
+ OPEN_BRACE = new TokenType.basic ("{");
+ CLOSED_BRACE = new TokenType.basic ("}");
+ DOUBLE_OPEN_BRACE = new TokenType.basic ("{{");
+ DOUBLE_CLOSED_BRACE = new TokenType.basic ("}}");
+ TRIPLE_OPEN_BRACE = new TokenType.basic ("{{{");
+ TRIPLE_CLOSED_BRACE = new TokenType.basic ("}}}");
+ DOUBLE_OPEN_BRACKET = new TokenType.basic ("[[");
+ DOUBLE_CLOSED_BRACKET = new TokenType.basic ("]]");
+ PIPE = new TokenType.basic ("|");
+ DOUBLE_PIPE = new TokenType.basic ("||");
+ ALIGN_RIGHT = new TokenType.basic ("))");
+ ALIGN_CENTER = new TokenType.basic (")(");
+
+ // .valadoc (importer)
+ VALADOC_COMMENT_START = new TokenType.basic ("/*");
+ VALADOC_COMMENT_END = new TokenType.basic ("*/");
+ VALADOC_ANY_WORD = ANY_WORD;
+ VALADOC_SPACE = SPACE;
+ VALADOC_TAB = TAB;
+ VALADOC_EOL = EOL;
+
+ initialized = true;
+
+
+ // Markdown: (importer)
+ MARKDOWN_PARAGRAPH = new TokenType.basic ("<paragraph>");
+ MARKDOWN_BLOCK_START = new TokenType.basic ("<block>");
+ MARKDOWN_BLOCK_END = new TokenType.basic ("</block>");
+ MARKDOWN_UNORDERED_LIST_ITEM_START = new TokenType.basic ("<unordered-list>");
+ MARKDOWN_UNORDERED_LIST_ITEM_END = new TokenType.basic ("</unordered-list>");
+ MARKDOWN_ORDERED_LIST_ITEM_START = new TokenType.basic ("<ordered-list>");
+ MARKDOWN_ORDERED_LIST_ITEM_END = new TokenType.basic ("</ordered-list>");
+
+ MARKDOWN_HEADLINE_1 = new TokenType.basic ("<headline-1>");
+ MARKDOWN_HEADLINE_2 = new TokenType.basic ("<headline-2>");
+ MARKDOWN_HEADLINE_HASH = new TokenType.basic ("<hash>");
+ MARKDOWN_HEADLINE_END = new TokenType.basic ("</headline>");
+ MARKDOWN_SOURCE = new TokenType.basic ("<source>");
+ MARKDOWN_PARAMETER = new TokenType.basic ("<parameter>");
+ MARKDOWN_CONSTANT = new TokenType.basic ("<constant>");
+ MARKDOWN_FUNCTION = new TokenType.basic ("<function>");
+ MARKDOWN_SYMBOL = new TokenType.basic ("<symbol>");
+ MARKDOWN_LOCAL_GMEMBER = new TokenType.basic ("<local-gmember>");
+ MARKDOWN_MAIL = new TokenType.basic ("<mail>");
+ MARKDOWN_LINK = new TokenType.basic ("<link>");
+
+ MARKDOWN_OPEN_BRACKET = new TokenType.basic ("[");
+ MARKDOWN_CLOSE_BRACKET = new TokenType.basic ("]");
+ MARKDOWN_OPEN_PARENS = new TokenType.basic ("(");
+ MARKDOWN_CLOSE_PARENS = new TokenType.basic (")");
+ MARKDOWN_EXCLAMATION_MARK = new TokenType.basic ("!");
+ MARKDOWN_GREATER_THAN = GREATER_THAN;
+ MARKDOWN_LESS_THAN = LESS_THAN;
+
+ MARKDOWN_ANY_WORD = ANY_WORD;
+ MARKDOWN_SPACE = SPACE;
+ MARKDOWN_EOC = EOL;
+ }
+ }
+
+ private static int EXACT_WORD = -1;
+
+ public static TokenType str (string str) {
+ return new TokenType (str, EXACT_WORD, null);
+ }
+
+ public static TokenType any () {
+ return ANY;
+ }
+
+ public static TokenType any_word () {
+ return ANY_WORD;
+ }
+
+ public static TokenType any_number () {
+ return ANY_NUMBER;
+ }
+
+ private TokenType (string string_value, int basic_value, Action? __action) {
+ _string_value = string_value;
+ _basic_value = basic_value;
+ if (__action != null) {
+ _action = (token) => { __action (token); };
+ } else {
+ _action = null;
+ }
+ }
+
+ private TokenType.basic (string string_value, string? pretty_string = null) {
+ _string_value = string_value;
+ _pretty_string = pretty_string;
+ _basic_value = ++_last_basic_value;
+ }
+
+ private static int _last_basic_value = -1;
+
+ private string _string_value;
+ private string? _pretty_string;
+ private int _basic_value = -1;
+ private Action? _action = null;
+
+ public delegate void Action (Token token) throws ParserError;
+
+ public TokenType action (Action action) {
+ return new TokenType (_string_value, _basic_value, action);
+ }
+
+ public void do_action (Token matched_token) throws ParserError {
+ if (_action != null) {
+ _action (matched_token);
+ }
+ }
+
+ public bool matches (Token token) {
+ if (_basic_value == ANY._basic_value) {
+ return true;
+ } else if (_basic_value == ANY_WORD._basic_value && token.is_word) {
+ return true;
+ } else if (_basic_value == ANY_NUMBER._basic_value && token.is_number) {
+ return true;
+ } else if (_basic_value == EXACT_WORD && token.is_word && token.word == _string_value) {
+ return true;
+ } else if (token.token_type != null && token.token_type._basic_value == _basic_value) {
+ return true;
+ }
+ return false;
+ }
+
+ public string to_string () {
+ return _string_value;
+ }
+
+ public string to_pretty_string () {
+ if (_pretty_string != null) {
+ return _pretty_string;
+ }
+ return _string_value;
+ }
+}
diff --git a/libvaladoc/settings.vala b/libvaladoc/settings.vala
new file mode 100644
index 000000000..823dd5b20
--- /dev/null
+++ b/libvaladoc/settings.vala
@@ -0,0 +1,169 @@
+/* settings.vala
+ *
+ * Copyright (C) 2008-2009 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:
+ * Brosch Florian <flo.brosch@gmail.com>
+ */
+
+
+/**
+ * Contains information about output settings configuration
+ */
+public class Valadoc.Settings : Object {
+ /**
+ * Output directory/file name.
+ */
+ public string path = "documentation/";
+
+ /**
+ * Package name
+ */
+ public string pkg_name = null;
+
+ /**
+ * Package version
+ */
+ public string pkg_version;
+
+ /**
+ * Wiki directory
+ */
+ public string wiki_directory;
+
+ /**
+ * Plugin-specific command line arguments
+ */
+ public string[] pluginargs;
+
+
+ /**
+ * Add private elements to documentation
+ */
+ public bool _private = false;
+
+ /**
+ * Add protected elements to documentation
+ */
+ public bool _protected = false;
+
+ /**
+ * Add internal elements to documentation
+ */
+ public bool _internal = false;
+
+ /**
+ * Add dependencies to the documentation
+ */
+ public bool with_deps = false;
+
+ public bool add_inherited = false;
+
+ /**
+ * Show all warnings
+ */
+ public bool verbose = false;
+
+
+
+ /**
+ * Do not warn when using experimental features.
+ */
+ public bool experimental;
+
+ /**
+ * Enable experimental enhancements for non-null types.
+ */
+ public bool experimental_non_null;
+
+ /**
+ * Use the given profile (dova, gobject, posix, ...) instead of the defaul
+ */
+ public string? profile;
+
+ /**
+ * Base source directory.
+ */
+ public string? basedir;
+
+ /**
+ * Output directory/file name.
+ */
+ public string? directory;
+
+
+ /**
+ * A list of defined symbols.
+ */
+ public string[] defines;
+
+ /**
+ * List of directories where to find .vapi files.
+ */
+ public string[] vapi_directories;
+
+ /**
+ * A list of all packages
+ */
+ public string[] packages;
+
+ /**
+ * A list of all source files.
+ */
+ public string[] source_files;
+
+ /**
+ * GObject-Introspection directory
+ */
+ public string? gir_directory;
+
+ /**
+ * GObject-Introspection repository file name
+ */
+ public string? gir_name;
+
+ /**
+ * A list of all metadata directories
+ */
+ public string[] metadata_directories;
+
+ /**
+ * Alternative paths for resources
+ */
+ public string[] alternative_resource_dirs;
+
+ /**
+ * A list of all gir directories.
+ */
+ public string[] gir_directories;
+
+ /**
+ * GLib version to target.
+ */
+ public string target_glib;
+
+ public string gir_namespace;
+
+ public string gir_version;
+
+ /**
+ * Use SVG as chart images
+ */
+ public bool use_svg_images = false;
+}
+
+
diff --git a/libvaladoc/taglets/tagletdeprecated.vala b/libvaladoc/taglets/tagletdeprecated.vala
new file mode 100644
index 000000000..c77457935
--- /dev/null
+++ b/libvaladoc/taglets/tagletdeprecated.vala
@@ -0,0 +1,61 @@
+/* tagletdeprecated.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.Deprecated : BlockContent, Taglet, Block {
+ public Rule? get_parser_rule (Rule run_rule) {
+ return run_rule;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ base.check (api_root, container, file_path, reporter, settings);
+ reporter.simple_warning ("%s: %s: @deprecated".printf (file_path, container.get_full_name ()),
+ "@deprecated is deprecated. Use [Version (deprecated = true)]");
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Deprecated deprecated = new Deprecated ();
+ deprecated.parent = new_parent;
+
+ foreach (Block element in content) {
+ Block copy = element.copy (deprecated) as Block;
+ deprecated.content.add (copy);
+ }
+
+ return deprecated;
+ }
+}
+
diff --git a/libvaladoc/taglets/tagletinheritdoc.vala b/libvaladoc/taglets/tagletinheritdoc.vala
new file mode 100644
index 000000000..d8b288545
--- /dev/null
+++ b/libvaladoc/taglets/tagletinheritdoc.vala
@@ -0,0 +1,232 @@
+/* tagletinheritdoc.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+public class Valadoc.Taglets.InheritDoc : InlineTaglet {
+ private Taglet? parent_taglet = null;
+
+ public Api.Node? inherited {
+ private set;
+ get;
+ }
+
+
+ public override Rule? get_parser_rule (Rule run_rule) {
+ return null;
+ }
+
+ private Taglet? find_parent_taglet () {
+ if (_inherited == null || _inherited.documentation == null) {
+ return null;
+ }
+
+ ContentElement pos;
+ for (pos = this.parent; pos != null && pos is Taglet == false; pos = pos.parent);
+ if (pos is Taglet) {
+ return (Taglet) pos;
+ }
+
+ return null;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // TODO Check that the container is an override of an abstract symbol
+ // Also retrieve that abstract symbol _inherited
+
+ if (container is Api.Method) {
+ _inherited = ((Api.Method) container).base_method;
+ } else if (container is Api.Property) {
+ _inherited = ((Api.Property) container).base_property;
+ } else if (container is Api.Class && ((Api.Class) container).base_type != null) {
+ _inherited = (Api.Node) ((Api.Class) container).base_type.data_type;
+ } else if (container is Api.Struct && ((Api.Struct) container).base_type != null) {
+ _inherited = (Api.Node) ((Api.Struct) container).base_type.data_type;
+ }
+
+ parent_taglet = find_parent_taglet ();
+ if (parent_taglet == null && _inherited != null) {
+ api_root.register_inheritdoc (container, this);
+ }
+
+
+ // TODO report error if inherited is null
+
+ // TODO postpone check after complete parse of the api tree comments
+ // And reenable that check
+ //base.check (api_root, container, reporter);
+ }
+
+ private Run[]? split_run (Inline? separator) {
+ if (separator == null) {
+ return null;
+ }
+
+ ContentElement parent = separator.parent;
+ Gee.List<Inline> parent_content = null;
+
+ if (parent is Run && ((Run) parent).style == Run.Style.NONE) {
+ parent_content = ((Run) parent).content;
+ } else if (parent is Paragraph) {
+ parent_content = ((Paragraph) parent).content;
+ }
+
+ if (parent_content != null) {
+ Run right_run = new Run (Run.Style.NONE);
+ Run left_run = new Run (Run.Style.NONE);
+ bool separated = false;
+
+ foreach (var current in parent_content) {
+ if (current == separator) {
+ separated = true;
+ } else if (separated) {
+ right_run.content.add (current);
+ current.parent = right_run;
+ } else {
+ left_run.content.add (current);
+ current.parent = left_run;
+ }
+ }
+
+ return { left_run, right_run };
+ }
+
+ return null;
+ }
+
+ internal void transform (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ ContentElement separator = this;
+ Run right_run = null;
+ Run left_run = null;
+ Run[]? parts;
+
+ while ((parts = split_run (separator as Inline)) != null) {
+ if (left_run != null) {
+ parts[0].content.add (left_run);
+ left_run.parent = parts[0];
+ }
+
+ if (right_run != null) {
+ parts[1].content.insert (0, right_run);
+ right_run.parent = parts[1];
+ }
+
+ separator = separator.parent;
+ right_run = parts[1];
+ left_run = parts[0];
+ }
+
+ if (separator is Paragraph == false || separator.parent is Comment == false) {
+ reporter.simple_error ("%s: %s: @inheritDoc".printf (file_path, container.get_full_name ()),
+ "Parent documentation can't be copied to this location.");
+ return ;
+ }
+
+ Comment comment = separator.parent as Comment;
+ assert (comment != null);
+
+ int insert_pos = comment.content.index_of ((Paragraph) separator);
+ int start_pos = insert_pos;
+ assert (insert_pos >= 0);
+
+ foreach (Block block in _inherited.documentation.content) {
+ comment.content.insert (insert_pos, (Block) block.copy (comment));
+ insert_pos++;
+ }
+
+ if (right_run != null) {
+ if (comment.content[insert_pos - 1] is Paragraph) {
+ ((Paragraph) comment.content[insert_pos - 1]).content.add (right_run);
+ right_run.parent = comment.content[insert_pos - 1];
+ } else {
+ Paragraph p = new Paragraph ();
+ p.content.add (right_run);
+ right_run.parent = p;
+ p.parent = comment;
+ comment.content.insert (insert_pos, p);
+ }
+ }
+
+ if (left_run != null) {
+ if (comment.content[start_pos] is Paragraph) {
+ ((Paragraph) comment.content[start_pos]).content.insert (0, left_run);
+ left_run.parent = comment.content[start_pos];
+ } else {
+ Paragraph p = new Paragraph ();
+ p.content.add (left_run);
+ left_run.parent = p;
+ p.parent = comment;
+ comment.content.insert (start_pos, p);
+ }
+ }
+
+ comment.content.remove ((Paragraph) separator);
+ }
+
+ private Run content_copy (Gee.List<ContentElement>? content) {
+ Run run = new Run (Run.Style.NONE);
+ run.parent = this;
+
+ if (content != null) {
+ foreach (ContentElement item in content) {
+ run.content.add (item.copy (this) as Inline);
+ }
+ }
+
+ return run;
+ }
+
+ public override ContentElement produce_content () {
+ if (_inherited != null && _inherited.documentation != null && parent_taglet != null) {
+ Gee.List<Taglet> parent_taglets = _inherited.documentation.find_taglets (null, parent_taglet.get_type ());
+ foreach (Taglet parent in parent_taglets) {
+ // we only care about the first match:
+ if (parent.inheritable (parent_taglet)) {
+ return content_copy (parent.get_inheritable_documentation ());
+ }
+ }
+ }
+ return new Text ("");
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ InheritDoc doc = new InheritDoc ();
+ doc.parent = new_parent;
+
+ doc.settings = settings;
+ doc.locator = locator;
+
+ doc._inherited = _inherited;
+
+ return doc;
+ }
+}
diff --git a/libvaladoc/taglets/tagletinit.vala b/libvaladoc/taglets/tagletinit.vala
new file mode 100644
index 000000000..7e88126aa
--- /dev/null
+++ b/libvaladoc/taglets/tagletinit.vala
@@ -0,0 +1,35 @@
+/* tagletinit.vala
+ *
+ * Copyright (C) 2008-2009 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>
+ */
+
+
+namespace Valadoc.Taglets {
+ public void init (ModuleLoader loader) {
+ loader.register_taglet ("see", typeof (Valadoc.Taglets.See));
+ loader.register_taglet ("since", typeof (Valadoc.Taglets.Since));
+ loader.register_taglet ("link", typeof (Valadoc.Taglets.Link));
+ loader.register_taglet ("throws", typeof (Valadoc.Taglets.Throws));
+ loader.register_taglet ("return", typeof (Valadoc.Taglets.Return));
+ loader.register_taglet ("param", typeof (Valadoc.Taglets.Param));
+ loader.register_taglet ("deprecated", typeof (Valadoc.Taglets.Deprecated));
+ loader.register_taglet ("inheritDoc", typeof (Valadoc.Taglets.InheritDoc));
+ }
+}
diff --git a/libvaladoc/taglets/tagletlink.vala b/libvaladoc/taglets/tagletlink.vala
new file mode 100644
index 000000000..b489a5898
--- /dev/null
+++ b/libvaladoc/taglets/tagletlink.vala
@@ -0,0 +1,186 @@
+/* taglet.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2014 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.Link : InlineTaglet {
+ public string symbol_name { internal set; get; }
+
+ /**
+ * Accept leading 's', e.g. #Widgets
+ */
+ public bool c_accept_plural { internal set; get; }
+
+ /**
+ * True if symbol_name could only be resolved after removing 's'
+ *
+ * E.g. true or #Widgets, false for #Widget
+ */
+ public bool c_is_plural { private set; get; }
+
+
+ private enum SymbolContext {
+ NORMAL,
+ FINISH,
+ TYPE
+ }
+
+ private SymbolContext _context = SymbolContext.NORMAL;
+ private Api.Node _symbol;
+
+ public override Rule? get_parser_rule (Rule run_rule) {
+ return Rule.seq ({
+ Rule.option ({ Rule.many ({ TokenType.SPACE }) }),
+ TokenType.any_word ().action ((token) => { symbol_name = token.to_string (); }),
+ Rule.option ({
+ Rule.many ({
+ Rule.one_of ({
+ TokenType.any_word ().action ((token) => { symbol_name += token.to_string (); }),
+ TokenType.MINUS.action ((token => { symbol_name += token.to_string (); }))
+ })
+ })
+ })
+ });
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings) {
+
+ if (symbol_name.has_prefix ("c::")) {
+ _symbol_name = _symbol_name.substring (3);
+ string? singular_symbol_name = (c_accept_plural && _symbol_name.has_suffix ("s"))
+ ? symbol_name.substring (0, _symbol_name.length - 1)
+ : null;
+
+ _symbol = api_root.search_symbol_cstr (container, symbol_name);
+ if (_symbol == null && singular_symbol_name != null) {
+ _symbol = api_root.search_symbol_cstr (container, singular_symbol_name);
+ c_is_plural = true;
+ }
+ _context = SymbolContext.NORMAL;
+
+ if (_symbol == null && _symbol_name.has_suffix ("_finish")) {
+ string tmp = _symbol_name.substring (0, _symbol_name.length - 7);
+
+ _symbol = api_root.search_symbol_cstr (container, tmp + "_async") as Api.Method;
+ if (_symbol != null && ((Api.Method) _symbol).is_yields) {
+ _context = SymbolContext.FINISH;
+ } else {
+ _symbol = api_root.search_symbol_cstr (container, tmp) as Api.Method;
+ if (_symbol != null && ((Api.Method) _symbol).is_yields) {
+ _context = SymbolContext.FINISH;
+ } else {
+ _symbol = null;
+ }
+ }
+ }
+
+ if (_symbol == null) {
+ _symbol = api_root.search_symbol_type_cstr (symbol_name);
+ if (_symbol == null && singular_symbol_name != null) {
+ _symbol = api_root.search_symbol_type_cstr (singular_symbol_name);
+ c_is_plural = true;
+ }
+ if (_symbol != null) {
+ _context = SymbolContext.TYPE;
+ }
+ }
+
+ if (_symbol != null) {
+ symbol_name = _symbol.name;
+ }
+ } else {
+ _symbol = api_root.search_symbol_str (container, symbol_name);
+ }
+
+ if (_symbol == null && symbol_name != "main") {
+ string node_segment = (container is Api.Package)? "" : container.get_full_name () + ": ";
+ reporter.simple_warning ("%s: %s@link".printf (file_path, node_segment),
+ "`%s' does not exist", symbol_name);
+ }
+
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override ContentElement produce_content () {
+ var link = new Content.SymbolLink ();
+ link.symbol = _symbol;
+ link.given_symbol_name = symbol_name;
+
+ Content.Inline content;
+ switch (_context) {
+ case SymbolContext.FINISH:
+ link.given_symbol_name += ".end";
+ content = link;
+ break;
+
+ case SymbolContext.TYPE:
+ Run run = new Content.Run (Run.Style.MONOSPACED);
+ content = run;
+
+ Content.Run keyword = new Content.Run (Run.Style.LANG_KEYWORD);
+ keyword.content.add (new Content.Text ("typeof"));
+ run.content.add (keyword);
+
+ run.content.add (new Content.Text (" ("));
+ run.content.add (link);
+ run.content.add (new Content.Text (")"));
+ break;
+
+ default:
+ content = link;
+ break;
+ }
+
+ if (c_is_plural == true) {
+ Run run = new Content.Run (Run.Style.NONE);
+ run.content.add (content);
+ run.content.add (new Content.Text ("s"));
+ return run;
+ }
+
+ return content;
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Link link = new Link ();
+ link.parent = new_parent;
+
+ link.settings = settings;
+ link.locator = locator;
+
+ link.symbol_name = symbol_name;
+ link.c_accept_plural = c_accept_plural;
+ link.c_is_plural = c_is_plural;
+ link._context = _context;
+ link._symbol = _symbol;
+
+ return link;
+ }
+}
diff --git a/libvaladoc/taglets/tagletparam.vala b/libvaladoc/taglets/tagletparam.vala
new file mode 100644
index 000000000..651a9ed3f
--- /dev/null
+++ b/libvaladoc/taglets/tagletparam.vala
@@ -0,0 +1,166 @@
+/* taglet.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Valadoc.Content;
+using Gee;
+
+
+public class Valadoc.Taglets.Param : BlockContent, Taglet, Block {
+ public string parameter_name { internal set; get; }
+
+ public weak Api.Symbol? parameter { private set; get; }
+
+ public int position { private set; get; default = -1; }
+
+ public bool is_c_self_param { internal set; get; }
+
+ public bool is_this { private set; get; }
+
+
+ public Rule? get_parser_rule (Rule run_rule) {
+ return Rule.seq ({
+ Rule.option ({ Rule.many ({ TokenType.SPACE }) }),
+ TokenType.any_word ().action ((token) => { parameter_name = token.to_string (); }),
+ run_rule
+ });
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // Check for the existence of such a parameter
+ unowned string? implicit_return_array_length = null;
+ bool has_instance = has_instance (container);
+ bool is_implicit = false;
+ this.parameter = null;
+
+ if (container is Api.Callable) {
+ implicit_return_array_length = ((Api.Callable) container).implicit_array_length_cparameter_name;
+ } else {
+ reporter.simple_warning ("%s: %s: @param".printf (file_path, container.get_full_name ()),
+ "@param used outside method/delegate/signal context");
+ base.check (api_root, container, file_path, reporter, settings);
+ return ;
+ }
+
+ if (is_c_self_param == true && has_instance) {
+ this.parameter_name = "this";
+ this.is_this = true;
+ this.position = 0;
+ } else if (parameter_name == "...") {
+ Gee.List<Api.Node> params = container.get_children_by_type (Api.NodeType.FORMAL_PARAMETER, false);
+ foreach (Api.Node param in params) {
+ if (((Api.FormalParameter) param).ellipsis) {
+ this.parameter = (Api.Symbol) param;
+ this.position = (has_instance)? params.size : params.size - 1;
+ break;
+ }
+ }
+ } else {
+ Gee.List<Api.Node> params = container.get_children_by_types ({Api.NodeType.FORMAL_PARAMETER,
+ Api.NodeType.TYPE_PARAMETER},
+ false);
+ int pos = (has_instance)? 1 : 0;
+
+ foreach (Api.Node param in params) {
+ if (param.name == parameter_name) {
+ this.parameter = (Api.Symbol) param;
+ this.position = pos;
+ break;
+ }
+
+ Api.FormalParameter formalparam = param as Api.FormalParameter;
+ if (formalparam != null && (formalparam.implicit_array_length_cparameter_name == parameter_name
+ || formalparam.implicit_closure_cparameter_name == parameter_name
+ || formalparam.implicit_destroy_cparameter_name == parameter_name))
+ {
+ is_implicit = true;
+ break;
+ }
+
+ pos++;
+ }
+
+ if (this.parameter == null
+ && (parameter_name == "error"
+ && container.has_children ({Api.NodeType.ERROR_DOMAIN, Api.NodeType.CLASS})
+ || parameter_name == implicit_return_array_length))
+ {
+ is_implicit = true;
+ }
+ }
+
+ if (this.parameter == null) {
+ if (is_implicit) {
+ reporter.simple_note ("%s: %s: @param".printf (file_path, container.get_full_name ()),
+ "Implicit parameter `%s' exposed in documentation", parameter_name);
+ } else if (!is_c_self_param) {
+ reporter.simple_warning ("%s: %s: @param".printf (file_path, container.get_full_name ()),
+ "Unknown parameter `%s'", parameter_name);
+ }
+ }
+
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ private bool has_instance (Api.Item element) {
+ if (element is Api.Method) {
+ return !((Api.Method) element).is_static;
+ }
+
+ return false;
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public Gee.List<ContentElement>? get_inheritable_documentation () {
+ return content;
+ }
+
+ public bool inheritable (Taglet taglet) {
+ if (taglet is Taglets.Param == false) {
+ return false;
+ }
+
+ Taglets.Param t = (Taglets.Param) taglet;
+ return (parameter == t.parameter || parameter_name == t.parameter_name);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Param param = new Param ();
+ param.parent = new_parent;
+
+ param.parameter_name = parameter_name;
+ param.parameter = parameter;
+ param.position = position;
+
+ foreach (Block element in content) {
+ Block copy = element.copy (param) as Block;
+ param.content.add (copy);
+ }
+
+ return param;
+ }
+}
diff --git a/libvaladoc/taglets/tagletreturn.vala b/libvaladoc/taglets/tagletreturn.vala
new file mode 100644
index 000000000..ef3e4ecf4
--- /dev/null
+++ b/libvaladoc/taglets/tagletreturn.vala
@@ -0,0 +1,79 @@
+/* taglet.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.Return : BlockContent, Taglet, Block {
+ public Rule? get_parser_rule (Rule run_rule) {
+ return run_rule;
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings) {
+ Api.TypeReference? type_ref = null;
+ bool creation_method = false;
+
+ if (container is Api.Method) {
+ creation_method = ((Api.Method) container).is_constructor;
+ type_ref = ((Api.Method) container).return_type;
+ } else if (container is Api.Callable) {
+ type_ref = ((Api.Callable) container).return_type;
+ } else {
+ reporter.simple_warning ("%s: %s: @return".printf (file_path, container.get_full_name ()),
+ "@return used outside method/delegate/signal context");
+ }
+
+ if (type_ref != null && type_ref.data_type == null && !creation_method) {
+ reporter.simple_warning ("%s: %s: @return".printf (file_path, container.get_full_name ()),
+ "Return description declared for void function");
+ }
+
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public Gee.List<ContentElement>? get_inheritable_documentation () {
+ return content;
+ }
+
+ public bool inheritable (Taglet taglet) {
+ return taglet is Taglets.Return;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Return ret = new Return ();
+ ret.parent = new_parent;
+
+ foreach (Block element in content) {
+ Block copy = element.copy (ret) as Block;
+ ret.content.add (copy);
+ }
+
+ return ret;
+ }
+}
diff --git a/libvaladoc/taglets/tagletsee.vala b/libvaladoc/taglets/tagletsee.vala
new file mode 100644
index 000000000..1e096fda7
--- /dev/null
+++ b/libvaladoc/taglets/tagletsee.vala
@@ -0,0 +1,77 @@
+/* tagletsee.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.See : ContentElement, Taglet, Block {
+ public string symbol_name { private set; get; }
+ public Api.Node symbol { private set; get; }
+
+ public Rule? get_parser_rule (Rule run_rule) {
+ Rule optional_spaces = Rule.option ({ Rule.many ({ TokenType.SPACE }) });
+
+ return Rule.seq ({
+ optional_spaces,
+ TokenType.any_word ().action ((token) => { symbol_name = token.to_string (); }),
+ optional_spaces
+ });
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings) {
+ if (symbol_name.has_prefix ("c::")) {
+ symbol_name = symbol_name.substring (3);
+ symbol = api_root.search_symbol_cstr (container, 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_warning ("%s: %s: @see".printf (file_path, container.get_full_name ()),
+ "`%s' does not exist", symbol_name);
+ }
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ See see = new See ();
+ see.parent = new_parent;
+
+ see.symbol_name = symbol_name;
+ see.symbol = symbol;
+
+ return see;
+ }}
diff --git a/libvaladoc/taglets/tagletsince.vala b/libvaladoc/taglets/tagletsince.vala
new file mode 100644
index 000000000..fccc063ef
--- /dev/null
+++ b/libvaladoc/taglets/tagletsince.vala
@@ -0,0 +1,63 @@
+/* tagletsince.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.Since : ContentElement, Taglet, Block {
+ public string version { get; internal set; }
+
+ public Rule? get_parser_rule (Rule run_rule) {
+ Rule optional_spaces = Rule.option ({ Rule.many ({ TokenType.SPACE }) });
+
+ return Rule.seq ({
+ optional_spaces,
+ TokenType.any_word ().action ((token) => { version = token.to_string (); }),
+ optional_spaces
+ });
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public override bool is_empty () {
+ return false;
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Since since = new Since ();
+ since.parent = new_parent;
+
+ since.version = version;
+
+ return since;
+ }
+}
+
diff --git a/libvaladoc/taglets/tagletthrows.vala b/libvaladoc/taglets/tagletthrows.vala
new file mode 100644
index 000000000..6d3631c7f
--- /dev/null
+++ b/libvaladoc/taglets/tagletthrows.vala
@@ -0,0 +1,125 @@
+/* tagletthrows.vala
+ *
+ * Copyright (C) 2008-2009 Didier Villevalois
+ * Copyright (C) 2008-2012 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:
+ * Didier 'Ptitjes Villevalois <ptitjes@free.fr>
+ */
+
+using Gee;
+using Valadoc.Content;
+
+
+public class Valadoc.Taglets.Throws : BlockContent, Taglet, Block {
+ // TODO: rename
+ public string error_domain_name { private set; get; }
+
+ /**
+ * Thrown Error domain or Error code
+ */
+ // TODO: rename
+ public Api.Node error_domain { private set; get; }
+
+ public Rule? get_parser_rule (Rule run_rule) {
+ return Rule.seq ({
+ Rule.option ({ Rule.many ({ TokenType.SPACE }) }),
+ TokenType.any_word ().action ((token) => { error_domain_name = token.to_string (); }),
+ run_rule
+ });
+ }
+
+ public override void check (Api.Tree api_root, Api.Node container, string file_path,
+ ErrorReporter reporter, Settings settings)
+ {
+ // context check:
+ if (container is Api.Method == false && container is Api.Delegate == false) {
+ reporter.simple_warning ("%s: %s: @throws".printf (file_path, container.get_full_name ()),
+ "@throws used outside method/delegate context");
+ base.check (api_root, container, file_path, reporter, settings);
+ return ;
+ }
+
+
+ // type check:
+ error_domain = api_root.search_symbol_str (container, error_domain_name);
+ if (error_domain == null) {
+ // TODO use ContentElement's source reference
+ reporter.simple_error ("%s: %s: @throws".printf (file_path, container.get_full_name ()),
+ "`%s' does not exist", error_domain_name);
+ base.check (api_root, container, file_path, reporter, settings);
+ return ;
+ }
+
+
+ // Check if the method is allowed to throw the given type or error code:
+ Gee.List<Api.Node> exceptions = container.get_children_by_types ({Api.NodeType.ERROR_DOMAIN,
+ Api.NodeType.CLASS},
+ false);
+ Api.Item expected_error_domain = (error_domain is Api.ErrorCode)
+ ? error_domain.parent
+ : error_domain;
+ bool report_warning = true;
+ foreach (Api.Node exception in exceptions) {
+ if (exception == expected_error_domain
+ || (exception is Api.Class && expected_error_domain is Api.ErrorDomain))
+ {
+ report_warning = false;
+ break;
+ }
+ }
+ if (report_warning) {
+ reporter.simple_warning ("%s: %s: @throws".printf (file_path, container.get_full_name ()),
+ "`%s' does not exist in exception list", error_domain_name);
+ }
+
+ base.check (api_root, container, file_path, reporter, settings);
+ }
+
+ public override void accept (ContentVisitor visitor) {
+ visitor.visit_taglet (this);
+ }
+
+ public Gee.List<ContentElement>? get_inheritable_documentation () {
+ return content;
+ }
+
+ public bool inheritable (Taglet taglet) {
+ if (taglet is Taglets.Throws == false) {
+ return false;
+ }
+
+ Taglets.Throws t = (Taglets.Throws) taglet;
+ return (error_domain == t.error_domain || error_domain_name == t.error_domain_name);
+ }
+
+ public override ContentElement copy (ContentElement? new_parent = null) {
+ Throws tr = new Throws ();
+ tr.parent = new_parent;
+
+ tr.error_domain_name = error_domain_name;
+ tr.error_domain = error_domain;
+
+ foreach (Block element in content) {
+ Block copy = element.copy (tr) as Block;
+ tr.content.add (copy);
+ }
+
+ return tr;
+ }
+}
+
diff --git a/libvaladoc/valadoc-1.0.deps.in b/libvaladoc/valadoc-1.0.deps.in
new file mode 100644
index 000000000..485c5a5ce
--- /dev/null
+++ b/libvaladoc/valadoc-1.0.deps.in
@@ -0,0 +1,3 @@
+libgvc
+gee-0.8
+gmodule-2.0
diff --git a/libvaladoc/valadoc-1.0.pc.in b/libvaladoc/valadoc-1.0.pc.in
new file mode 100644
index 000000000..8cf9ab02e
--- /dev/null
+++ b/libvaladoc/valadoc-1.0.pc.in
@@ -0,0 +1,14 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@/valadoc/
+includedir=@includedir@
+datarootdir=@datarootdir@
+datadir=@datadir@
+vapidir=@datadir@/vala/vapi
+
+Name: Valadoc
+Description: The Vala documentation compiler library
+Version: @VERSION@
+Requires: libgvc gee-0.8 gmodule-2.0
+Libs: -L${libdir} -lvaladoc
+Cflags: -I${includedir}/valadoc-1.0