Permalink
Cannot retrieve contributors at this time
Fetching contributors…
| # -*- coding: utf-8 -*- | |
| """ | |
| pygments.formatters.html | |
| ~~~~~~~~~~~~~~~~~~~~~~~~ | |
| Formatter for HTML output. | |
| :copyright: Copyright 2006-2013 by the Pygments team, see AUTHORS. | |
| :license: BSD, see LICENSE for details. | |
| """ | |
| import os | |
| import sys | |
| import os.path | |
| import StringIO | |
| from pygments.formatter import Formatter | |
| from pygments.token import Token, Text, STANDARD_TYPES | |
| from pygments.util import get_bool_opt, get_int_opt, get_list_opt, bytes | |
| try: | |
| import ctags | |
| except ImportError: | |
| ctags = None | |
| __all__ = ['HtmlFormatter'] | |
| _escape_html_table = { | |
| ord('&'): u'&', | |
| ord('<'): u'<', | |
| ord('>'): u'>', | |
| ord('"'): u'"', | |
| ord("'"): u''', | |
| } | |
| def escape_html(text, table=_escape_html_table): | |
| """Escape &, <, > as well as single and double quotes for HTML.""" | |
| return text.translate(table) | |
| def get_random_id(): | |
| """Return a random id for javascript fields.""" | |
| from random import random | |
| from time import time | |
| try: | |
| from hashlib import sha1 as sha | |
| except ImportError: | |
| import sha | |
| sha = sha.new | |
| return sha('%s|%s' % (random(), time())).hexdigest() | |
| 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 = '''\ | |
| td.linenos { background-color: #f0f0f0; padding-right: 10px; } | |
| span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; } | |
| pre { line-height: 125%%; } | |
| %(styledefs)s | |
| ''' | |
| DOC_HEADER = '''\ | |
| <!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"> | |
| <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 | |
| `anchorlines` 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 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. | |
| *New in Pygments 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: ``''``). *New in | |
| Pygments 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. *New in Pygments 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``. | |
| *New in Pygments 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. *New in Pygments 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``). *New in | |
| Pygments 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. *New in Pygments | |
| 0.7.* | |
| `lineanchors` | |
| If set to a nonempty string, e.g. ``foo``, the formatter will wrap each | |
| output line in an anchor tag with a ``name`` of ``foo-linenumber``. | |
| This allows easy linking to certain lines. *New in Pygments 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. *New in Pygments 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). | |
| *New in Pygments 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. | |
| *New in Pygments 1.6.* | |
| **Subclassing the HTML formatter** | |
| *New in Pygments 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, outfile): | |
| 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', '')) | |
| 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 = options.get('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 _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; ' % 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; ' % ndef['bgcolor'] | |
| if ndef['border']: | |
| style += 'border: 1px solid #%s; ' % 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. | |
| """ | |
| if arg is None: | |
| arg = ('cssclass' in self.options and '.'+self.cssclass or '') | |
| if isinstance(arg, basestring): | |
| 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) | |
| styles = [(level, ttype, cls, style) | |
| for cls, (style, ttype, level) in self.class2style.iteritems() | |
| if cls and style] | |
| styles.sort() | |
| lines = ['%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:]) | |
| for (level, ttype, cls, style) in styles] | |
| if arg and not self.nobackground and \ | |
| self.style.background_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(''), self.style.background_color, text_style)) | |
| if self.style.highlight_color is not None: | |
| lines.insert(0, '%s.hll { background-color: %s }' % | |
| (prefix(''), self.style.highlight_color)) | |
| return '\n'.join(lines) | |
| 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 >>sys.stderr, 'Note: Cannot determine output file name, ' \ | |
| 'using current directory as base for the CSS file name' | |
| 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: | |
| cf = open(cssfilename, "w") | |
| cf.write(CSSFILE_TEMPLATE % | |
| {'styledefs': self.get_style_defs('body')}) | |
| cf.close() | |
| except IOError, 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)) | |
| for t, line in inner: | |
| yield t, line | |
| yield 0, DOC_FOOTER | |
| def _wrap_tablelinenos(self, inner): | |
| dummyoutfile = StringIO.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 | |
| la = self.lineanchors | |
| aln = self.anchorlinenos | |
| nocls = self.noclasses | |
| if sp: | |
| lines = [] | |
| for i in range(fl, fl+lncount): | |
| if i % st == 0: | |
| if i % sp == 0: | |
| if aln: | |
| lines.append('<a href="#%s-%d" class="special">%*d</a>' % | |
| (la, i, mw, i)) | |
| else: | |
| lines.append('<span class="special">%*d</span>' % (mw, i)) | |
| else: | |
| if aln: | |
| lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i)) | |
| else: | |
| lines.append('%*d' % (mw, i)) | |
| else: | |
| lines.append('') | |
| ls = '\n'.join(lines) | |
| else: | |
| lines = [] | |
| for i in range(fl, fl+lncount): | |
| if i % st == 0: | |
| if aln: | |
| lines.append('<a href="#%s-%d">%*d</a>' % (la, i, mw, i)) | |
| else: | |
| lines.append('%*d' % (mw, i)) | |
| else: | |
| lines.append('') | |
| ls = '\n'.join(lines) | |
| # 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... | |
| if nocls: | |
| yield 0, ('<table class="%stable">' % self.cssclass + | |
| '<tr><td><div class="linenodiv" ' | |
| 'style="background-color: #f0f0f0; padding-right: 10px">' | |
| '<pre style="line-height: 125%">' + | |
| ls + '</pre></div></td><td class="code">') | |
| else: | |
| yield 0, ('<table class="%stable">' % self.cssclass + | |
| '<tr><td class="linenos"><div class="linenodiv"><pre>' + | |
| ls + '</pre></div></td><td class="code">') | |
| yield 0, dummyoutfile.getvalue() | |
| yield 0, '</td></tr></table>' | |
| def _wrap_inlinelinenos(self, inner): | |
| # need a list of lines since we need the width of a single number :( | |
| lines = list(inner) | |
| sp = self.linenospecial | |
| st = self.linenostep | |
| num = self.linenostart | |
| mw = len(str(len(lines) + num - 1)) | |
| if self.noclasses: | |
| if sp: | |
| for t, line in lines: | |
| if num%sp == 0: | |
| style = 'background-color: #ffffc0; padding: 0 5px 0 5px' | |
| else: | |
| style = 'background-color: #f0f0f0; padding: 0 5px 0 5px' | |
| yield 1, '<span style="%s">%*s</span> ' % ( | |
| style, mw, (num%st and ' ' or num)) + line | |
| num += 1 | |
| else: | |
| for t, line in lines: | |
| yield 1, ('<span style="background-color: #f0f0f0; ' | |
| 'padding: 0 5px 0 5px">%*s</span> ' % ( | |
| mw, (num%st and ' ' or num)) + line) | |
| num += 1 | |
| elif sp: | |
| for t, line in lines: | |
| yield 1, '<span class="lineno%s">%*s</span> ' % ( | |
| num%sp == 0 and ' special' or '', mw, | |
| (num%st and ' ' or num)) + line | |
| num += 1 | |
| else: | |
| for t, line in lines: | |
| yield 1, '<span class="lineno">%*s</span> ' % ( | |
| mw, (num%st and ' ' or num)) + line | |
| num += 1 | |
| def _wrap_lineanchors(self, inner): | |
| s = self.lineanchors | |
| i = self.linenostart - 1 # subtract 1 since we have to increment i | |
| # *before* yielding | |
| for t, line in inner: | |
| if t: | |
| i += 1 | |
| yield 1, '<a name="%s-%d"></a>' % (s, i) + 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)) + '>') | |
| for tup in inner: | |
| yield tup | |
| yield 0, '</div>\n' | |
| def _wrap_pre(self, inner): | |
| style = [] | |
| if self.prestyles: | |
| style.append(self.prestyles) | |
| if self.noclasses: | |
| style.append('line-height: 125%') | |
| style = '; '.join(style) | |
| yield 0, ('<pre' + (style and ' style="%s"' % style) + '>') | |
| for tup in inner: | |
| yield tup | |
| yield 0, '</pre>' | |
| def _format_lines(self, tokensource): | |
| """ | |
| Just format the tokens, without any wrapping tags. | |
| Yield individual lines. | |
| """ | |
| nocls = self.noclasses | |
| lsep = self.lineseparator | |
| # for <span style=""> lookup only | |
| getcls = self.ttype2class.get | |
| c2s = self.class2style | |
| escape_table = _escape_html_table | |
| tagsfile = self.tagsfile | |
| lspan = '' | |
| line = '' | |
| for ttype, value in tokensource: | |
| if nocls: | |
| cclass = getcls(ttype) | |
| while cclass is None: | |
| ttype = ttype.parent | |
| cclass = getcls(ttype) | |
| cspan = cclass and '<span style="%s">' % c2s[cclass][0] or '' | |
| else: | |
| cls = self._get_css_class(ttype) | |
| cspan = cls and '<span class="%s">' % cls or '' | |
| parts = value.translate(escape_table).split('\n') | |
| 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 += (lspan and '</span>') + cspan + part + \ | |
| (cspan and '</span>') + lsep | |
| else: # both are the same | |
| line += part + (lspan and '</span>') + lsep | |
| yield 1, line | |
| line = '' | |
| elif part: | |
| yield 1, cspan + part + (cspan and '</span>') + lsep | |
| else: | |
| yield 1, lsep | |
| # for the last line | |
| if line and parts[-1]: | |
| if lspan != cspan: | |
| line += (lspan and '</span>') + cspan + parts[-1] | |
| lspan = cspan | |
| else: | |
| line += 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: | |
| yield 1, line + (lspan and '</span>') + lsep | |
| def _lookup_ctag(self, token): | |
| entry = ctags.TagEntry() | |
| if self._ctags.find(entry, token, 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, outfile): | |
| """ | |
| Wrap the ``source``, which is a generator yielding | |
| individual lines, in custom generators. See docstring | |
| for `format`. Can be overridden. | |
| """ | |
| return self._wrap_div(self._wrap_pre(source)) | |
| 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) | |
| if self.hl_lines: | |
| source = self._highlight_lines(source) | |
| if not self.nowrap: | |
| if self.linenos == 2: | |
| source = self._wrap_inlinelinenos(source) | |
| if self.lineanchors: | |
| source = self._wrap_lineanchors(source) | |
| if self.linespans: | |
| source = self._wrap_linespans(source) | |
| source = self.wrap(source, outfile) | |
| if self.linenos == 1: | |
| source = self._wrap_tablelinenos(source) | |
| if self.full: | |
| source = self._wrap_full(source, outfile) | |
| for t, piece in source: | |
| outfile.write(piece) |