ThirdParty/Pygments/pygments/formatters/html.py

changeset 2426
da76c71624de
parent 1705
b0fbc9300f2b
child 2525
8b507a9a2d40
equal deleted inserted replaced
2425:ace8a08028f3 2426:da76c71624de
3 pygments.formatters.html 3 pygments.formatters.html
4 ~~~~~~~~~~~~~~~~~~~~~~~~ 4 ~~~~~~~~~~~~~~~~~~~~~~~~
5 5
6 Formatter for HTML output. 6 Formatter for HTML output.
7 7
8 :copyright: Copyright 2006-2012 by the Pygments team, see AUTHORS. 8 :copyright: Copyright 2006-2013 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 import os 12 import os
13 import sys 13 import sys
14 import os.path
14 import io 15 import io
15 16
16 from pygments.formatter import Formatter 17 from pygments.formatter import Formatter
17 from pygments.token import Token, Text, STANDARD_TYPES 18 from pygments.token import Token, Text, STANDARD_TYPES
18 from pygments.util import get_bool_opt, get_int_opt, get_list_opt, bytes 19 from pygments.util import get_bool_opt, get_int_opt, get_list_opt, bytes
19 20
21 try:
22 import ctags
23 except ImportError:
24 ctags = None
20 25
21 __all__ = ['HtmlFormatter'] 26 __all__ = ['HtmlFormatter']
22 27
23 28
24 _escape_html_table = { 29 _escape_html_table = {
139 144
140 With the `full` option, a complete HTML 4 document is output, including 145 With the `full` option, a complete HTML 4 document is output, including
141 the style definitions inside a ``<style>`` tag, or in a separate file if 146 the style definitions inside a ``<style>`` tag, or in a separate file if
142 the `cssfile` option is given. 147 the `cssfile` option is given.
143 148
149 When `tagsfile` is set to the path of a ctags index file, it is used to
150 generate hyperlinks from names to their definition. You must enable
151 `anchorlines` and run ctags with the `-n` option for this to work. The
152 `python-ctags` module from PyPI must be installed to use this feature;
153 otherwise a `RuntimeError` will be raised.
154
144 The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string 155 The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string
145 containing CSS rules for the CSS classes used by the formatter. The 156 containing CSS rules for the CSS classes used by the formatter. The
146 argument `arg` can be used to specify additional CSS selectors that 157 argument `arg` can be used to specify additional CSS selectors that
147 are prepended to the classes. A call `fmter.get_style_defs('td .code')` 158 are prepended to the classes. A call `fmter.get_style_defs('td .code')`
148 would result in the following CSS classes: 159 would result in the following CSS classes:
280 `lineanchors` 291 `lineanchors`
281 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each 292 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
282 output line in an anchor tag with a ``name`` of ``foo-linenumber``. 293 output line in an anchor tag with a ``name`` of ``foo-linenumber``.
283 This allows easy linking to certain lines. *New in Pygments 0.9.* 294 This allows easy linking to certain lines. *New in Pygments 0.9.*
284 295
296 `linespans`
297 If set to a nonempty string, e.g. ``foo``, the formatter will wrap each
298 output line in a span tag with an ``id`` of ``foo-linenumber``.
299 This allows easy access to lines via javascript. *New in Pygments 1.6.*
300
285 `anchorlinenos` 301 `anchorlinenos`
286 If set to `True`, will wrap line numbers in <a> tags. Used in 302 If set to `True`, will wrap line numbers in <a> tags. Used in
287 combination with `linenos` and `lineanchors`. 303 combination with `linenos` and `lineanchors`.
304
305 `tagsfile`
306 If set to the path of a ctags file, wrap names in anchor tags that
307 link to their definitions. `lineanchors` should be used, and the
308 tags file should specify line numbers (see the `-n` option to ctags).
309 *New in Pygments 1.6.*
310
311 `tagurlformat`
312 A string formatting pattern used to generate links to ctags definitions.
313 Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`.
314 Defaults to an empty string, resulting in just `#prefix-number` links.
315 *New in Pygments 1.6.*
288 316
289 317
290 **Subclassing the HTML formatter** 318 **Subclassing the HTML formatter**
291 319
292 *New in Pygments 0.7.* 320 *New in Pygments 0.7.*
349 self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight')) 377 self.cssclass = self._decodeifneeded(options.get('cssclass', 'highlight'))
350 self.cssstyles = self._decodeifneeded(options.get('cssstyles', '')) 378 self.cssstyles = self._decodeifneeded(options.get('cssstyles', ''))
351 self.prestyles = self._decodeifneeded(options.get('prestyles', '')) 379 self.prestyles = self._decodeifneeded(options.get('prestyles', ''))
352 self.cssfile = self._decodeifneeded(options.get('cssfile', '')) 380 self.cssfile = self._decodeifneeded(options.get('cssfile', ''))
353 self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False) 381 self.noclobber_cssfile = get_bool_opt(options, 'noclobber_cssfile', False)
382 self.tagsfile = self._decodeifneeded(options.get('tagsfile', ''))
383 self.tagurlformat = self._decodeifneeded(options.get('tagurlformat', ''))
384
385 if self.tagsfile:
386 if not ctags:
387 raise RuntimeError('The "ctags" package must to be installed '
388 'to be able to use the "tagsfile" feature.')
389 self._ctags = ctags.CTags(self.tagsfile)
354 390
355 linenos = options.get('linenos', False) 391 linenos = options.get('linenos', False)
356 if linenos == 'inline': 392 if linenos == 'inline':
357 self.linenos = 2 393 self.linenos = 2
358 elif linenos: 394 elif linenos:
364 self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) 400 self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
365 self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0)) 401 self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0))
366 self.nobackground = get_bool_opt(options, 'nobackground', False) 402 self.nobackground = get_bool_opt(options, 'nobackground', False)
367 self.lineseparator = options.get('lineseparator', '\n') 403 self.lineseparator = options.get('lineseparator', '\n')
368 self.lineanchors = options.get('lineanchors', '') 404 self.lineanchors = options.get('lineanchors', '')
405 self.linespans = options.get('linespans', '')
369 self.anchorlinenos = options.get('anchorlinenos', False) 406 self.anchorlinenos = options.get('anchorlinenos', False)
370 self.hl_lines = set() 407 self.hl_lines = set()
371 for lineno in get_list_opt(options, 'hl_lines', []): 408 for lineno in get_list_opt(options, 'hl_lines', []):
372 try: 409 try:
373 self.hl_lines.add(int(lineno)) 410 self.hl_lines.add(int(lineno))
594 mw, (num%st and ' ' or num)) + line 631 mw, (num%st and ' ' or num)) + line
595 num += 1 632 num += 1
596 633
597 def _wrap_lineanchors(self, inner): 634 def _wrap_lineanchors(self, inner):
598 s = self.lineanchors 635 s = self.lineanchors
599 i = self.linenostart - 1 # subtract 1 since we have to increment i *before* yielding 636 i = self.linenostart - 1 # subtract 1 since we have to increment i
637 # *before* yielding
600 for t, line in inner: 638 for t, line in inner:
601 if t: 639 if t:
602 i += 1 640 i += 1
603 yield 1, '<a name="%s-%d"></a>' % (s, i) + line 641 yield 1, '<a name="%s-%d"></a>' % (s, i) + line
642 else:
643 yield 0, line
644
645 def _wrap_linespans(self, inner):
646 s = self.linespans
647 i = self.linenostart - 1
648 for t, line in inner:
649 if t:
650 i += 1
651 yield 1, '<span id="%s-%d">%s</span>' % (s, i, line)
604 else: 652 else:
605 yield 0, line 653 yield 0, line
606 654
607 def _wrap_div(self, inner): 655 def _wrap_div(self, inner):
608 style = [] 656 style = []
641 lsep = self.lineseparator 689 lsep = self.lineseparator
642 # for <span style=""> lookup only 690 # for <span style=""> lookup only
643 getcls = self.ttype2class.get 691 getcls = self.ttype2class.get
644 c2s = self.class2style 692 c2s = self.class2style
645 escape_table = _escape_html_table 693 escape_table = _escape_html_table
694 tagsfile = self.tagsfile
646 695
647 lspan = '' 696 lspan = ''
648 line = '' 697 line = ''
649 for ttype, value in tokensource: 698 for ttype, value in tokensource:
650 if nocls: 699 if nocls:
656 else: 705 else:
657 cls = self._get_css_class(ttype) 706 cls = self._get_css_class(ttype)
658 cspan = cls and '<span class="%s">' % cls or '' 707 cspan = cls and '<span class="%s">' % cls or ''
659 708
660 parts = value.translate(escape_table).split('\n') 709 parts = value.translate(escape_table).split('\n')
710
711 if tagsfile and ttype in Token.Name:
712 filename, linenumber = self._lookup_ctag(value)
713 if linenumber:
714 base, filename = os.path.split(filename)
715 if base:
716 base += '/'
717 filename, extension = os.path.splitext(filename)
718 url = self.tagurlformat % {'path': base, 'fname': filename,
719 'fext': extension}
720 parts[0] = "<a href=\"%s#%s-%d\">%s" % \
721 (url, self.lineanchors, linenumber, parts[0])
722 parts[-1] = parts[-1] + "</a>"
661 723
662 # for all but the last line 724 # for all but the last line
663 for part in parts[:-1]: 725 for part in parts[:-1]:
664 if line: 726 if line:
665 if lspan != cspan: 727 if lspan != cspan:
686 # else we neither have to open a new span nor set lspan 748 # else we neither have to open a new span nor set lspan
687 749
688 if line: 750 if line:
689 yield 1, line + (lspan and '</span>') + lsep 751 yield 1, line + (lspan and '</span>') + lsep
690 752
753 def _lookup_ctag(self, token):
754 entry = ctags.TagEntry()
755 if self._ctags.find(entry, token, 0):
756 return entry['file'], entry['lineNumber']
757 else:
758 return None, None
759
691 def _highlight_lines(self, tokensource): 760 def _highlight_lines(self, tokensource):
692 """ 761 """
693 Highlighted the lines specified in the `hl_lines` option by 762 Highlighted the lines specified in the `hl_lines` option by
694 post-processing the token stream coming from `_format_lines`. 763 post-processing the token stream coming from `_format_lines`.
695 """ 764 """
738 if not self.nowrap: 807 if not self.nowrap:
739 if self.linenos == 2: 808 if self.linenos == 2:
740 source = self._wrap_inlinelinenos(source) 809 source = self._wrap_inlinelinenos(source)
741 if self.lineanchors: 810 if self.lineanchors:
742 source = self._wrap_lineanchors(source) 811 source = self._wrap_lineanchors(source)
812 if self.linespans:
813 source = self._wrap_linespans(source)
743 source = self.wrap(source, outfile) 814 source = self.wrap(source, outfile)
744 if self.linenos == 1: 815 if self.linenos == 1:
745 source = self._wrap_tablelinenos(source) 816 source = self._wrap_tablelinenos(source)
746 if self.full: 817 if self.full:
747 source = self._wrap_full(source, outfile) 818 source = self._wrap_full(source, outfile)

eric ide

mercurial