]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
libvaladoc: Add gi-docgen documentation support tintou/gidocgen
authorCorentin Noël <corentin.noel@collabora.com>
Thu, 8 Feb 2024 16:48:15 +0000 (17:48 +0100)
committerCorentin Noël <corentin.noel@collabora.com>
Thu, 8 Feb 2024 16:49:07 +0000 (17:49 +0100)
libvaladoc/Makefile.am
libvaladoc/documentation/documentationparser.vala
libvaladoc/documentation/gidocgenparser.vala [new file with mode: 0644]
libvaladoc/documentation/gidocgenscanner.vala [new file with mode: 0644]
libvaladoc/documentation/girmetadata.vala
valadoc/tests/Makefile.am
valadoc/tests/libvaladoc/gidocgen-scanner.vala [new file with mode: 0644]

index dad9a9e99a21097ca07a3819c912b28e1f4f6335..a493b5abab783785947159c94f884438ad4686ec 100644 (file)
@@ -42,6 +42,8 @@ libvaladoc_la_VALASOURCES = \
        documentation/documentationparser.vala \
        documentation/wiki.vala \
        documentation/wikiscanner.vala \
+       documentation/gidocgenparser.vala \
+       documentation/gidocgenscanner.vala \
        documentation/gtkdoccommentparser.vala \
        documentation/gtkdoccommentscanner.vala \
        documentation/gtkdocmarkdownparser.vala \
index 0a5a0d04c643c13a4e12e1858406238c7e772ce1..415476d538512075c98623770e43daa9ae919566 100644 (file)
@@ -50,7 +50,7 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 
                gtkdoc_parser = new Gtkdoc.Parser (settings, reporter, tree, modules);
                gtkdoc_markdown_parser = new Gtkdoc.MarkdownParser (settings, reporter, tree, modules);
-
+               gidocgen_parser = new Gidocgen.Parser (settings, reporter, tree, modules);
 
                metadata = new Vala.HashMap<Api.SourceFile, GirMetaData> ();
                id_registrar = new Importer.InternalIdRegistrar ();
@@ -60,6 +60,7 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
 
        private Gtkdoc.Parser gtkdoc_parser;
        private Gtkdoc.MarkdownParser gtkdoc_markdown_parser;
+       private Gidocgen.Parser gidocgen_parser;
 
        private Settings _settings;
        private ErrorReporter _reporter;
