170 lines
6.5 KiB
Python
170 lines
6.5 KiB
Python
# -*- coding:utf-8 -*-
|
|
## src/common/rst_xhtml_generator.py
|
|
##
|
|
## Copyright (C) 2006 Santiago Gala
|
|
## Nikos Kouremenos <kourem AT gmail.com>
|
|
## Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org>
|
|
## Copyright (C) 2007 Jean-Marie Traissard <jim AT lapin.org>
|
|
##
|
|
## This file is part of Gajim.
|
|
##
|
|
## Gajim 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; version 3 only.
|
|
##
|
|
## Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.
|
|
##
|
|
|
|
try:
|
|
from docutils import io
|
|
from docutils.core import Publisher
|
|
from docutils.parsers.rst import roles
|
|
from docutils import nodes, utils
|
|
from docutils.parsers.rst.roles import set_classes
|
|
except ImportError:
|
|
print("Requires docutils 0.4 for set_classes to be available")
|
|
def create_xhtml(text):
|
|
return None
|
|
else:
|
|
def pos_int_validator(text):
|
|
"""
|
|
Validates that text can be evaluated as a positive integer
|
|
"""
|
|
result = int(text)
|
|
if result < 0:
|
|
raise ValueError("Error: value '%(text)s' "
|
|
"must be a positive integer")
|
|
return result
|
|
|
|
def generate_uri_role( role_name, aliases, anchor_text, base_url,
|
|
interpret_url, validator):
|
|
"""
|
|
Create and register a uri based "interpreted role"
|
|
|
|
Those are similar to the RFC, and PEP ones, and take
|
|
role_name:
|
|
name that will be registered
|
|
aliases:
|
|
list of alternate names
|
|
anchor_text:
|
|
text that will be used, together with the role
|
|
base_url:
|
|
base url for the link
|
|
interpret_url:
|
|
this, modulo the validated text, will be added to it
|
|
validator:
|
|
should return the validated text, or raise ValueError
|
|
"""
|
|
def uri_reference_role(role, rawtext, text, lineno, inliner,
|
|
options=None, content=None):
|
|
if options is None:
|
|
options = {}
|
|
try:
|
|
valid_text = validator(text)
|
|
except ValueError as e:
|
|
msg = inliner.reporter.error( e.message % dict(text=text), line=lineno)
|
|
prb = inliner.problematic(rawtext, rawtext, msg)
|
|
return [prb], [msg]
|
|
ref = base_url + interpret_url % valid_text
|
|
set_classes(options)
|
|
node = nodes.reference(rawtext, anchor_text + utils.unescape(text), refuri=ref,
|
|
**options)
|
|
return [node], []
|
|
|
|
uri_reference_role.__doc__ = """Role to make handy references to URIs.
|
|
|
|
Use as :%(role_name)s:`71` (or any of %(aliases)s).
|
|
It will use %(base_url)s+%(interpret_url)s
|
|
validator should throw a ValueError, containing optionally
|
|
a %%(text)s format, if the interpreted text is not valid.
|
|
""" % locals()
|
|
roles.register_canonical_role(role_name, uri_reference_role)
|
|
from docutils.parsers.rst.languages import en
|
|
en.roles[role_name] = role_name
|
|
for alias in aliases:
|
|
en.roles[alias] = role_name
|
|
|
|
generate_uri_role('xep-reference', ('jep', 'xep'),
|
|
'XEP #', 'http://www.xmpp.org/extensions/', 'xep-%04d.html',
|
|
pos_int_validator)
|
|
generate_uri_role('gajim-ticket-reference', ('ticket', 'gtrack'),
|
|
'Gajim Ticket #', 'https://dev.gajim.org/gajim/gajim/issues/', '%d',
|
|
pos_int_validator)
|
|
|
|
class HTMLGenerator:
|
|
"""
|
|
Really simple HTMLGenerator starting from publish_parts
|
|
|
|
It reuses the docutils.core.Publisher class, which means it is *not*
|
|
threadsafe.
|
|
"""
|
|
def __init__(self, settings_spec=None, settings_overrides=None,
|
|
config_section='general'):
|
|
if settings_overrides is None:
|
|
settings_overrides = {'report_level': 5, 'halt_level': 5}
|
|
self.pub = Publisher(reader=None, parser=None, writer=None,
|
|
settings=None,
|
|
source_class=io.StringInput,
|
|
destination_class=io.StringOutput)
|
|
self.pub.set_components(reader_name='standalone',
|
|
parser_name='restructuredtext',
|
|
writer_name='html')
|
|
# hack: JEP-0071 does not allow HTML char entities, so we hack our way
|
|
# out of it.
|
|
# — == u"\u2014"
|
|
# a setting to only emit charater entities in the writer would be nice
|
|
# FIXME: several are emitted, and they are explicitly forbidden
|
|
# in the JEP
|
|
# == u"\u00a0"
|
|
self.pub.writer.translator_class.attribution_formats['dash'] = (
|
|
'\u2014', '')
|
|
self.pub.process_programmatic_settings(settings_spec,
|
|
settings_overrides,
|
|
config_section)
|
|
|
|
|
|
def create_xhtml(self, text, destination=None, destination_path=None,
|
|
enable_exit_status=None):
|
|
"""
|
|
Create xhtml for a fragment of IM dialog. We can use the source_name
|
|
to store info about the message
|
|
"""
|
|
self.pub.set_source(text, None)
|
|
self.pub.set_destination(destination, destination_path)
|
|
output = self.pub.publish(enable_exit_status=enable_exit_status)
|
|
# kludge until we can get docutils to stop generating (rare)
|
|
# entities
|
|
return '\u00a0'.join(self.pub.writer.parts['fragment'].strip().split(
|
|
' '))
|
|
|
|
Generator = HTMLGenerator()
|
|
|
|
def create_xhtml(text):
|
|
return Generator.create_xhtml(text)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
print("test 1\n" + Generator.create_xhtml("""
|
|
test::
|
|
|
|
>>> print(1)
|
|
1
|
|
|
|
*I* like it. It is for :JEP:`71`
|
|
|
|
this `` should trigger`` should trigger the problem.
|
|
|
|
"""))
|
|
print("test 2\n" + Generator.create_xhtml("""
|
|
*test1
|
|
|
|
test2_
|
|
"""))
|
|
print("test 3\n" + Generator.create_xhtml(""":ticket:`316` implements :xep:`71`"""))
|