root/branches/gajim_0.11.1/src/common/rst_xhtml_generator.py

Revision 8665, 5.0 kB (checked in by asterix, 15 months ago)

[sgala and I] better support of sizes in XHTML, simplify rst generator

Line 
1##      rst_xhtml_generator.py
2##
3## Copyright (C) 2006 Yann Le Boulanger <asterix@lagaule.org>
4## Copyright (C) 2006 Nikos Kouremenos <kourem@gmail.com>
5## Copyright (C) 2006 Santiago Gala
6##
7## This program is free software; you can redistribute it and/or modify
8## it under the terms of the GNU General Public License as published
9## by the Free Software Foundation; version 2 only.
10##
11## This program is distributed in the hope that it will be useful,
12## but WITHOUT ANY WARRANTY; without even the implied warranty of
13## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14## GNU General Public License for more details.
15##
16
17try:
18        from docutils import io
19        from docutils.core import Publisher
20        from docutils.parsers.rst import roles
21        from docutils import nodes,utils
22        from docutils.parsers.rst.roles import set_classes
23except:
24        print "Requires docutils 0.4 for set_classes to be available"
25        def create_xhtml(text):
26                return None
27else:
28        def pos_int_validator(text):
29                """Validates that text can be evaluated as a positive integer."""
30                result = int(text)
31                if result < 0:
32                        raise ValueError("Error: value '%(text)s' "
33                                                        "must be a positive integer")
34                return result
35
36        def generate_uri_role( role_name, aliases,
37                                        anchor_text, base_url,
38                                        interpret_url, validator):
39                '''Creates and register a uri based "interpreted role".
40
41                Those are similar to the RFC, and PEP ones, and take
42                role_name:
43                        name that will be registered
44                aliases:
45                        list of alternate names
46                anchor_text:
47                        text that will be used, together with the role
48                base_url:
49                        base url for the link
50                interpret_url:
51                        this, modulo the validated text, will be added to it
52                validator:
53                        should return the validated text, or raise ValueError
54                '''
55                def uri_reference_role(role, rawtext, text, lineno, inliner,
56                        options={}, content=[]):
57                        try:
58                                valid_text = validator(text)
59                        except ValueError, e:
60                                msg = inliner.reporter.error( e.message % dict(text=text), line=lineno)
61                                prb = inliner.problematic(rawtext, rawtext, msg)
62                                return [prb], [msg]
63                        ref = base_url + interpret_url % valid_text
64                        set_classes(options)
65                        node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref,
66                                        **options)
67                        return [node], []
68
69                uri_reference_role.__doc__ = """Role to make handy references to URIs.
70
71                        Use as :%(role_name)s:`71` (or any of %(aliases)s).
72                        It will use %(base_url)s+%(interpret_url)s
73                        validator should throw a ValueError, containing optionally
74                        a %%(text)s format, if the interpreted text is not valid.
75                        """ % locals()
76                roles.register_canonical_role(role_name, uri_reference_role)
77                from docutils.parsers.rst.languages import en
78                en.roles[role_name] = role_name
79                for alias in aliases:
80                        en.roles[alias] = role_name
81
82        generate_uri_role('xep-reference', ('jep', 'xep'),
83                                'XEP #', 'http://www.xmpp.org/extensions/', 'xep-%04d.html',
84                                pos_int_validator)
85        generate_uri_role('gajim-ticket-reference', ('ticket','gtrack'),
86                                'Gajim Ticket #', 'http://trac.gajim.org/ticket/', '%d',
87                                pos_int_validator)
88
89        class HTMLGenerator:
90                '''Really simple HTMLGenerator starting from publish_parts.
91
92                It reuses the docutils.core.Publisher class, which means it is *not*
93                threadsafe.
94                '''
95                def __init__(self,
96                        settings_spec=None,
97                        settings_overrides=dict(report_level=5, halt_level=5),
98                        config_section='general'):
99                        self.pub = Publisher(reader=None, parser=None, writer=None,
100                                settings=None,
101                                source_class=io.StringInput,
102                                destination_class=io.StringOutput)
103                        self.pub.set_components(reader_name='standalone',
104                                parser_name='restructuredtext',
105                                writer_name='html')
106                        # hack: JEP-0071 does not allow HTML char entities, so we hack our way
107                        # out of it.
108                        # &mdash; == u"\u2014"
109                        # a setting to only emit charater entities in the writer would be nice
110                        # FIXME: several &nbsp; are emitted, and they are explicitly forbidden
111                        # in the JEP
112                        # &nbsp; ==  u"\u00a0"
113                        self.pub.writer.translator_class.attribution_formats['dash'] = (
114                                u'\u2014', '')
115                        self.pub.process_programmatic_settings(settings_spec,
116                                settings_overrides,
117                                config_section)
118
119
120                def create_xhtml(self, text,
121                        destination=None,
122                        destination_path=None,
123                        enable_exit_status=None):
124                        ''' Create xhtml for a fragment of IM dialog.
125                        We can use the source_name to store info about
126                        the message.'''
127                        self.pub.set_source(text, None)
128                        self.pub.set_destination(destination, destination_path)
129                        output = self.pub.publish(enable_exit_status=enable_exit_status)
130                        # kludge until we can get docutils to stop generating (rare) &nbsp;
131                        # entities
132                        return u'\u00a0'.join(self.pub.writer.parts['fragment'].strip().split(
133                                '&nbsp;'))
134
135        Generator = HTMLGenerator()
136
137        def create_xhtml(text):
138                return Generator.create_xhtml(text)
139       
140
141if __name__ == '__main__':
142        print "test 1\n", Generator.create_xhtml("""
143test::
144
145>>> print 1
1461
147
148*I* like it. It is for :JEP:`71`
149
150this `` should    trigger`` should trigger the &nbsp; problem.
151
152""")
153        print "test 2\n", Generator.create_xhtml("""
154*test1
155
156test2_
157""")
158        print "test 3\n", Generator.create_xhtml(""":ticket:`316` implements :xep:`71`""")
Note: See TracBrowser for help on using the browser.