]>
jfr.im git - dlqueue.git/blob - venv/lib/python3.11/site-packages/pip/_vendor/pygments/formatters/svg.py
2 pygments.formatters.svg
3 ~~~~~~~~~~~~~~~~~~~~~~~
5 Formatter for SVG output.
7 :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
11 from pip
._vendor
.pygments
.formatter
import Formatter
12 from pip
._vendor
.pygments
.token
import Comment
13 from pip
._vendor
.pygments
.util
import get_bool_opt
, get_int_opt
15 __all__
= ['SvgFormatter']
18 def escape_html(text
):
19 """Escape &, <, > as well as single and double quotes for HTML."""
20 return text
.replace('&', '&'). \
21 replace('<', '<'). \
22 replace('>', '>'). \
23 replace('"', '"'). \
29 class SvgFormatter(Formatter
):
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.
35 By default, this formatter outputs a full SVG document including doctype
36 declaration and the ``<svg>`` root element.
40 Additional options accepted:
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``.
48 The value to give the wrapping ``<g>`` element's ``font-family``
49 attribute, defaults to ``"monospace"``.
52 The value to give the wrapping ``<g>`` element's ``font-size``
53 attribute, defaults to ``"14px"``.
56 If ``True``, add line numbers (default: ``False``).
59 The line number for the first line (default: ``1``).
62 If set to a number n > 1, only every nth line number is printed.
65 Maximum width devoted to line numbers (default: ``3*ystep``, sufficient
66 for up to 4-digit line numbers. Increase width for longer code blocks).
69 Starting offset in X direction, defaults to ``0``.
72 Starting offset in Y direction, defaults to the font size if it is given
73 in pixels, or ``20`` else. (This is necessary since text coordinates
74 refer to the text baseline, not the top edge.)
77 Offset to add to the Y coordinate for each subsequent line. This should
78 roughly be the text size plus 5. It defaults to that value if the text
79 size is given in pixels, or ``25`` else.
82 Convert spaces in the source to `` ``, which are non-breaking
83 spaces. SVG provides the ``xml:space`` attribute to control how
84 whitespace inside tags is handled, in theory, the ``preserve`` value
85 could be used to keep all whitespace as-is. However, many current SVG
86 viewers don't obey that rule, so this option is provided as a workaround
87 and defaults to ``True``.
93 def __init__(self
, **options
):
94 Formatter
.__init
__(self
, **options
)
95 self
.nowrap
= get_bool_opt(options
, 'nowrap', False)
96 self
.fontfamily
= options
.get('fontfamily', 'monospace')
97 self
.fontsize
= options
.get('fontsize', '14px')
98 self
.xoffset
= get_int_opt(options
, 'xoffset', 0)
99 fs
= self
.fontsize
.strip()
100 if fs
.endswith('px'): fs
= fs
[:-2].strip()
105 self
.yoffset
= get_int_opt(options
, 'yoffset', int_fs
)
106 self
.ystep
= get_int_opt(options
, 'ystep', int_fs
+ 5)
107 self
.spacehack
= get_bool_opt(options
, 'spacehack', True)
108 self
.linenos
= get_bool_opt(options
,'linenos',False)
109 self
.linenostart
= get_int_opt(options
,'linenostart',1)
110 self
.linenostep
= get_int_opt(options
,'linenostep',1)
111 self
.linenowidth
= get_int_opt(options
,'linenowidth', 3*self
.ystep
)
112 self
._stylecache
= {}
114 def format_unencoded(self
, tokensource
, outfile
):
116 Format ``tokensource``, an iterable of ``(tokentype, tokenstring)``
117 tuples and write it into ``outfile``.
119 For our implementation we put all lines in their own 'line group'.
125 outfile
.write('<?xml version="1.0" encoding="%s"?>\n' %
128 outfile
.write('<?xml version="1.0"?>\n')
129 outfile
.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" '
130 '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/'
132 outfile
.write('<svg xmlns="http://www.w3.org/2000/svg">\n')
133 outfile
.write('<g font-family="%s" font-size="%s">\n' %
134 (self
.fontfamily
, self
.fontsize
))
136 counter
= self
.linenostart
137 counter_step
= self
.linenostep
138 counter_style
= self
._get
_style
(Comment
)
142 if counter
% counter_step
== 0:
143 outfile
.write('<text x="%s" y="%s" %s text-anchor="end">%s</text>' %
144 (x
+self
.linenowidth
,y
,counter_style
,counter
))
145 line_x
+= self
.linenowidth
+ self
.ystep
148 outfile
.write('<text x="%s" y="%s" xml:space="preserve">' % (line_x
, y
))
149 for ttype
, value
in tokensource
:
150 style
= self
._get
_style
(ttype
)
151 tspan
= style
and '<tspan' + style
+ '>' or ''
152 tspanend
= tspan
and '</tspan>' or ''
153 value
= escape_html(value
)
155 value
= value
.expandtabs().replace(' ', ' ')
156 parts
= value
.split('\n')
157 for part
in parts
[:-1]:
158 outfile
.write(tspan
+ part
+ tspanend
)
160 outfile
.write('</text>\n')
161 if self
.linenos
and counter
% counter_step
== 0:
162 outfile
.write('<text x="%s" y="%s" text-anchor="end" %s>%s</text>' %
163 (x
+self
.linenowidth
,y
,counter_style
,counter
))
166 outfile
.write('<text x="%s" y="%s" ' 'xml:space="preserve">' % (line_x
,y
))
167 outfile
.write(tspan
+ parts
[-1] + tspanend
)
168 outfile
.write('</text>')
171 outfile
.write('</g></svg>\n')
173 def _get_style(self
, tokentype
):
174 if tokentype
in self
._stylecache
:
175 return self
._stylecache
[tokentype
]
176 otokentype
= tokentype
177 while not self
.style
.styles_token(tokentype
):
178 tokentype
= tokentype
.parent
179 value
= self
.style
.style_for_token(tokentype
)
182 result
= ' fill="#' + value
['color'] + '"'
184 result
+= ' font-weight="bold"'
186 result
+= ' font-style="italic"'
187 self
._stylecache
[otokentype
] = result