# -*- coding: utf-8 -*-""" pygments.formatters.svg ~~~~~~~~~~~~~~~~~~~~~~~ Formatter for SVG output. :copyright: Copyright 2006-2010 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details."""frompygments.formatterimportFormatterfrompygments.utilimportget_bool_opt,get_int_opt__all__=['SvgFormatter']defescape_html(text):"""Escape &, <, > as well as single and double quotes for HTML."""returntext.replace('&','&amp;'). \
replace('<','&lt;'). \
replace('>','&gt;'). \
replace('"','&quot;'). \
replace("'",'&#39;')class2style={}classSvgFormatter(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. By default, this formatter outputs a full SVG document including doctype declaration and the ``<svg>`` root element. *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 wrapping ``<g>`` element's ``font-family`` attribute, defaults to ``"monospace"``. `fontsize` The value to give the wrapping ``<g>`` element's ``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 outencodingFormatter.__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()iffs.endswith('px'):fs=fs[:-2].strip()try:int_fs=int(fs)except:int_fs=20self.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={}defformat_unencoded(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.xoffsety=self.yoffsetifnotself.nowrap:ifself.encoding: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))forttype,valueintokensource:style=self._get_style(ttype)tspan=styleand'<tspan'+style+'>'or''tspanend=tspanand'</tspan>'or''value=escape_html(value)ifself.spacehack:value=value.expandtabs().replace(' ','&#160;')parts=value.split('\n')forpartinparts[:-1]:outfile.write(tspan+part+tspanend)y+=self.ystepoutfile.write('</text>\n<text x="%s" y="%s" ''xml:space="preserve">'%(x,y))outfile.write(tspan+parts[-1]+tspanend)outfile.write('</text>')ifnotself.nowrap:outfile.write('</g></svg>\n')def_get_style(self,tokentype):iftokentypeinself._stylecache:returnself._stylecache[tokentype]otokentype=tokentypewhilenotself.style.styles_token(tokentype):tokentype=tokentype.parentvalue=self.style.style_for_token(tokentype)result=''ifvalue['color']:result=' fill="#'+value['color']+'"'ifvalue['bold']:result+=' font-weight="bold"'ifvalue['italic']:result+=' font-style="italic"'self._stylecache[otokentype]=resultreturnresult