blob: 74b62d7bc113f43f469a6c9437c41d5715538bc0 [file] [log] [blame]
# -*- coding: utf-8 -*-
#
# Copyright (C) 2004-2009 Edgewall Software
# Copyright (C) 2004 Daniel Lundin <daniel@edgewall.com>
# All rights reserved.
#
# This software is licensed as described in the file COPYING, which
# you should have received as part of this distribution. The terms
# are also available at http://trac.edgewall.org/wiki/TracLicense.
#
# This software consists of voluntary contributions made by many
# individuals. For the exact contribution history, see the revision
# history and logs, available at http://trac.edgewall.org/log/.
#
# Author: Daniel Lundin <daniel@edgewall.com>
"""Syntax highlighting module, based on the SilverCity module.
Get it at: http://silvercity.sourceforge.net/
"""
import re
from StringIO import StringIO
from genshi.core import Markup
from trac.core import *
from trac.config import ListOption
from trac.env import ISystemInfoProvider
from trac.mimeview.api import IHTMLPreviewRenderer, Mimeview
from trac.util import get_pkginfo
try:
import SilverCity
have_silvercity = True
except ImportError:
have_silvercity = False
__all__ = ['SilverCityRenderer']
types = {
'text/css': ('CSS', 3),
'text/html': ('HyperText', 3, {'asp.default.language':1}),
'application/xml': ('XML', 3),
'application/xhtml+xml': ('HyperText', 3, {'asp.default.language':1}),
'application/rss+xml': ('HyperText', 3, {'asp.default.language':1}),
'application/x-yaml': ('YAML', 3),
'text/x-yaml': ('YAML', 3),
'application/x-javascript': ('CPP', 3), # Kludgy.
'text/x-asp': ('HyperText', 3, {'asp.default.language':2}),
'text/x-c++hdr': ('CPP', 3),
'text/x-c++src': ('CPP', 3),
'text/x-chdr': ('CPP', 3),
'text/x-csrc': ('CPP', 3),
'text/x-perl': ('Perl', 3),
'text/x-php': ('HyperText', 3, {'asp.default.language': 4}),
'application/x-httpd-php': ('HyperText', 3, {'asp.default.language': 4}),
'application/x-httpd-php4': ('HyperText', 3, {'asp.default.language': 4}),
'application/x-httpd-php3': ('HyperText', 3, {'asp.default.language': 4}),
'text/x-java': ('Java', 3),
'text/x-javascript': ('CPP', 3), # Kludgy.
'text/x-psp': ('HyperText', 3, {'asp.default.language': 3}),
'text/x-python': ('Python', 3),
'text/x-ruby': ('Ruby', 3),
'text/x-sql': ('SQL', 3),
'text/x-verilog': ('Verilog', 3),
'text/xml': ('XML', 3),
'text/xslt': ('XSLT', 3),
'image/svg+xml': ('XML', 3)
}
CRLF_RE = re.compile('\r$', re.MULTILINE)
class SilverCityRenderer(Component):
"""Syntax highlighting based on SilverCity."""
implements(ISystemInfoProvider, IHTMLPreviewRenderer)
silvercity_modes = ListOption('mimeviewer', 'silvercity_modes',
'', doc=
"""List of additional MIME types known by SilverCity.
For each, a tuple `mimetype:mode:quality` has to be
specified, where `mimetype` is the MIME type,
`mode` is the corresponding SilverCity mode to be used
for the conversion and `quality` is the quality ratio
associated to this conversion.
That can also be used to override the default
quality ratio used by the SilverCity render, which is 3
(''since 0.10'').""")
expand_tabs = True
returns_source = True
def __init__(self):
self._types = None
# ISystemInfoProvider methods
def get_system_info(self):
if have_silvercity:
yield 'SilverCity', get_pkginfo(SilverCity).get('version', '?')
# TODO: the above works only if setuptools was used to build
# SilverCity, which is not yet the case by default for 0.9.7.
# I've not been able to find an alternative way to get version.
# IHTMLPreviewRenderer methods
def get_quality_ratio(self, mimetype):
# Extend default MIME type to mode mappings with configured ones
if not have_silvercity:
return 0
if not self._types:
self._types = {}
self._types.update(types)
self._types.update(
Mimeview(self.env).configured_modes_mapping('silvercity'))
return self._types.get(mimetype, (None, 0))[1]
def render(self, context, mimetype, content, filename=None, rev=None):
try:
mimetype = mimetype.split(';', 1)[0]
typelang = self._types[mimetype]
lang = typelang[0]
module = getattr(SilverCity, lang)
generator = getattr(module, lang + "HTMLGenerator")
try:
allprops = typelang[2]
propset = SilverCity.PropertySet()
for p in allprops.keys():
propset[p] = allprops[p]
except IndexError:
pass
except (KeyError, AttributeError):
err = "No SilverCity lexer found for mime-type '%s'." % mimetype
raise Exception, err
# SilverCity does not like unicode strings
content = content.encode('utf-8')
# SilverCity generates extra empty line against some types of
# the line such as comment or #include with CRLF. So we
# standardize to LF end-of-line style before call.
content = CRLF_RE.sub('', content)
buf = StringIO()
generator().generate_html(buf, content)
br_re = re.compile(r'<br\s*/?>$', re.MULTILINE)
span_default_re = re.compile(r'<span class="\w+_default">(.*?)</span>',
re.DOTALL)
html = span_default_re.sub(r'\1', br_re.sub('', buf.getvalue()))
# Convert the output back to a unicode string
html = html.decode('utf-8')
# SilverCity generates _way_ too many non-breaking spaces...
# We don't need them anyway, so replace them by normal spaces
return [Markup(line)
for line in html.replace('&nbsp;', ' ').splitlines()]