summaryrefslogtreecommitdiff
path: root/giscanner
diff options
context:
space:
mode:
authorTomeu Vizoso <tomeu.vizoso@collabora.com>2012-02-20 18:18:04 +0100
committerTomeu Vizoso <tomeu.vizoso@collabora.com>2012-02-20 18:18:04 +0100
commitad5c6abcbcd6c1cd26b9a714995c622f5dbe3b07 (patch)
treec040697e6ad1bb8269351968c3612927d9daea80 /giscanner
parent4fbb34bb0ea4a1d142052e62a29480c704550f8b (diff)
parent990b33b9fb5856b62550725bcff29f7e39a488a4 (diff)
downloadgobject-introspection-ad5c6abcbcd6c1cd26b9a714995c622f5dbe3b07.tar.gz
Merge branch 'mallard-templates'
Diffstat (limited to 'giscanner')
-rw-r--r--giscanner/ast.py2
-rw-r--r--giscanner/docbookdescription.py185
-rw-r--r--giscanner/docbookwriter.py569
-rw-r--r--giscanner/docmain.py53
-rw-r--r--giscanner/girparser.py30
-rw-r--r--giscanner/mallard-C-class.tmpl48
-rw-r--r--giscanner/mallard-C-default.tmpl11
-rw-r--r--giscanner/mallard-C-function.tmpl95
-rw-r--r--giscanner/mallard-C-namespace.tmpl19
-rw-r--r--giscanner/mallard-C-property.tmpl13
-rw-r--r--giscanner/mallard-C-record.tmpl12
-rw-r--r--giscanner/mallard-C-signal.tmpl13
-rw-r--r--giscanner/mallard-Python-class.tmpl63
-rw-r--r--giscanner/mallard-Python-default.tmpl11
-rw-r--r--giscanner/mallard-Python-enum.tmpl23
-rw-r--r--giscanner/mallard-Python-function.tmpl88
-rw-r--r--giscanner/mallard-Python-namespace.tmpl19
-rw-r--r--giscanner/mallard-Python-property.tmpl16
-rw-r--r--giscanner/mallard-Python-record.tmpl12
-rw-r--r--giscanner/mallard-Python-signal.tmpl50
-rw-r--r--giscanner/mallardwriter.py602
21 files changed, 700 insertions, 1234 deletions
diff --git a/giscanner/ast.py b/giscanner/ast.py
index 91faff88..6df356dd 100644
--- a/giscanner/ast.py
+++ b/giscanner/ast.py
@@ -556,6 +556,7 @@ class Callable(Node):
self.parameters = parameters
self.throws = not not throws
self.instance_parameter = None # Parameter
+ self.parent = None # A Class or Interface
def get_parameter_index(self, name):
for i, parameter in enumerate(self.parameters):
@@ -1007,6 +1008,7 @@ class Property(Node):
self.transfer = PARAM_TRANSFER_NONE
else:
self.transfer = transfer
+ self.parent = None # A Class or Interface
class Callback(Callable):
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&lt;$2&gt;/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 += "&amp;"
- 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 += "&lt;"
- 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 += "&gt;"
- 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="&lt;i&gt;Our&lt;/i&gt; 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="&lt;i&gt;Our&lt;/i&gt; 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&lt;%s&gt;" % (node.array_type, str(node.element_type))
- elif isinstance(node, ast.Map):
- return "GHashTable&lt;%s, %s&gt;" % (str(node.key_type), str(node.value_type))
- elif isinstance(node, ast.List):
- return "GList&lt;%s&gt;" % 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('&#xA0;:')
- 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
diff --git a/giscanner/docmain.py b/giscanner/docmain.py
index e6ae8b60..e3ef4ae4 100644
--- a/giscanner/docmain.py
+++ b/giscanner/docmain.py
@@ -21,39 +21,15 @@
import os
import optparse
-from .docbookwriter import DocBookWriter
-from .docbookwriter import DocBookFormatterC
-from .docbookwriter import DocBookFormatterPython
from .mallardwriter import MallardWriter
-from .mallardwriter import MallardFormatterC
-from .mallardwriter import MallardFormatterPython
from .transformer import Transformer
-class GIDocGenerator(object):
-
- def parse(self, filename):
- if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
- top_srcdir = os.environ['UNINSTALLED_INTROSPECTION_SRCDIR']
- top_builddir = os.environ['UNINSTALLED_INTROSPECTION_BUILDDIR']
- extra_include_dirs = [os.path.join(top_srcdir, 'gir'), top_builddir]
- else:
- extra_include_dirs = []
- self.transformer = Transformer.parse_from_gir(filename, extra_include_dirs)
-
- def generate(self, writer, output):
- writer.add_transformer(self.transformer)
- writer.write(output)
-
def doc_main(args):
parser = optparse.OptionParser('%prog [options] GIR-file')
parser.add_option("-o", "--output",
action="store", dest="output",
help="Filename to write output")
- parser.add_option("-f", "--format",
- action="store", dest="format",
- default="docbook",
- help="Output format")
parser.add_option("-l", "--language",
action="store", dest="language",
default="Python",
@@ -66,28 +42,15 @@ def doc_main(args):
if len(args) < 2:
raise SystemExit("Need an input GIR filename")
- if options.format == "docbook":
- if options.language == "Python":
- formatter = DocBookFormatterPython()
- elif options.language == "C":
- formatter = DocBookFormatterC()
- else:
- raise SystemExit("Unsupported language: %s" % (options.language, ))
- writer = DocBookWriter(formatter)
- elif options.format == "mallard":
- if options.language == "Python":
- formatter = MallardFormatterPython()
- elif options.language == "C":
- formatter = MallardFormatterC()
- else:
- raise SystemExit("Unsupported language: %s" % (options.language, ))
- writer = MallardWriter(formatter)
+ if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
+ top_srcdir = os.environ['UNINSTALLED_INTROSPECTION_SRCDIR']
+ top_builddir = os.environ['UNINSTALLED_INTROSPECTION_BUILDDIR']
+ extra_include_dirs = [os.path.join(top_srcdir, 'gir'), top_builddir]
else:
- raise SystemExit("Unsupported output format: %s" % (options.format, ))
-
- generator = GIDocGenerator()
- generator.parse(args[1])
+ extra_include_dirs = []
+ transformer = Transformer.parse_from_gir(args[1], extra_include_dirs)
- generator.generate(writer, options.output)
+ writer = MallardWriter(transformer, options.language)
+ writer.write(options.output)
return 0
diff --git a/giscanner/girparser.py b/giscanner/girparser.py
index 5faaf197..a59037da 100644
--- a/giscanner/girparser.py
+++ b/giscanner/girparser.py
@@ -256,27 +256,27 @@ class GIRParser(object):
for iface in self._find_children(node, _corens('prerequisite')):
obj.prerequisites.append(self._namespace.type_from_name(iface.attrib['name']))
for func_node in self._find_children(node, _corens('function')):
- func = self._parse_function_common(func_node, ast.Function)
+ func = self._parse_function_common(func_node, ast.Function, obj)
obj.static_methods.append(func)
for method in self._find_children(node, _corens('method')):
- func = self._parse_function_common(method, ast.Function)
+ func = self._parse_function_common(method, ast.Function, obj)
func.is_method = True
obj.methods.append(func)
for method in self._find_children(node, _corens('virtual-method')):
- func = self._parse_function_common(method, ast.VFunction)
+ func = self._parse_function_common(method, ast.VFunction, obj)
self._parse_generic_attribs(method, func)
func.is_method = True
func.invoker = method.get('invoker')
obj.virtual_methods.append(func)
for ctor in self._find_children(node, _corens('constructor')):
- func = self._parse_function_common(ctor, ast.Function)
+ func = self._parse_function_common(ctor, ast.Function, obj)
func.is_constructor = True
obj.constructors.append(func)
obj.fields.extend(self._parse_fields(node))
for prop in self._find_children(node, _corens('property')):
- obj.properties.append(self._parse_property(prop))
+ obj.properties.append(self._parse_property(prop, obj))
for signal in self._find_children(node, _glibns('signal')):
- obj.signals.append(self._parse_function_common(signal, ast.Signal))
+ obj.signals.append(self._parse_function_common(signal, ast.Signal, obj))
def _parse_callback(self, node):
callback = self._parse_function_common(node, ast.Callback)
@@ -286,7 +286,7 @@ class GIRParser(object):
function = self._parse_function_common(node, ast.Function)
self._namespace.append(function)
- def _parse_function_common(self, node, klass):
+ def _parse_function_common(self, node, klass, parent=None):
name = node.attrib['name']
returnnode = node.find(_corens('return-value'))
if not returnnode:
@@ -319,6 +319,7 @@ class GIRParser(object):
func.shadows = node.attrib.get('shadows', None)
func.shadowed_by = node.attrib.get('shadowed-by', None)
func.moved_to = node.attrib.get('moved-to', None)
+ func.parent = parent
parameters_node = node.find(_corens('parameters'))
if (parameters_node is not None):
@@ -377,13 +378,13 @@ class GIRParser(object):
compound.fields.extend(self._parse_fields(node))
for method in self._find_children(node, _corens('method')):
compound.methods.append(
- self._parse_function_common(method, ast.Function))
+ self._parse_function_common(method, ast.Function, compound))
for func in self._find_children(node, _corens('function')):
compound.static_methods.append(
- self._parse_function_common(func, ast.Function))
+ self._parse_function_common(func, ast.Function, compound))
for ctor in self._find_children(node, _corens('constructor')):
compound.constructors.append(
- self._parse_function_common(ctor, ast.Function))
+ self._parse_function_common(ctor, ast.Function, compound))
return compound
def _parse_record(self, node, anonymous=False):
@@ -482,15 +483,15 @@ class GIRParser(object):
if self._types_only:
return
for method in self._find_children(node, _corens('method')):
- func = self._parse_function_common(method, ast.Function)
+ func = self._parse_function_common(method, ast.Function, obj)
func.is_method = True
obj.methods.append(func)
for ctor in self._find_children(node, _corens('constructor')):
obj.constructors.append(
- self._parse_function_common(ctor, ast.Function))
+ self._parse_function_common(ctor, ast.Function, obj))
for callback in self._find_children(node, _corens('callback')):
obj.fields.append(
- self._parse_function_common(callback, ast.Callback))
+ self._parse_function_common(callback, ast.Callback, obj))
def _parse_field(self, node):
type_node = None
@@ -521,7 +522,7 @@ class GIRParser(object):
self._parse_generic_attribs(node, field)
return field
- def _parse_property(self, node):
+ def _parse_property(self, node, parent):
prop = ast.Property(node.attrib['name'],
self._parse_type(node),
node.attrib.get('readable') != '0',
@@ -530,6 +531,7 @@ class GIRParser(object):
node.attrib.get('construct-only') == '1',
node.attrib.get('transfer-ownership'))
self._parse_generic_attribs(node, prop)
+ prop.parent = parent
return prop
def _parse_member(self, node):
diff --git a/giscanner/mallard-C-class.tmpl b/giscanner/mallard-C-class.tmpl
new file mode 100644
index 00000000..2d739043
--- /dev/null
+++ b/giscanner/mallard-C-class.tmpl
@@ -0,0 +1,48 @@
+<?xml version="1.0"?>
+<page id="${node.namespace.name}.${node.name}"
+ type="guide"
+ style="class"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:api="http://projectmallard.org/experimental/api/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="index" group="class"/>
+ </info>
+ <title>${node.ctype}</title>
+${formatter.format(node.doc)}
+% if node.version:
+<p>Since ${node.version}</p>
+% endif
+ <synopsis ui:expanded="no">
+ <title>Hierarchy</title>
+ <tree>
+ <item>
+ <code>GObjectObject</code>
+ </item>
+ </tree>
+ </synopsis>
+ <links type="topic" ui:expanded="yes"
+ api:type="function" api:mime="text/x-csrc"
+ groups="constructor" style="linklist">
+ <title>Constructors</title>
+ </links>
+ <links type="topic" ui:expanded="yes"
+ api:type="function" api:mime="text/x-csrc"
+ groups="method" style="linklist">
+ <title>Methods</title>
+ </links>
+ <links type="topic" ui:expanded="yes"
+ api:type="function" api:mime="text/x-csrc"
+ groups="function" style="linklist">
+ <title>Functions</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="property" style="linklist">
+ <title>Properties</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="signal" style="linklist">
+ <title>Signals</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="#first #default #last" style="linklist">
+ <title>Other</title>
+ </links>
+</page>
diff --git a/giscanner/mallard-C-default.tmpl b/giscanner/mallard-C-default.tmpl
new file mode 100644
index 00000000..577fa566
--- /dev/null
+++ b/giscanner/mallard-C-default.tmpl
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<page id="${namespace.name}.${node.name}"
+ type="topic"
+ style=""
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ </info>
+ <title>${namespace.name}.${node.name}</title>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-C-function.tmpl b/giscanner/mallard-C-function.tmpl
new file mode 100644
index 00000000..2da4710f
--- /dev/null
+++ b/giscanner/mallard-C-function.tmpl
@@ -0,0 +1,95 @@
+<?xml version="1.0"?>
+<%
+page_style = 'function'
+if node.is_constructor:
+ page_style = 'constructor'
+elif node.is_method:
+ page_style = 'method'
+%>
+<page id="${page_id}"
+ type="topic"
+ style="${page_style}"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:api="http://projectmallard.org/experimental/api/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+% if node.parent is not None:
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="${page_style}"/>
+% else:
+ <link type="guide" xref="index" group="${page_style}"/>
+% endif
+ <api:function>
+ <api:returns>
+ <api:type>${formatter.format_type(node.retval.type) | x}</api:type>
+ </api:returns>
+ <api:name>${node.symbol}</api:name>
+% if node.is_method:
+ <api:arg>
+ <api:type>${node.parent.ctype} *</api:type>
+ <api:name>self</api:name>
+ </api:arg>
+% endif
+% for arg in node.parameters:
+% if arg.type.ctype == '<varargs>':
+ <api:varargs/>
+% else:
+ <api:arg>
+ <api:type>${formatter.format_type(arg.type) | x}</api:type>
+ <api:name>${arg.argname}</api:name>
+ </api:arg>
+% endif
+% endfor
+ </api:function>
+ </info>
+ <title>${node.symbol}</title>
+<synopsis><code mime="text/x-csrc">
+${node.retval.type.ctype} ${node.symbol} (\
+% if node.is_method:
+${node.parent.ctype} *self\
+%endif
+% if len(node.parameters) == 0:
+% if not node.is_method:
+void\
+%endif
+);
+% elif node.is_method:
+,
+% endif
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+% if ix != 0:
+${' ' * (len(formatter.format_type(node.retval.type)) + len(node.symbol) + 3)}\
+% endif
+% if arg.type.ctype == '<varargs>':
+...\
+% else:
+${formatter.format_type(arg.type) | x} ${arg.argname}\
+% endif
+% if ix == len(node.parameters) - 1:
+);
+% else:
+,
+%endif
+% endfor
+</code></synopsis>
+${formatter.format(node.doc)}
+
+% if node.parameters or node.retval:
+<table>
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+<tr>
+<td><p>${arg.argname} :</p></td>
+<td>${formatter.format(arg.doc)}</td>
+</tr>
+% endfor
+% if node.retval:
+<tr>
+<td><p>Returns :</p></td>
+<td>${formatter.format(node.retval.doc)}</td>
+</tr>
+% endif
+</table>
+% endif
+% if node.version:
+<p>Since ${node.version}</p>
+% endif
+</page>
diff --git a/giscanner/mallard-C-namespace.tmpl b/giscanner/mallard-C-namespace.tmpl
new file mode 100644
index 00000000..284ba238
--- /dev/null
+++ b/giscanner/mallard-C-namespace.tmpl
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<page id="index"
+ type="guide"
+ style="namespace"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ </info>
+ <title>${node.name} Documentation</title>
+ <links type="topic" ui:expanded="yes" groups="class" style="linklist">
+ <title>Classes</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="function" style="linklist">
+ <title>Functions</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="#first #default #last" style="linklist">
+ <title>Other</title>
+ </links>
+</page>
diff --git a/giscanner/mallard-C-property.tmpl b/giscanner/mallard-C-property.tmpl
new file mode 100644
index 00000000..2d37ba10
--- /dev/null
+++ b/giscanner/mallard-C-property.tmpl
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<page id="${namespace.name}.${node.name}"
+ type="topic"
+ style="property"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="property"/>
+ <title type="link" role="topic">${node.name}</title>
+ </info>
+ <title>${node.parent.ctype}:${node.name}</title>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-C-record.tmpl b/giscanner/mallard-C-record.tmpl
new file mode 100644
index 00000000..a173e77a
--- /dev/null
+++ b/giscanner/mallard-C-record.tmpl
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<page id="${node.namespace.name}.${node.name}"
+ type="guide"
+ style="record"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="index"/>
+ </info>
+ <title>${node.namespace.name}${node.name}</title>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-C-signal.tmpl b/giscanner/mallard-C-signal.tmpl
new file mode 100644
index 00000000..7aae3ae4
--- /dev/null
+++ b/giscanner/mallard-C-signal.tmpl
@@ -0,0 +1,13 @@
+<?xml version="1.0"?>
+<page id="${namespace.name}.${node.name}"
+ type="topic"
+ style="signal"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="signal"/>
+ <title type="link" role="topic">${node.name}</title>
+ </info>
+ <title>${node.parent.ctype}::${node.name}</title>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-Python-class.tmpl b/giscanner/mallard-Python-class.tmpl
new file mode 100644
index 00000000..62feb9ab
--- /dev/null
+++ b/giscanner/mallard-Python-class.tmpl
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<page id="${node.namespace.name}.${node.name}"
+ type="guide"
+ style="class"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:api="http://projectmallard.org/experimental/api/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="index" group="class"/>
+ </info>
+ <title>${namespace.name}.${node.name}</title>
+${formatter.format(node.doc)}
+
+ <synopsis><code>
+from gi.repository import ${namespace.name}
+
+${formatter.to_underscores(node.name).lower()} = ${namespace.name}.${node.name}(\
+% for property_, ix in zip(node.properties, range(len(node.properties))):
+% if property_.construct or property_.construct_only or property_.writable:
+<link xref='${namespace.name}.${node.name}-${property_.name}'>${property_.name.replace('-', '_')}</link>=value\
+% if ix != len(node.properties) - 1:
+, \
+% endif
+% endif
+% endfor
+)\
+ </code></synopsis>
+
+% if node.version:
+<p>Since ${node.version}</p>
+% endif
+ <synopsis>
+ <title>Hierarchy</title>
+ <tree>
+% for class_ in formatter.get_class_hierarchy(node):
+ <item>
+ <code>${class_.namespace.name}.${class_.name}</code>
+% endfor
+% for class_ in formatter.get_class_hierarchy(node):
+ </item>
+% endfor
+ </tree>
+ </synopsis>
+ <links type="topic" ui:expanded="yes"
+ api:type="function" api:mime="text/x-python"
+ groups="method" style="linklist">
+ <title>Methods</title>
+ </links>
+ <links type="topic" ui:expanded="yes"
+ api:type="function" api:mime="text/x-python"
+ groups="function" style="linklist">
+ <title>Functions</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="property" style="linklist">
+ <title>Properties</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="signal" style="linklist">
+ <title>Signals</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="#first #default #last" style="linklist">
+ <title>Other</title>
+ </links>
+</page>
diff --git a/giscanner/mallard-Python-default.tmpl b/giscanner/mallard-Python-default.tmpl
new file mode 100644
index 00000000..683adf6a
--- /dev/null
+++ b/giscanner/mallard-Python-default.tmpl
@@ -0,0 +1,11 @@
+<?xml version="1.0"?>
+<page id="${page_id}"
+ type="topic"
+ style=""
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ </info>
+ <title>${namespace.name}.${node.name}</title>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-Python-enum.tmpl b/giscanner/mallard-Python-enum.tmpl
new file mode 100644
index 00000000..fd6ca0fb
--- /dev/null
+++ b/giscanner/mallard-Python-enum.tmpl
@@ -0,0 +1,23 @@
+<?xml version="1.0"?>
+<page id="${node.namespace.name}.${node.name}"
+ type="guide"
+ style="enum"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="index"/>
+ </info>
+ <title>${node.namespace.name}.${node.name}</title>
+ ${formatter.format(node.doc)}
+% if node.members:
+<table>
+% for member, ix in zip(node.members, range(len(node.members))):
+<tr>
+<td><p>${node.name}.${member.name.upper()} :</p></td>
+<td>${formatter.format(member.doc)}</td>
+</tr>
+% endfor
+</table>
+% endif
+
+</page>
diff --git a/giscanner/mallard-Python-function.tmpl b/giscanner/mallard-Python-function.tmpl
new file mode 100644
index 00000000..7aa25e8e
--- /dev/null
+++ b/giscanner/mallard-Python-function.tmpl
@@ -0,0 +1,88 @@
+<?xml version="1.0"?>
+<%
+page_style = 'function'
+if node.is_constructor:
+ page_style = 'constructor'
+elif node.is_method:
+ page_style = 'method'
+%>
+<page id="${page_id}"
+ type="topic"
+ style="${page_style}"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:api="http://projectmallard.org/experimental/api/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+% if node.parent is not None:
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="${page_style}"/>
+% else:
+ <link type="guide" xref="index" group="${page_style}"/>
+% endif
+ <api:function>
+ <api:returns>
+ <api:type>${formatter.format_type(node.retval.type) | x}</api:type>
+ </api:returns>
+ <api:name>${node.symbol}</api:name>
+% if node.is_method:
+ <api:arg>
+ <api:type>${node.parent.ctype} *</api:type>
+ <api:name>self</api:name>
+ </api:arg>
+% endif
+% for arg in node.parameters:
+% if arg.type.ctype == '<varargs>':
+ <api:varargs/>
+% else:
+ <api:arg>
+ <api:type>${formatter.format_type(arg.type) | x}</api:type>
+ <api:name>${arg.argname}</api:name>
+ </api:arg>
+% endif
+% endfor
+ </api:function>
+ </info>
+ <title>${node.name}</title>
+<synopsis><code mime="text/x-python">
+% if len(node.parameters) != 0:
+@accepts(\
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+${formatter.format_type(arg.type) | x}\
+% if ix != len(node.parameters) - 1:
+, \
+%endif
+% endfor
+)
+% endif
+@returns(${formatter.format_type(node.retval.type) | x})
+def \
+${node.name}(\
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+${arg.argname}\
+% if ix != len(node.parameters) - 1:
+, \
+%endif
+% endfor
+)
+</code></synopsis>
+${formatter.format(node.doc)}
+
+% if node.parameters or node.retval:
+<table>
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+<tr>
+<td><p>${arg.argname} :</p></td>
+<td>${formatter.format(arg.doc)}</td>
+</tr>
+% endfor
+% if node.retval and node.retval.type.ctype != 'void':
+<tr>
+<td><p>Returns :</p></td>
+<td>${formatter.format(node.retval.doc)}</td>
+</tr>
+% endif
+</table>
+% endif
+% if node.version:
+<p>Since ${node.version}</p>
+% endif
+</page>
diff --git a/giscanner/mallard-Python-namespace.tmpl b/giscanner/mallard-Python-namespace.tmpl
new file mode 100644
index 00000000..935cd440
--- /dev/null
+++ b/giscanner/mallard-Python-namespace.tmpl
@@ -0,0 +1,19 @@
+<?xml version="1.0"?>
+<page id="index"
+ type="guide"
+ style="namespace"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ </info>
+ <title>${node.name} Documentation</title>
+ <links type="topic" ui:expanded="yes" groups="class">
+ <title>Classes</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="function">
+ <title>Functions</title>
+ </links>
+ <links type="topic" ui:expanded="yes" groups="#first #default #last">
+ <title>Other</title>
+ </links>
+</page>
diff --git a/giscanner/mallard-Python-property.tmpl b/giscanner/mallard-Python-property.tmpl
new file mode 100644
index 00000000..c4d2229e
--- /dev/null
+++ b/giscanner/mallard-Python-property.tmpl
@@ -0,0 +1,16 @@
+<?xml version="1.0"?>
+<page id="${namespace.name}.${node.parent.name}-${node.name}"
+ type="topic"
+ style="property"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="property"/>
+ <title type="link" role="topic">${node.name}</title>
+ </info>
+ <title>${namespace.name}.${node.parent.name}:${node.name}</title>
+<synopsis><code mime="text/x-python">
+"${node.name}" ${formatter.format_type(node.type)} : ${formatter.format_property_flags(node)}
+</code></synopsis>
+${formatter.format(node.doc)}
+</page>
diff --git a/giscanner/mallard-Python-record.tmpl b/giscanner/mallard-Python-record.tmpl
new file mode 100644
index 00000000..1b00e3be
--- /dev/null
+++ b/giscanner/mallard-Python-record.tmpl
@@ -0,0 +1,12 @@
+<?xml version="1.0"?>
+<page id="${node.namespace.name}.${node.name}"
+ type="guide"
+ style="record"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="index"/>
+ </info>
+ <title>${node.namespace.name}${node.name}</title>
+ <p>${node.doc}</p>
+</page>
diff --git a/giscanner/mallard-Python-signal.tmpl b/giscanner/mallard-Python-signal.tmpl
new file mode 100644
index 00000000..7dcbb0cd
--- /dev/null
+++ b/giscanner/mallard-Python-signal.tmpl
@@ -0,0 +1,50 @@
+<?xml version="1.0"?>
+<page id="${namespace.name}.${node.parent.name}-${node.name}"
+ type="topic"
+ style="signal"
+ xmlns="http://projectmallard.org/1.0/"
+ xmlns:ui="http://projectmallard.org/experimental/ui/">
+ <info>
+ <link type="guide" xref="${namespace.name}.${node.parent.name}" group="signal"/>
+ <title type="link" role="topic">${node.name}</title>
+ </info>
+ <title>${namespace.name}.${node.parent.name}::${node.name}</title>
+<synopsis><code mime="text/x-python">
+def callback(\
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+${arg.argname}, \
+% endfor
+user_param1, ...)
+</code></synopsis>
+${formatter.format(node.doc)}
+
+% if node.parameters or node.retval:
+<table>
+% for arg, ix in zip(node.parameters, range(len(node.parameters))):
+<tr>
+<td><p>${arg.argname} :</p></td>
+<td>${formatter.format(arg.doc)}</td>
+</tr>
+% endfor
+<tr>
+<td><p>user_param1 :</p></td>
+<td><p>first user parameter (if any) specified with the connect() method</p></td>
+</tr>
+<tr>
+<td><p>... :</p></td>
+<td><p>additional user parameters (if any)</p></td>
+</tr>
+% if node.retval and \
+ node.retval.type.ctype != 'void' and \
+ node.retval.type.ctype is not None:
+<tr>
+<td><p>Returns :</p></td>
+<td>${node.retval.type.ctype} ${formatter.format(node.retval.doc)}</td>
+</tr>
+% endif
+</table>
+% endif
+% if node.version:
+<p>Since ${node.version}</p>
+% endif
+</page>
diff --git a/giscanner/mallardwriter.py b/giscanner/mallardwriter.py
index a71528e9..5fd97048 100644
--- a/giscanner/mallardwriter.py
+++ b/giscanner/mallardwriter.py
@@ -21,465 +21,225 @@
# 02110-1301, USA.
#
-import os.path
+import os
import re
-import sys
+import tempfile
-from . import ast
-from .girparser import GIRParser
-from .xmlwriter import XMLWriter
+from xml.sax import saxutils
+from mako.template import Template
+from mako.runtime import supports_caller
-XMLNS = "http://projectmallard.org/1.0/"
-XMLNS_UI = "http://projectmallard.org/experimental/ui/"
+from . import ast
+from .utils import to_underscores
def _space(num):
return " " * num
class MallardFormatter(object):
- def __init__(self):
- pass
-
- def get_title(self, node, parent):
- raise NotImplementedError('get_title not implemented')
-
- # FIXME
- 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 param.type.target_fundamental == '<varargs>':
- extra_content = "..."
- continue
- extra_content = " "
- if param.type.ctype is not None and '*' in param.type.ctype:
- extra_content += '*'
- if param.argname is None:
- import pdb
- pdb.set_trace()
- extra_content += param.argname
- extra_content += comma
- self._render_parameter(param, extra_content)
+ def __init__(self, transformer):
+ self._transformer = transformer
- self._writer.write_line(");\n")
+ def escape(self, text):
+ return saxutils.escape(text.encode('utf-8')).decode('utf-8')
- def get_method_as_title(self, entity):
- method = entity.get_ast()
- return "%s ()" % method.symbol
+ def format(self, doc):
+ if doc is None:
+ return ''
- def get_page_name(self, node):
- if node.gtype_name is None:
- return node.ctype
- return node.gtype_name
+ result = ''
+ for para in doc.split('\n\n'):
+ result += '<p>'
+ result += self.format_inline(para)
+ result += '</p>'
+ return result
- def get_class_name(self, node):
- if node.gtype_name is None:
- return node.ctype
- return node.gtype_name
+ def format_inline(self, para):
+ result = ''
- def get_type_name(self, node):
- if isinstance(node, ast.Array):
- if node.array_type == ast.Array.C:
- return str(node.element_type) + "[]"
+ poss = []
+ poss.append((para.find('#'), '#'))
+ poss = [pos for pos in poss if pos[0] >= 0]
+ poss.sort(cmp=lambda x, y: cmp(x[0], y[0]))
+ if len(poss) == 0:
+ result += self.escape(para)
+ elif poss[0][1] == '#':
+ pos = poss[0][0]
+ result += self.escape(para[:pos])
+ rest = para[pos + 1:]
+ link = re.split('[^a-zA-Z_:-]', rest, maxsplit=1)[0]
+ if link.endswith(':'):
+ link = link[:-1]
+ namespace = self._transformer.namespace
+ if '::' in link:
+ type_name, signal_name = link.split('::')
+ if type_name in namespace.ctypes:
+ type_ = namespace.get_by_ctype(type_name)
+ xref = '%s.%s-%s' % (namespace.name, type_.name, signal_name)
+ xref_name = '%s.%s::%s' % (namespace.name, type_.name, signal_name)
+ else:
+ xref = link
+ xref_name = link
+ elif ':' in link:
+ type_name, property_name = link.split(':')
+ if type_name in namespace.ctypes:
+ type_ = namespace.get_by_ctype(type_name)
+ xref = '%s.%s-%s' % (namespace.name, type_.name, property_name)
+ xref_name = '%s.%s:%s' % (namespace.name, type_.name, property_name)
+ else:
+ xref = link
+ xref_name = link
+ elif link in namespace.ctypes:
+ type_ = namespace.get_by_ctype(link)
+ xref = '%s.%s' % (namespace.name, type_.name)
+ xref_name = xref
else:
- return "%s&lt;%s&gt;" % (node.array_type, str(node.element_type))
- elif isinstance(node, ast.Map):
- return "GHashTable&lt;%s, %s&gt;" % (str(node.key_type), str(node.value_type))
- elif isinstance(node, ast.List):
- return "GList&lt;%s&gt;" % str(node.element_type)
- else:
- return str(node)
-
- def render_method(self, entity, link=False):
- method = entity.get_ast()
- 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 retval_type.ctype is not None and '*' 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:
- annotations['element-type'] = argument.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, entity):
- method = entity.get_ast()
-
- self._render_param(method.parent_class.name.lower(), 'instance', [])
-
- for param in method.parameters:
- self._render_param(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):
- if argname is None:
- return
- 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('&#xA0;:')
- 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()
+ xref = link
+ xref_name = link
+ result += '<link xref="%s">%s</link>' % (xref, xref_name)
+ if len(link) < len(rest):
+ result += self.format_inline(rest[len(link):])
- def render_property(self, entity, link=False):
- prop = entity.get_ast()
+ return result
- prop_name = '"%s"' % prop.name
- prop_type = self.get_type_name(prop.type)
+ def format_type(self, type_):
+ raise NotImplementedError
+ def format_property_flags(self, property_):
flags = []
- if prop.readable:
+ if property_.readable:
flags.append("Read")
- if prop.writable:
+ if property_.writable:
flags.append("Write")
- if prop.construct:
+ if property_.construct:
flags.append("Construct")
- if prop.construct_only:
+ if property_.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)
+ return " / ".join(flags)
- self._writer.write_line(line + "\n")
+ def to_underscores(self, string):
+ return to_underscores(string)
- self._writer.enable_whitespace()
+ def get_class_hierarchy(self, node):
+ parent_chain = []
+ while node.parent:
+ node = self._transformer.lookup_giname(str(node.parent))
+ parent_chain.append(node)
- def render_signal(self, entity, link=False):
- signal = entity.get_ast()
-
- sig_name = '"%s"' % signal.name
- flags = ["TODO: signal flags not in GIR currently"]
- self._render_prop_or_signal(sig_name, "", flags)
+ parent_chain.reverse()
+ return parent_chain
class MallardFormatterC(MallardFormatter):
- def get_title(self, node, parent):
- if isinstance(node, ast.Namespace):
- return "%s Documentation" % node.name
- elif isinstance(node, ast.Function):
- return node.symbol
- elif isinstance(node, ast.Property):
- return parent.c_name + ':' + node.name
- elif isinstance(node, ast.Signal):
- return parent.c_name + '::' + node.name
- else:
- return node.c_name
-class MallardFormatterPython(MallardFormatter):
- def get_title(self, node, parent):
- if isinstance(node, ast.Namespace):
- return "%s Documentation" % node.name
- elif isinstance(node, ast.Function):
- if node.is_method or node.is_constructor:
- return "%s.%s.%s" % (node.namespace.name, parent.name, node.name)
- else:
- return "%s.%s" % (node.namespace.name, node.name)
- elif isinstance(node, ast.Property):
- return "%s" % node.name
- elif isinstance(node, ast.Signal):
- return "%s" % node.name
+ def format_type(self, type_):
+ if isinstance(type_, ast.Array):
+ try:
+ return self.format_type(type_.element_type) + '*'
+ except:
+ return type_.target_fundamental
+ elif type_.ctype is not None:
+ return type_.ctype
else:
- return "%s.%s" % (node.namespace.name, node.name)
-
-class MallardPage(object):
- def __init__(self, writer, node, parent):
- self.writer = writer
- self.node = node
- self.parent = parent
- self.page_id = None
- self.page_type = 'topic'
- self.page_style = ''
+ return type_.target_fundamental
- node.page = self
- if not isinstance(node, ast.Namespace):
- if node.namespace is None:
- if parent is not None and parent.namespace is not None:
- node.namespace = parent.namespace
-
- self.title = writer._formatter.get_title(node, parent)
- self.links = []
- self.linksels = []
+class MallardFormatterPython(MallardFormatter):
- if isinstance(node, ast.Namespace):
- self.page_id = 'index'
- elif isinstance(node, ast.Property) and parent is not None:
- self.page_id = node.namespace.name + '.' + parent.name + '-' + node.name
- elif isinstance(node, ast.Signal) and parent is not None:
- self.page_id = node.namespace.name + '.' + parent.name + '--' + node.name
- elif parent is not None and not isinstance(parent, ast.Namespace):
- self.page_id = node.namespace.name + '.' + parent.name + '.' + node.name
+ def format_type(self, type_):
+ if isinstance(type_, ast.Array):
+ return '[' + self.format_type(type_.element_type) + ']'
+ elif isinstance(type_, ast.Map):
+ return '{%s: %s}' % (self.format_type(type_.key_type),
+ self.format_type(type_.value_type))
+ elif type_.target_giname is not None:
+ return type_.target_giname
else:
- self.page_id = node.namespace.name + '.' + node.name
-
- if getattr(node, 'symbol', None) is not None:
- self.writer._xrefs[node.symbol] = self.page_id
- elif isinstance(node, ast.Class):
- self.writer._xrefs[node.c_name] = self.page_id
-
- self.create_content()
- self.add_child_nodes()
-
- def add_link(self, linktype, xref, group=None):
- self.links.append((linktype, xref, group))
-
- def add_child_nodes(self):
- children = []
- if isinstance(self.node, ast.Namespace):
- children = [node for node in self.node.itervalues()]
- elif isinstance(self.node, (ast.Class, ast.Record)):
- children = self.node.methods + self.node.constructors
- elif isinstance(self.node, ast.Interface):
- children = self.node.methods
-
- if isinstance(self.node, (ast.Class, ast.Interface)):
- children += self.node.properties + self.node.signals
- for child in children:
- self.writer._pages.append(MallardPage(self.writer, child, self.node))
+ return type_.target_fundamental
- def create_content(self):
- if isinstance(self.node, ast.Namespace):
- self.page_type = 'guide'
- self.page_style = 'namespace'
- self.linksels = (('class', 'Classes'),
- ('function', 'Functions'),
- ('#first #default #last', 'Other'))
- elif isinstance(self.node, ast.Class):
- self.page_type = 'guide'
- self.page_style = 'class'
- self.linksels = (('constructor', 'Constructors'),
- ('method', 'Methods'),
- ('property', 'Properties'),
- ('signal', 'Signals'),
- ('#first #default #last', 'Other'))
- self.add_link('guide', self.parent.page.page_id, 'class')
- elif isinstance(self.node, ast.Record):
- self.page_type = 'guide'
- self.page_style = 'record'
- self.add_link('guide', self.parent.page.page_id)
- elif isinstance(self.node, ast.Interface):
- self.page_type = 'guide'
- self.page_style = 'interface'
- self.add_link('guide', self.parent.page.page_id)
- elif isinstance(self.node, ast.Function):
- if self.node.is_constructor:
- self.page_style = 'constructor'
- self.add_link('guide', self.parent.page.page_id, 'constructor')
- elif self.node.is_method:
- self.page_style = 'method'
- self.add_link('guide', self.parent.page.page_id, 'method')
- else:
- self.page_style = 'function'
- self.add_link('guide', self.parent.page.page_id, 'function')
- elif isinstance(self.node, ast.Property):
- self.page_style = 'property'
- self.add_link('guide', self.parent.page.page_id, 'property')
- elif isinstance(self.node, ast.Signal):
- self.page_style = 'signal'
- self.add_link('guide', self.parent.page.page_id, 'signal')
-
- def render(self, writer):
- with writer.tagcontext('page', [
- ('id', self.page_id),
- ('type', self.page_type),
- ('style', self.page_style),
- ('xmlns', XMLNS), ('xmlns:ui', XMLNS_UI)]):
- with writer.tagcontext('info'):
- for linktype, xref, group in self.links:
- if group is not None:
- writer.write_tag('link', [
- ('type', linktype), ('xref', xref), ('group', group)])
- else:
- writer.write_tag('link', [
- ('type', linktype), ('xref', xref)])
- writer.write_tag('title', [], self.title)
- if isinstance(self.node, ast.Annotated):
- self.render_doc(writer, self.node.doc)
- if isinstance(self.node, ast.Class):
- parent_chain = []
- node = self.node
- while node.parent:
- node = self.writer._transformer.lookup_giname(str(node.parent))
- parent_chain.append(node)
- if node.namespace.name == 'GObject' and node.name == 'Object':
- break
- parent_chain.reverse()
- def print_chain(chain):
- with writer.tagcontext('item', []):
- attrs = []
- title = self.writer._formatter.get_title(chain[0], None)
- if hasattr(chain[0], 'page'):
- attrs.append(('xref', chain[0].page.page_id))
- writer.write_tag('code', attrs, title)
- if len(chain) > 1:
- print_chain(chain[1:])
- with writer.tagcontext('synopsis', [('ui:expanded', 'no')]):
- writer.write_tag('title', [], 'Hierarchy')
- with writer.tagcontext('tree', []):
- print_chain(parent_chain)
- for linkstype, title in self.linksels:
- with writer.tagcontext('links', [
- ('type', 'topic'), ('ui:expanded', 'yes'),
- ('groups', linkstype)]):
- writer.write_tag('title', [], title)
-
- def render_doc(self, writer, doc):
- if doc is not None:
- for para in doc.split('\n\n'):
- writer.disable_whitespace()
- with writer.tagcontext('p', []):
- self.render_doc_inline(writer, para)
- writer.enable_whitespace()
-
- def render_doc_inline(self, writer, text):
- poss = []
- poss.append((text.find('#'), '#'))
- poss = [pos for pos in poss if pos[0] >= 0]
- poss.sort(cmp=lambda x, y: cmp(x[0], y[0]))
- if len(poss) == 0:
- writer.write_line(text, do_escape=True)
- elif poss[0][1] == '#':
- pos = poss[0][0]
- writer.write_line(text[:pos], do_escape=True)
- rest = text[pos + 1:]
- link = re.split('[^a-zA-Z_:-]', rest, maxsplit=1)[0]
- xref = self.writer._xrefs.get(link, link)
- writer.write_tag('link', [('xref', xref)], link)
- if len(link) < len(rest):
- self.render_doc_inline(writer, rest[len(link):])
+ def format(self, doc):
+ doc = MallardFormatter.format(self, doc)
+ doc = doc.replace('%NULL', 'None')
+ doc = doc.replace('%TRUE', 'True')
+ doc = doc.replace('%FALSE', 'False')
+ return doc
class MallardWriter(object):
- def __init__(self, formatter):
- self._namespace = None
- self._index = None
- self._pages = []
- self._formatter = formatter
- self._xrefs = {}
-
- def add_transformer(self, transformer):
+ def __init__(self, transformer, language):
self._transformer = transformer
- self._namespace = self._transformer._namespace
- self._index = MallardPage(self, self._namespace, None)
-
- def write(self, output):
- xmlwriter = XMLWriter()
- self._index.render(xmlwriter)
- fp = open(output, 'w')
- fp.write(xmlwriter.get_xml())
- fp.close()
+ self._language = language
- for page in self._pages:
- xmlwriter = XMLWriter()
- page.render(xmlwriter)
- fp = open(os.path.join(os.path.dirname(output), page.page_id + '.page'), 'w')
- fp.write(xmlwriter.get_xml())
- fp.close()
-
- def _render_page_object_hierarchy(self, page_node):
- parent_chain = self._get_parent_chain(page_node)
- parent_chain.append(page_node)
- lines = []
+ if self._language == 'C':
+ self._formatter = MallardFormatterC(self._transformer)
+ elif self._language == 'Python':
+ self._formatter = MallardFormatterPython(self._transformer)
+ else:
+ raise SystemExit("Unsupported language: %s" % language)
- 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))
+ def write(self, output):
+ nodes = [self._transformer.namespace]
+ for node in self._transformer.namespace.itervalues():
+ if isinstance(node, ast.Function) and node.moved_to is not None:
+ continue
+ if getattr(node, 'disguised', False):
+ continue
+ nodes.append(node)
+ if isinstance(node, (ast.Class, ast.Interface, ast.Record)):
+ nodes += getattr(node, 'methods', [])
+ nodes += getattr(node, 'constructors', [])
+ nodes += getattr(node, 'static_methods', [])
+ nodes += getattr(node, 'virtual_methods', [])
+ nodes += getattr(node, 'properties', [])
+ nodes += getattr(node, 'signals', [])
+ for node in nodes:
+ self._render_node(node, output)
+
+ def _render_node(self, node, output):
+ namespace = self._transformer.namespace
+ if isinstance(node, ast.Namespace):
+ template_name = 'mallard-%s-namespace.tmpl' % self._language
+ page_id = 'index'
+ elif isinstance(node, (ast.Class, ast.Interface)):
+ template_name = 'mallard-%s-class.tmpl' % self._language
+ page_id = '%s.%s' % (namespace.name, node.name)
+ elif isinstance(node, ast.Record):
+ template_name = 'mallard-%s-record.tmpl' % self._language
+ page_id = '%s.%s' % (namespace.name, node.name)
+ elif isinstance(node, ast.Function):
+ template_name = 'mallard-%s-function.tmpl' % self._language
+ if node.parent is not None:
+ page_id = '%s.%s.%s' % (namespace.name, node.parent.name, node.name)
+ else:
+ page_id = '%s.%s' % (namespace.name, node.name)
+ elif isinstance(node, ast.Enum):
+ template_name = 'mallard-%s-enum.tmpl' % self._language
+ page_id = '%s.%s' % (namespace.name, node.name)
+ elif isinstance(node, ast.Property) and node.parent is not None:
+ template_name = 'mallard-%s-property.tmpl' % self._language
+ page_id = '%s.%s-%s' % (namespace.name, node.parent.name, node.name)
+ elif isinstance(node, ast.Signal) and node.parent is not None:
+ template_name = 'mallard-%s-signal.tmpl' % self._language
+ page_id = '%s.%s-%s' % (namespace.name, node.parent.name, node.name)
+ else:
+ template_name = 'mallard-%s-default.tmpl' % self._language
+ page_id = '%s.%s' % (namespace.name, node.name)
- self._writer.disable_whitespace()
- self._writer.write_line("\n".join(lines))
- self._writer.enable_whitespace()
+ if 'UNINSTALLED_INTROSPECTION_SRCDIR' in os.environ:
+ top_srcdir = os.environ['UNINSTALLED_INTROSPECTION_SRCDIR']
+ template_dir = os.path.join(top_srcdir, 'giscanner')
+ else:
+ template_dir = os.path.dirname(__file__)
+
+ file_name = os.path.join(template_dir, template_name)
+ file_name = os.path.abspath(file_name)
+ template = Template(filename=file_name, output_encoding='utf-8',
+ module_directory=tempfile.gettempdir())
+ result = template.render(namespace=namespace,
+ node=node,
+ page_id=page_id,
+ formatter=self._formatter)
+
+ output_file_name = os.path.join(os.path.dirname(output),
+ page_id + '.page')
+ fp = open(output_file_name, 'w')
+ fp.write(result)
+ fp.close()