From c8eb3be09ec2bda9494e2e62791f3fb6fe222dd9 Mon Sep 17 00:00:00 2001 From: rockon999 Date: Wed, 8 Aug 2018 14:10:53 -0500 Subject: Improve markdown compatibility of docwriter. --- giscanner/docwriter.py | 93 +++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 80 insertions(+), 13 deletions(-) diff --git a/giscanner/docwriter.py b/giscanner/docwriter.py index 38102bf8..590fd891 100644 --- a/giscanner/docwriter.py +++ b/giscanner/docwriter.py @@ -34,6 +34,7 @@ import tempfile from xml.sax import saxutils from mako.lookup import TemplateLookup import markdown +from markdown.extensions.headerid import HeaderIdExtension from . import ast, xmlwriter from .utils import to_underscores @@ -64,7 +65,6 @@ language_mimes = { "yaml": "application/x-yaml", } - def make_page_id(node, recursive=False): if isinstance(node, ast.Namespace): if recursive: @@ -192,14 +192,17 @@ class TemplatedScanner(object): class DocstringScanner(TemplatedScanner): def __init__(self): specs = [ - ('new_paragraph', r'\n\n'), - ('new_line', r'\n'), ('!alpha', r'[a-zA-Z0-9_]+'), ('!alpha_dash', r'[a-zA-Z0-9_-]+'), ('code_start_with_language', - r'\|\[\>\"\s*\-\-\>'), + r'\|\[\>\"\s*\-\-\>'), ('code_start', r'\|\['), ('code_end', r'\]\|'), + ('html_code_start', r''), + ('html_code_end', r''), + ('markdown_code_toggle', r'\`'), + ('markdown_attr_start', r'\{'), + ('markdown_attr_end', r'\}'), ('property', r'#<>:(<>)'), ('signal', r'#<>::(<>)'), ('type_name', r'#(<>)'), @@ -219,9 +222,13 @@ class DocFormatter(object): # https://wiki.gnome.org/Projects/GTK%2B/DocumentationSyntax/Markdown # we won't insert paragraphs and will respect new lines. self._processing_code = False + self._processing_attr = False def escape(self, text): return saxutils.escape(text) + + def unescape(self, text): + return saxutils.unescape(text) def should_render_node(self, node): if getattr(node, "private", False): @@ -275,6 +282,8 @@ class DocFormatter(object): raise KeyError("Could not find %s" % (name, )) def _process_other(self, node, match, props): + if self._processing_code: + return match return self.escape(match) def _process_property(self, node, match, props): @@ -302,6 +311,9 @@ class DocFormatter(object): return self.format_xref(signal) def _process_type_name(self, node, match, props): + if self._processing_attr: + return match + ident = props['type_name'] type_ = self._resolve_type(ident) plural = False @@ -354,31 +366,66 @@ class DocFormatter(object): # # A better solution would be to replace DocstringScanner by Markdown # entirely, implementing the custom markup with Markdown extensions. + # + # UPDATE: As a temporary fix for code blocks we will convert directly to ``` syntax. + # + # NOTES: + # _process_markdown_code_toggle: + # Whenever we encounter ` we need to toggle whether we are escaping text as text inside + # inline code blocks is unescaped + # _process_markdown_attr_(start|end): + # Whenever we encounter { or } we must stop parsing type names as curly braces are used for + # attributes in GIR files in addition to type declarations. + # _process_html_code_(start|end): + # Whenever we encounter an HTML block we must stop escaping text. + # + # TODO: Convert to markdown extensions. + + def _process_markdown_code_toggle(self, node, match, props): + self._processing_code = not self._processing_code + return match + + def _process_markdown_attr_start(self, node, match, props): + if not self._processing_code: + self._processing_attr = True + return match + + def _process_markdown_attr_end(self, node, match, props): + if not self._processing_code: + self._processing_attr = False + return match + + def _process_html_code_start(self, node, match, props): + self._processing_code = True + return match + + def _process_html_code_end(self, node, match, props): + self._processing_code = False + return match def _process_code_start(self, node, match, props): self._processing_code = True - return '

\n    '
+        return '

\n```\n' def _process_code_start_with_language(self, node, match, props): self._processing_code = True try: - mime = language_mimes[props["language_name"].lower()] - return '

\n    '
+            return '

\n```' + props["language_name"].lower() + '\n' except KeyError: - return '

\n    '
+            return '

\n```\n' def _process_code_end(self, node, match, props): self._processing_code = False - return '\n

' + return '\n```\n

' def _process_new_line(self, node, match, props): if self._processing_code: - return '\n ' + return '\n' return '\n' def _process_new_paragraph(self, node, match, props): if self._processing_code: - return '\n\n ' + return '\n\n' return "

" def _process_token(self, node, tok): @@ -395,6 +442,11 @@ class DocFormatter(object): 'code_start': self._process_code_start, 'code_start_with_language': self._process_code_start_with_language, 'code_end': self._process_code_end, + 'html_code_start': self._process_html_code_start, + 'html_code_end': self._process_html_code_end, + 'markdown_code_toggle': self._process_markdown_code_toggle, + 'markdown_attr_start': self._process_markdown_attr_start, + 'markdown_attr_end': self._process_markdown_attr_end, 'new_line': self._process_new_line, 'new_paragraph': self._process_new_paragraph, } @@ -1053,6 +1105,9 @@ class DocFormatterGjs(DocFormatterIntrospectableBase): class DevDocsFormatterGjs(DocFormatterGjs): + output_format = "devdocs" + output_extension = ".html" + def _is_static_method(self, node): if not hasattr(node.parent, "static_methods"): return False @@ -1112,7 +1167,13 @@ class DevDocsFormatterGjs(DocFormatterGjs): return '' cleaned_up_gtkdoc = super(DevDocsFormatterGjs, self).format_inline(node, doc) - return markdown.markdown(cleaned_up_gtkdoc) + return markdown.markdown(cleaned_up_gtkdoc, extensions=[ + InlineMarkdown(), + 'markdown.extensions.fenced_code', + 'markdown.extensions.nl2br', + 'markdown.extensions.attr_list', + HeaderIdExtension(forceid=False) + ]) def format_function_name(self, func): name = func.name @@ -1194,7 +1255,13 @@ class DevDocsFormatterGjs(DocFormatterGjs): if para is None: return '' cleaned_up_gtkdoc = super(DevDocsFormatterGjs, self).format_inline(node, para) - return markdown.markdown(cleaned_up_gtkdoc, extensions=[InlineMarkdown()]) + return markdown.markdown(cleaned_up_gtkdoc, extensions=[ + InlineMarkdown(), + 'markdown.extensions.fenced_code', + 'markdown.extensions.nl2br', + 'markdown.extensions.attr_list', + HeaderIdExtension(forceid=False) + ]) def format_in_parameters(self, node): return ', '.join(p.argname for p in self.get_in_parameters(node)) -- cgit v1.2.1