diff options
Diffstat (limited to 'pygments/formatters')
-rw-r--r-- | pygments/formatters/__init__.py | 73 | ||||
-rw-r--r-- | pygments/formatters/bbcode.py | 99 | ||||
-rw-r--r-- | pygments/formatters/html.py | 280 | ||||
-rw-r--r-- | pygments/formatters/latex.py | 191 | ||||
-rw-r--r-- | pygments/formatters/other.py | 73 | ||||
-rw-r--r-- | pygments/formatters/terminal.py | 98 |
6 files changed, 814 insertions, 0 deletions
diff --git a/pygments/formatters/__init__.py b/pygments/formatters/__init__.py new file mode 100644 index 00000000..b701efb4 --- /dev/null +++ b/pygments/formatters/__init__.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters + ~~~~~~~~~~~~~~~~~~ + + Pygments formatters. + + :copyright: 2006 by Georg Brandl, Armin Ronacher. + :license: GNU LGPL, see LICENSE for more details. +""" +import os.path +from pygments.formatters.html import HtmlFormatter +from pygments.formatters.terminal import TerminalFormatter +from pygments.formatters.latex import LatexFormatter +from pygments.formatters.bbcode import BBCodeFormatter +from pygments.formatters.other import NullFormatter, RawTokenFormatter + + +def _doc_desc(obj): + res = '' + for line in obj.__doc__.strip().splitlines(): + if line.strip(): res += line.strip() + " " + else: break + return res + + +#: Map formatter classes to ``(longname, names, file extensions, descr)``. +FORMATTERS = { + HtmlFormatter: ('HTML', ('html',), ('.htm', '.html'), + _doc_desc(HtmlFormatter)), + TerminalFormatter: ('Terminal', ('terminal', 'console'), (), + _doc_desc(TerminalFormatter)), + LatexFormatter: ('LaTeX', ('latex', 'tex'), ('.tex',), + _doc_desc(LatexFormatter)), + RawTokenFormatter: ('Raw tokens', ('raw', 'tokens'), ('.raw',), + _doc_desc(RawTokenFormatter)), + NullFormatter: ('Text only', ('text', 'null'), ('.txt',), + _doc_desc(NullFormatter)), + BBCodeFormatter: ('BBcode', ('bbcode', 'bb'), (), + _doc_desc(BBCodeFormatter)) +} + + +_formatter_cache = {} + +def _init_formatter_cache(): + if _formatter_cache: return + for cls, info in FORMATTERS.iteritems(): + for alias in info[1]: + _formatter_cache[alias] = cls + for ext in info[2]: + _formatter_cache["/"+ext] = cls + + +def get_formatter_by_name(name, **options): + _init_formatter_cache() + cls = _formatter_cache.get(name, None) + if not cls: + raise ValueError("No formatter found for name %r" % name) + return cls(**options) + + +def get_formatter_for_filename(fn, **options): + _init_formatter_cache() + # try by filename extension + cls = _formatter_cache.get("/"+os.path.splitext(fn)[1], None) + if cls: + return cls(**options) + # try by whole file name + cls = _formatter_cache.get("/"+os.path.basename(fn), None) + if not cls: + raise ValueError("No formatter found for file name %r" % fn) + return cls(**options) diff --git a/pygments/formatters/bbcode.py b/pygments/formatters/bbcode.py new file mode 100644 index 00000000..61384c7f --- /dev/null +++ b/pygments/formatters/bbcode.py @@ -0,0 +1,99 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters.bbcode + ~~~~~~~~~~~~~~~~~~~~~~~~~ + + BBcode formatter. + + :copyright: 2006 by Lukas Meuser. + :license: GNU LGPL, see LICENSE for more details. +""" + + +from pygments.formatter import Formatter +from pygments.util import get_bool_opt + +__all__ = ['BBCodeFormatter'] + + +class BBCodeFormatter(Formatter): + """ + Output BBCode tags with appropiate colors and formatting. + + This formatter doesn't support background colors and borders, as there are + no common BBcodes 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: + + ``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). + """ + + def __init__(self, **options): + Formatter.__init__(self, **options) + self._make_styles() + self._code = get_bool_opt(options, 'codetag', False) + self._mono = get_bool_opt(options, 'monofont', False) + + def _make_styles(self): + self.styles = {} + for token, style in self.style._styles.iteritems(): + start = end = '' + color, bold, italic, underline, bg, border = style + if color: + start += '[color=#%s]' % color + end = '[/color]' + end + if bold: + start += '[b]' + end = '[/b]' + end + if italic: + start += '[i]' + end = '[/i]' + end + if underline: + start += '[u]' + end = '[/u]' + end + # there are no common BBcodes for background-color and border + + self.styles[token] = start, end + + def format(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/pygments/formatters/html.py b/pygments/formatters/html.py new file mode 100644 index 00000000..6223aba6 --- /dev/null +++ b/pygments/formatters/html.py @@ -0,0 +1,280 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters.html + ~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for HTML output. + + :copyright: 2006 by Georg Brandl, Armin Ronacher. + :license: GNU LGPL, see LICENSE for more details. +""" +import StringIO + +from pygments.formatter import Formatter +from pygments.token import Token, Text, STANDARD_TYPES +from pygments.util import get_bool_opt, get_int_opt, get_list_opt + + +__all__ = ['HtmlFormatter'] + + +def escape_html(text): + """Escape &, <, > as well as single and double quotes for HTML.""" + return text.replace('&', '&'). \ + replace('<', '<'). \ + replace('>', '>'). \ + replace('"', '"'). \ + replace("'", ''') + + +def get_random_id(): + """Return a random id for javascript fields.""" + from random import random + from time import time + try: + from hashlib import sha1 as sha + except ImportError: + import sha + sha = sha.new + return sha('%s|%s' % (random(), time())).hexdigest() + + +def _get_ttype_class(ttype): + fname = STANDARD_TYPES.get(ttype) + if fname: return fname + aname = '' + while fname is None: + aname = '-' + ttype[-1] + aname + ttype = ttype.parent + fname = STANDARD_TYPES.get(ttype) + return fname + aname + + +DOC_TEMPLATE = '''\ +<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" + "http://www.w3.org/TR/html4/strict.dtd"> + +<html> +<head> + <title>%(title)s</title> + <style type="text/css"> +td.linenos { background-color: #f0f0f0; padding-right: 10px; } +%(styledefs)s + </style> +</head> +<body> +<h2>%(title)s</h2> + +%(code)s + +</body> +</html> +''' + + +class HtmlFormatter(Formatter): + """ + Output HTML <span> tags with appropriate classes. + + Additional options accepted: + + ``nowrap`` + If set to true, don't wrap the tokens at all. This disables + all other options (default: False). + ``noclasses`` + If set to true, token <span>s will not use CSS classes, but + inline styles. + ``classprefix`` + Prefix for token CSS classes, is prepended to all token style + classes (e.g. class="o" -> class="_o" if classprefix == '_') + (default: ''). + ``cssclass`` + CSS class for the wrapping <div> (default: 'highlight'). + ``cssstyles`` + Inline CSS styles for the wrapping <div>. (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 + (default: 1). + ``linenospecial`` + If set to a number n > 0, every nth line number is given a special + CSS class ``special`` (default: 0). + ``nobackground`` + If set to ``True`` the formatter won't output the background color + for the overall element (this automatically defaults to ``False`` + when there is no overall element [eg: no argument for the + `get_syntax_defs` method given]) (default: ``False``) + """ + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.nowrap = get_bool_opt(options, 'nowrap', False) + self.noclasses = get_bool_opt(options, 'noclasses', False) + self.classprefix = options.get('classprefix', '') + self.cssclass = options.get('cssclass', 'highlight') + self.cssstyles = options.get('cssstyles', '') + 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.linenospecial = abs(get_int_opt(options, 'linenospecial', 0)) + self.nobackground = get_bool_opt(options, 'nobackground', False) + + self._class_cache = {} + self._create_stylesheet() + + def _get_css_class(self, ttype): + """Return the css class of this token type prefixed with + the classprefix option.""" + if ttype in self._class_cache: + return self._class_cache[ttype] + + return self.classprefix + STANDARD_TYPES.get(ttype) or _get_ttype_class(ttype) + + def _create_stylesheet(self): + t2c = self.ttype2class = {Token: ''} + c2s = self.class2style = {} + cp = self.classprefix + for ttype, ndef in self.style: + name = cp + _get_ttype_class(ttype) + style = '' + if ndef['color']: + style += 'color: #%s; ' % ndef['color'] + if ndef['bold']: + style += 'font-weight: bold; ' + if ndef['italic']: + style += 'font-style: italic; ' + if ndef['underline']: + style += 'text-decoration: underline; ' + if ndef['bgcolor']: + style += 'background-color: #%s; ' % ndef['bgcolor'] + if ndef['border']: + style += 'border: 1px solid #%s; ' % ndef['border'] + if style: + t2c[ttype] = name + # save len(ttype) to enable ordering the styles by + # hierarchy (necessary for CSS cascading rules!) + c2s[name] = (style[:-2], ttype, len(ttype)) + + def get_style_defs(self, arg=''): + """ + Return CSS style definitions for the classes produced by the + current highlighting style. ``arg`` can be a string of selectors + to insert before the token type classes. + """ + if arg: + arg += ' ' + styles = [(level, ttype, cls, style) + for cls, (style, ttype, level) in self.class2style.iteritems() + if cls and style] + styles.sort() + lines = ['%s.%s { %s } /* %s */' % (arg, 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 }' % + (arg, self.style.background_color, text_style)) + return '\n'.join(lines) + + def _format_nowrap(self, tokensource, outfile, lnos=False): + lncount = 0 + nocls = self.noclasses + # for <span style=""> lookup only + getcls = self.ttype2class.get + c2s = self.class2style + + write = outfile.write + lspan = '' + for ttype, value in tokensource: + htmlvalue = escape_html(value) + if lnos: + lncount += value.count("\n") + + if nocls: + cclass = getcls(ttype) + while cclass is None: + ttype = ttype.parent + cclass = getcls(ttype) + cspan = cclass and '<span style="%s">' % c2s[cclass][0] + else: + cls = self._get_css_class(ttype) + cspan = cls and '<span class="%s">' % cls + + if cspan == lspan: + if not cspan: + write(htmlvalue) + else: + write(htmlvalue.replace('\n', '</span>\n' + cspan)) + elif htmlvalue: # if no value, leave old span open + if lspan: + write('</span>') + lspan = cspan + if cspan: + htmlvalue = htmlvalue.replace('\n', '</span>\n' + cspan) + write(cspan + htmlvalue) + else: + write(htmlvalue) + if lspan: + write('</span>') + return lncount + + def format(self, tokensource, outfile): + if self.nowrap: + self._format_nowrap(tokensource, outfile) + return + + realoutfile = outfile + lnos = self.linenos + full = self.full + + div = ('<div' + (self.cssclass and ' class="%s" ' % self.cssclass) + + (self.cssstyles and ' style="%s"' % self.cssstyles) + '>') + if full or lnos: + outfile = StringIO.StringIO() + else: + outfile.write(div) + + outfile.write('<pre>') + lncount = self._format_nowrap(tokensource, outfile, lnos) + outfile.write('</pre>') + + ret = '' + if lnos: + fl = self.linenostart + mw = len(str(lncount + fl - 1)) + sp = self.linenospecial + st = self.linenostep + if sp: + ls = '\n'.join([(i%st == 0 and + (i%sp == 0 and '<span class="special">%*d</span>' + or '%*d') % (mw, i) + or '') + for i in range(fl, fl + lncount)]) + else: + ls = '\n'.join([(i%st == 0 and ('%*d' % (mw, i)) or '') + for i in range(fl, fl + lncount)]) + + ret = div + ('<table><tr>' + '<td class="linenos" title="click to toggle" ' + 'onclick="with (this.firstChild.style) { display = ' + '''(display == '') ? 'none' : '' }"><pre>''' + + ls + '</pre></td><td class="code">') + ret += outfile.getvalue() + ret += '</td></tr></table>' + + if full: + if not ret: + ret = div + outfile.getvalue() + '</div>\n' + realoutfile.write(DOC_TEMPLATE % + dict(title = self.title, + styledefs = self.get_style_defs('body'), + code = ret)) + elif lnos: + realoutfile.write(ret + '</div>\n') + else: + realoutfile.write('</div>\n') diff --git a/pygments/formatters/latex.py b/pygments/formatters/latex.py new file mode 100644 index 00000000..84fe5d12 --- /dev/null +++ b/pygments/formatters/latex.py @@ -0,0 +1,191 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters.latex + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for LaTeX fancyvrb output. + + :copyright: 2006 by Georg Brandl. + :license: GNU LGPL, see LICENSE for more details. +""" +import StringIO + +from pygments.formatter import Formatter +from pygments.token import Token +from pygments.util import get_bool_opt, get_int_opt + + +__all__ = ['LatexFormatter'] + + +def escape_tex(text): + return text.replace('@', '\x00'). \ + replace('[', '\x01'). \ + replace(']', '\x02'). \ + replace('\x00', '@at[]').\ + replace('\x01', '@lb[]').\ + replace('\x02', '@rb[]') + + +DOC_TEMPLATE = r''' +\documentclass{%(docclass)s} +\usepackage{fancyvrb} +\usepackage{color} +%(preamble)s + +%(styledefs)s + +\begin{document} + +\section*{%(title)s} + +%(code)s +\end{document} +''' + + +class LatexFormatter(Formatter): + """ + Output LaTeX "color" and "fancyvrb" control sequences. + """ + + def __init__(self, **options): + """ + Additional options accepted: + + ``docclass`` + If ``full`` is true, this is the document class to use (default: 'article'). + ``preamble`` + If ``full`` is true, this can be further preamble commands (default: ''). + ``linenos`` + If 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 (default: 1). + ``verboptions`` + Additional options given to the Verbatim environment (default: ''). + ``nobackground`` + If set to ``True`` the formatter won't output the background color + for the overall element (default: ``False``) + Note that light colors on dark background with this option disabled + won't be readable very good. + """ + 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._create_stylecmds() + + + def _create_stylecmds(self): + t2c = self.ttype2cmd = {Token: ''} + c2d = self.cmd2def = {} + + letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + first = iter(letters) + second = iter(letters) + firstl = first.next() + + 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: + cmndef = '#1' + if ndef['bold']: + cmndef = r'\textbf{' + cmndef + '}' + if ndef['italic']: + cmndef = r'\textit{' + cmndef + '}' + if ndef['underline']: + cmndef = r'\underline{' + cmndef + '}' + if ndef['color']: + cmndef = r'\textcolor[rgb]{%s}{%s}' % ( + rgbcolor(ndef['color']), + cmndef + ) + if ndef['border']: + cmndef = r'\fcolorbox[rgb]{%s}{%s}{%s}' % ( + rgbcolor(ndef['border']), + rgbcolor(ndef['bgcolor']), + cmndef + ) + elif ndef['bgcolor']: + cmndef = r'\colorbox[rgb]{%s}{%s}' % ( + rgbcolor(ndef['bgcolor']), + cmndef + ) + if cmndef == '#1': + continue + try: + alias = 'C' + firstl + second.next() + except StopIteration: + firstl = first.next() + second = iter(letters) + alias = 'C' + firstl + second.next() + t2c[ttype] = alias + c2d[alias] = cmndef + + def get_style_defs(self, arg=''): + """ + Return the \\newcommand sequences needed to define the commands + used to format text in the verbatim environment. If ``arg`` is + given and true, use \\renewcommand instead. + """ + nc = (arg and r'\renewcommand' or r'\newcommand') + return '%s\\at{@}\n%s\\lb{[}\n%s\\rb{]}\n' % (nc, nc, nc) + \ + '\n'.join(['%s\\%s[1]{%s}' % (nc, alias, cmndef) + for alias, cmndef in self.cmd2def.iteritems() + if cmndef != '#1']) + + def format(self, tokensource, outfile): + #XXX: add support for background colors!!!!!!!111!1 + + if self.full: + realoutfile = outfile + outfile = StringIO.StringIO() + + outfile.write(r'\begin{Verbatim}[commandchars=@\[\]') + if self.linenos: + start, step = self.linenostart, self.linenostep + outfile.write(',numbers=left' + + (start and ',firstnumber=%d' % start or '') + + (step and ',stepnumber=%d' % step or '')) + if self.verboptions: + outfile.write(',' + self.verboptions) + outfile.write(']\n') + + for ttype, value in tokensource: + value = escape_tex(value) + cmd = self.ttype2cmd.get(ttype) + while cmd is None: + ttype = ttype.parent + cmd = self.ttype2cmd.get(ttype) + if cmd: + spl = value.split('\n') + for line in spl[:-1]: + if line: + outfile.write("@%s[%s]" % (cmd, line)) + outfile.write('\n') + if spl[-1]: + outfile.write("@%s[%s]" % (cmd, spl[-1])) + else: + outfile.write(value) + + outfile.write('\n\\end{Verbatim}\n') + + if self.full: + realoutfile.write(DOC_TEMPLATE % + dict(docclass = self.docclass, + preamble = self.preamble, + title = self.title, + styledefs = self.get_style_defs(), + code = outfile.getvalue())) diff --git a/pygments/formatters/other.py b/pygments/formatters/other.py new file mode 100644 index 00000000..eb8d72fc --- /dev/null +++ b/pygments/formatters/other.py @@ -0,0 +1,73 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters.other + ~~~~~~~~~~~~~~~~~~~~~~~~ + + Other formatters. + + :copyright: 2006 by Georg Brandl, Armin Ronacher. + :license: GNU LGPL, see LICENSE for more details. +""" + +from pygments.formatter import Formatter +import StringIO + +__all__ = ['NullFormatter', 'RawTokenFormatter'] + + +class NullFormatter(Formatter): + """ + Output the text unchanged without any formatting. + """ + def format(self, tokensource, outfile): + for ttype, value in tokensource: + outfile.write(value) + + +class RawTokenFormatter(Formatter): + """ + Output a raw token representation for storing token streams. + + The format is ``tokentype<TAB>repr(tokenstring)`` + + Additional options accepted: + + ``compress`` + If set to "gz" or "bz2", compress the token stream with + the given compression algorithm (default: ''). + """ + + def __init__(self, **options): + Formatter.__init__(self, **options) + self.compress = options.get('compress', '') + + def format(self, tokensource, outfile): + if self.compress == 'gz': + import gzip + outfile = gzip.GzipFile('', 'wb', 9, outfile) + write = outfile.write + flush = outfile.flush + elif self.compress == 'bz2': + import bz2 + compressor = bz2.BZ2Compressor(9) + def write(text): + outfile.write(compressor.compress(text)) + def flush(): + outfile.write(compressor.flush()) + outfile.flush() + else: + write = outfile.write + flush = outfile.flush + + lasttype = None + lastval = '' + for ttype, value in tokensource: + if ttype is lasttype: + lastval += value + else: + if lasttype: + write("%s\t%r\n" % (lasttype, lastval)) + lastval = value + lasttype = ttype + write("%s\t%r\n" % (lasttype, lastval)) + flush() diff --git a/pygments/formatters/terminal.py b/pygments/formatters/terminal.py new file mode 100644 index 00000000..b4b0071e --- /dev/null +++ b/pygments/formatters/terminal.py @@ -0,0 +1,98 @@ +# -*- coding: utf-8 -*- +""" + pygments.formatters.terminal + ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + Formatter for terminal output with ANSI sequences. + + :copyright: 2006 by Georg Brandl. + :license: GNU LGPL, see LICENSE for more details. +""" + +from pygments.formatter import Formatter +from pygments.token import Keyword, Name, Comment, String, Error, \ + Number, Operator, Generic, Token +from pygments.console import ansiformat +from pygments.util import get_bool_opt + + +__all__ = ['TerminalFormatter'] + + +#: Map token types to a tuple of color values for light and dark +#: backgrounds. +TERMINAL_COLORS = { + Token: ('', ''), + + Comment: ('lightgray', 'darkgray'), + Keyword: ('darkblue', 'blue'), + Keyword.Type: ('teal', 'turquoise'), + Operator.Word: ('purple', 'fuchsia'), + Name.Builtin: ('teal', 'turquoise'), + Name.Function: ('darkgreen', 'green'), + Name.Namespace: ('_teal_', '_turquoise_'), + Name.Class: ('_darkgreen_', '_green_'), + Name.Exception: ('teal', 'turquoise'), + Name.Decorator: ('darkgray', 'lightgray'), + Name.Variable: ('darkred', 'red'), + Name.Constant: ('darkred', 'red'), + Name.Attribute: ('teal', 'turquoise'), + Name.Tag: ('blue', 'blue'), + String: ('brown', 'brown'), + Number: ('darkblue', 'blue'), + + Generic.Deleted: ('red', 'red'), + Generic.Inserted: ('darkgreen', 'green'), + Generic.Heading: ('**', '**'), + Generic.Subheading: ('*purple*', '*fuchsia*'), + Generic.Error: ('red', 'red'), + + Error: ('_red_', '_red_'), +} + + +class TerminalFormatter(Formatter): + """ + Output plain text with coloring ANSI sequences. + """ + + def __init__(self, **options): + """ + Accepted options: + + ``bg`` + Set to ``'light'`` or ``'dark'`` depending on the + terminal's background. + + ``colorscheme`` + ``None`` or a dictionary mapping token types to + ``(lightbg, darkbg)`` color names. + + ``debug`` + If true, output "<<ERROR>>" after each error token. + """ + Formatter.__init__(self, **options) + self.darkbg = options.get('bg', 'light') == 'dark' + self.colorscheme = options.get('colorscheme', None) or TERMINAL_COLORS + self.debug = get_bool_opt(options, 'debug', False) + + def format(self, tokensource, outfile): + dbg = self.debug + 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(ansiformat(color, line)) + outfile.write('\n') + if spl[-1]: + outfile.write(ansiformat(color, spl[-1])) + else: + outfile.write(value) + if dbg and ttype is Error: + outfile.write('<<ERROR>>') |