[valadoc] gir-importer: add support for markdown
- From: Florian Brosch <flobrosch src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [valadoc] gir-importer: add support for markdown
- Date: Tue, 2 Sep 2014 17:16:10 +0000 (UTC)
commit 30c774c06fa73105ee30032a4f967dce95b55f1f
Author: Florian Brosch <flo brosch gmail com>
Date: Wed Aug 20 00:36:16 2014 +0200
gir-importer: add support for markdown
src/libvaladoc/Makefile.am | 3 +
src/libvaladoc/api/girsourcecomment.vala | 6 +-
src/libvaladoc/content/blockcontent.vala | 5 +-
.../documentation/documentationparser.vala | 51 ++-
src/libvaladoc/documentation/girmetadata.vala | 7 +
.../documentation/gtkdoccommentparser.vala | 149 +----
.../documentation/gtkdocmarkdownparser.vala | 816 ++++++++++++++++++++
.../documentation/gtkdocmarkdownscanner.vala | 761 ++++++++++++++++++
src/libvaladoc/documentation/importerhelper.vala | 156 ++++
.../importer/girdocumentationimporter.vala | 66 ++-
src/libvaladoc/parser/token.vala | 10 +-
src/libvaladoc/parser/tokentype.vala | 68 ++
src/libvaladoc/taglets/tagletdeprecated.vala | 7 +-
src/libvaladoc/taglets/tagletlink.vala | 62 ++-
src/libvaladoc/taglets/tagletparam.vala | 6 +-
src/libvaladoc/taglets/tagletreturn.vala | 6 +-
src/libvaladoc/taglets/tagletthrows.vala | 7 +-
17 files changed, 1996 insertions(+), 190 deletions(-)
---
diff --git a/src/libvaladoc/Makefile.am b/src/libvaladoc/Makefile.am
index 82caa07..84cebd8 100644
--- a/src/libvaladoc/Makefile.am
+++ b/src/libvaladoc/Makefile.am
@@ -52,6 +52,9 @@ libvaladoc_la_VALASOURCES = \
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 \
diff --git a/src/libvaladoc/api/girsourcecomment.vala b/src/libvaladoc/api/girsourcecomment.vala
index 77bfb5f..c935ba3 100644
--- a/src/libvaladoc/api/girsourcecomment.vala
+++ b/src/libvaladoc/api/girsourcecomment.vala
@@ -31,7 +31,11 @@ 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? 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 ();
diff --git a/src/libvaladoc/content/blockcontent.vala b/src/libvaladoc/content/blockcontent.vala
index 0411b61..47e99a2 100644
--- a/src/libvaladoc/content/blockcontent.vala
+++ b/src/libvaladoc/content/blockcontent.vala
@@ -28,10 +28,13 @@ public abstract class Valadoc.Content.BlockContent : ContentElement {
private Gee.List<Block> _content;
- internal BlockContent () {
+ construct {
_content = new ArrayList<Block> ();
}
+ internal BlockContent () {
+ }
+
public override void configure (Settings settings, ResourceLocator locator) {
}
diff --git a/src/libvaladoc/documentation/documentationparser.vala
b/src/libvaladoc/documentation/documentationparser.vala
index 9e0b3bb..a4a1201 100644
--- a/src/libvaladoc/documentation/documentationparser.vala
+++ b/src/libvaladoc/documentation/documentationparser.vala
@@ -27,6 +27,7 @@ using Gee;
public class Valadoc.DocumentationParser : Object, ResourceLocator {
+ private HashMap<Api.SourceFile, GirMetaData> metadata = new HashMap<Api.SourceFile, GirMetaData> ();
public DocumentationParser (Settings settings, ErrorReporter reporter,
Api.Tree tree, ModuleLoader modules)
@@ -47,11 +48,13 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
_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);
init_valadoc_rules ();
}
private Gtkdoc.Parser gtkdoc_parser;
+ private Gtkdoc.MarkdownParser gtkdoc_markdown_parser;
private Settings _settings;
private ErrorReporter _reporter;
@@ -69,8 +72,16 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
public Comment? parse (Api.Node element, Api.SourceComment comment) {
if (comment is Api.GirSourceComment) {
- Comment doc_comment = gtkdoc_parser.parse (element, (Api.GirSourceComment) comment);
- return doc_comment;
+ 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);
+ return doc_comment;
+ } else {
+ Comment doc_comment = gtkdoc_markdown_parser.parse (element, gir_comment,
metadata);
+ return doc_comment;
+ }
} else {
return parse_comment_str (element, comment.content, comment.file.get_name (),
comment.first_line,
comment.first_column);
@@ -125,6 +136,17 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
return (Page) pop ();
}
+ 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);
+ this.metadata.set (gir_comment.file, metadata);
+ return metadata;
+ }
+
public string resolve (string path) {
return path;
}
@@ -146,6 +168,7 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
return node;
}
+ private Rule multiline_block_run;
private Rule multiline_run;
private int current_level = 0;
private int[] levels = new int[0];
@@ -769,16 +792,36 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
})
.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) => {
- var taglet = _factory.create_taglet (token.to_string ());
+
+ 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 = taglet.get_parser_rule (multiline_run);
+
+ 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
}));
}
diff --git a/src/libvaladoc/documentation/girmetadata.vala b/src/libvaladoc/documentation/girmetadata.vala
index 53c1e9e..41e2be8 100644
--- a/src/libvaladoc/documentation/girmetadata.vala
+++ b/src/libvaladoc/documentation/girmetadata.vala
@@ -27,6 +27,9 @@ public class Valadoc.GirMetaData : Object {
private string? metadata_path = null;
private string? resource_dir = null;
+ public bool is_docbook { private set; get; default = false; }
+
+
/**
* Used to manipulate paths to resources inside gir-files
*/
@@ -82,6 +85,10 @@ public class Valadoc.GirMetaData : Object {
this.resource_dir = key_file.get_string ("General", "resources");
break;
+ case "is_docbook":
+ this.is_docbook = key_file.get_boolean ("General", "is_docbook");
+ break;
+
default:
reporter.simple_warning ("%s: warning: Unknown key 'General.%s'",
metadata_path, key);
break;
diff --git a/src/libvaladoc/documentation/gtkdoccommentparser.vala
b/src/libvaladoc/documentation/gtkdoccommentparser.vala
index 5e0ce5b..f102934 100644
--- a/src/libvaladoc/documentation/gtkdoccommentparser.vala
+++ b/src/libvaladoc/documentation/gtkdoccommentparser.vala
@@ -48,20 +48,8 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
private Regex? is_numeric_regex = null;
private Regex? normalize_regex = null;
- private HashMap<Api.SourceFile, GirMetaData> metadata = new HashMap<Api.SourceFile, GirMetaData> ();
private GirMetaData? current_metadata = null;
- 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);
- this.metadata.set (gir_comment.file, metadata);
- return metadata;
- }
-
private inline string fix_resource_path (string path) {
return this.current_metadata.get_resource_path (path);
}
@@ -88,131 +76,6 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
return is_numeric_regex.match (str);
}
- private inline Text? split_text (Text text) {
- 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) {
- 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);
- 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) {
- if (item is Text) {
- return split_text ((Text) item);
- } else if (item is Run) {
- return split_run ((Run) item);
- }
-
- return null;
- }
-
- private inline Paragraph? split_paragraph (Paragraph p) {
- 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);
- 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;
- }
-
- private void extract_short_desc (Comment comment) {
- 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);
- if (second_paragraph == null) {
- return ;
- }
-
- if (second_paragraph.is_empty () == false) {
- comment.content.insert (1, second_paragraph);
- }
- }
-
private void report_unexpected_token (Token got, string expected) {
if (!this.show_warnings) {
return ;
@@ -252,9 +115,9 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
private Api.Node? element;
- public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment) {
- this.current_metadata = get_metadata_for_comment (gir_comment);
+ public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment, GirMetaData gir_metadata) {
this.instance_param_name = gir_comment.instance_param_name;
+ this.current_metadata = gir_metadata;
this.element = element;
Comment? comment = this.parse_main_content (gir_comment);
@@ -321,9 +184,11 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
return null;
}
- InlineContent? taglet = factory.create_taglet (taglet_name) as InlineContent;
+ BlockContent? taglet = factory.create_taglet (taglet_name) as BlockContent;
assert (taglet != null);
- taglet.content.add (ic);
+ Paragraph paragraph = factory.create_paragraph ();
+ paragraph.content.add (ic);
+ taglet.content.add (paragraph);
return taglet as Taglet;
}
@@ -357,7 +222,7 @@ public class Valadoc.Gtkdoc.Parser : Object, ResourceLocator {
return null;
}
- extract_short_desc (comment);
+ ImporterHelper.extract_short_desc (comment, factory);
return comment;
}
diff --git a/src/libvaladoc/documentation/gtkdocmarkdownparser.vala
b/src/libvaladoc/documentation/gtkdocmarkdownparser.vala
new file mode 100644
index 0000000..841949d
--- /dev/null
+++ b/src/libvaladoc/documentation/gtkdocmarkdownparser.vala
@@ -0,0 +1,816 @@
+/* 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 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 {
+ _run = _factory.create_run (Run.Style.MONOSPACED);
+ _run.content.add (_factory.create_text (token.value));
+ }
+
+ 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 ();
+
+ 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.to_string ()));
+ }
+
+ source = source.offset (source.index_of_char ('>') + 1);
+ }
+
+ 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 (() => {
+ // TODO
+ })
+ }),
+ 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,
string? this_name = null) {
+ this.metadata = metadata;
+ this.gir_comment = gir_comment;
+ this.element = element;
+
+ bool has_instance = false;
+ if (element is Api.Method) {
+ has_instance = !((Api.Method) element).is_static;
+ }
+
+
+ // 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 ();
+
+ if (taglet != null && !(has_instance && param_name ==
gir_comment.instance_param_name)) {
+ taglet.parameter_name = param_name;
+ add_taglet (ref cmnt, taglet);
+ }
+ }
+
+
+ cmnt.check (_tree, element, gir_comment.file.relative_path, _reporter, _settings);
+
+ this.metadata = null;
+ this.gir_comment = null;
+ this.element = element;
+
+ 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/src/libvaladoc/documentation/gtkdocmarkdownscanner.vala
b/src/libvaladoc/documentation/gtkdocmarkdownscanner.vala
new file mode 100644
index 0000000..1908957
--- /dev/null
+++ b/src/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/src/libvaladoc/documentation/importerhelper.vala
b/src/libvaladoc/documentation/importerhelper.vala
new file mode 100644
index 0000000..36ed06d
--- /dev/null
+++ b/src/libvaladoc/documentation/importerhelper.vala
@@ -0,0 +1,156 @@
+/* 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 {
+
+
+ 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) {
+ 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/src/libvaladoc/importer/girdocumentationimporter.vala
b/src/libvaladoc/importer/girdocumentationimporter.vala
index 1988b96..45bbf09 100644
--- a/src/libvaladoc/importer/girdocumentationimporter.vala
+++ b/src/libvaladoc/importer/girdocumentationimporter.vala
@@ -317,31 +317,67 @@ public class Valadoc.Importer.GirDocumentationImporter : DocumentationImporter {
}
private Api.GirSourceComment? parse_symbol_doc () {
- if (reader.name != "doc") {
- return null;
+ 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");
}
- start_element ("doc");
- next ();
+ 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);
+ }
- Api.GirSourceComment? comment = null;
+ 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);
+ }
- if (current_token == MarkupTokenType.TEXT) {
- comment = new Api.GirSourceComment (reader.content, file, begin.line,
- begin.column,
end.line, end.column);
- next ();
+ 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;
+ }
}
- end_element ("doc");
return comment;
}
- private Api.SourceComment? parse_doc () {
- if (reader.name != "doc") {
+ private Api.SourceComment? parse_doc (string element_name = "doc") {
+ if (reader.name != element_name) {
return null;
}
- start_element ("doc");
+ start_element (element_name);
next ();
Api.SourceComment? comment = null;
@@ -352,7 +388,7 @@ public class Valadoc.Importer.GirDocumentationImporter : DocumentationImporter {
next ();
}
- end_element ("doc");
+ end_element (element_name);
return comment;
}
diff --git a/src/libvaladoc/parser/token.vala b/src/libvaladoc/parser/token.vala
index ced9ab3..6cbff5e 100644
--- a/src/libvaladoc/parser/token.vala
+++ b/src/libvaladoc/parser/token.vala
@@ -24,10 +24,11 @@ using Gee;
public class Valadoc.Token : Object {
- public Token.from_type (TokenType type, SourceLocation begin, SourceLocation end) {
+ 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) {
@@ -40,6 +41,7 @@ public class Valadoc.Token : Object {
private string? _word = null;
private SourceLocation _begin;
private SourceLocation _end;
+ private string? _value;
public bool is_word {
get {
@@ -69,6 +71,12 @@ public class Valadoc.Token : Object {
}
}
+ public string? value {
+ get {
+ return _value;
+ }
+ }
+
public TokenType? token_type {
get {
return _type;
diff --git a/src/libvaladoc/parser/tokentype.vala b/src/libvaladoc/parser/tokentype.vala
index ea61955..3cad35e 100644
--- a/src/libvaladoc/parser/tokentype.vala
+++ b/src/libvaladoc/parser/tokentype.vala
@@ -69,6 +69,39 @@ public class Valadoc.TokenType : Object {
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 () {
@@ -119,6 +152,41 @@ public class Valadoc.TokenType : Object {
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;
}
}
diff --git a/src/libvaladoc/taglets/tagletdeprecated.vala b/src/libvaladoc/taglets/tagletdeprecated.vala
index 16e71af..c10a3c6 100644
--- a/src/libvaladoc/taglets/tagletdeprecated.vala
+++ b/src/libvaladoc/taglets/tagletdeprecated.vala
@@ -24,7 +24,8 @@
using Gee;
using Valadoc.Content;
-public class Valadoc.Taglets.Deprecated : InlineContent, Taglet, Block {
+
+public class Valadoc.Taglets.Deprecated : BlockContent, Taglet, Block {
public Rule? get_parser_rule (Rule run_rule) {
return run_rule;
}
@@ -49,8 +50,8 @@ public class Valadoc.Taglets.Deprecated : InlineContent, Taglet, Block {
Deprecated deprecated = new Deprecated ();
deprecated.parent = new_parent;
- foreach (Inline element in content) {
- Inline copy = element.copy (deprecated) as Inline;
+ foreach (Block element in content) {
+ Block copy = element.copy (deprecated) as Block;
deprecated.content.add (copy);
}
diff --git a/src/libvaladoc/taglets/tagletlink.vala b/src/libvaladoc/taglets/tagletlink.vala
index 89ab8c3..72ed12a 100644
--- a/src/libvaladoc/taglets/tagletlink.vala
+++ b/src/libvaladoc/taglets/tagletlink.vala
@@ -28,6 +28,19 @@ 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,
@@ -54,9 +67,18 @@ public class Valadoc.Taglets.Link : InlineTaglet {
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")) {
@@ -77,6 +99,10 @@ public class Valadoc.Taglets.Link : InlineTaglet {
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;
}
@@ -84,10 +110,6 @@ public class Valadoc.Taglets.Link : InlineTaglet {
if (_symbol != null) {
symbol_name = _symbol.name;
-
- if (_context == SymbolContext.FINISH) {
- symbol_name = symbol_name + ".end";
- }
}
} else {
_symbol = api_root.search_symbol_str (container, symbol_name);
@@ -107,27 +129,39 @@ public class Valadoc.Taglets.Link : InlineTaglet {
link.symbol = _symbol;
link.label = symbol_name;
- // TODO: move typeof () to gtkdoc-importer
+ Content.Inline content;
switch (_context) {
case SymbolContext.FINISH:
- // covered by symbol_name
- return link;
+ link.label += ".end";
+ content = link;
+ break;
case SymbolContext.TYPE:
- Content.Run content = new Content.Run (Run.Style.MONOSPACED);
+ 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"));
- content.content.add (keyword);
+ run.content.add (keyword);
- content.content.add (new Content.Text (" ("));
- content.content.add (link);
- content.content.add (new Content.Text (")"));
- return content;
+ run.content.add (new Content.Text (" ("));
+ run.content.add (link);
+ run.content.add (new Content.Text (")"));
+ break;
default:
- return link;
+ 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 () {
diff --git a/src/libvaladoc/taglets/tagletparam.vala b/src/libvaladoc/taglets/tagletparam.vala
index b2a42be..94c602a 100644
--- a/src/libvaladoc/taglets/tagletparam.vala
+++ b/src/libvaladoc/taglets/tagletparam.vala
@@ -25,7 +25,7 @@ using Valadoc.Content;
using Gee;
-public class Valadoc.Taglets.Param : InlineContent, Taglet, Block {
+public class Valadoc.Taglets.Param : BlockContent, Taglet, Block {
public string parameter_name { internal set; get; }
public weak Api.Symbol? parameter { private set; get; }
@@ -141,8 +141,8 @@ public class Valadoc.Taglets.Param : InlineContent, Taglet, Block {
param.parameter = parameter;
param.position = position;
- foreach (Inline element in content) {
- Inline copy = element.copy (param) as Inline;
+ foreach (Block element in content) {
+ Block copy = element.copy (param) as Block;
param.content.add (copy);
}
diff --git a/src/libvaladoc/taglets/tagletreturn.vala b/src/libvaladoc/taglets/tagletreturn.vala
index 71b5836..50d3adb 100644
--- a/src/libvaladoc/taglets/tagletreturn.vala
+++ b/src/libvaladoc/taglets/tagletreturn.vala
@@ -25,7 +25,7 @@ using Gee;
using Valadoc.Content;
-public class Valadoc.Taglets.Return : InlineContent, Taglet, Block {
+public class Valadoc.Taglets.Return : BlockContent, Taglet, Block {
public Rule? get_parser_rule (Rule run_rule) {
return run_rule;
}
@@ -69,8 +69,8 @@ public class Valadoc.Taglets.Return : InlineContent, Taglet, Block {
Return ret = new Return ();
ret.parent = new_parent;
- foreach (Inline element in content) {
- Inline copy = element.copy (ret) as Inline;
+ foreach (Block element in content) {
+ Block copy = element.copy (ret) as Block;
ret.content.add (copy);
}
diff --git a/src/libvaladoc/taglets/tagletthrows.vala b/src/libvaladoc/taglets/tagletthrows.vala
index daacd73..cfbb098 100644
--- a/src/libvaladoc/taglets/tagletthrows.vala
+++ b/src/libvaladoc/taglets/tagletthrows.vala
@@ -24,7 +24,8 @@
using Gee;
using Valadoc.Content;
-public class Valadoc.Taglets.Throws : InlineContent, Taglet, Block {
+
+public class Valadoc.Taglets.Throws : BlockContent, Taglet, Block {
// TODO: rename
public string error_domain_name { private set; get; }
@@ -113,8 +114,8 @@ public class Valadoc.Taglets.Throws : InlineContent, Taglet, Block {
tr.error_domain_name = error_domain_name;
tr.error_domain = error_domain;
- foreach (Inline element in content) {
- Inline copy = element.copy (tr) as Inline;
+ foreach (Block element in content) {
+ Block copy = element.copy (tr) as Block;
tr.content.add (copy);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]