2 pygments.formatters.html
3 ~~~~~~~~~~~~~~~~~~~~~~~~
5 Formatter for HTML output.
7 :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
8 :license: BSD, see LICENSE for details.
15 from io
import StringIO
17 from pip
._vendor
.pygments
.formatter
import Formatter
18 from pip
._vendor
.pygments
.token
import Token
, Text
, STANDARD_TYPES
19 from pip
._vendor
.pygments
.util
import get_bool_opt
, get_int_opt
, get_list_opt
26 __all__
= ['HtmlFormatter']
29 _escape_html_table
= {
38 def escape_html(text
, table
=_escape_html_table
):
39 """Escape &, <, > as well as single and double quotes for HTML."""
40 return text
.translate(table
)
44 if color
.startswith('calc') or color
.startswith('var'):
50 def _get_ttype_class(ttype
):
51 fname
= STANDARD_TYPES
.get(ttype
)
56 aname
= '-' + ttype
[-1] + aname
58 fname
= STANDARD_TYPES
.get(ttype
)
62 CSSFILE_TEMPLATE
= '''\
64 generated by Pygments <https://pygments.org/>
65 Copyright 2006-2023 by the Pygments team.
66 Licensed under the BSD license, see LICENSE for details.
72 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
73 "http://www.w3.org/TR/html4/strict.dtd">
75 generated by Pygments <https://pygments.org/>
76 Copyright 2006-2023 by the Pygments team.
77 Licensed under the BSD license, see LICENSE for details.
81 <title>%(title)s</title>
82 <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
83 <style type="text/css">
84 ''' + CSSFILE_TEMPLATE
+ '''
92 DOC_HEADER_EXTERNALCSS
= '''\
93 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
94 "http://www.w3.org/TR/html4/strict.dtd">
98 <title>%(title)s</title>
99 <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
100 <link rel="stylesheet" href="%(cssfile)s" type="text/css">
113 class HtmlFormatter(Formatter
):
115 Format tokens as HTML 4 ``<span>`` tags. By default, the content is enclosed
116 in a ``<pre>`` tag, itself wrapped in a ``<div>`` tag (but see the `nowrap` option).
117 The ``<div>``'s CSS class can be set by the `cssclass` option.
119 If the `linenos` option is set to ``"table"``, the ``<pre>`` is
120 additionally wrapped inside a ``<table>`` which has one row and two
121 cells: one containing the line numbers and one containing the code.
126 <div class="highlight" >
128 <td class="linenos" title="click to toggle"
129 onclick="with (this.firstChild.style)
130 { display = (display == '') ? 'none' : '' }">
135 <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar):
136 <span class="Ke">pass</span>
141 (whitespace added to improve clarity).
143 A list of lines can be specified using the `hl_lines` option to make these
144 lines highlighted (as of Pygments 0.11).
146 With the `full` option, a complete HTML 4 document is output, including
147 the style definitions inside a ``<style>`` tag, or in a separate file if
148 the `cssfile` option is given.
150 When `tagsfile` is set to the path of a ctags index file, it is used to
151 generate hyperlinks from names to their definition. You must enable
152 `lineanchors` and run ctags with the `-n` option for this to work. The
153 `python-ctags` module from PyPI must be installed to use this feature;
154 otherwise a `RuntimeError` will be raised.
156 The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string
157 containing CSS rules for the CSS classes used by the formatter. The
158 argument `arg` can be used to specify additional CSS selectors that
159 are prepended to the classes. A call `fmter.get_style_defs('td .code')`
160 would result in the following CSS classes:
164 td .code .kw { font-weight: bold; color: #00FF00 }
165 td .code .cm { color: #999999 }
168 If you have Pygments 0.6 or higher, you can also pass a list or tuple to the
169 `get_style_defs()` method to request multiple prefixes for the tokens:
171 .. sourcecode:: python
173 formatter.get_style_defs(['div.syntax pre', 'pre.syntax'])
175 The output would then look like this:
180 pre.syntax .kw { font-weight: bold; color: #00FF00 }
182 pre.syntax .cm { color: #999999 }
185 Additional options accepted:
188 If set to ``True``, don't add a ``<pre>`` and a ``<div>`` tag
189 around the tokens. This disables most other options (default: ``False``).
192 Tells the formatter to output a "full" document, i.e. a complete
193 self-contained document (default: ``False``).
196 If `full` is true, the title that should be used to caption the
197 document (default: ``''``).
200 The style to use, can be a string or a Style subclass (default:
201 ``'default'``). This option has no effect if the `cssfile`
202 and `noclobber_cssfile` option are given and the file specified in
206 If set to true, token ``<span>`` tags (as well as line number elements)
207 will not use CSS classes, but inline styles. This is not recommended
208 for larger pieces of code since it increases output size by quite a bit
209 (default: ``False``).
212 Since the token types use relatively short class names, they may clash
213 with some of your own class names. In this case you can use the
214 `classprefix` option to give a string to prepend to all Pygments-generated
215 CSS class names for token types.
216 Note that this option also affects the output of `get_style_defs()`.
219 CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``).
220 If you set this option, the default selector for `get_style_defs()`
223 .. versionadded:: 0.9
224 If you select the ``'table'`` line numbers, the wrapping table will
225 have a CSS class of this string plus ``'table'``, the default is
226 accordingly ``'highlighttable'``.
229 Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``).
232 Inline CSS styles for the ``<pre>`` tag (default: ``''``).
234 .. versionadded:: 0.11
237 If the `full` option is true and this option is given, it must be the
238 name of an external file. If the filename does not include an absolute
239 path, the file's path will be assumed to be relative to the main output
240 file's path, if the latter can be found. The stylesheet is then written
241 to this file instead of the HTML file.
243 .. versionadded:: 0.6
246 If `cssfile` is given and the specified file exists, the css file will
247 not be overwritten. This allows the use of the `full` option in
248 combination with a user specified css file. Default is ``False``.
250 .. versionadded:: 1.1
253 If set to ``'table'``, output line numbers as a table with two cells,
254 one containing the line numbers, the other the whole code. This is
255 copy-and-paste-friendly, but may cause alignment problems with some
256 browsers or fonts. If set to ``'inline'``, the line numbers will be
257 integrated in the ``<pre>`` tag that contains the code (that setting
258 is *new in Pygments 0.8*).
260 For compatibility with Pygments 0.7 and earlier, every true value
261 except ``'inline'`` means the same as ``'table'`` (in particular, that
262 means also ``True``).
264 The default value is ``False``, which means no line numbers at all.
266 **Note:** with the default ("table") line number mechanism, the line
267 numbers and code can have different line heights in Internet Explorer
268 unless you give the enclosing ``<pre>`` tags an explicit ``line-height``
269 CSS property (you get the default line spacing with ``line-height:
273 Specify a list of lines to be highlighted. The line numbers are always
274 relative to the input (i.e. the first line is line 1) and are
275 independent of `linenostart`.
277 .. versionadded:: 0.11
280 The line number for the first line (default: ``1``).
283 If set to a number n > 1, only every nth line number is printed.
286 If set to a number n > 0, every nth line number is given the CSS
287 class ``"special"`` (default: ``0``).
290 If set to ``True``, the formatter won't output the background color
291 for the wrapping element (this automatically defaults to ``False``
292 when there is no wrapping element [eg: no argument for the
293 `get_syntax_defs` method given]) (default: ``False``).
295 .. versionadded:: 0.6
298 This string is output between lines of code. It defaults to ``"\n"``,
299 which is enough to break a line inside ``<pre>`` tags, but you can
300 e.g. set it to ``"<br>"`` to get HTML line breaks.
302 .. versionadded:: 0.7
305 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
306 output line in an anchor tag with an ``id`` (and `name`) of ``foo-linenumber``.
307 This allows easy linking to certain lines.
309 .. versionadded:: 0.9
312 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
313 output line in a span tag with an ``id`` of ``foo-linenumber``.
314 This allows easy access to lines via javascript.
316 .. versionadded:: 1.6
319 If set to `True`, will wrap line numbers in <a> tags. Used in
320 combination with `linenos` and `lineanchors`.
323 If set to the path of a ctags file, wrap names in anchor tags that
324 link to their definitions. `lineanchors` should be used, and the
325 tags file should specify line numbers (see the `-n` option to ctags).
327 .. versionadded:: 1.6
330 A string formatting pattern used to generate links to ctags definitions.
331 Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`.
332 Defaults to an empty string, resulting in just `#prefix-number` links.
334 .. versionadded:: 1.6
337 A string used to generate a filename when rendering ``<pre>`` blocks,
338 for example if displaying source code. If `linenos` is set to
339 ``'table'`` then the filename will be rendered in an initial row
340 containing a single `<th>` which spans both columns.
342 .. versionadded:: 2.1
345 Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended
346 by the HTML5 specification.
348 .. versionadded:: 2.4
351 Add ``title`` attributes to all token ``<span>`` tags that show the
354 .. versionadded:: 2.10
357 **Subclassing the HTML formatter**
359 .. versionadded:: 0.7
361 The HTML formatter is now built in a way that allows easy subclassing, thus
362 customizing the output HTML code. The `format()` method calls
363 `self._format_lines()` which returns a generator that yields tuples of ``(1,
364 line)``, where the ``1`` indicates that the ``line`` is a line of the
365 formatted source code.
367 If the `nowrap` option is set, the generator is the iterated over and the
368 resulting HTML is output.
370 Otherwise, `format()` calls `self.wrap()`, which wraps the generator with
371 other generators. These may add some HTML code to the one generated by
372 `_format_lines()`, either by modifying the lines generated by the latter,
373 then yielding them again with ``(1, line)``, and/or by yielding other HTML
374 code before or after the lines, with ``(0, html)``. The distinction between
375 source lines and other code makes it possible to wrap the generator multiple
378 The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag.
380 A custom `HtmlFormatter` subclass could look like this:
382 .. sourcecode:: python
384 class CodeHtmlFormatter(HtmlFormatter):
386 def wrap(self, source, *, include_div):
387 return self._wrap_code(source)
389 def _wrap_code(self, source):
393 # it's a line of formatted code
398 This results in wrapping the formatted lines with a ``<code>`` tag, where the
399 source lines are broken using ``<br>`` tags.
401 After calling `wrap()`, the `format()` method also adds the "line numbers"
402 and/or "full document" wrappers if the respective options are set. Then, all
403 HTML yielded by the wrapped generator is output.
408 filenames
= ['*.html', '*.htm']
410 def __init__(self
, **options
):
411 Formatter
.__init
__(self
, **options
)
412 self
.title
= self
._decodeifneeded
(self
.title
)
413 self
.nowrap
= get_bool_opt(options
, 'nowrap', False)
414 self
.noclasses
= get_bool_opt(options
, 'noclasses', False)
415 self
.classprefix
= options
.get('classprefix', '')
416 self
.cssclass
= self
._decodeifneeded
(options
.get('cssclass', 'highlight'))
417 self
.cssstyles
= self
._decodeifneeded
(options
.get('cssstyles', ''))
418 self
.prestyles
= self
._decodeifneeded
(options
.get('prestyles', ''))
419 self
.cssfile
= self
._decodeifneeded
(options
.get('cssfile', ''))
420 self
.noclobber_cssfile
= get_bool_opt(options
, 'noclobber_cssfile', False)
421 self
.tagsfile
= self
._decodeifneeded
(options
.get('tagsfile', ''))
422 self
.tagurlformat
= self
._decodeifneeded
(options
.get('tagurlformat', ''))
423 self
.filename
= self
._decodeifneeded
(options
.get('filename', ''))
424 self
.wrapcode
= get_bool_opt(options
, 'wrapcode', False)
425 self
.span_element_openers
= {}
426 self
.debug_token_types
= get_bool_opt(options
, 'debug_token_types', False)
430 raise RuntimeError('The "ctags" package must to be installed '
431 'to be able to use the "tagsfile" feature.')
432 self
._ctags
= ctags
.CTags(self
.tagsfile
)
434 linenos
= options
.get('linenos', False)
435 if linenos
== 'inline':
438 # compatibility with <= 0.7
442 self
.linenostart
= abs(get_int_opt(options
, 'linenostart', 1))
443 self
.linenostep
= abs(get_int_opt(options
, 'linenostep', 1))
444 self
.linenospecial
= abs(get_int_opt(options
, 'linenospecial', 0))
445 self
.nobackground
= get_bool_opt(options
, 'nobackground', False)
446 self
.lineseparator
= options
.get('lineseparator', '\n')
447 self
.lineanchors
= options
.get('lineanchors', '')
448 self
.linespans
= options
.get('linespans', '')
449 self
.anchorlinenos
= get_bool_opt(options
, 'anchorlinenos', False)
450 self
.hl_lines
= set()
451 for lineno
in get_list_opt(options
, 'hl_lines', []):
453 self
.hl_lines
.add(int(lineno
))
457 self
._create
_stylesheet
()
459 def _get_css_class(self
, ttype
):
460 """Return the css class of this token type prefixed with
461 the classprefix option."""
462 ttypeclass
= _get_ttype_class(ttype
)
464 return self
.classprefix
+ ttypeclass
467 def _get_css_classes(self
, ttype
):
468 """Return the CSS classes of this token type prefixed with the classprefix option."""
469 cls
= self
._get
_css
_class
(ttype
)
470 while ttype
not in STANDARD_TYPES
:
472 cls
= self
._get
_css
_class
(ttype
) + ' ' + cls
475 def _get_css_inline_styles(self
, ttype
):
476 """Return the inline CSS styles for this token type."""
477 cclass
= self
.ttype2class
.get(ttype
)
478 while cclass
is None:
480 cclass
= self
.ttype2class
.get(ttype
)
483 def _create_stylesheet(self
):
484 t2c
= self
.ttype2class
= {Token: ''}
485 c2s
= self
.class2style
= {}
486 for ttype
, ndef
in self
.style
:
487 name
= self
._get
_css
_class
(ttype
)
490 style
+= 'color: %s; ' % webify(ndef
['color'])
492 style
+= 'font-weight: bold; '
494 style
+= 'font-style: italic; '
495 if ndef
['underline']:
496 style
+= 'text-decoration: underline; '
498 style
+= 'background-color: %s; ' % webify(ndef
['bgcolor'])
500 style
+= 'border: 1px solid %s; ' % webify(ndef
['border'])
503 # save len(ttype) to enable ordering the styles by
504 # hierarchy (necessary for CSS cascading rules!)
505 c2s
[name
] = (style
[:-2], ttype
, len(ttype
))
507 def get_style_defs(self
, arg
=None):
509 Return CSS style definitions for the classes produced by the current
510 highlighting style. ``arg`` can be a string or list of selectors to
511 insert before the token type classes.
515 style_lines
.extend(self
.get_linenos_style_defs())
516 style_lines
.extend(self
.get_background_style_defs(arg
))
517 style_lines
.extend(self
.get_token_style_defs(arg
))
519 return '\n'.join(style_lines
)
521 def get_token_style_defs(self
, arg
=None):
522 prefix
= self
.get_css_prefix(arg
)
525 (level
, ttype
, cls
, style
)
526 for cls
, (style
, ttype
, level
) in self
.class2style
.items()
532 '%s { %s } /* %s */' % (prefix(cls
), style
, repr(ttype
)[6:])
533 for (level
, ttype
, cls
, style
) in styles
538 def get_background_style_defs(self
, arg
=None):
539 prefix
= self
.get_css_prefix(arg
)
540 bg_color
= self
.style
.background_color
541 hl_color
= self
.style
.highlight_color
545 if arg
and not self
.nobackground
and bg_color
is not None:
547 if Text
in self
.ttype2class
:
548 text_style
= ' ' + self
.class2style
[self
.ttype2class
[Text
]][0]
550 0, '%s{ background: %s;%s }' % (
551 prefix(''), bg_color
, text_style
554 if hl_color
is not None:
556 0, '%s { background-color: %s }' % (prefix('hll'), hl_color
)
561 def get_linenos_style_defs(self
):
563 'pre { %s }' % self
._pre
_style
,
564 'td.linenos .normal { %s }' % self
._linenos
_style
,
565 'span.linenos { %s }' % self
._linenos
_style
,
566 'td.linenos .special { %s }' % self
._linenos
_special
_style
,
567 'span.linenos.special { %s }' % self
._linenos
_special
_style
,
572 def get_css_prefix(self
, arg
):
574 arg
= ('cssclass' in self
.options
and '.'+self
.cssclass
or '')
575 if isinstance(arg
, str):
585 tmp
.append((arg
and arg
+ ' ' or '') + cls
)
586 return ', '.join(tmp
)
591 def _pre_style(self
):
592 return 'line-height: 125%;'
595 def _linenos_style(self
):
596 return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % (
597 self
.style
.line_number_color
,
598 self
.style
.line_number_background_color
602 def _linenos_special_style(self
):
603 return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % (
604 self
.style
.line_number_special_color
,
605 self
.style
.line_number_special_background_color
608 def _decodeifneeded(self
, value
):
609 if isinstance(value
, bytes):
611 return value
.decode(self
.encoding
)
612 return value
.decode()
615 def _wrap_full(self
, inner
, outfile
):
617 if os
.path
.isabs(self
.cssfile
):
618 # it's an absolute filename
619 cssfilename
= self
.cssfile
622 filename
= outfile
.name
623 if not filename
or filename
[0] == '<':
624 # pseudo files, e.g. name == '<fdopen>'
626 cssfilename
= os
.path
.join(os
.path
.dirname(filename
),
628 except AttributeError:
629 print('Note: Cannot determine output file name, '
630 'using current directory as base for the CSS file name',
632 cssfilename
= self
.cssfile
633 # write CSS file only if noclobber_cssfile isn't given as an option.
635 if not os
.path
.exists(cssfilename
) or not self
.noclobber_cssfile
:
636 with open(cssfilename
, "w", encoding
="utf-8") as cf
:
637 cf
.write(CSSFILE_TEMPLATE
%
638 {'styledefs': self.get_style_defs('body')}
)
639 except OSError as err
:
640 err
.strerror
= 'Error writing CSS file: ' + err
.strerror
643 yield 0, (DOC_HEADER_EXTERNALCSS
%
644 dict(title
=self
.title
,
645 cssfile
=self
.cssfile
,
646 encoding
=self
.encoding
))
648 yield 0, (DOC_HEADER
%
649 dict(title
=self
.title
,
650 styledefs
=self
.get_style_defs('body'),
651 encoding
=self
.encoding
))
656 def _wrap_tablelinenos(self
, inner
):
657 dummyoutfile
= StringIO()
659 for t
, line
in inner
:
662 dummyoutfile
.write(line
)
664 fl
= self
.linenostart
665 mw
= len(str(lncount
+ fl
- 1))
666 sp
= self
.linenospecial
668 anchor_name
= self
.lineanchors
or self
.linespans
669 aln
= self
.anchorlinenos
670 nocls
= self
.noclasses
674 for i
in range(fl
, fl
+lncount
):
675 print_line
= i
% st
== 0
676 special_line
= sp
and i
% sp
== 0
679 line
= '%*d' % (mw
, i
)
681 line
= '<a href="#%s-%d">%s</a>' % (anchor_name
, i
, line
)
687 style
= ' style="%s"' % self
._linenos
_special
_style
689 style
= ' style="%s"' % self
._linenos
_style
692 style
= ' class="special"'
694 style
= ' class="normal"'
697 line
= '<span%s>%s</span>' % (style
, line
)
701 ls
= '\n'.join(lines
)
703 # If a filename was specified, we can't put it into the code table as it
704 # would misalign the line numbers. Hence we emit a separate row for it.
708 '<tr><th colspan="2" class="filename">'
709 '<span class="filename">' + self
.filename
+ '</span>'
712 # in case you wonder about the seemingly redundant <div> here: since the
713 # content in the other cell also is wrapped in a div, some browsers in
714 # some configurations seem to mess up the formatting...
715 yield 0, (f
'<table class="{self.cssclass}table">' + filename_tr
+
716 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
717 ls
+ '</pre></div></td><td class="code">')
719 yield 0, dummyoutfile
.getvalue()
721 yield 0, '</td></tr></table>'
724 def _wrap_inlinelinenos(self
, inner
):
725 # need a list of lines since we need the width of a single number :(
726 inner_lines
= list(inner
)
727 sp
= self
.linenospecial
729 num
= self
.linenostart
730 mw
= len(str(len(inner_lines
) + num
- 1))
731 anchor_name
= self
.lineanchors
or self
.linespans
732 aln
= self
.anchorlinenos
733 nocls
= self
.noclasses
735 for _
, inner_line
in inner_lines
:
736 print_line
= num
% st
== 0
737 special_line
= sp
and num
% sp
== 0
740 line
= '%*d' % (mw
, num
)
746 style
= ' style="%s"' % self
._linenos
_special
_style
748 style
= ' style="%s"' % self
._linenos
_style
751 style
= ' class="linenos special"'
753 style
= ' class="linenos"'
756 linenos
= '<span%s>%s</span>' % (style
, line
)
761 yield 1, ('<a href="#%s-%d">%s</a>' % (anchor_name
, num
, linenos
) +
764 yield 1, linenos
+ inner_line
767 def _wrap_lineanchors(self
, inner
):
769 # subtract 1 since we have to increment i *before* yielding
770 i
= self
.linenostart
- 1
771 for t
, line
in inner
:
774 href
= "" if self
.linenos
else ' href="#%s-%d"' % (s
, i
)
775 yield 1, '<a id="%s-%d" name="%s-%d"%s></a>' % (s
, i
, s
, i
, href
) + line
779 def _wrap_linespans(self
, inner
):
781 i
= self
.linenostart
- 1
782 for t
, line
in inner
:
785 yield 1, '<span id="%s-%d">%s</span>' % (s
, i
, line
)
789 def _wrap_div(self
, inner
):
791 if (self
.noclasses
and not self
.nobackground
and
792 self
.style
.background_color
is not None):
793 style
.append('background: %s' % (self
.style
.background_color
,))
795 style
.append(self
.cssstyles
)
796 style
= '; '.join(style
)
798 yield 0, ('<div' + (self
.cssclass
and ' class="%s"' % self
.cssclass
) +
799 (style
and (' style="%s"' % style
)) + '>')
803 def _wrap_pre(self
, inner
):
806 style
.append(self
.prestyles
)
808 style
.append(self
._pre
_style
)
809 style
= '; '.join(style
)
811 if self
.filename
and self
.linenos
!= 1:
812 yield 0, ('<span class="filename">' + self
.filename
+ '</span>')
814 # the empty span here is to keep leading empty lines from being
815 # ignored by HTML parsers
816 yield 0, ('<pre' + (style
and ' style="%s"' % style
) + '><span></span>')
820 def _wrap_code(self
, inner
):
825 @functools.lru_cache(maxsize
=100)
826 def _translate_parts(self
, value
):
827 """HTML-escape a value and split it by newlines."""
828 return value
.translate(_escape_html_table
).split('\n')
830 def _format_lines(self
, tokensource
):
832 Just format the tokens, without any wrapping tags.
833 Yield individual lines.
835 nocls
= self
.noclasses
836 lsep
= self
.lineseparator
837 tagsfile
= self
.tagsfile
841 for ttype
, value
in tokensource
:
843 cspan
= self
.span_element_openers
[ttype
]
845 title
= ' title="%s"' % '.'.join(ttype
) if self
.debug_token_types
else ''
847 css_style
= self
._get
_css
_inline
_styles
(ttype
)
849 css_style
= self
.class2style
[css_style
][0]
850 cspan
= '<span style="%s"%s>' % (css_style
, title
)
854 css_class
= self
._get
_css
_classes
(ttype
)
856 cspan
= '<span class="%s"%s>' % (css_class
, title
)
859 self
.span_element_openers
[ttype
] = cspan
861 parts
= self
._translate
_parts
(value
)
863 if tagsfile
and ttype
in Token
.Name
:
864 filename
, linenumber
= self
._lookup
_ctag
(value
)
866 base
, filename
= os
.path
.split(filename
)
869 filename
, extension
= os
.path
.splitext(filename
)
870 url
= self
.tagurlformat
% {'path': base
, 'fname': filename
,
872 parts
[0] = "<a href=\"%s#%s-%d\">%s" % \
873 (url
, self
.lineanchors
, linenumber
, parts
[0])
874 parts
[-1] = parts
[-1] + "</a>"
876 # for all but the last line
877 for part
in parts
[:-1]:
879 # Also check for part being non-empty, so we avoid creating
881 if lspan
!= cspan
and part
:
882 line
.extend(((lspan
and '</span>'), cspan
, part
,
883 (cspan
and '</span>'), lsep
))
884 else: # both are the same, or the current part was empty
885 line
.extend((part
, (lspan
and '</span>'), lsep
))
886 yield 1, ''.join(line
)
889 yield 1, ''.join((cspan
, part
, (cspan
and '</span>'), lsep
))
893 if line
and parts
[-1]:
895 line
.extend(((lspan
and '</span>'), cspan
, parts
[-1]))
898 line
.append(parts
[-1])
900 line
= [cspan
, parts
[-1]]
902 # else we neither have to open a new span nor set lspan
905 line
.extend(((lspan
and '</span>'), lsep
))
906 yield 1, ''.join(line
)
908 def _lookup_ctag(self
, token
):
909 entry
= ctags
.TagEntry()
910 if self
._ctags
.find(entry
, token
.encode(), 0):
911 return entry
['file'], entry
['lineNumber']
915 def _highlight_lines(self
, tokensource
):
917 Highlighted the lines specified in the `hl_lines` option by
918 post-processing the token stream coming from `_format_lines`.
922 for i
, (t
, value
) in enumerate(tokensource
):
925 if i
+ 1 in hls
: # i + 1 because Python indexes start at 0
928 if self
.style
.highlight_color
is not None:
929 style
= (' style="background-color: %s"' %
930 (self
.style
.highlight_color
,))
931 yield 1, '<span%s>%s</span>' % (style
, value
)
933 yield 1, '<span class="hll">%s</span>' % value
937 def wrap(self
, source
):
939 Wrap the ``source``, which is a generator yielding
940 individual lines, in custom generators. See docstring
941 for `format`. Can be overridden.
946 output
= self
._wrap
_code
(output
)
948 output
= self
._wrap
_pre
(output
)
952 def format_unencoded(self
, tokensource
, outfile
):
954 The formatting process uses several nested generators; which of
955 them are used is determined by the user's options.
957 Each generator should take at least one argument, ``inner``,
958 and wrap the pieces of text generated by this.
960 Always yield 2-tuples: (code, text). If "code" is 1, the text
961 is part of the original tokensource being highlighted, if it's
962 0, the text is some piece of wrapping. This makes it possible to
963 use several different wrappers that process the original source
964 linewise, e.g. line number generators.
966 source
= self
._format
_lines
(tokensource
)
968 # As a special case, we wrap line numbers before line highlighting
969 # so the line numbers get wrapped in the highlighting tag.
970 if not self
.nowrap
and self
.linenos
== 2:
971 source
= self
._wrap
_inlinelinenos
(source
)
974 source
= self
._highlight
_lines
(source
)
978 source
= self
._wrap
_lineanchors
(source
)
980 source
= self
._wrap
_linespans
(source
)
981 source
= self
.wrap(source
)
982 if self
.linenos
== 1:
983 source
= self
._wrap
_tablelinenos
(source
)
984 source
= self
._wrap
_div
(source
)
986 source
= self
._wrap
_full
(source
, outfile
)
988 for t
, piece
in source
: