3 pygments.formatters.svg |
3 pygments.formatters.svg |
4 ~~~~~~~~~~~~~~~~~~~~~~~ |
4 ~~~~~~~~~~~~~~~~~~~~~~~ |
5 |
5 |
6 Formatter for SVG output. |
6 Formatter for SVG output. |
7 |
7 |
8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS. |
8 :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. |
9 :license: BSD, see LICENSE for details. |
9 :license: BSD, see LICENSE for details. |
10 """ |
10 """ |
11 |
11 |
12 from pygments.formatter import Formatter |
12 from pygments.formatter import Formatter |
|
13 from pygments.token import Comment |
13 from pygments.util import get_bool_opt, get_int_opt |
14 from pygments.util import get_bool_opt, get_int_opt |
14 |
15 |
15 __all__ = ['SvgFormatter'] |
16 __all__ = ['SvgFormatter'] |
16 |
17 |
17 |
18 |
50 |
51 |
51 `fontsize` |
52 `fontsize` |
52 The value to give the wrapping ``<g>`` element's ``font-size`` |
53 The value to give the wrapping ``<g>`` element's ``font-size`` |
53 attribute, defaults to ``"14px"``. |
54 attribute, defaults to ``"14px"``. |
54 |
55 |
|
56 `linenos` |
|
57 If ``True``, add line numbers (default: ``False``). |
|
58 |
|
59 `linenostart` |
|
60 The line number for the first line (default: ``1``). |
|
61 |
|
62 `linenostep` |
|
63 If set to a number n > 1, only every nth line number is printed. |
|
64 |
|
65 `linenowidth` |
|
66 Maximum width devoted to line numbers (default: ``3*ystep``, sufficient |
|
67 for up to 4-digit line numbers. Increase width for longer code blocks). |
|
68 |
55 `xoffset` |
69 `xoffset` |
56 Starting offset in X direction, defaults to ``0``. |
70 Starting offset in X direction, defaults to ``0``. |
57 |
71 |
58 `yoffset` |
72 `yoffset` |
59 Starting offset in Y direction, defaults to the font size if it is given |
73 Starting offset in Y direction, defaults to the font size if it is given |
90 except: |
104 except: |
91 int_fs = 20 |
105 int_fs = 20 |
92 self.yoffset = get_int_opt(options, 'yoffset', int_fs) |
106 self.yoffset = get_int_opt(options, 'yoffset', int_fs) |
93 self.ystep = get_int_opt(options, 'ystep', int_fs + 5) |
107 self.ystep = get_int_opt(options, 'ystep', int_fs + 5) |
94 self.spacehack = get_bool_opt(options, 'spacehack', True) |
108 self.spacehack = get_bool_opt(options, 'spacehack', True) |
|
109 self.linenos = get_bool_opt(options,'linenos',False) |
|
110 self.linenostart = get_int_opt(options,'linenostart',1) |
|
111 self.linenostep = get_int_opt(options,'linenostep',1) |
|
112 self.linenowidth = get_int_opt(options,'linenowidth', 3*self.ystep) |
95 self._stylecache = {} |
113 self._stylecache = {} |
96 |
114 |
97 def format_unencoded(self, tokensource, outfile): |
115 def format_unencoded(self, tokensource, outfile): |
98 """ |
116 """ |
99 Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` |
117 Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` |
113 '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/' |
131 '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/' |
114 'svg10.dtd">\n') |
132 'svg10.dtd">\n') |
115 outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n') |
133 outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n') |
116 outfile.write('<g font-family="%s" font-size="%s">\n' % |
134 outfile.write('<g font-family="%s" font-size="%s">\n' % |
117 (self.fontfamily, self.fontsize)) |
135 (self.fontfamily, self.fontsize)) |
118 outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (x, y)) |
136 |
|
137 counter = self.linenostart |
|
138 counter_step = self.linenostep |
|
139 counter_style = self._get_style(Comment) |
|
140 line_x = x |
|
141 |
|
142 if self.linenos: |
|
143 if counter % counter_step == 0: |
|
144 outfile.write('<text x="%s" y="%s" %s text-anchor="end">%s</text>' % (x+self.linenowidth,y,counter_style,counter)) |
|
145 line_x += self.linenowidth + self.ystep |
|
146 counter += 1 |
|
147 |
|
148 outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (line_x, y)) |
119 for ttype, value in tokensource: |
149 for ttype, value in tokensource: |
120 style = self._get_style(ttype) |
150 style = self._get_style(ttype) |
121 tspan = style and '<tspan' + style + '>' or '' |
151 tspan = style and '<tspan' + style + '>' or '' |
122 tspanend = tspan and '</tspan>' or '' |
152 tspanend = tspan and '</tspan>' or '' |
123 value = escape_html(value) |
153 value = escape_html(value) |
125 value = value.expandtabs().replace(' ', ' ') |
155 value = value.expandtabs().replace(' ', ' ') |
126 parts = value.split('\n') |
156 parts = value.split('\n') |
127 for part in parts[:-1]: |
157 for part in parts[:-1]: |
128 outfile.write(tspan + part + tspanend) |
158 outfile.write(tspan + part + tspanend) |
129 y += self.ystep |
159 y += self.ystep |
130 outfile.write('</text>\n<text x="%s" y="%s" ' |
160 outfile.write('</text>\n') |
131 'xml:space="preserve">' % (x, y)) |
161 if self.linenos and counter % counter_step == 0: |
|
162 outfile.write('<text x="%s" y="%s" text-anchor="end" %s>%s</text>' % (x+self.linenowidth,y,counter_style,counter)) |
|
163 |
|
164 counter += 1 |
|
165 outfile.write('<text x="%s" y="%s" ' 'xml:space="preserve">' % (line_x,y)) |
132 outfile.write(tspan + parts[-1] + tspanend) |
166 outfile.write(tspan + parts[-1] + tspanend) |
133 outfile.write('</text>') |
167 outfile.write('</text>') |
134 |
168 |
135 if not self.nowrap: |
169 if not self.nowrap: |
136 outfile.write('</g></svg>\n') |
170 outfile.write('</g></svg>\n') |