Spaces:
Sleeping
Sleeping
whisper-large-v3
/
venv
/lib
/python3.10
/site-packages
/pip
/_vendor
/pygments
/formatters
/html.py
""" | |
pygments.formatters.html | |
~~~~~~~~~~~~~~~~~~~~~~~~ | |
Formatter for HTML output. | |
:copyright: Copyright 2006-2022 by the Pygments team, see AUTHORS. | |
:license: BSD, see LICENSE for details. | |
""" | |
import functools | |
import os | |
import sys | |
import os.path | |
from io import StringIO | |
from pip._vendor.pygments.formatter import Formatter | |
from pip._vendor.pygments.token import Token, Text, STANDARD_TYPES | |
from pip._vendor.pygments.util import get_bool_opt, get_int_opt, get_list_opt | |
try: | |
import ctags | |
except ImportError: | |
ctags = None | |
__all__ = ['HtmlFormatter'] | |
_escape_html_table = { | |
ord('&'): '&', | |
ord('<'): '<', | |
ord('>'): '>', | |
ord('"'): '"', | |
ord("'"): ''', | |
} | |
def escape_html(text, table=_escape_html_table): | |
"""Escape &, <, > as well as single and double quotes for HTML.""" | |
return text.translate(table) | |
def webify(color): | |
if color.startswith('calc') or color.startswith('var'): | |
return color | |
else: | |
return '#' + color | |
def _get_ttype_class(ttype): | |
fname = STANDARD_TYPES.get(ttype) | |
if fname: | |
return fname | |
aname = '' | |
while fname is None: | |
aname = '-' + ttype[-1] + aname | |
ttype = ttype.parent | |
fname = STANDARD_TYPES.get(ttype) | |
return fname + aname | |
CSSFILE_TEMPLATE = '''\ | |
/* | |
generated by Pygments <https://pygments.org/> | |
Copyright 2006-2022 by the Pygments team. | |
Licensed under the BSD license, see LICENSE for details. | |
*/ | |
%(styledefs)s | |
''' | |
DOC_HEADER = '''\ | |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" | |
"http://www.w3.org/TR/html4/strict.dtd"> | |
<!-- | |
generated by Pygments <https://pygments.org/> | |
Copyright 2006-2022 by the Pygments team. | |
Licensed under the BSD license, see LICENSE for details. | |
--> | |
<html> | |
<head> | |
<title>%(title)s</title> | |
<meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> | |
<style type="text/css"> | |
''' + CSSFILE_TEMPLATE + ''' | |
</style> | |
</head> | |
<body> | |
<h2>%(title)s</h2> | |
''' | |
DOC_HEADER_EXTERNALCSS = '''\ | |
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" | |
"http://www.w3.org/TR/html4/strict.dtd"> | |
<html> | |
<head> | |
<title>%(title)s</title> | |
<meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> | |
<link rel="stylesheet" href="%(cssfile)s" type="text/css"> | |
</head> | |
<body> | |
<h2>%(title)s</h2> | |
''' | |
DOC_FOOTER = '''\ | |
</body> | |
</html> | |
''' | |
class HtmlFormatter(Formatter): | |
r""" | |
Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped | |
in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` | |
option. | |
If the `linenos` option is set to ``"table"``, the ``<pre>`` is | |
additionally wrapped inside a ``<table>`` which has one row and two | |
cells: one containing the line numbers and one containing the code. | |
Example: | |
.. sourcecode:: html | |
<div class="highlight" > | |
<table><tr> | |
<td class="linenos" title="click to toggle" | |
onclick="with (this.firstChild.style) | |
{ display = (display == '') ? 'none' : '' }"> | |
<pre>1 | |
2</pre> | |
</td> | |
<td class="code"> | |
<pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar): | |
<span class="Ke">pass</span> | |
</pre> | |
</td> | |
</tr></table></div> | |
(whitespace added to improve clarity). | |
Wrapping can be disabled using the `nowrap` option. | |
A list of lines can be specified using the `hl_lines` option to make these | |
lines highlighted (as of Pygments 0.11). | |
With the `full` option, a complete HTML 4 document is output, including | |
the style definitions inside a ``<style>`` tag, or in a separate file if | |
the `cssfile` option is given. | |
When `tagsfile` is set to the path of a ctags index file, it is used to | |
generate hyperlinks from names to their definition. You must enable | |
`lineanchors` and run ctags with the `-n` option for this to work. The | |
`python-ctags` module from PyPI must be installed to use this feature; | |
otherwise a `RuntimeError` will be raised. | |
The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string | |
containing CSS rules for the CSS classes used by the formatter. The | |
argument `arg` can be used to specify additional CSS selectors that | |
are prepended to the classes. A call `fmter.get_style_defs('td .code')` | |
would result in the following CSS classes: | |
.. sourcecode:: css | |
td .code .kw { font-weight: bold; color: #00FF00 } | |
td .code .cm { color: #999999 } | |
... | |
If you have Pygments 0.6 or higher, you can also pass a list or tuple to the | |
`get_style_defs()` method to request multiple prefixes for the tokens: | |
.. sourcecode:: python | |
formatter.get_style_defs(['div.syntax pre', 'pre.syntax']) | |
The output would then look like this: | |
.. sourcecode:: css | |
div.syntax pre .kw, | |
pre.syntax .kw { font-weight: bold; color: #00FF00 } | |
div.syntax pre .cm, | |
pre.syntax .cm { color: #999999 } | |
... | |
Additional options accepted: | |
`nowrap` | |
If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>`` | |
tag. This disables most other options (default: ``False``). | |
`full` | |
Tells the formatter to output a "full" document, i.e. a complete | |
self-contained document (default: ``False``). | |
`title` | |
If `full` is true, the title that should be used to caption the | |
document (default: ``''``). | |
`style` | |
The style to use, can be a string or a Style subclass (default: | |
``'default'``). This option has no effect if the `cssfile` | |
and `noclobber_cssfile` option are given and the file specified in | |
`cssfile` exists. | |
`noclasses` | |
If set to true, token ``<span>`` tags (as well as line number elements) | |
will not use CSS classes, but inline styles. This is not recommended | |
for larger pieces of code since it increases output size by quite a bit | |
(default: ``False``). | |
`classprefix` | |
Since the token types use relatively short class names, they may clash | |
with some of your own class names. In this case you can use the | |
`classprefix` option to give a string to prepend to all Pygments-generated | |
CSS class names for token types. | |
Note that this option also affects the output of `get_style_defs()`. | |
`cssclass` | |
CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``). | |
If you set this option, the default selector for `get_style_defs()` | |
will be this class. | |
.. versionadded:: 0.9 | |
If you select the ``'table'`` line numbers, the wrapping table will | |
have a CSS class of this string plus ``'table'``, the default is | |
accordingly ``'highlighttable'``. | |
`cssstyles` | |
Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``). | |
`prestyles` | |
Inline CSS styles for the ``<pre>`` tag (default: ``''``). | |
.. versionadded:: 0.11 | |
`cssfile` | |
If the `full` option is true and this option is given, it must be the | |
name of an external file. If the filename does not include an absolute | |
path, the file's path will be assumed to be relative to the main output | |
file's path, if the latter can be found. The stylesheet is then written | |
to this file instead of the HTML file. | |
.. versionadded:: 0.6 | |
`noclobber_cssfile` | |
If `cssfile` is given and the specified file exists, the css file will | |
not be overwritten. This allows the use of the `full` option in | |
combination with a user specified css file. Default is ``False``. | |
.. versionadded:: 1.1 | |
`linenos` | |
If set to ``'table'``, output line numbers as a table with two cells, | |
one containing the line numbers, the other the whole code. This is | |
copy-and-paste-friendly, but may cause alignment problems with some | |
browsers or fonts. If set to ``'inline'``, the line numbers will be | |
integrated in the ``<pre>`` tag that contains the code (that setting | |
is *new in Pygments 0.8*). | |
For compatibility with Pygments 0.7 and earlier, every true value | |
except ``'inline'`` means the same as ``'table'`` (in particular, that | |
means also ``True``). | |
The default value is ``False``, which means no line numbers at all. | |
**Note:** with the default ("table") line number mechanism, the line | |
numbers and code can have different line heights in Internet Explorer | |
unless you give the enclosing ``<pre>`` tags an explicit ``line-height`` | |
CSS property (you get the default line spacing with ``line-height: | |
125%``). | |
`hl_lines` | |
Specify a list of lines to be highlighted. The line numbers are always | |
relative to the input (i.e. the first line is line 1) and are | |
independent of `linenostart`. | |
.. versionadded:: 0.11 | |
`linenostart` | |
The line number for the first line (default: ``1``). | |
`linenostep` | |
If set to a number n > 1, only every nth line number is printed. | |
`linenospecial` | |
If set to a number n > 0, every nth line number is given the CSS | |
class ``"special"`` (default: ``0``). | |
`nobackground` | |
If set to ``True``, the formatter won't output the background color | |
for the wrapping element (this automatically defaults to ``False`` | |
when there is no wrapping element [eg: no argument for the | |
`get_syntax_defs` method given]) (default: ``False``). | |
.. versionadded:: 0.6 | |
`lineseparator` | |
This string is output between lines of code. It defaults to ``"\n"``, | |
which is enough to break a line inside ``<pre>`` tags, but you can | |
e.g. set it to ``"<br>"`` to get HTML line breaks. | |
.. versionadded:: 0.7 | |
`lineanchors` | |
If set to a nonempty string, e.g. ``foo``, the formatter will wrap each | |
output line in an anchor tag with an ``id`` (and `name`) of ``foo-linenumber``. | |
This allows easy linking to certain lines. | |
.. versionadded:: 0.9 | |
`linespans` | |
If set to a nonempty string, e.g. ``foo``, the formatter will wrap each | |
output line in a span tag with an ``id`` of ``foo-linenumber``. | |
This allows easy access to lines via javascript. | |
.. versionadded:: 1.6 | |
`anchorlinenos` | |
If set to `True`, will wrap line numbers in <a> tags. Used in | |
combination with `linenos` and `lineanchors`. | |
`tagsfile` | |
If set to the path of a ctags file, wrap names in anchor tags that | |
link to their definitions. `lineanchors` should be used, and the | |
tags file should specify line numbers (see the `-n` option to ctags). | |
.. versionadded:: 1.6 | |
`tagurlformat` | |
A string formatting pattern used to generate links to ctags definitions. | |
Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`. | |
Defaults to an empty string, resulting in just `#prefix-number` links. | |
.. versionadded:: 1.6 | |
`filename` | |
A string used to generate a filename when rendering ``<pre>`` blocks, | |
for example if displaying source code. If `linenos` is set to | |
``'table'`` then the filename will be rendered in an initial row | |
containing a single `<th>` which spans both columns. | |
.. versionadded:: 2.1 | |
`wrapcode` | |
Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended | |
by the HTML5 specification. | |
.. versionadded:: 2.4 | |
`debug_token_types` | |
Add ``title`` attributes to all token ``<span>`` tags that show the | |
name of the token. | |
.. versionadded:: 2.10 | |
**Subclassing the HTML formatter** | |
.. versionadded:: 0.7 | |
The HTML formatter is now built in a way that allows easy subclassing, thus | |
customizing the output HTML code. The `format()` method calls | |
`self._format_lines()` which returns a generator that yields tuples of ``(1, | |
line)``, where the ``1`` indicates that the ``line`` is a line of the | |
formatted source code. | |
If the `nowrap` option is set, the generator is the iterated over and the | |
resulting HTML is output. | |
Otherwise, `format()` calls `self.wrap()`, which wraps the generator with | |
other generators. These may add some HTML code to the one generated by | |
`_format_lines()`, either by modifying the lines generated by the latter, | |
then yielding them again with ``(1, line)``, and/or by yielding other HTML | |
code before or after the lines, with ``(0, html)``. The distinction between | |
source lines and other code makes it possible to wrap the generator multiple | |
times. | |
The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag. | |
A custom `HtmlFormatter` subclass could look like this: | |
.. sourcecode:: python | |
class CodeHtmlFormatter(HtmlFormatter): | |
def wrap(self, source, *, include_div): | |
return self._wrap_code(source) | |
def _wrap_code(self, source): | |
yield 0, '<code>' | |
for i, t in source: | |
if i == 1: | |
# it's a line of formatted code | |
t += '<br>' | |
yield i, t | |
yield 0, '</code>' | |
This results in wrapping the formatted lines with a ``<code>`` tag, where the | |
source lines are broken using ``<br>`` tags. | |
After calling `wrap()`, the `format()` method also adds the "line numbers" | |
and/or "full document" wrappers if the respective options are set. Then, all | |
HTML yielded by the wrapped generator is output. | |
""" | |
name = 'HTML' | |
aliases = ['html'] | |
filenames = ['*.html', '*.htm'] | |
def __init__(self, **options): | |
Formatter.__init__(self, **options) | |
self.title = self._decodeifneeded(self.title) | |
self.nowrap = get_bool_opt(options, 'nowrap', False) | |
self.noclasses = get_bool_opt(options, 'noclasses', False) | |
self.classprefix = options.get('classprefix', '') | |
self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight')) | |
self.cssstyles = self._decodeifneeded(options.get('cssstyles', '')) | |
self.prestyles = self._decodeifneeded(options.get('prestyles', '')) | |
self.cssfile = self._decodeifneeded(options.get('cssfile', '')) | |
self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False) | |
self.tagsfile = self._decodeifneeded(options.get('tagsfile', '')) | |
self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', '')) | |
self.filename = self._decodeifneeded(options.get('filename', '')) | |
self.wrapcode = get_bool_opt(options, 'wrapcode', False) | |
self.span_element_openers = {} | |
self.debug_token_types = get_bool_opt(options, 'debug_token_types', False) | |
if self.tagsfile: | |
if not ctags: | |
raise RuntimeError('The "ctags" package must to be installed ' | |
'to be able to use the "tagsfile" feature.') | |
self._ctags = ctags.CTags(self.tagsfile) | |
linenos = options.get('linenos', False) | |
if linenos == 'inline': | |
self.linenos = 2 | |
elif linenos: | |
# compatibility with <= 0.7 | |
self.linenos = 1 | |
else: | |
self.linenos = 0 | |
self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) | |
self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) | |
self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0)) | |
self.nobackground = get_bool_opt(options, 'nobackground', False) | |
self.lineseparator = options.get('lineseparator', '\n') | |
self.lineanchors = options.get('lineanchors', '') | |
self.linespans = options.get('linespans', '') | |
self.anchorlinenos = get_bool_opt(options, 'anchorlinenos', False) | |
self.hl_lines = set() | |
for lineno in get_list_opt(options, 'hl_lines', []): | |
try: | |
self.hl_lines.add(int(lineno)) | |
except ValueError: | |
pass | |
self._create_stylesheet() | |
def _get_css_class(self, ttype): | |
"""Return the css class of this token type prefixed with | |
the classprefix option.""" | |
ttypeclass = _get_ttype_class(ttype) | |
if ttypeclass: | |
return self.classprefix + ttypeclass | |
return '' | |
def _get_css_classes(self, ttype): | |
"""Return the CSS classes of this token type prefixed with the classprefix option.""" | |
cls = self._get_css_class(ttype) | |
while ttype not in STANDARD_TYPES: | |
ttype = ttype.parent | |
cls = self._get_css_class(ttype) + ' ' + cls | |
return cls or '' | |
def _get_css_inline_styles(self, ttype): | |
"""Return the inline CSS styles for this token type.""" | |
cclass = self.ttype2class.get(ttype) | |
while cclass is None: | |
ttype = ttype.parent | |
cclass = self.ttype2class.get(ttype) | |
return cclass or '' | |
def _create_stylesheet(self): | |
t2c = self.ttype2class = {Token: ''} | |
c2s = self.class2style = {} | |
for ttype, ndef in self.style: | |
name = self._get_css_class(ttype) | |
style = '' | |
if ndef['color']: | |
style += 'color: %s; ' % webify(ndef['color']) | |
if ndef['bold']: | |
style += 'font-weight: bold; ' | |
if ndef['italic']: | |
style += 'font-style: italic; ' | |
if ndef['underline']: | |
style += 'text-decoration: underline; ' | |
if ndef['bgcolor']: | |
style += 'background-color: %s; ' % webify(ndef['bgcolor']) | |
if ndef['border']: | |
style += 'border: 1px solid %s; ' % webify(ndef['border']) | |
if style: | |
t2c[ttype] = name | |
# save len(ttype) to enable ordering the styles by | |
# hierarchy (necessary for CSS cascading rules!) | |
c2s[name] = (style[:-2], ttype, len(ttype)) | |
def get_style_defs(self, arg=None): | |
""" | |
Return CSS style definitions for the classes produced by the current | |
highlighting style. ``arg`` can be a string or list of selectors to | |
insert before the token type classes. | |
""" | |
style_lines = [] | |
style_lines.extend(self.get_linenos_style_defs()) | |
style_lines.extend(self.get_background_style_defs(arg)) | |
style_lines.extend(self.get_token_style_defs(arg)) | |
return '\n'.join(style_lines) | |
def get_token_style_defs(self, arg=None): | |
prefix = self.get_css_prefix(arg) | |
styles = [ | |
(level, ttype, cls, style) | |
for cls, (style, ttype, level) in self.class2style.items() | |
if cls and style | |
] | |
styles.sort() | |
lines = [ | |
'%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:]) | |
for (level, ttype, cls, style) in styles | |
] | |
return lines | |
def get_background_style_defs(self, arg=None): | |
prefix = self.get_css_prefix(arg) | |
bg_color = self.style.background_color | |
hl_color = self.style.highlight_color | |
lines = [] | |
if arg and not self.nobackground and bg_color is not None: | |
text_style = '' | |
if Text in self.ttype2class: | |
text_style = ' ' + self.class2style[self.ttype2class[Text]][0] | |
lines.insert( | |
0, '%s{ background: %s;%s }' % ( | |
prefix(''), bg_color, text_style | |
) | |
) | |
if hl_color is not None: | |
lines.insert( | |
0, '%s { background-color: %s }' % (prefix('hll'), hl_color) | |
) | |
return lines | |
def get_linenos_style_defs(self): | |
lines = [ | |
'pre { %s }' % self._pre_style, | |
'td.linenos .normal { %s }' % self._linenos_style, | |
'span.linenos { %s }' % self._linenos_style, | |
'td.linenos .special { %s }' % self._linenos_special_style, | |
'span.linenos.special { %s }' % self._linenos_special_style, | |
] | |
return lines | |
def get_css_prefix(self, arg): | |
if arg is None: | |
arg = ('cssclass' in self.options and '.'+self.cssclass or '') | |
if isinstance(arg, str): | |
args = [arg] | |
else: | |
args = list(arg) | |
def prefix(cls): | |
if cls: | |
cls = '.' + cls | |
tmp = [] | |
for arg in args: | |
tmp.append((arg and arg + ' ' or '') + cls) | |
return ', '.join(tmp) | |
return prefix | |
def _pre_style(self): | |
return 'line-height: 125%;' | |
def _linenos_style(self): | |
return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % ( | |
self.style.line_number_color, | |
self.style.line_number_background_color | |
) | |
def _linenos_special_style(self): | |
return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % ( | |
self.style.line_number_special_color, | |
self.style.line_number_special_background_color | |
) | |
def _decodeifneeded(self, value): | |
if isinstance(value, bytes): | |
if self.encoding: | |
return value.decode(self.encoding) | |
return value.decode() | |
return value | |
def _wrap_full(self, inner, outfile): | |
if self.cssfile: | |
if os.path.isabs(self.cssfile): | |
# it's an absolute filename | |
cssfilename = self.cssfile | |
else: | |
try: | |
filename = outfile.name | |
if not filename or filename[0] == '<': | |
# pseudo files, e.g. name == '<fdopen>' | |
raise AttributeError | |
cssfilename = os.path.join(os.path.dirname(filename), | |
self.cssfile) | |
except AttributeError: | |
print('Note: Cannot determine output file name, ' | |
'using current directory as base for the CSS file name', | |
file=sys.stderr) | |
cssfilename = self.cssfile | |
# write CSS file only if noclobber_cssfile isn't given as an option. | |
try: | |
if not os.path.exists(cssfilename) or not self.noclobber_cssfile: | |
with open(cssfilename, "w") as cf: | |
cf.write(CSSFILE_TEMPLATE % | |
{'styledefs': self.get_style_defs('body')}) | |
except OSError as err: | |
err.strerror = 'Error writing CSS file: ' + err.strerror | |
raise | |
yield 0, (DOC_HEADER_EXTERNALCSS % | |
dict(title=self.title, | |
cssfile=self.cssfile, | |
encoding=self.encoding)) | |
else: | |
yield 0, (DOC_HEADER % | |
dict(title=self.title, | |
styledefs=self.get_style_defs('body'), | |
encoding=self.encoding)) | |
yield from inner | |
yield 0, DOC_FOOTER | |
def _wrap_tablelinenos(self, inner): | |
dummyoutfile = StringIO() | |
lncount = 0 | |
for t, line in inner: | |
if t: | |
lncount += 1 | |
dummyoutfile.write(line) | |
fl = self.linenostart | |
mw = len(str(lncount + fl - 1)) | |
sp = self.linenospecial | |
st = self.linenostep | |
anchor_name = self.lineanchors or self.linespans | |
aln = self.anchorlinenos | |
nocls = self.noclasses | |
lines = [] | |
for i in range(fl, fl+lncount): | |
print_line = i % st == 0 | |
special_line = sp and i % sp == 0 | |
if print_line: | |
line = '%*d' % (mw, i) | |
if aln: | |
line = '<a href="#%s-%d">%s</a>' % (anchor_name, i, line) | |
else: | |
line = ' ' * mw | |
if nocls: | |
if special_line: | |
style = ' style="%s"' % self._linenos_special_style | |
else: | |
style = ' style="%s"' % self._linenos_style | |
else: | |
if special_line: | |
style = ' class="special"' | |
else: | |
style = ' class="normal"' | |
if style: | |
line = '<span%s>%s</span>' % (style, line) | |
lines.append(line) | |
ls = '\n'.join(lines) | |
# If a filename was specified, we can't put it into the code table as it | |
# would misalign the line numbers. Hence we emit a separate row for it. | |
filename_tr = "" | |
if self.filename: | |
filename_tr = ( | |
'<tr><th colspan="2" class="filename">' | |
'<span class="filename">' + self.filename + '</span>' | |
'</th></tr>') | |
# in case you wonder about the seemingly redundant <div> here: since the | |
# content in the other cell also is wrapped in a div, some browsers in | |
# some configurations seem to mess up the formatting... | |
yield 0, (f'<table class="{self.cssclass}table">' + filename_tr + | |
'<tr><td class="linenos"><div class="linenodiv"><pre>' + | |
ls + '</pre></div></td><td class="code">') | |
yield 0, '<div>' | |
yield 0, dummyoutfile.getvalue() | |
yield 0, '</div>' | |
yield 0, '</td></tr></table>' | |
def _wrap_inlinelinenos(self, inner): | |
# need a list of lines since we need the width of a single number :( | |
inner_lines = list(inner) | |
sp = self.linenospecial | |
st = self.linenostep | |
num = self.linenostart | |
mw = len(str(len(inner_lines) + num - 1)) | |
anchor_name = self.lineanchors or self.linespans | |
aln = self.anchorlinenos | |
nocls = self.noclasses | |
for _, inner_line in inner_lines: | |
print_line = num % st == 0 | |
special_line = sp and num % sp == 0 | |
if print_line: | |
line = '%*d' % (mw, num) | |
else: | |
line = ' ' * mw | |
if nocls: | |
if special_line: | |
style = ' style="%s"' % self._linenos_special_style | |
else: | |
style = ' style="%s"' % self._linenos_style | |
else: | |
if special_line: | |
style = ' class="linenos special"' | |
else: | |
style = ' class="linenos"' | |
if style: | |
linenos = '<span%s>%s</span>' % (style, line) | |
else: | |
linenos = line | |
if aln: | |
yield 1, ('<a href="#%s-%d">%s</a>' % (anchor_name, num, linenos) + | |
inner_line) | |
else: | |
yield 1, linenos + inner_line | |
num += 1 | |
def _wrap_lineanchors(self, inner): | |
s = self.lineanchors | |
# subtract 1 since we have to increment i *before* yielding | |
i = self.linenostart - 1 | |
for t, line in inner: | |
if t: | |
i += 1 | |
href = "" if self.linenos else ' href="#%s-%d"' % (s, i) | |
yield 1, '<a id="%s-%d" name="%s-%d"%s></a>' % (s, i, s, i, href) + line | |
else: | |
yield 0, line | |
def _wrap_linespans(self, inner): | |
s = self.linespans | |
i = self.linenostart - 1 | |
for t, line in inner: | |
if t: | |
i += 1 | |
yield 1, '<span id="%s-%d">%s</span>' % (s, i, line) | |
else: | |
yield 0, line | |
def _wrap_div(self, inner): | |
style = [] | |
if (self.noclasses and not self.nobackground and | |
self.style.background_color is not None): | |
style.append('background: %s' % (self.style.background_color,)) | |
if self.cssstyles: | |
style.append(self.cssstyles) | |
style = '; '.join(style) | |
yield 0, ('<div' + (self.cssclass and ' class="%s"' % self.cssclass) + | |
(style and (' style="%s"' % style)) + '>') | |
yield from inner | |
yield 0, '</div>\n' | |
def _wrap_pre(self, inner): | |
style = [] | |
if self.prestyles: | |
style.append(self.prestyles) | |
if self.noclasses: | |
style.append(self._pre_style) | |
style = '; '.join(style) | |
if self.filename and self.linenos != 1: | |
yield 0, ('<span class="filename">' + self.filename + '</span>') | |
# the empty span here is to keep leading empty lines from being | |
# ignored by HTML parsers | |
yield 0, ('<pre' + (style and ' style="%s"' % style) + '><span></span>') | |
yield from inner | |
yield 0, '</pre>' | |
def _wrap_code(self, inner): | |
yield 0, '<code>' | |
yield from inner | |
yield 0, '</code>' | |
def _translate_parts(self, value): | |
"""HTML-escape a value and split it by newlines.""" | |
return value.translate(_escape_html_table).split('\n') | |
def _format_lines(self, tokensource): | |
""" | |
Just format the tokens, without any wrapping tags. | |
Yield individual lines. | |
""" | |
nocls = self.noclasses | |
lsep = self.lineseparator | |
tagsfile = self.tagsfile | |
lspan = '' | |
line = [] | |
for ttype, value in tokensource: | |
try: | |
cspan = self.span_element_openers[ttype] | |
except KeyError: | |
title = ' title="%s"' % '.'.join(ttype) if self.debug_token_types else '' | |
if nocls: | |
css_style = self._get_css_inline_styles(ttype) | |
if css_style: | |
css_style = self.class2style[css_style][0] | |
cspan = '<span style="%s"%s>' % (css_style, title) | |
else: | |
cspan = '' | |
else: | |
css_class = self._get_css_classes(ttype) | |
if css_class: | |
cspan = '<span class="%s"%s>' % (css_class, title) | |
else: | |
cspan = '' | |
self.span_element_openers[ttype] = cspan | |
parts = self._translate_parts(value) | |
if tagsfile and ttype in Token.Name: | |
filename, linenumber = self._lookup_ctag(value) | |
if linenumber: | |
base, filename = os.path.split(filename) | |
if base: | |
base += '/' | |
filename, extension = os.path.splitext(filename) | |
url = self.tagurlformat % {'path': base, 'fname': filename, | |
'fext': extension} | |
parts[0] = "<a href=\"%s#%s-%d\">%s" % \ | |
(url, self.lineanchors, linenumber, parts[0]) | |
parts[-1] = parts[-1] + "</a>" | |
# for all but the last line | |
for part in parts[:-1]: | |
if line: | |
if lspan != cspan: | |
line.extend(((lspan and '</span>'), cspan, part, | |
(cspan and '</span>'), lsep)) | |
else: # both are the same | |
line.extend((part, (lspan and '</span>'), lsep)) | |
yield 1, ''.join(line) | |
line = [] | |
elif part: | |
yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep)) | |
else: | |
yield 1, lsep | |
# for the last line | |
if line and parts[-1]: | |
if lspan != cspan: | |
line.extend(((lspan and '</span>'), cspan, parts[-1])) | |
lspan = cspan | |
else: | |
line.append(parts[-1]) | |
elif parts[-1]: | |
line = [cspan, parts[-1]] | |
lspan = cspan | |
# else we neither have to open a new span nor set lspan | |
if line: | |
line.extend(((lspan and '</span>'), lsep)) | |
yield 1, ''.join(line) | |
def _lookup_ctag(self, token): | |
entry = ctags.TagEntry() | |
if self._ctags.find(entry, token.encode(), 0): | |
return entry['file'], entry['lineNumber'] | |
else: | |
return None, None | |
def _highlight_lines(self, tokensource): | |
""" | |
Highlighted the lines specified in the `hl_lines` option by | |
post-processing the token stream coming from `_format_lines`. | |
""" | |
hls = self.hl_lines | |
for i, (t, value) in enumerate(tokensource): | |
if t != 1: | |
yield t, value | |
if i + 1 in hls: # i + 1 because Python indexes start at 0 | |
if self.noclasses: | |
style = '' | |
if self.style.highlight_color is not None: | |
style = (' style="background-color: %s"' % | |
(self.style.highlight_color,)) | |
yield 1, '<span%s>%s</span>' % (style, value) | |
else: | |
yield 1, '<span class="hll">%s</span>' % value | |
else: | |
yield 1, value | |
def wrap(self, source): | |
""" | |
Wrap the ``source``, which is a generator yielding | |
individual lines, in custom generators. See docstring | |
for `format`. Can be overridden. | |
""" | |
output = source | |
if self.wrapcode: | |
output = self._wrap_code(output) | |
output = self._wrap_pre(output) | |
return output | |
def format_unencoded(self, tokensource, outfile): | |
""" | |
The formatting process uses several nested generators; which of | |
them are used is determined by the user's options. | |
Each generator should take at least one argument, ``inner``, | |
and wrap the pieces of text generated by this. | |
Always yield 2-tuples: (code, text). If "code" is 1, the text | |
is part of the original tokensource being highlighted, if it's | |
0, the text is some piece of wrapping. This makes it possible to | |
use several different wrappers that process the original source | |
linewise, e.g. line number generators. | |
""" | |
source = self._format_lines(tokensource) | |
# As a special case, we wrap line numbers before line highlighting | |
# so the line numbers get wrapped in the highlighting tag. | |
if not self.nowrap and self.linenos == 2: | |
source = self._wrap_inlinelinenos(source) | |
if self.hl_lines: | |
source = self._highlight_lines(source) | |
if not self.nowrap: | |
if self.lineanchors: | |
source = self._wrap_lineanchors(source) | |
if self.linespans: | |
source = self._wrap_linespans(source) | |
source = self.wrap(source) | |
if self.linenos == 1: | |
source = self._wrap_tablelinenos(source) | |
source = self._wrap_div(source) | |
if self.full: | |
source = self._wrap_full(source, outfile) | |
for t, piece in source: | |
outfile.write(piece) | |