From: Corentin Noël Date: Thu, 8 Feb 2024 16:48:15 +0000 (+0100) Subject: libvaladoc: Add gi-docgen documentation support X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4f9b03987e2ca2e7f80d352a57d21131be68ac69;p=thirdparty%2Fvala.git libvaladoc: Add gi-docgen documentation support --- diff --git a/libvaladoc/Makefile.am b/libvaladoc/Makefile.am index dad9a9e99..a493b5aba 100644 --- a/libvaladoc/Makefile.am +++ b/libvaladoc/Makefile.am @@ -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 \ diff --git a/libvaladoc/documentation/documentationparser.vala b/libvaladoc/documentation/documentationparser.vala index 0a5a0d04c..415476d53 100644 --- a/libvaladoc/documentation/documentationparser.vala +++ b/libvaladoc/documentation/documentationparser.vala @@ -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 (); 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 index 000000000..a10a94625 --- /dev/null +++ b/libvaladoc/documentation/gidocgenparser.vala @@ -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 + */ + +using Valadoc.Content; +using Valadoc; + +public class Valadoc.Gidocgen.Parser : Object, ResourceLocator { + private Valadoc.Parser parser; + private Content.ContentFactory _factory; + + private Vala.ArrayList _stack = new Vala.ArrayList (); + + 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 index 000000000..9cd63fb93 --- /dev/null +++ b/libvaladoc/documentation/gidocgenscanner.vala @@ -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 + */ + + +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 states = new Vala.ArrayList (); + + 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; + } +} + diff --git a/libvaladoc/documentation/girmetadata.vala b/libvaladoc/documentation/girmetadata.vala index 7d1b78ee9..b6438b6d2 100644 --- a/libvaladoc/documentation/girmetadata.vala +++ b/libvaladoc/documentation/girmetadata.vala @@ -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": diff --git a/valadoc/tests/Makefile.am b/valadoc/tests/Makefile.am index 559642a39..526dee19b 100644 --- a/valadoc/tests/Makefile.am +++ b/valadoc/tests/Makefile.am @@ -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 index 000000000..c75b15fca --- /dev/null +++ b/valadoc/tests/libvaladoc/gidocgen-scanner.vala @@ -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 + */ + + +using Valadoc; + + +void main () { + var scanner = new Gidocgen.Scanner (); + scanner.reset (""" + + + + + + +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); + +}