eric6/ThirdParty/Pygments/pygments/formatters/html.py

changeset 6942
2602857055c5
parent 5713
6762afd9f963
child 7547
21b0534faebc
equal deleted inserted replaced
6941:f99d60d6b59b 6942:2602857055c5
1 # -*- coding: utf-8 -*-
2 """
3 pygments.formatters.html
4 ~~~~~~~~~~~~~~~~~~~~~~~~
5
6 Formatter for HTML output.
7
8 :copyright: Copyright 2006-2017 by the Pygments team, see AUTHORS.
9 :license: BSD, see LICENSE for details.
10 """
11
12 from __future__ import print_function
13
14 import os
15 import sys
16 import os.path
17
18 from pygments.formatter import Formatter
19 from pygments.token import Token, Text, STANDARD_TYPES
20 from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \
21 StringIO, string_types, iteritems
22
23 try:
24 import ctags
25 except ImportError:
26 ctags = None
27
28 __all__ = ['HtmlFormatter']
29
30
31 _escape_html_table = {
32 ord('&'): u'&',
33 ord('<'): u'&lt;',
34 ord('>'): u'&gt;',
35 ord('"'): u'&quot;',
36 ord("'"): u'&#39;',
37 }
38
39
40 def escape_html(text, table=_escape_html_table):
41 """Escape &, <, > as well as single and double quotes for HTML."""
42 return text.translate(table)
43
44
45 def _get_ttype_class(ttype):
46 fname = STANDARD_TYPES.get(ttype)
47 if fname:
48 return fname
49 aname = ''
50 while fname is None:
51 aname = '-' + ttype[-1] + aname
52 ttype = ttype.parent
53 fname = STANDARD_TYPES.get(ttype)
54 return fname + aname
55
56
57 CSSFILE_TEMPLATE = '''\
58 td.linenos { background-color: #f0f0f0; padding-right: 10px; }
59 span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
60 pre { line-height: 125%%; }
61 %(styledefs)s
62 '''
63
64 DOC_HEADER = '''\
65 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
66 "http://www.w3.org/TR/html4/strict.dtd">
67
68 <html>
69 <head>
70 <title>%(title)s</title>
71 <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
72 <style type="text/css">
73 ''' + CSSFILE_TEMPLATE + '''
74 </style>
75 </head>
76 <body>
77 <h2>%(title)s</h2>
78
79 '''
80
81 DOC_HEADER_EXTERNALCSS = '''\
82 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
83 "http://www.w3.org/TR/html4/strict.dtd">
84
85 <html>
86 <head>
87 <title>%(title)s</title>
88 <meta http-equiv="content-type" content="text/html; charset=%(encoding)s">
89 <link rel="stylesheet" href="%(cssfile)s" type="text/css">
90 </head>
91 <body>
92 <h2>%(title)s</h2>
93
94 '''
95
96 DOC_FOOTER = '''\
97 </body>
98 </html>
99 '''
100
101
102 class HtmlFormatter(Formatter):
103 r"""
104 Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped
105 in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass`
106 option.
107
108 If the `linenos` option is set to ``"table"``, the ``<pre>`` is
109 additionally wrapped inside a ``<table>`` which has one row and two
110 cells: one containing the line numbers and one containing the code.
111 Example:
112
113 .. sourcecode:: html
114
115 <div class="highlight" >
116 <table><tr>
117 <td class="linenos" title="click to toggle"
118 onclick="with (this.firstChild.style)
119 { display = (display == '') ? 'none' : '' }">
120 <pre>1
121 2</pre>
122 </td>
123 <td class="code">
124 <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar):
125 <span class="Ke">pass</span>
126 </pre>
127 </td>
128 </tr></table></div>
129
130 (whitespace added to improve clarity).
131
132 Wrapping can be disabled using the `nowrap` option.
133
134 A list of lines can be specified using the `hl_lines` option to make these
135 lines highlighted (as of Pygments 0.11).
136
137 With the `full` option, a complete HTML 4 document is output, including
138 the style definitions inside a ``<style>`` tag, or in a separate file if
139 the `cssfile` option is given.
140
141 When `tagsfile` is set to the path of a ctags index file, it is used to
142 generate hyperlinks from names to their definition. You must enable
143 `lineanchors` and run ctags with the `-n` option for this to work. The
144 `python-ctags` module from PyPI must be installed to use this feature;
145 otherwise a `RuntimeError` will be raised.
146
147 The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string
148 containing CSS rules for the CSS classes used by the formatter. The
149 argument `arg` can be used to specify additional CSS selectors that
150 are prepended to the classes. A call `fmter.get_style_defs('td .code')`
151 would result in the following CSS classes:
152
153 .. sourcecode:: css
154
155 td .code .kw { font-weight: bold; color: #00FF00 }
156 td .code .cm { color: #999999 }
157 ...
158
159 If you have Pygments 0.6 or higher, you can also pass a list or tuple to the
160 `get_style_defs()` method to request multiple prefixes for the tokens:
161
162 .. sourcecode:: python
163
164 formatter.get_style_defs(['div.syntax pre', 'pre.syntax'])
165
166 The output would then look like this:
167
168 .. sourcecode:: css
169
170 div.syntax pre .kw,
171 pre.syntax .kw { font-weight: bold; color: #00FF00 }
172 div.syntax pre .cm,
173 pre.syntax .cm { color: #999999 }
174 ...
175
176 Additional options accepted:
177
178 `nowrap`
179 If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>``
180 tag. This disables most other options (default: ``False``).
181
182 `full`
183 Tells the formatter to output a "full" document, i.e. a complete
184 self-contained document (default: ``False``).
185
186 `title`
187 If `full` is true, the title that should be used to caption the
188 document (default: ``''``).
189
190 `style`
191 The style to use, can be a string or a Style subclass (default:
192 ``'default'``). This option has no effect if the `cssfile`
193 and `noclobber_cssfile` option are given and the file specified in
194 `cssfile` exists.
195
196 `noclasses`
197 If set to true, token ``<span>`` tags will not use CSS classes, but
198 inline styles. This is not recommended for larger pieces of code since
199 it increases output size by quite a bit (default: ``False``).
200
201 `classprefix`
202 Since the token types use relatively short class names, they may clash
203 with some of your own class names. In this case you can use the
204 `classprefix` option to give a string to prepend to all Pygments-generated
205 CSS class names for token types.
206 Note that this option also affects the output of `get_style_defs()`.
207
208 `cssclass`
209 CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``).
210 If you set this option, the default selector for `get_style_defs()`
211 will be this class.
212
213 .. versionadded:: 0.9
214 If you select the ``'table'`` line numbers, the wrapping table will
215 have a CSS class of this string plus ``'table'``, the default is
216 accordingly ``'highlighttable'``.
217
218 `cssstyles`
219 Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``).
220
221 `prestyles`
222 Inline CSS styles for the ``<pre>`` tag (default: ``''``).
223
224 .. versionadded:: 0.11
225
226 `cssfile`
227 If the `full` option is true and this option is given, it must be the
228 name of an external file. If the filename does not include an absolute
229 path, the file's path will be assumed to be relative to the main output
230 file's path, if the latter can be found. The stylesheet is then written
231 to this file instead of the HTML file.
232
233 .. versionadded:: 0.6
234
235 `noclobber_cssfile`
236 If `cssfile` is given and the specified file exists, the css file will
237 not be overwritten. This allows the use of the `full` option in
238 combination with a user specified css file. Default is ``False``.
239
240 .. versionadded:: 1.1
241
242 `linenos`
243 If set to ``'table'``, output line numbers as a table with two cells,
244 one containing the line numbers, the other the whole code. This is
245 copy-and-paste-friendly, but may cause alignment problems with some
246 browsers or fonts. If set to ``'inline'``, the line numbers will be
247 integrated in the ``<pre>`` tag that contains the code (that setting
248 is *new in Pygments 0.8*).
249
250 For compatibility with Pygments 0.7 and earlier, every true value
251 except ``'inline'`` means the same as ``'table'`` (in particular, that
252 means also ``True``).
253
254 The default value is ``False``, which means no line numbers at all.
255
256 **Note:** with the default ("table") line number mechanism, the line
257 numbers and code can have different line heights in Internet Explorer
258 unless you give the enclosing ``<pre>`` tags an explicit ``line-height``
259 CSS property (you get the default line spacing with ``line-height:
260 125%``).
261
262 `hl_lines`
263 Specify a list of lines to be highlighted.
264
265 .. versionadded:: 0.11
266
267 `linenostart`
268 The line number for the first line (default: ``1``).
269
270 `linenostep`
271 If set to a number n > 1, only every nth line number is printed.
272
273 `linenospecial`
274 If set to a number n > 0, every nth line number is given the CSS
275 class ``"special"`` (default: ``0``).
276
277 `nobackground`
278 If set to ``True``, the formatter won't output the background color
279 for the wrapping element (this automatically defaults to ``False``
280 when there is no wrapping element [eg: no argument for the
281 `get_syntax_defs` method given]) (default: ``False``).
282
283 .. versionadded:: 0.6
284
285 `lineseparator`
286 This string is output between lines of code. It defaults to ``"\n"``,
287 which is enough to break a line inside ``<pre>`` tags, but you can
288 e.g. set it to ``"<br>"`` to get HTML line breaks.
289
290 .. versionadded:: 0.7
291
292 `lineanchors`
293 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
294 output line in an anchor tag with a ``name`` of ``foo-linenumber``.
295 This allows easy linking to certain lines.
296
297 .. versionadded:: 0.9
298
299 `linespans`
300 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
301 output line in a span tag with an ``id`` of ``foo-linenumber``.
302 This allows easy access to lines via javascript.
303
304 .. versionadded:: 1.6
305
306 `anchorlinenos`
307 If set to `True`, will wrap line numbers in <a> tags. Used in
308 combination with `linenos` and `lineanchors`.
309
310 `tagsfile`
311 If set to the path of a ctags file, wrap names in anchor tags that
312 link to their definitions. `lineanchors` should be used, and the
313 tags file should specify line numbers (see the `-n` option to ctags).
314
315 .. versionadded:: 1.6
316
317 `tagurlformat`
318 A string formatting pattern used to generate links to ctags definitions.
319 Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`.
320 Defaults to an empty string, resulting in just `#prefix-number` links.
321
322 .. versionadded:: 1.6
323
324 `filename`
325 A string used to generate a filename when rendering <pre> blocks,
326 for example if displaying source code.
327
328 .. versionadded:: 2.1
329
330
331 **Subclassing the HTML formatter**
332
333 .. versionadded:: 0.7
334
335 The HTML formatter is now built in a way that allows easy subclassing, thus
336 customizing the output HTML code. The `format()` method calls
337 `self._format_lines()` which returns a generator that yields tuples of ``(1,
338 line)``, where the ``1`` indicates that the ``line`` is a line of the
339 formatted source code.
340
341 If the `nowrap` option is set, the generator is the iterated over and the
342 resulting HTML is output.
343
344 Otherwise, `format()` calls `self.wrap()`, which wraps the generator with
345 other generators. These may add some HTML code to the one generated by
346 `_format_lines()`, either by modifying the lines generated by the latter,
347 then yielding them again with ``(1, line)``, and/or by yielding other HTML
348 code before or after the lines, with ``(0, html)``. The distinction between
349 source lines and other code makes it possible to wrap the generator multiple
350 times.
351
352 The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag.
353
354 A custom `HtmlFormatter` subclass could look like this:
355
356 .. sourcecode:: python
357
358 class CodeHtmlFormatter(HtmlFormatter):
359
360 def wrap(self, source, outfile):
361 return self._wrap_code(source)
362
363 def _wrap_code(self, source):
364 yield 0, '<code>'
365 for i, t in source:
366 if i == 1:
367 # it's a line of formatted code
368 t += '<br>'
369 yield i, t
370 yield 0, '</code>'
371
372 This results in wrapping the formatted lines with a ``<code>`` tag, where the
373 source lines are broken using ``<br>`` tags.
374
375 After calling `wrap()`, the `format()` method also adds the "line numbers"
376 and/or "full document" wrappers if the respective options are set. Then, all
377 HTML yielded by the wrapped generator is output.
378 """
379
380 name = 'HTML'
381 aliases = ['html']
382 filenames = ['*.html', '*.htm']
383
384 def __init__(self, **options):
385 Formatter.__init__(self, **options)
386 self.title = self._decodeifneeded(self.title)
387 self.nowrap = get_bool_opt(options, 'nowrap', False)
388 self.noclasses = get_bool_opt(options, 'noclasses', False)
389 self.classprefix = options.get('classprefix', '')
390 self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight'))
391 self.cssstyles = self._decodeifneeded(options.get('cssstyles', ''))
392 self.prestyles = self._decodeifneeded(options.get('prestyles', ''))
393 self.cssfile = self._decodeifneeded(options.get('cssfile', ''))
394 self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False)
395 self.tagsfile = self._decodeifneeded(options.get('tagsfile', ''))
396 self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', ''))
397 self.filename = self._decodeifneeded(options.get('filename', ''))
398
399 if self.tagsfile:
400 if not ctags:
401 raise RuntimeError('The "ctags" package must to be installed '
402 'to be able to use the "tagsfile" feature.')
403 self._ctags = ctags.CTags(self.tagsfile)
404
405 linenos = options.get('linenos', False)
406 if linenos == 'inline':
407 self.linenos = 2
408 elif linenos:
409 # compatibility with <= 0.7
410 self.linenos = 1
411 else:
412 self.linenos = 0
413 self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
414 self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
415 self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0))
416 self.nobackground = get_bool_opt(options, 'nobackground', False)
417 self.lineseparator = options.get('lineseparator', '\n')
418 self.lineanchors = options.get('lineanchors', '')
419 self.linespans = options.get('linespans', '')
420 self.anchorlinenos = options.get('anchorlinenos', False)
421 self.hl_lines = set()
422 for lineno in get_list_opt(options, 'hl_lines', []):
423 try:
424 self.hl_lines.add(int(lineno))
425 except ValueError:
426 pass
427
428 self._create_stylesheet()
429
430 def _get_css_class(self, ttype):
431 """Return the css class of this token type prefixed with
432 the classprefix option."""
433 ttypeclass = _get_ttype_class(ttype)
434 if ttypeclass:
435 return self.classprefix + ttypeclass
436 return ''
437
438 def _get_css_classes(self, ttype):
439 """Return the css classes of this token type prefixed with
440 the classprefix option."""
441 cls = self._get_css_class(ttype)
442 while ttype not in STANDARD_TYPES:
443 ttype = ttype.parent
444 cls = self._get_css_class(ttype) + ' ' + cls
445 return cls
446
447 def _create_stylesheet(self):
448 t2c = self.ttype2class = {Token: ''}
449 c2s = self.class2style = {}
450 for ttype, ndef in self.style:
451 name = self._get_css_class(ttype)
452 style = ''
453 if ndef['color']:
454 style += 'color: #%s; ' % ndef['color']
455 if ndef['bold']:
456 style += 'font-weight: bold; '
457 if ndef['italic']:
458 style += 'font-style: italic; '
459 if ndef['underline']:
460 style += 'text-decoration: underline; '
461 if ndef['bgcolor']:
462 style += 'background-color: #%s; ' % ndef['bgcolor']
463 if ndef['border']:
464 style += 'border: 1px solid #%s; ' % ndef['border']
465 if style:
466 t2c[ttype] = name
467 # save len(ttype) to enable ordering the styles by
468 # hierarchy (necessary for CSS cascading rules!)
469 c2s[name] = (style[:-2], ttype, len(ttype))
470
471 def get_style_defs(self, arg=None):
472 """
473 Return CSS style definitions for the classes produced by the current
474 highlighting style. ``arg`` can be a string or list of selectors to
475 insert before the token type classes.
476 """
477 if arg is None:
478 arg = ('cssclass' in self.options and '.'+self.cssclass or '')
479 if isinstance(arg, string_types):
480 args = [arg]
481 else:
482 args = list(arg)
483
484 def prefix(cls):
485 if cls:
486 cls = '.' + cls
487 tmp = []
488 for arg in args:
489 tmp.append((arg and arg + ' ' or '') + cls)
490 return ', '.join(tmp)
491
492 styles = [(level, ttype, cls, style)
493 for cls, (style, ttype, level) in iteritems(self.class2style)
494 if cls and style]
495 styles.sort()
496 lines = ['%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:])
497 for (level, ttype, cls, style) in styles]
498 if arg and not self.nobackground and \
499 self.style.background_color is not None:
500 text_style = ''
501 if Text in self.ttype2class:
502 text_style = ' ' + self.class2style[self.ttype2class[Text]][0]
503 lines.insert(0, '%s { background: %s;%s }' %
504 (prefix(''), self.style.background_color, text_style))
505 if self.style.highlight_color is not None:
506 lines.insert(0, '%s.hll { background-color: %s }' %
507 (prefix(''), self.style.highlight_color))
508 return '\n'.join(lines)
509
510 def _decodeifneeded(self, value):
511 if isinstance(value, bytes):
512 if self.encoding:
513 return value.decode(self.encoding)
514 return value.decode()
515 return value
516
517 def _wrap_full(self, inner, outfile):
518 if self.cssfile:
519 if os.path.isabs(self.cssfile):
520 # it's an absolute filename
521 cssfilename = self.cssfile
522 else:
523 try:
524 filename = outfile.name
525 if not filename or filename[0] == '<':
526 # pseudo files, e.g. name == '<fdopen>'
527 raise AttributeError
528 cssfilename = os.path.join(os.path.dirname(filename),
529 self.cssfile)
530 except AttributeError:
531 print('Note: Cannot determine output file name, '
532 'using current directory as base for the CSS file name',
533 file=sys.stderr)
534 cssfilename = self.cssfile
535 # write CSS file only if noclobber_cssfile isn't given as an option.
536 try:
537 if not os.path.exists(cssfilename) or not self.noclobber_cssfile:
538 cf = open(cssfilename, "w")
539 cf.write(CSSFILE_TEMPLATE %
540 {'styledefs': self.get_style_defs('body')})
541 cf.close()
542 except IOError as err:
543 err.strerror = 'Error writing CSS file: ' + err.strerror
544 raise
545
546 yield 0, (DOC_HEADER_EXTERNALCSS %
547 dict(title=self.title,
548 cssfile=self.cssfile,
549 encoding=self.encoding))
550 else:
551 yield 0, (DOC_HEADER %
552 dict(title=self.title,
553 styledefs=self.get_style_defs('body'),
554 encoding=self.encoding))
555
556 for t, line in inner:
557 yield t, line
558 yield 0, DOC_FOOTER
559
560 def _wrap_tablelinenos(self, inner):
561 dummyoutfile = StringIO()
562 lncount = 0
563 for t, line in inner:
564 if t:
565 lncount += 1
566 dummyoutfile.write(line)
567
568 fl = self.linenostart
569 mw = len(str(lncount + fl - 1))
570 sp = self.linenospecial
571 st = self.linenostep
572 la = self.lineanchors
573 aln = self.anchorlinenos
574 nocls = self.noclasses
575 if sp:
576 lines = []
577
578 for i in range(fl, fl+lncount):
579 if i % st == 0:
580 if i % sp == 0:
581 if aln:
582 lines.append('<a href="#%s-%d" class="special">%*d</a>' %
583 (la, i, mw, i))
584 else:
585 lines.append('<span class="special">%*d</span>' % (mw, i))
586 else:
587 if aln:
588 lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i))
589 else:
590 lines.append('%*d' % (mw, i))
591 else:
592 lines.append('')
593 ls = '\n'.join(lines)
594 else:
595 lines = []
596 for i in range(fl, fl+lncount):
597 if i % st == 0:
598 if aln:
599 lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i))
600 else:
601 lines.append('%*d' % (mw, i))
602 else:
603 lines.append('')
604 ls = '\n'.join(lines)
605
606 # in case you wonder about the seemingly redundant <div> here: since the
607 # content in the other cell also is wrapped in a div, some browsers in
608 # some configurations seem to mess up the formatting...
609 if nocls:
610 yield 0, ('<table class="%stable">' % self.cssclass +
611 '<tr><td><div class="linenodiv" '
612 'style="background-color: #f0f0f0; padding-right: 10px">'
613 '<pre style="line-height: 125%">' +
614 ls + '</pre></div></td><td class="code">')
615 else:
616 yield 0, ('<table class="%stable">' % self.cssclass +
617 '<tr><td class="linenos"><div class="linenodiv"><pre>' +
618 ls + '</pre></div></td><td class="code">')
619 yield 0, dummyoutfile.getvalue()
620 yield 0, '</td></tr></table>'
621
622 def _wrap_inlinelinenos(self, inner):
623 # need a list of lines since we need the width of a single number :(
624 lines = list(inner)
625 sp = self.linenospecial
626 st = self.linenostep
627 num = self.linenostart
628 mw = len(str(len(lines) + num - 1))
629
630 if self.noclasses:
631 if sp:
632 for t, line in lines:
633 if num % sp == 0:
634 style = 'background-color: #ffffc0; padding: 0 5px 0 5px'
635 else:
636 style = 'background-color: #f0f0f0; padding: 0 5px 0 5px'
637 yield 1, '<span style="%s">%*s </span>' % (
638 style, mw, (num % st and ' ' or num)) + line
639 num += 1
640 else:
641 for t, line in lines:
642 yield 1, ('<span style="background-color: #f0f0f0; '
643 'padding: 0 5px 0 5px">%*s </span>' % (
644 mw, (num % st and ' ' or num)) + line)
645 num += 1
646 elif sp:
647 for t, line in lines:
648 yield 1, '<span class="lineno%s">%*s </span>' % (
649 num % sp == 0 and ' special' or '', mw,
650 (num % st and ' ' or num)) + line
651 num += 1
652 else:
653 for t, line in lines:
654 yield 1, '<span class="lineno">%*s </span>' % (
655 mw, (num % st and ' ' or num)) + line
656 num += 1
657
658 def _wrap_lineanchors(self, inner):
659 s = self.lineanchors
660 # subtract 1 since we have to increment i *before* yielding
661 i = self.linenostart - 1
662 for t, line in inner:
663 if t:
664 i += 1
665 yield 1, '<a name="%s-%d"></a>' % (s, i) + line
666 else:
667 yield 0, line
668
669 def _wrap_linespans(self, inner):
670 s = self.linespans
671 i = self.linenostart - 1
672 for t, line in inner:
673 if t:
674 i += 1
675 yield 1, '<span id="%s-%d">%s</span>' % (s, i, line)
676 else:
677 yield 0, line
678
679 def _wrap_div(self, inner):
680 style = []
681 if (self.noclasses and not self.nobackground and
682 self.style.background_color is not None):
683 style.append('background: %s' % (self.style.background_color,))
684 if self.cssstyles:
685 style.append(self.cssstyles)
686 style = '; '.join(style)
687
688 yield 0, ('<div' + (self.cssclass and ' class="%s"' % self.cssclass) +
689 (style and (' style="%s"' % style)) + '>')
690 for tup in inner:
691 yield tup
692 yield 0, '</div>\n'
693
694 def _wrap_pre(self, inner):
695 style = []
696 if self.prestyles:
697 style.append(self.prestyles)
698 if self.noclasses:
699 style.append('line-height: 125%')
700 style = '; '.join(style)
701
702 if self.filename:
703 yield 0, ('<span class="filename">' + self.filename + '</span>')
704
705 # the empty span here is to keep leading empty lines from being
706 # ignored by HTML parsers
707 yield 0, ('<pre' + (style and ' style="%s"' % style) + '><span></span>')
708 for tup in inner:
709 yield tup
710 yield 0, '</pre>'
711
712 def _format_lines(self, tokensource):
713 """
714 Just format the tokens, without any wrapping tags.
715 Yield individual lines.
716 """
717 nocls = self.noclasses
718 lsep = self.lineseparator
719 # for <span style=""> lookup only
720 getcls = self.ttype2class.get
721 c2s = self.class2style
722 escape_table = _escape_html_table
723 tagsfile = self.tagsfile
724
725 lspan = ''
726 line = []
727 for ttype, value in tokensource:
728 if nocls:
729 cclass = getcls(ttype)
730 while cclass is None:
731 ttype = ttype.parent
732 cclass = getcls(ttype)
733 cspan = cclass and '<span style="%s">' % c2s[cclass][0] or ''
734 else:
735 cls = self._get_css_classes(ttype)
736 cspan = cls and '<span class="%s">' % cls or ''
737
738 parts = value.translate(escape_table).split('\n')
739
740 if tagsfile and ttype in Token.Name:
741 filename, linenumber = self._lookup_ctag(value)
742 if linenumber:
743 base, filename = os.path.split(filename)
744 if base:
745 base += '/'
746 filename, extension = os.path.splitext(filename)
747 url = self.tagurlformat % {'path': base, 'fname': filename,
748 'fext': extension}
749 parts[0] = "<a href=\"%s#%s-%d\">%s" % \
750 (url, self.lineanchors, linenumber, parts[0])
751 parts[-1] = parts[-1] + "</a>"
752
753 # for all but the last line
754 for part in parts[:-1]:
755 if line:
756 if lspan != cspan:
757 line.extend(((lspan and '</span>'), cspan, part,
758 (cspan and '</span>'), lsep))
759 else: # both are the same
760 line.extend((part, (lspan and '</span>'), lsep))
761 yield 1, ''.join(line)
762 line = []
763 elif part:
764 yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep))
765 else:
766 yield 1, lsep
767 # for the last line
768 if line and parts[-1]:
769 if lspan != cspan:
770 line.extend(((lspan and '</span>'), cspan, parts[-1]))
771 lspan = cspan
772 else:
773 line.append(parts[-1])
774 elif parts[-1]:
775 line = [cspan, parts[-1]]
776 lspan = cspan
777 # else we neither have to open a new span nor set lspan
778
779 if line:
780 line.extend(((lspan and '</span>'), lsep))
781 yield 1, ''.join(line)
782
783 def _lookup_ctag(self, token):
784 entry = ctags.TagEntry()
785 if self._ctags.find(entry, token, 0):
786 return entry['file'], entry['lineNumber']
787 else:
788 return None, None
789
790 def _highlight_lines(self, tokensource):
791 """
792 Highlighted the lines specified in the `hl_lines` option by
793 post-processing the token stream coming from `_format_lines`.
794 """
795 hls = self.hl_lines
796
797 for i, (t, value) in enumerate(tokensource):
798 if t != 1:
799 yield t, value
800 if i + 1 in hls: # i + 1 because Python indexes start at 0
801 if self.noclasses:
802 style = ''
803 if self.style.highlight_color is not None:
804 style = (' style="background-color: %s"' %
805 (self.style.highlight_color,))
806 yield 1, '<span%s>%s</span>' % (style, value)
807 else:
808 yield 1, '<span class="hll">%s</span>' % value
809 else:
810 yield 1, value
811
812 def wrap(self, source, outfile):
813 """
814 Wrap the ``source``, which is a generator yielding
815 individual lines, in custom generators. See docstring
816 for `format`. Can be overridden.
817 """
818 return self._wrap_div(self._wrap_pre(source))
819
820 def format_unencoded(self, tokensource, outfile):
821 """
822 The formatting process uses several nested generators; which of
823 them are used is determined by the user's options.
824
825 Each generator should take at least one argument, ``inner``,
826 and wrap the pieces of text generated by this.
827
828 Always yield 2-tuples: (code, text). If "code" is 1, the text
829 is part of the original tokensource being highlighted, if it's
830 0, the text is some piece of wrapping. This makes it possible to
831 use several different wrappers that process the original source
832 linewise, e.g. line number generators.
833 """
834 source = self._format_lines(tokensource)
835 if self.hl_lines:
836 source = self._highlight_lines(source)
837 if not self.nowrap:
838 if self.linenos == 2:
839 source = self._wrap_inlinelinenos(source)
840 if self.lineanchors:
841 source = self._wrap_lineanchors(source)
842 if self.linespans:
843 source = self._wrap_linespans(source)
844 source = self.wrap(source, outfile)
845 if self.linenos == 1:
846 source = self._wrap_tablelinenos(source)
847 if self.full:
848 source = self._wrap_full(source, outfile)
849
850 for t, piece in source:
851 outfile.write(piece)

eric ide

mercurial