~ubuntu-branches/ubuntu/natty/moin/natty-updates

« back to all changes in this revision

Viewing changes to MoinMoin/support/pygments/formatters/svg.py

  • Committer: Bazaar Package Importer
  • Author(s): Jonas Smedegaard
  • Date: 2008-06-22 21:17:13 UTC
  • mto: This revision was merged to the branch mainline in revision 18.
  • Revision ID: james.westby@ubuntu.com-20080622211713-inlv5k4eifxckelr
ImportĀ upstreamĀ versionĀ 1.7.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# -*- coding: utf-8 -*-
2
 
"""
3
 
    pygments.formatters.svg
4
 
    ~~~~~~~~~~~~~~~~~~~~~~~
5
 
 
6
 
    Formatter for SVG output.
7
 
 
8
 
    :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS.
9
 
    :license: BSD, see LICENSE for details.
10
 
"""
11
 
 
12
 
from pygments.formatter import Formatter
13
 
from pygments.util import get_bool_opt, get_int_opt
14
 
 
15
 
__all__ = ['SvgFormatter']
16
 
 
17
 
 
18
 
def escape_html(text):
19
 
    """Escape &, <, > as well as single and double quotes for HTML."""
20
 
    return text.replace('&', '&amp;').  \
21
 
                replace('<', '&lt;').   \
22
 
                replace('>', '&gt;').   \
23
 
                replace('"', '&quot;'). \
24
 
                replace("'", '&#39;')
25
 
 
26
 
 
27
 
class2style = {}
28
 
 
29
 
class SvgFormatter(Formatter):
30
 
    """
31
 
    Format tokens as an SVG graphics file.  This formatter is still experimental.
32
 
    Each line of code is a ``<text>`` element with explicit ``x`` and ``y``
33
 
    coordinates containing ``<tspan>`` elements with the individual token styles.
34
 
 
35
 
    By default, this formatter outputs a full SVG document including doctype
36
 
    declaration and the ``<svg>`` root element.
37
 
 
38
 
    *New in Pygments 0.9.*
39
 
 
40
 
    Additional options accepted:
41
 
 
42
 
    `nowrap`
43
 
        Don't wrap the SVG ``<text>`` elements in ``<svg><g>`` elements and
44
 
        don't add a XML declaration and a doctype.  If true, the `fontfamily`
45
 
        and `fontsize` options are ignored.  Defaults to ``False``.
46
 
 
47
 
    `fontfamily`
48
 
        The value to give the wrapping ``<g>`` element's ``font-family``
49
 
        attribute, defaults to ``"monospace"``.
50
 
 
51
 
    `fontsize`
52
 
        The value to give the wrapping ``<g>`` element's ``font-size``
53
 
        attribute, defaults to ``"14px"``.
54
 
 
55
 
    `xoffset`
56
 
        Starting offset in X direction, defaults to ``0``.
57
 
 
58
 
    `yoffset`
59
 
        Starting offset in Y direction, defaults to the font size if it is given
60
 
        in pixels, or ``20`` else.  (This is necessary since text coordinates
61
 
        refer to the text baseline, not the top edge.)
62
 
 
63
 
    `ystep`
64
 
        Offset to add to the Y coordinate for each subsequent line.  This should
65
 
        roughly be the text size plus 5.  It defaults to that value if the text
66
 
        size is given in pixels, or ``25`` else.
67
 
 
68
 
    `spacehack`
69
 
        Convert spaces in the source to ``&#160;``, which are non-breaking
70
 
        spaces.  SVG provides the ``xml:space`` attribute to control how
71
 
        whitespace inside tags is handled, in theory, the ``preserve`` value
72
 
        could be used to keep all whitespace as-is.  However, many current SVG
73
 
        viewers don't obey that rule, so this option is provided as a workaround
74
 
        and defaults to ``True``.
75
 
    """
76
 
    name = 'SVG'
77
 
    aliases = ['svg']
78
 
    filenames = ['*.svg']
79
 
 
80
 
    def __init__(self, **options):
81
 
        # XXX outencoding
82
 
        Formatter.__init__(self, **options)
83
 
        self.nowrap = get_bool_opt(options, 'nowrap', False)
84
 
        self.fontfamily = options.get('fontfamily', 'monospace')
85
 
        self.fontsize = options.get('fontsize', '14px')
86
 
        self.xoffset = get_int_opt(options, 'xoffset', 0)
87
 
        fs = self.fontsize.strip()
88
 
        if fs.endswith('px'): fs = fs[:-2].strip()
89
 
        try:
90
 
            int_fs = int(fs)
91
 
        except:
92
 
            int_fs = 20
93
 
        self.yoffset = get_int_opt(options, 'yoffset', int_fs)
94
 
        self.ystep = get_int_opt(options, 'ystep', int_fs + 5)
95
 
        self.spacehack = get_bool_opt(options, 'spacehack', True)
96
 
        self._stylecache = {}
97
 
 
98
 
    def format_unencoded(self, tokensource, outfile):
99
 
        """
100
 
        Format ``tokensource``, an iterable of ``(tokentype, tokenstring)``
101
 
        tuples and write it into ``outfile``.
102
 
 
103
 
        For our implementation we put all lines in their own 'line group'.
104
 
        """
105
 
        x = self.xoffset
106
 
        y = self.yoffset
107
 
        if not self.nowrap:
108
 
            if self.encoding:
109
 
                outfile.write('<?xml version="1.0" encoding="%s"?>\n' %
110
 
                              self.encoding)
111
 
            else:
112
 
                outfile.write('<?xml version="1.0"?>\n')
113
 
            outfile.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" '
114
 
                          '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/'
115
 
                          'svg10.dtd">\n')
116
 
            outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n')
117
 
            outfile.write('<g font-family="%s" font-size="%s">\n' %
118
 
                          (self.fontfamily, self.fontsize))
119
 
        outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (x, y))
120
 
        for ttype, value in tokensource:
121
 
            style = self._get_style(ttype)
122
 
            tspan = style and '<tspan' + style + '>' or ''
123
 
            tspanend = tspan and '</tspan>' or ''
124
 
            value = escape_html(value)
125
 
            if self.spacehack:
126
 
                value = value.expandtabs().replace(' ', '&#160;')
127
 
            parts = value.split('\n')
128
 
            for part in parts[:-1]:
129
 
                outfile.write(tspan + part + tspanend)
130
 
                y += self.ystep
131
 
                outfile.write('</text>\n<text x="%s" y="%s" '
132
 
                              'xml:space="preserve">' % (x, y))
133
 
            outfile.write(tspan + parts[-1] + tspanend)
134
 
        outfile.write('</text>')
135
 
 
136
 
        if not self.nowrap:
137
 
            outfile.write('</g></svg>\n')
138
 
 
139
 
    def _get_style(self, tokentype):
140
 
        if tokentype in self._stylecache:
141
 
            return self._stylecache[tokentype]
142
 
        otokentype = tokentype
143
 
        while not self.style.styles_token(tokentype):
144
 
            tokentype = tokentype.parent
145
 
        value = self.style.style_for_token(tokentype)
146
 
        result = ''
147
 
        if value['color']:
148
 
            result = ' fill="#' + value['color'] + '"'
149
 
        if value['bold']:
150
 
            result += ' font-weight="bold"'
151
 
        if value['italic']:
152
 
            result += ' font-style="italic"'
153
 
        self._stylecache[otokentype] = result
154
 
        return result