diff options
-rw-r--r-- | Makefile-giscanner.am | 2 | ||||
-rw-r--r-- | giscanner/docbookdescription.py | 185 | ||||
-rw-r--r-- | giscanner/docbookwriter.py | 569 |
3 files changed, 0 insertions, 756 deletions
diff --git a/Makefile-giscanner.am b/Makefile-giscanner.am index 3655997f..d4e417a3 100644 --- a/Makefile-giscanner.am +++ b/Makefile-giscanner.am @@ -33,8 +33,6 @@ pkgpyexec_PYTHON = \ giscanner/ast.py \ giscanner/cachestore.py \ giscanner/codegen.py \ - giscanner/docbookdescription.py \ - giscanner/docbookwriter.py \ giscanner/docmain.py \ giscanner/dumper.py \ giscanner/introspectablepass.py \ diff --git a/giscanner/docbookdescription.py b/giscanner/docbookdescription.py deleted file mode 100644 index 9ec7219d..00000000 --- a/giscanner/docbookdescription.py +++ /dev/null @@ -1,185 +0,0 @@ - -TAG_PROGRAM_LISTING = '<programlisting' -TAG_CDATA = '<![CDATA[' -TAGS = {TAG_PROGRAM_LISTING, TAG_CDATA, ']]>', '</programlisting>'} - -def get_formatted_description(description): - desc = description.replace("|[", "<informalexample><programlisting>") \ - .replace("]|", "</programlisting></informalexample>") - - desc = "<para>%s</para>" % desc - -# we still need to handle this case -# # Handle "#include <xxxxx>" -# $text =~ s/#include(\s+)<([^>]+)>/#include$1<$2>/g; - - formatted_desc = "" - - inside_tags = [] - last_offset = 0 - for start, end, tag in _find_xml_tag_matches(desc): - if len(inside_tags) == 0: - new_desc = "\n</para>\n<para>\n".join(desc[last_offset:start].split('\n\n')) - else: - new_desc = desc[last_offset:start] - - if TAG_CDATA not in inside_tags: - new_desc = _escape_non_cdata_section(new_desc) - - formatted_desc += new_desc - formatted_desc += tag - if tag == TAG_PROGRAM_LISTING: - formatted_desc += '>' - - if tag in (TAG_CDATA, TAG_PROGRAM_LISTING): - inside_tags.append(tag) - else: - try: - inside_tags.pop() - except IndexError: - print "Error: mismatched tag:", tag - last_offset = end - - formatted_desc += _escape_non_cdata_section(desc[last_offset:]) - return formatted_desc - -def _find_xml_tag_matches(string): - offset = 0 - while True: - indexes = [] - for tag in TAGS: - pos = string.find(tag, offset) - if pos != -1: - indexes.append((tag, pos)) - - if indexes: - tag, first = min(indexes, key=lambda x: x[1]) - if tag == TAG_PROGRAM_LISTING: - end = string.find('>', first + len(tag) - 1) + 1 - else: - end = first + len(tag) - offset = end - yield first, end, tag - else: - return - -def _escape_non_cdata_section(string): - string = _escape_ampersand_not_in_entity(string) - string = _escape_lt_not_in_xml_tag(string) - return _escape_gt_not_in_xml_tag(string) - -def _escape_ampersand_not_in_entity(string): - parts = string.split('&') - - output = parts[0] - for part in parts[1:]: - end = part.find(';') - if end == -1 or not part[:end].isalpha(): - output += "&" - else: - output += "&" - output += part - - return output - -def _is_valid_xml_tag_name(name): - if len(name) < 1: - return False - elif name.isalpha() or (name[0].isalpha() and name[1:].isalnum()): - return True - -def _is_valid_xml_tag(string): - # handle case where line end is between tag name and first argument. - # ie. <link\nlinkend="link-id">My Link</link> - string = string.replace('\n', ' ') - - if string[-1] == '/': - string = string[:-1] - - # string is the inner part of the tag, without < and > - if string[0] == '/' and _is_valid_xml_tag_name(string[1:]): - #valid end tag - return True - elif _is_valid_xml_tag_name(string): - #valid start tag with not params - return True - elif " " in string: - # we are looking for: <tagname arg="value" arg2="value2"> - # TODO: handle spaces in values (between quotations) - tagname, rest = string.split(" ", 1) - if not _is_valid_xml_tag_name(tagname): - return False - - while rest.strip(): - rest = rest.lstrip() - - if not '=' in rest: - return False - argname, rest = rest.split('=', 1) - if not _is_valid_xml_tag_name(argname): - return False - if rest[0] != '"': - return False - value, rest = rest[1:].split('"', 1) - - return True - -def _escape_lt_not_in_xml_tag(string): - parts = string.split('<') - - output = parts[0] - for part in parts[1:]: - end = part.find('>') - if end == -1 or not _is_valid_xml_tag(part[:end]): - output += "<" - else: - output += "<" - output += part - - return output - -def _escape_gt_not_in_xml_tag(string): - parts = string.split('>') - - output = parts[0] - for part in parts[1:]: - start = output.rfind('<') - if start == -1 or not _is_valid_xml_tag(output[start+1:]): - output += ">" - else: - output += ">" - output += part - - return output - - -def test(): - assert _is_valid_xml_tag_name('a') - assert _is_valid_xml_tag_name('refsect1') - assert not _is_valid_xml_tag_name('1refsect') - assert not _is_valid_xml_tag_name('1') - - assert _is_valid_xml_tag('/a') - assert _is_valid_xml_tag('/refsect1') - assert not _is_valid_xml_tag('/1') - assert _is_valid_xml_tag('link') - assert _is_valid_xml_tag('link linkend="value"') - assert _is_valid_xml_tag('link linkend="value"') - assert _is_valid_xml_tag('link/') - assert _is_valid_xml_tag('link linkend="value"/') - assert _is_valid_xml_tag('link linkend="value" arg23="anothervalue"') - assert _is_valid_xml_tag('link linkend="value" arg23="anothervalue with spaces"') - assert not _is_valid_xml_tag('link linkend="value arg23="anothervalue with spaces"') - assert not _is_valid_xml_tag('link linkend') - assert _is_valid_xml_tag('link\nlinkend="link-id"') - assert _is_valid_xml_tag('xref linkend="gtkstylecontext-classes"/') - - assert _is_valid_xml_tag('a href="http://www.gtk.org" title="<i>Our</i> website"') - assert _is_valid_xml_tag('ulink \nurl="http://www.freedesktop.org/Standards/wm-spec"') - - string = 'gtk_label_set_markup (label, "Go to the <a href="http://www.gtk.org" ' \ - + 'title="<i>Our</i> website">GTK+ website</a> for more...");' - assert _escape_lt_not_in_xml_tag(string) == string - -if __name__ == '__main__': - test() diff --git a/giscanner/docbookwriter.py b/giscanner/docbookwriter.py deleted file mode 100644 index d4701e68..00000000 --- a/giscanner/docbookwriter.py +++ /dev/null @@ -1,569 +0,0 @@ -#!/usr/bin/env python -# -*- Mode: Python -*- -# GObject-Introspection - a framework for introspecting GObject libraries -# Copyright (C) 2010 Zach Goldberg -# Copyright (C) 2011 Johan Dahlin -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program 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 General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. -# - -import sys - -from . import ast -from .girparser import GIRParser -from .xmlwriter import XMLWriter -from .docbookdescription import get_formatted_description - -XMLNS = "http://docbook.org/ns/docbook" -XMLVERSION = "5.0" -DOCTYPE = """<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" - "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [ -<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> -<!ENTITY version SYSTEM "version.xml"> -]>""" #" - -def _space(num): - return " " * num - -class DocBookFormatter(object): - def __init__(self): - self.namespace = None - self.writer = None - - def set_namespace(self, namespace): - self.namespace = namespace - - def set_writer(self, writer): - self.writer = writer - - def get_type_string(self, type): - return str(type.ctype) - - def render_parameter(self, param_type, param_name): - return "%s %s" % (param_type, param_name) - - def _render_parameter(self, param, extra_content=''): - with self.writer.tagcontext("parameter"): - if param.type.ctype is not None: - link_dest = param.type.ctype.replace("*", "") - else: - link_dest = param.type.ctype - with self.writer.tagcontext("link", [("linkend", "%s" % link_dest)]): - self.writer.write_tag("type", [], link_dest) - self.writer.write_line(extra_content) - - def _render_parameters(self, parent, parameters): - self.writer.write_line( - "%s(" % _space(40 - len(parent.symbol))) - - parent_class = parent.parent_class - ctype = ast.Type(parent.parent_class.ctype + '*') - params = [] - params.append(ast.Parameter(parent_class.name.lower(), ctype)) - params.extend(parameters) - - first_param = True - for param in params: - if not first_param: - self.writer.write_line("\n%s" % _space(61)) - else: - first_param = False - - if not param == params[-1]: - comma = ", " - else: - comma = "" - - if isinstance(param.type, ast.Varargs): - with self.writer.tagcontext("parameter"): - self.writer.write_line('...%s' % comma) - else: - extra_content = " " - if param.type.ctype is not None and '*' in param.type.ctype: - extra_content += '*' - extra_content += param.argname - extra_content += comma - self._render_parameter(param, extra_content) - - self.writer.write_line(");\n") - - def get_method_as_title(self, method): - return "%s ()" % method.symbol - - def get_page_name(self, node): - # page name is only used for xml:id (not displayed to users) - if isinstance(node, ast.Alias) or node.gtype_name is None: - return node.ctype - return node.gtype_name - - def get_class_name(self, node): - if node.gtype_name is None: - return node.ctype - return node.gtype_name - - def get_type_name(self, node): - if isinstance(node, ast.Array): - if node.array_type == ast.Array.C: - return str(node.element_type) + "[]" - else: - return "%s<%s>" % (node.array_type, str(node.element_type)) - elif isinstance(node, ast.Map): - return "GHashTable<%s, %s>" % (str(node.key_type), str(node.value_type)) - elif isinstance(node, ast.List): - return "GList<%s>" % str(node.element_type) - else: - return str(node) - - def render_method(self, method, link=False): - self.writer.disable_whitespace() - - retval_type = method.retval.type - if retval_type.ctype: - link_dest = retval_type.ctype.replace("*", "") - else: - link_dest = str(retval_type) - - if retval_type.target_giname: - ns = retval_type.target_giname.split('.') - if ns[0] == self.namespace.name: - link_dest = "%s" % ( - retval_type.ctype.replace("*", "")) - - with self.writer.tagcontext("link", [("linkend", link_dest)]): - self.writer.write_tag("returnvalue", [], link_dest) - - if '*' in retval_type.ctype: - self.writer.write_line(' *') - - self.writer.write_line( - _space(20 - len(self.get_type_string(method.retval.type)))) - - if link: - self.writer.write_tag("link", [("linkend", - method.symbol.replace("_", "-"))], - method.symbol) - else: - self.writer.write_line(method.symbol) - - self._render_parameters(method, method.parameters) - self.writer.enable_whitespace() - - def _get_annotations(self, argument): - annotations = {} - - if hasattr(argument.type, 'element_type') and \ - argument.type.element_type is not None: - if isinstance(argument.type.element_type, ast.Array): - element_type = argument.type.element_type.array_type - else: - element_type = argument.type.element_type - annotations['element-type'] = element_type - - if argument.transfer is not None and argument.transfer != 'none': - annotations['transfer'] = argument.transfer - - if hasattr(argument, 'allow_none') and argument.allow_none: - annotations['allow-none'] = None - - return annotations - - def render_param_list(self, method): - self._render_param(method.parent_class.name.lower(), 'instance', []) - - for param in method.parameters: - if isinstance(param.type, ast.Varargs): - argname = '...' - else: - argname = param.argname - self._render_param(argname, param.doc, self._get_annotations(param)) - - self._render_param('Returns', method.retval.doc, - self._get_annotations(method.retval)) - - def _render_param(self, argname, doc, annotations): - with self.writer.tagcontext('varlistentry'): - with self.writer.tagcontext('term'): - self.writer.disable_whitespace() - try: - with self.writer.tagcontext('parameter'): - self.writer.write_line(argname) - if doc is not None: - self.writer.write_line(' :') - finally: - self.writer.enable_whitespace() - if doc is not None: - with self.writer.tagcontext('listitem'): - with self.writer.tagcontext('simpara'): - self.writer.write_line(doc) - if annotations: - with self.writer.tagcontext('emphasis', [('role', 'annotation')]): - for key, value in annotations.iteritems(): - self.writer.disable_whitespace() - try: - self.writer.write_line('[%s' % key) - if value is not None: - self.writer.write_line(' %s' % value) - self.writer.write_line(']') - finally: - self.writer.enable_whitespace() - - def render_property(self, prop, link=False): - prop_name = '"%s"' % prop.name - prop_type = self.get_type_name(prop.type) - - flags = [] - if prop.readable: - flags.append("Read") - if prop.writable: - flags.append("Write") - if prop.construct: - flags.append("Construct") - if prop.construct_only: - flags.append("Construct Only") - - self._render_prop_or_signal(prop_name, prop_type, flags) - - def _render_prop_or_signal(self, name, type_, flags): - self.writer.disable_whitespace() - - line = _space(2) + name + _space(27 - len(name)) - line += str(type_) + _space(22 - len(str(type_))) - line += ": " + " / ".join(flags) - - self.writer.write_line(line + "\n") - - self.writer.enable_whitespace() - - - def render_signal(self, signal, link=False): - sig_name = '"%s"' % signal.name - - flags = [] - if signal.when == "first": - flags.append("Run First") - elif signal.when == "last": - flags.append("Run Last") - elif signal.when == "cleanup": - flags.append("Cleanup") - - if signal.no_recurse: - flags.append('No Recursion') - if signal.detailed: - flags.append("Has Details") - if signal.action: - flags.append("Action") - if signal.no_hooks: - flags.append("No Hooks") - - self._render_prop_or_signal(sig_name, "", flags) - - -class DocBookFormatterPython(DocBookFormatter): - def get_title(self, page): - return "%s.%s" % (page.ast.namespace.name, page.ast.name) - - def render_struct(self, page): - class_ = page.ast - try: - self.writer.disable_whitespace() - self.writer.write_line("class %s" % self.get_title(page)) - - if hasattr(page.ast, "parent") and page.ast.parent is not None: - if isinstance(page.ast.parent, ast.Type): - parent_name = page.ast.parent - else: - parent_name = "%s.%s" % (page.ast.parent.namespace.name, - page.ast.parent.name) - elif isinstance(page.ast, ast.Interface): - parent_name = "GObject.Interface" - else: - parent_name = None - if parent_name is not None: - self.writer.write_line("(%s)" % (parent_name)) - - self.writer.write_line(":\n") - finally: - self.writer.enable_whitespace() - - -class DocBookFormatterC(DocBookFormatter): - def get_title(self, page): - return page.ast.ctype - - def render_struct(self, page): - try: - self.writer.disable_whitespace() - self.writer.write_line("struct ") - self.writer.write_tag( - "link", - [("linkend", "%s-struct" % page.name)], - "%s" % page.name) - self.writer.write_line(";\n") - finally: - self.writer.enable_whitespace() - - -class DocBookPage(object): - def __init__(self, name, ast_node): - self.methods = [] - self.properties = [] - self.signals = [] - self.name = name - self.description = ast_node.doc - self.ast = ast_node - self.id = None - - if isinstance(ast_node, (ast.Class, ast.Record, ast.Interface)): - for method in ast_node.methods: - method.parent_class = ast_node - self.methods = ast_node.methods - - if isinstance(ast_node, (ast.Class, ast.Interface)): - self.properties = ast_node.properties - self.signals = ast_node.signals - - def get_methods(self): - return self.methods - - def get_properties(self): - return self.properties - - def get_signals(self): - return self.signals - -class DocBookWriter(object): - def __init__(self, formatter): - self._namespace = None - self._pages = [] - - self._writer = XMLWriter() - - formatter.set_writer(self._writer) - self._formatter = formatter - - def _add_page(self, page): - self._pages.append(page) - - def add_transformer(self, transformer): - self._transformer = transformer - - self._namespace = self._transformer._namespace - self._formatter.set_namespace(self._namespace) - - for name, node in self._namespace.iteritems(): - if isinstance(node, (ast.Class, ast.Record, ast.Interface, ast.Alias)): - page_name = self._formatter.get_page_name(node) - self._add_node(node, page_name) - - def _add_node(self, node, name): - page = DocBookPage(name, node) - self._add_page(page) - - if isinstance(node, (ast.Class, ast.Record, ast.Interface, ast.Alias)): - page.id = node.ctype - - def write(self, output): - self._writer.write_line(DOCTYPE) - with self._writer.tagcontext("book", [ - ("xml:id", "page_%s" % self._namespace.name), - ("xmlns", XMLNS), - ("version", XMLVERSION)]): - self._writer.write_tag("title", [], "%s Documentation" % ( - self._namespace.name)) - - for page in self._pages: - self._render_page(page) - - fp = open(output, 'w') - fp.write(self._writer.get_xml()) - fp.close() - - def _render_page(self, page): - with self._writer.tagcontext("chapter", [("xml:id", "ch_%s" % ( - page.name))]): - self._writer.write_tag( - "title", [], self._formatter.get_title(page)) - - with self._writer.tagcontext("refsynopsisdiv", - [('id', '%s.synopsis' % page.name), - ('role', 'synopsis')]): - - self._writer.write_tag( - "title", [("role", "synopsis.title")], "Synopsis") - - if not isinstance(page.ast, ast.Alias): - self._writer.write_tag("anchor", [("id", page.name)]) - - with self._writer.tagcontext('synopsis'): - self._formatter.render_struct(page) - - for ast_node in page.get_methods(): - self._formatter.render_method(ast_node, link=True) - - if isinstance(page.ast, (ast.Class, ast.Interface)): - with self._writer.tagcontext("refsect1", - [('id', '%s.object-hierarchy' % page.name), - ('role', 'object_hierarchy')]): - self._writer.write_tag('title', [('role', 'object_hierarchy.title')], - "Object Hierarchy") - with self._writer.tagcontext('synopsis'): - self._render_page_object_hierarchy(page.ast) - - if page.get_properties(): - with self._writer.tagcontext('refsect1', - [('id', '%s.properties' % page.name), - ('role', 'properties')]): - self._writer.write_tag("title", [('role', 'properties.title')], - "Properties") - with self._writer.tagcontext("synopsis"): - for ast_node in page.get_properties(): - if isinstance(ast_node.type, ast.TypeUnknown): - print "Warning: ignoring property '%s' for " \ - "lack of type" % ast_node.name - continue - self._formatter.render_property(ast_node, link=True) - - if page.get_signals(): - with self._writer.tagcontext('refsect1', - [('id', '%s.signals' % page.name), - ('role', 'signal_proto')]): - self._writer.write_tag('title', [('role', 'signal_proto.title')], - "Signals") - with self._writer.tagcontext('synopsis'): - for ast_node in page.get_signals(): - self._formatter.render_signal(ast_node, link=True) - - if page.description: - with self._writer.tagcontext('refsect1', - [('id', '%s.description' % (page.name, ))]): - self._writer.write_tag( - "title", [("role", "desc.title")], "Description") - self._render_description(page.description) - - with self._writer.tagcontext('refsect1', - [('id', "%s-details" % page.id.lower()), - ("role", "details")]): - self._writer.write_tag("title", [("role", "details.title")], - "Details") - - if isinstance(page.ast, ast.Alias): - self._render_alias_detail(page.ast) - else: - self._render_struct_detail(page.ast) - - for ast_node in page.get_methods(): - self._render_method(ast_node) - - if page.get_properties(): - with self._writer.tagcontext('refsect1', - [('id', '%s.property-details' % page.name), - ('role', 'property_details')]): - self._writer.write_tag('title', [('role', 'property_details.title')], - "Property Details") - for ast_node in page.get_properties(): - self._render_property(ast_node) - - if page.get_signals(): - with self._writer.tagcontext('refsect1', - [('id', '%s.signal-details' % page.name), - ('role', 'signals')]): - self._writer.write_tag('title', [('role', 'signal.title')], - "Signal Details") - for ast_node in page.get_signals(): - self._render_signal(ast_node) - - def _render_alias_detail(self, alias): - with self._writer.tagcontext('refsect2', - [('id', "%s" % alias.ctype), - ('role', 'typedef')]): - self._writer.write_tag("title", [], "%s" % alias.ctype) - with self._writer.tagcontext("indexterm", [("zone", "%s" % alias.ctype)]): - self._writer.write_tag("primary", [("sortas", alias.name)], alias.ctype) - self._writer.write_tag("programlisting", - [], - "typedef %s %s" % (alias.target.ctype, - alias.ctype)) - self._writer.write_tag("para", [], alias.doc) - - def _render_struct_detail(self, struct): - with self._writer.tagcontext('refsect2', - [('id', "%s-struct" % struct.ctype), - ('role', 'struct')]): - self._writer.write_tag("title", [], "struct %s" % struct.ctype) - with self._writer.tagcontext("indexterm", [("zone", "%s-struct" % struct.ctype)]): - self._writer.write_tag("primary", [("sortas", struct.name)], struct.ctype) - self._writer.write_tag("programlisting", [], "struct %s;" % struct.ctype) - - def _render_method(self, ast_node): - - link_name = ast_node.symbol.replace("_", "-") - - self._writer.push_tag('refsect2', - [('id', link_name), - ('role', 'function')]) - self._writer.write_tag("title", [], - self._formatter.get_method_as_title(ast_node)) - - with self._writer.tagcontext("indexterm", [("zone", link_name)]): - self._writer.write_tag("primary", [], ast_node.name) - - with self._writer.tagcontext("programlisting"): - self._formatter.render_method(ast_node) - - description = ast_node.doc - if description: - self._render_description(ast_node.doc) - - with self._writer.tagcontext("variablelist", [("role", "params")]): - self._formatter.render_param_list(ast_node) - - self._writer.pop_tag() - - def _render_property(self, ast_node): - self._writer.write_line("Not implemented yet") - - def _render_signal(self, ast_node): - self._writer.write_line("Not implemented yet") - - def _render_page_object_hierarchy(self, page_node): - parent_chain = self._get_parent_chain(page_node) - parent_chain.append(page_node) - lines = [] - - for level, parent in enumerate(parent_chain): - prepend = "" - if level > 0: - prepend = _space((level - 1)* 6) + " +----" - lines.append(_space(2) + prepend + self._formatter.get_class_name(parent)) - - self._writer.disable_whitespace() - self._writer.write_line("\n".join(lines)) - self._writer.enable_whitespace() - - def _render_description(self, description): - formatted_desc = get_formatted_description(description) - self._writer.write_line(formatted_desc) - - def _get_parent_chain(self, page_node): - parent_chain = [] - - node = page_node - while node.parent and node.gi_name != 'GObject.Object': - node = self._transformer.lookup_giname(str(node.parent)) - parent_chain.append(node) - - parent_chain.reverse() - return parent_chain |