diff options
author | ilezhankin <[email protected]> | 2022-02-10 16:45:56 +0300 |
---|---|---|
committer | Daniil Cherednik <[email protected]> | 2022-02-10 16:45:56 +0300 |
commit | 62a805381e41500fbc7914c37c71ab040a098f4e (patch) | |
tree | 1a2c5ffcf89eb53ecd79dbc9bc0a195c27404d0c /contrib/python/Pygments/py2/pygments/formatters | |
parent | 1d125034f06575234f83f24f08677955133f140e (diff) |
Restoring authorship annotation for <[email protected]>. Commit 2 of 2.
Diffstat (limited to 'contrib/python/Pygments/py2/pygments/formatters')
12 files changed, 3156 insertions, 3156 deletions
diff --git a/contrib/python/Pygments/py2/pygments/formatters/__init__.py b/contrib/python/Pygments/py2/pygments/formatters/__init__.py index 864deba3290..6f1130a801e 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/__init__.py +++ b/contrib/python/Pygments/py2/pygments/formatters/__init__.py @@ -1,84 +1,84 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters - ~~~~~~~~~~~~~~~~~~~ - - Pygments formatters. - +# -*- coding: utf-8 -*- +""" + pygments.formatters + ~~~~~~~~~~~~~~~~~~~ + + Pygments formatters. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import re -import sys -import types -import fnmatch -from os.path import basename - -from pygments.formatters._mapping import FORMATTERS -from pygments.plugin import find_plugin_formatters -from pygments.util import ClassNotFound, itervalues - -__all__ = ['get_formatter_by_name', 'get_formatter_for_filename', + :license: BSD, see LICENSE for details. +""" + +import re +import sys +import types +import fnmatch +from os.path import basename + +from pygments.formatters._mapping import FORMATTERS +from pygments.plugin import find_plugin_formatters +from pygments.util import ClassNotFound, itervalues + +__all__ = ['get_formatter_by_name', 'get_formatter_for_filename', 'get_all_formatters', 'load_formatter_from_file'] + list(FORMATTERS) - -_formatter_cache = {} # classes by name -_pattern_cache = {} - - -def _fn_matches(fn, glob): - """Return whether the supplied file name fn matches pattern filename.""" - if glob not in _pattern_cache: - pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob)) - return pattern.match(fn) - return _pattern_cache[glob].match(fn) - - -def _load_formatters(module_name): - """Load a formatter (and all others in the module too).""" - mod = __import__(module_name, None, None, ['__all__']) - for formatter_name in mod.__all__: - cls = getattr(mod, formatter_name) - _formatter_cache[cls.name] = cls - - -def get_all_formatters(): - """Return a generator for all formatter classes.""" - # NB: this returns formatter classes, not info like get_all_lexers(). - for info in itervalues(FORMATTERS): - if info[1] not in _formatter_cache: - _load_formatters(info[0]) - yield _formatter_cache[info[1]] - for _, formatter in find_plugin_formatters(): - yield formatter - - -def find_formatter_class(alias): - """Lookup a formatter by alias. - - Returns None if not found. - """ - for module_name, name, aliases, _, _ in itervalues(FORMATTERS): - if alias in aliases: - if name not in _formatter_cache: - _load_formatters(module_name) - return _formatter_cache[name] - for _, cls in find_plugin_formatters(): - if alias in cls.aliases: - return cls - - -def get_formatter_by_name(_alias, **options): - """Lookup and instantiate a formatter by alias. - - Raises ClassNotFound if not found. - """ - cls = find_formatter_class(_alias) - if cls is None: - raise ClassNotFound("no formatter found for name %r" % _alias) - return cls(**options) - - + +_formatter_cache = {} # classes by name +_pattern_cache = {} + + +def _fn_matches(fn, glob): + """Return whether the supplied file name fn matches pattern filename.""" + if glob not in _pattern_cache: + pattern = _pattern_cache[glob] = re.compile(fnmatch.translate(glob)) + return pattern.match(fn) + return _pattern_cache[glob].match(fn) + + +def _load_formatters(module_name): + """Load a formatter (and all others in the module too).""" + mod = __import__(module_name, None, None, ['__all__']) + for formatter_name in mod.__all__: + cls = getattr(mod, formatter_name) + _formatter_cache[cls.name] = cls + + +def get_all_formatters(): + """Return a generator for all formatter classes.""" + # NB: this returns formatter classes, not info like get_all_lexers(). + for info in itervalues(FORMATTERS): + if info[1] not in _formatter_cache: + _load_formatters(info[0]) + yield _formatter_cache[info[1]] + for _, formatter in find_plugin_formatters(): + yield formatter + + +def find_formatter_class(alias): + """Lookup a formatter by alias. + + Returns None if not found. + """ + for module_name, name, aliases, _, _ in itervalues(FORMATTERS): + if alias in aliases: + if name not in _formatter_cache: + _load_formatters(module_name) + return _formatter_cache[name] + for _, cls in find_plugin_formatters(): + if alias in cls.aliases: + return cls + + +def get_formatter_by_name(_alias, **options): + """Lookup and instantiate a formatter by alias. + + Raises ClassNotFound if not found. + """ + cls = find_formatter_class(_alias) + if cls is None: + raise ClassNotFound("no formatter found for name %r" % _alias) + return cls(**options) + + def load_formatter_from_file(filename, formattername="CustomFormatter", **options): """Load a formatter from a file. @@ -115,40 +115,40 @@ def load_formatter_from_file(filename, formattername="CustomFormatter", raise ClassNotFound('error when loading custom formatter: %s' % err) -def get_formatter_for_filename(fn, **options): - """Lookup and instantiate a formatter by filename pattern. - - Raises ClassNotFound if not found. - """ - fn = basename(fn) - for modname, name, _, filenames, _ in itervalues(FORMATTERS): - for filename in filenames: - if _fn_matches(fn, filename): - if name not in _formatter_cache: - _load_formatters(modname) - return _formatter_cache[name](**options) - for cls in find_plugin_formatters(): - for filename in cls.filenames: - if _fn_matches(fn, filename): - return cls(**options) - raise ClassNotFound("no formatter found for file name %r" % fn) - - -class _automodule(types.ModuleType): - """Automatically import formatters.""" - - def __getattr__(self, name): - info = FORMATTERS.get(name) - if info: - _load_formatters(info[0]) - cls = _formatter_cache[info[1]] - setattr(self, name, cls) - return cls - raise AttributeError(name) - - -oldmod = sys.modules[__name__] -newmod = _automodule(__name__) -newmod.__dict__.update(oldmod.__dict__) -sys.modules[__name__] = newmod -del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types +def get_formatter_for_filename(fn, **options): + """Lookup and instantiate a formatter by filename pattern. + + Raises ClassNotFound if not found. + """ + fn = basename(fn) + for modname, name, _, filenames, _ in itervalues(FORMATTERS): + for filename in filenames: + if _fn_matches(fn, filename): + if name not in _formatter_cache: + _load_formatters(modname) + return _formatter_cache[name](**options) + for cls in find_plugin_formatters(): + for filename in cls.filenames: + if _fn_matches(fn, filename): + return cls(**options) + raise ClassNotFound("no formatter found for file name %r" % fn) + + +class _automodule(types.ModuleType): + """Automatically import formatters.""" + + def __getattr__(self, name): + info = FORMATTERS.get(name) + if info: + _load_formatters(info[0]) + cls = _formatter_cache[info[1]] + setattr(self, name, cls) + return cls + raise AttributeError(name) + + +oldmod = sys.modules[__name__] +newmod = _automodule(__name__) +newmod.__dict__.update(oldmod.__dict__) +sys.modules[__name__] = newmod +del newmod.newmod, newmod.oldmod, newmod.sys, newmod.types diff --git a/contrib/python/Pygments/py2/pygments/formatters/_mapping.py b/contrib/python/Pygments/py2/pygments/formatters/_mapping.py index 29f22e689c5..5086e51970b 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/_mapping.py +++ b/contrib/python/Pygments/py2/pygments/formatters/_mapping.py @@ -1,85 +1,85 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters._mapping - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter mapping definitions. This file is generated by itself. Everytime - you change something on a builtin formatter definition, run this script from - the formatters folder to update it. - - Do not alter the FORMATTERS dictionary by hand. - +# -*- coding: utf-8 -*- +""" + pygments.formatters._mapping + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter mapping definitions. This file is generated by itself. Everytime + you change something on a builtin formatter definition, run this script from + the formatters folder to update it. + + Do not alter the FORMATTERS dictionary by hand. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from __future__ import print_function - -FORMATTERS = { - 'BBCodeFormatter': ('pygments.formatters.bbcode', 'BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'), - 'BmpImageFormatter': ('pygments.formatters.img', 'img_bmp', ('bmp', 'bitmap'), ('*.bmp',), 'Create a bitmap image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), - 'GifImageFormatter': ('pygments.formatters.img', 'img_gif', ('gif',), ('*.gif',), 'Create a GIF image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), - 'HtmlFormatter': ('pygments.formatters.html', 'HTML', ('html',), ('*.html', '*.htm'), "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."), - 'IRCFormatter': ('pygments.formatters.irc', 'IRC', ('irc', 'IRC'), (), 'Format tokens with IRC color sequences'), - 'ImageFormatter': ('pygments.formatters.img', 'img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), - 'JpgImageFormatter': ('pygments.formatters.img', 'img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), - 'LatexFormatter': ('pygments.formatters.latex', 'LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'), - 'NullFormatter': ('pygments.formatters.other', 'Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'), - 'RawTokenFormatter': ('pygments.formatters.other', 'Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'), - 'RtfFormatter': ('pygments.formatters.rtf', 'RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft(R) Word(R) documents.'), - 'SvgFormatter': ('pygments.formatters.svg', 'SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file. This formatter is still experimental. Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` coordinates containing ``<tspan>`` elements with the individual token styles.'), - 'Terminal256Formatter': ('pygments.formatters.terminal256', 'Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), - 'TerminalFormatter': ('pygments.formatters.terminal', 'Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.'), - 'TerminalTrueColorFormatter': ('pygments.formatters.terminal256', 'TerminalTrueColor', ('terminal16m', 'console16m', '16m'), (), 'Format tokens with ANSI color sequences, for output in a true-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), - 'TestcaseFormatter': ('pygments.formatters.other', 'Testcase', ('testcase',), (), 'Format tokens as appropriate for a new testcase.') -} - -if __name__ == '__main__': # pragma: no cover - import sys - import os - - # lookup formatters - found_formatters = [] - imports = [] - sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) - from pygments.util import docstring_headline - - for root, dirs, files in os.walk('.'): - for filename in files: - if filename.endswith('.py') and not filename.startswith('_'): - module_name = 'pygments.formatters%s.%s' % ( - root[1:].replace('/', '.'), filename[:-3]) - print(module_name) - module = __import__(module_name, None, None, ['']) - for formatter_name in module.__all__: - formatter = getattr(module, formatter_name) - found_formatters.append( - '%r: %r' % (formatter_name, - (module_name, - formatter.name, - tuple(formatter.aliases), - tuple(formatter.filenames), - docstring_headline(formatter)))) - # sort them to make the diff minimal - found_formatters.sort() - - # extract useful sourcecode from this file - with open(__file__) as fp: - content = fp.read() - # replace crnl to nl for Windows. - # - # Note that, originally, contributers should keep nl of master - # repository, for example by using some kind of automatic - # management EOL, like `EolExtension - # <https://www.mercurial-scm.org/wiki/EolExtension>`. - content = content.replace("\r\n", "\n") - header = content[:content.find('FORMATTERS = {')] - footer = content[content.find("if __name__ == '__main__':"):] - - # write new file + :license: BSD, see LICENSE for details. +""" + +from __future__ import print_function + +FORMATTERS = { + 'BBCodeFormatter': ('pygments.formatters.bbcode', 'BBCode', ('bbcode', 'bb'), (), 'Format tokens with BBcodes. These formatting codes are used by many bulletin boards, so you can highlight your sourcecode with pygments before posting it there.'), + 'BmpImageFormatter': ('pygments.formatters.img', 'img_bmp', ('bmp', 'bitmap'), ('*.bmp',), 'Create a bitmap image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'GifImageFormatter': ('pygments.formatters.img', 'img_gif', ('gif',), ('*.gif',), 'Create a GIF image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'HtmlFormatter': ('pygments.formatters.html', 'HTML', ('html',), ('*.html', '*.htm'), "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."), + 'IRCFormatter': ('pygments.formatters.irc', 'IRC', ('irc', 'IRC'), (), 'Format tokens with IRC color sequences'), + 'ImageFormatter': ('pygments.formatters.img', 'img', ('img', 'IMG', 'png'), ('*.png',), 'Create a PNG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'JpgImageFormatter': ('pygments.formatters.img', 'img_jpg', ('jpg', 'jpeg'), ('*.jpg',), 'Create a JPEG image from source code. This uses the Python Imaging Library to generate a pixmap from the source code.'), + 'LatexFormatter': ('pygments.formatters.latex', 'LaTeX', ('latex', 'tex'), ('*.tex',), 'Format tokens as LaTeX code. This needs the `fancyvrb` and `color` standard packages.'), + 'NullFormatter': ('pygments.formatters.other', 'Text only', ('text', 'null'), ('*.txt',), 'Output the text unchanged without any formatting.'), + 'RawTokenFormatter': ('pygments.formatters.other', 'Raw tokens', ('raw', 'tokens'), ('*.raw',), 'Format tokens as a raw representation for storing token streams.'), + 'RtfFormatter': ('pygments.formatters.rtf', 'RTF', ('rtf',), ('*.rtf',), 'Format tokens as RTF markup. This formatter automatically outputs full RTF documents with color information and other useful stuff. Perfect for Copy and Paste into Microsoft(R) Word(R) documents.'), + 'SvgFormatter': ('pygments.formatters.svg', 'SVG', ('svg',), ('*.svg',), 'Format tokens as an SVG graphics file. This formatter is still experimental. Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` coordinates containing ``<tspan>`` elements with the individual token styles.'), + 'Terminal256Formatter': ('pygments.formatters.terminal256', 'Terminal256', ('terminal256', 'console256', '256'), (), 'Format tokens with ANSI color sequences, for output in a 256-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TerminalFormatter': ('pygments.formatters.terminal', 'Terminal', ('terminal', 'console'), (), 'Format tokens with ANSI color sequences, for output in a text console. Color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TerminalTrueColorFormatter': ('pygments.formatters.terminal256', 'TerminalTrueColor', ('terminal16m', 'console16m', '16m'), (), 'Format tokens with ANSI color sequences, for output in a true-color terminal or console. Like in `TerminalFormatter` color sequences are terminated at newlines, so that paging the output works correctly.'), + 'TestcaseFormatter': ('pygments.formatters.other', 'Testcase', ('testcase',), (), 'Format tokens as appropriate for a new testcase.') +} + +if __name__ == '__main__': # pragma: no cover + import sys + import os + + # lookup formatters + found_formatters = [] + imports = [] + sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) + from pygments.util import docstring_headline + + for root, dirs, files in os.walk('.'): + for filename in files: + if filename.endswith('.py') and not filename.startswith('_'): + module_name = 'pygments.formatters%s.%s' % ( + root[1:].replace('/', '.'), filename[:-3]) + print(module_name) + module = __import__(module_name, None, None, ['']) + for formatter_name in module.__all__: + formatter = getattr(module, formatter_name) + found_formatters.append( + '%r: %r' % (formatter_name, + (module_name, + formatter.name, + tuple(formatter.aliases), + tuple(formatter.filenames), + docstring_headline(formatter)))) + # sort them to make the diff minimal + found_formatters.sort() + + # extract useful sourcecode from this file + with open(__file__) as fp: + content = fp.read() + # replace crnl to nl for Windows. + # + # Note that, originally, contributers should keep nl of master + # repository, for example by using some kind of automatic + # management EOL, like `EolExtension + # <https://www.mercurial-scm.org/wiki/EolExtension>`. + content = content.replace("\r\n", "\n") + header = content[:content.find('FORMATTERS = {')] + footer = content[content.find("if __name__ == '__main__':"):] + + # write new file with open(__file__, 'w') as fp: - fp.write(header) - fp.write('FORMATTERS = {\n %s\n}\n\n' % ',\n '.join(found_formatters)) - fp.write(footer) - - print ('=== %d formatters processed.' % len(found_formatters)) + fp.write(header) + fp.write('FORMATTERS = {\n %s\n}\n\n' % ',\n '.join(found_formatters)) + fp.write(footer) + + print ('=== %d formatters processed.' % len(found_formatters)) diff --git a/contrib/python/Pygments/py2/pygments/formatters/bbcode.py b/contrib/python/Pygments/py2/pygments/formatters/bbcode.py index 1016695c4b7..784aee3ae77 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/bbcode.py +++ b/contrib/python/Pygments/py2/pygments/formatters/bbcode.py @@ -1,109 +1,109 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.bbcode - ~~~~~~~~~~~~~~~~~~~~~~~~~~ - - BBcode formatter. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.bbcode + ~~~~~~~~~~~~~~~~~~~~~~~~~~ + + BBcode formatter. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - - -from pygments.formatter import Formatter -from pygments.util import get_bool_opt - -__all__ = ['BBCodeFormatter'] - - -class BBCodeFormatter(Formatter): - """ - Format tokens with BBcodes. These formatting codes are used by many - bulletin boards, so you can highlight your sourcecode with pygments before - posting it there. - - This formatter has no support for background colors and borders, as there - are no common BBcode tags for that. - - Some board systems (e.g. phpBB) don't support colors in their [code] tag, - so you can't use the highlighting together with that tag. - Text in a [code] tag usually is shown with a monospace font (which this - formatter can do with the ``monofont`` option) and no spaces (which you - need for indentation) are removed. - - Additional options accepted: - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). - - `codetag` - If set to true, put the output into ``[code]`` tags (default: - ``false``) - - `monofont` - If set to true, add a tag to show the code with a monospace font - (default: ``false``). - """ - name = 'BBCode' - aliases = ['bbcode', 'bb'] - filenames = [] - - def __init__(self, **options): - Formatter.__init__(self, **options) - self._code = get_bool_opt(options, 'codetag', False) - self._mono = get_bool_opt(options, 'monofont', False) - - self.styles = {} - self._make_styles() - - def _make_styles(self): - for ttype, ndef in self.style: - start = end = '' - if ndef['color']: - start += '[color=#%s]' % ndef['color'] - end = '[/color]' + end - if ndef['bold']: - start += '[b]' - end = '[/b]' + end - if ndef['italic']: - start += '[i]' - end = '[/i]' + end - if ndef['underline']: - start += '[u]' - end = '[/u]' + end - # there are no common BBcodes for background-color and border - - self.styles[ttype] = start, end - - def format_unencoded(self, tokensource, outfile): - if self._code: - outfile.write('[code]') - if self._mono: - outfile.write('[font=monospace]') - - lastval = '' - lasttype = None - - for ttype, value in tokensource: - while ttype not in self.styles: - ttype = ttype.parent - if ttype == lasttype: - lastval += value - else: - if lastval: - start, end = self.styles[lasttype] - outfile.write(''.join((start, lastval, end))) - lastval = value - lasttype = ttype - - if lastval: - start, end = self.styles[lasttype] - outfile.write(''.join((start, lastval, end))) - - if self._mono: - outfile.write('[/font]') - if self._code: - outfile.write('[/code]') - if self._code or self._mono: - outfile.write('\n') + :license: BSD, see LICENSE for details. +""" + + +from pygments.formatter import Formatter +from pygments.util import get_bool_opt + +__all__ = ['BBCodeFormatter'] + + +class BBCodeFormatter(Formatter): + """ + Format tokens with BBcodes. These formatting codes are used by many + bulletin boards, so you can highlight your sourcecode with pygments before + posting it there. + + This formatter has no support for background colors and borders, as there + are no common BBcode tags for that. + + Some board systems (e.g. phpBB) don't support colors in their [code] tag, + so you can't use the highlighting together with that tag. + Text in a [code] tag usually is shown with a monospace font (which this + formatter can do with the ``monofont`` option) and no spaces (which you + need for indentation) are removed. + + Additional options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + + `codetag` + If set to true, put the output into ``[code]`` tags (default: + ``false``) + + `monofont` + If set to true, add a tag to show the code with a monospace font + (default: ``false``). + """ + name = 'BBCode' + aliases = ['bbcode', 'bb'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self._code = get_bool_opt(options, 'codetag', False) + self._mono = get_bool_opt(options, 'monofont', False) + + self.styles = {} + self._make_styles() + + def _make_styles(self): + for ttype, ndef in self.style: + start = end = '' + if ndef['color']: + start += '[color=#%s]' % ndef['color'] + end = '[/color]' + end + if ndef['bold']: + start += '[b]' + end = '[/b]' + end + if ndef['italic']: + start += '[i]' + end = '[/i]' + end + if ndef['underline']: + start += '[u]' + end = '[/u]' + end + # there are no common BBcodes for background-color and border + + self.styles[ttype] = start, end + + def format_unencoded(self, tokensource, outfile): + if self._code: + outfile.write('[code]') + if self._mono: + outfile.write('[font=monospace]') + + lastval = '' + lasttype = None + + for ttype, value in tokensource: + while ttype not in self.styles: + ttype = ttype.parent + if ttype == lasttype: + lastval += value + else: + if lastval: + start, end = self.styles[lasttype] + outfile.write(''.join((start, lastval, end))) + lastval = value + lasttype = ttype + + if lastval: + start, end = self.styles[lasttype] + outfile.write(''.join((start, lastval, end))) + + if self._mono: + outfile.write('[/font]') + if self._code: + outfile.write('[/code]') + if self._code or self._mono: + outfile.write('\n') diff --git a/contrib/python/Pygments/py2/pygments/formatters/html.py b/contrib/python/Pygments/py2/pygments/formatters/html.py index a2d171cd416..042f04cfb1e 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/html.py +++ b/contrib/python/Pygments/py2/pygments/formatters/html.py @@ -1,880 +1,880 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.html - ~~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for HTML output. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.html + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for HTML output. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from __future__ import print_function - -import os -import sys -import os.path - -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, \ - StringIO, string_types, iteritems - -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) - + :license: BSD, see LICENSE for details. +""" + +from __future__ import print_function + +import os +import sys +import os.path + +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, \ + StringIO, string_types, iteritems + +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 webify(color): if color.startswith('calc') or color.startswith('var'): return color else: return '#' + color - -def _get_ttype_class(ttype): - fname = STANDARD_TYPES.get(ttype) - if fname: - return fname - aname = '' - while fname is None: - aname = '-' + ttype[-1] + aname - ttype = ttype.parent - fname = STANDARD_TYPES.get(ttype) - return fname + aname - - -CSSFILE_TEMPLATE = '''\ + +def _get_ttype_class(ttype): + fname = STANDARD_TYPES.get(ttype) + if fname: + return fname + aname = '' + while fname is None: + aname = '-' + ttype[-1] + aname + ttype = ttype.parent + fname = STANDARD_TYPES.get(ttype) + return fname + aname + + +CSSFILE_TEMPLATE = '''\ /* generated by Pygments <http://pygments.org> Copyright 2006-2019 by the Pygments team. Licensed under the BSD license, see LICENSE for details. */ -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"> +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"> <!-- generated by Pygments <http://pygments.org> Copyright 2006-2019 by the Pygments team. Licensed under the BSD license, see LICENSE for details. --> -<html> -<head> - <title>%(title)s</title> - <meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> - <style type="text/css"> -''' + CSSFILE_TEMPLATE + ''' - </style> -</head> -<body> -<h2>%(title)s</h2> - -''' - -DOC_HEADER_EXTERNALCSS = '''\ -<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" - "http://www.w3.org/TR/html4/strict.dtd"> - -<html> -<head> - <title>%(title)s</title> - <meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> - <link rel="stylesheet" href="%(cssfile)s" type="text/css"> -</head> -<body> -<h2>%(title)s</h2> - -''' - -DOC_FOOTER = '''\ -</body> -</html> -''' - - -class HtmlFormatter(Formatter): - r""" - Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped - in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` - option. - - If the `linenos` option is set to ``"table"``, the ``<pre>`` is - additionally wrapped inside a ``<table>`` which has one row and two - cells: one containing the line numbers and one containing the code. - Example: - - .. sourcecode:: html - - <div class="highlight" > - <table><tr> - <td class="linenos" title="click to toggle" - onclick="with (this.firstChild.style) - { display = (display == '') ? 'none' : '' }"> - <pre>1 - 2</pre> - </td> - <td class="code"> - <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar): - <span class="Ke">pass</span> - </pre> - </td> - </tr></table></div> - - (whitespace added to improve clarity). - - Wrapping can be disabled using the `nowrap` option. - - A list of lines can be specified using the `hl_lines` option to make these - lines highlighted (as of Pygments 0.11). - - With the `full` option, a complete HTML 4 document is output, including - the style definitions inside a ``<style>`` tag, or in a separate file if - the `cssfile` option is given. - - When `tagsfile` is set to the path of a ctags index file, it is used to - generate hyperlinks from names to their definition. You must enable - `lineanchors` and run ctags with the `-n` option for this to work. The - `python-ctags` module from PyPI must be installed to use this feature; - otherwise a `RuntimeError` will be raised. - - The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string - containing CSS rules for the CSS classes used by the formatter. The - argument `arg` can be used to specify additional CSS selectors that - are prepended to the classes. A call `fmter.get_style_defs('td .code')` - would result in the following CSS classes: - - .. sourcecode:: css - - td .code .kw { font-weight: bold; color: #00FF00 } - td .code .cm { color: #999999 } - ... - - If you have Pygments 0.6 or higher, you can also pass a list or tuple to the - `get_style_defs()` method to request multiple prefixes for the tokens: - - .. sourcecode:: python - - formatter.get_style_defs(['div.syntax pre', 'pre.syntax']) - - The output would then look like this: - - .. sourcecode:: css - - div.syntax pre .kw, - pre.syntax .kw { font-weight: bold; color: #00FF00 } - div.syntax pre .cm, - pre.syntax .cm { color: #999999 } - ... - - Additional options accepted: - - `nowrap` - If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>`` - tag. This disables most other options (default: ``False``). - - `full` - Tells the formatter to output a "full" document, i.e. a complete - self-contained document (default: ``False``). - - `title` - If `full` is true, the title that should be used to caption the - document (default: ``''``). - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). This option has no effect if the `cssfile` - and `noclobber_cssfile` option are given and the file specified in - `cssfile` exists. - - `noclasses` - If set to true, token ``<span>`` tags will not use CSS classes, but - inline styles. This is not recommended for larger pieces of code since - it increases output size by quite a bit (default: ``False``). - - `classprefix` - Since the token types use relatively short class names, they may clash - with some of your own class names. In this case you can use the - `classprefix` option to give a string to prepend to all Pygments-generated - CSS class names for token types. - Note that this option also affects the output of `get_style_defs()`. - - `cssclass` - CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``). - If you set this option, the default selector for `get_style_defs()` - will be this class. - - .. versionadded:: 0.9 - If you select the ``'table'`` line numbers, the wrapping table will - have a CSS class of this string plus ``'table'``, the default is - accordingly ``'highlighttable'``. - - `cssstyles` - Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``). - - `prestyles` - Inline CSS styles for the ``<pre>`` tag (default: ``''``). - - .. versionadded:: 0.11 - - `cssfile` - If the `full` option is true and this option is given, it must be the - name of an external file. If the filename does not include an absolute - path, the file's path will be assumed to be relative to the main output - file's path, if the latter can be found. The stylesheet is then written - to this file instead of the HTML file. - - .. versionadded:: 0.6 - - `noclobber_cssfile` - If `cssfile` is given and the specified file exists, the css file will - not be overwritten. This allows the use of the `full` option in - combination with a user specified css file. Default is ``False``. - - .. versionadded:: 1.1 - - `linenos` - If set to ``'table'``, output line numbers as a table with two cells, - one containing the line numbers, the other the whole code. This is - copy-and-paste-friendly, but may cause alignment problems with some - browsers or fonts. If set to ``'inline'``, the line numbers will be - integrated in the ``<pre>`` tag that contains the code (that setting - is *new in Pygments 0.8*). - - For compatibility with Pygments 0.7 and earlier, every true value - except ``'inline'`` means the same as ``'table'`` (in particular, that - means also ``True``). - - The default value is ``False``, which means no line numbers at all. - - **Note:** with the default ("table") line number mechanism, the line - numbers and code can have different line heights in Internet Explorer - unless you give the enclosing ``<pre>`` tags an explicit ``line-height`` - CSS property (you get the default line spacing with ``line-height: - 125%``). - - `hl_lines` - Specify a list of lines to be highlighted. - - .. versionadded:: 0.11 - - `linenostart` - The line number for the first line (default: ``1``). - - `linenostep` - If set to a number n > 1, only every nth line number is printed. - - `linenospecial` - If set to a number n > 0, every nth line number is given the CSS - class ``"special"`` (default: ``0``). - - `nobackground` - If set to ``True``, the formatter won't output the background color - for the wrapping element (this automatically defaults to ``False`` - when there is no wrapping element [eg: no argument for the - `get_syntax_defs` method given]) (default: ``False``). - - .. versionadded:: 0.6 - - `lineseparator` - This string is output between lines of code. It defaults to ``"\n"``, - which is enough to break a line inside ``<pre>`` tags, but you can - e.g. set it to ``"<br>"`` to get HTML line breaks. - - .. versionadded:: 0.7 - - `lineanchors` - If set to a nonempty string, e.g. ``foo``, the formatter will wrap each - output line in an anchor tag with a ``name`` of ``foo-linenumber``. - This allows easy linking to certain lines. - - .. versionadded:: 0.9 - - `linespans` - If set to a nonempty string, e.g. ``foo``, the formatter will wrap each - output line in a span tag with an ``id`` of ``foo-linenumber``. - This allows easy access to lines via javascript. - - .. versionadded:: 1.6 - - `anchorlinenos` - If set to `True`, will wrap line numbers in <a> tags. Used in - combination with `linenos` and `lineanchors`. - - `tagsfile` - If set to the path of a ctags file, wrap names in anchor tags that - link to their definitions. `lineanchors` should be used, and the - tags file should specify line numbers (see the `-n` option to ctags). - - .. versionadded:: 1.6 - - `tagurlformat` - A string formatting pattern used to generate links to ctags definitions. - Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`. - Defaults to an empty string, resulting in just `#prefix-number` links. - - .. versionadded:: 1.6 - - `filename` +<html> +<head> + <title>%(title)s</title> + <meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> + <style type="text/css"> +''' + CSSFILE_TEMPLATE + ''' + </style> +</head> +<body> +<h2>%(title)s</h2> + +''' + +DOC_HEADER_EXTERNALCSS = '''\ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> + +<html> +<head> + <title>%(title)s</title> + <meta http-equiv="content-type" content="text/html; charset=%(encoding)s"> + <link rel="stylesheet" href="%(cssfile)s" type="text/css"> +</head> +<body> +<h2>%(title)s</h2> + +''' + +DOC_FOOTER = '''\ +</body> +</html> +''' + + +class HtmlFormatter(Formatter): + r""" + Format tokens as HTML 4 ``<span>`` tags within a ``<pre>`` tag, wrapped + in a ``<div>`` tag. The ``<div>``'s CSS class can be set by the `cssclass` + option. + + If the `linenos` option is set to ``"table"``, the ``<pre>`` is + additionally wrapped inside a ``<table>`` which has one row and two + cells: one containing the line numbers and one containing the code. + Example: + + .. sourcecode:: html + + <div class="highlight" > + <table><tr> + <td class="linenos" title="click to toggle" + onclick="with (this.firstChild.style) + { display = (display == '') ? 'none' : '' }"> + <pre>1 + 2</pre> + </td> + <td class="code"> + <pre><span class="Ke">def </span><span class="NaFu">foo</span>(bar): + <span class="Ke">pass</span> + </pre> + </td> + </tr></table></div> + + (whitespace added to improve clarity). + + Wrapping can be disabled using the `nowrap` option. + + A list of lines can be specified using the `hl_lines` option to make these + lines highlighted (as of Pygments 0.11). + + With the `full` option, a complete HTML 4 document is output, including + the style definitions inside a ``<style>`` tag, or in a separate file if + the `cssfile` option is given. + + When `tagsfile` is set to the path of a ctags index file, it is used to + generate hyperlinks from names to their definition. You must enable + `lineanchors` and run ctags with the `-n` option for this to work. The + `python-ctags` module from PyPI must be installed to use this feature; + otherwise a `RuntimeError` will be raised. + + The `get_style_defs(arg='')` method of a `HtmlFormatter` returns a string + containing CSS rules for the CSS classes used by the formatter. The + argument `arg` can be used to specify additional CSS selectors that + are prepended to the classes. A call `fmter.get_style_defs('td .code')` + would result in the following CSS classes: + + .. sourcecode:: css + + td .code .kw { font-weight: bold; color: #00FF00 } + td .code .cm { color: #999999 } + ... + + If you have Pygments 0.6 or higher, you can also pass a list or tuple to the + `get_style_defs()` method to request multiple prefixes for the tokens: + + .. sourcecode:: python + + formatter.get_style_defs(['div.syntax pre', 'pre.syntax']) + + The output would then look like this: + + .. sourcecode:: css + + div.syntax pre .kw, + pre.syntax .kw { font-weight: bold; color: #00FF00 } + div.syntax pre .cm, + pre.syntax .cm { color: #999999 } + ... + + Additional options accepted: + + `nowrap` + If set to ``True``, don't wrap the tokens at all, not even inside a ``<pre>`` + tag. This disables most other options (default: ``False``). + + `full` + Tells the formatter to output a "full" document, i.e. a complete + self-contained document (default: ``False``). + + `title` + If `full` is true, the title that should be used to caption the + document (default: ``''``). + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). This option has no effect if the `cssfile` + and `noclobber_cssfile` option are given and the file specified in + `cssfile` exists. + + `noclasses` + If set to true, token ``<span>`` tags will not use CSS classes, but + inline styles. This is not recommended for larger pieces of code since + it increases output size by quite a bit (default: ``False``). + + `classprefix` + Since the token types use relatively short class names, they may clash + with some of your own class names. In this case you can use the + `classprefix` option to give a string to prepend to all Pygments-generated + CSS class names for token types. + Note that this option also affects the output of `get_style_defs()`. + + `cssclass` + CSS class for the wrapping ``<div>`` tag (default: ``'highlight'``). + If you set this option, the default selector for `get_style_defs()` + will be this class. + + .. versionadded:: 0.9 + If you select the ``'table'`` line numbers, the wrapping table will + have a CSS class of this string plus ``'table'``, the default is + accordingly ``'highlighttable'``. + + `cssstyles` + Inline CSS styles for the wrapping ``<div>`` tag (default: ``''``). + + `prestyles` + Inline CSS styles for the ``<pre>`` tag (default: ``''``). + + .. versionadded:: 0.11 + + `cssfile` + If the `full` option is true and this option is given, it must be the + name of an external file. If the filename does not include an absolute + path, the file's path will be assumed to be relative to the main output + file's path, if the latter can be found. The stylesheet is then written + to this file instead of the HTML file. + + .. versionadded:: 0.6 + + `noclobber_cssfile` + If `cssfile` is given and the specified file exists, the css file will + not be overwritten. This allows the use of the `full` option in + combination with a user specified css file. Default is ``False``. + + .. versionadded:: 1.1 + + `linenos` + If set to ``'table'``, output line numbers as a table with two cells, + one containing the line numbers, the other the whole code. This is + copy-and-paste-friendly, but may cause alignment problems with some + browsers or fonts. If set to ``'inline'``, the line numbers will be + integrated in the ``<pre>`` tag that contains the code (that setting + is *new in Pygments 0.8*). + + For compatibility with Pygments 0.7 and earlier, every true value + except ``'inline'`` means the same as ``'table'`` (in particular, that + means also ``True``). + + The default value is ``False``, which means no line numbers at all. + + **Note:** with the default ("table") line number mechanism, the line + numbers and code can have different line heights in Internet Explorer + unless you give the enclosing ``<pre>`` tags an explicit ``line-height`` + CSS property (you get the default line spacing with ``line-height: + 125%``). + + `hl_lines` + Specify a list of lines to be highlighted. + + .. versionadded:: 0.11 + + `linenostart` + The line number for the first line (default: ``1``). + + `linenostep` + If set to a number n > 1, only every nth line number is printed. + + `linenospecial` + If set to a number n > 0, every nth line number is given the CSS + class ``"special"`` (default: ``0``). + + `nobackground` + If set to ``True``, the formatter won't output the background color + for the wrapping element (this automatically defaults to ``False`` + when there is no wrapping element [eg: no argument for the + `get_syntax_defs` method given]) (default: ``False``). + + .. versionadded:: 0.6 + + `lineseparator` + This string is output between lines of code. It defaults to ``"\n"``, + which is enough to break a line inside ``<pre>`` tags, but you can + e.g. set it to ``"<br>"`` to get HTML line breaks. + + .. versionadded:: 0.7 + + `lineanchors` + If set to a nonempty string, e.g. ``foo``, the formatter will wrap each + output line in an anchor tag with a ``name`` of ``foo-linenumber``. + This allows easy linking to certain lines. + + .. versionadded:: 0.9 + + `linespans` + If set to a nonempty string, e.g. ``foo``, the formatter will wrap each + output line in a span tag with an ``id`` of ``foo-linenumber``. + This allows easy access to lines via javascript. + + .. versionadded:: 1.6 + + `anchorlinenos` + If set to `True`, will wrap line numbers in <a> tags. Used in + combination with `linenos` and `lineanchors`. + + `tagsfile` + If set to the path of a ctags file, wrap names in anchor tags that + link to their definitions. `lineanchors` should be used, and the + tags file should specify line numbers (see the `-n` option to ctags). + + .. versionadded:: 1.6 + + `tagurlformat` + A string formatting pattern used to generate links to ctags definitions. + Available variables are `%(path)s`, `%(fname)s` and `%(fext)s`. + Defaults to an empty string, resulting in just `#prefix-number` links. + + .. versionadded:: 1.6 + + `filename` A string used to generate a filename when rendering ``<pre>`` blocks, - for example if displaying source code. - - .. versionadded:: 2.1 - + for example if displaying source code. + + .. versionadded:: 2.1 + `wrapcode` Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended by the HTML5 specification. - + .. versionadded:: 2.4 - **Subclassing the HTML formatter** - - .. versionadded:: 0.7 - - The HTML formatter is now built in a way that allows easy subclassing, thus - customizing the output HTML code. The `format()` method calls - `self._format_lines()` which returns a generator that yields tuples of ``(1, - line)``, where the ``1`` indicates that the ``line`` is a line of the - formatted source code. - - If the `nowrap` option is set, the generator is the iterated over and the - resulting HTML is output. - - Otherwise, `format()` calls `self.wrap()`, which wraps the generator with - other generators. These may add some HTML code to the one generated by - `_format_lines()`, either by modifying the lines generated by the latter, - then yielding them again with ``(1, line)``, and/or by yielding other HTML - code before or after the lines, with ``(0, html)``. The distinction between - source lines and other code makes it possible to wrap the generator multiple - times. - - The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag. - - A custom `HtmlFormatter` subclass could look like this: - - .. sourcecode:: python - - class CodeHtmlFormatter(HtmlFormatter): - - def wrap(self, source, 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', '')) - self.filename = self._decodeifneeded(options.get('filename', '')) + **Subclassing the HTML formatter** + + .. versionadded:: 0.7 + + The HTML formatter is now built in a way that allows easy subclassing, thus + customizing the output HTML code. The `format()` method calls + `self._format_lines()` which returns a generator that yields tuples of ``(1, + line)``, where the ``1`` indicates that the ``line`` is a line of the + formatted source code. + + If the `nowrap` option is set, the generator is the iterated over and the + resulting HTML is output. + + Otherwise, `format()` calls `self.wrap()`, which wraps the generator with + other generators. These may add some HTML code to the one generated by + `_format_lines()`, either by modifying the lines generated by the latter, + then yielding them again with ``(1, line)``, and/or by yielding other HTML + code before or after the lines, with ``(0, html)``. The distinction between + source lines and other code makes it possible to wrap the generator multiple + times. + + The default `wrap()` implementation adds a ``<div>`` and a ``<pre>`` tag. + + A custom `HtmlFormatter` subclass could look like this: + + .. sourcecode:: python + + class CodeHtmlFormatter(HtmlFormatter): + + def wrap(self, source, 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', '')) + self.filename = self._decodeifneeded(options.get('filename', '')) self.wrapcode = get_bool_opt(options, 'wrapcode', False) - - if self.tagsfile: - if not ctags: - raise RuntimeError('The "ctags" package must to be installed ' - 'to be able to use the "tagsfile" feature.') - self._ctags = ctags.CTags(self.tagsfile) - - linenos = options.get('linenos', False) - if linenos == 'inline': - self.linenos = 2 - elif linenos: - # compatibility with <= 0.7 - self.linenos = 1 - else: - self.linenos = 0 - self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) - self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) - self.linenospecial = abs(get_int_opt(options, 'linenospecial', 0)) - self.nobackground = get_bool_opt(options, 'nobackground', False) + + 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', u'\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 _get_css_classes(self, ttype): - """Return the css classes of this token type prefixed with - the classprefix option.""" - cls = self._get_css_class(ttype) - while ttype not in STANDARD_TYPES: - ttype = ttype.parent - cls = self._get_css_class(ttype) + ' ' + cls - return cls - - 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']: + 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 _get_css_classes(self, ttype): + """Return the css classes of this token type prefixed with + the classprefix option.""" + cls = self._get_css_class(ttype) + while ttype not in STANDARD_TYPES: + ttype = ttype.parent + cls = self._get_css_class(ttype) + ' ' + cls + return cls + + def _create_stylesheet(self): + t2c = self.ttype2class = {Token: ''} + c2s = self.class2style = {} + for ttype, ndef in self.style: + name = self._get_css_class(ttype) + style = '' + if ndef['color']: style += 'color: %s; ' % webify(ndef['color']) - if ndef['bold']: - style += 'font-weight: bold; ' - if ndef['italic']: - style += 'font-style: italic; ' - if ndef['underline']: - style += 'text-decoration: underline; ' - if ndef['bgcolor']: + if ndef['bold']: + style += 'font-weight: bold; ' + if ndef['italic']: + style += 'font-style: italic; ' + if ndef['underline']: + style += 'text-decoration: underline; ' + if ndef['bgcolor']: style += 'background-color: %s; ' % webify(ndef['bgcolor']) - if ndef['border']: + if ndef['border']: style += 'border: 1px solid %s; ' % webify(ndef['border']) - if style: - t2c[ttype] = name - # save len(ttype) to enable ordering the styles by - # hierarchy (necessary for CSS cascading rules!) - c2s[name] = (style[:-2], ttype, len(ttype)) - - def get_style_defs(self, arg=None): - """ - Return CSS style definitions for the classes produced by the current - highlighting style. ``arg`` can be a string or list of selectors to - insert before the token type classes. - """ - if arg is None: - arg = ('cssclass' in self.options and '.'+self.cssclass or '') - if isinstance(arg, string_types): - 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 iteritems(self.class2style) - 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('Note: Cannot determine output file name, ' - 'using current directory as base for the CSS file name', - file=sys.stderr) - cssfilename = self.cssfile - # write CSS file only if noclobber_cssfile isn't given as an option. - try: - if not os.path.exists(cssfilename) or not self.noclobber_cssfile: + 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, string_types): + 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 iteritems(self.class2style) + 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('Note: Cannot determine output file name, ' + 'using current directory as base for the CSS file name', + file=sys.stderr) + cssfilename = self.cssfile + # write CSS file only if noclobber_cssfile isn't given as an option. + try: + if not os.path.exists(cssfilename) or not self.noclobber_cssfile: with open(cssfilename, "w") as cf: cf.write(CSSFILE_TEMPLATE % {'styledefs': self.get_style_defs('body')}) - except IOError as err: - err.strerror = 'Error writing CSS file: ' + err.strerror - raise - - yield 0, (DOC_HEADER_EXTERNALCSS % - dict(title=self.title, - cssfile=self.cssfile, - encoding=self.encoding)) - else: - yield 0, (DOC_HEADER % - dict(title=self.title, - styledefs=self.get_style_defs('body'), - encoding=self.encoding)) - - for t, line in inner: - yield t, line - yield 0, DOC_FOOTER - - def _wrap_tablelinenos(self, inner): - dummyoutfile = StringIO() - lncount = 0 - for t, line in inner: - if t: - lncount += 1 - dummyoutfile.write(line) - - fl = self.linenostart - mw = len(str(lncount + fl - 1)) - sp = self.linenospecial - st = self.linenostep - 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 - # subtract 1 since we have to increment i *before* yielding - i = self.linenostart - 1 - 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) - - if self.filename: - yield 0, ('<span class="filename">' + self.filename + '</span>') - + except IOError as err: + err.strerror = 'Error writing CSS file: ' + err.strerror + raise + + yield 0, (DOC_HEADER_EXTERNALCSS % + dict(title=self.title, + cssfile=self.cssfile, + encoding=self.encoding)) + else: + yield 0, (DOC_HEADER % + dict(title=self.title, + styledefs=self.get_style_defs('body'), + encoding=self.encoding)) + + for t, line in inner: + yield t, line + yield 0, DOC_FOOTER + + def _wrap_tablelinenos(self, inner): + dummyoutfile = StringIO() + lncount = 0 + for t, line in inner: + if t: + lncount += 1 + dummyoutfile.write(line) + + fl = self.linenostart + mw = len(str(lncount + fl - 1)) + sp = self.linenospecial + st = self.linenostep + 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 + # subtract 1 since we have to increment i *before* yielding + i = self.linenostart - 1 + 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) + + if self.filename: + yield 0, ('<span class="filename">' + self.filename + '</span>') + # the empty span here is to keep leading empty lines from being # ignored by HTML parsers yield 0, ('<pre' + (style and ' style="%s"' % style) + '><span></span>') - for tup in inner: - yield tup - yield 0, '</pre>' - + for tup in inner: + yield tup + yield 0, '</pre>' + def _wrap_code(self, inner): yield 0, '<code>' for tup in inner: yield tup yield 0, '</code>' - 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_classes(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.extend(((lspan and '</span>'), cspan, part, - (cspan and '</span>'), lsep)) - else: # both are the same - line.extend((part, (lspan and '</span>'), lsep)) - yield 1, ''.join(line) - line = [] - elif part: - yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep)) - else: - yield 1, lsep - # for the last line - if line and parts[-1]: - if lspan != cspan: - line.extend(((lspan and '</span>'), cspan, parts[-1])) - lspan = cspan - else: - line.append(parts[-1]) - elif parts[-1]: - line = [cspan, parts[-1]] - lspan = cspan - # else we neither have to open a new span nor set lspan - - if line: - line.extend(((lspan and '</span>'), lsep)) - yield 1, ''.join(line) - - def _lookup_ctag(self, token): - entry = ctags.TagEntry() - if self._ctags.find(entry, token, 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. - """ + 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_classes(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.extend(((lspan and '</span>'), cspan, part, + (cspan and '</span>'), lsep)) + else: # both are the same + line.extend((part, (lspan and '</span>'), lsep)) + yield 1, ''.join(line) + line = [] + elif part: + yield 1, ''.join((cspan, part, (cspan and '</span>'), lsep)) + else: + yield 1, lsep + # for the last line + if line and parts[-1]: + if lspan != cspan: + line.extend(((lspan and '</span>'), cspan, parts[-1])) + lspan = cspan + else: + line.append(parts[-1]) + elif parts[-1]: + line = [cspan, parts[-1]] + lspan = cspan + # else we neither have to open a new span nor set lspan + + if line: + line.extend(((lspan and '</span>'), lsep)) + yield 1, ''.join(line) + + def _lookup_ctag(self, token): + entry = ctags.TagEntry() + if self._ctags.find(entry, token, 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. + """ if self.wrapcode: return self._wrap_div(self._wrap_pre(self._wrap_code(source))) else: 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) + + 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) diff --git a/contrib/python/Pygments/py2/pygments/formatters/img.py b/contrib/python/Pygments/py2/pygments/formatters/img.py index 95056cc54a1..6bb3364458e 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/img.py +++ b/contrib/python/Pygments/py2/pygments/formatters/img.py @@ -1,93 +1,93 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.img - ~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for Pixmap output. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.img + ~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for Pixmap output. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - + :license: BSD, see LICENSE for details. +""" + import os -import sys - -from pygments.formatter import Formatter -from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \ - get_choice_opt, xrange - -import subprocess - -# Import this carefully -try: - from PIL import Image, ImageDraw, ImageFont - pil_available = True -except ImportError: - pil_available = False - -try: - import _winreg -except ImportError: - try: - import winreg as _winreg - except ImportError: - _winreg = None - -__all__ = ['ImageFormatter', 'GifImageFormatter', 'JpgImageFormatter', - 'BmpImageFormatter'] - - -# For some unknown reason every font calls it something different -STYLES = { - 'NORMAL': ['', 'Roman', 'Book', 'Normal', 'Regular', 'Medium'], - 'ITALIC': ['Oblique', 'Italic'], - 'BOLD': ['Bold'], - 'BOLDITALIC': ['Bold Oblique', 'Bold Italic'], -} - -# A sane default for modern systems +import sys + +from pygments.formatter import Formatter +from pygments.util import get_bool_opt, get_int_opt, get_list_opt, \ + get_choice_opt, xrange + +import subprocess + +# Import this carefully +try: + from PIL import Image, ImageDraw, ImageFont + pil_available = True +except ImportError: + pil_available = False + +try: + import _winreg +except ImportError: + try: + import winreg as _winreg + except ImportError: + _winreg = None + +__all__ = ['ImageFormatter', 'GifImageFormatter', 'JpgImageFormatter', + 'BmpImageFormatter'] + + +# For some unknown reason every font calls it something different +STYLES = { + 'NORMAL': ['', 'Roman', 'Book', 'Normal', 'Regular', 'Medium'], + 'ITALIC': ['Oblique', 'Italic'], + 'BOLD': ['Bold'], + 'BOLDITALIC': ['Bold Oblique', 'Bold Italic'], +} + +# A sane default for modern systems DEFAULT_FONT_NAME_NIX = 'DejaVu Sans Mono' -DEFAULT_FONT_NAME_WIN = 'Courier New' +DEFAULT_FONT_NAME_WIN = 'Courier New' DEFAULT_FONT_NAME_MAC = 'Menlo' - - -class PilNotAvailable(ImportError): - """When Python imaging library is not available""" - - -class FontNotFound(Exception): - """When there are no usable fonts specified""" - - -class FontManager(object): - """ - Manages a set of fonts: normal, italic, bold, etc... - """ - - def __init__(self, font_name, font_size=14): - self.font_name = font_name - self.font_size = font_size - self.fonts = {} - self.encoding = None - if sys.platform.startswith('win'): - if not font_name: - self.font_name = DEFAULT_FONT_NAME_WIN - self._create_win() + + +class PilNotAvailable(ImportError): + """When Python imaging library is not available""" + + +class FontNotFound(Exception): + """When there are no usable fonts specified""" + + +class FontManager(object): + """ + Manages a set of fonts: normal, italic, bold, etc... + """ + + def __init__(self, font_name, font_size=14): + self.font_name = font_name + self.font_size = font_size + self.fonts = {} + self.encoding = None + if sys.platform.startswith('win'): + if not font_name: + self.font_name = DEFAULT_FONT_NAME_WIN + self._create_win() elif sys.platform.startswith('darwin'): if not font_name: self.font_name = DEFAULT_FONT_NAME_MAC self._create_mac() - else: - if not font_name: - self.font_name = DEFAULT_FONT_NAME_NIX - self._create_nix() - - def _get_nix_font_path(self, name, style): - proc = subprocess.Popen(['fc-list', "%s:style=%s" % (name, style), 'file'], - stdout=subprocess.PIPE, stderr=None) - stdout, _ = proc.communicate() - if proc.returncode == 0: - lines = stdout.splitlines() + else: + if not font_name: + self.font_name = DEFAULT_FONT_NAME_NIX + self._create_nix() + + def _get_nix_font_path(self, name, style): + proc = subprocess.Popen(['fc-list', "%s:style=%s" % (name, style), 'file'], + stdout=subprocess.PIPE, stderr=None) + stdout, _ = proc.communicate() + if proc.returncode == 0: + lines = stdout.splitlines() for line in lines: if line.startswith(b'Fontconfig warning:'): continue @@ -95,28 +95,28 @@ class FontManager(object): if path: return path return None - - def _create_nix(self): - for name in STYLES['NORMAL']: - path = self._get_nix_font_path(self.font_name, name) - if path is not None: - self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) - break - else: - raise FontNotFound('No usable fonts named: "%s"' % - self.font_name) - for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): - for stylename in STYLES[style]: - path = self._get_nix_font_path(self.font_name, stylename) - if path is not None: - self.fonts[style] = ImageFont.truetype(path, self.font_size) - break - else: - if style == 'BOLDITALIC': - self.fonts[style] = self.fonts['BOLD'] - else: - self.fonts[style] = self.fonts['NORMAL'] - + + def _create_nix(self): + for name in STYLES['NORMAL']: + path = self._get_nix_font_path(self.font_name, name) + if path is not None: + self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) + break + else: + raise FontNotFound('No usable fonts named: "%s"' % + self.font_name) + for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): + for stylename in STYLES[style]: + path = self._get_nix_font_path(self.font_name, stylename) + if path is not None: + self.fonts[style] = ImageFont.truetype(path, self.font_size) + break + else: + if style == 'BOLDITALIC': + self.fonts[style] = self.fonts['BOLD'] + else: + self.fonts[style] = self.fonts['NORMAL'] + def _get_mac_font_path(self, font_map, name, style): return font_map.get((name + ' ' + style).strip().lower()) @@ -148,455 +148,455 @@ class FontManager(object): else: self.fonts[style] = self.fonts['NORMAL'] - def _lookup_win(self, key, basename, styles, fail=False): - for suffix in ('', ' (TrueType)'): - for style in styles: - try: - valname = '%s%s%s' % (basename, style and ' '+style, suffix) - val, _ = _winreg.QueryValueEx(key, valname) - return val - except EnvironmentError: - continue - else: - if fail: - raise FontNotFound('Font %s (%s) not found in registry' % - (basename, styles[0])) - return None - - def _create_win(self): - try: - key = _winreg.OpenKey( - _winreg.HKEY_LOCAL_MACHINE, - r'Software\Microsoft\Windows NT\CurrentVersion\Fonts') - except EnvironmentError: - try: - key = _winreg.OpenKey( - _winreg.HKEY_LOCAL_MACHINE, - r'Software\Microsoft\Windows\CurrentVersion\Fonts') - except EnvironmentError: - raise FontNotFound('Can\'t open Windows font registry key') - try: - path = self._lookup_win(key, self.font_name, STYLES['NORMAL'], True) - self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) - for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): - path = self._lookup_win(key, self.font_name, STYLES[style]) - if path: - self.fonts[style] = ImageFont.truetype(path, self.font_size) - else: - if style == 'BOLDITALIC': - self.fonts[style] = self.fonts['BOLD'] - else: - self.fonts[style] = self.fonts['NORMAL'] - finally: - _winreg.CloseKey(key) - - def get_char_size(self): - """ - Get the character size. - """ - return self.fonts['NORMAL'].getsize('M') - - def get_font(self, bold, oblique): - """ - Get the font based on bold and italic flags. - """ - if bold and oblique: - return self.fonts['BOLDITALIC'] - elif bold: - return self.fonts['BOLD'] - elif oblique: - return self.fonts['ITALIC'] - else: - return self.fonts['NORMAL'] - - -class ImageFormatter(Formatter): - """ - Create a PNG image from source code. This uses the Python Imaging Library to - generate a pixmap from the source code. - - .. versionadded:: 0.10 - - Additional options accepted: - - `image_format` - An image format to output to that is recognised by PIL, these include: - - * "PNG" (default) - * "JPEG" - * "BMP" - * "GIF" - - `line_pad` - The extra spacing (in pixels) between each line of text. - - Default: 2 - - `font_name` - The font name to be used as the base font from which others, such as - bold and italic fonts will be generated. This really should be a - monospace font to look sane. - + def _lookup_win(self, key, basename, styles, fail=False): + for suffix in ('', ' (TrueType)'): + for style in styles: + try: + valname = '%s%s%s' % (basename, style and ' '+style, suffix) + val, _ = _winreg.QueryValueEx(key, valname) + return val + except EnvironmentError: + continue + else: + if fail: + raise FontNotFound('Font %s (%s) not found in registry' % + (basename, styles[0])) + return None + + def _create_win(self): + try: + key = _winreg.OpenKey( + _winreg.HKEY_LOCAL_MACHINE, + r'Software\Microsoft\Windows NT\CurrentVersion\Fonts') + except EnvironmentError: + try: + key = _winreg.OpenKey( + _winreg.HKEY_LOCAL_MACHINE, + r'Software\Microsoft\Windows\CurrentVersion\Fonts') + except EnvironmentError: + raise FontNotFound('Can\'t open Windows font registry key') + try: + path = self._lookup_win(key, self.font_name, STYLES['NORMAL'], True) + self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) + for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): + path = self._lookup_win(key, self.font_name, STYLES[style]) + if path: + self.fonts[style] = ImageFont.truetype(path, self.font_size) + else: + if style == 'BOLDITALIC': + self.fonts[style] = self.fonts['BOLD'] + else: + self.fonts[style] = self.fonts['NORMAL'] + finally: + _winreg.CloseKey(key) + + def get_char_size(self): + """ + Get the character size. + """ + return self.fonts['NORMAL'].getsize('M') + + def get_font(self, bold, oblique): + """ + Get the font based on bold and italic flags. + """ + if bold and oblique: + return self.fonts['BOLDITALIC'] + elif bold: + return self.fonts['BOLD'] + elif oblique: + return self.fonts['ITALIC'] + else: + return self.fonts['NORMAL'] + + +class ImageFormatter(Formatter): + """ + Create a PNG image from source code. This uses the Python Imaging Library to + generate a pixmap from the source code. + + .. versionadded:: 0.10 + + Additional options accepted: + + `image_format` + An image format to output to that is recognised by PIL, these include: + + * "PNG" (default) + * "JPEG" + * "BMP" + * "GIF" + + `line_pad` + The extra spacing (in pixels) between each line of text. + + Default: 2 + + `font_name` + The font name to be used as the base font from which others, such as + bold and italic fonts will be generated. This really should be a + monospace font to look sane. + Default: "Courier New" on Windows, "Menlo" on Mac OS, and "DejaVu Sans Mono" on \\*nix - - `font_size` - The font size in points to be used. - - Default: 14 - - `image_pad` - The padding, in pixels to be used at each edge of the resulting image. - - Default: 10 - - `line_numbers` - Whether line numbers should be shown: True/False - - Default: True - - `line_number_start` - The line number of the first line. - - Default: 1 - - `line_number_step` - The step used when printing line numbers. - - Default: 1 - - `line_number_bg` - The background colour (in "#123456" format) of the line number bar, or - None to use the style background color. - - Default: "#eed" - - `line_number_fg` - The text color of the line numbers (in "#123456"-like format). - - Default: "#886" - - `line_number_chars` - The number of columns of line numbers allowable in the line number - margin. - - Default: 2 - - `line_number_bold` - Whether line numbers will be bold: True/False - - Default: False - - `line_number_italic` - Whether line numbers will be italicized: True/False - - Default: False - - `line_number_separator` - Whether a line will be drawn between the line number area and the - source code area: True/False - - Default: True - - `line_number_pad` - The horizontal padding (in pixels) between the line number margin, and - the source code area. - - Default: 6 - - `hl_lines` - Specify a list of lines to be highlighted. - - .. versionadded:: 1.2 - - Default: empty list - - `hl_color` - Specify the color for highlighting lines. - - .. versionadded:: 1.2 - - Default: highlight color of the selected style - """ - - # Required by the pygments mapper - name = 'img' - aliases = ['img', 'IMG', 'png'] - filenames = ['*.png'] - - unicodeoutput = False - - default_image_format = 'png' - - def __init__(self, **options): - """ - See the class docstring for explanation of options. - """ - if not pil_available: - raise PilNotAvailable( - 'Python Imaging Library is required for this formatter') - Formatter.__init__(self, **options) - self.encoding = 'latin1' # let pygments.format() do the right thing - # Read the style - self.styles = dict(self.style) - if self.style.background_color is None: - self.background_color = '#fff' - else: - self.background_color = self.style.background_color - # Image options - self.image_format = get_choice_opt( - options, 'image_format', ['png', 'jpeg', 'gif', 'bmp'], - self.default_image_format, normcase=True) - self.image_pad = get_int_opt(options, 'image_pad', 10) - self.line_pad = get_int_opt(options, 'line_pad', 2) - # The fonts - fontsize = get_int_opt(options, 'font_size', 14) - self.fonts = FontManager(options.get('font_name', ''), fontsize) - self.fontw, self.fonth = self.fonts.get_char_size() - # Line number options - self.line_number_fg = options.get('line_number_fg', '#886') - self.line_number_bg = options.get('line_number_bg', '#eed') - self.line_number_chars = get_int_opt(options, - 'line_number_chars', 2) - self.line_number_bold = get_bool_opt(options, - 'line_number_bold', False) - self.line_number_italic = get_bool_opt(options, - 'line_number_italic', False) - self.line_number_pad = get_int_opt(options, 'line_number_pad', 6) - self.line_numbers = get_bool_opt(options, 'line_numbers', True) - self.line_number_separator = get_bool_opt(options, - 'line_number_separator', True) - self.line_number_step = get_int_opt(options, 'line_number_step', 1) - self.line_number_start = get_int_opt(options, 'line_number_start', 1) - if self.line_numbers: - self.line_number_width = (self.fontw * self.line_number_chars + - self.line_number_pad * 2) - else: - self.line_number_width = 0 - self.hl_lines = [] - hl_lines_str = get_list_opt(options, 'hl_lines', []) - for line in hl_lines_str: - try: - self.hl_lines.append(int(line)) - except ValueError: - pass - self.hl_color = options.get('hl_color', - self.style.highlight_color) or '#f90' - self.drawables = [] - - def get_style_defs(self, arg=''): - raise NotImplementedError('The -S option is meaningless for the image ' - 'formatter. Use -O style=<stylename> instead.') - - def _get_line_height(self): - """ - Get the height of a line. - """ - return self.fonth + self.line_pad - - def _get_line_y(self, lineno): - """ - Get the Y coordinate of a line number. - """ - return lineno * self._get_line_height() + self.image_pad - - def _get_char_width(self): - """ - Get the width of a character. - """ - return self.fontw - - def _get_char_x(self, charno): - """ - Get the X coordinate of a character position. - """ - return charno * self.fontw + self.image_pad + self.line_number_width - - def _get_text_pos(self, charno, lineno): - """ - Get the actual position for a character and line position. - """ - return self._get_char_x(charno), self._get_line_y(lineno) - - def _get_linenumber_pos(self, lineno): - """ - Get the actual position for the start of a line number. - """ - return (self.image_pad, self._get_line_y(lineno)) - - def _get_text_color(self, style): - """ - Get the correct color for the token from the style. - """ - if style['color'] is not None: - fill = '#' + style['color'] - else: - fill = '#000' - return fill - - def _get_style_font(self, style): - """ - Get the correct font for the style. - """ - return self.fonts.get_font(style['bold'], style['italic']) - - def _get_image_size(self, maxcharno, maxlineno): - """ - Get the required image size. - """ - return (self._get_char_x(maxcharno) + self.image_pad, - self._get_line_y(maxlineno + 0) + self.image_pad) - - def _draw_linenumber(self, posno, lineno): - """ - Remember a line number drawable to paint later. - """ - self._draw_text( - self._get_linenumber_pos(posno), - str(lineno).rjust(self.line_number_chars), - font=self.fonts.get_font(self.line_number_bold, - self.line_number_italic), - fill=self.line_number_fg, - ) - - def _draw_text(self, pos, text, font, **kw): - """ - Remember a single drawable tuple to paint later. - """ - self.drawables.append((pos, text, font, kw)) - - def _create_drawables(self, tokensource): - """ - Create drawables for the token content. - """ - lineno = charno = maxcharno = 0 - for ttype, value in tokensource: - while ttype not in self.styles: - ttype = ttype.parent - style = self.styles[ttype] - # TODO: make sure tab expansion happens earlier in the chain. It - # really ought to be done on the input, as to do it right here is - # quite complex. - value = value.expandtabs(4) - lines = value.splitlines(True) - # print lines - for i, line in enumerate(lines): - temp = line.rstrip('\n') - if temp: - self._draw_text( - self._get_text_pos(charno, lineno), - temp, - font = self._get_style_font(style), - fill = self._get_text_color(style) - ) - charno += len(temp) - maxcharno = max(maxcharno, charno) - if line.endswith('\n'): - # add a line for each extra line in the value - charno = 0 - lineno += 1 - self.maxcharno = maxcharno - self.maxlineno = lineno - - def _draw_line_numbers(self): - """ - Create drawables for the line numbers. - """ - if not self.line_numbers: - return - for p in xrange(self.maxlineno): - n = p + self.line_number_start - if (n % self.line_number_step) == 0: - self._draw_linenumber(p, n) - - def _paint_line_number_bg(self, im): - """ - Paint the line number background on the image. - """ - if not self.line_numbers: - return - if self.line_number_fg is None: - return - draw = ImageDraw.Draw(im) - recth = im.size[-1] - rectw = self.image_pad + self.line_number_width - self.line_number_pad - draw.rectangle([(0, 0), (rectw, recth)], - fill=self.line_number_bg) + + `font_size` + The font size in points to be used. + + Default: 14 + + `image_pad` + The padding, in pixels to be used at each edge of the resulting image. + + Default: 10 + + `line_numbers` + Whether line numbers should be shown: True/False + + Default: True + + `line_number_start` + The line number of the first line. + + Default: 1 + + `line_number_step` + The step used when printing line numbers. + + Default: 1 + + `line_number_bg` + The background colour (in "#123456" format) of the line number bar, or + None to use the style background color. + + Default: "#eed" + + `line_number_fg` + The text color of the line numbers (in "#123456"-like format). + + Default: "#886" + + `line_number_chars` + The number of columns of line numbers allowable in the line number + margin. + + Default: 2 + + `line_number_bold` + Whether line numbers will be bold: True/False + + Default: False + + `line_number_italic` + Whether line numbers will be italicized: True/False + + Default: False + + `line_number_separator` + Whether a line will be drawn between the line number area and the + source code area: True/False + + Default: True + + `line_number_pad` + The horizontal padding (in pixels) between the line number margin, and + the source code area. + + Default: 6 + + `hl_lines` + Specify a list of lines to be highlighted. + + .. versionadded:: 1.2 + + Default: empty list + + `hl_color` + Specify the color for highlighting lines. + + .. versionadded:: 1.2 + + Default: highlight color of the selected style + """ + + # Required by the pygments mapper + name = 'img' + aliases = ['img', 'IMG', 'png'] + filenames = ['*.png'] + + unicodeoutput = False + + default_image_format = 'png' + + def __init__(self, **options): + """ + See the class docstring for explanation of options. + """ + if not pil_available: + raise PilNotAvailable( + 'Python Imaging Library is required for this formatter') + Formatter.__init__(self, **options) + self.encoding = 'latin1' # let pygments.format() do the right thing + # Read the style + self.styles = dict(self.style) + if self.style.background_color is None: + self.background_color = '#fff' + else: + self.background_color = self.style.background_color + # Image options + self.image_format = get_choice_opt( + options, 'image_format', ['png', 'jpeg', 'gif', 'bmp'], + self.default_image_format, normcase=True) + self.image_pad = get_int_opt(options, 'image_pad', 10) + self.line_pad = get_int_opt(options, 'line_pad', 2) + # The fonts + fontsize = get_int_opt(options, 'font_size', 14) + self.fonts = FontManager(options.get('font_name', ''), fontsize) + self.fontw, self.fonth = self.fonts.get_char_size() + # Line number options + self.line_number_fg = options.get('line_number_fg', '#886') + self.line_number_bg = options.get('line_number_bg', '#eed') + self.line_number_chars = get_int_opt(options, + 'line_number_chars', 2) + self.line_number_bold = get_bool_opt(options, + 'line_number_bold', False) + self.line_number_italic = get_bool_opt(options, + 'line_number_italic', False) + self.line_number_pad = get_int_opt(options, 'line_number_pad', 6) + self.line_numbers = get_bool_opt(options, 'line_numbers', True) + self.line_number_separator = get_bool_opt(options, + 'line_number_separator', True) + self.line_number_step = get_int_opt(options, 'line_number_step', 1) + self.line_number_start = get_int_opt(options, 'line_number_start', 1) + if self.line_numbers: + self.line_number_width = (self.fontw * self.line_number_chars + + self.line_number_pad * 2) + else: + self.line_number_width = 0 + self.hl_lines = [] + hl_lines_str = get_list_opt(options, 'hl_lines', []) + for line in hl_lines_str: + try: + self.hl_lines.append(int(line)) + except ValueError: + pass + self.hl_color = options.get('hl_color', + self.style.highlight_color) or '#f90' + self.drawables = [] + + def get_style_defs(self, arg=''): + raise NotImplementedError('The -S option is meaningless for the image ' + 'formatter. Use -O style=<stylename> instead.') + + def _get_line_height(self): + """ + Get the height of a line. + """ + return self.fonth + self.line_pad + + def _get_line_y(self, lineno): + """ + Get the Y coordinate of a line number. + """ + return lineno * self._get_line_height() + self.image_pad + + def _get_char_width(self): + """ + Get the width of a character. + """ + return self.fontw + + def _get_char_x(self, charno): + """ + Get the X coordinate of a character position. + """ + return charno * self.fontw + self.image_pad + self.line_number_width + + def _get_text_pos(self, charno, lineno): + """ + Get the actual position for a character and line position. + """ + return self._get_char_x(charno), self._get_line_y(lineno) + + def _get_linenumber_pos(self, lineno): + """ + Get the actual position for the start of a line number. + """ + return (self.image_pad, self._get_line_y(lineno)) + + def _get_text_color(self, style): + """ + Get the correct color for the token from the style. + """ + if style['color'] is not None: + fill = '#' + style['color'] + else: + fill = '#000' + return fill + + def _get_style_font(self, style): + """ + Get the correct font for the style. + """ + return self.fonts.get_font(style['bold'], style['italic']) + + def _get_image_size(self, maxcharno, maxlineno): + """ + Get the required image size. + """ + return (self._get_char_x(maxcharno) + self.image_pad, + self._get_line_y(maxlineno + 0) + self.image_pad) + + def _draw_linenumber(self, posno, lineno): + """ + Remember a line number drawable to paint later. + """ + self._draw_text( + self._get_linenumber_pos(posno), + str(lineno).rjust(self.line_number_chars), + font=self.fonts.get_font(self.line_number_bold, + self.line_number_italic), + fill=self.line_number_fg, + ) + + def _draw_text(self, pos, text, font, **kw): + """ + Remember a single drawable tuple to paint later. + """ + self.drawables.append((pos, text, font, kw)) + + def _create_drawables(self, tokensource): + """ + Create drawables for the token content. + """ + lineno = charno = maxcharno = 0 + for ttype, value in tokensource: + while ttype not in self.styles: + ttype = ttype.parent + style = self.styles[ttype] + # TODO: make sure tab expansion happens earlier in the chain. It + # really ought to be done on the input, as to do it right here is + # quite complex. + value = value.expandtabs(4) + lines = value.splitlines(True) + # print lines + for i, line in enumerate(lines): + temp = line.rstrip('\n') + if temp: + self._draw_text( + self._get_text_pos(charno, lineno), + temp, + font = self._get_style_font(style), + fill = self._get_text_color(style) + ) + charno += len(temp) + maxcharno = max(maxcharno, charno) + if line.endswith('\n'): + # add a line for each extra line in the value + charno = 0 + lineno += 1 + self.maxcharno = maxcharno + self.maxlineno = lineno + + def _draw_line_numbers(self): + """ + Create drawables for the line numbers. + """ + if not self.line_numbers: + return + for p in xrange(self.maxlineno): + n = p + self.line_number_start + if (n % self.line_number_step) == 0: + self._draw_linenumber(p, n) + + def _paint_line_number_bg(self, im): + """ + Paint the line number background on the image. + """ + if not self.line_numbers: + return + if self.line_number_fg is None: + return + draw = ImageDraw.Draw(im) + recth = im.size[-1] + rectw = self.image_pad + self.line_number_width - self.line_number_pad + draw.rectangle([(0, 0), (rectw, recth)], + fill=self.line_number_bg) if self.line_number_separator: draw.line([(rectw, 0), (rectw, recth)], fill=self.line_number_fg) - del draw - - def format(self, tokensource, outfile): - """ - Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` - tuples and write it into ``outfile``. - - This implementation calculates where it should draw each token on the - pixmap, then calculates the required pixmap size and draws the items. - """ - self._create_drawables(tokensource) - self._draw_line_numbers() - im = Image.new( - 'RGB', - self._get_image_size(self.maxcharno, self.maxlineno), - self.background_color - ) - self._paint_line_number_bg(im) - draw = ImageDraw.Draw(im) - # Highlight - if self.hl_lines: - x = self.image_pad + self.line_number_width - self.line_number_pad + 1 - recth = self._get_line_height() - rectw = im.size[0] - x - for linenumber in self.hl_lines: - y = self._get_line_y(linenumber - 1) - draw.rectangle([(x, y), (x + rectw, y + recth)], - fill=self.hl_color) - for pos, value, font, kw in self.drawables: - draw.text(pos, value, font=font, **kw) - im.save(outfile, self.image_format.upper()) - - -# Add one formatter per format, so that the "-f gif" option gives the correct result -# when used in pygmentize. - -class GifImageFormatter(ImageFormatter): - """ - Create a GIF image from source code. This uses the Python Imaging Library to - generate a pixmap from the source code. - - .. versionadded:: 1.0 - """ - - name = 'img_gif' - aliases = ['gif'] - filenames = ['*.gif'] - default_image_format = 'gif' - - -class JpgImageFormatter(ImageFormatter): - """ - Create a JPEG image from source code. This uses the Python Imaging Library to - generate a pixmap from the source code. - - .. versionadded:: 1.0 - """ - - name = 'img_jpg' - aliases = ['jpg', 'jpeg'] - filenames = ['*.jpg'] - default_image_format = 'jpeg' - - -class BmpImageFormatter(ImageFormatter): - """ - Create a bitmap image from source code. This uses the Python Imaging Library to - generate a pixmap from the source code. - - .. versionadded:: 1.0 - """ - - name = 'img_bmp' - aliases = ['bmp', 'bitmap'] - filenames = ['*.bmp'] - default_image_format = 'bmp' + del draw + + def format(self, tokensource, outfile): + """ + Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` + tuples and write it into ``outfile``. + + This implementation calculates where it should draw each token on the + pixmap, then calculates the required pixmap size and draws the items. + """ + self._create_drawables(tokensource) + self._draw_line_numbers() + im = Image.new( + 'RGB', + self._get_image_size(self.maxcharno, self.maxlineno), + self.background_color + ) + self._paint_line_number_bg(im) + draw = ImageDraw.Draw(im) + # Highlight + if self.hl_lines: + x = self.image_pad + self.line_number_width - self.line_number_pad + 1 + recth = self._get_line_height() + rectw = im.size[0] - x + for linenumber in self.hl_lines: + y = self._get_line_y(linenumber - 1) + draw.rectangle([(x, y), (x + rectw, y + recth)], + fill=self.hl_color) + for pos, value, font, kw in self.drawables: + draw.text(pos, value, font=font, **kw) + im.save(outfile, self.image_format.upper()) + + +# Add one formatter per format, so that the "-f gif" option gives the correct result +# when used in pygmentize. + +class GifImageFormatter(ImageFormatter): + """ + Create a GIF image from source code. This uses the Python Imaging Library to + generate a pixmap from the source code. + + .. versionadded:: 1.0 + """ + + name = 'img_gif' + aliases = ['gif'] + filenames = ['*.gif'] + default_image_format = 'gif' + + +class JpgImageFormatter(ImageFormatter): + """ + Create a JPEG image from source code. This uses the Python Imaging Library to + generate a pixmap from the source code. + + .. versionadded:: 1.0 + """ + + name = 'img_jpg' + aliases = ['jpg', 'jpeg'] + filenames = ['*.jpg'] + default_image_format = 'jpeg' + + +class BmpImageFormatter(ImageFormatter): + """ + Create a bitmap image from source code. This uses the Python Imaging Library to + generate a pixmap from the source code. + + .. versionadded:: 1.0 + """ + + name = 'img_bmp' + aliases = ['bmp', 'bitmap'] + filenames = ['*.bmp'] + default_image_format = 'bmp' diff --git a/contrib/python/Pygments/py2/pygments/formatters/irc.py b/contrib/python/Pygments/py2/pygments/formatters/irc.py index 45f330f3ca1..0650492a011 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/irc.py +++ b/contrib/python/Pygments/py2/pygments/formatters/irc.py @@ -1,30 +1,30 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.irc - ~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for IRC output - +# -*- coding: utf-8 -*- +""" + pygments.formatters.irc + ~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for IRC output + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -from pygments.formatter import Formatter -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Token, Whitespace -from pygments.util import get_choice_opt - - -__all__ = ['IRCFormatter'] - - -#: Map token types to a tuple of color values for light and dark -#: backgrounds. -IRC_COLORS = { - Token: ('', ''), - + :license: BSD, see LICENSE for details. +""" + +import sys + +from pygments.formatter import Formatter +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Token, Whitespace +from pygments.util import get_choice_opt + + +__all__ = ['IRCFormatter'] + + +#: Map token types to a tuple of color values for light and dark +#: backgrounds. +IRC_COLORS = { + Token: ('', ''), + Whitespace: ('gray', 'brightblack'), Comment: ('gray', 'brightblack'), Comment.Preproc: ('cyan', 'brightcyan'), @@ -43,140 +43,140 @@ IRC_COLORS = { Name.Tag: ('brightblue', 'brightblue'), String: ('yellow', 'yellow'), Number: ('blue', 'brightblue'), - + Generic.Deleted: ('brightred', 'brightred'), Generic.Inserted: ('green', 'brightgreen'), - Generic.Heading: ('**', '**'), + Generic.Heading: ('**', '**'), Generic.Subheading: ('*magenta*', '*brightmagenta*'), Generic.Error: ('brightred', 'brightred'), - + Error: ('_brightred_', '_brightred_'), -} - - -IRC_COLOR_MAP = { - 'white': 0, - 'black': 1, +} + + +IRC_COLOR_MAP = { + 'white': 0, + 'black': 1, 'blue': 2, 'brightgreen': 3, 'brightred': 4, 'yellow': 5, 'magenta': 6, - 'orange': 7, + 'orange': 7, 'green': 7, #compat w/ ansi 'brightyellow': 8, - 'lightgreen': 9, + 'lightgreen': 9, 'brightcyan': 9, # compat w/ ansi 'cyan': 10, - 'lightblue': 11, + 'lightblue': 11, 'red': 11, # compat w/ ansi 'brightblue': 12, 'brightmagenta': 13, 'brightblack': 14, 'gray': 15, -} - -def ircformat(color, text): - if len(color) < 1: - return text - add = sub = '' - if '_' in color: # italic - add += '\x1D' - sub = '\x1D' + sub - color = color.strip('_') - if '*' in color: # bold - add += '\x02' - sub = '\x02' + sub - color = color.strip('*') - # underline (\x1F) not supported - # backgrounds (\x03FF,BB) not supported - if len(color) > 0: # actual color - may have issues with ircformat("red", "blah")+"10" type stuff - add += '\x03' + str(IRC_COLOR_MAP[color]).zfill(2) - sub = '\x03' + sub - return add + text + sub - return '<'+add+'>'+text+'</'+sub+'>' - - -class IRCFormatter(Formatter): - r""" - Format tokens with IRC color sequences - - The `get_style_defs()` method doesn't do anything special since there is - no support for common styles. - - Options accepted: - - `bg` - Set to ``"light"`` or ``"dark"`` depending on the terminal's background - (default: ``"light"``). - - `colorscheme` - A dictionary mapping token types to (lightbg, darkbg) color names or - ``None`` (default: ``None`` = use builtin colorscheme). - - `linenos` - Set to ``True`` to have line numbers in the output as well - (default: ``False`` = no line numbers). - """ - name = 'IRC' - aliases = ['irc', 'IRC'] - filenames = [] - - def __init__(self, **options): - Formatter.__init__(self, **options) - self.darkbg = get_choice_opt(options, 'bg', - ['light', 'dark'], 'light') == 'dark' - self.colorscheme = options.get('colorscheme', None) or IRC_COLORS - self.linenos = options.get('linenos', False) - self._lineno = 0 - - def _write_lineno(self, outfile): - self._lineno += 1 - outfile.write("\n%04d: " % self._lineno) - - def _format_unencoded_with_lineno(self, tokensource, outfile): - self._write_lineno(outfile) - - for ttype, value in tokensource: - if value.endswith("\n"): - self._write_lineno(outfile) - value = value[:-1] - color = self.colorscheme.get(ttype) - while color is None: - ttype = ttype[:-1] - color = self.colorscheme.get(ttype) - if color: - color = color[self.darkbg] - spl = value.split('\n') - for line in spl[:-1]: - self._write_lineno(outfile) - if line: - outfile.write(ircformat(color, line[:-1])) - if spl[-1]: - outfile.write(ircformat(color, spl[-1])) - else: - outfile.write(value) - - outfile.write("\n") - - def format_unencoded(self, tokensource, outfile): - if self.linenos: - self._format_unencoded_with_lineno(tokensource, outfile) - return - - for ttype, value in tokensource: - color = self.colorscheme.get(ttype) - while color is None: - ttype = ttype[:-1] - color = self.colorscheme.get(ttype) - if color: - color = color[self.darkbg] - spl = value.split('\n') - for line in spl[:-1]: - if line: - outfile.write(ircformat(color, line)) - outfile.write('\n') - if spl[-1]: - outfile.write(ircformat(color, spl[-1])) - else: - outfile.write(value) +} + +def ircformat(color, text): + if len(color) < 1: + return text + add = sub = '' + if '_' in color: # italic + add += '\x1D' + sub = '\x1D' + sub + color = color.strip('_') + if '*' in color: # bold + add += '\x02' + sub = '\x02' + sub + color = color.strip('*') + # underline (\x1F) not supported + # backgrounds (\x03FF,BB) not supported + if len(color) > 0: # actual color - may have issues with ircformat("red", "blah")+"10" type stuff + add += '\x03' + str(IRC_COLOR_MAP[color]).zfill(2) + sub = '\x03' + sub + return add + text + sub + return '<'+add+'>'+text+'</'+sub+'>' + + +class IRCFormatter(Formatter): + r""" + Format tokens with IRC color sequences + + The `get_style_defs()` method doesn't do anything special since there is + no support for common styles. + + Options accepted: + + `bg` + Set to ``"light"`` or ``"dark"`` depending on the terminal's background + (default: ``"light"``). + + `colorscheme` + A dictionary mapping token types to (lightbg, darkbg) color names or + ``None`` (default: ``None`` = use builtin colorscheme). + + `linenos` + Set to ``True`` to have line numbers in the output as well + (default: ``False`` = no line numbers). + """ + name = 'IRC' + aliases = ['irc', 'IRC'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.darkbg = get_choice_opt(options, 'bg', + ['light', 'dark'], 'light') == 'dark' + self.colorscheme = options.get('colorscheme', None) or IRC_COLORS + self.linenos = options.get('linenos', False) + self._lineno = 0 + + def _write_lineno(self, outfile): + self._lineno += 1 + outfile.write("\n%04d: " % self._lineno) + + def _format_unencoded_with_lineno(self, tokensource, outfile): + self._write_lineno(outfile) + + for ttype, value in tokensource: + if value.endswith("\n"): + self._write_lineno(outfile) + value = value[:-1] + color = self.colorscheme.get(ttype) + while color is None: + ttype = ttype[:-1] + color = self.colorscheme.get(ttype) + if color: + color = color[self.darkbg] + spl = value.split('\n') + for line in spl[:-1]: + self._write_lineno(outfile) + if line: + outfile.write(ircformat(color, line[:-1])) + if spl[-1]: + outfile.write(ircformat(color, spl[-1])) + else: + outfile.write(value) + + outfile.write("\n") + + def format_unencoded(self, tokensource, outfile): + if self.linenos: + self._format_unencoded_with_lineno(tokensource, outfile) + return + + for ttype, value in tokensource: + color = self.colorscheme.get(ttype) + while color is None: + ttype = ttype[:-1] + color = self.colorscheme.get(ttype) + if color: + color = color[self.darkbg] + spl = value.split('\n') + for line in spl[:-1]: + if line: + outfile.write(ircformat(color, line)) + outfile.write('\n') + if spl[-1]: + outfile.write(ircformat(color, spl[-1])) + else: + outfile.write(value) diff --git a/contrib/python/Pygments/py2/pygments/formatters/latex.py b/contrib/python/Pygments/py2/pygments/formatters/latex.py index 86c1a18d369..7f6aa9e307d 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/latex.py +++ b/contrib/python/Pygments/py2/pygments/formatters/latex.py @@ -1,418 +1,418 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.latex - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for LaTeX fancyvrb output. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.latex + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for LaTeX fancyvrb output. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from __future__ import division - -from pygments.formatter import Formatter -from pygments.lexer import Lexer -from pygments.token import Token, STANDARD_TYPES -from pygments.util import get_bool_opt, get_int_opt, StringIO, xrange, \ - iteritems - - -__all__ = ['LatexFormatter'] - - -def escape_tex(text, commandprefix): - return text.replace('\\', '\x00'). \ - replace('{', '\x01'). \ - replace('}', '\x02'). \ - replace('\x00', r'\%sZbs{}' % commandprefix). \ - replace('\x01', r'\%sZob{}' % commandprefix). \ - replace('\x02', r'\%sZcb{}' % commandprefix). \ - replace('^', r'\%sZca{}' % commandprefix). \ - replace('_', r'\%sZus{}' % commandprefix). \ - replace('&', r'\%sZam{}' % commandprefix). \ - replace('<', r'\%sZlt{}' % commandprefix). \ - replace('>', r'\%sZgt{}' % commandprefix). \ - replace('#', r'\%sZsh{}' % commandprefix). \ - replace('%', r'\%sZpc{}' % commandprefix). \ - replace('$', r'\%sZdl{}' % commandprefix). \ - replace('-', r'\%sZhy{}' % commandprefix). \ - replace("'", r'\%sZsq{}' % commandprefix). \ - replace('"', r'\%sZdq{}' % commandprefix). \ - replace('~', r'\%sZti{}' % commandprefix) - - -DOC_TEMPLATE = r''' -\documentclass{%(docclass)s} -\usepackage{fancyvrb} -\usepackage{color} -\usepackage[%(encoding)s]{inputenc} -%(preamble)s - -%(styledefs)s - -\begin{document} - -\section*{%(title)s} - -%(code)s -\end{document} -''' - -## Small explanation of the mess below :) -# -# The previous version of the LaTeX formatter just assigned a command to -# each token type defined in the current style. That obviously is -# problematic if the highlighted code is produced for a different style -# than the style commands themselves. -# -# This version works much like the HTML formatter which assigns multiple -# CSS classes to each <span> tag, from the most specific to the least -# specific token type, thus falling back to the parent token type if one -# is not defined. Here, the classes are there too and use the same short -# forms given in token.STANDARD_TYPES. -# -# Highlighted code now only uses one custom command, which by default is -# \PY and selectable by the commandprefix option (and in addition the -# escapes \PYZat, \PYZlb and \PYZrb which haven't been renamed for -# backwards compatibility purposes). -# -# \PY has two arguments: the classes, separated by +, and the text to -# render in that style. The classes are resolved into the respective -# style commands by magic, which serves to ignore unknown classes. -# -# The magic macros are: -# * \PY@it, \PY@bf, etc. are unconditionally wrapped around the text -# to render in \PY@do. Their definition determines the style. -# * \PY@reset resets \PY@it etc. to do nothing. -# * \PY@toks parses the list of classes, using magic inspired by the -# keyval package (but modified to use plusses instead of commas -# because fancyvrb redefines commas inside its environments). -# * \PY@tok processes one class, calling the \PY@tok@classname command -# if it exists. -# * \PY@tok@classname sets the \PY@it etc. to reflect the chosen style -# for its class. -# * \PY resets the style, parses the classnames and then calls \PY@do. -# -# Tip: to read this code, print it out in substituted form using e.g. -# >>> print STYLE_TEMPLATE % {'cp': 'PY'} - -STYLE_TEMPLATE = r''' -\makeatletter -\def\%(cp)s@reset{\let\%(cp)s@it=\relax \let\%(cp)s@bf=\relax%% - \let\%(cp)s@ul=\relax \let\%(cp)s@tc=\relax%% - \let\%(cp)s@bc=\relax \let\%(cp)s@ff=\relax} -\def\%(cp)s@tok#1{\csname %(cp)s@tok@#1\endcsname} -\def\%(cp)s@toks#1+{\ifx\relax#1\empty\else%% - \%(cp)s@tok{#1}\expandafter\%(cp)s@toks\fi} -\def\%(cp)s@do#1{\%(cp)s@bc{\%(cp)s@tc{\%(cp)s@ul{%% - \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}} -\def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}} - -%(styles)s - -\def\%(cp)sZbs{\char`\\} -\def\%(cp)sZus{\char`\_} -\def\%(cp)sZob{\char`\{} -\def\%(cp)sZcb{\char`\}} -\def\%(cp)sZca{\char`\^} -\def\%(cp)sZam{\char`\&} -\def\%(cp)sZlt{\char`\<} -\def\%(cp)sZgt{\char`\>} -\def\%(cp)sZsh{\char`\#} -\def\%(cp)sZpc{\char`\%%} -\def\%(cp)sZdl{\char`\$} -\def\%(cp)sZhy{\char`\-} -\def\%(cp)sZsq{\char`\'} -\def\%(cp)sZdq{\char`\"} -\def\%(cp)sZti{\char`\~} -%% for compatibility with earlier versions -\def\%(cp)sZat{@} -\def\%(cp)sZlb{[} -\def\%(cp)sZrb{]} -\makeatother -''' - - -def _get_ttype_name(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 - - -class LatexFormatter(Formatter): - r""" - Format tokens as LaTeX code. This needs the `fancyvrb` and `color` - standard packages. - - Without the `full` option, code is formatted as one ``Verbatim`` - environment, like this: - - .. sourcecode:: latex - - \begin{Verbatim}[commandchars=\\\{\}] - \PY{k}{def }\PY{n+nf}{foo}(\PY{n}{bar}): - \PY{k}{pass} - \end{Verbatim} - - The special command used here (``\PY``) and all the other macros it needs - are output by the `get_style_defs` method. - - With the `full` option, a complete LaTeX document is output, including - the command definitions in the preamble. - - The `get_style_defs()` method of a `LatexFormatter` returns a string - containing ``\def`` commands defining the macros needed inside the - ``Verbatim`` environments. - - Additional options accepted: - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). - - `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: ``''``). - - `docclass` - If the `full` option is enabled, this is the document class to use - (default: ``'article'``). - - `preamble` - If the `full` option is enabled, this can be further preamble commands, - e.g. ``\usepackage`` (default: ``''``). - - `linenos` - If set to ``True``, output line numbers (default: ``False``). - - `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. - - `verboptions` - Additional options given to the Verbatim environment (see the *fancyvrb* - docs for possible values) (default: ``''``). - - `commandprefix` - The LaTeX commands used to produce colored output are constructed - using this prefix and some letters (default: ``'PY'``). - - .. versionadded:: 0.7 - .. versionchanged:: 0.10 - The default is now ``'PY'`` instead of ``'C'``. - - `texcomments` - If set to ``True``, enables LaTeX comment lines. That is, LaTex markup - in comment tokens is not escaped so that LaTeX can render it (default: - ``False``). - - .. versionadded:: 1.2 - - `mathescape` - If set to ``True``, enables LaTeX math mode escape in comments. That - is, ``'$...$'`` inside a comment will trigger math mode (default: - ``False``). - - .. versionadded:: 1.2 - - `escapeinside` - If set to a string of length 2, enables escaping to LaTeX. Text - delimited by these 2 characters is read as LaTeX code and - typeset accordingly. It has no effect in string literals. It has - no effect in comments if `texcomments` or `mathescape` is - set. (default: ``''``). - - .. versionadded:: 2.0 - - `envname` - Allows you to pick an alternative environment name replacing Verbatim. - The alternate environment still has to support Verbatim's option syntax. - (default: ``'Verbatim'``). - - .. versionadded:: 2.0 - """ - name = 'LaTeX' - aliases = ['latex', 'tex'] - filenames = ['*.tex'] - - def __init__(self, **options): - Formatter.__init__(self, **options) - self.docclass = options.get('docclass', 'article') - self.preamble = options.get('preamble', '') - self.linenos = get_bool_opt(options, 'linenos', False) - self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) - self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) - self.verboptions = options.get('verboptions', '') - self.nobackground = get_bool_opt(options, 'nobackground', False) - self.commandprefix = options.get('commandprefix', 'PY') - self.texcomments = get_bool_opt(options, 'texcomments', False) - self.mathescape = get_bool_opt(options, 'mathescape', False) - self.escapeinside = options.get('escapeinside', '') - if len(self.escapeinside) == 2: - self.left = self.escapeinside[0] - self.right = self.escapeinside[1] - else: - self.escapeinside = '' - self.envname = options.get('envname', u'Verbatim') - - self._create_stylesheet() - - def _create_stylesheet(self): - t2n = self.ttype2name = {Token: ''} - c2d = self.cmd2def = {} - cp = self.commandprefix - - def rgbcolor(col): - if col: - return ','.join(['%.2f' % (int(col[i] + col[i + 1], 16) / 255.0) - for i in (0, 2, 4)]) - else: - return '1,1,1' - - for ttype, ndef in self.style: - name = _get_ttype_name(ttype) - cmndef = '' - if ndef['bold']: - cmndef += r'\let\$$@bf=\textbf' - if ndef['italic']: - cmndef += r'\let\$$@it=\textit' - if ndef['underline']: - cmndef += r'\let\$$@ul=\underline' - if ndef['roman']: - cmndef += r'\let\$$@ff=\textrm' - if ndef['sans']: - cmndef += r'\let\$$@ff=\textsf' - if ndef['mono']: - cmndef += r'\let\$$@ff=\textsf' - if ndef['color']: - cmndef += (r'\def\$$@tc##1{\textcolor[rgb]{%s}{##1}}' % - rgbcolor(ndef['color'])) - if ndef['border']: - cmndef += (r'\def\$$@bc##1{\setlength{\fboxsep}{0pt}' - r'\fcolorbox[rgb]{%s}{%s}{\strut ##1}}' % - (rgbcolor(ndef['border']), - rgbcolor(ndef['bgcolor']))) - elif ndef['bgcolor']: - cmndef += (r'\def\$$@bc##1{\setlength{\fboxsep}{0pt}' - r'\colorbox[rgb]{%s}{\strut ##1}}' % - rgbcolor(ndef['bgcolor'])) - if cmndef == '': - continue - cmndef = cmndef.replace('$$', cp) - t2n[ttype] = name - c2d[name] = cmndef - - def get_style_defs(self, arg=''): - """ - Return the command sequences needed to define the commands - used to format text in the verbatim environment. ``arg`` is ignored. - """ - cp = self.commandprefix - styles = [] - for name, definition in iteritems(self.cmd2def): - styles.append(r'\expandafter\def\csname %s@tok@%s\endcsname{%s}' % - (cp, name, definition)) - return STYLE_TEMPLATE % {'cp': self.commandprefix, - 'styles': '\n'.join(styles)} - - def format_unencoded(self, tokensource, outfile): - # TODO: add support for background colors - t2n = self.ttype2name - cp = self.commandprefix - - if self.full: - realoutfile = outfile - outfile = StringIO() - - outfile.write(u'\\begin{' + self.envname + u'}[commandchars=\\\\\\{\\}') - if self.linenos: - start, step = self.linenostart, self.linenostep - outfile.write(u',numbers=left' + - (start and u',firstnumber=%d' % start or u'') + - (step and u',stepnumber=%d' % step or u'')) - if self.mathescape or self.texcomments or self.escapeinside: - outfile.write(u',codes={\\catcode`\\$=3\\catcode`\\^=7\\catcode`\\_=8}') - if self.verboptions: - outfile.write(u',' + self.verboptions) - outfile.write(u']\n') - - for ttype, value in tokensource: - if ttype in Token.Comment: - if self.texcomments: - # Try to guess comment starting lexeme and escape it ... - start = value[0:1] - for i in xrange(1, len(value)): - if start[0] != value[i]: - break - start += value[i] - - value = value[len(start):] - start = escape_tex(start, cp) - - # ... but do not escape inside comment. - value = start + value - elif self.mathescape: - # Only escape parts not inside a math environment. - parts = value.split('$') - in_math = False - for i, part in enumerate(parts): - if not in_math: - parts[i] = escape_tex(part, cp) - in_math = not in_math - value = '$'.join(parts) - elif self.escapeinside: - text = value - value = '' - while text: - a, sep1, text = text.partition(self.left) - if sep1: - b, sep2, text = text.partition(self.right) - if sep2: - value += escape_tex(a, cp) + b - else: - value += escape_tex(a + sep1 + b, cp) - else: - value += escape_tex(a, cp) - else: - value = escape_tex(value, cp) - elif ttype not in Token.Escape: - value = escape_tex(value, cp) - styles = [] - while ttype is not Token: - try: - styles.append(t2n[ttype]) - except KeyError: - # not in current style - styles.append(_get_ttype_name(ttype)) - ttype = ttype.parent - styleval = '+'.join(reversed(styles)) - if styleval: - spl = value.split('\n') - for line in spl[:-1]: - if line: - outfile.write("\\%s{%s}{%s}" % (cp, styleval, line)) - outfile.write('\n') - if spl[-1]: - outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1])) - else: - outfile.write(value) - - outfile.write(u'\\end{' + self.envname + u'}\n') - - if self.full: + :license: BSD, see LICENSE for details. +""" + +from __future__ import division + +from pygments.formatter import Formatter +from pygments.lexer import Lexer +from pygments.token import Token, STANDARD_TYPES +from pygments.util import get_bool_opt, get_int_opt, StringIO, xrange, \ + iteritems + + +__all__ = ['LatexFormatter'] + + +def escape_tex(text, commandprefix): + return text.replace('\\', '\x00'). \ + replace('{', '\x01'). \ + replace('}', '\x02'). \ + replace('\x00', r'\%sZbs{}' % commandprefix). \ + replace('\x01', r'\%sZob{}' % commandprefix). \ + replace('\x02', r'\%sZcb{}' % commandprefix). \ + replace('^', r'\%sZca{}' % commandprefix). \ + replace('_', r'\%sZus{}' % commandprefix). \ + replace('&', r'\%sZam{}' % commandprefix). \ + replace('<', r'\%sZlt{}' % commandprefix). \ + replace('>', r'\%sZgt{}' % commandprefix). \ + replace('#', r'\%sZsh{}' % commandprefix). \ + replace('%', r'\%sZpc{}' % commandprefix). \ + replace('$', r'\%sZdl{}' % commandprefix). \ + replace('-', r'\%sZhy{}' % commandprefix). \ + replace("'", r'\%sZsq{}' % commandprefix). \ + replace('"', r'\%sZdq{}' % commandprefix). \ + replace('~', r'\%sZti{}' % commandprefix) + + +DOC_TEMPLATE = r''' +\documentclass{%(docclass)s} +\usepackage{fancyvrb} +\usepackage{color} +\usepackage[%(encoding)s]{inputenc} +%(preamble)s + +%(styledefs)s + +\begin{document} + +\section*{%(title)s} + +%(code)s +\end{document} +''' + +## Small explanation of the mess below :) +# +# The previous version of the LaTeX formatter just assigned a command to +# each token type defined in the current style. That obviously is +# problematic if the highlighted code is produced for a different style +# than the style commands themselves. +# +# This version works much like the HTML formatter which assigns multiple +# CSS classes to each <span> tag, from the most specific to the least +# specific token type, thus falling back to the parent token type if one +# is not defined. Here, the classes are there too and use the same short +# forms given in token.STANDARD_TYPES. +# +# Highlighted code now only uses one custom command, which by default is +# \PY and selectable by the commandprefix option (and in addition the +# escapes \PYZat, \PYZlb and \PYZrb which haven't been renamed for +# backwards compatibility purposes). +# +# \PY has two arguments: the classes, separated by +, and the text to +# render in that style. The classes are resolved into the respective +# style commands by magic, which serves to ignore unknown classes. +# +# The magic macros are: +# * \PY@it, \PY@bf, etc. are unconditionally wrapped around the text +# to render in \PY@do. Their definition determines the style. +# * \PY@reset resets \PY@it etc. to do nothing. +# * \PY@toks parses the list of classes, using magic inspired by the +# keyval package (but modified to use plusses instead of commas +# because fancyvrb redefines commas inside its environments). +# * \PY@tok processes one class, calling the \PY@tok@classname command +# if it exists. +# * \PY@tok@classname sets the \PY@it etc. to reflect the chosen style +# for its class. +# * \PY resets the style, parses the classnames and then calls \PY@do. +# +# Tip: to read this code, print it out in substituted form using e.g. +# >>> print STYLE_TEMPLATE % {'cp': 'PY'} + +STYLE_TEMPLATE = r''' +\makeatletter +\def\%(cp)s@reset{\let\%(cp)s@it=\relax \let\%(cp)s@bf=\relax%% + \let\%(cp)s@ul=\relax \let\%(cp)s@tc=\relax%% + \let\%(cp)s@bc=\relax \let\%(cp)s@ff=\relax} +\def\%(cp)s@tok#1{\csname %(cp)s@tok@#1\endcsname} +\def\%(cp)s@toks#1+{\ifx\relax#1\empty\else%% + \%(cp)s@tok{#1}\expandafter\%(cp)s@toks\fi} +\def\%(cp)s@do#1{\%(cp)s@bc{\%(cp)s@tc{\%(cp)s@ul{%% + \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}} +\def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}} + +%(styles)s + +\def\%(cp)sZbs{\char`\\} +\def\%(cp)sZus{\char`\_} +\def\%(cp)sZob{\char`\{} +\def\%(cp)sZcb{\char`\}} +\def\%(cp)sZca{\char`\^} +\def\%(cp)sZam{\char`\&} +\def\%(cp)sZlt{\char`\<} +\def\%(cp)sZgt{\char`\>} +\def\%(cp)sZsh{\char`\#} +\def\%(cp)sZpc{\char`\%%} +\def\%(cp)sZdl{\char`\$} +\def\%(cp)sZhy{\char`\-} +\def\%(cp)sZsq{\char`\'} +\def\%(cp)sZdq{\char`\"} +\def\%(cp)sZti{\char`\~} +%% for compatibility with earlier versions +\def\%(cp)sZat{@} +\def\%(cp)sZlb{[} +\def\%(cp)sZrb{]} +\makeatother +''' + + +def _get_ttype_name(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 + + +class LatexFormatter(Formatter): + r""" + Format tokens as LaTeX code. This needs the `fancyvrb` and `color` + standard packages. + + Without the `full` option, code is formatted as one ``Verbatim`` + environment, like this: + + .. sourcecode:: latex + + \begin{Verbatim}[commandchars=\\\{\}] + \PY{k}{def }\PY{n+nf}{foo}(\PY{n}{bar}): + \PY{k}{pass} + \end{Verbatim} + + The special command used here (``\PY``) and all the other macros it needs + are output by the `get_style_defs` method. + + With the `full` option, a complete LaTeX document is output, including + the command definitions in the preamble. + + The `get_style_defs()` method of a `LatexFormatter` returns a string + containing ``\def`` commands defining the macros needed inside the + ``Verbatim`` environments. + + Additional options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + + `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: ``''``). + + `docclass` + If the `full` option is enabled, this is the document class to use + (default: ``'article'``). + + `preamble` + If the `full` option is enabled, this can be further preamble commands, + e.g. ``\usepackage`` (default: ``''``). + + `linenos` + If set to ``True``, output line numbers (default: ``False``). + + `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. + + `verboptions` + Additional options given to the Verbatim environment (see the *fancyvrb* + docs for possible values) (default: ``''``). + + `commandprefix` + The LaTeX commands used to produce colored output are constructed + using this prefix and some letters (default: ``'PY'``). + + .. versionadded:: 0.7 + .. versionchanged:: 0.10 + The default is now ``'PY'`` instead of ``'C'``. + + `texcomments` + If set to ``True``, enables LaTeX comment lines. That is, LaTex markup + in comment tokens is not escaped so that LaTeX can render it (default: + ``False``). + + .. versionadded:: 1.2 + + `mathescape` + If set to ``True``, enables LaTeX math mode escape in comments. That + is, ``'$...$'`` inside a comment will trigger math mode (default: + ``False``). + + .. versionadded:: 1.2 + + `escapeinside` + If set to a string of length 2, enables escaping to LaTeX. Text + delimited by these 2 characters is read as LaTeX code and + typeset accordingly. It has no effect in string literals. It has + no effect in comments if `texcomments` or `mathescape` is + set. (default: ``''``). + + .. versionadded:: 2.0 + + `envname` + Allows you to pick an alternative environment name replacing Verbatim. + The alternate environment still has to support Verbatim's option syntax. + (default: ``'Verbatim'``). + + .. versionadded:: 2.0 + """ + name = 'LaTeX' + aliases = ['latex', 'tex'] + filenames = ['*.tex'] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.docclass = options.get('docclass', 'article') + self.preamble = options.get('preamble', '') + self.linenos = get_bool_opt(options, 'linenos', False) + self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) + self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) + self.verboptions = options.get('verboptions', '') + self.nobackground = get_bool_opt(options, 'nobackground', False) + self.commandprefix = options.get('commandprefix', 'PY') + self.texcomments = get_bool_opt(options, 'texcomments', False) + self.mathescape = get_bool_opt(options, 'mathescape', False) + self.escapeinside = options.get('escapeinside', '') + if len(self.escapeinside) == 2: + self.left = self.escapeinside[0] + self.right = self.escapeinside[1] + else: + self.escapeinside = '' + self.envname = options.get('envname', u'Verbatim') + + self._create_stylesheet() + + def _create_stylesheet(self): + t2n = self.ttype2name = {Token: ''} + c2d = self.cmd2def = {} + cp = self.commandprefix + + def rgbcolor(col): + if col: + return ','.join(['%.2f' % (int(col[i] + col[i + 1], 16) / 255.0) + for i in (0, 2, 4)]) + else: + return '1,1,1' + + for ttype, ndef in self.style: + name = _get_ttype_name(ttype) + cmndef = '' + if ndef['bold']: + cmndef += r'\let\$$@bf=\textbf' + if ndef['italic']: + cmndef += r'\let\$$@it=\textit' + if ndef['underline']: + cmndef += r'\let\$$@ul=\underline' + if ndef['roman']: + cmndef += r'\let\$$@ff=\textrm' + if ndef['sans']: + cmndef += r'\let\$$@ff=\textsf' + if ndef['mono']: + cmndef += r'\let\$$@ff=\textsf' + if ndef['color']: + cmndef += (r'\def\$$@tc##1{\textcolor[rgb]{%s}{##1}}' % + rgbcolor(ndef['color'])) + if ndef['border']: + cmndef += (r'\def\$$@bc##1{\setlength{\fboxsep}{0pt}' + r'\fcolorbox[rgb]{%s}{%s}{\strut ##1}}' % + (rgbcolor(ndef['border']), + rgbcolor(ndef['bgcolor']))) + elif ndef['bgcolor']: + cmndef += (r'\def\$$@bc##1{\setlength{\fboxsep}{0pt}' + r'\colorbox[rgb]{%s}{\strut ##1}}' % + rgbcolor(ndef['bgcolor'])) + if cmndef == '': + continue + cmndef = cmndef.replace('$$', cp) + t2n[ttype] = name + c2d[name] = cmndef + + def get_style_defs(self, arg=''): + """ + Return the command sequences needed to define the commands + used to format text in the verbatim environment. ``arg`` is ignored. + """ + cp = self.commandprefix + styles = [] + for name, definition in iteritems(self.cmd2def): + styles.append(r'\expandafter\def\csname %s@tok@%s\endcsname{%s}' % + (cp, name, definition)) + return STYLE_TEMPLATE % {'cp': self.commandprefix, + 'styles': '\n'.join(styles)} + + def format_unencoded(self, tokensource, outfile): + # TODO: add support for background colors + t2n = self.ttype2name + cp = self.commandprefix + + if self.full: + realoutfile = outfile + outfile = StringIO() + + outfile.write(u'\\begin{' + self.envname + u'}[commandchars=\\\\\\{\\}') + if self.linenos: + start, step = self.linenostart, self.linenostep + outfile.write(u',numbers=left' + + (start and u',firstnumber=%d' % start or u'') + + (step and u',stepnumber=%d' % step or u'')) + if self.mathescape or self.texcomments or self.escapeinside: + outfile.write(u',codes={\\catcode`\\$=3\\catcode`\\^=7\\catcode`\\_=8}') + if self.verboptions: + outfile.write(u',' + self.verboptions) + outfile.write(u']\n') + + for ttype, value in tokensource: + if ttype in Token.Comment: + if self.texcomments: + # Try to guess comment starting lexeme and escape it ... + start = value[0:1] + for i in xrange(1, len(value)): + if start[0] != value[i]: + break + start += value[i] + + value = value[len(start):] + start = escape_tex(start, cp) + + # ... but do not escape inside comment. + value = start + value + elif self.mathescape: + # Only escape parts not inside a math environment. + parts = value.split('$') + in_math = False + for i, part in enumerate(parts): + if not in_math: + parts[i] = escape_tex(part, cp) + in_math = not in_math + value = '$'.join(parts) + elif self.escapeinside: + text = value + value = '' + while text: + a, sep1, text = text.partition(self.left) + if sep1: + b, sep2, text = text.partition(self.right) + if sep2: + value += escape_tex(a, cp) + b + else: + value += escape_tex(a + sep1 + b, cp) + else: + value += escape_tex(a, cp) + else: + value = escape_tex(value, cp) + elif ttype not in Token.Escape: + value = escape_tex(value, cp) + styles = [] + while ttype is not Token: + try: + styles.append(t2n[ttype]) + except KeyError: + # not in current style + styles.append(_get_ttype_name(ttype)) + ttype = ttype.parent + styleval = '+'.join(reversed(styles)) + if styleval: + spl = value.split('\n') + for line in spl[:-1]: + if line: + outfile.write("\\%s{%s}{%s}" % (cp, styleval, line)) + outfile.write('\n') + if spl[-1]: + outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1])) + else: + outfile.write(value) + + outfile.write(u'\\end{' + self.envname + u'}\n') + + if self.full: encoding = self.encoding or 'utf8' # map known existings encodings from LaTeX distribution encoding = { @@ -420,63 +420,63 @@ class LatexFormatter(Formatter): 'latin_1': 'latin1', 'iso_8859_1': 'latin1', }.get(encoding.replace('-', '_'), encoding) - realoutfile.write(DOC_TEMPLATE % - dict(docclass = self.docclass, - preamble = self.preamble, - title = self.title, + realoutfile.write(DOC_TEMPLATE % + dict(docclass = self.docclass, + preamble = self.preamble, + title = self.title, encoding = encoding, - styledefs = self.get_style_defs(), - code = outfile.getvalue())) - - -class LatexEmbeddedLexer(Lexer): - """ - This lexer takes one lexer as argument, the lexer for the language - being formatted, and the left and right delimiters for escaped text. - - First everything is scanned using the language lexer to obtain - strings and comments. All other consecutive tokens are merged and - the resulting text is scanned for escaped segments, which are given - the Token.Escape type. Finally text that is not escaped is scanned - again with the language lexer. - """ - def __init__(self, left, right, lang, **options): - self.left = left - self.right = right - self.lang = lang - Lexer.__init__(self, **options) - - def get_tokens_unprocessed(self, text): - buf = '' - idx = 0 - for i, t, v in self.lang.get_tokens_unprocessed(text): - if t in Token.Comment or t in Token.String: - if buf: - for x in self.get_tokens_aux(idx, buf): - yield x - buf = '' - yield i, t, v - else: - if not buf: - idx = i - buf += v - if buf: - for x in self.get_tokens_aux(idx, buf): - yield x - - def get_tokens_aux(self, index, text): - while text: - a, sep1, text = text.partition(self.left) - if a: - for i, t, v in self.lang.get_tokens_unprocessed(a): - yield index + i, t, v - index += len(a) - if sep1: - b, sep2, text = text.partition(self.right) - if sep2: - yield index + len(sep1), Token.Escape, b - index += len(sep1) + len(b) + len(sep2) - else: - yield index, Token.Error, sep1 - index += len(sep1) - text = b + styledefs = self.get_style_defs(), + code = outfile.getvalue())) + + +class LatexEmbeddedLexer(Lexer): + """ + This lexer takes one lexer as argument, the lexer for the language + being formatted, and the left and right delimiters for escaped text. + + First everything is scanned using the language lexer to obtain + strings and comments. All other consecutive tokens are merged and + the resulting text is scanned for escaped segments, which are given + the Token.Escape type. Finally text that is not escaped is scanned + again with the language lexer. + """ + def __init__(self, left, right, lang, **options): + self.left = left + self.right = right + self.lang = lang + Lexer.__init__(self, **options) + + def get_tokens_unprocessed(self, text): + buf = '' + idx = 0 + for i, t, v in self.lang.get_tokens_unprocessed(text): + if t in Token.Comment or t in Token.String: + if buf: + for x in self.get_tokens_aux(idx, buf): + yield x + buf = '' + yield i, t, v + else: + if not buf: + idx = i + buf += v + if buf: + for x in self.get_tokens_aux(idx, buf): + yield x + + def get_tokens_aux(self, index, text): + while text: + a, sep1, text = text.partition(self.left) + if a: + for i, t, v in self.lang.get_tokens_unprocessed(a): + yield index + i, t, v + index += len(a) + if sep1: + b, sep2, text = text.partition(self.right) + if sep2: + yield index + len(sep1), Token.Escape, b + index += len(sep1) + len(b) + len(sep2) + else: + yield index, Token.Error, sep1 + index += len(sep1) + text = b diff --git a/contrib/python/Pygments/py2/pygments/formatters/other.py b/contrib/python/Pygments/py2/pygments/formatters/other.py index c85cf6e26f3..c09eff0cb44 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/other.py +++ b/contrib/python/Pygments/py2/pygments/formatters/other.py @@ -1,164 +1,164 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.other - ~~~~~~~~~~~~~~~~~~~~~~~~~ - - Other formatters: NullFormatter, RawTokenFormatter. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.other + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + Other formatters: NullFormatter, RawTokenFormatter. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from pygments.formatter import Formatter + :license: BSD, see LICENSE for details. +""" + +from pygments.formatter import Formatter from pygments.util import get_choice_opt -from pygments.token import Token -from pygments.console import colorize - -__all__ = ['NullFormatter', 'RawTokenFormatter', 'TestcaseFormatter'] - - -class NullFormatter(Formatter): - """ - Output the text unchanged without any formatting. - """ - name = 'Text only' - aliases = ['text', 'null'] - filenames = ['*.txt'] - - def format(self, tokensource, outfile): - enc = self.encoding - for ttype, value in tokensource: - if enc: - outfile.write(value.encode(enc)) - else: - outfile.write(value) - - -class RawTokenFormatter(Formatter): - r""" - Format tokens as a raw representation for storing token streams. - - The format is ``tokentype<TAB>repr(tokenstring)\n``. The output can later - be converted to a token stream with the `RawTokenLexer`, described in the - :doc:`lexer list <lexers>`. - - Only two options are accepted: - - `compress` - If set to ``'gz'`` or ``'bz2'``, compress the output with the given - compression algorithm after encoding (default: ``''``). - `error_color` - If set to a color name, highlight error tokens using that color. If - set but with no value, defaults to ``'red'``. - - .. versionadded:: 0.11 - - """ - name = 'Raw tokens' - aliases = ['raw', 'tokens'] - filenames = ['*.raw'] - - unicodeoutput = False - - def __init__(self, **options): - Formatter.__init__(self, **options) - # We ignore self.encoding if it is set, since it gets set for lexer - # and formatter if given with -Oencoding on the command line. - # The RawTokenFormatter outputs only ASCII. Override here. - self.encoding = 'ascii' # let pygments.format() do the right thing - self.compress = get_choice_opt(options, 'compress', - ['', 'none', 'gz', 'bz2'], '') - self.error_color = options.get('error_color', None) - if self.error_color is True: - self.error_color = 'red' - if self.error_color is not None: - try: - colorize(self.error_color, '') - except KeyError: - raise ValueError("Invalid color %r specified" % - self.error_color) - - def format(self, tokensource, outfile): - try: - outfile.write(b'') - except TypeError: - raise TypeError('The raw tokens formatter needs a binary ' - 'output file') - if self.compress == 'gz': - import gzip - outfile = gzip.GzipFile('', 'wb', 9, outfile) - - def write(text): - outfile.write(text.encode()) - flush = outfile.flush - elif self.compress == 'bz2': - import bz2 - compressor = bz2.BZ2Compressor(9) - - def write(text): - outfile.write(compressor.compress(text.encode())) - - def flush(): - outfile.write(compressor.flush()) - outfile.flush() - else: - def write(text): - outfile.write(text.encode()) - flush = outfile.flush - - if self.error_color: - for ttype, value in tokensource: - line = "%s\t%r\n" % (ttype, value) - if ttype is Token.Error: - write(colorize(self.error_color, line)) - else: - write(line) - else: - for ttype, value in tokensource: - write("%s\t%r\n" % (ttype, value)) - flush() - - -TESTCASE_BEFORE = u'''\ +from pygments.token import Token +from pygments.console import colorize + +__all__ = ['NullFormatter', 'RawTokenFormatter', 'TestcaseFormatter'] + + +class NullFormatter(Formatter): + """ + Output the text unchanged without any formatting. + """ + name = 'Text only' + aliases = ['text', 'null'] + filenames = ['*.txt'] + + def format(self, tokensource, outfile): + enc = self.encoding + for ttype, value in tokensource: + if enc: + outfile.write(value.encode(enc)) + else: + outfile.write(value) + + +class RawTokenFormatter(Formatter): + r""" + Format tokens as a raw representation for storing token streams. + + The format is ``tokentype<TAB>repr(tokenstring)\n``. The output can later + be converted to a token stream with the `RawTokenLexer`, described in the + :doc:`lexer list <lexers>`. + + Only two options are accepted: + + `compress` + If set to ``'gz'`` or ``'bz2'``, compress the output with the given + compression algorithm after encoding (default: ``''``). + `error_color` + If set to a color name, highlight error tokens using that color. If + set but with no value, defaults to ``'red'``. + + .. versionadded:: 0.11 + + """ + name = 'Raw tokens' + aliases = ['raw', 'tokens'] + filenames = ['*.raw'] + + unicodeoutput = False + + def __init__(self, **options): + Formatter.__init__(self, **options) + # We ignore self.encoding if it is set, since it gets set for lexer + # and formatter if given with -Oencoding on the command line. + # The RawTokenFormatter outputs only ASCII. Override here. + self.encoding = 'ascii' # let pygments.format() do the right thing + self.compress = get_choice_opt(options, 'compress', + ['', 'none', 'gz', 'bz2'], '') + self.error_color = options.get('error_color', None) + if self.error_color is True: + self.error_color = 'red' + if self.error_color is not None: + try: + colorize(self.error_color, '') + except KeyError: + raise ValueError("Invalid color %r specified" % + self.error_color) + + def format(self, tokensource, outfile): + try: + outfile.write(b'') + except TypeError: + raise TypeError('The raw tokens formatter needs a binary ' + 'output file') + if self.compress == 'gz': + import gzip + outfile = gzip.GzipFile('', 'wb', 9, outfile) + + def write(text): + outfile.write(text.encode()) + flush = outfile.flush + elif self.compress == 'bz2': + import bz2 + compressor = bz2.BZ2Compressor(9) + + def write(text): + outfile.write(compressor.compress(text.encode())) + + def flush(): + outfile.write(compressor.flush()) + outfile.flush() + else: + def write(text): + outfile.write(text.encode()) + flush = outfile.flush + + if self.error_color: + for ttype, value in tokensource: + line = "%s\t%r\n" % (ttype, value) + if ttype is Token.Error: + write(colorize(self.error_color, line)) + else: + write(line) + else: + for ttype, value in tokensource: + write("%s\t%r\n" % (ttype, value)) + flush() + + +TESTCASE_BEFORE = u'''\ def testNeedsName(lexer): - fragment = %r - tokens = [ -''' -TESTCASE_AFTER = u'''\ - ] + fragment = %r + tokens = [ +''' +TESTCASE_AFTER = u'''\ + ] assert list(lexer.get_tokens(fragment)) == tokens -''' - - -class TestcaseFormatter(Formatter): - """ - Format tokens as appropriate for a new testcase. - - .. versionadded:: 2.0 - """ - name = 'Testcase' - aliases = ['testcase'] - - def __init__(self, **options): - Formatter.__init__(self, **options) - if self.encoding is not None and self.encoding != 'utf-8': - raise ValueError("Only None and utf-8 are allowed encodings.") - - def format(self, tokensource, outfile): - indentation = ' ' * 12 - rawbuf = [] - outbuf = [] - for ttype, value in tokensource: - rawbuf.append(value) - outbuf.append('%s(%s, %r),\n' % (indentation, ttype, value)) - - before = TESTCASE_BEFORE % (u''.join(rawbuf),) - during = u''.join(outbuf) - after = TESTCASE_AFTER - if self.encoding is None: - outfile.write(before + during + after) - else: - outfile.write(before.encode('utf-8')) - outfile.write(during.encode('utf-8')) - outfile.write(after.encode('utf-8')) - outfile.flush() +''' + + +class TestcaseFormatter(Formatter): + """ + Format tokens as appropriate for a new testcase. + + .. versionadded:: 2.0 + """ + name = 'Testcase' + aliases = ['testcase'] + + def __init__(self, **options): + Formatter.__init__(self, **options) + if self.encoding is not None and self.encoding != 'utf-8': + raise ValueError("Only None and utf-8 are allowed encodings.") + + def format(self, tokensource, outfile): + indentation = ' ' * 12 + rawbuf = [] + outbuf = [] + for ttype, value in tokensource: + rawbuf.append(value) + outbuf.append('%s(%s, %r),\n' % (indentation, ttype, value)) + + before = TESTCASE_BEFORE % (u''.join(rawbuf),) + during = u''.join(outbuf) + after = TESTCASE_AFTER + if self.encoding is None: + outfile.write(before + during + after) + else: + outfile.write(before.encode('utf-8')) + outfile.write(during.encode('utf-8')) + outfile.write(after.encode('utf-8')) + outfile.flush() diff --git a/contrib/python/Pygments/py2/pygments/formatters/rtf.py b/contrib/python/Pygments/py2/pygments/formatters/rtf.py index 13eced3e300..1246db2a734 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/rtf.py +++ b/contrib/python/Pygments/py2/pygments/formatters/rtf.py @@ -1,147 +1,147 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.rtf - ~~~~~~~~~~~~~~~~~~~~~~~ - - A formatter that generates RTF files. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.rtf + ~~~~~~~~~~~~~~~~~~~~~~~ + + A formatter that generates RTF files. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from pygments.formatter import Formatter -from pygments.util import get_int_opt, _surrogatepair - - -__all__ = ['RtfFormatter'] - - -class RtfFormatter(Formatter): - """ - Format tokens as RTF markup. This formatter automatically outputs full RTF - documents with color information and other useful stuff. Perfect for Copy and - Paste into Microsoft(R) Word(R) documents. - - Please note that ``encoding`` and ``outencoding`` options are ignored. - The RTF format is ASCII natively, but handles unicode characters correctly - thanks to escape sequences. - - .. versionadded:: 0.6 - - Additional options accepted: - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). - - `fontface` + :license: BSD, see LICENSE for details. +""" + +from pygments.formatter import Formatter +from pygments.util import get_int_opt, _surrogatepair + + +__all__ = ['RtfFormatter'] + + +class RtfFormatter(Formatter): + """ + Format tokens as RTF markup. This formatter automatically outputs full RTF + documents with color information and other useful stuff. Perfect for Copy and + Paste into Microsoft(R) Word(R) documents. + + Please note that ``encoding`` and ``outencoding`` options are ignored. + The RTF format is ASCII natively, but handles unicode characters correctly + thanks to escape sequences. + + .. versionadded:: 0.6 + + Additional options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + + `fontface` The used font family, for example ``Bitstream Vera Sans``. Defaults to - some generic font which is supposed to have fixed width. - - `fontsize` - Size of the font used. Size is specified in half points. The - default is 24 half-points, giving a size 12 font. - - .. versionadded:: 2.0 - """ - name = 'RTF' - aliases = ['rtf'] - filenames = ['*.rtf'] - - def __init__(self, **options): - r""" - Additional options accepted: - - ``fontface`` - Name of the font used. Could for example be ``'Courier New'`` - to further specify the default which is ``'\fmodern'``. The RTF - specification claims that ``\fmodern`` are "Fixed-pitch serif - and sans serif fonts". Hope every RTF implementation thinks - the same about modern... - - """ - Formatter.__init__(self, **options) - self.fontface = options.get('fontface') or '' - self.fontsize = get_int_opt(options, 'fontsize', 0) - - def _escape(self, text): - return text.replace(u'\\', u'\\\\') \ - .replace(u'{', u'\\{') \ - .replace(u'}', u'\\}') - - def _escape_text(self, text): + some generic font which is supposed to have fixed width. + + `fontsize` + Size of the font used. Size is specified in half points. The + default is 24 half-points, giving a size 12 font. + + .. versionadded:: 2.0 + """ + name = 'RTF' + aliases = ['rtf'] + filenames = ['*.rtf'] + + def __init__(self, **options): + r""" + Additional options accepted: + + ``fontface`` + Name of the font used. Could for example be ``'Courier New'`` + to further specify the default which is ``'\fmodern'``. The RTF + specification claims that ``\fmodern`` are "Fixed-pitch serif + and sans serif fonts". Hope every RTF implementation thinks + the same about modern... + + """ + Formatter.__init__(self, **options) + self.fontface = options.get('fontface') or '' + self.fontsize = get_int_opt(options, 'fontsize', 0) + + def _escape(self, text): + return text.replace(u'\\', u'\\\\') \ + .replace(u'{', u'\\{') \ + .replace(u'}', u'\\}') + + def _escape_text(self, text): # empty strings, should give a small performance improvement - if not text: - return u'' - - # escape text - text = self._escape(text) - - buf = [] - for c in text: - cn = ord(c) - if cn < (2**7): - # ASCII character - buf.append(str(c)) - elif (2**7) <= cn < (2**16): - # single unicode escape sequence - buf.append(u'{\\u%d}' % cn) - elif (2**16) <= cn: - # RTF limits unicode to 16 bits. - # Force surrogate pairs - buf.append(u'{\\u%d}{\\u%d}' % _surrogatepair(cn)) - - return u''.join(buf).replace(u'\n', u'\\par\n') - - def format_unencoded(self, tokensource, outfile): - # rtf 1.8 header - outfile.write(u'{\\rtf1\\ansi\\uc0\\deff0' - u'{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset0%s;}}' - u'{\\colortbl;' % (self.fontface and - u' ' + self._escape(self.fontface) or - u'')) - - # convert colors and save them in a mapping to access them later. - color_mapping = {} - offset = 1 - for _, style in self.style: - for color in style['color'], style['bgcolor'], style['border']: - if color and color not in color_mapping: - color_mapping[color] = offset - outfile.write(u'\\red%d\\green%d\\blue%d;' % ( - int(color[0:2], 16), - int(color[2:4], 16), - int(color[4:6], 16) - )) - offset += 1 - outfile.write(u'}\\f0 ') - if self.fontsize: - outfile.write(u'\\fs%d' % (self.fontsize)) - - # highlight stream - for ttype, value in tokensource: - while not self.style.styles_token(ttype) and ttype.parent: - ttype = ttype.parent - style = self.style.style_for_token(ttype) - buf = [] - if style['bgcolor']: - buf.append(u'\\cb%d' % color_mapping[style['bgcolor']]) - if style['color']: - buf.append(u'\\cf%d' % color_mapping[style['color']]) - if style['bold']: - buf.append(u'\\b') - if style['italic']: - buf.append(u'\\i') - if style['underline']: - buf.append(u'\\ul') - if style['border']: - buf.append(u'\\chbrdr\\chcfpat%d' % - color_mapping[style['border']]) - start = u''.join(buf) - if start: - outfile.write(u'{%s ' % start) - outfile.write(self._escape_text(value)) - if start: - outfile.write(u'}') - - outfile.write(u'}') + if not text: + return u'' + + # escape text + text = self._escape(text) + + buf = [] + for c in text: + cn = ord(c) + if cn < (2**7): + # ASCII character + buf.append(str(c)) + elif (2**7) <= cn < (2**16): + # single unicode escape sequence + buf.append(u'{\\u%d}' % cn) + elif (2**16) <= cn: + # RTF limits unicode to 16 bits. + # Force surrogate pairs + buf.append(u'{\\u%d}{\\u%d}' % _surrogatepair(cn)) + + return u''.join(buf).replace(u'\n', u'\\par\n') + + def format_unencoded(self, tokensource, outfile): + # rtf 1.8 header + outfile.write(u'{\\rtf1\\ansi\\uc0\\deff0' + u'{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset0%s;}}' + u'{\\colortbl;' % (self.fontface and + u' ' + self._escape(self.fontface) or + u'')) + + # convert colors and save them in a mapping to access them later. + color_mapping = {} + offset = 1 + for _, style in self.style: + for color in style['color'], style['bgcolor'], style['border']: + if color and color not in color_mapping: + color_mapping[color] = offset + outfile.write(u'\\red%d\\green%d\\blue%d;' % ( + int(color[0:2], 16), + int(color[2:4], 16), + int(color[4:6], 16) + )) + offset += 1 + outfile.write(u'}\\f0 ') + if self.fontsize: + outfile.write(u'\\fs%d' % (self.fontsize)) + + # highlight stream + for ttype, value in tokensource: + while not self.style.styles_token(ttype) and ttype.parent: + ttype = ttype.parent + style = self.style.style_for_token(ttype) + buf = [] + if style['bgcolor']: + buf.append(u'\\cb%d' % color_mapping[style['bgcolor']]) + if style['color']: + buf.append(u'\\cf%d' % color_mapping[style['color']]) + if style['bold']: + buf.append(u'\\b') + if style['italic']: + buf.append(u'\\i') + if style['underline']: + buf.append(u'\\ul') + if style['border']: + buf.append(u'\\chbrdr\\chcfpat%d' % + color_mapping[style['border']]) + start = u''.join(buf) + if start: + outfile.write(u'{%s ' % start) + outfile.write(self._escape_text(value)) + if start: + outfile.write(u'}') + + outfile.write(u'}') diff --git a/contrib/python/Pygments/py2/pygments/formatters/svg.py b/contrib/python/Pygments/py2/pygments/formatters/svg.py index 6125a403f50..ccfd2b3fffd 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/svg.py +++ b/contrib/python/Pygments/py2/pygments/formatters/svg.py @@ -1,153 +1,153 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.svg - ~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for SVG output. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.svg + ~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for SVG output. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -from pygments.formatter import Formatter -from pygments.util import get_bool_opt, get_int_opt - -__all__ = ['SvgFormatter'] - - -def escape_html(text): - """Escape &, <, > as well as single and double quotes for HTML.""" - return text.replace('&', '&'). \ - replace('<', '<'). \ - replace('>', '>'). \ - replace('"', '"'). \ - replace("'", ''') - - -class2style = {} - -class SvgFormatter(Formatter): - """ - Format tokens as an SVG graphics file. This formatter is still experimental. - Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` - coordinates containing ``<tspan>`` elements with the individual token styles. - - By default, this formatter outputs a full SVG document including doctype - declaration and the ``<svg>`` root element. - - .. versionadded:: 0.9 - - Additional options accepted: - - `nowrap` - Don't wrap the SVG ``<text>`` elements in ``<svg><g>`` elements and - don't add a XML declaration and a doctype. If true, the `fontfamily` - and `fontsize` options are ignored. Defaults to ``False``. - - `fontfamily` - The value to give the wrapping ``<g>`` element's ``font-family`` - attribute, defaults to ``"monospace"``. - - `fontsize` - The value to give the wrapping ``<g>`` element's ``font-size`` - attribute, defaults to ``"14px"``. - - `xoffset` - Starting offset in X direction, defaults to ``0``. - - `yoffset` - Starting offset in Y direction, defaults to the font size if it is given - in pixels, or ``20`` else. (This is necessary since text coordinates - refer to the text baseline, not the top edge.) - - `ystep` - Offset to add to the Y coordinate for each subsequent line. This should - roughly be the text size plus 5. It defaults to that value if the text - size is given in pixels, or ``25`` else. - - `spacehack` - Convert spaces in the source to `` ``, which are non-breaking - spaces. SVG provides the ``xml:space`` attribute to control how - whitespace inside tags is handled, in theory, the ``preserve`` value - could be used to keep all whitespace as-is. However, many current SVG - viewers don't obey that rule, so this option is provided as a workaround - and defaults to ``True``. - """ - name = 'SVG' - aliases = ['svg'] - filenames = ['*.svg'] - - def __init__(self, **options): - Formatter.__init__(self, **options) - self.nowrap = get_bool_opt(options, 'nowrap', False) - self.fontfamily = options.get('fontfamily', 'monospace') - self.fontsize = options.get('fontsize', '14px') - self.xoffset = get_int_opt(options, 'xoffset', 0) - fs = self.fontsize.strip() - if fs.endswith('px'): fs = fs[:-2].strip() - try: - int_fs = int(fs) - except: - int_fs = 20 - self.yoffset = get_int_opt(options, 'yoffset', int_fs) - self.ystep = get_int_opt(options, 'ystep', int_fs + 5) - self.spacehack = get_bool_opt(options, 'spacehack', True) - self._stylecache = {} - - def format_unencoded(self, tokensource, outfile): - """ - Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` - tuples and write it into ``outfile``. - - For our implementation we put all lines in their own 'line group'. - """ - x = self.xoffset - y = self.yoffset - if not self.nowrap: - if self.encoding: - outfile.write('<?xml version="1.0" encoding="%s"?>\n' % - self.encoding) - else: - outfile.write('<?xml version="1.0"?>\n') - outfile.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" ' - '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/' - 'svg10.dtd">\n') - outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n') - outfile.write('<g font-family="%s" font-size="%s">\n' % - (self.fontfamily, self.fontsize)) - outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (x, y)) - for ttype, value in tokensource: - style = self._get_style(ttype) - tspan = style and '<tspan' + style + '>' or '' - tspanend = tspan and '</tspan>' or '' - value = escape_html(value) - if self.spacehack: - value = value.expandtabs().replace(' ', ' ') - parts = value.split('\n') - for part in parts[:-1]: - outfile.write(tspan + part + tspanend) - y += self.ystep - outfile.write('</text>\n<text x="%s" y="%s" ' - 'xml:space="preserve">' % (x, y)) - outfile.write(tspan + parts[-1] + tspanend) - outfile.write('</text>') - - if not self.nowrap: - outfile.write('</g></svg>\n') - - def _get_style(self, tokentype): - if tokentype in self._stylecache: - return self._stylecache[tokentype] - otokentype = tokentype - while not self.style.styles_token(tokentype): - tokentype = tokentype.parent - value = self.style.style_for_token(tokentype) - result = '' - if value['color']: - result = ' fill="#' + value['color'] + '"' - if value['bold']: - result += ' font-weight="bold"' - if value['italic']: - result += ' font-style="italic"' - self._stylecache[otokentype] = result - return result + :license: BSD, see LICENSE for details. +""" + +from pygments.formatter import Formatter +from pygments.util import get_bool_opt, get_int_opt + +__all__ = ['SvgFormatter'] + + +def escape_html(text): + """Escape &, <, > as well as single and double quotes for HTML.""" + return text.replace('&', '&'). \ + replace('<', '<'). \ + replace('>', '>'). \ + replace('"', '"'). \ + replace("'", ''') + + +class2style = {} + +class SvgFormatter(Formatter): + """ + Format tokens as an SVG graphics file. This formatter is still experimental. + Each line of code is a ``<text>`` element with explicit ``x`` and ``y`` + coordinates containing ``<tspan>`` elements with the individual token styles. + + By default, this formatter outputs a full SVG document including doctype + declaration and the ``<svg>`` root element. + + .. versionadded:: 0.9 + + Additional options accepted: + + `nowrap` + Don't wrap the SVG ``<text>`` elements in ``<svg><g>`` elements and + don't add a XML declaration and a doctype. If true, the `fontfamily` + and `fontsize` options are ignored. Defaults to ``False``. + + `fontfamily` + The value to give the wrapping ``<g>`` element's ``font-family`` + attribute, defaults to ``"monospace"``. + + `fontsize` + The value to give the wrapping ``<g>`` element's ``font-size`` + attribute, defaults to ``"14px"``. + + `xoffset` + Starting offset in X direction, defaults to ``0``. + + `yoffset` + Starting offset in Y direction, defaults to the font size if it is given + in pixels, or ``20`` else. (This is necessary since text coordinates + refer to the text baseline, not the top edge.) + + `ystep` + Offset to add to the Y coordinate for each subsequent line. This should + roughly be the text size plus 5. It defaults to that value if the text + size is given in pixels, or ``25`` else. + + `spacehack` + Convert spaces in the source to `` ``, which are non-breaking + spaces. SVG provides the ``xml:space`` attribute to control how + whitespace inside tags is handled, in theory, the ``preserve`` value + could be used to keep all whitespace as-is. However, many current SVG + viewers don't obey that rule, so this option is provided as a workaround + and defaults to ``True``. + """ + name = 'SVG' + aliases = ['svg'] + filenames = ['*.svg'] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.nowrap = get_bool_opt(options, 'nowrap', False) + self.fontfamily = options.get('fontfamily', 'monospace') + self.fontsize = options.get('fontsize', '14px') + self.xoffset = get_int_opt(options, 'xoffset', 0) + fs = self.fontsize.strip() + if fs.endswith('px'): fs = fs[:-2].strip() + try: + int_fs = int(fs) + except: + int_fs = 20 + self.yoffset = get_int_opt(options, 'yoffset', int_fs) + self.ystep = get_int_opt(options, 'ystep', int_fs + 5) + self.spacehack = get_bool_opt(options, 'spacehack', True) + self._stylecache = {} + + def format_unencoded(self, tokensource, outfile): + """ + Format ``tokensource``, an iterable of ``(tokentype, tokenstring)`` + tuples and write it into ``outfile``. + + For our implementation we put all lines in their own 'line group'. + """ + x = self.xoffset + y = self.yoffset + if not self.nowrap: + if self.encoding: + outfile.write('<?xml version="1.0" encoding="%s"?>\n' % + self.encoding) + else: + outfile.write('<?xml version="1.0"?>\n') + outfile.write('<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.0//EN" ' + '"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/' + 'svg10.dtd">\n') + outfile.write('<svg xmlns="http://www.w3.org/2000/svg">\n') + outfile.write('<g font-family="%s" font-size="%s">\n' % + (self.fontfamily, self.fontsize)) + outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (x, y)) + for ttype, value in tokensource: + style = self._get_style(ttype) + tspan = style and '<tspan' + style + '>' or '' + tspanend = tspan and '</tspan>' or '' + value = escape_html(value) + if self.spacehack: + value = value.expandtabs().replace(' ', ' ') + parts = value.split('\n') + for part in parts[:-1]: + outfile.write(tspan + part + tspanend) + y += self.ystep + outfile.write('</text>\n<text x="%s" y="%s" ' + 'xml:space="preserve">' % (x, y)) + outfile.write(tspan + parts[-1] + tspanend) + outfile.write('</text>') + + if not self.nowrap: + outfile.write('</g></svg>\n') + + def _get_style(self, tokentype): + if tokentype in self._stylecache: + return self._stylecache[tokentype] + otokentype = tokentype + while not self.style.styles_token(tokentype): + tokentype = tokentype.parent + value = self.style.style_for_token(tokentype) + result = '' + if value['color']: + result = ' fill="#' + value['color'] + '"' + if value['bold']: + result += ' font-weight="bold"' + if value['italic']: + result += ' font-style="italic"' + self._stylecache[otokentype] = result + return result diff --git a/contrib/python/Pygments/py2/pygments/formatters/terminal.py b/contrib/python/Pygments/py2/pygments/formatters/terminal.py index a9749e25e72..e60bde912fd 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/terminal.py +++ b/contrib/python/Pygments/py2/pygments/formatters/terminal.py @@ -1,31 +1,31 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.terminal - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for terminal output with ANSI sequences. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.terminal + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for terminal output with ANSI sequences. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -import sys - -from pygments.formatter import Formatter -from pygments.token import Keyword, Name, Comment, String, Error, \ - Number, Operator, Generic, Token, Whitespace -from pygments.console import ansiformat -from pygments.util import get_choice_opt - - -__all__ = ['TerminalFormatter'] - - -#: Map token types to a tuple of color values for light and dark -#: backgrounds. -TERMINAL_COLORS = { - Token: ('', ''), - + :license: BSD, see LICENSE for details. +""" + +import sys + +from pygments.formatter import Formatter +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Token, Whitespace +from pygments.console import ansiformat +from pygments.util import get_choice_opt + + +__all__ = ['TerminalFormatter'] + + +#: Map token types to a tuple of color values for light and dark +#: backgrounds. +TERMINAL_COLORS = { + Token: ('', ''), + Whitespace: ('gray', 'brightblack'), Comment: ('gray', 'brightblack'), Comment.Preproc: ('cyan', 'brightcyan'), @@ -44,93 +44,93 @@ TERMINAL_COLORS = { Name.Tag: ('brightblue', 'brightblue'), String: ('yellow', 'yellow'), Number: ('blue', 'brightblue'), - + Generic.Deleted: ('brightred', 'brightred'), Generic.Inserted: ('green', 'brightgreen'), - Generic.Heading: ('**', '**'), + Generic.Heading: ('**', '**'), Generic.Subheading: ('*magenta*', '*brightmagenta*'), - Generic.Prompt: ('**', '**'), + Generic.Prompt: ('**', '**'), Generic.Error: ('brightred', 'brightred'), - + Error: ('_brightred_', '_brightred_'), -} - - -class TerminalFormatter(Formatter): - r""" - Format tokens with ANSI color sequences, for output in a text console. - Color sequences are terminated at newlines, so that paging the output - works correctly. - - The `get_style_defs()` method doesn't do anything special since there is - no support for common styles. - - Options accepted: - - `bg` - Set to ``"light"`` or ``"dark"`` depending on the terminal's background - (default: ``"light"``). - - `colorscheme` - A dictionary mapping token types to (lightbg, darkbg) color names or - ``None`` (default: ``None`` = use builtin colorscheme). - - `linenos` - Set to ``True`` to have line numbers on the terminal output as well - (default: ``False`` = no line numbers). - """ - name = 'Terminal' - aliases = ['terminal', 'console'] - filenames = [] - - def __init__(self, **options): - Formatter.__init__(self, **options) - self.darkbg = get_choice_opt(options, 'bg', - ['light', 'dark'], 'light') == 'dark' - self.colorscheme = options.get('colorscheme', None) or TERMINAL_COLORS - self.linenos = options.get('linenos', False) - self._lineno = 0 - - def format(self, tokensource, outfile): - # hack: if the output is a terminal and has an encoding set, - # use that to avoid unicode encode problems - if not self.encoding and hasattr(outfile, "encoding") and \ - hasattr(outfile, "isatty") and outfile.isatty() and \ - sys.version_info < (3,): - self.encoding = outfile.encoding - return Formatter.format(self, tokensource, outfile) - - def _write_lineno(self, outfile): - self._lineno += 1 - outfile.write("%s%04d: " % (self._lineno != 1 and '\n' or '', self._lineno)) - - def _get_color(self, ttype): - # self.colorscheme is a dict containing usually generic types, so we - # have to walk the tree of dots. The base Token type must be a key, - # even if it's empty string, as in the default above. - colors = self.colorscheme.get(ttype) - while colors is None: - ttype = ttype.parent - colors = self.colorscheme.get(ttype) - return colors[self.darkbg] - - def format_unencoded(self, tokensource, outfile): - if self.linenos: - self._write_lineno(outfile) - - for ttype, value in tokensource: - color = self._get_color(ttype) - - for line in value.splitlines(True): - if color: - outfile.write(ansiformat(color, line.rstrip('\n'))) - else: - outfile.write(line.rstrip('\n')) - if line.endswith('\n'): - if self.linenos: - self._write_lineno(outfile) - else: - outfile.write('\n') - - if self.linenos: - outfile.write("\n") +} + + +class TerminalFormatter(Formatter): + r""" + Format tokens with ANSI color sequences, for output in a text console. + Color sequences are terminated at newlines, so that paging the output + works correctly. + + The `get_style_defs()` method doesn't do anything special since there is + no support for common styles. + + Options accepted: + + `bg` + Set to ``"light"`` or ``"dark"`` depending on the terminal's background + (default: ``"light"``). + + `colorscheme` + A dictionary mapping token types to (lightbg, darkbg) color names or + ``None`` (default: ``None`` = use builtin colorscheme). + + `linenos` + Set to ``True`` to have line numbers on the terminal output as well + (default: ``False`` = no line numbers). + """ + name = 'Terminal' + aliases = ['terminal', 'console'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.darkbg = get_choice_opt(options, 'bg', + ['light', 'dark'], 'light') == 'dark' + self.colorscheme = options.get('colorscheme', None) or TERMINAL_COLORS + self.linenos = options.get('linenos', False) + self._lineno = 0 + + def format(self, tokensource, outfile): + # hack: if the output is a terminal and has an encoding set, + # use that to avoid unicode encode problems + if not self.encoding and hasattr(outfile, "encoding") and \ + hasattr(outfile, "isatty") and outfile.isatty() and \ + sys.version_info < (3,): + self.encoding = outfile.encoding + return Formatter.format(self, tokensource, outfile) + + def _write_lineno(self, outfile): + self._lineno += 1 + outfile.write("%s%04d: " % (self._lineno != 1 and '\n' or '', self._lineno)) + + def _get_color(self, ttype): + # self.colorscheme is a dict containing usually generic types, so we + # have to walk the tree of dots. The base Token type must be a key, + # even if it's empty string, as in the default above. + colors = self.colorscheme.get(ttype) + while colors is None: + ttype = ttype.parent + colors = self.colorscheme.get(ttype) + return colors[self.darkbg] + + def format_unencoded(self, tokensource, outfile): + if self.linenos: + self._write_lineno(outfile) + + for ttype, value in tokensource: + color = self._get_color(ttype) + + for line in value.splitlines(True): + if color: + outfile.write(ansiformat(color, line.rstrip('\n'))) + else: + outfile.write(line.rstrip('\n')) + if line.endswith('\n'): + if self.linenos: + self._write_lineno(outfile) + else: + outfile.write('\n') + + if self.linenos: + outfile.write("\n") diff --git a/contrib/python/Pygments/py2/pygments/formatters/terminal256.py b/contrib/python/Pygments/py2/pygments/formatters/terminal256.py index ac5814b0043..43ec01c24b7 100644 --- a/contrib/python/Pygments/py2/pygments/formatters/terminal256.py +++ b/contrib/python/Pygments/py2/pygments/formatters/terminal256.py @@ -1,54 +1,54 @@ -# -*- coding: utf-8 -*- -""" - pygments.formatters.terminal256 - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - Formatter for 256-color terminal output with ANSI sequences. - - RGB-to-XTERM color conversion routines adapted from xterm256-conv - tool (http://frexx.de/xterm-256-notes/data/xterm256-conv2.tar.bz2) - by Wolfgang Frisch. - - Formatter version 1. - +# -*- coding: utf-8 -*- +""" + pygments.formatters.terminal256 + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for 256-color terminal output with ANSI sequences. + + RGB-to-XTERM color conversion routines adapted from xterm256-conv + tool (http://frexx.de/xterm-256-notes/data/xterm256-conv2.tar.bz2) + by Wolfgang Frisch. + + Formatter version 1. + :copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS. - :license: BSD, see LICENSE for details. -""" - -# TODO: -# - Options to map style's bold/underline/italic/border attributes -# to some ANSI attrbutes (something like 'italic=underline') -# - An option to output "style RGB to xterm RGB/index" conversion table -# - An option to indicate that we are running in "reverse background" -# xterm. This means that default colors are white-on-black, not -# black-on-while, so colors like "white background" need to be converted -# to "white background, black foreground", etc... - -import sys - -from pygments.formatter import Formatter + :license: BSD, see LICENSE for details. +""" + +# TODO: +# - Options to map style's bold/underline/italic/border attributes +# to some ANSI attrbutes (something like 'italic=underline') +# - An option to output "style RGB to xterm RGB/index" conversion table +# - An option to indicate that we are running in "reverse background" +# xterm. This means that default colors are white-on-black, not +# black-on-while, so colors like "white background" need to be converted +# to "white background, black foreground", etc... + +import sys + +from pygments.formatter import Formatter from pygments.console import codes from pygments.style import ansicolors - - -__all__ = ['Terminal256Formatter', 'TerminalTrueColorFormatter'] - - -class EscapeSequence: - def __init__(self, fg=None, bg=None, bold=False, underline=False): - self.fg = fg - self.bg = bg - self.bold = bold - self.underline = underline - - def escape(self, attrs): - if len(attrs): - return "\x1b[" + ";".join(attrs) + "m" - return "" - - def color_string(self): - attrs = [] - if self.fg is not None: + + +__all__ = ['Terminal256Formatter', 'TerminalTrueColorFormatter'] + + +class EscapeSequence: + def __init__(self, fg=None, bg=None, bold=False, underline=False): + self.fg = fg + self.bg = bg + self.bold = bold + self.underline = underline + + def escape(self, attrs): + if len(attrs): + return "\x1b[" + ";".join(attrs) + "m" + return "" + + def color_string(self): + attrs = [] + if self.fg is not None: if self.fg in ansicolors: esc = codes[self.fg.replace('ansi','')] if ';01m' in esc: @@ -57,54 +57,54 @@ class EscapeSequence: attrs.append(esc[2:4]) else: attrs.extend(("38", "5", "%i" % self.fg)) - if self.bg is not None: + if self.bg is not None: if self.bg in ansicolors: esc = codes[self.bg.replace('ansi','')] # extract fg color code, add 10 for bg. attrs.append(str(int(esc[2:4])+10)) else: attrs.extend(("48", "5", "%i" % self.bg)) - if self.bold: - attrs.append("01") - if self.underline: - attrs.append("04") - return self.escape(attrs) - - def true_color_string(self): - attrs = [] - if self.fg: - attrs.extend(("38", "2", str(self.fg[0]), str(self.fg[1]), str(self.fg[2]))) - if self.bg: - attrs.extend(("48", "2", str(self.bg[0]), str(self.bg[1]), str(self.bg[2]))) - if self.bold: - attrs.append("01") - if self.underline: - attrs.append("04") - return self.escape(attrs) - - def reset_string(self): - attrs = [] - if self.fg is not None: - attrs.append("39") - if self.bg is not None: - attrs.append("49") - if self.bold or self.underline: - attrs.append("00") - return self.escape(attrs) - - -class Terminal256Formatter(Formatter): - """ - Format tokens with ANSI color sequences, for output in a 256-color - terminal or console. Like in `TerminalFormatter` color sequences - are terminated at newlines, so that paging the output works correctly. - - The formatter takes colors from a style defined by the `style` option - and converts them to nearest ANSI 256-color escape sequences. Bold and - underline attributes from the style are preserved (and displayed). - - .. versionadded:: 0.9 - + if self.bold: + attrs.append("01") + if self.underline: + attrs.append("04") + return self.escape(attrs) + + def true_color_string(self): + attrs = [] + if self.fg: + attrs.extend(("38", "2", str(self.fg[0]), str(self.fg[1]), str(self.fg[2]))) + if self.bg: + attrs.extend(("48", "2", str(self.bg[0]), str(self.bg[1]), str(self.bg[2]))) + if self.bold: + attrs.append("01") + if self.underline: + attrs.append("04") + return self.escape(attrs) + + def reset_string(self): + attrs = [] + if self.fg is not None: + attrs.append("39") + if self.bg is not None: + attrs.append("49") + if self.bold or self.underline: + attrs.append("00") + return self.escape(attrs) + + +class Terminal256Formatter(Formatter): + """ + Format tokens with ANSI color sequences, for output in a 256-color + terminal or console. Like in `TerminalFormatter` color sequences + are terminated at newlines, so that paging the output works correctly. + + The formatter takes colors from a style defined by the `style` option + and converts them to nearest ANSI 256-color escape sequences. Bold and + underline attributes from the style are preserved (and displayed). + + .. versionadded:: 0.9 + .. versionchanged:: 2.2 If the used style defines foreground colors in the form ``#ansi*``, then `Terminal256Formatter` will map these to non extended foreground color. @@ -116,200 +116,200 @@ class Terminal256Formatter(Formatter): See :ref:`this table <new-ansi-color-names>` for more information. - Options accepted: - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). - """ - name = 'Terminal256' - aliases = ['terminal256', 'console256', '256'] - filenames = [] - - def __init__(self, **options): - Formatter.__init__(self, **options) - - self.xterm_colors = [] - self.best_match = {} - self.style_string = {} - - self.usebold = 'nobold' not in options - self.useunderline = 'nounderline' not in options - - self._build_color_table() # build an RGB-to-256 color conversion table - self._setup_styles() # convert selected style's colors to term. colors - - def _build_color_table(self): - # colors 0..15: 16 basic colors - - self.xterm_colors.append((0x00, 0x00, 0x00)) # 0 - self.xterm_colors.append((0xcd, 0x00, 0x00)) # 1 - self.xterm_colors.append((0x00, 0xcd, 0x00)) # 2 - self.xterm_colors.append((0xcd, 0xcd, 0x00)) # 3 - self.xterm_colors.append((0x00, 0x00, 0xee)) # 4 - self.xterm_colors.append((0xcd, 0x00, 0xcd)) # 5 - self.xterm_colors.append((0x00, 0xcd, 0xcd)) # 6 - self.xterm_colors.append((0xe5, 0xe5, 0xe5)) # 7 - self.xterm_colors.append((0x7f, 0x7f, 0x7f)) # 8 - self.xterm_colors.append((0xff, 0x00, 0x00)) # 9 - self.xterm_colors.append((0x00, 0xff, 0x00)) # 10 - self.xterm_colors.append((0xff, 0xff, 0x00)) # 11 - self.xterm_colors.append((0x5c, 0x5c, 0xff)) # 12 - self.xterm_colors.append((0xff, 0x00, 0xff)) # 13 - self.xterm_colors.append((0x00, 0xff, 0xff)) # 14 - self.xterm_colors.append((0xff, 0xff, 0xff)) # 15 - - # colors 16..232: the 6x6x6 color cube - - valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) - - for i in range(217): - r = valuerange[(i // 36) % 6] - g = valuerange[(i // 6) % 6] - b = valuerange[i % 6] - self.xterm_colors.append((r, g, b)) - - # colors 233..253: grayscale - - for i in range(1, 22): - v = 8 + i * 10 - self.xterm_colors.append((v, v, v)) - - def _closest_color(self, r, g, b): - distance = 257*257*3 # "infinity" (>distance from #000000 to #ffffff) - match = 0 - - for i in range(0, 254): - values = self.xterm_colors[i] - - rd = r - values[0] - gd = g - values[1] - bd = b - values[2] - d = rd*rd + gd*gd + bd*bd - - if d < distance: - match = i - distance = d - return match - - def _color_index(self, color): - index = self.best_match.get(color, None) + Options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + """ + name = 'Terminal256' + aliases = ['terminal256', 'console256', '256'] + filenames = [] + + def __init__(self, **options): + Formatter.__init__(self, **options) + + self.xterm_colors = [] + self.best_match = {} + self.style_string = {} + + self.usebold = 'nobold' not in options + self.useunderline = 'nounderline' not in options + + self._build_color_table() # build an RGB-to-256 color conversion table + self._setup_styles() # convert selected style's colors to term. colors + + def _build_color_table(self): + # colors 0..15: 16 basic colors + + self.xterm_colors.append((0x00, 0x00, 0x00)) # 0 + self.xterm_colors.append((0xcd, 0x00, 0x00)) # 1 + self.xterm_colors.append((0x00, 0xcd, 0x00)) # 2 + self.xterm_colors.append((0xcd, 0xcd, 0x00)) # 3 + self.xterm_colors.append((0x00, 0x00, 0xee)) # 4 + self.xterm_colors.append((0xcd, 0x00, 0xcd)) # 5 + self.xterm_colors.append((0x00, 0xcd, 0xcd)) # 6 + self.xterm_colors.append((0xe5, 0xe5, 0xe5)) # 7 + self.xterm_colors.append((0x7f, 0x7f, 0x7f)) # 8 + self.xterm_colors.append((0xff, 0x00, 0x00)) # 9 + self.xterm_colors.append((0x00, 0xff, 0x00)) # 10 + self.xterm_colors.append((0xff, 0xff, 0x00)) # 11 + self.xterm_colors.append((0x5c, 0x5c, 0xff)) # 12 + self.xterm_colors.append((0xff, 0x00, 0xff)) # 13 + self.xterm_colors.append((0x00, 0xff, 0xff)) # 14 + self.xterm_colors.append((0xff, 0xff, 0xff)) # 15 + + # colors 16..232: the 6x6x6 color cube + + valuerange = (0x00, 0x5f, 0x87, 0xaf, 0xd7, 0xff) + + for i in range(217): + r = valuerange[(i // 36) % 6] + g = valuerange[(i // 6) % 6] + b = valuerange[i % 6] + self.xterm_colors.append((r, g, b)) + + # colors 233..253: grayscale + + for i in range(1, 22): + v = 8 + i * 10 + self.xterm_colors.append((v, v, v)) + + def _closest_color(self, r, g, b): + distance = 257*257*3 # "infinity" (>distance from #000000 to #ffffff) + match = 0 + + for i in range(0, 254): + values = self.xterm_colors[i] + + rd = r - values[0] + gd = g - values[1] + bd = b - values[2] + d = rd*rd + gd*gd + bd*bd + + if d < distance: + match = i + distance = d + return match + + def _color_index(self, color): + index = self.best_match.get(color, None) if color in ansicolors: # strip the `ansi/#ansi` part and look up code index = color self.best_match[color] = index - if index is None: - try: - rgb = int(str(color), 16) - except ValueError: - rgb = 0 - - r = (rgb >> 16) & 0xff - g = (rgb >> 8) & 0xff - b = rgb & 0xff - index = self._closest_color(r, g, b) - self.best_match[color] = index - return index - - def _setup_styles(self): - for ttype, ndef in self.style: - escape = EscapeSequence() + if index is None: + try: + rgb = int(str(color), 16) + except ValueError: + rgb = 0 + + r = (rgb >> 16) & 0xff + g = (rgb >> 8) & 0xff + b = rgb & 0xff + index = self._closest_color(r, g, b) + self.best_match[color] = index + return index + + def _setup_styles(self): + for ttype, ndef in self.style: + escape = EscapeSequence() # get foreground from ansicolor if set if ndef['ansicolor']: escape.fg = self._color_index(ndef['ansicolor']) elif ndef['color']: - escape.fg = self._color_index(ndef['color']) + escape.fg = self._color_index(ndef['color']) if ndef['bgansicolor']: escape.bg = self._color_index(ndef['bgansicolor']) elif ndef['bgcolor']: - escape.bg = self._color_index(ndef['bgcolor']) - if self.usebold and ndef['bold']: - escape.bold = True - if self.useunderline and ndef['underline']: - escape.underline = True - self.style_string[str(ttype)] = (escape.color_string(), - escape.reset_string()) - - def format(self, tokensource, outfile): - # hack: if the output is a terminal and has an encoding set, - # use that to avoid unicode encode problems - if not self.encoding and hasattr(outfile, "encoding") and \ - hasattr(outfile, "isatty") and outfile.isatty() and \ - sys.version_info < (3,): - self.encoding = outfile.encoding - return Formatter.format(self, tokensource, outfile) - - def format_unencoded(self, tokensource, outfile): - for ttype, value in tokensource: - not_found = True - while ttype and not_found: - try: - # outfile.write( "<" + str(ttype) + ">" ) - on, off = self.style_string[str(ttype)] - - # Like TerminalFormatter, add "reset colors" escape sequence - # on newline. - spl = value.split('\n') - for line in spl[:-1]: - if line: - outfile.write(on + line + off) - outfile.write('\n') - if spl[-1]: - outfile.write(on + spl[-1] + off) - - not_found = False - # outfile.write( '#' + str(ttype) + '#' ) - - except KeyError: - # ottype = ttype - ttype = ttype[:-1] - # outfile.write( '!' + str(ottype) + '->' + str(ttype) + '!' ) - - if not_found: - outfile.write(value) - - -class TerminalTrueColorFormatter(Terminal256Formatter): - r""" - Format tokens with ANSI color sequences, for output in a true-color - terminal or console. Like in `TerminalFormatter` color sequences - are terminated at newlines, so that paging the output works correctly. - - .. versionadded:: 2.1 - - Options accepted: - - `style` - The style to use, can be a string or a Style subclass (default: - ``'default'``). - """ - name = 'TerminalTrueColor' - aliases = ['terminal16m', 'console16m', '16m'] - filenames = [] - - def _build_color_table(self): - pass - - def _color_tuple(self, color): - try: - rgb = int(str(color), 16) - except ValueError: - return None - r = (rgb >> 16) & 0xff - g = (rgb >> 8) & 0xff - b = rgb & 0xff - return (r, g, b) - - def _setup_styles(self): - for ttype, ndef in self.style: - escape = EscapeSequence() - if ndef['color']: - escape.fg = self._color_tuple(ndef['color']) - if ndef['bgcolor']: - escape.bg = self._color_tuple(ndef['bgcolor']) - if self.usebold and ndef['bold']: - escape.bold = True - if self.useunderline and ndef['underline']: - escape.underline = True - self.style_string[str(ttype)] = (escape.true_color_string(), - escape.reset_string()) + escape.bg = self._color_index(ndef['bgcolor']) + if self.usebold and ndef['bold']: + escape.bold = True + if self.useunderline and ndef['underline']: + escape.underline = True + self.style_string[str(ttype)] = (escape.color_string(), + escape.reset_string()) + + def format(self, tokensource, outfile): + # hack: if the output is a terminal and has an encoding set, + # use that to avoid unicode encode problems + if not self.encoding and hasattr(outfile, "encoding") and \ + hasattr(outfile, "isatty") and outfile.isatty() and \ + sys.version_info < (3,): + self.encoding = outfile.encoding + return Formatter.format(self, tokensource, outfile) + + def format_unencoded(self, tokensource, outfile): + for ttype, value in tokensource: + not_found = True + while ttype and not_found: + try: + # outfile.write( "<" + str(ttype) + ">" ) + on, off = self.style_string[str(ttype)] + + # Like TerminalFormatter, add "reset colors" escape sequence + # on newline. + spl = value.split('\n') + for line in spl[:-1]: + if line: + outfile.write(on + line + off) + outfile.write('\n') + if spl[-1]: + outfile.write(on + spl[-1] + off) + + not_found = False + # outfile.write( '#' + str(ttype) + '#' ) + + except KeyError: + # ottype = ttype + ttype = ttype[:-1] + # outfile.write( '!' + str(ottype) + '->' + str(ttype) + '!' ) + + if not_found: + outfile.write(value) + + +class TerminalTrueColorFormatter(Terminal256Formatter): + r""" + Format tokens with ANSI color sequences, for output in a true-color + terminal or console. Like in `TerminalFormatter` color sequences + are terminated at newlines, so that paging the output works correctly. + + .. versionadded:: 2.1 + + Options accepted: + + `style` + The style to use, can be a string or a Style subclass (default: + ``'default'``). + """ + name = 'TerminalTrueColor' + aliases = ['terminal16m', 'console16m', '16m'] + filenames = [] + + def _build_color_table(self): + pass + + def _color_tuple(self, color): + try: + rgb = int(str(color), 16) + except ValueError: + return None + r = (rgb >> 16) & 0xff + g = (rgb >> 8) & 0xff + b = rgb & 0xff + return (r, g, b) + + def _setup_styles(self): + for ttype, ndef in self.style: + escape = EscapeSequence() + if ndef['color']: + escape.fg = self._color_tuple(ndef['color']) + if ndef['bgcolor']: + escape.bg = self._color_tuple(ndef['bgcolor']) + if self.usebold and ndef['bold']: + escape.bold = True + if self.useunderline and ndef['underline']: + escape.underline = True + self.style_string[str(ttype)] = (escape.true_color_string(), + escape.reset_string()) |