@@ -80,12 +81,18 @@ public class Valadoc.DocumentationParser : Object, ResourceLocator {
                        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;
+                       switch (metadata.doc_kind) {
+                               case GirMetaData.DocKind.MARKDOWN:
+                                       Comment doc_comment = gtkdoc_markdown_parser.parse (element, gir_comment, metadata, id_registrar);
+                                       return doc_comment;
+                               case GirMetaData.DocKind.DOCBOOK:
+                                       Comment doc_comment = gtkdoc_parser.parse (element, gir_comment, metadata, id_registrar);
+                                       return doc_comment;
+                               case GirMetaData.DocKind.GI_DOCGEN:
+                                       Comment doc_comment = gidocgen_parser.parse (element, gir_comment, metadata, id_registrar);
+                                       return doc_comment;
+                               default:
+                                       assert_not_reached ();
                        }
                } else {
                        return parse_comment_str (element, comment.content, comment.file.get_name (),
diff --git a/libvaladoc/documentation/gidocgenparser.vala b/libvaladoc/documentation/gidocgenparser.vala
new file mode 100644 (file)
index 0000000..a10a946
--- /dev/null
@@ -0,0 +1,91 @@
+/* gidocgenparser.vala
+ *
+ * Copyright (C) 2023 Corentin Noël
+ *
+ * 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:
+ *     Corentin Noël <corentin.noel@collabora.com>
+ */
+
+using Valadoc.Content;
+using Valadoc;
+
+public class Valadoc.Gidocgen.Parser : Object, ResourceLocator {
+       private Valadoc.Parser parser;
+       private Content.ContentFactory _factory;
+
+       private Vala.ArrayList<Object> _stack = new Vala.ArrayList<Object> ();
+
+       private Settings _settings;
+       private ErrorReporter _reporter;
+       private Api.Tree _tree;
+
+       private Importer.InternalIdRegistrar id_registrar;
+       private GirMetaData metadata;
+       private Api.GirSourceComment gir_comment;
+       private Api.Node element;
+
+       public Parser (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;
+       }
+
+       public Comment? parse (Api.Node element, Api.GirSourceComment gir_comment, GirMetaData metadata, Importer.InternalIdRegistrar id_registrar) {
+               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);
+               }
+               return null;
+       }
+
+       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 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;
+       }
+
+       public string resolve (string path) {
+               return path;
+       }
+}
diff --git a/libvaladoc/documentation/gidocgenscanner.vala b/libvaladoc/documentation/gidocgenscanner.vala
new file mode 100644 (file)
index 0000000..9cd63fb
--- /dev/null
@@ -0,0 +1,759 @@
+/* gidocgenscanner.vala
+ *
+ * Copyright (C) 2014 Florian Brosch
+ * Copyright (C) 2023 Corentin Noël
+ *
+ * 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;
+
+public class Valadoc.Gidocgen.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 Vala.List<State> states = new Vala.ArrayList<State> ();
+
+       private inline void push_state (State state) {
+               states.insert (0, state);
+       }
+
+       private inline State pop_state () {
+               return states.remove_at (0);
+       }
+
+       private inline State peek_state () {
+               return states.get (0);
+       }
+
+
+       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.get (0) == State.UNORDERED_LIST) {
+                       emit_token (Valadoc.TokenType.MARKDOWN_UNORDERED_LIST_ITEM_END);
+                       pop_state ();
+                       return true;
+               } else if (states.get (0) == 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 Vala.SourceLocation get_begin () {
+               return Vala.SourceLocation (_index, _last_line, get_line_start_column () + _last_column);
+       }
+
+       private Vala.SourceLocation get_end (int offset = 0) {
+               return Vala.SourceLocation (_index, _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;
+       }
+}
+
index 7d1b78ee9bb186dfdf5fe740194c1f4d832e06fc..b6438b6d2d9999dcf073c66fa0e365253e538489 100644 (file)
@@ -28,8 +28,13 @@ public class Valadoc.GirMetaData : Object {
        private string? metadata_path = null;
        private string? resource_dir = null;
 
+       public enum DocKind {
+               MARKDOWN,
+               DOCBOOK,
+               GI_DOCGEN
+       }
 
-       public bool is_docbook { private set; get; default = false; }
+       public DocKind doc_kind { private set; get; default = DocKind.MARKDOWN; }
        public string index_sgml { private set; get; default = null; }
        public string index_sgml_online { private set; get; default = null; }
 
@@ -89,7 +94,15 @@ public class Valadoc.GirMetaData : Object {
                                break;
 
                        case "is_docbook":
-                               this.is_docbook = key_file.get_boolean ("General", "is_docbook");
+                               if (key_file.get_boolean ("General", "is_docbook")) {
+                                       doc_kind = DocKind.DOCBOOK;
+                               }
+                               break;
+
+                       case "is_gi_docgen":
+                               if (key_file.get_boolean ("General", "is_gi_docgen")) {
+                                       doc_kind = DocKind.GI_DOCGEN;
+                               }
                                break;
 
                        case "index_sgml":
index 559642a39e3777e212f197d2dfab19bd0f213d74..526dee19b631cd2a0bad245809c19588e1759b93 100644 (file)
@@ -24,6 +24,7 @@ AM_TESTS_ENVIRONMENT = \
 TESTS = \
        libvaladoc/errorreporter.vala \
        libvaladoc/markupreader.vala \
+       libvaladoc/gidocgen-scanner.vala \
        libvaladoc/gtkdoc-scanner.vala \
        libvaladoc/parser-manyrule.vala \
        libvaladoc/parser-oneofrule.vala \
diff --git a/valadoc/tests/libvaladoc/gidocgen-scanner.vala b/valadoc/tests/libvaladoc/gidocgen-scanner.vala
new file mode 100644 (file)
index 0000000..c75b15f
--- /dev/null
@@ -0,0 +1,225 @@
+/* gidocgen-scanner.vala
+ *
+ * Copyright (C) 2023 Corentin Noël
+ *
+ * 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:
+ *     Corentin Noël <corentin.noel@collabora.com>
+ */
+
+
+using Valadoc;
+
+
+void main () {
+       var scanner = new Gidocgen.Scanner ();
+       scanner.reset ("""<element1>
+<element2 a="a-val" b="b-val">
+</element3>
+<element4 />
+<element5 a="a-val" b="b-val"/>
+<!---->
+<!--
+AAAA
+-->
+foo_bar ()
+%aaa
+@param
+#TypeName
+myword
+
+|[]|
+::my-signal
+:my-property
+""");
+
+       var token = scanner.next ();
+
+       assert (token.type == Gtkdoc.TokenType.XML_OPEN);
+       assert (token.content == "element1");
+       assert (((Vala.Map) token.attributes).size == 0);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_OPEN);
+       assert (token.content == "element2");
+       assert (token.attributes.get ("a") == "a-val");
+       assert (token.attributes.get ("b") == "b-val");
+       assert (((Vala.Map) token.attributes).size == 2);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_CLOSE);
+       assert (token.content == "element3");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_OPEN);
+       assert (token.content == "element4");
+       assert (((Vala.Map) token.attributes).size == 0);
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_CLOSE);
+       assert (token.content == "element4");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_OPEN);
+       assert (token.content == "element5");
+       assert (token.attributes.get ("a") == "a-val");
+       assert (token.attributes.get ("b") == "b-val");
+       assert (((Vala.Map) token.attributes).size == 2);
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_CLOSE);
+       assert (token.content == "element5");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_COMMENT);
+       assert (token.content == "");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.XML_COMMENT);
+       assert (token.content == "");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_FUNCTION);
+       assert (token.content == "foo_bar");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_CONST);
+       assert (token.content == "aaa");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_PARAM);
+       assert (token.content == "param");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_TYPE);
+       assert (token.content == "TypeName");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.WORD);
+       assert (token.content == "myword");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.SPACE);
+       assert (token.content == "      ");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_PARAGRAPH);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_SOURCE_OPEN);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_SOURCE_CLOSE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_SIGNAL);
+       assert (token.content == "my-signal");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.GTKDOC_PROPERTY);
+       assert (token.content == "my-property");
+       assert (token.attributes == null);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.NEWLINE);
+
+
+       token = scanner.next ();
+       assert (token.type == Gtkdoc.TokenType.EOF);
+
+}