This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/shared/common/parsers.py

1972 lines
62 KiB
Python

# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import nested_scopes
__doc__ = """Glasnost Common Parsers"""
__version__ = '$Revision$'[11:-2]
import os
import re
from stat import *
import tools
import sys
import types
try:
import docutils
except ImportError:
docutils = None
import context
from XhtmlGenerator import enhanceTypo
def parseGlasnostLink(link):
"""Parse a link to a Glasnost object as happening in Spip or ReST syntax
and returns a (title, url) tuple.
Note that those can contains replaceable items (with
replaceSpecialTags).
"""
link = link.replace('\n', ' ')
matchObject = re.match(
r'(?P<role>alias|art(icle)?|atom|book|card|election|file|'\
'grade|group|heading|im(g|age)?|person(ne)?|rubri(c|que)|'\
'short|system|vote|%s) *(?P<localId>\S+) *(?P<option>\S+)?' % \
'|'.join(context.getVar('knownRoles') or ['zzz']), link)
if matchObject is None:
name = link
for prefix in [ 'http://', 'https://', 'ftp://', 'mailto:' ]:
if name.startswith(prefix):
if not '/' in name[len(prefix):]:
name = name[len(prefix):]
break
else:
name = ''
return name, link
role = matchObject.group('role')
dispatcherHost = context.getVar('dispatcherId')[11:]
localId = matchObject.group('localId')
option = matchObject.group('option') and \
':%s' % matchObject.group('option') or ''
if role == 'alias':
title = '[{glasnost:aliaslabel:%s:%s}]' % (dispatcherHost, localId)
url = '[{glasnost:alias:%s:%s%s}]' % (dispatcherHost, localId, option)
return title, url
serverRoles = { # backward compatibility
'art': 'articles',
'article': 'articles',
'election': 'elections',
'file': 'uploadfiles',
'group': 'groups',
'img': 'uploadfiles',
'image': 'uploadfiles',
'person': 'people',
'rubric': 'rubrics',
}
if serverRoles.has_key(role):
serverRole = serverRoles[role]
elif role in (context.getVar('knownRoles') or []):
serverRole = role
else:
return '', link
title = '[{glasnost:label:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
url = '[{glasnost:partialid:%s:%s:%s%s}]' % (
dispatcherHost, serverRole, localId, option)
return title, url
class Formatter:
def close(self, **keywords):
return ''
def list(self, list):
def getListIndent(stack):
if len(stack) == 0:
return -1
else:
return stack[-1][0]
stack = []
result = ''
for line in list:
indent, type, text = line
while indent < getListIndent(stack):
result += self.listEnd(len(stack), stack[-1][1])
del stack[-1]
if indent > getListIndent(stack):
stack.append((indent, type))
result += self.listBegin(len(stack) - 1, type)
result += self.listItem(len(stack), text)
while stack:
result += self.listEnd(len(stack) - 1, stack[-1][1])
del stack[-1]
return result
def open(self, **keywords):
return ''
def prescaleImage(self):
return 1
def table(self, table, hasHeader):
result = ''
rows = len(table)
cols = max(map(len, table))
result += self.tableBegin(rows, cols)
for i in range(len(table)):
row = table[i]
rowNumber = i
if hasHeader:
rowNumber -= 1
result += self.tableLineBegin(rowNumber,
isHeader = i == 0 and hasHeader)
j = 0
for cell in row:
if type(cell) in [types.StringType, types.UnicodeType] \
and cell.strip() == '###':
cell = rowNumber + 1
result += self.tableCell(cell, rowNumber, j,
isHeader = i == 0 and hasHeader)
j += 1
result += self.tableLineEnd(i, isHeader = i == 0 and hasHeader)
result += self.tableEnd(isHeader = len(table) == 1 and hasHeader)
return result
def text(self, text):
return text
class FormatterDocBook(Formatter):
def close(self, docType = 'article', **keywords):
if docType == 'article':
return """\
</article>
"""
elif docType == 'book':
return """\
</book>
"""
elif docType == 'chapter':
return """\
</chapter>
"""
def emphasis(self, text):
if not text:
return ''
return '<emphasis>%(text)s</emphasis>' % {
'text': text,
}
def footNoteCall(self, text):
if not text:
return ''
return '<footnote>%(text)s</footnote>' % {
'text': text,
}
def image(self, name, url, width = None, height = None, fullUrl = None):
if width:
width = ' width="%s"' % width
else:
width = ''
if height:
height = ' depth="%s"' % height
else:
height = ''
if width or height:
scaleFit = ' scalefit="1"'
else:
scaleFit = ''
url = self.text(url)
image = """\
<inlinemediaobject>
<imageobject>
<imagedata fileref="%(url)s"%(height)s%(width)s%(scaleFit)s/>
</imageobject>
<textobject>
<phrase>%(name)s</phrase>
</textobject>
</inlinemediaobject>\
""" % {
'height': height,
'name': name,
'scaleFit': scaleFit,
'url': url,
'width': width,
}
if fullUrl:
image = self.link(image, fullUrl)
return image
def intertitle(self, text, sublevel = 0):
return '<bridgehead>%(text)s</bridgehead>\n' % {
'text': text,
}
def lineBreak(self):
return '<simpara/>\n'
def lineSeparator(self):
# FIXME: The following instruction doesn't work with the current
# stylesheet.
# return '<beginpage/>\n'
return '<simpara/>\n'
def link(self, name, url, title = None):
url = self.text(url)
return '<ulink url="%(url)s">%(name)s</ulink>' % {
'name': name,
'url': url,
}
def listBegin(self, indent, type):
if type:
type = 'orderedlist'
else:
type = 'itemizedlist'
if indent == 0:
return '%(indent)s<%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
else:
return '%(indent)s<listitem><%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listEnd(self, indent, type):
if type:
type = 'orderedlist'
else:
type = 'itemizedlist'
if indent == 0:
return '%(indent)s</%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
else:
return '%(indent)s</%(type)s></listitem>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listItem(self, indent, item):
return '%(indent)s<listitem><para>%(item)s</para></listitem>\n' % {
'indent': ' ' * indent,
'item': item,
}
def nonBreakingSpace(self):
return '&nbsp;'
def open(self, docType = 'article', addHeader = 1, language = 'fr',
publicationDate = None, title = None, **keywords):
if publicationDate:
publicationDate = """\
<pubdate>%s</pubdate>
""" % publicationDate
else:
publicationDate = ''
if title:
title = """\
<title>%s</title>
""" % title
else:
title = ''
if docType == 'article':
if addHeader:
text = """\
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE article PUBLIC "-//Norman Walsh//DTD DocBk XML V4.1.2/EN"
"file:///usr/share/sgml/docbook/dtd/xml/4.1.2/docbookx.dtd" [
]>
"""
else:
text = ''
text += """\
<article lang="%(language)s">
%(title)s\
<articleinfo>
<author>
<firstname>Frederic</firstname>
<surname>Peters</surname>
</author>
<editor>
<firstname>Emmanuel</firstname>
<surname>Raviart</surname>
</editor>
</articleinfo>
%(publicationDate)s\
""" % {
'language': language,
'publicationDate': publicationDate,
'title': title,
}
return text
elif docType == 'book':
if addHeader:
text = """\
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE book PUBLIC "-//Norman Walsh//DTD DocBk XML V4.1.2/EN"
"file:///usr/share/sgml/docbook/dtd/xml/4.1.2/docbookx.dtd" [
]>
"""
else:
text = ''
text += """\
<book lang="%(language)s">
%(title)s\
<bookinfo>
<author>
<firstname>Frederic</firstname>
<surname>Peters</surname>
</author>
<editor>
<firstname>Emmanuel</firstname>
<surname>Raviart</surname>
</editor>
</bookinfo>
%(publicationDate)s\
""" % {
'language': language,
'publicationDate': publicationDate,
'title': title,
}
return text
elif docType == 'chapter':
if addHeader:
text = """\
<?xml version="1.0" encoding="iso-8859-1"?>
<!DOCTYPE chapter PUBLIC "-//Norman Walsh//DTD DocBk XML V4.1.2/EN"
"file:///usr/share/sgml/docbook/dtd/xml/4.1.2/docbookx.dtd" [
]>
"""
else:
text = ''
text += """\
<chapter>
%(title)s\
<chapterinfo>
<author>
<firstname>Frederic</firstname>
<surname>Peters</surname>
</author>
<editor>
<firstname>Emmanuel</firstname>
<surname>Raviart</surname>
</editor>
</chapterinfo>
%(publicationDate)s\
""" % {
'publicationDate': publicationDate,
'title': title,
}
return text
def paragraph(self, text):
text = text.strip()
if not text:
return self.lineBreak()
return '<para>%(text)s</para>\n' % {
'text': text,
}
def preformatted(self, text):
if not text:
return ''
text = self.text(text)
return '<literallayout class="monospaced">%(text)s</literallayout>' % {
'text': text,
}
def preformattedInline(self, text):
if not text:
return ''
text = self.text(text)
return '<literal>%(text)s</literal>' % {
'text': text,
}
def punctuationAndSpace(self, punctuation):
return {
'« ': '«&nbsp;',
}[punctuation]
def spaceAndPunctuation(self, punctuation):
return {
' :': '&nbsp;:',
' ;': '&nbsp;;',
' !': '&nbsp;!',
' ?': '&nbsp;?',
' »': '&nbsp;»',
' %': '&nbsp;%',
' ...': '&nbsp;...',
}[punctuation]
def strong(self, text):
if not text:
return ''
return '<emphasis role="strong">%(text)s</emphasis>' % {
'text': text,
}
def tableBegin(self, rows, cols):
return '<informaltable><tgroup cols="%(cols)s">\n' % {
'cols': cols,
}
def tableCell(self, cell, row, col, isHeader):
if not cell:
cell = '&nbsp;'
return ' <entry>%(cell)s</entry>\n' % {
'cell': cell,
}
def tableEnd(self, isHeader = 0):
if isHeader:
return ' </thead>\n</tgroup></informaltable>\n'
else:
return ' </tbody>\n</tgroup></informaltable>\n'
def tableLineBegin(self, tableLineCount, isHeader = 0):
if isHeader:
return ' <thead>\n <row>\n'
elif tableLineCount == 0:
return ' <tbody>\n <row>\n'
else:
return ' <row>\n'
def tableLineEnd(self, tableLineCount, isHeader = 0):
if isHeader:
return ' </row>\n </thead>\n <tbody>'
elif tableLineCount == 0:
return ' </row>\n </tbody>\n'
else:
return ' </row>\n'
def teletype(self, text):
if not text:
return ''
return '<literal>%(text)s</literal>' % {
'text': text,
}
def text(self, text):
if not text:
return ''
text = text.replace('&', '&amp;')
text = text.replace('<', '&lt;')
return text
_non_id_chars = re.compile('[^a-z0-9]+')
_non_id_at_ends = re.compile('^[-0-9]+|-+$')
class FormatterHtml(Formatter):
def __init__(self):
self.states = [ '' ]
def intertitle(self, text, sublevel = 0):
nameText = re.sub('<.*?>', '', text).strip()
# from docutils/nodes.py, def make_id(string)
nameText = _non_id_chars.sub('-', ' '.join(nameText.lower().split()))
nameText = _non_id_at_ends.sub('', nameText)
return '<h%(sectionLevel)d id="%(nameText)s">%(text)s'\
'</h%(sectionLevel)d>\n' % {
'text': text,
'sectionLevel': self.sectionLevel + sublevel,
'nameText': nameText,
}
def lineBreak(self):
return '<br />\n'
def list(self, list):
# FIXME: the Formatter.list method doesn't work for sub-lists, so it is
# rewritten here. Maybe this method should also be used by
# Formatter.list
def getListIndent(stack):
if len(stack) == 0:
return -1
else:
return stack[-1][0]
self.states.append('blockLevel')
stack = []
result = ''
for line in list:
indent, type, text = line
while indent < getListIndent(stack):
result += self.listItemEnd()
result += self.listEnd(len(stack), stack[-1][1])
del stack[-1]
if indent > getListIndent(stack):
stack.append((indent, type))
result += '\n'
result += self.listBegin(len(stack) - 1, type)
else:
result += self.listItemEnd()
result += self.listItemBegin(len(stack), text)
while stack:
result += self.listItemEnd()
result += self.listEnd(len(stack) - 1, stack[-1][1])
del stack[-1]
return result
def listBegin(self, indent, type):
if type:
type = 'ol'
else:
type = 'ul'
return '%(indent)s<%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listEnd(self, indent, type):
if type:
type = 'ol'
else:
type = 'ul'
return '%(indent)s</%(type)s>\n' % {
'indent': ' ' * indent,
'type': type,
}
def listItemBegin(self, indent, item):
return '%(indent)s<li>%(item)s' % {
'indent': ' ' * indent,
'item': item,
}
def listItemEnd(self):
return '</li>\n'
def nonBreakingSpace(self):
return '&nbsp;'
def open(self, **keywords):
self.sectionLevel = 2
if keywords.has_key('sectionLevel'):
self.sectionLevel = int(keywords['sectionLevel'])
return ''
def paragraph(self, text):
if self.states[-1] == 'blockLevel':
self.states.pop()
return text
def line80(text):
t = []
i = 0
while 1:
val = text[i+70:].find(' ')
if val == -1:
t.append(text[i:])
break
part = text[i:i+70+val+1]
t.append(part)
i += len(part)
return '\n'.join(t)
text = enhanceTypo(text.strip())
text = line80(text.replace('\n', ' '))
if not text:
return self.lineBreak()
return '<p>%(text)s</p>\n' % {
'text': text,
}
def preformatted(self, text):
if not text:
return ''
## text = self.text(text)
self.states.append('blockLevel')
return '<pre>%(text)s</pre>' % {
'text': text,
}
def preformattedInline(self, text):
if not text:
return ''
text = self.text(text)
return '<code>%(text)s</code>' % {
'text': text,
}
def punctuationAndSpace(self, punctuation):
return {
'« ': '«&nbsp;',
}[punctuation]
def spaceAndPunctuation(self, punctuation):
return {
' :': '&nbsp;:',
' ;': '&nbsp;;',
' !': '&nbsp;!',
' ?': '&nbsp;?',
' »': '&nbsp;»',
' %': '&nbsp;%',
' ...': '&nbsp;...',
}[punctuation]
def tableBegin(self, rows, cols):
self.states.append('blockLevel')
return '<table>\n'
def tableCell(self, cell, row, col, isHeader):
if not cell:
cell = '&nbsp;'
if isHeader:
tag = 'th'
attrtag = ' scope="col"'
else:
tag = 'td'
attrtag = ''
return ' <%(tag)s%(attrtag)s>%(cell)s</%(tag)s>\n' % {
'tag': tag,
'cell': cell.strip(),
'attrtag': attrtag,
}
def tableEnd(self, isHeader = 0):
return '</table>\n'
def tableLineBegin(self, tableLineCount, isHeader = 0):
if isHeader:
return ' <tr>\n'
elif (tableLineCount + 1) % 2 == 0:
return ' <tr class="even">\n'
else:
return ' <tr class="odd">\n'
def tableLineEnd(self, tableLineCount, isHeader = 0):
return ' </tr>\n'
def text(self, text):
if not text:
return ''
text = text.replace('&', '&amp;')
text = text.replace('<', '&lt;')
text = text.replace('\x85', '&#8230;') # ellipsis (...)
return text
class FormatterHtmlComplete(FormatterHtml):
_footNotes = None
def close(self, **keywords):
footNotes = self._footNotes
if footNotes is None or len(footNotes) == 0:
return ''
indexes = footNotes.keys()
indexes.sort()
result = '<div class="spip-notes">\n'
for index in indexes:
result += '<p>'
result += '[<a href="#nh%(index)s" name="nb%(index)s" '\
'class="spip-note">%(index)s</a>]&nbsp;%(text)s' % {
'index': index,
'text': footNotes[index],
}
result += '</p>\n'
result += '</div>\n'
return result
def emphasis(self, text):
if not text:
return ''
return '<em>%(text)s</em>' % {
'text': text,
}
def footNoteCall(self, footNote):
if self._footNotes is None:
self._footNotes = {}
index = len(self._footNotes) + 1
self._footNotes[index] = footNote
return '&nbsp;[<a href="#nb%(index)s" name="nh%(index)s" '\
'class="spip-note">%(index)s</a>]' % { 'index': index }
def image(self, name, url, width = None, height = None, fullUrl = None):
if width:
width = ' width="%s"' % width
else:
width = ''
if height:
height = ' height="%s"' % height
else:
height = ''
image = """\
<img src="%(url)s" alt="%(name)s" title="%(name)s"%(height)s%(width)s />\
""" % {
'height': height,
'name': name,
'url': url,
'width': width,
}
if fullUrl:
image = '<a href="%(fullUrl)s">%(image)s</a>' % {
'fullUrl': fullUrl,
'image': image,
}
return image
def lineSeparator(self):
return '<hr />\n'
def link(self, name, url, title=None):
url = url.replace('"', '&quot;') # '"' must be converted.
# The following replace should not be done. An url must be left as is.
# url = url.replace('&', '&amp;') #
# url = url.replace('<', '&lt;') # ?
# url = url.replace('>', '&gt;') # ?
attrs = ['href="%s"' % url]
if title:
attrs.append('title="%s"' % title)
if url.startswith('http://'):
attrs.append('class="external"')
attrs = ' '.join(attrs)
return '<a %s>%s</a>' % (attrs, name)
def strong(self, text):
if not text:
return ''
return '<strong>%(text)s</strong>' % {
'text': text,
}
def teletype(self, text):
if not text:
return ''
return '<tt>%(text)s</tt>' % {
'text': text,
}
class FormatterHtmlSimple(FormatterHtml):
def emphasis(self, text):
return text
def footNoteCall(self, footNote):
return ''
def image(self, name, url, width = None, height = None, fullUrl = None):
return ''
def lineSeparator(self):
return '<br />\n'
def link(self, name, url, title=None):
return str(name)
def strong(self, text):
return text
def teletype(self, text):
return text
class FormatterLatex(Formatter):
sectionType = 'section'
def close(self, docType = 'article', **keywords):
if docType in ['article', 'book', 'report']:
return """\
\\end{document}
"""
else:
return ''
def emphasis(self, text):
if not text:
return ''
return '\\begin{it}%(text)s\\end{it}' % {
'text': text,
}
def footNoteCall(self, text):
if not text:
return ''
return '\\footnote{%(text)s}' % {
'text': text,
}
def image(self, name, url, width = None, height = None, fullUrl = None):
if width is None:
width = ''
if height is None:
height = ''
if fullUrl is not None:
url = fullUrl
return '[{glasnost:latex:includegraphics:%s:width=%s:height=%s}]' \
% (url, width, height)
def intertitle(self, text, sublevel = 0):
return '\\%(sectionType)s{%(text)s}\n' % {
'sectionType': self.sectionType,
'text': text,
}
def lineBreak(self):
return ''
return '\\linebreak\n'
def lineSeparator(self):
return '\\hrulefill\n'
def link(self, name, url, title=None):
url = self.text(url)
# FIXME: link support in LaTeX conversion.
return name
def listBegin(self, indent, type):
if type:
type = 'enumerate'
else:
type = 'itemize'
return '%(indent)s\\begin{%(type)s}\n' % {
'indent': ' ' * indent,
'type': type,
}
def listEnd(self, indent, type):
if type:
type = 'enumerate'
else:
type = 'itemize'
return '%(indent)s\\end{%(type)s}\n' % {
'indent': ' ' * indent,
'type': type,
}
def listItem(self, indent, item):
return '%(indent)s\\item %(item)s\n' % {
'indent': ' ' * indent,
'item': item,
}
def nonBreakingSpace(self):
return '~'
def open(self, docType = 'article', addHeader = 1, author = '',
language = 'fr', publicationDate = None, title = None,
**keywords):
if docType == 'subArticle':
self.sectionType = 'subsection'
return ''
if docType in ['article', 'book', 'report']:
if author:
author = """\
\\author{%s}
""" % author
else:
author = ''
languages = {
'de': 'german',
'en': 'english',
'fi': 'finnish',
'fr': 'french',
'sv': 'swedish',
}
if language and language in languages.keys():
language = languages[language]
else:
language = 'english'
if publicationDate:
publicationDate = """\
\\date{%s}
""" % publicationDate
else:
publicationDate = ''
if title:
title = """\
\\title{%s}
""" % title
else:
title = ''
text = """\
\\documentclass{%(docType)s}
\\usepackage[%(language)s]{babel}
\\usepackage[pdftex]{graphicx}
\\usepackage[latin9]{inputenc}
\\usepackage{listings}
\lstset{breaklines,breakindent=0pt,breakautoindent=false}
\\begin{document}
%(title)s\
%(author)s\
%(publicationDate)s\
\\maketitle
\\tableofcontents
""" % {
'author': author,
'docType': docType,
'language': language,
'publicationDate': publicationDate,
'title': title,
}
return text
elif docType == 'chapter':
text = """\
\\chapter{%s}
""" % title
return text
def paragraph(self, text):
text = text.strip()
if not text:
return self.lineBreak()
return '%(text)s\n\n' % {
'text': text,
}
def preformatted(self, text):
if not text:
return ''
## return '\\begin{verbatim}%(text)s\\end{verbatim}' % {
## 'text': text,
## }
return '\\begin{lstlisting}{}%(text)s\\end{lstlisting}' % {
'text': text,
}
def preformattedInline(self, text):
if not text:
return ''
## return '\\begin{verbatim}%(text)s\\end{verbatim}' % {
## 'text': text,
## }
return '\\begin{tt}\\begin{lstlisting}{}%(text)s\\end{lstlisting}\\end{tt}' % {
'text': text,
}
def prescaleImage(self):
return 0
def punctuationAndSpace(self, punctuation):
return self.text(punctuation)
def spaceAndPunctuation(self, punctuation):
return self.text(punctuation)
def strong(self, text):
if not text:
return ''
return '\\begin{bf}%(text)s\\end{bf}' % {
'text': text,
}
def tableBegin(self, rows, cols):
spec = '|l' * cols + '|'
return '\n\\begin{tabular}{%(spec)s}\n\\hline\n' % {
'spec': spec,
}
def tableCell(self, cell, row, col, isHeader):
if col > 0:
separator = ' & '
else:
separator = ''
return '%(separator)s%(cell)s' % {
'cell': cell,
'separator': separator,
}
def tableEnd(self, isHeader = 0):
return '\\end{tabular}\n\n'
def tableLineBegin(self, tableLineCount, isHeader = 0):
return ''
def tableLineEnd(self, tableLineCount, isHeader = 0):
return ' \\\\\n\\hline\n'
def teletype(self, text):
if not text:
return ''
if not '\n' in text:
return '\\texttt{%s}' % text
return '\\begin{ttfamily}%(text)s\\end{ttfamily}' % {
'text': text,
}
def text(self, text):
if not text:
return ''
# The 3 following instructions must be the first ones.
text = text.replace('\\',
'[{glasnost:dollar}]\\backslash[{glasnost:dollar}]')
text = text.replace('$', '\\$')
text = text.replace('[{glasnost:dollar}]', '$')
text = text.replace('{', '\\{')
text = text.replace('}', '\\}')
text = text.replace('#', '\\#')
text = text.replace('%', '\\%')
text = text.replace('&', '\\&')
text = text.replace('~', '\\begin{verbatim}~\\end{verbatim}')
text = text.replace('_', '\\_')
text = text.replace('^', '\\begin{verbatim}^\\end{verbatim}')
return text
class SpipParser:
codeRegexp = r"""
(?P<codeStop>\</(code|CODE)\>)
|(?P<wordAsIs>\w+)
"""
codeRegexp = codeRegexp.replace('\n', '')
codeRegexpObject = None
footNoteRegexp = r"""
(?P<footNoteStop>\]\])
|(?P<image>\<((im(g|age)?)|(IM(G|AGE)?)) *(\d+|[^ \>]+)( +\d+\*\d+)?\>)
|(?P<teletypeStart>\(\()
|(?P<teletypeStop>\)\))
|(?P<strongStart>\{\{)
|(?P<strongStop>\}\})
|(?P<emphasisStart>\{)
|(?P<emphasisStop>\})
|(?P<linkStart>\[)
|(?P<antislash>\\.?)
|(?P<punctuationAndSpace>[«] )
|(?P<spaceAndPunctuation> ([:;!\%]|\.\.\.))
|(?P<nonBreakingSpace>~)
|(?P<word>\w+)
"""
footNoteRegexp = footNoteRegexp.replace('\n', '')
footNoteRegexpObject = None
linkNameRegexp = r"""
(?P<image>\<((im(g|age)?)|(IM(G|AGE)?)) *(\d+|[^ \>]+)( +\d+\*\d+)?\>)
|(?P<teletypeStart>\(\()
|(?P<teletypeStop>\)\))
|(?P<strongStart>\{\{)
|(?P<strongStop>\}\})
|(?P<emphasisStart>\{)
|(?P<emphasisStop>\})
|(?P<linkMiddle>->)
|(?P<linkWithoutMiddleStop>\])
|(?P<antislash>\\.?)
|(?P<punctuationAndSpace>[«] )
|(?P<spaceAndPunctuation> ([:;!\%]|\.\.\.))
|(?P<nonBreakingSpace>~)
|(?P<word>\w+)
"""
linkNameRegexp = linkNameRegexp.replace('\n', '')
linkNameRegexpObject = None
linkRegexp = r"""
(?P<linkStop>\])
|(?P<wordInUrl>\w+)
"""
linkRegexp = linkRegexp.replace('\n', '')
linkRegexpObject = None
listRegexp = r"""
(?P<listLineStart>^ *-([0-9aAiI]\.)?(?=[^-]))
|(?P<listLineStop>\r?\n(?= *-([0-9aAiI]\.)?(?=[^-])))
|(?P<listLineContinuation>\r?\n(?= +))
|(?P<listStop>(?=\r?\n|$))
|(?P<image>\<((im(g|age)?)|(IM(G|AGE)?)) *(\d+|[^ \>]+)( +\d+\*\d+)?\>)
|(?P<teletypeStart>\(\()
|(?P<teletypeStop>\)\))
|(?P<strongStart>\{\{)
|(?P<strongStop>\}\})
|(?P<emphasisStart>\{)
|(?P<emphasisStop>\})
|(?P<footNoteStart>\[\[)
|(?P<linkStart>\[)
|(?P<antislash>\\.?)
|(?P<punctuationAndSpace>[«] )
|(?P<spaceAndPunctuation> ([:;!\%]|\.\.\.))
|(?P<nonBreakingSpace>~)
|(?P<word>\w+)
"""
listRegexp = listRegexp.replace('\n', '')
listRegexpObject = None
paragraphRegexp = r"""
(?P<paragraphStop>\r?\n( *\r?\n)* *(?=\r?\n|$))
|(?P<lineSeparator>^ *[-_]{4,} *(\r?\n|$))
|(?P<intertitleStart>^ *\{\{\{)
|(?P<intertitleStop>\}\}\}( *$|))
|(?P<listStart>^ *-([0-9aAiI]\.)?)
|(?P<tableWithHeaderStart>^ *\|(?=( *\{\{.*?\}\} *\|)+ *(\r?\n|$)))
|(?P<tableStart>^ *\|)
|(?P<codeStart>\<(code|CODE)\>)
|(?P<image>\<((im(g|age)?)|(IM(G|AGE)?)) *(\d+|[^ \>]+)( +\d+\*\d+)?\>)
|(?P<teletypeStart>\(\()
|(?P<teletypeStop>\)\))
|(?P<strongStart>\{\{)
|(?P<strongStop>\}\})
|(?P<emphasisStart>\{)
|(?P<emphasisStop>\})
|(?P<footNoteStart>\[\[)
|(?P<linkStart>\[)
|(?P<antislash>\\.?)
|(?P<punctuationAndSpace>[«] )
|(?P<spaceAndPunctuation> ([:;!\%]|\.\.\.))
|(?P<nonBreakingSpace>~)
|(?P<word>\w+)
"""
paragraphRegexp = paragraphRegexp.replace('\n', '')
paragraphRegexpObject = None
posDelta = 0
spipRegexp = r"""
(?P<paragraphStart>\r?\n)
"""
spipRegexp = spipRegexp.replace('\n', '')
spipRegexpObject = None
states = None
tableRegexp = r"""
(?P<rowStart>^ *\|)
|(?P<rowStop>\| *\r?\n(?= *\|))
|(?P<tableStop>\| *(?=\r?\n|$))
|(?P<cellRestart>\|)
|(?P<image>\<((im(g|age)?)|(IM(G|AGE)?)) *(\d+|[^ \>]+)( +\d+\*\d+)?\>)
|(?P<teletypeStart>\(\()
|(?P<teletypeStop>\)\))
|(?P<strongStart>\{\{)
|(?P<strongStop>\}\})
|(?P<emphasisStart>\{)
|(?P<emphasisStop>\})
|(?P<footNoteStart>\[\[)
|(?P<linkStart>\[)
|(?P<antislash>\\.?)
|(?P<punctuationAndSpace>[«] )
|(?P<spaceAndPunctuation> ([:;!\%]|\.\.\.))
|(?P<nonBreakingSpace>~)
|(?P<word>\w+)
"""
tableRegexp = tableRegexp.replace('\n', '')
tableRegexpObject = None
def __init__(self):
self.codeRegexpObject = re.compile(self.codeRegexp,
re.MULTILINE | re.DOTALL)
self.footNoteRegexpObject = re.compile(self.footNoteRegexp,
re.MULTILINE | re.DOTALL)
self.linkNameRegexpObject = re.compile(self.linkNameRegexp,
re.MULTILINE | re.DOTALL)
self.linkRegexpObject = re.compile(self.linkRegexp,
re.MULTILINE | re.DOTALL)
self.listRegexpObject = re.compile(self.listRegexp,
re.MULTILINE | re.DOTALL)
self.paragraphRegexpObject = re.compile(self.paragraphRegexp,
re.MULTILINE | re.DOTALL)
self.spipRegexpObject = re.compile(self.spipRegexp,
re.MULTILINE | re.DOTALL)
self.tableRegexpObject = re.compile(self.tableRegexp,
re.MULTILINE | re.DOTALL)
self.states = []
self.pushState({
'state': None,
})
self.pushState({
'formattedText': '',
'paragraphsCount': 0,
'regexpObject': self.spipRegexpObject,
'state': 'spip',
})
self.pushState({
'formattedText': '',
'ignoreEmptyParagraph': 0,
'regexpObject': self.paragraphRegexpObject,
'state': 'paragraph',
})
def format(self, formatter, rawText, **keywords):
self.formatter = formatter
formattedText = self.formatter.open(**keywords)
if not rawText:
rawText = ''
rawText = rawText.expandtabs()
pos = 0
while pos < len(rawText):
regexpObject = self.getVar('regexpObject')
matchObject = regexpObject.match(rawText, pos)
if matchObject is None or matchObject.lastgroup is None:
self.setVar(
'formattedText',
self.getVar('formattedText') \
+ self.formatter.text(rawText[pos]))
pos += 1
else:
groupName = matchObject.lastgroup
result = apply(getattr(self, 'handle_' + groupName),
(matchObject.group(groupName), ))
if result:
self.setVar('formattedText',
self.getVar('formattedText') + result)
pos = matchObject.end(groupName) + self.posDelta
if self.posDelta != 0:
del self.posDelta
while len(self.states) > 2:
if self.getVar('state') == 'list':
result = self.handle_listStop(None)
if result:
self.setVar('formattedText',
self.getVar('formattedText') + result)
elif self.getVar('state') == 'paragraph':
result = self.handle_paragraphStop(None, isLastParagraph = 1)
if result:
self.setVar('formattedText',
self.getVar('formattedText') + result)
else:
self.pullState()
formattedText += self.getVar('formattedText')
formattedText = formattedText.strip() + '\n'
formattedText += self.formatter.close(**keywords)
return formattedText
def getVar(self, name):
for state in self.states:
if state.has_key(name):
return state[name]
else:
raise KeyError(name)
def getPreviousVar(self, name):
for state in self.states[1:]:
if state.has_key(name):
return state[name]
else:
raise KeyError(name)
def handle_antislash(self, group):
character = group[1]
if character == 'n':
return self.formatter.lineBreak()
else:
return self.formatter.text(character)
def handle_cellRestart(self, group):
self.handle_cellStop(group)
self.handle_cellStart(group)
return None
def handle_cellStart(self, group):
table = self.getVar('table')
table[-1].append([])
return None
def handle_cellStop(self, group):
table = self.getVar('table')
table[-1][-1] = self.getVar('formattedText')
self.setVar('formattedText', '')
return None
def handle_codeStart(self, group):
self.pushState({
'formattedText': '',
'regexpObject': self.codeRegexpObject,
'state': 'code',
})
return None
def handle_codeStop(self, group):
if self.getVar('state') != 'code':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.preformatted(formattedText)
def handle_emphasisStart(self, group):
self.pushState({
'formattedText': '',
'state': 'emphasis',
})
return None
def handle_emphasisStop(self, group):
if self.getVar('state') != 'emphasis':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.emphasis(formattedText)
def handle_footNoteStart(self, group):
self.pushState({
'formattedText': '',
'regexpObject': self.footNoteRegexpObject,
'state': 'footNote',
})
return None
def handle_footNoteStop(self, group):
if self.getVar('state') != 'footNote':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.footNoteCall(formattedText)
def handle_image(self, group):
matchObject = re.match(
r'\<((im(g|age)?)|(IM(G|AGE)?)) '\
'*((?P<localId>\d+)|(?P<url>[^ \>]+))'\
'( +(?P<width>\d+)\*(?P<height>\d+))?\>', group)
localId = matchObject.group('localId')
url = matchObject.group('url')
width = matchObject.group('width')
height = matchObject.group('height')
if localId:
dispatcherHost = context.getVar('dispatcherId')[11:]
serverRole = 'uploadfiles'
id = '[{glasnost:partialid:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
name = '[{glasnost:label:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
if (width or height) and self.formatter.prescaleImage():
url = '[{glasnost:thumbnail:%s:%s:%s:width=%s:height=%s}]' % (
dispatcherHost, serverRole, localId, width, height)
fullUrl = '[{glasnost:image:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
# Disable image scaling from formatter.
width = height = None
else:
url = '[{glasnost:image:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
fullUrl = None
else:
name = ''
fullUrl = None
return self.formatter.image(name, url, width, height, fullUrl)
def handle_intertitleStart(self, group):
inParagraph = self.getVar('state') == 'paragraph'
if inParagraph:
result = self.handle_paragraphStop(None, ignoreEmptyParagraph = 1)
if result:
self.setVar('formattedText',
self.getVar('formattedText') + result)
self.pushState({
'formattedText': '',
'inParagraph': inParagraph,
'regexpObject': self.paragraphRegexpObject,
'state': 'intertitle',
})
return None
def handle_intertitleStop(self, group):
if self.getVar('state') == 'intertitle':
formattedText = self.getVar('formattedText')
inParagraph = self.getVar('inParagraph')
self.pullState()
formattedText = self.formatter.intertitle(formattedText)
self.setVar('formattedText',
self.getVar('formattedText') + formattedText)
if inParagraph:
return self.handle_paragraphStart(None,
ignoreEmptyParagraph = 1)
else:
return None
elif self.getVar('state') == 'strong':
self.posDelta -= 1
return self.handle_strongStop(group[:-1])
elif self.getVar('state') == 'emphasis':
self.posDelta -= 2
return self.handle_emphasisStop(group[:-2])
else:
return None
def handle_lineSeparator(self, group):
inParagraph = self.getVar('state') == 'paragraph'
if inParagraph:
result = self.handle_paragraphStop(None, ignoreEmptyParagraph = 1)
if result:
self.setVar('formattedText',
self.getVar('formattedText') + result)
formattedText = self.formatter.lineSeparator()
self.setVar('formattedText',
self.getVar('formattedText') + formattedText)
if inParagraph:
return self.handle_paragraphStart(None, ignoreEmptyParagraph = 1)
else:
return None
def handle_linkMiddle(self, group):
if self.getVar('state') != 'linkName':
return None
name = self.getVar('formattedText')
self.pullState()
self.pushState({
'formattedText': '',
'name': name,
'regexpObject': self.linkRegexpObject,
'state': 'link',
})
return None
def handle_linkStart(self, group):
self.pushState({
'formattedText': '',
'regexpObject': self.linkNameRegexpObject,
'state': 'linkName',
})
return None
def handle_linkStop(self, group):
if self.getVar('state') != 'link':
return None
title = None
name = self.getVar('name')
link = self.getVar('formattedText')
self.pullState()
link = link.strip()
title, url = parseGlasnostLink(link)
if not title:
title = url
if name and '|' in name:
oTitle = title
name, title = name.split('|', 2)
if not name:
name = oTitle
elif not name:
name = title
title = None
if name == title or url == title:
title = None
return self.formatter.link(name.strip(), url, title)
def handle_linkWithoutMiddleStop(self, group):
if self.getVar('state') != 'linkName':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.text('[') \
+ formattedText \
+ self.formatter.text(']')
def handle_listLineStart(self, group):
matchObject = re.match(
r'^(?P<indent> *)-((?P<type>[0-9aAiI])\.)?',
group)
indent = len(matchObject.group('indent'))
type = matchObject.group('type')
list = self.getVar('list')
list.append([indent, type, None])
return None
def handle_listLineContinuation(self, group):
return None
def handle_listLineStop(self, group):
list = self.getVar('list')
list[-1][-1] = self.getVar('formattedText').lstrip()
self.setVar('formattedText', '')
return None
def handle_listStart(self, group):
self.pushState({
'formattedText': '',
'list': [],
'regexpObject': self.listRegexpObject,
'state': 'list',
})
return self.handle_listLineStart(group)
def handle_listStop(self, group):
if self.getVar('state') != 'list':
# The following pullState is mandatory, because group is empty, so
# if we don't pull a state, handle_listStop will be called forever.
if len(self.states) > 2:
self.pullState()
return None
self.handle_listLineStop(group)
list = self.getVar('list')
self.pullState()
return self.formatter.list(list)
def handle_nonBreakingSpace(self, group):
return self.formatter.nonBreakingSpace()
def handle_paragraphStart(self, group, ignoreEmptyParagraph = 1):
self.pushState({
'formattedText': '',
'ignoreEmptyParagraph': ignoreEmptyParagraph,
'regexpObject': self.paragraphRegexpObject,
'state': 'paragraph',
})
return None
def handle_paragraphStop(self, group, ignoreEmptyParagraph = 0,
isLastParagraph = 0):
if self.getVar('state') != 'paragraph':
return None
formattedText = self.getVar('formattedText').strip()
ignoreEmptyParagraph = ignoreEmptyParagraph \
or self.getVar('ignoreEmptyParagraph')
self.pullState()
self.setVar('paragraphsCount', self.getVar('paragraphsCount') + 1)
if ignoreEmptyParagraph and not formattedText:
return None
elif isLastParagraph and self.getVar('paragraphsCount') == 1:
return formattedText
elif re.match('^<strong>.+</strong>$', formattedText) and \
len(re.findall('<strong>.+?</strong>', formattedText)) == 1:
formattedText = formattedText[8:-9]
return self.formatter.intertitle(formattedText, sublevel = 1)
else:
return self.formatter.paragraph(formattedText)
def handle_punctuationAndSpace(self, punctuation):
return self.formatter.punctuationAndSpace(punctuation)
def handle_rowStart(self, group):
table = self.getVar('table')
table.append([])
return self.handle_cellStart(group)
def handle_rowStop(self, group):
return self.handle_cellStop(group)
def handle_spaceAndPunctuation(self, punctuation):
return self.formatter.spaceAndPunctuation(punctuation)
def handle_strongStart(self, group):
if self.getVar('state') == 'table' and self.getVar('hasHeader'):
return None
self.pushState({
'formattedText': '',
'state': 'strong',
})
return None
def handle_strongStop(self, group):
if self.getVar('state') != 'strong':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.strong(formattedText)
def handle_tableStart(self, group, hasHeader = 0):
self.pushState({
'formattedText': '',
'hasHeader': hasHeader,
'table': [],
'regexpObject': self.tableRegexpObject,
'state': 'table',
})
return self.handle_rowStart(group)
def handle_tableStop(self, group):
self.handle_rowStop(group)
table = self.getVar('table')
hasHeader = self.getVar('hasHeader')
self.pullState()
return self.formatter.table(table, hasHeader)
def handle_tableWithHeaderStart(self, group):
return self.handle_tableStart(group, hasHeader = 1)
def handle_teletypeStart(self, group):
self.pushState({
'formattedText': '',
'state': 'teletype',
})
return None
def handle_teletypeStop(self, group):
if self.getVar('state') != 'teletype':
return None
formattedText = self.getVar('formattedText')
self.pullState()
return self.formatter.teletype(formattedText)
def handle_word(self, word):
return self.formatter.text(word)
def handle_wordAsIs(self, word):
return word
def handle_wordInUrl(self, word):
return word
def hasVar(self, name):
for state in self.states:
if state.has_key(name):
return 1
else:
return 0
def pullState(self):
del self.states[0]
def pushState(self, state):
self.states.insert(0, state)
def setVar(self, name, value):
self.states[0][name] = value
def makeDocBookFromSpip(text, **keywords):
parser = SpipParser()
formatter = FormatterDocBook()
return parser.format(formatter, text, **keywords)
def makeHtmlFromDocBook(text, inline = 0):
# FIXME: To do: Handle the case when inline == 0.
filePath = newTemporaryFile('docbook')
errorFilePath = filePath + '.err'
xmlFilePath = filePath + '.xml'
htmlFilePath = filePath + '.html'
xmlFile = open(xmlFilePath, 'wb')
xmlFile.write(text)
xmlFile.close()
result = os.system('xsltproc -o %(htmlFilePath)s %(xsltFilePath)s '\
'%(xmlFilePath)s 2>%(errorFilePath)s' % {
'errorFilePath': errorFilePath,
'htmlFilePath': htmlFilePath,
'xmlFilePath': xmlFilePath,
'xsltFilePath':
'/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/xhtml/docbook.xsl',
})
os.remove(xmlFilePath)
errorFileStat = os.stat(errorFilePath)
errorFileSize = errorFileStat[ST_SIZE]
if errorFileSize > 0:
errorFile = open(errorFilePath, 'rb')
error = errorFile.read()
errorFile.close()
else:
error = None
os.remove(errorFilePath)
if error is not None and error.find('error:') >= 0:
error = error.replace('&', '&amp;')
error = error.replace('"', '&quot;')
error = error.replace('<', '&lt;')
error = error.replace('>', '&gt;')
error = '<pre>%s</pre>' % error
return error
else:
htmlFile = open(htmlFilePath, 'rb')
html = htmlFile.read()
htmlFile.close()
os.remove(htmlFilePath)
return html
def makeHtmlFromHtml(text, inline = 0, **keywords):
# from http://sourceforge.net/snippet/detail.php?type=snippet&id=100121
AllowedHTML = re.compile(r"""
(?isx) # case-insensitive, multiline, verbose regexp
</?b> | # bold
</?i> | # italics
</?p> | # paragraph (alignment)
<a .+?> | # anchors (links)
</a> | # anchor close
</?ol> | # ordered lists (numbered)
</?ul> | # unordered lists (bulleted)
<li> | # list elements
</?em> | # emphasis
<br /> | # link breaks
<hr /> | # horizontal rules
</?tt> | # teletype font
</?strong> | # strong emphasis
</?blockquote> | # block quotes
</?address> | # addresses
</?h[2-6]> # heading markers
""")
def HTMLChecker(match_obj):
"""Validate HTML.
Given an re module match object as a parameter, it returns either
the HTML tag in question if it's allowed, or a null string.
"""
if AllowedHTML.search(match_obj.group()):
return match_obj.group()
else:
return ""
text = re.sub(r"(?is)<.+?>", HTMLChecker, text)
return text
def makeHtmlFromPreformattedText(text, simple = 0, inline = 0):
if simple:
formatter = FormatterHtmlSimple()
else:
formatter = FormatterHtmlComplete()
text = text.replace('&', '&amp;')
text = text.replace('<', '&lt;')
text = text.replace('\f', formatter.lineSeparator())
if inline:
text = formatter.preformattedInline(text)
else:
text = formatter.preformatted(text)
return text
def makeHtmlFromReStructuredText(text, simple = 0, inline = 0, **keywords):
# FIXME: To do: Handle the case when inline == 0.
if not docutils:
return 'docutils package not installed, no support for' \
' reStructuredText'
from docutils import core, frontend, io, readers, parsers, writers, nodes
htmlWriter = writers.get_writer_class('html')
htmlTranslator = htmlWriter().translator_class
class Writer(htmlWriter):
def __init__(self, **keywords):
htmlWriter.__init__(self)
self.translator_class = GlasnostHTMLTranslator
sectionLevel = 2
if keywords.has_key('sectionLevel'):
sectionLevel = int(keywords['sectionLevel']) - 1
self.translator_class.baseSectionLevel = sectionLevel
class GlasnostHTMLTranslator(htmlTranslator):
baseSectionLevel = 1
def __init__(self, document):
htmlTranslator.__init__(self, document)
self.section_level = self.baseSectionLevel
def astext(self):
return enhanceTypo(''.join(self.body))
def encode(self, text):
"""Encode special characters in `text` & return."""
# FIXME: A codec to do these and all other HTML entities would be
# nice.
text = text.replace("&", "&amp;")
text = text.replace("<", "&lt;")
text = text.replace('"', "&quot;")
text = text.replace(">", "&gt;")
return text
def visit_document(self, node):
pass
def depart_document(self, node):
pass
def visit_footnote(self, node):
self.body.append(self.starttag(node, 'div', CLASS = 'footnotes'))
self.footnote_backrefs(node)
def footnote_backrefs(self, node):
if self.settings.footnote_backlinks and node.hasattr('backrefs'):
backrefs = node['backrefs']
if len(backrefs) == 1:
self.context.append('')
self.context.append('<a class="fn-backref" href="#%s" '
'name="%s">' % (backrefs[0], node['id']))
else:
i = 1
backlinks = []
for backref in backrefs:
backlinks.append('<a class="fn-backref" href="#%s">%s</a>'
% (backref, i))
i += 1
self.context.append('<em>(%s)</em> ' % ', '.join(backlinks))
self.context.append('<a name="%s">' % node['id'])
else:
self.context.append('')
self.context.append('<a name="%s">' % node['id'])
def visit_label(self, node):
self.body.append(self.starttag(node, 'p', self.context.pop()))
def depart_label(self, node):
self.body.append('</a>&nbsp;%s' % self.context.pop())
def depart_footnote(self, node):
self.body.append('\n</div>\n')
def visit_section(self, node):
self.section_level += 1
def depart_section(self, node):
self.section_level -= 1
def visit_reference(self, node):
title = ''
if node.has_key('refuri'):
# href = node['refuri']
# too bad: refuri has spaces removed; we have to dig the raw
# attribute.
try:
href = re.match(r'`.*<(?P<href>.*)>`',
node.rawsource, re.DOTALL).group('href')
except:
href = node['refuri']
title, href = parseGlasnostLink(href)
elif node.has_key('refid'):
href = '#' + node['refid']
elif node.has_key('refname'):
href = '#' + self.document.nameids[node['refname']]
if title:
self.body.append(self.starttag(node, 'a', '', href=href,
title=title,
CLASS='reference'))
else:
self.body.append(self.starttag(node, 'a', '', href=href,
CLASS='reference'))
def visit_image(self, node):
# FIXME: should support non-uploadfiles images
atts = node.attributes.copy()
fullUrl = None
matchObject = re.match(
r'((?P<localId>\S+)((,(?P<width>\d+)\*(?P<height>\d+))|))?', atts['uri'])
if matchObject and matchObject.group('localId'):
dispatcherHost = context.getVar('dispatcherId')[11:]
localId = matchObject.group('localId')
width = matchObject.group('width')
height = matchObject.group('height')
serverRole = 'uploadfiles'
id = '[{glasnost:partialid:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
if not atts.has_key('title'):
atts['title'] = '[{glasnost:label:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
if (width or height):
# had: "and self.formatter.prescaleImage():"
atts['src'] = '[{glasnost:thumbnail:%s:%s:%s:width=%s:height=%s}]' \
% (dispatcherHost, serverRole, localId, width, height)
atts['width'] = width
atts['height'] = height
fullUrl = '[{glasnost:image:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
# Disable image scaling from formatter.
width = height = None
else:
atts['src'] = '[{glasnost:image:%s:%s:%s}]' % (
dispatcherHost, serverRole, localId)
if not atts.has_key('src'):
atts['src'] = atts['uri']
del atts['uri']
if isinstance(node.parent, nodes.TextElement):
self.context.append('')
if fullUrl:
self.body.append('<a href="%s">' % fullUrl)
self.context.append('</a>')
else:
self.body.append('<p>')
if fullUrl:
self.body.append('<a href="%s">' % fullUrl)
self.context.append('</a>')
self.context.append('</p>\n')
self.body.append(self.emptytag(node, 'img', '', **atts))
def visit_table(self, node):
self.body.append(
self.starttag(node, 'table', CLASS='rst'))
self.rowOdd = 0
def depart_thead(self, node):
htmlTranslator.depart_thead(self, node)
self.rowOdd = 0
def visit_row(self, node):
self.rowOdd = not self.rowOdd
if self.rowOdd:
klass = 'odd'
else:
klass = 'even'
self.body.append(self.starttag(node, 'tr', '', CLASS=klass))
return core.publish_string(text, writer=Writer(**keywords),
settings_overrides={'output_encoding': 'iso-8859-1'})
def makeHtmlFromSpip(text, simple = 0, inline = 0, **keywords):
if not text:
return ''
text = text.replace('\r\n', '\n')
text = text.replace('\x91', "'").replace('\x92', "'").replace(
'\x93', "'").replace('\x94', "'").replace(
'\x81', "'").replace('\x82', "'").replace(
'&#8217;', "'").replace('&#8230;', '...').replace(
'&#8211;', '--').replace('&#8220;', '"').replace(
'&#180;', "'").replace('&#8221;', '"').replace(
'&#8216;', "'").replace('&#339;', 'oe')
if not inline:
# Force the spip parser to produce paragraphs.
text += '\n\n'
parser = SpipParser()
if simple:
formatter = FormatterHtmlSimple()
else:
formatter = FormatterHtmlComplete()
return parser.format(formatter, text, **keywords).strip()
def makeHtmlFromUnformattedText(text, simple = 0, inline = 0):
text = text.replace('&', '&amp;')
text = text.replace('<', '&lt;')
return text
def makeLatexFromSpip(text, **keywords):
parser = SpipParser()
formatter = FormatterLatex()
return parser.format(formatter, text, **keywords)
def newTemporaryFile(directoryName = '', fileNameSuffix = ''):
import tempfile
directoryPath = os.path.join('/tmp/glasnost', directoryName)
if not os.path.exists('/tmp/glasnost'):
os.mkdir('/tmp/glasnost', 0777)
if not os.path.exists(directoryPath):
os.mkdir(directoryPath, 0777)
tempfile.tempdir = directoryPath
filePath = tempfile.mktemp(fileNameSuffix)
return filePath