Anonymous avatar Anonymous committed 35fa367

Add SVG formatter.

Comments (0)

Files changed (3)

 
 - Added 256-color terminal formatter.
 
+- Added an experimental SVG formatter.
+
 - Added the ``lineanchors`` option to the HTML formatter, thanks to
   Ian Charnas for the idea.
 

pygments/formatters/_mapping.py

 from pygments.formatters.other import NullFormatter
 from pygments.formatters.other import RawTokenFormatter
 from pygments.formatters.rtf import RtfFormatter
+from pygments.formatters.svg import SvgFormatter
 from pygments.formatters.terminal import TerminalFormatter
 from pygments.formatters.terminal256 import Terminal256Formatter
 
     NullFormatter: ('Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'),
     RawTokenFormatter: ('Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'),
     RtfFormatter: ('RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft\xc2\xae Word\xc2\xae documents.'),
+    SvgFormatter: ('SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file.  This formatter is still experimental.'),
     Terminal256Formatter: ('Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'),
     TerminalFormatter: ('Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.')
 }

pygments/formatters/svg.py

+# -*- coding: utf-8 -*-
+"""
+    pygments.formatters.svg
+    ~~~~~~~~~~~~~~~~~~~~~~~
+
+    Formatter for SVG output.
+
+    :copyright: 2007 by an unknown contributor.
+    :license: BSD, see LICENSE for more details.
+"""
+import StringIO
+
+from pygments.formatter import Formatter
+from pygments.util import get_bool_opt, get_int_opt
+
+__all__ = ['SvgFormatter']
+
+
+def escape_html(text):
+    """Escape &, <, > as well as single and double quotes for HTML."""
+    return text.replace('&', '&amp;').  \
+                replace('<', '&lt;').   \
+                replace('>', '&gt;').   \
+                replace('"', '&quot;'). \
+                replace("'", '&#39;')
+
+
+class2style = {}
+
+class SvgFormatter(Formatter):
+    """
+    Format tokens as an SVG graphics file.  This formatter is still experimental.
+    Each line of code is a ``<text>`` element with explicit ``x`` and ``y``
+    coordinates containing ``<tspan>`` elements with the individual token styles.
+
+    *New in Pygments 0.9.*
+
+    Additional options accepted:
+
+    `nowrap`
+        Don't wrap the SVG ``<text>`` elements in ``<svg><g>`` elements and
+        don't add a XML declaration and a doctype.  If true, the `fontfamily`
+        and `fontsize` options are ignored.  Defaults to ``False``.
+
+    `fontfamily`
+        The value to give the ``<text>`` elements' ``font-family`` attribute,
+        defaults to ``"monospace"``.
+
+    `fontsize`
+        The value to give the ``<text>`` elements' ``font-size`` attribute,
+        defaults to ``"14px"``.
+
+    `xoffset`
+        Starting offset in X direction, defaults to ``0``.
+
+    `yoffset`
+        Starting offset in Y direction, defaults to the font size if it is given
+        in pixels, or ``20`` else.  (This is necessary since text coordinates
+        refer to the text baseline, not the top edge.)
+
+    `ystep`
+        Offset to add to the Y coordinate for each subsequent line.  This should
+        roughly be the text size plus 5.  It defaults to that value if the text
+        size is given in pixels, or ``25`` else.
+
+    `spacehack`
+        Convert spaces in the source to ``&160;``, which are non-breaking
+        spaces.  SVG provides the ``xml:space`` attribute to control how
+        whitespace inside tags is handled, in theory, the ``preserve`` value
+        could be used to keep all whitespace as-is.  However, many current SVG
+        viewers don't obey that rule, so this option is provided as a workaround
+        and defaults to ``True``.
+    """
+    name = 'SVG'
+    aliases = ['svg']
+    filenames = ['*.svg']
+
+    def __init__(self, **options):
+        # XXX outencoding
+        Formatter.__init__(self, **options)
+        self.nowrap = get_bool_opt(options, 'nowrap', False)
+        self.fontfamily = options.get('fontfamily', 'monospace')
+        self.fontsize = options.get('fontsize', '14px')
+        self.xoffset = get_int_opt(options, 'xoffset', 0)
+        fs = self.fontsize.strip()
+        if fs.endswith('px'): fs = fs[:-2].strip()
+        try:
+            int_fs = int(fs)
+        except:
+            int_fs = 20
+        self.yoffset = get_int_opt(options, 'yoffset', int_fs)
+        self.ystep = get_int_opt(options, 'ystep', int_fs + 5)
+        self.spacehack = get_bool_opt(options, 'spacehack', True)
+        self._stylecache = {}
+
+    def format(self, tokensource, outfile):
+        """
+        Format ``tokensource``, an iterable of ``(tokentype, tokenstring)``
+        tuples and write it into ``outfile``.
+
+        For our implementation we put all lines in their own 'line group'.
+        """
+        x = self.xoffset
+        y = self.yoffset
+        enc = self.encoding
+        if not self.nowrap:
+            if enc:
+                outfile.write('<?xml version="1.0" encoding="%s"?>\n' % self.encoding)
+            else:
+                outfile.write('<?xml version="1.0"?>\n')
+            outfile.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" '
+                          '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">\n')
+            outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n')
+            outfile.write('<g font-family="%s" font-size="%s">\n' % (self.fontfamily,
+                                                                     self.fontsize))
+        outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (x, y))
+        for ttype, value in tokensource:
+            if enc:
+                value = value.encode(enc)
+            style = self._get_style(ttype)
+            tspan = style and '<tspan' + style + '>' or ''
+            tspanend = tspan and '</tspan>' or ''
+            value = escape_html(value)
+            if self.spacehack:
+                value = value.expandtabs().replace(' ', '&#160;')
+            parts = value.split('\n')
+            for part in parts[:-1]:
+                outfile.write(tspan + part + tspanend)
+                y += self.ystep
+                outfile.write('</text>\n<text x="%s" y="%s" '
+                              'xml:space="preserve">' % (x, y))
+            outfile.write(tspan + parts[-1] + tspanend)
+        outfile.write('</text>')
+
+        if not self.nowrap:
+            outfile.write('</g></svg>\n')
+
+    def _get_style(self, tokentype):
+        if tokentype in self._stylecache:
+            return self._stylecache[tokentype]
+        otokentype = tokentype
+        while not self.style.styles_token(tokentype):
+            tokentype = tokentype.parent
+        value = self.style.style_for_token(tokentype)
+        result = ''
+        if value['color']:
+            result = ' fill="#' + value['color'] + '"'
+        if value['bold']:
+            result += ' font-weight="bold"'
+        if value['italic']:
+            result += ' font-style="italic"'
+        self._stylecache[otokentype] = result
+        return result
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.