[Santiago Gala] We can now generate HTML thanks to rst. see #316
This commit is contained in:
parent
6b40b5ad32
commit
1345afa86c
|
@ -34,6 +34,8 @@ from message_textview import MessageTextView
|
||||||
from common.contacts import GC_Contact
|
from common.contacts import GC_Contact
|
||||||
from common.logger import Constants
|
from common.logger import Constants
|
||||||
constants = Constants()
|
constants = Constants()
|
||||||
|
from rst_xhtml_generator import create_xhtml
|
||||||
|
from common.xmpp.protocol import NS_XHTML
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import gtkspell
|
import gtkspell
|
||||||
|
@ -1251,6 +1253,8 @@ class ChatControl(ChatControlBase):
|
||||||
else:
|
else:
|
||||||
kind = 'outgoing'
|
kind = 'outgoing'
|
||||||
name = gajim.nicks[self.account]
|
name = gajim.nicks[self.account]
|
||||||
|
if not xhtml and not encrypted and gajim.config.get('rst_formatting_outgoing_messages'):
|
||||||
|
xhtml = '<body xmlns="%s">%s</body>' % (NS_XHTML, create_xhtml(text))
|
||||||
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
|
ChatControlBase.print_conversation_line(self, text, kind, name, tim,
|
||||||
subject = subject, old_kind = self.old_msg_kind, xhtml = xhtml)
|
subject = subject, old_kind = self.old_msg_kind, xhtml = xhtml)
|
||||||
if text.startswith('/me ') or text.startswith('/me\n'):
|
if text.startswith('/me ') or text.startswith('/me\n'):
|
||||||
|
|
|
@ -91,6 +91,8 @@ class Config:
|
||||||
_('Treat * / _ pairs as possible formatting characters.'), True],
|
_('Treat * / _ pairs as possible formatting characters.'), True],
|
||||||
'show_ascii_formatting_chars': [ opt_bool, True , _('If True, do not '
|
'show_ascii_formatting_chars': [ opt_bool, True , _('If True, do not '
|
||||||
'remove */_ . So *abc* will be bold but with * * not removed.')],
|
'remove */_ . So *abc* will be bold but with * * not removed.')],
|
||||||
|
'rst_formatting_outgoing_messages': [ opt_bool, False,
|
||||||
|
_('Uses ReStructured text markup for HTML, plus ascii formatting if selected.')],
|
||||||
'sounds_on': [ opt_bool, True ],
|
'sounds_on': [ opt_bool, True ],
|
||||||
# 'aplay', 'play', 'esdplay', 'artsplay' detected first time only
|
# 'aplay', 'play', 'esdplay', 'artsplay' detected first time only
|
||||||
'soundplayer': [ opt_str, '' ],
|
'soundplayer': [ opt_str, '' ],
|
||||||
|
|
|
@ -652,7 +652,6 @@ class Connection(ConnectionHandlers):
|
||||||
p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed)
|
p.setTag(common.xmpp.NS_SIGNED + ' x').setData(signed)
|
||||||
if self.connection:
|
if self.connection:
|
||||||
self.connection.send(p)
|
self.connection.send(p)
|
||||||
self.priority = priority
|
|
||||||
self.dispatch('STATUS', show)
|
self.dispatch('STATUS', show)
|
||||||
|
|
||||||
def _on_disconnected(self):
|
def _on_disconnected(self):
|
||||||
|
@ -677,6 +676,8 @@ class Connection(ConnectionHandlers):
|
||||||
user_nick = None, xhtml = None):
|
user_nick = None, xhtml = None):
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
|
if not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
|
||||||
|
xhtml = create_xhtml(msg)
|
||||||
if not msg and chatstate is None:
|
if not msg and chatstate is None:
|
||||||
return
|
return
|
||||||
fjid = jid
|
fjid = jid
|
||||||
|
@ -694,6 +695,10 @@ class Connection(ConnectionHandlers):
|
||||||
# one in locale and one en
|
# one in locale and one en
|
||||||
msgtxt = _('[This message is *encrypted* (See :JEP:`27`]') +\
|
msgtxt = _('[This message is *encrypted* (See :JEP:`27`]') +\
|
||||||
' ([This message is *encrypted* (See :JEP:`27`])'
|
' ([This message is *encrypted* (See :JEP:`27`])'
|
||||||
|
if msgtxt and not xhtml and gajim.config.get(
|
||||||
|
'rst_formatting_outgoing_messages'):
|
||||||
|
# Generate a XHTML part using reStructured text markup
|
||||||
|
xhtml = create_xhtml(msgtxt)
|
||||||
if type == 'chat':
|
if type == 'chat':
|
||||||
msg_iq = common.xmpp.Message(to = fjid, body = msgtxt, typ = type,
|
msg_iq = common.xmpp.Message(to = fjid, body = msgtxt, typ = type,
|
||||||
xhtml = xhtml)
|
xhtml = xhtml)
|
||||||
|
@ -987,6 +992,8 @@ class Connection(ConnectionHandlers):
|
||||||
def send_gc_message(self, jid, msg, xhtml = None):
|
def send_gc_message(self, jid, msg, xhtml = None):
|
||||||
if not self.connection:
|
if not self.connection:
|
||||||
return
|
return
|
||||||
|
if not xhtml and gajim.config.get('rst_formatting_outgoing_messages'):
|
||||||
|
xhtml = create_xhtml(msg)
|
||||||
msg_iq = common.xmpp.Message(jid, msg, typ = 'groupchat', xhtml = xhtml)
|
msg_iq = common.xmpp.Message(jid, msg, typ = 'groupchat', xhtml = xhtml)
|
||||||
self.connection.send(msg_iq)
|
self.connection.send(msg_iq)
|
||||||
self.dispatch('MSGSENT', (jid, msg))
|
self.dispatch('MSGSENT', (jid, msg))
|
||||||
|
|
|
@ -0,0 +1,100 @@
|
||||||
|
from docutils import io
|
||||||
|
from docutils.core import Publisher
|
||||||
|
from docutils.parsers.rst import roles
|
||||||
|
|
||||||
|
def jep_reference_role(role, rawtext, text, lineno, inliner,
|
||||||
|
options={}, content=[]):
|
||||||
|
"""Role to make handy references to Jabber Enhancement Proposals (JEP).
|
||||||
|
|
||||||
|
Use as :JEP:`71` (or jep, or jep-reference).
|
||||||
|
Modeled after the sample in docutils documentation.
|
||||||
|
"""
|
||||||
|
from docutils import nodes,utils
|
||||||
|
from docutils.parsers.rst.roles import set_classes
|
||||||
|
|
||||||
|
jep_base_url = 'http://www.jabber.org/jeps/'
|
||||||
|
jep_url = 'jep-%04d.html'
|
||||||
|
try:
|
||||||
|
jepnum = int(text)
|
||||||
|
if jepnum <= 0:
|
||||||
|
raise ValueError
|
||||||
|
except ValueError:
|
||||||
|
msg = inliner.reporter.error(
|
||||||
|
'JEP number must be a number greater than or equal to 1; '
|
||||||
|
'"%s" is invalid.' % text, line=lineno)
|
||||||
|
prb = inliner.problematic(rawtext, rawtext, msg)
|
||||||
|
return [prb], [msg]
|
||||||
|
ref = jep_base_url + jep_url % jepnum
|
||||||
|
set_classes(options)
|
||||||
|
node = nodes.reference(rawtext, 'JEP ' + utils.unescape(text), refuri=ref,
|
||||||
|
**options)
|
||||||
|
return [node], []
|
||||||
|
|
||||||
|
roles.register_canonical_role('jep-reference', jep_reference_role)
|
||||||
|
from docutils.parsers.rst.languages.en import roles
|
||||||
|
roles['jep-reference'] = 'jep-reference'
|
||||||
|
roles['jep'] = 'jep-reference'
|
||||||
|
|
||||||
|
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=dict(report_level=5, halt_level=5),
|
||||||
|
config_section='general'):
|
||||||
|
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
|
||||||
|
# TODO: several are emitted, and they are explicitly forbidden in the JEP
|
||||||
|
# == u"\u00a0"
|
||||||
|
self.pub.writer.translator_class.attribution_formats["dash"] = (u"\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 u'\u00a0'.join(self.pub.writer.parts['fragment'].strip().split(' '))
|
||||||
|
|
||||||
|
Generator = HTMLGenerator()
|
||||||
|
|
||||||
|
def create_xhtml(text):
|
||||||
|
return Generator.create_xhtml(text)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print Generator.create_xhtml("""
|
||||||
|
test::
|
||||||
|
|
||||||
|
>>> print 1
|
||||||
|
1
|
||||||
|
|
||||||
|
*I* like it. It is for :JEP:`71`
|
||||||
|
|
||||||
|
this `` should trigger`` should trigger the problem.
|
||||||
|
|
||||||
|
""")
|
||||||
|
print Generator.create_xhtml("""
|
||||||
|
*test1
|
||||||
|
|
||||||
|
test2_
|
||||||
|
""")
|
Loading…
Reference in New Issue