Voice et bot modif
This commit is contained in:
parent
189d56026b
commit
7333a22bcd
10774 changed files with 634644 additions and 933308 deletions
|
|
@ -1,25 +0,0 @@
|
|||
Copyright (c) 2006-2022 by the respective authors (see AUTHORS file).
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
|
@ -21,12 +21,12 @@
|
|||
.. _Pygments master branch:
|
||||
https://github.com/pygments/pygments/archive/master.zip#egg=Pygments-dev
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from io import StringIO, BytesIO
|
||||
|
||||
__version__ = '2.19.2'
|
||||
__version__ = '2.15.1'
|
||||
__docformat__ = 'restructuredtext'
|
||||
|
||||
__all__ = ['lex', 'format', 'highlight']
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Main entry point for ``python -m pygments``.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,668 @@
|
|||
"""
|
||||
pygments.cmdline
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
Command line interface.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import argparse
|
||||
from textwrap import dedent
|
||||
|
||||
from pip._vendor.pygments import __version__, highlight
|
||||
from pip._vendor.pygments.util import ClassNotFound, OptionError, docstring_headline, \
|
||||
guess_decode, guess_decode_from_terminal, terminal_encoding, \
|
||||
UnclosingTextIOWrapper
|
||||
from pip._vendor.pygments.lexers import get_all_lexers, get_lexer_by_name, guess_lexer, \
|
||||
load_lexer_from_file, get_lexer_for_filename, find_lexer_class_for_filename
|
||||
from pip._vendor.pygments.lexers.special import TextLexer
|
||||
from pip._vendor.pygments.formatters.latex import LatexEmbeddedLexer, LatexFormatter
|
||||
from pip._vendor.pygments.formatters import get_all_formatters, get_formatter_by_name, \
|
||||
load_formatter_from_file, get_formatter_for_filename, find_formatter_class
|
||||
from pip._vendor.pygments.formatters.terminal import TerminalFormatter
|
||||
from pip._vendor.pygments.formatters.terminal256 import Terminal256Formatter, TerminalTrueColorFormatter
|
||||
from pip._vendor.pygments.filters import get_all_filters, find_filter_class
|
||||
from pip._vendor.pygments.styles import get_all_styles, get_style_by_name
|
||||
|
||||
|
||||
def _parse_options(o_strs):
|
||||
opts = {}
|
||||
if not o_strs:
|
||||
return opts
|
||||
for o_str in o_strs:
|
||||
if not o_str.strip():
|
||||
continue
|
||||
o_args = o_str.split(',')
|
||||
for o_arg in o_args:
|
||||
o_arg = o_arg.strip()
|
||||
try:
|
||||
o_key, o_val = o_arg.split('=', 1)
|
||||
o_key = o_key.strip()
|
||||
o_val = o_val.strip()
|
||||
except ValueError:
|
||||
opts[o_arg] = True
|
||||
else:
|
||||
opts[o_key] = o_val
|
||||
return opts
|
||||
|
||||
|
||||
def _parse_filters(f_strs):
|
||||
filters = []
|
||||
if not f_strs:
|
||||
return filters
|
||||
for f_str in f_strs:
|
||||
if ':' in f_str:
|
||||
fname, fopts = f_str.split(':', 1)
|
||||
filters.append((fname, _parse_options([fopts])))
|
||||
else:
|
||||
filters.append((f_str, {}))
|
||||
return filters
|
||||
|
||||
|
||||
def _print_help(what, name):
|
||||
try:
|
||||
if what == 'lexer':
|
||||
cls = get_lexer_by_name(name)
|
||||
print("Help on the %s lexer:" % cls.name)
|
||||
print(dedent(cls.__doc__))
|
||||
elif what == 'formatter':
|
||||
cls = find_formatter_class(name)
|
||||
print("Help on the %s formatter:" % cls.name)
|
||||
print(dedent(cls.__doc__))
|
||||
elif what == 'filter':
|
||||
cls = find_filter_class(name)
|
||||
print("Help on the %s filter:" % name)
|
||||
print(dedent(cls.__doc__))
|
||||
return 0
|
||||
except (AttributeError, ValueError):
|
||||
print("%s not found!" % what, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
|
||||
def _print_list(what):
|
||||
if what == 'lexer':
|
||||
print()
|
||||
print("Lexers:")
|
||||
print("~~~~~~~")
|
||||
|
||||
info = []
|
||||
for fullname, names, exts, _ in get_all_lexers():
|
||||
tup = (', '.join(names)+':', fullname,
|
||||
exts and '(filenames ' + ', '.join(exts) + ')' or '')
|
||||
info.append(tup)
|
||||
info.sort()
|
||||
for i in info:
|
||||
print(('* %s\n %s %s') % i)
|
||||
|
||||
elif what == 'formatter':
|
||||
print()
|
||||
print("Formatters:")
|
||||
print("~~~~~~~~~~~")
|
||||
|
||||
info = []
|
||||
for cls in get_all_formatters():
|
||||
doc = docstring_headline(cls)
|
||||
tup = (', '.join(cls.aliases) + ':', doc, cls.filenames and
|
||||
'(filenames ' + ', '.join(cls.filenames) + ')' or '')
|
||||
info.append(tup)
|
||||
info.sort()
|
||||
for i in info:
|
||||
print(('* %s\n %s %s') % i)
|
||||
|
||||
elif what == 'filter':
|
||||
print()
|
||||
print("Filters:")
|
||||
print("~~~~~~~~")
|
||||
|
||||
for name in get_all_filters():
|
||||
cls = find_filter_class(name)
|
||||
print("* " + name + ':')
|
||||
print(" %s" % docstring_headline(cls))
|
||||
|
||||
elif what == 'style':
|
||||
print()
|
||||
print("Styles:")
|
||||
print("~~~~~~~")
|
||||
|
||||
for name in get_all_styles():
|
||||
cls = get_style_by_name(name)
|
||||
print("* " + name + ':')
|
||||
print(" %s" % docstring_headline(cls))
|
||||
|
||||
|
||||
def _print_list_as_json(requested_items):
|
||||
import json
|
||||
result = {}
|
||||
if 'lexer' in requested_items:
|
||||
info = {}
|
||||
for fullname, names, filenames, mimetypes in get_all_lexers():
|
||||
info[fullname] = {
|
||||
'aliases': names,
|
||||
'filenames': filenames,
|
||||
'mimetypes': mimetypes
|
||||
}
|
||||
result['lexers'] = info
|
||||
|
||||
if 'formatter' in requested_items:
|
||||
info = {}
|
||||
for cls in get_all_formatters():
|
||||
doc = docstring_headline(cls)
|
||||
info[cls.name] = {
|
||||
'aliases': cls.aliases,
|
||||
'filenames': cls.filenames,
|
||||
'doc': doc
|
||||
}
|
||||
result['formatters'] = info
|
||||
|
||||
if 'filter' in requested_items:
|
||||
info = {}
|
||||
for name in get_all_filters():
|
||||
cls = find_filter_class(name)
|
||||
info[name] = {
|
||||
'doc': docstring_headline(cls)
|
||||
}
|
||||
result['filters'] = info
|
||||
|
||||
if 'style' in requested_items:
|
||||
info = {}
|
||||
for name in get_all_styles():
|
||||
cls = get_style_by_name(name)
|
||||
info[name] = {
|
||||
'doc': docstring_headline(cls)
|
||||
}
|
||||
result['styles'] = info
|
||||
|
||||
json.dump(result, sys.stdout)
|
||||
|
||||
def main_inner(parser, argns):
|
||||
if argns.help:
|
||||
parser.print_help()
|
||||
return 0
|
||||
|
||||
if argns.V:
|
||||
print('Pygments version %s, (c) 2006-2023 by Georg Brandl, Matthäus '
|
||||
'Chajdas and contributors.' % __version__)
|
||||
return 0
|
||||
|
||||
def is_only_option(opt):
|
||||
return not any(v for (k, v) in vars(argns).items() if k != opt)
|
||||
|
||||
# handle ``pygmentize -L``
|
||||
if argns.L is not None:
|
||||
arg_set = set()
|
||||
for k, v in vars(argns).items():
|
||||
if v:
|
||||
arg_set.add(k)
|
||||
|
||||
arg_set.discard('L')
|
||||
arg_set.discard('json')
|
||||
|
||||
if arg_set:
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
|
||||
# print version
|
||||
if not argns.json:
|
||||
main(['', '-V'])
|
||||
allowed_types = {'lexer', 'formatter', 'filter', 'style'}
|
||||
largs = [arg.rstrip('s') for arg in argns.L]
|
||||
if any(arg not in allowed_types for arg in largs):
|
||||
parser.print_help(sys.stderr)
|
||||
return 0
|
||||
if not largs:
|
||||
largs = allowed_types
|
||||
if not argns.json:
|
||||
for arg in largs:
|
||||
_print_list(arg)
|
||||
else:
|
||||
_print_list_as_json(largs)
|
||||
return 0
|
||||
|
||||
# handle ``pygmentize -H``
|
||||
if argns.H:
|
||||
if not is_only_option('H'):
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
what, name = argns.H
|
||||
if what not in ('lexer', 'formatter', 'filter'):
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
return _print_help(what, name)
|
||||
|
||||
# parse -O options
|
||||
parsed_opts = _parse_options(argns.O or [])
|
||||
|
||||
# parse -P options
|
||||
for p_opt in argns.P or []:
|
||||
try:
|
||||
name, value = p_opt.split('=', 1)
|
||||
except ValueError:
|
||||
parsed_opts[p_opt] = True
|
||||
else:
|
||||
parsed_opts[name] = value
|
||||
|
||||
# encodings
|
||||
inencoding = parsed_opts.get('inencoding', parsed_opts.get('encoding'))
|
||||
outencoding = parsed_opts.get('outencoding', parsed_opts.get('encoding'))
|
||||
|
||||
# handle ``pygmentize -N``
|
||||
if argns.N:
|
||||
lexer = find_lexer_class_for_filename(argns.N)
|
||||
if lexer is None:
|
||||
lexer = TextLexer
|
||||
|
||||
print(lexer.aliases[0])
|
||||
return 0
|
||||
|
||||
# handle ``pygmentize -C``
|
||||
if argns.C:
|
||||
inp = sys.stdin.buffer.read()
|
||||
try:
|
||||
lexer = guess_lexer(inp, inencoding=inencoding)
|
||||
except ClassNotFound:
|
||||
lexer = TextLexer
|
||||
|
||||
print(lexer.aliases[0])
|
||||
return 0
|
||||
|
||||
# handle ``pygmentize -S``
|
||||
S_opt = argns.S
|
||||
a_opt = argns.a
|
||||
if S_opt is not None:
|
||||
f_opt = argns.f
|
||||
if not f_opt:
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
if argns.l or argns.INPUTFILE:
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
|
||||
try:
|
||||
parsed_opts['style'] = S_opt
|
||||
fmter = get_formatter_by_name(f_opt, **parsed_opts)
|
||||
except ClassNotFound as err:
|
||||
print(err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
print(fmter.get_style_defs(a_opt or ''))
|
||||
return 0
|
||||
|
||||
# if no -S is given, -a is not allowed
|
||||
if argns.a is not None:
|
||||
parser.print_help(sys.stderr)
|
||||
return 2
|
||||
|
||||
# parse -F options
|
||||
F_opts = _parse_filters(argns.F or [])
|
||||
|
||||
# -x: allow custom (eXternal) lexers and formatters
|
||||
allow_custom_lexer_formatter = bool(argns.x)
|
||||
|
||||
# select lexer
|
||||
lexer = None
|
||||
|
||||
# given by name?
|
||||
lexername = argns.l
|
||||
if lexername:
|
||||
# custom lexer, located relative to user's cwd
|
||||
if allow_custom_lexer_formatter and '.py' in lexername:
|
||||
try:
|
||||
filename = None
|
||||
name = None
|
||||
if ':' in lexername:
|
||||
filename, name = lexername.rsplit(':', 1)
|
||||
|
||||
if '.py' in name:
|
||||
# This can happen on Windows: If the lexername is
|
||||
# C:\lexer.py -- return to normal load path in that case
|
||||
name = None
|
||||
|
||||
if filename and name:
|
||||
lexer = load_lexer_from_file(filename, name,
|
||||
**parsed_opts)
|
||||
else:
|
||||
lexer = load_lexer_from_file(lexername, **parsed_opts)
|
||||
except ClassNotFound as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
else:
|
||||
try:
|
||||
lexer = get_lexer_by_name(lexername, **parsed_opts)
|
||||
except (OptionError, ClassNotFound) as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# read input code
|
||||
code = None
|
||||
|
||||
if argns.INPUTFILE:
|
||||
if argns.s:
|
||||
print('Error: -s option not usable when input file specified',
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
|
||||
infn = argns.INPUTFILE
|
||||
try:
|
||||
with open(infn, 'rb') as infp:
|
||||
code = infp.read()
|
||||
except Exception as err:
|
||||
print('Error: cannot read infile:', err, file=sys.stderr)
|
||||
return 1
|
||||
if not inencoding:
|
||||
code, inencoding = guess_decode(code)
|
||||
|
||||
# do we have to guess the lexer?
|
||||
if not lexer:
|
||||
try:
|
||||
lexer = get_lexer_for_filename(infn, code, **parsed_opts)
|
||||
except ClassNotFound as err:
|
||||
if argns.g:
|
||||
try:
|
||||
lexer = guess_lexer(code, **parsed_opts)
|
||||
except ClassNotFound:
|
||||
lexer = TextLexer(**parsed_opts)
|
||||
else:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
except OptionError as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
elif not argns.s: # treat stdin as full file (-s support is later)
|
||||
# read code from terminal, always in binary mode since we want to
|
||||
# decode ourselves and be tolerant with it
|
||||
code = sys.stdin.buffer.read() # use .buffer to get a binary stream
|
||||
if not inencoding:
|
||||
code, inencoding = guess_decode_from_terminal(code, sys.stdin)
|
||||
# else the lexer will do the decoding
|
||||
if not lexer:
|
||||
try:
|
||||
lexer = guess_lexer(code, **parsed_opts)
|
||||
except ClassNotFound:
|
||||
lexer = TextLexer(**parsed_opts)
|
||||
|
||||
else: # -s option needs a lexer with -l
|
||||
if not lexer:
|
||||
print('Error: when using -s a lexer has to be selected with -l',
|
||||
file=sys.stderr)
|
||||
return 2
|
||||
|
||||
# process filters
|
||||
for fname, fopts in F_opts:
|
||||
try:
|
||||
lexer.add_filter(fname, **fopts)
|
||||
except ClassNotFound as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
# select formatter
|
||||
outfn = argns.o
|
||||
fmter = argns.f
|
||||
if fmter:
|
||||
# custom formatter, located relative to user's cwd
|
||||
if allow_custom_lexer_formatter and '.py' in fmter:
|
||||
try:
|
||||
filename = None
|
||||
name = None
|
||||
if ':' in fmter:
|
||||
# Same logic as above for custom lexer
|
||||
filename, name = fmter.rsplit(':', 1)
|
||||
|
||||
if '.py' in name:
|
||||
name = None
|
||||
|
||||
if filename and name:
|
||||
fmter = load_formatter_from_file(filename, name,
|
||||
**parsed_opts)
|
||||
else:
|
||||
fmter = load_formatter_from_file(fmter, **parsed_opts)
|
||||
except ClassNotFound as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
else:
|
||||
try:
|
||||
fmter = get_formatter_by_name(fmter, **parsed_opts)
|
||||
except (OptionError, ClassNotFound) as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
|
||||
if outfn:
|
||||
if not fmter:
|
||||
try:
|
||||
fmter = get_formatter_for_filename(outfn, **parsed_opts)
|
||||
except (OptionError, ClassNotFound) as err:
|
||||
print('Error:', err, file=sys.stderr)
|
||||
return 1
|
||||
try:
|
||||
outfile = open(outfn, 'wb')
|
||||
except Exception as err:
|
||||
print('Error: cannot open outfile:', err, file=sys.stderr)
|
||||
return 1
|
||||
else:
|
||||
if not fmter:
|
||||
if os.environ.get('COLORTERM','') in ('truecolor', '24bit'):
|
||||
fmter = TerminalTrueColorFormatter(**parsed_opts)
|
||||
elif '256' in os.environ.get('TERM', ''):
|
||||
fmter = Terminal256Formatter(**parsed_opts)
|
||||
else:
|
||||
fmter = TerminalFormatter(**parsed_opts)
|
||||
outfile = sys.stdout.buffer
|
||||
|
||||
# determine output encoding if not explicitly selected
|
||||
if not outencoding:
|
||||
if outfn:
|
||||
# output file? use lexer encoding for now (can still be None)
|
||||
fmter.encoding = inencoding
|
||||
else:
|
||||
# else use terminal encoding
|
||||
fmter.encoding = terminal_encoding(sys.stdout)
|
||||
|
||||
# provide coloring under Windows, if possible
|
||||
if not outfn and sys.platform in ('win32', 'cygwin') and \
|
||||
fmter.name in ('Terminal', 'Terminal256'): # pragma: no cover
|
||||
# unfortunately colorama doesn't support binary streams on Py3
|
||||
outfile = UnclosingTextIOWrapper(outfile, encoding=fmter.encoding)
|
||||
fmter.encoding = None
|
||||
try:
|
||||
import pip._vendor.colorama.initialise as colorama_initialise
|
||||
except ImportError:
|
||||
pass
|
||||
else:
|
||||
outfile = colorama_initialise.wrap_stream(
|
||||
outfile, convert=None, strip=None, autoreset=False, wrap=True)
|
||||
|
||||
# When using the LaTeX formatter and the option `escapeinside` is
|
||||
# specified, we need a special lexer which collects escaped text
|
||||
# before running the chosen language lexer.
|
||||
escapeinside = parsed_opts.get('escapeinside', '')
|
||||
if len(escapeinside) == 2 and isinstance(fmter, LatexFormatter):
|
||||
left = escapeinside[0]
|
||||
right = escapeinside[1]
|
||||
lexer = LatexEmbeddedLexer(left, right, lexer)
|
||||
|
||||
# ... and do it!
|
||||
if not argns.s:
|
||||
# process whole input as per normal...
|
||||
try:
|
||||
highlight(code, lexer, fmter, outfile)
|
||||
finally:
|
||||
if outfn:
|
||||
outfile.close()
|
||||
return 0
|
||||
else:
|
||||
# line by line processing of stdin (eg: for 'tail -f')...
|
||||
try:
|
||||
while 1:
|
||||
line = sys.stdin.buffer.readline()
|
||||
if not line:
|
||||
break
|
||||
if not inencoding:
|
||||
line = guess_decode_from_terminal(line, sys.stdin)[0]
|
||||
highlight(line, lexer, fmter, outfile)
|
||||
if hasattr(outfile, 'flush'):
|
||||
outfile.flush()
|
||||
return 0
|
||||
except KeyboardInterrupt: # pragma: no cover
|
||||
return 0
|
||||
finally:
|
||||
if outfn:
|
||||
outfile.close()
|
||||
|
||||
|
||||
class HelpFormatter(argparse.HelpFormatter):
|
||||
def __init__(self, prog, indent_increment=2, max_help_position=16, width=None):
|
||||
if width is None:
|
||||
try:
|
||||
width = shutil.get_terminal_size().columns - 2
|
||||
except Exception:
|
||||
pass
|
||||
argparse.HelpFormatter.__init__(self, prog, indent_increment,
|
||||
max_help_position, width)
|
||||
|
||||
|
||||
def main(args=sys.argv):
|
||||
"""
|
||||
Main command line entry point.
|
||||
"""
|
||||
desc = "Highlight an input file and write the result to an output file."
|
||||
parser = argparse.ArgumentParser(description=desc, add_help=False,
|
||||
formatter_class=HelpFormatter)
|
||||
|
||||
operation = parser.add_argument_group('Main operation')
|
||||
lexersel = operation.add_mutually_exclusive_group()
|
||||
lexersel.add_argument(
|
||||
'-l', metavar='LEXER',
|
||||
help='Specify the lexer to use. (Query names with -L.) If not '
|
||||
'given and -g is not present, the lexer is guessed from the filename.')
|
||||
lexersel.add_argument(
|
||||
'-g', action='store_true',
|
||||
help='Guess the lexer from the file contents, or pass through '
|
||||
'as plain text if nothing can be guessed.')
|
||||
operation.add_argument(
|
||||
'-F', metavar='FILTER[:options]', action='append',
|
||||
help='Add a filter to the token stream. (Query names with -L.) '
|
||||
'Filter options are given after a colon if necessary.')
|
||||
operation.add_argument(
|
||||
'-f', metavar='FORMATTER',
|
||||
help='Specify the formatter to use. (Query names with -L.) '
|
||||
'If not given, the formatter is guessed from the output filename, '
|
||||
'and defaults to the terminal formatter if the output is to the '
|
||||
'terminal or an unknown file extension.')
|
||||
operation.add_argument(
|
||||
'-O', metavar='OPTION=value[,OPTION=value,...]', action='append',
|
||||
help='Give options to the lexer and formatter as a comma-separated '
|
||||
'list of key-value pairs. '
|
||||
'Example: `-O bg=light,python=cool`.')
|
||||
operation.add_argument(
|
||||
'-P', metavar='OPTION=value', action='append',
|
||||
help='Give a single option to the lexer and formatter - with this '
|
||||
'you can pass options whose value contains commas and equal signs. '
|
||||
'Example: `-P "heading=Pygments, the Python highlighter"`.')
|
||||
operation.add_argument(
|
||||
'-o', metavar='OUTPUTFILE',
|
||||
help='Where to write the output. Defaults to standard output.')
|
||||
|
||||
operation.add_argument(
|
||||
'INPUTFILE', nargs='?',
|
||||
help='Where to read the input. Defaults to standard input.')
|
||||
|
||||
flags = parser.add_argument_group('Operation flags')
|
||||
flags.add_argument(
|
||||
'-v', action='store_true',
|
||||
help='Print a detailed traceback on unhandled exceptions, which '
|
||||
'is useful for debugging and bug reports.')
|
||||
flags.add_argument(
|
||||
'-s', action='store_true',
|
||||
help='Process lines one at a time until EOF, rather than waiting to '
|
||||
'process the entire file. This only works for stdin, only for lexers '
|
||||
'with no line-spanning constructs, and is intended for streaming '
|
||||
'input such as you get from `tail -f`. '
|
||||
'Example usage: `tail -f sql.log | pygmentize -s -l sql`.')
|
||||
flags.add_argument(
|
||||
'-x', action='store_true',
|
||||
help='Allow custom lexers and formatters to be loaded from a .py file '
|
||||
'relative to the current working directory. For example, '
|
||||
'`-l ./customlexer.py -x`. By default, this option expects a file '
|
||||
'with a class named CustomLexer or CustomFormatter; you can also '
|
||||
'specify your own class name with a colon (`-l ./lexer.py:MyLexer`). '
|
||||
'Users should be very careful not to use this option with untrusted '
|
||||
'files, because it will import and run them.')
|
||||
flags.add_argument('--json', help='Output as JSON. This can '
|
||||
'be only used in conjunction with -L.',
|
||||
default=False,
|
||||
action='store_true')
|
||||
|
||||
special_modes_group = parser.add_argument_group(
|
||||
'Special modes - do not do any highlighting')
|
||||
special_modes = special_modes_group.add_mutually_exclusive_group()
|
||||
special_modes.add_argument(
|
||||
'-S', metavar='STYLE -f formatter',
|
||||
help='Print style definitions for STYLE for a formatter '
|
||||
'given with -f. The argument given by -a is formatter '
|
||||
'dependent.')
|
||||
special_modes.add_argument(
|
||||
'-L', nargs='*', metavar='WHAT',
|
||||
help='List lexers, formatters, styles or filters -- '
|
||||
'give additional arguments for the thing(s) you want to list '
|
||||
'(e.g. "styles"), or omit them to list everything.')
|
||||
special_modes.add_argument(
|
||||
'-N', metavar='FILENAME',
|
||||
help='Guess and print out a lexer name based solely on the given '
|
||||
'filename. Does not take input or highlight anything. If no specific '
|
||||
'lexer can be determined, "text" is printed.')
|
||||
special_modes.add_argument(
|
||||
'-C', action='store_true',
|
||||
help='Like -N, but print out a lexer name based solely on '
|
||||
'a given content from standard input.')
|
||||
special_modes.add_argument(
|
||||
'-H', action='store', nargs=2, metavar=('NAME', 'TYPE'),
|
||||
help='Print detailed help for the object <name> of type <type>, '
|
||||
'where <type> is one of "lexer", "formatter" or "filter".')
|
||||
special_modes.add_argument(
|
||||
'-V', action='store_true',
|
||||
help='Print the package version.')
|
||||
special_modes.add_argument(
|
||||
'-h', '--help', action='store_true',
|
||||
help='Print this help.')
|
||||
special_modes_group.add_argument(
|
||||
'-a', metavar='ARG',
|
||||
help='Formatter-specific additional argument for the -S (print '
|
||||
'style sheet) mode.')
|
||||
|
||||
argns = parser.parse_args(args[1:])
|
||||
|
||||
try:
|
||||
return main_inner(parser, argns)
|
||||
except BrokenPipeError:
|
||||
# someone closed our stdout, e.g. by quitting a pager.
|
||||
return 0
|
||||
except Exception:
|
||||
if argns.v:
|
||||
print(file=sys.stderr)
|
||||
print('*' * 65, file=sys.stderr)
|
||||
print('An unhandled exception occurred while highlighting.',
|
||||
file=sys.stderr)
|
||||
print('Please report the whole traceback to the issue tracker at',
|
||||
file=sys.stderr)
|
||||
print('<https://github.com/pygments/pygments/issues>.',
|
||||
file=sys.stderr)
|
||||
print('*' * 65, file=sys.stderr)
|
||||
print(file=sys.stderr)
|
||||
raise
|
||||
import traceback
|
||||
info = traceback.format_exception(*sys.exc_info())
|
||||
msg = info[-1].strip()
|
||||
if len(info) >= 3:
|
||||
# extract relevant file and position info
|
||||
msg += '\n (f%s)' % info[-2].split('\n')[0].strip()[1:]
|
||||
print(file=sys.stderr)
|
||||
print('*** Error while highlighting:', file=sys.stderr)
|
||||
print(msg, file=sys.stderr)
|
||||
print('*** If this is a bug you want to report, please rerun with -v.',
|
||||
file=sys.stderr)
|
||||
return 1
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Format colored console output.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -27,12 +27,12 @@ light_colors = ["brightblack", "brightred", "brightgreen", "brightyellow", "brig
|
|||
"brightmagenta", "brightcyan", "white"]
|
||||
|
||||
x = 30
|
||||
for dark, light in zip(dark_colors, light_colors):
|
||||
codes[dark] = esc + "%im" % x
|
||||
codes[light] = esc + "%im" % (60 + x)
|
||||
for d, l in zip(dark_colors, light_colors):
|
||||
codes[d] = esc + "%im" % x
|
||||
codes[l] = esc + "%im" % (60 + x)
|
||||
x += 1
|
||||
|
||||
del dark, light, x
|
||||
del d, l, x
|
||||
|
||||
codes["white"] = codes["bold"]
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Module that implements the default filter.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -62,7 +62,8 @@ class FunctionFilter(Filter):
|
|||
|
||||
def __init__(self, **options):
|
||||
if not hasattr(self, 'function'):
|
||||
raise TypeError(f'{self.__class__.__name__!r} used without bound function')
|
||||
raise TypeError('%r used without bound function' %
|
||||
self.__class__.__name__)
|
||||
Filter.__init__(self, **options)
|
||||
|
||||
def filter(self, lexer, stream):
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Module containing filter lookup functions and default
|
||||
filters.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -39,7 +39,7 @@ def get_filter_by_name(filtername, **options):
|
|||
if cls:
|
||||
return cls(**options)
|
||||
else:
|
||||
raise ClassNotFound(f'filter {filtername!r} not found')
|
||||
raise ClassNotFound('filter %r not found' % filtername)
|
||||
|
||||
|
||||
def get_all_filters():
|
||||
|
|
@ -79,9 +79,9 @@ class CodeTagFilter(Filter):
|
|||
Filter.__init__(self, **options)
|
||||
tags = get_list_opt(options, 'codetags',
|
||||
['XXX', 'TODO', 'FIXME', 'BUG', 'NOTE'])
|
||||
self.tag_re = re.compile(r'\b({})\b'.format('|'.join([
|
||||
self.tag_re = re.compile(r'\b(%s)\b' % '|'.join([
|
||||
re.escape(tag) for tag in tags if tag
|
||||
])))
|
||||
]))
|
||||
|
||||
def filter(self, lexer, stream):
|
||||
regex = self.tag_re
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Base formatter class.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -122,8 +122,3 @@ class Formatter:
|
|||
# wrap the outfile in a StreamWriter
|
||||
outfile = codecs.lookup(self.encoding)[3](outfile)
|
||||
return self.format_unencoded(tokensource, outfile)
|
||||
|
||||
# Allow writing Formatter[str] or Formatter[bytes]. That's equivalent to
|
||||
# Formatter. This helps when using third-party type stubs from typeshed.
|
||||
def __class_getitem__(cls, name):
|
||||
return cls
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Pygments formatters.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -77,7 +77,7 @@ def get_formatter_by_name(_alias, **options):
|
|||
"""
|
||||
cls = find_formatter_class(_alias)
|
||||
if cls is None:
|
||||
raise ClassNotFound(f"no formatter found for name {_alias!r}")
|
||||
raise ClassNotFound("no formatter found for name %r" % _alias)
|
||||
return cls(**options)
|
||||
|
||||
|
||||
|
|
@ -103,16 +103,17 @@ def load_formatter_from_file(filename, formattername="CustomFormatter", **option
|
|||
exec(f.read(), custom_namespace)
|
||||
# Retrieve the class `formattername` from that namespace
|
||||
if formattername not in custom_namespace:
|
||||
raise ClassNotFound(f'no valid {formattername} class found in {filename}')
|
||||
raise ClassNotFound('no valid %s class found in %s' %
|
||||
(formattername, filename))
|
||||
formatter_class = custom_namespace[formattername]
|
||||
# And finally instantiate it with the options
|
||||
return formatter_class(**options)
|
||||
except OSError as err:
|
||||
raise ClassNotFound(f'cannot read {filename}: {err}')
|
||||
raise ClassNotFound('cannot read %s: %s' % (filename, err))
|
||||
except ClassNotFound:
|
||||
raise
|
||||
except Exception as err:
|
||||
raise ClassNotFound(f'error when loading custom formatter: {err}')
|
||||
raise ClassNotFound('error when loading custom formatter: %s' % err)
|
||||
|
||||
|
||||
def get_formatter_for_filename(fn, **options):
|
||||
|
|
@ -130,11 +131,11 @@ def get_formatter_for_filename(fn, **options):
|
|||
if name not in _formatter_cache:
|
||||
_load_formatters(modname)
|
||||
return _formatter_cache[name](**options)
|
||||
for _name, cls in find_plugin_formatters():
|
||||
for cls in find_plugin_formatters():
|
||||
for filename in cls.filenames:
|
||||
if _fn_matches(fn, filename):
|
||||
return cls(**options)
|
||||
raise ClassNotFound(f"no formatter found for file name {fn!r}")
|
||||
raise ClassNotFound("no formatter found for file name %r" % fn)
|
||||
|
||||
|
||||
class _automodule(types.ModuleType):
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -0,0 +1,108 @@
|
|||
"""
|
||||
pygments.formatters.bbcode
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
BBcode formatter.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.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')
|
||||
|
|
@ -0,0 +1,170 @@
|
|||
"""
|
||||
pygments.formatters.groff
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for groff output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import math
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.util import get_bool_opt, get_int_opt
|
||||
|
||||
__all__ = ['GroffFormatter']
|
||||
|
||||
|
||||
class GroffFormatter(Formatter):
|
||||
"""
|
||||
Format tokens with groff escapes to change their color and font style.
|
||||
|
||||
.. versionadded:: 2.11
|
||||
|
||||
Additional options accepted:
|
||||
|
||||
`style`
|
||||
The style to use, can be a string or a Style subclass (default:
|
||||
``'default'``).
|
||||
|
||||
`monospaced`
|
||||
If set to true, monospace font will be used (default: ``true``).
|
||||
|
||||
`linenos`
|
||||
If set to true, print the line numbers (default: ``false``).
|
||||
|
||||
`wrap`
|
||||
Wrap lines to the specified number of characters. Disabled if set to 0
|
||||
(default: ``0``).
|
||||
"""
|
||||
|
||||
name = 'groff'
|
||||
aliases = ['groff','troff','roff']
|
||||
filenames = []
|
||||
|
||||
def __init__(self, **options):
|
||||
Formatter.__init__(self, **options)
|
||||
|
||||
self.monospaced = get_bool_opt(options, 'monospaced', True)
|
||||
self.linenos = get_bool_opt(options, 'linenos', False)
|
||||
self._lineno = 0
|
||||
self.wrap = get_int_opt(options, 'wrap', 0)
|
||||
self._linelen = 0
|
||||
|
||||
self.styles = {}
|
||||
self._make_styles()
|
||||
|
||||
|
||||
def _make_styles(self):
|
||||
regular = '\\f[CR]' if self.monospaced else '\\f[R]'
|
||||
bold = '\\f[CB]' if self.monospaced else '\\f[B]'
|
||||
italic = '\\f[CI]' if self.monospaced else '\\f[I]'
|
||||
|
||||
for ttype, ndef in self.style:
|
||||
start = end = ''
|
||||
if ndef['color']:
|
||||
start += '\\m[%s]' % ndef['color']
|
||||
end = '\\m[]' + end
|
||||
if ndef['bold']:
|
||||
start += bold
|
||||
end = regular + end
|
||||
if ndef['italic']:
|
||||
start += italic
|
||||
end = regular + end
|
||||
if ndef['bgcolor']:
|
||||
start += '\\M[%s]' % ndef['bgcolor']
|
||||
end = '\\M[]' + end
|
||||
|
||||
self.styles[ttype] = start, end
|
||||
|
||||
|
||||
def _define_colors(self, outfile):
|
||||
colors = set()
|
||||
for _, ndef in self.style:
|
||||
if ndef['color'] is not None:
|
||||
colors.add(ndef['color'])
|
||||
|
||||
for color in sorted(colors):
|
||||
outfile.write('.defcolor ' + color + ' rgb #' + color + '\n')
|
||||
|
||||
|
||||
def _write_lineno(self, outfile):
|
||||
self._lineno += 1
|
||||
outfile.write("%s% 4d " % (self._lineno != 1 and '\n' or '', self._lineno))
|
||||
|
||||
|
||||
def _wrap_line(self, line):
|
||||
length = len(line.rstrip('\n'))
|
||||
space = ' ' if self.linenos else ''
|
||||
newline = ''
|
||||
|
||||
if length > self.wrap:
|
||||
for i in range(0, math.floor(length / self.wrap)):
|
||||
chunk = line[i*self.wrap:i*self.wrap+self.wrap]
|
||||
newline += (chunk + '\n' + space)
|
||||
remainder = length % self.wrap
|
||||
if remainder > 0:
|
||||
newline += line[-remainder-1:]
|
||||
self._linelen = remainder
|
||||
elif self._linelen + length > self.wrap:
|
||||
newline = ('\n' + space) + line
|
||||
self._linelen = length
|
||||
else:
|
||||
newline = line
|
||||
self._linelen += length
|
||||
|
||||
return newline
|
||||
|
||||
|
||||
def _escape_chars(self, text):
|
||||
text = text.replace('\\', '\\[u005C]'). \
|
||||
replace('.', '\\[char46]'). \
|
||||
replace('\'', '\\[u0027]'). \
|
||||
replace('`', '\\[u0060]'). \
|
||||
replace('~', '\\[u007E]')
|
||||
copy = text
|
||||
|
||||
for char in copy:
|
||||
if len(char) != len(char.encode()):
|
||||
uni = char.encode('unicode_escape') \
|
||||
.decode()[1:] \
|
||||
.replace('x', 'u00') \
|
||||
.upper()
|
||||
text = text.replace(char, '\\[u' + uni[1:] + ']')
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def format_unencoded(self, tokensource, outfile):
|
||||
self._define_colors(outfile)
|
||||
|
||||
outfile.write('.nf\n\\f[CR]\n')
|
||||
|
||||
if self.linenos:
|
||||
self._write_lineno(outfile)
|
||||
|
||||
for ttype, value in tokensource:
|
||||
while ttype not in self.styles:
|
||||
ttype = ttype.parent
|
||||
start, end = self.styles[ttype]
|
||||
|
||||
for line in value.splitlines(True):
|
||||
if self.wrap > 0:
|
||||
line = self._wrap_line(line)
|
||||
|
||||
if start and end:
|
||||
text = self._escape_chars(line.rstrip('\n'))
|
||||
if text != '':
|
||||
outfile.write(''.join((start, text, end)))
|
||||
else:
|
||||
outfile.write(self._escape_chars(line.rstrip('\n')))
|
||||
|
||||
if line.endswith('\n'):
|
||||
if self.linenos:
|
||||
self._write_lineno(outfile)
|
||||
self._linelen = 0
|
||||
else:
|
||||
outfile.write('\n')
|
||||
self._linelen = 0
|
||||
|
||||
outfile.write('\n.fi')
|
||||
|
|
@ -0,0 +1,989 @@
|
|||
"""
|
||||
pygments.formatters.html
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for HTML output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import functools
|
||||
import os
|
||||
import sys
|
||||
import os.path
|
||||
from io import StringIO
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.token import Token, Text, STANDARD_TYPES
|
||||
from pip._vendor.pygments.util import get_bool_opt, get_int_opt, get_list_opt
|
||||
|
||||
try:
|
||||
import ctags
|
||||
except ImportError:
|
||||
ctags = None
|
||||
|
||||
__all__ = ['HtmlFormatter']
|
||||
|
||||
|
||||
_escape_html_table = {
|
||||
ord('&'): '&',
|
||||
ord('<'): '<',
|
||||
ord('>'): '>',
|
||||
ord('"'): '"',
|
||||
ord("'"): ''',
|
||||
}
|
||||
|
||||
|
||||
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 = '''\
|
||||
/*
|
||||
generated by Pygments <https://pygments.org/>
|
||||
Copyright 2006-2023 by the Pygments team.
|
||||
Licensed under the BSD license, see LICENSE for details.
|
||||
*/
|
||||
%(styledefs)s
|
||||
'''
|
||||
|
||||
DOC_HEADER = '''\
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
|
||||
"http://www.w3.org/TR/html4/strict.dtd">
|
||||
<!--
|
||||
generated by Pygments <https://pygments.org/>
|
||||
Copyright 2006-2023 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. By default, the content is enclosed
|
||||
in a ``<pre>`` tag, itself wrapped in a ``<div>`` tag (but see the `nowrap` option).
|
||||
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).
|
||||
|
||||
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 add a ``<pre>`` and a ``<div>`` tag
|
||||
around the tokens. 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 (as well as line number elements)
|
||||
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. The line numbers are always
|
||||
relative to the input (i.e. the first line is line 1) and are
|
||||
independent of `linenostart`.
|
||||
|
||||
.. 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 an ``id`` (and `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. If `linenos` is set to
|
||||
``'table'`` then the filename will be rendered in an initial row
|
||||
containing a single `<th>` which spans both columns.
|
||||
|
||||
.. versionadded:: 2.1
|
||||
|
||||
`wrapcode`
|
||||
Wrap the code inside ``<pre>`` blocks using ``<code>``, as recommended
|
||||
by the HTML5 specification.
|
||||
|
||||
.. versionadded:: 2.4
|
||||
|
||||
`debug_token_types`
|
||||
Add ``title`` attributes to all token ``<span>`` tags that show the
|
||||
name of the token.
|
||||
|
||||
.. versionadded:: 2.10
|
||||
|
||||
|
||||
**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, *, include_div):
|
||||
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)
|
||||
self.span_element_openers = {}
|
||||
self.debug_token_types = get_bool_opt(options, 'debug_token_types', 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', '\n')
|
||||
self.lineanchors = options.get('lineanchors', '')
|
||||
self.linespans = options.get('linespans', '')
|
||||
self.anchorlinenos = get_bool_opt(options, '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 or ''
|
||||
|
||||
def _get_css_inline_styles(self, ttype):
|
||||
"""Return the inline CSS styles for this token type."""
|
||||
cclass = self.ttype2class.get(ttype)
|
||||
while cclass is None:
|
||||
ttype = ttype.parent
|
||||
cclass = self.ttype2class.get(ttype)
|
||||
return cclass or ''
|
||||
|
||||
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']:
|
||||
style += 'background-color: %s; ' % webify(ndef['bgcolor'])
|
||||
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.
|
||||
"""
|
||||
style_lines = []
|
||||
|
||||
style_lines.extend(self.get_linenos_style_defs())
|
||||
style_lines.extend(self.get_background_style_defs(arg))
|
||||
style_lines.extend(self.get_token_style_defs(arg))
|
||||
|
||||
return '\n'.join(style_lines)
|
||||
|
||||
def get_token_style_defs(self, arg=None):
|
||||
prefix = self.get_css_prefix(arg)
|
||||
|
||||
styles = [
|
||||
(level, ttype, cls, style)
|
||||
for cls, (style, ttype, level) in self.class2style.items()
|
||||
if cls and style
|
||||
]
|
||||
styles.sort()
|
||||
|
||||
lines = [
|
||||
'%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:])
|
||||
for (level, ttype, cls, style) in styles
|
||||
]
|
||||
|
||||
return lines
|
||||
|
||||
def get_background_style_defs(self, arg=None):
|
||||
prefix = self.get_css_prefix(arg)
|
||||
bg_color = self.style.background_color
|
||||
hl_color = self.style.highlight_color
|
||||
|
||||
lines = []
|
||||
|
||||
if arg and not self.nobackground and bg_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(''), bg_color, text_style
|
||||
)
|
||||
)
|
||||
if hl_color is not None:
|
||||
lines.insert(
|
||||
0, '%s { background-color: %s }' % (prefix('hll'), hl_color)
|
||||
)
|
||||
|
||||
return lines
|
||||
|
||||
def get_linenos_style_defs(self):
|
||||
lines = [
|
||||
'pre { %s }' % self._pre_style,
|
||||
'td.linenos .normal { %s }' % self._linenos_style,
|
||||
'span.linenos { %s }' % self._linenos_style,
|
||||
'td.linenos .special { %s }' % self._linenos_special_style,
|
||||
'span.linenos.special { %s }' % self._linenos_special_style,
|
||||
]
|
||||
|
||||
return lines
|
||||
|
||||
def get_css_prefix(self, arg):
|
||||
if arg is None:
|
||||
arg = ('cssclass' in self.options and '.'+self.cssclass or '')
|
||||
if isinstance(arg, str):
|
||||
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)
|
||||
|
||||
return prefix
|
||||
|
||||
@property
|
||||
def _pre_style(self):
|
||||
return 'line-height: 125%;'
|
||||
|
||||
@property
|
||||
def _linenos_style(self):
|
||||
return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % (
|
||||
self.style.line_number_color,
|
||||
self.style.line_number_background_color
|
||||
)
|
||||
|
||||
@property
|
||||
def _linenos_special_style(self):
|
||||
return 'color: %s; background-color: %s; padding-left: 5px; padding-right: 5px;' % (
|
||||
self.style.line_number_special_color,
|
||||
self.style.line_number_special_background_color
|
||||
)
|
||||
|
||||
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", encoding="utf-8") as cf:
|
||||
cf.write(CSSFILE_TEMPLATE %
|
||||
{'styledefs': self.get_style_defs('body')})
|
||||
except OSError 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))
|
||||
|
||||
yield from inner
|
||||
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
|
||||
anchor_name = self.lineanchors or self.linespans
|
||||
aln = self.anchorlinenos
|
||||
nocls = self.noclasses
|
||||
|
||||
lines = []
|
||||
|
||||
for i in range(fl, fl+lncount):
|
||||
print_line = i % st == 0
|
||||
special_line = sp and i % sp == 0
|
||||
|
||||
if print_line:
|
||||
line = '%*d' % (mw, i)
|
||||
if aln:
|
||||
line = '<a href="#%s-%d">%s</a>' % (anchor_name, i, line)
|
||||
else:
|
||||
line = ' ' * mw
|
||||
|
||||
if nocls:
|
||||
if special_line:
|
||||
style = ' style="%s"' % self._linenos_special_style
|
||||
else:
|
||||
style = ' style="%s"' % self._linenos_style
|
||||
else:
|
||||
if special_line:
|
||||
style = ' class="special"'
|
||||
else:
|
||||
style = ' class="normal"'
|
||||
|
||||
if style:
|
||||
line = '<span%s>%s</span>' % (style, line)
|
||||
|
||||
lines.append(line)
|
||||
|
||||
ls = '\n'.join(lines)
|
||||
|
||||
# If a filename was specified, we can't put it into the code table as it
|
||||
# would misalign the line numbers. Hence we emit a separate row for it.
|
||||
filename_tr = ""
|
||||
if self.filename:
|
||||
filename_tr = (
|
||||
'<tr><th colspan="2" class="filename">'
|
||||
'<span class="filename">' + self.filename + '</span>'
|
||||
'</th></tr>')
|
||||
|
||||
# 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...
|
||||
yield 0, (f'<table class="{self.cssclass}table">' + filename_tr +
|
||||
'<tr><td class="linenos"><div class="linenodiv"><pre>' +
|
||||
ls + '</pre></div></td><td class="code">')
|
||||
yield 0, '<div>'
|
||||
yield 0, dummyoutfile.getvalue()
|
||||
yield 0, '</div>'
|
||||
yield 0, '</td></tr></table>'
|
||||
|
||||
|
||||
def _wrap_inlinelinenos(self, inner):
|
||||
# need a list of lines since we need the width of a single number :(
|
||||
inner_lines = list(inner)
|
||||
sp = self.linenospecial
|
||||
st = self.linenostep
|
||||
num = self.linenostart
|
||||
mw = len(str(len(inner_lines) + num - 1))
|
||||
anchor_name = self.lineanchors or self.linespans
|
||||
aln = self.anchorlinenos
|
||||
nocls = self.noclasses
|
||||
|
||||
for _, inner_line in inner_lines:
|
||||
print_line = num % st == 0
|
||||
special_line = sp and num % sp == 0
|
||||
|
||||
if print_line:
|
||||
line = '%*d' % (mw, num)
|
||||
else:
|
||||
line = ' ' * mw
|
||||
|
||||
if nocls:
|
||||
if special_line:
|
||||
style = ' style="%s"' % self._linenos_special_style
|
||||
else:
|
||||
style = ' style="%s"' % self._linenos_style
|
||||
else:
|
||||
if special_line:
|
||||
style = ' class="linenos special"'
|
||||
else:
|
||||
style = ' class="linenos"'
|
||||
|
||||
if style:
|
||||
linenos = '<span%s>%s</span>' % (style, line)
|
||||
else:
|
||||
linenos = line
|
||||
|
||||
if aln:
|
||||
yield 1, ('<a href="#%s-%d">%s</a>' % (anchor_name, num, linenos) +
|
||||
inner_line)
|
||||
else:
|
||||
yield 1, linenos + inner_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
|
||||
href = "" if self.linenos else ' href="#%s-%d"' % (s, i)
|
||||
yield 1, '<a id="%s-%d" name="%s-%d"%s></a>' % (s, i, s, i, href) + 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)) + '>')
|
||||
yield from inner
|
||||
yield 0, '</div>\n'
|
||||
|
||||
def _wrap_pre(self, inner):
|
||||
style = []
|
||||
if self.prestyles:
|
||||
style.append(self.prestyles)
|
||||
if self.noclasses:
|
||||
style.append(self._pre_style)
|
||||
style = '; '.join(style)
|
||||
|
||||
if self.filename and self.linenos != 1:
|
||||
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>')
|
||||
yield from inner
|
||||
yield 0, '</pre>'
|
||||
|
||||
def _wrap_code(self, inner):
|
||||
yield 0, '<code>'
|
||||
yield from inner
|
||||
yield 0, '</code>'
|
||||
|
||||
@functools.lru_cache(maxsize=100)
|
||||
def _translate_parts(self, value):
|
||||
"""HTML-escape a value and split it by newlines."""
|
||||
return value.translate(_escape_html_table).split('\n')
|
||||
|
||||
def _format_lines(self, tokensource):
|
||||
"""
|
||||
Just format the tokens, without any wrapping tags.
|
||||
Yield individual lines.
|
||||
"""
|
||||
nocls = self.noclasses
|
||||
lsep = self.lineseparator
|
||||
tagsfile = self.tagsfile
|
||||
|
||||
lspan = ''
|
||||
line = []
|
||||
for ttype, value in tokensource:
|
||||
try:
|
||||
cspan = self.span_element_openers[ttype]
|
||||
except KeyError:
|
||||
title = ' title="%s"' % '.'.join(ttype) if self.debug_token_types else ''
|
||||
if nocls:
|
||||
css_style = self._get_css_inline_styles(ttype)
|
||||
if css_style:
|
||||
css_style = self.class2style[css_style][0]
|
||||
cspan = '<span style="%s"%s>' % (css_style, title)
|
||||
else:
|
||||
cspan = ''
|
||||
else:
|
||||
css_class = self._get_css_classes(ttype)
|
||||
if css_class:
|
||||
cspan = '<span class="%s"%s>' % (css_class, title)
|
||||
else:
|
||||
cspan = ''
|
||||
self.span_element_openers[ttype] = cspan
|
||||
|
||||
parts = self._translate_parts(value)
|
||||
|
||||
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:
|
||||
# Also check for part being non-empty, so we avoid creating
|
||||
# empty <span> tags
|
||||
if lspan != cspan and part:
|
||||
line.extend(((lspan and '</span>'), cspan, part,
|
||||
(cspan and '</span>'), lsep))
|
||||
else: # both are the same, or the current part was empty
|
||||
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.encode(), 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):
|
||||
"""
|
||||
Wrap the ``source``, which is a generator yielding
|
||||
individual lines, in custom generators. See docstring
|
||||
for `format`. Can be overridden.
|
||||
"""
|
||||
|
||||
output = source
|
||||
if self.wrapcode:
|
||||
output = self._wrap_code(output)
|
||||
|
||||
output = self._wrap_pre(output)
|
||||
|
||||
return output
|
||||
|
||||
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)
|
||||
|
||||
# As a special case, we wrap line numbers before line highlighting
|
||||
# so the line numbers get wrapped in the highlighting tag.
|
||||
if not self.nowrap and self.linenos == 2:
|
||||
source = self._wrap_inlinelinenos(source)
|
||||
|
||||
if self.hl_lines:
|
||||
source = self._highlight_lines(source)
|
||||
|
||||
if not self.nowrap:
|
||||
if self.lineanchors:
|
||||
source = self._wrap_lineanchors(source)
|
||||
if self.linespans:
|
||||
source = self._wrap_linespans(source)
|
||||
source = self.wrap(source)
|
||||
if self.linenos == 1:
|
||||
source = self._wrap_tablelinenos(source)
|
||||
source = self._wrap_div(source)
|
||||
if self.full:
|
||||
source = self._wrap_full(source, outfile)
|
||||
|
||||
for t, piece in source:
|
||||
outfile.write(piece)
|
||||
|
|
@ -0,0 +1,645 @@
|
|||
"""
|
||||
pygments.formatters.img
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for Pixmap output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.util import get_bool_opt, get_int_opt, get_list_opt, \
|
||||
get_choice_opt
|
||||
|
||||
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_MAC = 'Menlo'
|
||||
|
||||
|
||||
class PilNotAvailable(ImportError):
|
||||
"""When Python imaging library is not available"""
|
||||
|
||||
|
||||
class FontNotFound(Exception):
|
||||
"""When there are no usable fonts specified"""
|
||||
|
||||
|
||||
class FontManager:
|
||||
"""
|
||||
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()
|
||||
for line in lines:
|
||||
if line.startswith(b'Fontconfig warning:'):
|
||||
continue
|
||||
path = line.decode().strip().strip(':')
|
||||
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 _get_mac_font_path(self, font_map, name, style):
|
||||
return font_map.get((name + ' ' + style).strip().lower())
|
||||
|
||||
def _create_mac(self):
|
||||
font_map = {}
|
||||
for font_dir in (os.path.join(os.getenv("HOME"), 'Library/Fonts/'),
|
||||
'/Library/Fonts/', '/System/Library/Fonts/'):
|
||||
font_map.update(
|
||||
(os.path.splitext(f)[0].lower(), os.path.join(font_dir, f))
|
||||
for f in os.listdir(font_dir)
|
||||
if f.lower().endswith(('ttf', 'ttc')))
|
||||
|
||||
for name in STYLES['NORMAL']:
|
||||
path = self._get_mac_font_path(font_map, 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_mac_font_path(font_map, 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 _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 OSError:
|
||||
continue
|
||||
else:
|
||||
if fail:
|
||||
raise FontNotFound('Font %s (%s) not found in registry' %
|
||||
(basename, styles[0]))
|
||||
return None
|
||||
|
||||
def _create_win(self):
|
||||
lookuperror = None
|
||||
keynames = [ (_winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows NT\CurrentVersion\Fonts'),
|
||||
(_winreg.HKEY_CURRENT_USER, r'Software\Microsoft\Windows\CurrentVersion\Fonts'),
|
||||
(_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows NT\CurrentVersion\Fonts'),
|
||||
(_winreg.HKEY_LOCAL_MACHINE, r'Software\Microsoft\Windows\CurrentVersion\Fonts') ]
|
||||
for keyname in keynames:
|
||||
try:
|
||||
key = _winreg.OpenKey(*keyname)
|
||||
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']
|
||||
return
|
||||
except FontNotFound as err:
|
||||
lookuperror = err
|
||||
finally:
|
||||
_winreg.CloseKey(key)
|
||||
except OSError:
|
||||
pass
|
||||
else:
|
||||
# If we get here, we checked all registry keys and had no luck
|
||||
# We can be in one of two situations now:
|
||||
# * All key lookups failed. In this case lookuperror is None and we
|
||||
# will raise a generic error
|
||||
# * At least one lookup failed with a FontNotFound error. In this
|
||||
# case, we will raise that as a more specific error
|
||||
if lookuperror:
|
||||
raise lookuperror
|
||||
raise FontNotFound('Can\'t open Windows font registry key')
|
||||
|
||||
def get_char_size(self):
|
||||
"""
|
||||
Get the character size.
|
||||
"""
|
||||
return self.get_text_size('M')
|
||||
|
||||
def get_text_size(self, text):
|
||||
"""
|
||||
Get the text size (width, height).
|
||||
"""
|
||||
font = self.fonts['NORMAL']
|
||||
if hasattr(font, 'getbbox'): # Pillow >= 9.2.0
|
||||
return font.getbbox(text)[2:4]
|
||||
else:
|
||||
return font.getsize(text)
|
||||
|
||||
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, linelength):
|
||||
"""
|
||||
Get the X coordinate of a character position.
|
||||
"""
|
||||
return linelength + self.image_pad + self.line_number_width
|
||||
|
||||
def _get_text_pos(self, linelength, lineno):
|
||||
"""
|
||||
Get the actual position for a character and line position.
|
||||
"""
|
||||
return self._get_char_x(linelength), 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_text_bg_color(self, style):
|
||||
"""
|
||||
Get the correct background color for the token from the style.
|
||||
"""
|
||||
if style['bgcolor'] is not None:
|
||||
bg_color = '#' + style['bgcolor']
|
||||
else:
|
||||
bg_color = None
|
||||
return bg_color
|
||||
|
||||
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, maxlinelength, maxlineno):
|
||||
"""
|
||||
Get the required image size.
|
||||
"""
|
||||
return (self._get_char_x(maxlinelength) + 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),
|
||||
text_fg=self.line_number_fg,
|
||||
text_bg=None,
|
||||
)
|
||||
|
||||
def _draw_text(self, pos, text, font, text_fg, text_bg):
|
||||
"""
|
||||
Remember a single drawable tuple to paint later.
|
||||
"""
|
||||
self.drawables.append((pos, text, font, text_fg, text_bg))
|
||||
|
||||
def _create_drawables(self, tokensource):
|
||||
"""
|
||||
Create drawables for the token content.
|
||||
"""
|
||||
lineno = charno = maxcharno = 0
|
||||
maxlinelength = linelength = 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(linelength, lineno),
|
||||
temp,
|
||||
font = self._get_style_font(style),
|
||||
text_fg = self._get_text_color(style),
|
||||
text_bg = self._get_text_bg_color(style),
|
||||
)
|
||||
temp_width, _ = self.fonts.get_text_size(temp)
|
||||
linelength += temp_width
|
||||
maxlinelength = max(maxlinelength, linelength)
|
||||
charno += len(temp)
|
||||
maxcharno = max(maxcharno, charno)
|
||||
if line.endswith('\n'):
|
||||
# add a line for each extra line in the value
|
||||
linelength = 0
|
||||
charno = 0
|
||||
lineno += 1
|
||||
self.maxlinelength = maxlinelength
|
||||
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 range(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.maxlinelength, 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, text_fg, text_bg in self.drawables:
|
||||
if text_bg:
|
||||
text_size = draw.textsize(text=value, font=font)
|
||||
draw.rectangle([pos[0], pos[1], pos[0] + text_size[0], pos[1] + text_size[1]], fill=text_bg)
|
||||
draw.text(pos, value, font=font, fill=text_fg)
|
||||
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'
|
||||
|
|
@ -0,0 +1,154 @@
|
|||
"""
|
||||
pygments.formatters.irc
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for IRC output
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.token import Keyword, Name, Comment, String, Error, \
|
||||
Number, Operator, Generic, Token, Whitespace
|
||||
from pip._vendor.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'),
|
||||
Keyword: ('blue', 'brightblue'),
|
||||
Keyword.Type: ('cyan', 'brightcyan'),
|
||||
Operator.Word: ('magenta', 'brightcyan'),
|
||||
Name.Builtin: ('cyan', 'brightcyan'),
|
||||
Name.Function: ('green', 'brightgreen'),
|
||||
Name.Namespace: ('_cyan_', '_brightcyan_'),
|
||||
Name.Class: ('_green_', '_brightgreen_'),
|
||||
Name.Exception: ('cyan', 'brightcyan'),
|
||||
Name.Decorator: ('brightblack', 'gray'),
|
||||
Name.Variable: ('red', 'brightred'),
|
||||
Name.Constant: ('red', 'brightred'),
|
||||
Name.Attribute: ('cyan', 'brightcyan'),
|
||||
Name.Tag: ('brightblue', 'brightblue'),
|
||||
String: ('yellow', 'yellow'),
|
||||
Number: ('blue', 'brightblue'),
|
||||
|
||||
Generic.Deleted: ('brightred', 'brightred'),
|
||||
Generic.Inserted: ('green', 'brightgreen'),
|
||||
Generic.Heading: ('**', '**'),
|
||||
Generic.Subheading: ('*magenta*', '*brightmagenta*'),
|
||||
Generic.Error: ('brightred', 'brightred'),
|
||||
|
||||
Error: ('_brightred_', '_brightred_'),
|
||||
}
|
||||
|
||||
|
||||
IRC_COLOR_MAP = {
|
||||
'white': 0,
|
||||
'black': 1,
|
||||
'blue': 2,
|
||||
'brightgreen': 3,
|
||||
'brightred': 4,
|
||||
'yellow': 5,
|
||||
'magenta': 6,
|
||||
'orange': 7,
|
||||
'green': 7, #compat w/ ansi
|
||||
'brightyellow': 8,
|
||||
'lightgreen': 9,
|
||||
'brightcyan': 9, # compat w/ ansi
|
||||
'cyan': 10,
|
||||
'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):
|
||||
if self.linenos:
|
||||
self._lineno += 1
|
||||
outfile.write("%04d: " % self._lineno)
|
||||
|
||||
def format_unencoded(self, tokensource, outfile):
|
||||
self._write_lineno(outfile)
|
||||
|
||||
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')
|
||||
self._write_lineno(outfile)
|
||||
if spl[-1]:
|
||||
outfile.write(ircformat(color, spl[-1]))
|
||||
else:
|
||||
outfile.write(value)
|
||||
|
|
@ -0,0 +1,521 @@
|
|||
"""
|
||||
pygments.formatters.latex
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for LaTeX fancyvrb output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from io import StringIO
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.lexer import Lexer, do_insertions
|
||||
from pip._vendor.pygments.token import Token, STANDARD_TYPES
|
||||
from pip._vendor.pygments.util import get_bool_opt, get_int_opt
|
||||
|
||||
|
||||
__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}
|
||||
|
||||
Wrapping can be disabled using the `nowrap` option.
|
||||
|
||||
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:
|
||||
|
||||
`nowrap`
|
||||
If set to ``True``, don't wrap the tokens at all, not even inside a
|
||||
``\begin{Verbatim}`` environment. This disables most other options
|
||||
(default: ``False``).
|
||||
|
||||
`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.nowrap = get_bool_opt(options, 'nowrap', False)
|
||||
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', '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}{\string -\fboxrule}'
|
||||
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 self.cmd2def.items():
|
||||
styles.append(r'\@namedef{%s@tok@%s}{%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()
|
||||
|
||||
if not self.nowrap:
|
||||
outfile.write('\\begin{' + self.envname + '}[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.mathescape or self.texcomments or self.escapeinside:
|
||||
outfile.write(',codes={\\catcode`\\$=3\\catcode`\\^=7'
|
||||
'\\catcode`\\_=8\\relax}')
|
||||
if self.verboptions:
|
||||
outfile.write(',' + self.verboptions)
|
||||
outfile.write(']\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 range(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)
|
||||
|
||||
if not self.nowrap:
|
||||
outfile.write('\\end{' + self.envname + '}\n')
|
||||
|
||||
if self.full:
|
||||
encoding = self.encoding or 'utf8'
|
||||
# map known existings encodings from LaTeX distribution
|
||||
encoding = {
|
||||
'utf_8': 'utf8',
|
||||
'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,
|
||||
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):
|
||||
# find and remove all the escape tokens (replace with an empty string)
|
||||
# this is very similar to DelegatingLexer.get_tokens_unprocessed.
|
||||
buffered = ''
|
||||
insertions = []
|
||||
insertion_buf = []
|
||||
for i, t, v in self._find_safe_escape_tokens(text):
|
||||
if t is None:
|
||||
if insertion_buf:
|
||||
insertions.append((len(buffered), insertion_buf))
|
||||
insertion_buf = []
|
||||
buffered += v
|
||||
else:
|
||||
insertion_buf.append((i, t, v))
|
||||
if insertion_buf:
|
||||
insertions.append((len(buffered), insertion_buf))
|
||||
return do_insertions(insertions,
|
||||
self.lang.get_tokens_unprocessed(buffered))
|
||||
|
||||
def _find_safe_escape_tokens(self, text):
|
||||
""" find escape tokens that are not in strings or comments """
|
||||
for i, t, v in self._filter_to(
|
||||
self.lang.get_tokens_unprocessed(text),
|
||||
lambda t: t in Token.Comment or t in Token.String
|
||||
):
|
||||
if t is None:
|
||||
for i2, t2, v2 in self._find_escape_tokens(v):
|
||||
yield i + i2, t2, v2
|
||||
else:
|
||||
yield i, None, v
|
||||
|
||||
def _filter_to(self, it, pred):
|
||||
""" Keep only the tokens that match `pred`, merge the others together """
|
||||
buf = ''
|
||||
idx = 0
|
||||
for i, t, v in it:
|
||||
if pred(t):
|
||||
if buf:
|
||||
yield idx, None, buf
|
||||
buf = ''
|
||||
yield i, t, v
|
||||
else:
|
||||
if not buf:
|
||||
idx = i
|
||||
buf += v
|
||||
if buf:
|
||||
yield idx, None, buf
|
||||
|
||||
def _find_escape_tokens(self, text):
|
||||
""" Find escape tokens within text, give token=None otherwise """
|
||||
index = 0
|
||||
while text:
|
||||
a, sep1, text = text.partition(self.left)
|
||||
if a:
|
||||
yield index, None, a
|
||||
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
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
"""
|
||||
pygments.formatters.other
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Other formatters: NullFormatter, RawTokenFormatter.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.util import get_choice_opt
|
||||
from pip._vendor.pygments.token import Token
|
||||
from pip._vendor.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)
|
||||
|
||||
write = outfile.write
|
||||
flush = outfile.close
|
||||
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
|
||||
|
||||
if self.error_color:
|
||||
for ttype, value in tokensource:
|
||||
line = b"%r\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(b"%r\t%r\n" % (ttype, value))
|
||||
flush()
|
||||
|
||||
|
||||
TESTCASE_BEFORE = '''\
|
||||
def testNeedsName(lexer):
|
||||
fragment = %r
|
||||
tokens = [
|
||||
'''
|
||||
TESTCASE_AFTER = '''\
|
||||
]
|
||||
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 % (''.join(rawbuf),)
|
||||
during = ''.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()
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
"""
|
||||
pygments.formatters.pangomarkup
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for Pango markup output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
|
||||
|
||||
__all__ = ['PangoMarkupFormatter']
|
||||
|
||||
|
||||
_escape_table = {
|
||||
ord('&'): '&',
|
||||
ord('<'): '<',
|
||||
}
|
||||
|
||||
|
||||
def escape_special_chars(text, table=_escape_table):
|
||||
"""Escape & and < for Pango Markup."""
|
||||
return text.translate(table)
|
||||
|
||||
|
||||
class PangoMarkupFormatter(Formatter):
|
||||
"""
|
||||
Format tokens as Pango Markup code. It can then be rendered to an SVG.
|
||||
|
||||
.. versionadded:: 2.9
|
||||
"""
|
||||
|
||||
name = 'Pango Markup'
|
||||
aliases = ['pango', 'pangomarkup']
|
||||
filenames = []
|
||||
|
||||
def __init__(self, **options):
|
||||
Formatter.__init__(self, **options)
|
||||
|
||||
self.styles = {}
|
||||
|
||||
for token, style in self.style:
|
||||
start = ''
|
||||
end = ''
|
||||
if style['color']:
|
||||
start += '<span fgcolor="#%s">' % style['color']
|
||||
end = '</span>' + end
|
||||
if style['bold']:
|
||||
start += '<b>'
|
||||
end = '</b>' + end
|
||||
if style['italic']:
|
||||
start += '<i>'
|
||||
end = '</i>' + end
|
||||
if style['underline']:
|
||||
start += '<u>'
|
||||
end = '</u>' + end
|
||||
self.styles[token] = (start, end)
|
||||
|
||||
def format_unencoded(self, tokensource, outfile):
|
||||
lastval = ''
|
||||
lasttype = None
|
||||
|
||||
outfile.write('<tt>')
|
||||
|
||||
for ttype, value in tokensource:
|
||||
while ttype not in self.styles:
|
||||
ttype = ttype.parent
|
||||
if ttype == lasttype:
|
||||
lastval += escape_special_chars(value)
|
||||
else:
|
||||
if lastval:
|
||||
stylebegin, styleend = self.styles[lasttype]
|
||||
outfile.write(stylebegin + lastval + styleend)
|
||||
lastval = escape_special_chars(value)
|
||||
lasttype = ttype
|
||||
|
||||
if lastval:
|
||||
stylebegin, styleend = self.styles[lasttype]
|
||||
outfile.write(stylebegin + lastval + styleend)
|
||||
|
||||
outfile.write('</tt>')
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
"""
|
||||
pygments.formatters.rtf
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
A formatter that generates RTF files.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.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('\\', '\\\\') \
|
||||
.replace('{', '\\{') \
|
||||
.replace('}', '\\}')
|
||||
|
||||
def _escape_text(self, text):
|
||||
# empty strings, should give a small performance improvement
|
||||
if not text:
|
||||
return ''
|
||||
|
||||
# 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%d}' % cn)
|
||||
elif (2**16) <= cn:
|
||||
# RTF limits unicode to 16 bits.
|
||||
# Force surrogate pairs
|
||||
buf.append('{\\u%d}{\\u%d}' % surrogatepair(cn))
|
||||
|
||||
return ''.join(buf).replace('\n', '\\par\n')
|
||||
|
||||
def format_unencoded(self, tokensource, outfile):
|
||||
# rtf 1.8 header
|
||||
outfile.write('{\\rtf1\\ansi\\uc0\\deff0'
|
||||
'{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset0%s;}}'
|
||||
'{\\colortbl;' % (self.fontface and
|
||||
' ' + self._escape(self.fontface) or
|
||||
''))
|
||||
|
||||
# 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('\\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('}\\f0 ')
|
||||
if self.fontsize:
|
||||
outfile.write('\\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('\\cb%d' % color_mapping[style['bgcolor']])
|
||||
if style['color']:
|
||||
buf.append('\\cf%d' % color_mapping[style['color']])
|
||||
if style['bold']:
|
||||
buf.append('\\b')
|
||||
if style['italic']:
|
||||
buf.append('\\i')
|
||||
if style['underline']:
|
||||
buf.append('\\ul')
|
||||
if style['border']:
|
||||
buf.append('\\chbrdr\\chcfpat%d' %
|
||||
color_mapping[style['border']])
|
||||
start = ''.join(buf)
|
||||
if start:
|
||||
outfile.write('{%s ' % start)
|
||||
outfile.write(self._escape_text(value))
|
||||
if start:
|
||||
outfile.write('}')
|
||||
|
||||
outfile.write('}')
|
||||
|
|
@ -0,0 +1,188 @@
|
|||
"""
|
||||
pygments.formatters.svg
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for SVG output.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.token import Comment
|
||||
from pip._vendor.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"``.
|
||||
|
||||
`linenos`
|
||||
If ``True``, add 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.
|
||||
|
||||
`linenowidth`
|
||||
Maximum width devoted to line numbers (default: ``3*ystep``, sufficient
|
||||
for up to 4-digit line numbers. Increase width for longer code blocks).
|
||||
|
||||
`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.linenos = get_bool_opt(options,'linenos',False)
|
||||
self.linenostart = get_int_opt(options,'linenostart',1)
|
||||
self.linenostep = get_int_opt(options,'linenostep',1)
|
||||
self.linenowidth = get_int_opt(options,'linenowidth', 3*self.ystep)
|
||||
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))
|
||||
|
||||
counter = self.linenostart
|
||||
counter_step = self.linenostep
|
||||
counter_style = self._get_style(Comment)
|
||||
line_x = x
|
||||
|
||||
if self.linenos:
|
||||
if counter % counter_step == 0:
|
||||
outfile.write('<text x="%s" y="%s" %s text-anchor="end">%s</text>' %
|
||||
(x+self.linenowidth,y,counter_style,counter))
|
||||
line_x += self.linenowidth + self.ystep
|
||||
counter += 1
|
||||
|
||||
outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (line_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')
|
||||
if self.linenos and counter % counter_step == 0:
|
||||
outfile.write('<text x="%s" y="%s" text-anchor="end" %s>%s</text>' %
|
||||
(x+self.linenowidth,y,counter_style,counter))
|
||||
|
||||
counter += 1
|
||||
outfile.write('<text x="%s" y="%s" ' 'xml:space="preserve">' % (line_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
|
||||
|
|
@ -0,0 +1,127 @@
|
|||
"""
|
||||
pygments.formatters.terminal
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Formatter for terminal output with ANSI sequences.
|
||||
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.token import Keyword, Name, Comment, String, Error, \
|
||||
Number, Operator, Generic, Token, Whitespace
|
||||
from pip._vendor.pygments.console import ansiformat
|
||||
from pip._vendor.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'),
|
||||
Keyword: ('blue', 'brightblue'),
|
||||
Keyword.Type: ('cyan', 'brightcyan'),
|
||||
Operator.Word: ('magenta', 'brightmagenta'),
|
||||
Name.Builtin: ('cyan', 'brightcyan'),
|
||||
Name.Function: ('green', 'brightgreen'),
|
||||
Name.Namespace: ('_cyan_', '_brightcyan_'),
|
||||
Name.Class: ('_green_', '_brightgreen_'),
|
||||
Name.Exception: ('cyan', 'brightcyan'),
|
||||
Name.Decorator: ('brightblack', 'gray'),
|
||||
Name.Variable: ('red', 'brightred'),
|
||||
Name.Constant: ('red', 'brightred'),
|
||||
Name.Attribute: ('cyan', 'brightcyan'),
|
||||
Name.Tag: ('brightblue', 'brightblue'),
|
||||
String: ('yellow', 'yellow'),
|
||||
Number: ('blue', 'brightblue'),
|
||||
|
||||
Generic.Deleted: ('brightred', 'brightred'),
|
||||
Generic.Inserted: ('green', 'brightgreen'),
|
||||
Generic.Heading: ('**', '**'),
|
||||
Generic.Subheading: ('*magenta*', '*brightmagenta*'),
|
||||
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):
|
||||
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")
|
||||
|
|
@ -0,0 +1,338 @@
|
|||
"""
|
||||
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-2023 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...
|
||||
|
||||
from pip._vendor.pygments.formatter import Formatter
|
||||
from pip._vendor.pygments.console import codes
|
||||
from pip._vendor.pygments.style import ansicolors
|
||||
|
||||
|
||||
__all__ = ['Terminal256Formatter', 'TerminalTrueColorFormatter']
|
||||
|
||||
|
||||
class EscapeSequence:
|
||||
def __init__(self, fg=None, bg=None, bold=False, underline=False, italic=False):
|
||||
self.fg = fg
|
||||
self.bg = bg
|
||||
self.bold = bold
|
||||
self.underline = underline
|
||||
self.italic = italic
|
||||
|
||||
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:
|
||||
self.bold = True
|
||||
# extract fg color code.
|
||||
attrs.append(esc[2:4])
|
||||
else:
|
||||
attrs.extend(("38", "5", "%i" % self.fg))
|
||||
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")
|
||||
if self.italic:
|
||||
attrs.append("03")
|
||||
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")
|
||||
if self.italic:
|
||||
attrs.append("03")
|
||||
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 or self.italic:
|
||||
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.
|
||||
See :ref:`AnsiTerminalStyle` for more information.
|
||||
|
||||
.. versionchanged:: 2.4
|
||||
The ANSI color names have been updated with names that are easier to
|
||||
understand and align with colornames of other projects and terminals.
|
||||
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'``).
|
||||
|
||||
`linenos`
|
||||
Set to ``True`` to have line numbers on the terminal output as well
|
||||
(default: ``False`` = no line numbers).
|
||||
"""
|
||||
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.useitalic = 'noitalic' 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
|
||||
|
||||
self.linenos = options.get('linenos', False)
|
||||
self._lineno = 0
|
||||
|
||||
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()
|
||||
# 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'])
|
||||
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
|
||||
if self.useitalic and ndef['italic']:
|
||||
escape.italic = True
|
||||
self.style_string[str(ttype)] = (escape.color_string(),
|
||||
escape.reset_string())
|
||||
|
||||
def _write_lineno(self, outfile):
|
||||
self._lineno += 1
|
||||
outfile.write("%s%04d: " % (self._lineno != 1 and '\n' or '', self._lineno))
|
||||
|
||||
def format(self, tokensource, outfile):
|
||||
return Formatter.format(self, tokensource, outfile)
|
||||
|
||||
def format_unencoded(self, tokensource, outfile):
|
||||
if self.linenos:
|
||||
self._write_lineno(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)
|
||||
if self.linenos:
|
||||
self._write_lineno(outfile)
|
||||
else:
|
||||
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.parent
|
||||
# outfile.write( '!' + str(ottype) + '->' + str(ttype) + '!' )
|
||||
|
||||
if not_found:
|
||||
outfile.write(value)
|
||||
|
||||
if self.linenos:
|
||||
outfile.write("\n")
|
||||
|
||||
|
||||
|
||||
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
|
||||
if self.useitalic and ndef['italic']:
|
||||
escape.italic = True
|
||||
self.style_string[str(ttype)] = (escape.true_color_string(),
|
||||
escape.reset_string())
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Base lexer classes.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -67,17 +67,10 @@ class Lexer(metaclass=LexerMeta):
|
|||
:no-value:
|
||||
.. autoattribute:: priority
|
||||
|
||||
Lexers included in Pygments should have two additional attributes:
|
||||
Lexers included in Pygments should have an additional attribute:
|
||||
|
||||
.. autoattribute:: url
|
||||
:no-value:
|
||||
.. autoattribute:: version_added
|
||||
:no-value:
|
||||
|
||||
Lexers included in Pygments may have additional attributes:
|
||||
|
||||
.. autoattribute:: _example
|
||||
:no-value:
|
||||
|
||||
You can pass options to the constructor. The basic options recognized
|
||||
by all lexers and processed by the base `Lexer` class are:
|
||||
|
|
@ -132,16 +125,9 @@ class Lexer(metaclass=LexerMeta):
|
|||
priority = 0
|
||||
|
||||
#: URL of the language specification/definition. Used in the Pygments
|
||||
#: documentation. Set to an empty string to disable.
|
||||
#: documentation.
|
||||
url = None
|
||||
|
||||
#: Version of Pygments in which the lexer was added.
|
||||
version_added = None
|
||||
|
||||
#: Example file name. Relative to the ``tests/examplefiles`` directory.
|
||||
#: This is used by the documentation generator to show an example.
|
||||
_example = None
|
||||
|
||||
def __init__(self, **options):
|
||||
"""
|
||||
This constructor takes arbitrary options as keyword arguments.
|
||||
|
|
@ -174,9 +160,10 @@ class Lexer(metaclass=LexerMeta):
|
|||
|
||||
def __repr__(self):
|
||||
if self.options:
|
||||
return f'<pygments.lexers.{self.__class__.__name__} with {self.options!r}>'
|
||||
return '<pygments.lexers.%s with %r>' % (self.__class__.__name__,
|
||||
self.options)
|
||||
else:
|
||||
return f'<pygments.lexers.{self.__class__.__name__}>'
|
||||
return '<pygments.lexers.%s>' % self.__class__.__name__
|
||||
|
||||
def add_filter(self, filter_, **options):
|
||||
"""
|
||||
|
|
@ -203,17 +190,26 @@ class Lexer(metaclass=LexerMeta):
|
|||
it's the same as if the return values was ``0.0``.
|
||||
"""
|
||||
|
||||
def _preprocess_lexer_input(self, text):
|
||||
"""Apply preprocessing such as decoding the input, removing BOM and normalizing newlines."""
|
||||
def get_tokens(self, text, unfiltered=False):
|
||||
"""
|
||||
This method is the basic interface of a lexer. It is called by
|
||||
the `highlight()` function. It must process the text and return an
|
||||
iterable of ``(tokentype, value)`` pairs from `text`.
|
||||
|
||||
Normally, you don't need to override this method. The default
|
||||
implementation processes the options recognized by all lexers
|
||||
(`stripnl`, `stripall` and so on), and then yields all tokens
|
||||
from `get_tokens_unprocessed()`, with the ``index`` dropped.
|
||||
|
||||
If `unfiltered` is set to `True`, the filtering mechanism is
|
||||
bypassed even if filters are defined.
|
||||
"""
|
||||
if not isinstance(text, str):
|
||||
if self.encoding == 'guess':
|
||||
text, _ = guess_decode(text)
|
||||
elif self.encoding == 'chardet':
|
||||
try:
|
||||
# pip vendoring note: this code is not reachable by pip,
|
||||
# removed import of chardet to make it clear.
|
||||
raise ImportError('chardet is not vendored by pip')
|
||||
from pip._vendor import chardet
|
||||
except ImportError as e:
|
||||
raise ImportError('To enable chardet encoding guessing, '
|
||||
'please install the chardet library '
|
||||
|
|
@ -250,24 +246,6 @@ class Lexer(metaclass=LexerMeta):
|
|||
if self.ensurenl and not text.endswith('\n'):
|
||||
text += '\n'
|
||||
|
||||
return text
|
||||
|
||||
def get_tokens(self, text, unfiltered=False):
|
||||
"""
|
||||
This method is the basic interface of a lexer. It is called by
|
||||
the `highlight()` function. It must process the text and return an
|
||||
iterable of ``(tokentype, value)`` pairs from `text`.
|
||||
|
||||
Normally, you don't need to override this method. The default
|
||||
implementation processes the options recognized by all lexers
|
||||
(`stripnl`, `stripall` and so on), and then yields all tokens
|
||||
from `get_tokens_unprocessed()`, with the ``index`` dropped.
|
||||
|
||||
If `unfiltered` is set to `True`, the filtering mechanism is
|
||||
bypassed even if filters are defined.
|
||||
"""
|
||||
text = self._preprocess_lexer_input(text)
|
||||
|
||||
def streamer():
|
||||
for _, t, v in self.get_tokens_unprocessed(text):
|
||||
yield t, v
|
||||
|
|
@ -512,7 +490,7 @@ class RegexLexerMeta(LexerMeta):
|
|||
def _process_token(cls, token):
|
||||
"""Preprocess the token component of a token definition."""
|
||||
assert type(token) is _TokenType or callable(token), \
|
||||
f'token type must be simple type or callable, not {token!r}'
|
||||
'token type must be simple type or callable, not %r' % (token,)
|
||||
return token
|
||||
|
||||
def _process_new_state(cls, new_state, unprocessed, processed):
|
||||
|
|
@ -528,14 +506,14 @@ class RegexLexerMeta(LexerMeta):
|
|||
elif new_state[:5] == '#pop:':
|
||||
return -int(new_state[5:])
|
||||
else:
|
||||
assert False, f'unknown new state {new_state!r}'
|
||||
assert False, 'unknown new state %r' % new_state
|
||||
elif isinstance(new_state, combined):
|
||||
# combine a new state from existing ones
|
||||
tmp_state = '_tmp_%d' % cls._tmpname
|
||||
cls._tmpname += 1
|
||||
itokens = []
|
||||
for istate in new_state:
|
||||
assert istate != new_state, f'circular state ref {istate!r}'
|
||||
assert istate != new_state, 'circular state ref %r' % istate
|
||||
itokens.extend(cls._process_state(unprocessed,
|
||||
processed, istate))
|
||||
processed[tmp_state] = itokens
|
||||
|
|
@ -548,12 +526,12 @@ class RegexLexerMeta(LexerMeta):
|
|||
'unknown new state ' + istate
|
||||
return new_state
|
||||
else:
|
||||
assert False, f'unknown new state def {new_state!r}'
|
||||
assert False, 'unknown new state def %r' % new_state
|
||||
|
||||
def _process_state(cls, unprocessed, processed, state):
|
||||
"""Preprocess a single state definition."""
|
||||
assert isinstance(state, str), f"wrong state name {state!r}"
|
||||
assert state[0] != '#', f"invalid state name {state!r}"
|
||||
assert type(state) is str, "wrong state name %r" % state
|
||||
assert state[0] != '#', "invalid state name %r" % state
|
||||
if state in processed:
|
||||
return processed[state]
|
||||
tokens = processed[state] = []
|
||||
|
|
@ -561,7 +539,7 @@ class RegexLexerMeta(LexerMeta):
|
|||
for tdef in unprocessed[state]:
|
||||
if isinstance(tdef, include):
|
||||
# it's a state reference
|
||||
assert tdef != state, f"circular state reference {state!r}"
|
||||
assert tdef != state, "circular state reference %r" % state
|
||||
tokens.extend(cls._process_state(unprocessed, processed,
|
||||
str(tdef)))
|
||||
continue
|
||||
|
|
@ -575,12 +553,13 @@ class RegexLexerMeta(LexerMeta):
|
|||
tokens.append((re.compile('').match, None, new_state))
|
||||
continue
|
||||
|
||||
assert type(tdef) is tuple, f"wrong rule def {tdef!r}"
|
||||
assert type(tdef) is tuple, "wrong rule def %r" % tdef
|
||||
|
||||
try:
|
||||
rex = cls._process_regex(tdef[0], rflags, state)
|
||||
except Exception as err:
|
||||
raise ValueError(f"uncompilable regex {tdef[0]!r} in state {state!r} of {cls!r}: {err}") from err
|
||||
raise ValueError("uncompilable regex %r in state %r of %r: %s" %
|
||||
(tdef[0], state, cls, err)) from err
|
||||
|
||||
token = cls._process_token(tdef[1])
|
||||
|
||||
|
|
@ -741,7 +720,7 @@ class RegexLexer(Lexer, metaclass=RegexLexerMeta):
|
|||
elif new_state == '#push':
|
||||
statestack.append(statestack[-1])
|
||||
else:
|
||||
assert False, f"wrong state def: {new_state!r}"
|
||||
assert False, "wrong state def: %r" % new_state
|
||||
statetokens = tokendefs[statestack[-1]]
|
||||
break
|
||||
else:
|
||||
|
|
@ -773,7 +752,8 @@ class LexerContext:
|
|||
self.stack = stack or ['root']
|
||||
|
||||
def __repr__(self):
|
||||
return f'LexerContext({self.text!r}, {self.pos!r}, {self.stack!r})'
|
||||
return 'LexerContext(%r, %r, %r)' % (
|
||||
self.text, self.pos, self.stack)
|
||||
|
||||
|
||||
class ExtendedRegexLexer(RegexLexer):
|
||||
|
|
@ -828,7 +808,7 @@ class ExtendedRegexLexer(RegexLexer):
|
|||
elif new_state == '#push':
|
||||
ctx.stack.append(ctx.stack[-1])
|
||||
else:
|
||||
assert False, f"wrong state def: {new_state!r}"
|
||||
assert False, "wrong state def: %r" % new_state
|
||||
statetokens = tokendefs[ctx.stack[-1]]
|
||||
break
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Pygments lexers.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -22,7 +22,6 @@ from pip._vendor.pygments.util import ClassNotFound, guess_decode
|
|||
COMPAT = {
|
||||
'Python3Lexer': 'PythonLexer',
|
||||
'Python3TracebackLexer': 'PythonTracebackLexer',
|
||||
'LeanLexer': 'Lean3Lexer',
|
||||
}
|
||||
|
||||
__all__ = ['get_lexer_by_name', 'get_lexer_for_filename', 'find_lexer_class',
|
||||
|
|
@ -93,7 +92,7 @@ def find_lexer_class_by_name(_alias):
|
|||
.. versionadded:: 2.2
|
||||
"""
|
||||
if not _alias:
|
||||
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
||||
raise ClassNotFound('no lexer for alias %r found' % _alias)
|
||||
# lookup builtin lexers
|
||||
for module_name, name, aliases, _, _ in LEXERS.values():
|
||||
if _alias.lower() in aliases:
|
||||
|
|
@ -104,7 +103,7 @@ def find_lexer_class_by_name(_alias):
|
|||
for cls in find_plugin_lexers():
|
||||
if _alias.lower() in cls.aliases:
|
||||
return cls
|
||||
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
||||
raise ClassNotFound('no lexer for alias %r found' % _alias)
|
||||
|
||||
|
||||
def get_lexer_by_name(_alias, **options):
|
||||
|
|
@ -117,7 +116,7 @@ def get_lexer_by_name(_alias, **options):
|
|||
found.
|
||||
"""
|
||||
if not _alias:
|
||||
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
||||
raise ClassNotFound('no lexer for alias %r found' % _alias)
|
||||
|
||||
# lookup builtin lexers
|
||||
for module_name, name, aliases, _, _ in LEXERS.values():
|
||||
|
|
@ -129,7 +128,7 @@ def get_lexer_by_name(_alias, **options):
|
|||
for cls in find_plugin_lexers():
|
||||
if _alias.lower() in cls.aliases:
|
||||
return cls(**options)
|
||||
raise ClassNotFound(f'no lexer for alias {_alias!r} found')
|
||||
raise ClassNotFound('no lexer for alias %r found' % _alias)
|
||||
|
||||
|
||||
def load_lexer_from_file(filename, lexername="CustomLexer", **options):
|
||||
|
|
@ -154,16 +153,17 @@ def load_lexer_from_file(filename, lexername="CustomLexer", **options):
|
|||
exec(f.read(), custom_namespace)
|
||||
# Retrieve the class `lexername` from that namespace
|
||||
if lexername not in custom_namespace:
|
||||
raise ClassNotFound(f'no valid {lexername} class found in {filename}')
|
||||
raise ClassNotFound('no valid %s class found in %s' %
|
||||
(lexername, filename))
|
||||
lexer_class = custom_namespace[lexername]
|
||||
# And finally instantiate it with the options
|
||||
return lexer_class(**options)
|
||||
except OSError as err:
|
||||
raise ClassNotFound(f'cannot read {filename}: {err}')
|
||||
raise ClassNotFound('cannot read %s: %s' % (filename, err))
|
||||
except ClassNotFound:
|
||||
raise
|
||||
except Exception as err:
|
||||
raise ClassNotFound(f'error when loading custom lexer: {err}')
|
||||
raise ClassNotFound('error when loading custom lexer: %s' % err)
|
||||
|
||||
|
||||
def find_lexer_class_for_filename(_fn, code=None):
|
||||
|
|
@ -224,7 +224,7 @@ def get_lexer_for_filename(_fn, code=None, **options):
|
|||
"""
|
||||
res = find_lexer_class_for_filename(_fn, code)
|
||||
if not res:
|
||||
raise ClassNotFound(f'no lexer for filename {_fn!r} found')
|
||||
raise ClassNotFound('no lexer for filename %r found' % _fn)
|
||||
return res(**options)
|
||||
|
||||
|
||||
|
|
@ -244,7 +244,7 @@ def get_lexer_for_mimetype(_mime, **options):
|
|||
for cls in find_plugin_lexers():
|
||||
if _mime in cls.mimetypes:
|
||||
return cls(**options)
|
||||
raise ClassNotFound(f'no lexer for mimetype {_mime!r} found')
|
||||
raise ClassNotFound('no lexer for mimetype %r found' % _mime)
|
||||
|
||||
|
||||
def _iter_lexerclasses(plugins=True):
|
||||
|
|
@ -279,7 +279,7 @@ def guess_lexer_for_filename(_fn, _text, **options):
|
|||
matching_lexers.add(lexer)
|
||||
primary[lexer] = False
|
||||
if not matching_lexers:
|
||||
raise ClassNotFound(f'no lexer for filename {fn!r} found')
|
||||
raise ClassNotFound('no lexer for filename %r found' % fn)
|
||||
if len(matching_lexers) == 1:
|
||||
return matching_lexers.pop()(**options)
|
||||
result = []
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -31,8 +31,7 @@ LEXERS = {
|
|||
'ArduinoLexer': ('pip._vendor.pygments.lexers.c_like', 'Arduino', ('arduino',), ('*.ino',), ('text/x-arduino',)),
|
||||
'ArrowLexer': ('pip._vendor.pygments.lexers.arrow', 'Arrow', ('arrow',), ('*.arw',), ()),
|
||||
'ArturoLexer': ('pip._vendor.pygments.lexers.arturo', 'Arturo', ('arturo', 'art'), ('*.art',), ()),
|
||||
'AscLexer': ('pip._vendor.pygments.lexers.asc', 'ASCII armored', ('asc', 'pem'), ('*.asc', '*.pem', 'id_dsa', 'id_ecdsa', 'id_ecdsa_sk', 'id_ed25519', 'id_ed25519_sk', 'id_rsa'), ('application/pgp-keys', 'application/pgp-encrypted', 'application/pgp-signature', 'application/pem-certificate-chain')),
|
||||
'Asn1Lexer': ('pip._vendor.pygments.lexers.asn1', 'ASN.1', ('asn1',), ('*.asn1',), ()),
|
||||
'AscLexer': ('pip._vendor.pygments.lexers.asc', 'ASCII armored', ('asc', 'pem'), ('*.asc', '*.pem', 'id_dsa', 'id_ecdsa', 'id_ecdsa_sk', 'id_ed25519', 'id_ed25519_sk', 'id_rsa'), ('application/pgp-keys', 'application/pgp-encrypted', 'application/pgp-signature')),
|
||||
'AspectJLexer': ('pip._vendor.pygments.lexers.jvm', 'AspectJ', ('aspectj',), ('*.aj',), ('text/x-aspectj',)),
|
||||
'AsymptoteLexer': ('pip._vendor.pygments.lexers.graphics', 'Asymptote', ('asymptote', 'asy'), ('*.asy',), ('text/x-asymptote',)),
|
||||
'AugeasLexer': ('pip._vendor.pygments.lexers.configs', 'Augeas', ('augeas',), ('*.aug',), ()),
|
||||
|
|
@ -42,11 +41,10 @@ LEXERS = {
|
|||
'BBCBasicLexer': ('pip._vendor.pygments.lexers.basic', 'BBC Basic', ('bbcbasic',), ('*.bbc',), ()),
|
||||
'BBCodeLexer': ('pip._vendor.pygments.lexers.markup', 'BBCode', ('bbcode',), (), ('text/x-bbcode',)),
|
||||
'BCLexer': ('pip._vendor.pygments.lexers.algebra', 'BC', ('bc',), ('*.bc',), ()),
|
||||
'BQNLexer': ('pip._vendor.pygments.lexers.bqn', 'BQN', ('bqn',), ('*.bqn',), ()),
|
||||
'BSTLexer': ('pip._vendor.pygments.lexers.bibtex', 'BST', ('bst', 'bst-pybtex'), ('*.bst',), ()),
|
||||
'BareLexer': ('pip._vendor.pygments.lexers.bare', 'BARE', ('bare',), ('*.bare',), ()),
|
||||
'BaseMakefileLexer': ('pip._vendor.pygments.lexers.make', 'Base Makefile', ('basemake',), (), ()),
|
||||
'BashLexer': ('pip._vendor.pygments.lexers.shell', 'Bash', ('bash', 'sh', 'ksh', 'zsh', 'shell', 'openrc'), ('*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '*.exheres-0', '*.exlib', '*.zsh', '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc', '.kshrc', 'kshrc', 'PKGBUILD'), ('application/x-sh', 'application/x-shellscript', 'text/x-shellscript')),
|
||||
'BashLexer': ('pip._vendor.pygments.lexers.shell', 'Bash', ('bash', 'sh', 'ksh', 'zsh', 'shell'), ('*.sh', '*.ksh', '*.bash', '*.ebuild', '*.eclass', '*.exheres-0', '*.exlib', '*.zsh', '.bashrc', 'bashrc', '.bash_*', 'bash_*', 'zshrc', '.zshrc', '.kshrc', 'kshrc', 'PKGBUILD'), ('application/x-sh', 'application/x-shellscript', 'text/x-shellscript')),
|
||||
'BashSessionLexer': ('pip._vendor.pygments.lexers.shell', 'Bash Session', ('console', 'shell-session'), ('*.sh-session', '*.shell-session'), ('application/x-shell-session', 'application/x-sh-session')),
|
||||
'BatchLexer': ('pip._vendor.pygments.lexers.shell', 'Batchfile', ('batch', 'bat', 'dosbatch', 'winbatch'), ('*.bat', '*.cmd'), ('application/x-dos-batch',)),
|
||||
'BddLexer': ('pip._vendor.pygments.lexers.bdd', 'Bdd', ('bdd',), ('*.feature',), ('text/x-bdd',)),
|
||||
|
|
@ -55,7 +53,6 @@ LEXERS = {
|
|||
'BibTeXLexer': ('pip._vendor.pygments.lexers.bibtex', 'BibTeX', ('bibtex', 'bib'), ('*.bib',), ('text/x-bibtex',)),
|
||||
'BlitzBasicLexer': ('pip._vendor.pygments.lexers.basic', 'BlitzBasic', ('blitzbasic', 'b3d', 'bplus'), ('*.bb', '*.decls'), ('text/x-bb',)),
|
||||
'BlitzMaxLexer': ('pip._vendor.pygments.lexers.basic', 'BlitzMax', ('blitzmax', 'bmax'), ('*.bmx',), ('text/x-bmx',)),
|
||||
'BlueprintLexer': ('pip._vendor.pygments.lexers.blueprint', 'Blueprint', ('blueprint',), ('*.blp',), ('text/x-blueprint',)),
|
||||
'BnfLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'BNF', ('bnf',), ('*.bnf',), ('text/x-bnf',)),
|
||||
'BoaLexer': ('pip._vendor.pygments.lexers.boa', 'Boa', ('boa',), ('*.boa',), ()),
|
||||
'BooLexer': ('pip._vendor.pygments.lexers.dotnet', 'Boo', ('boo',), ('*.boo',), ('text/x-boo',)),
|
||||
|
|
@ -93,7 +90,6 @@ LEXERS = {
|
|||
'ClojureScriptLexer': ('pip._vendor.pygments.lexers.jvm', 'ClojureScript', ('clojurescript', 'cljs'), ('*.cljs',), ('text/x-clojurescript', 'application/x-clojurescript')),
|
||||
'CobolFreeformatLexer': ('pip._vendor.pygments.lexers.business', 'COBOLFree', ('cobolfree',), ('*.cbl', '*.CBL'), ()),
|
||||
'CobolLexer': ('pip._vendor.pygments.lexers.business', 'COBOL', ('cobol',), ('*.cob', '*.COB', '*.cpy', '*.CPY'), ('text/x-cobol',)),
|
||||
'CodeQLLexer': ('pip._vendor.pygments.lexers.codeql', 'CodeQL', ('codeql', 'ql'), ('*.ql', '*.qll'), ()),
|
||||
'CoffeeScriptLexer': ('pip._vendor.pygments.lexers.javascript', 'CoffeeScript', ('coffeescript', 'coffee-script', 'coffee'), ('*.coffee',), ('text/coffeescript',)),
|
||||
'ColdfusionCFCLexer': ('pip._vendor.pygments.lexers.templates', 'Coldfusion CFC', ('cfc',), ('*.cfc',), ()),
|
||||
'ColdfusionHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'Coldfusion HTML', ('cfm',), ('*.cfm', '*.cfml'), ('application/x-coldfusion',)),
|
||||
|
|
@ -128,14 +124,11 @@ LEXERS = {
|
|||
'Dasm16Lexer': ('pip._vendor.pygments.lexers.asm', 'DASM16', ('dasm16',), ('*.dasm16', '*.dasm'), ('text/x-dasm16',)),
|
||||
'DaxLexer': ('pip._vendor.pygments.lexers.dax', 'Dax', ('dax',), ('*.dax',), ()),
|
||||
'DebianControlLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Control file', ('debcontrol', 'control'), ('control',), ()),
|
||||
'DebianSourcesLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Sources file', ('debian.sources',), ('*.sources',), ()),
|
||||
'DelphiLexer': ('pip._vendor.pygments.lexers.pascal', 'Delphi', ('delphi', 'pas', 'pascal', 'objectpascal'), ('*.pas', '*.dpr'), ('text/x-pascal',)),
|
||||
'DesktopLexer': ('pip._vendor.pygments.lexers.configs', 'Desktop file', ('desktop',), ('*.desktop',), ('application/x-desktop',)),
|
||||
'DevicetreeLexer': ('pip._vendor.pygments.lexers.devicetree', 'Devicetree', ('devicetree', 'dts'), ('*.dts', '*.dtsi'), ('text/x-c',)),
|
||||
'DgLexer': ('pip._vendor.pygments.lexers.python', 'dg', ('dg',), ('*.dg',), ('text/x-dg',)),
|
||||
'DiffLexer': ('pip._vendor.pygments.lexers.diff', 'Diff', ('diff', 'udiff'), ('*.diff', '*.patch'), ('text/x-diff', 'text/x-patch')),
|
||||
'DjangoLexer': ('pip._vendor.pygments.lexers.templates', 'Django/Jinja', ('django', 'jinja'), (), ('application/x-django-templating', 'application/x-jinja')),
|
||||
'DnsZoneLexer': ('pip._vendor.pygments.lexers.dns', 'Zone', ('zone',), ('*.zone',), ('text/dns',)),
|
||||
'DockerLexer': ('pip._vendor.pygments.lexers.configs', 'Docker', ('docker', 'dockerfile'), ('Dockerfile', '*.docker'), ('text/x-dockerfile-config',)),
|
||||
'DtdLexer': ('pip._vendor.pygments.lexers.html', 'DTD', ('dtd',), ('*.dtd',), ('application/xml-dtd',)),
|
||||
'DuelLexer': ('pip._vendor.pygments.lexers.webmisc', 'Duel', ('duel', 'jbst', 'jsonml+bst'), ('*.duel', '*.jbst'), ('text/x-duel', 'text/x-jbst')),
|
||||
|
|
@ -157,9 +150,9 @@ LEXERS = {
|
|||
'ErbLexer': ('pip._vendor.pygments.lexers.templates', 'ERB', ('erb',), (), ('application/x-ruby-templating',)),
|
||||
'ErlangLexer': ('pip._vendor.pygments.lexers.erlang', 'Erlang', ('erlang',), ('*.erl', '*.hrl', '*.es', '*.escript'), ('text/x-erlang',)),
|
||||
'ErlangShellLexer': ('pip._vendor.pygments.lexers.erlang', 'Erlang erl session', ('erl',), ('*.erl-sh',), ('text/x-erl-shellsession',)),
|
||||
'EvoqueHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Evoque', ('html+evoque',), (), ('text/html+evoque',)),
|
||||
'EvoqueHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Evoque', ('html+evoque',), ('*.html',), ('text/html+evoque',)),
|
||||
'EvoqueLexer': ('pip._vendor.pygments.lexers.templates', 'Evoque', ('evoque',), ('*.evoque',), ('application/x-evoque',)),
|
||||
'EvoqueXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Evoque', ('xml+evoque',), (), ('application/xml+evoque',)),
|
||||
'EvoqueXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Evoque', ('xml+evoque',), ('*.xml',), ('application/xml+evoque',)),
|
||||
'ExeclineLexer': ('pip._vendor.pygments.lexers.shell', 'execline', ('execline',), ('*.exec',), ()),
|
||||
'EzhilLexer': ('pip._vendor.pygments.lexers.ezhil', 'Ezhil', ('ezhil',), ('*.n',), ('text/x-ezhil',)),
|
||||
'FSharpLexer': ('pip._vendor.pygments.lexers.dotnet', 'F#', ('fsharp', 'f#'), ('*.fs', '*.fsi', '*.fsx'), ('text/x-fsharp',)),
|
||||
|
|
@ -191,15 +184,12 @@ LEXERS = {
|
|||
'GenshiTextLexer': ('pip._vendor.pygments.lexers.templates', 'Genshi Text', ('genshitext',), (), ('application/x-genshi-text', 'text/x-genshi')),
|
||||
'GettextLexer': ('pip._vendor.pygments.lexers.textfmts', 'Gettext Catalog', ('pot', 'po'), ('*.pot', '*.po'), ('application/x-gettext', 'text/x-gettext', 'text/gettext')),
|
||||
'GherkinLexer': ('pip._vendor.pygments.lexers.testing', 'Gherkin', ('gherkin', 'cucumber'), ('*.feature',), ('text/x-gherkin',)),
|
||||
'GleamLexer': ('pip._vendor.pygments.lexers.gleam', 'Gleam', ('gleam',), ('*.gleam',), ('text/x-gleam',)),
|
||||
'GnuplotLexer': ('pip._vendor.pygments.lexers.graphics', 'Gnuplot', ('gnuplot',), ('*.plot', '*.plt'), ('text/x-gnuplot',)),
|
||||
'GoLexer': ('pip._vendor.pygments.lexers.go', 'Go', ('go', 'golang'), ('*.go',), ('text/x-gosrc',)),
|
||||
'GoloLexer': ('pip._vendor.pygments.lexers.jvm', 'Golo', ('golo',), ('*.golo',), ()),
|
||||
'GoodDataCLLexer': ('pip._vendor.pygments.lexers.business', 'GoodData-CL', ('gooddata-cl',), ('*.gdc',), ('text/x-gooddata-cl',)),
|
||||
'GoogleSqlLexer': ('pip._vendor.pygments.lexers.sql', 'GoogleSQL', ('googlesql', 'zetasql'), ('*.googlesql', '*.googlesql.sql'), ('text/x-google-sql', 'text/x-google-sql-aux')),
|
||||
'GosuLexer': ('pip._vendor.pygments.lexers.jvm', 'Gosu', ('gosu',), ('*.gs', '*.gsx', '*.gsp', '*.vark'), ('text/x-gosu',)),
|
||||
'GosuTemplateLexer': ('pip._vendor.pygments.lexers.jvm', 'Gosu Template', ('gst',), ('*.gst',), ('text/x-gosu-template',)),
|
||||
'GraphQLLexer': ('pip._vendor.pygments.lexers.graphql', 'GraphQL', ('graphql',), ('*.graphql',), ()),
|
||||
'GraphvizLexer': ('pip._vendor.pygments.lexers.graphviz', 'Graphviz', ('graphviz', 'dot'), ('*.gv', '*.dot'), ('text/x-graphviz', 'text/vnd.graphviz')),
|
||||
'GroffLexer': ('pip._vendor.pygments.lexers.markup', 'Groff', ('groff', 'nroff', 'man'), ('*.[1-9]', '*.man', '*.1p', '*.3pm'), ('application/x-troff', 'text/troff')),
|
||||
'GroovyLexer': ('pip._vendor.pygments.lexers.jvm', 'Groovy', ('groovy',), ('*.groovy', '*.gradle'), ('text/x-groovy',)),
|
||||
|
|
@ -208,7 +198,6 @@ LEXERS = {
|
|||
'HamlLexer': ('pip._vendor.pygments.lexers.html', 'Haml', ('haml',), ('*.haml',), ('text/x-haml',)),
|
||||
'HandlebarsHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Handlebars', ('html+handlebars',), ('*.handlebars', '*.hbs'), ('text/html+handlebars', 'text/x-handlebars-template')),
|
||||
'HandlebarsLexer': ('pip._vendor.pygments.lexers.templates', 'Handlebars', ('handlebars',), (), ()),
|
||||
'HareLexer': ('pip._vendor.pygments.lexers.hare', 'Hare', ('hare',), ('*.ha',), ('text/x-hare',)),
|
||||
'HaskellLexer': ('pip._vendor.pygments.lexers.haskell', 'Haskell', ('haskell', 'hs'), ('*.hs',), ('text/x-haskell',)),
|
||||
'HaxeLexer': ('pip._vendor.pygments.lexers.haxe', 'Haxe', ('haxe', 'hxsl', 'hx'), ('*.hx', '*.hxsl'), ('text/haxe', 'text/x-haxe', 'text/x-hx')),
|
||||
'HexdumpLexer': ('pip._vendor.pygments.lexers.hexdump', 'Hexdump', ('hexdump',), (), ()),
|
||||
|
|
@ -221,8 +210,8 @@ LEXERS = {
|
|||
'HtmlSmartyLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Smarty', ('html+smarty',), (), ('text/html+smarty',)),
|
||||
'HttpLexer': ('pip._vendor.pygments.lexers.textfmts', 'HTTP', ('http',), (), ()),
|
||||
'HxmlLexer': ('pip._vendor.pygments.lexers.haxe', 'Hxml', ('haxeml', 'hxml'), ('*.hxml',), ()),
|
||||
'HyLexer': ('pip._vendor.pygments.lexers.lisp', 'Hy', ('hylang', 'hy'), ('*.hy',), ('text/x-hy', 'application/x-hy')),
|
||||
'HybrisLexer': ('pip._vendor.pygments.lexers.scripting', 'Hybris', ('hybris',), ('*.hyb',), ('text/x-hybris', 'application/x-hybris')),
|
||||
'HyLexer': ('pip._vendor.pygments.lexers.lisp', 'Hy', ('hylang',), ('*.hy',), ('text/x-hy', 'application/x-hy')),
|
||||
'HybrisLexer': ('pip._vendor.pygments.lexers.scripting', 'Hybris', ('hybris', 'hy'), ('*.hy', '*.hyb'), ('text/x-hybris', 'application/x-hybris')),
|
||||
'IDLLexer': ('pip._vendor.pygments.lexers.idl', 'IDL', ('idl',), ('*.pro',), ('text/idl',)),
|
||||
'IconLexer': ('pip._vendor.pygments.lexers.unicon', 'Icon', ('icon',), ('*.icon', '*.ICON'), ()),
|
||||
'IdrisLexer': ('pip._vendor.pygments.lexers.haskell', 'Idris', ('idris', 'idr'), ('*.idr',), ('text/x-idris',)),
|
||||
|
|
@ -230,7 +219,7 @@ LEXERS = {
|
|||
'Inform6Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 6', ('inform6', 'i6'), ('*.inf',), ()),
|
||||
'Inform6TemplateLexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 6 template', ('i6t',), ('*.i6t',), ()),
|
||||
'Inform7Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'Inform 7', ('inform7', 'i7'), ('*.ni', '*.i7x'), ()),
|
||||
'IniLexer': ('pip._vendor.pygments.lexers.configs', 'INI', ('ini', 'cfg', 'dosini'), ('*.ini', '*.cfg', '*.inf', '.editorconfig'), ('text/x-ini', 'text/inf')),
|
||||
'IniLexer': ('pip._vendor.pygments.lexers.configs', 'INI', ('ini', 'cfg', 'dosini'), ('*.ini', '*.cfg', '*.inf', '.editorconfig', '*.service', '*.socket', '*.device', '*.mount', '*.automount', '*.swap', '*.target', '*.path', '*.timer', '*.slice', '*.scope'), ('text/x-ini', 'text/inf')),
|
||||
'IoLexer': ('pip._vendor.pygments.lexers.iolang', 'Io', ('io',), ('*.io',), ('text/x-iosrc',)),
|
||||
'IokeLexer': ('pip._vendor.pygments.lexers.jvm', 'Ioke', ('ioke', 'ik'), ('*.ik',), ('text/x-iokesrc',)),
|
||||
'IrcLogsLexer': ('pip._vendor.pygments.lexers.textfmts', 'IRC logs', ('irc',), ('*.weechatlog',), ('text/x-irclog',)),
|
||||
|
|
@ -239,7 +228,6 @@ LEXERS = {
|
|||
'JMESPathLexer': ('pip._vendor.pygments.lexers.jmespath', 'JMESPath', ('jmespath', 'jp'), ('*.jp',), ()),
|
||||
'JSLTLexer': ('pip._vendor.pygments.lexers.jslt', 'JSLT', ('jslt',), ('*.jslt',), ('text/x-jslt',)),
|
||||
'JagsLexer': ('pip._vendor.pygments.lexers.modeling', 'JAGS', ('jags',), ('*.jag', '*.bug'), ()),
|
||||
'JanetLexer': ('pip._vendor.pygments.lexers.lisp', 'Janet', ('janet',), ('*.janet', '*.jdn'), ('text/x-janet', 'application/x-janet')),
|
||||
'JasminLexer': ('pip._vendor.pygments.lexers.jvm', 'Jasmin', ('jasmin', 'jasminxt'), ('*.j',), ()),
|
||||
'JavaLexer': ('pip._vendor.pygments.lexers.jvm', 'Java', ('java',), ('*.java',), ('text/x-java',)),
|
||||
'JavascriptDjangoLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Django/Jinja', ('javascript+django', 'js+django', 'javascript+jinja', 'js+jinja'), ('*.js.j2', '*.js.jinja2'), ('application/x-javascript+django', 'application/x-javascript+jinja', 'text/x-javascript+django', 'text/x-javascript+jinja', 'text/javascript+django', 'text/javascript+jinja')),
|
||||
|
|
@ -251,13 +239,11 @@ LEXERS = {
|
|||
'JavascriptUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'Javascript+UL4', ('js+ul4',), ('*.jsul4',), ()),
|
||||
'JclLexer': ('pip._vendor.pygments.lexers.scripting', 'JCL', ('jcl',), ('*.jcl',), ('text/x-jcl',)),
|
||||
'JsgfLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'JSGF', ('jsgf',), ('*.jsgf',), ('application/jsgf', 'application/x-jsgf', 'text/jsgf')),
|
||||
'Json5Lexer': ('pip._vendor.pygments.lexers.json5', 'JSON5', ('json5',), ('*.json5',), ()),
|
||||
'JsonBareObjectLexer': ('pip._vendor.pygments.lexers.data', 'JSONBareObject', (), (), ()),
|
||||
'JsonLdLexer': ('pip._vendor.pygments.lexers.data', 'JSON-LD', ('jsonld', 'json-ld'), ('*.jsonld',), ('application/ld+json',)),
|
||||
'JsonLexer': ('pip._vendor.pygments.lexers.data', 'JSON', ('json', 'json-object'), ('*.json', '*.jsonl', '*.ndjson', 'Pipfile.lock'), ('application/json', 'application/json-object', 'application/x-ndjson', 'application/jsonl', 'application/json-seq')),
|
||||
'JsonLexer': ('pip._vendor.pygments.lexers.data', 'JSON', ('json', 'json-object'), ('*.json', 'Pipfile.lock'), ('application/json', 'application/json-object')),
|
||||
'JsonnetLexer': ('pip._vendor.pygments.lexers.jsonnet', 'Jsonnet', ('jsonnet',), ('*.jsonnet', '*.libsonnet'), ()),
|
||||
'JspLexer': ('pip._vendor.pygments.lexers.templates', 'Java Server Page', ('jsp',), ('*.jsp',), ('application/x-jsp',)),
|
||||
'JsxLexer': ('pip._vendor.pygments.lexers.jsx', 'JSX', ('jsx', 'react'), ('*.jsx', '*.react'), ('text/jsx', 'text/typescript-jsx')),
|
||||
'JuliaConsoleLexer': ('pip._vendor.pygments.lexers.julia', 'Julia console', ('jlcon', 'julia-repl'), (), ()),
|
||||
'JuliaLexer': ('pip._vendor.pygments.lexers.julia', 'Julia', ('julia', 'jl'), ('*.jl',), ('text/x-julia', 'application/x-julia')),
|
||||
'JuttleLexer': ('pip._vendor.pygments.lexers.javascript', 'Juttle', ('juttle',), ('*.juttle',), ('application/juttle', 'application/x-juttle', 'text/x-juttle', 'text/juttle')),
|
||||
|
|
@ -268,17 +254,13 @@ LEXERS = {
|
|||
'KokaLexer': ('pip._vendor.pygments.lexers.haskell', 'Koka', ('koka',), ('*.kk', '*.kki'), ('text/x-koka',)),
|
||||
'KotlinLexer': ('pip._vendor.pygments.lexers.jvm', 'Kotlin', ('kotlin',), ('*.kt', '*.kts'), ('text/x-kotlin',)),
|
||||
'KuinLexer': ('pip._vendor.pygments.lexers.kuin', 'Kuin', ('kuin',), ('*.kn',), ()),
|
||||
'KustoLexer': ('pip._vendor.pygments.lexers.kusto', 'Kusto', ('kql', 'kusto'), ('*.kql', '*.kusto', '.csl'), ()),
|
||||
'LSLLexer': ('pip._vendor.pygments.lexers.scripting', 'LSL', ('lsl',), ('*.lsl',), ('text/x-lsl',)),
|
||||
'LassoCssLexer': ('pip._vendor.pygments.lexers.templates', 'CSS+Lasso', ('css+lasso',), (), ('text/css+lasso',)),
|
||||
'LassoHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Lasso', ('html+lasso',), (), ('text/html+lasso', 'application/x-httpd-lasso', 'application/x-httpd-lasso[89]')),
|
||||
'LassoJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Lasso', ('javascript+lasso', 'js+lasso'), (), ('application/x-javascript+lasso', 'text/x-javascript+lasso', 'text/javascript+lasso')),
|
||||
'LassoLexer': ('pip._vendor.pygments.lexers.javascript', 'Lasso', ('lasso', 'lassoscript'), ('*.lasso', '*.lasso[89]'), ('text/x-lasso',)),
|
||||
'LassoXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Lasso', ('xml+lasso',), (), ('application/xml+lasso',)),
|
||||
'LdaprcLexer': ('pip._vendor.pygments.lexers.ldap', 'LDAP configuration file', ('ldapconf', 'ldaprc'), ('.ldaprc', 'ldaprc', 'ldap.conf'), ('text/x-ldapconf',)),
|
||||
'LdifLexer': ('pip._vendor.pygments.lexers.ldap', 'LDIF', ('ldif',), ('*.ldif',), ('text/x-ldif',)),
|
||||
'Lean3Lexer': ('pip._vendor.pygments.lexers.lean', 'Lean', ('lean', 'lean3'), ('*.lean',), ('text/x-lean', 'text/x-lean3')),
|
||||
'Lean4Lexer': ('pip._vendor.pygments.lexers.lean', 'Lean4', ('lean4',), ('*.lean',), ('text/x-lean4',)),
|
||||
'LeanLexer': ('pip._vendor.pygments.lexers.theorem', 'Lean', ('lean',), ('*.lean',), ('text/x-lean',)),
|
||||
'LessCssLexer': ('pip._vendor.pygments.lexers.css', 'LessCss', ('less',), ('*.less',), ('text/x-less-css',)),
|
||||
'LighttpdConfLexer': ('pip._vendor.pygments.lexers.configs', 'Lighttpd configuration file', ('lighttpd', 'lighty'), ('lighttpd.conf',), ('text/x-lighttpd-conf',)),
|
||||
'LilyPondLexer': ('pip._vendor.pygments.lexers.lilypond', 'LilyPond', ('lilypond',), ('*.ly',), ()),
|
||||
|
|
@ -295,7 +277,6 @@ LEXERS = {
|
|||
'LogosLexer': ('pip._vendor.pygments.lexers.objective', 'Logos', ('logos',), ('*.x', '*.xi', '*.xm', '*.xmi'), ('text/x-logos',)),
|
||||
'LogtalkLexer': ('pip._vendor.pygments.lexers.prolog', 'Logtalk', ('logtalk',), ('*.lgt', '*.logtalk'), ('text/x-logtalk',)),
|
||||
'LuaLexer': ('pip._vendor.pygments.lexers.scripting', 'Lua', ('lua',), ('*.lua', '*.wlua'), ('text/x-lua', 'application/x-lua')),
|
||||
'LuauLexer': ('pip._vendor.pygments.lexers.scripting', 'Luau', ('luau',), ('*.luau',), ()),
|
||||
'MCFunctionLexer': ('pip._vendor.pygments.lexers.minecraft', 'MCFunction', ('mcfunction', 'mcf'), ('*.mcfunction',), ('text/mcfunction',)),
|
||||
'MCSchemaLexer': ('pip._vendor.pygments.lexers.minecraft', 'MCSchema', ('mcschema',), ('*.mcschema',), ('text/mcschema',)),
|
||||
'MIMELexer': ('pip._vendor.pygments.lexers.mime', 'MIME', ('mime',), (), ('multipart/mixed', 'multipart/related', 'multipart/alternative')),
|
||||
|
|
@ -309,7 +290,6 @@ LEXERS = {
|
|||
'MakoJavascriptLexer': ('pip._vendor.pygments.lexers.templates', 'JavaScript+Mako', ('javascript+mako', 'js+mako'), (), ('application/x-javascript+mako', 'text/x-javascript+mako', 'text/javascript+mako')),
|
||||
'MakoLexer': ('pip._vendor.pygments.lexers.templates', 'Mako', ('mako',), ('*.mao',), ('application/x-mako',)),
|
||||
'MakoXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Mako', ('xml+mako',), (), ('application/xml+mako',)),
|
||||
'MapleLexer': ('pip._vendor.pygments.lexers.maple', 'Maple', ('maple',), ('*.mpl', '*.mi', '*.mm'), ('text/x-maple',)),
|
||||
'MaqlLexer': ('pip._vendor.pygments.lexers.business', 'MAQL', ('maql',), ('*.maql',), ('text/x-gooddata-maql', 'application/x-gooddata-maql')),
|
||||
'MarkdownLexer': ('pip._vendor.pygments.lexers.markup', 'Markdown', ('markdown', 'md'), ('*.md', '*.markdown'), ('text/x-markdown',)),
|
||||
'MaskLexer': ('pip._vendor.pygments.lexers.javascript', 'Mask', ('mask',), ('*.mask',), ('text/x-mask',)),
|
||||
|
|
@ -324,7 +304,6 @@ LEXERS = {
|
|||
'ModelicaLexer': ('pip._vendor.pygments.lexers.modeling', 'Modelica', ('modelica',), ('*.mo',), ('text/x-modelica',)),
|
||||
'Modula2Lexer': ('pip._vendor.pygments.lexers.modula2', 'Modula-2', ('modula2', 'm2'), ('*.def', '*.mod'), ('text/x-modula2',)),
|
||||
'MoinWikiLexer': ('pip._vendor.pygments.lexers.markup', 'MoinMoin/Trac Wiki markup', ('trac-wiki', 'moin'), (), ('text/x-trac-wiki',)),
|
||||
'MojoLexer': ('pip._vendor.pygments.lexers.mojo', 'Mojo', ('mojo', '🔥'), ('*.mojo', '*.🔥'), ('text/x-mojo', 'application/x-mojo')),
|
||||
'MonkeyLexer': ('pip._vendor.pygments.lexers.basic', 'Monkey', ('monkey',), ('*.monkey',), ('text/x-monkey',)),
|
||||
'MonteLexer': ('pip._vendor.pygments.lexers.monte', 'Monte', ('monte',), ('*.mt',), ()),
|
||||
'MoonScriptLexer': ('pip._vendor.pygments.lexers.scripting', 'MoonScript', ('moonscript', 'moon'), ('*.moon',), ('text/x-moonscript', 'application/x-moonscript')),
|
||||
|
|
@ -361,7 +340,6 @@ LEXERS = {
|
|||
'NotmuchLexer': ('pip._vendor.pygments.lexers.textfmts', 'Notmuch', ('notmuch',), (), ()),
|
||||
'NuSMVLexer': ('pip._vendor.pygments.lexers.smv', 'NuSMV', ('nusmv',), ('*.smv',), ()),
|
||||
'NumPyLexer': ('pip._vendor.pygments.lexers.python', 'NumPy', ('numpy',), (), ()),
|
||||
'NumbaIRLexer': ('pip._vendor.pygments.lexers.numbair', 'Numba_IR', ('numba_ir', 'numbair'), ('*.numba_ir',), ('text/x-numba_ir', 'text/x-numbair')),
|
||||
'ObjdumpLexer': ('pip._vendor.pygments.lexers.asm', 'objdump', ('objdump',), ('*.objdump',), ('text/x-objdump',)),
|
||||
'ObjectiveCLexer': ('pip._vendor.pygments.lexers.objective', 'Objective-C', ('objective-c', 'objectivec', 'obj-c', 'objc'), ('*.m', '*.h'), ('text/x-objective-c',)),
|
||||
'ObjectiveCppLexer': ('pip._vendor.pygments.lexers.objective', 'Objective-C++', ('objective-c++', 'objectivec++', 'obj-c++', 'objc++'), ('*.mm', '*.hh'), ('text/x-objective-c++',)),
|
||||
|
|
@ -373,14 +351,11 @@ LEXERS = {
|
|||
'OocLexer': ('pip._vendor.pygments.lexers.ooc', 'Ooc', ('ooc',), ('*.ooc',), ('text/x-ooc',)),
|
||||
'OpaLexer': ('pip._vendor.pygments.lexers.ml', 'Opa', ('opa',), ('*.opa',), ('text/x-opa',)),
|
||||
'OpenEdgeLexer': ('pip._vendor.pygments.lexers.business', 'OpenEdge ABL', ('openedge', 'abl', 'progress'), ('*.p', '*.cls'), ('text/x-openedge', 'application/x-openedge')),
|
||||
'OpenScadLexer': ('pip._vendor.pygments.lexers.openscad', 'OpenSCAD', ('openscad',), ('*.scad',), ('application/x-openscad',)),
|
||||
'OrgLexer': ('pip._vendor.pygments.lexers.markup', 'Org Mode', ('org', 'orgmode', 'org-mode'), ('*.org',), ('text/org',)),
|
||||
'OutputLexer': ('pip._vendor.pygments.lexers.special', 'Text output', ('output',), (), ()),
|
||||
'PacmanConfLexer': ('pip._vendor.pygments.lexers.configs', 'PacmanConf', ('pacmanconf',), ('pacman.conf',), ()),
|
||||
'PanLexer': ('pip._vendor.pygments.lexers.dsls', 'Pan', ('pan',), ('*.pan',), ()),
|
||||
'ParaSailLexer': ('pip._vendor.pygments.lexers.parasail', 'ParaSail', ('parasail',), ('*.psi', '*.psl'), ('text/x-parasail',)),
|
||||
'PawnLexer': ('pip._vendor.pygments.lexers.pawn', 'Pawn', ('pawn',), ('*.p', '*.pwn', '*.inc'), ('text/x-pawn',)),
|
||||
'PddlLexer': ('pip._vendor.pygments.lexers.pddl', 'PDDL', ('pddl',), ('*.pddl',), ()),
|
||||
'PegLexer': ('pip._vendor.pygments.lexers.grammar_notation', 'PEG', ('peg',), ('*.peg',), ('text/x-peg',)),
|
||||
'Perl6Lexer': ('pip._vendor.pygments.lexers.perl', 'Perl6', ('perl6', 'pl6', 'raku'), ('*.pl', '*.pm', '*.nqp', '*.p6', '*.6pl', '*.p6l', '*.pl6', '*.6pm', '*.p6m', '*.pm6', '*.t', '*.raku', '*.rakumod', '*.rakutest', '*.rakudoc'), ('text/x-perl6', 'application/x-perl6')),
|
||||
'PerlLexer': ('pip._vendor.pygments.lexers.perl', 'Perl', ('perl', 'pl'), ('*.pl', '*.pm', '*.t', '*.perl'), ('text/x-perl', 'application/x-perl')),
|
||||
|
|
@ -404,19 +379,16 @@ LEXERS = {
|
|||
'ProcfileLexer': ('pip._vendor.pygments.lexers.procfile', 'Procfile', ('procfile',), ('Procfile',), ()),
|
||||
'PrologLexer': ('pip._vendor.pygments.lexers.prolog', 'Prolog', ('prolog',), ('*.ecl', '*.prolog', '*.pro', '*.pl'), ('text/x-prolog',)),
|
||||
'PromQLLexer': ('pip._vendor.pygments.lexers.promql', 'PromQL', ('promql',), ('*.promql',), ()),
|
||||
'PromelaLexer': ('pip._vendor.pygments.lexers.c_like', 'Promela', ('promela',), ('*.pml', '*.prom', '*.prm', '*.promela', '*.pr', '*.pm'), ('text/x-promela',)),
|
||||
'PropertiesLexer': ('pip._vendor.pygments.lexers.configs', 'Properties', ('properties', 'jproperties'), ('*.properties',), ('text/x-java-properties',)),
|
||||
'ProtoBufLexer': ('pip._vendor.pygments.lexers.dsls', 'Protocol Buffer', ('protobuf', 'proto'), ('*.proto',), ()),
|
||||
'PrqlLexer': ('pip._vendor.pygments.lexers.prql', 'PRQL', ('prql',), ('*.prql',), ('application/prql', 'application/x-prql')),
|
||||
'PsyshConsoleLexer': ('pip._vendor.pygments.lexers.php', 'PsySH console session for PHP', ('psysh',), (), ()),
|
||||
'PtxLexer': ('pip._vendor.pygments.lexers.ptx', 'PTX', ('ptx',), ('*.ptx',), ('text/x-ptx',)),
|
||||
'PugLexer': ('pip._vendor.pygments.lexers.html', 'Pug', ('pug', 'jade'), ('*.pug', '*.jade'), ('text/x-pug', 'text/x-jade')),
|
||||
'PuppetLexer': ('pip._vendor.pygments.lexers.dsls', 'Puppet', ('puppet',), ('*.pp',), ()),
|
||||
'PyPyLogLexer': ('pip._vendor.pygments.lexers.console', 'PyPy Log', ('pypylog', 'pypy'), ('*.pypylog',), ('application/x-pypylog',)),
|
||||
'Python2Lexer': ('pip._vendor.pygments.lexers.python', 'Python 2.x', ('python2', 'py2'), (), ('text/x-python2', 'application/x-python2')),
|
||||
'Python2TracebackLexer': ('pip._vendor.pygments.lexers.python', 'Python 2.x Traceback', ('py2tb',), ('*.py2tb',), ('text/x-python2-traceback',)),
|
||||
'PythonConsoleLexer': ('pip._vendor.pygments.lexers.python', 'Python console session', ('pycon', 'python-console'), (), ('text/x-python-doctest',)),
|
||||
'PythonLexer': ('pip._vendor.pygments.lexers.python', 'Python', ('python', 'py', 'sage', 'python3', 'py3', 'bazel', 'starlark', 'pyi'), ('*.py', '*.pyw', '*.pyi', '*.jy', '*.sage', '*.sc', 'SConstruct', 'SConscript', '*.bzl', 'BUCK', 'BUILD', 'BUILD.bazel', 'WORKSPACE', '*.tac'), ('text/x-python', 'application/x-python', 'text/x-python3', 'application/x-python3')),
|
||||
'PythonConsoleLexer': ('pip._vendor.pygments.lexers.python', 'Python console session', ('pycon',), (), ('text/x-python-doctest',)),
|
||||
'PythonLexer': ('pip._vendor.pygments.lexers.python', 'Python', ('python', 'py', 'sage', 'python3', 'py3'), ('*.py', '*.pyw', '*.pyi', '*.jy', '*.sage', '*.sc', 'SConstruct', 'SConscript', '*.bzl', 'BUCK', 'BUILD', 'BUILD.bazel', 'WORKSPACE', '*.tac'), ('text/x-python', 'application/x-python', 'text/x-python3', 'application/x-python3')),
|
||||
'PythonTracebackLexer': ('pip._vendor.pygments.lexers.python', 'Python Traceback', ('pytb', 'py3tb'), ('*.pytb', '*.py3tb'), ('text/x-python-traceback', 'text/x-python3-traceback')),
|
||||
'PythonUL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'Python+UL4', ('py+ul4',), ('*.pyul4',), ()),
|
||||
'QBasicLexer': ('pip._vendor.pygments.lexers.basic', 'QBasic', ('qbasic', 'basic'), ('*.BAS', '*.bas'), ('text/basic',)),
|
||||
|
|
@ -443,7 +415,6 @@ LEXERS = {
|
|||
'RedLexer': ('pip._vendor.pygments.lexers.rebol', 'Red', ('red', 'red/system'), ('*.red', '*.reds'), ('text/x-red', 'text/x-red-system')),
|
||||
'RedcodeLexer': ('pip._vendor.pygments.lexers.esoteric', 'Redcode', ('redcode',), ('*.cw',), ()),
|
||||
'RegeditLexer': ('pip._vendor.pygments.lexers.configs', 'reg', ('registry',), ('*.reg',), ('text/x-windows-registry',)),
|
||||
'RegoLexer': ('pip._vendor.pygments.lexers.rego', 'Rego', ('rego',), ('*.rego',), ('text/x-rego',)),
|
||||
'ResourceLexer': ('pip._vendor.pygments.lexers.resource', 'ResourceBundle', ('resourcebundle', 'resource'), (), ()),
|
||||
'RexxLexer': ('pip._vendor.pygments.lexers.scripting', 'Rexx', ('rexx', 'arexx'), ('*.rexx', '*.rex', '*.rx', '*.arexx'), ('text/x-rexx',)),
|
||||
'RhtmlLexer': ('pip._vendor.pygments.lexers.templates', 'RHTML', ('rhtml', 'html+erb', 'html+ruby'), ('*.rhtml',), ('text/html+ruby',)),
|
||||
|
|
@ -489,7 +460,6 @@ LEXERS = {
|
|||
'SnobolLexer': ('pip._vendor.pygments.lexers.snobol', 'Snobol', ('snobol',), ('*.snobol',), ('text/x-snobol',)),
|
||||
'SnowballLexer': ('pip._vendor.pygments.lexers.dsls', 'Snowball', ('snowball',), ('*.sbl',), ()),
|
||||
'SolidityLexer': ('pip._vendor.pygments.lexers.solidity', 'Solidity', ('solidity',), ('*.sol',), ()),
|
||||
'SoongLexer': ('pip._vendor.pygments.lexers.soong', 'Soong', ('androidbp', 'bp', 'soong'), ('Android.bp',), ()),
|
||||
'SophiaLexer': ('pip._vendor.pygments.lexers.sophia', 'Sophia', ('sophia',), ('*.aes',), ()),
|
||||
'SourcePawnLexer': ('pip._vendor.pygments.lexers.pawn', 'SourcePawn', ('sp',), ('*.sp',), ('text/x-sourcepawn',)),
|
||||
'SourcesListLexer': ('pip._vendor.pygments.lexers.installers', 'Debian Sourcelist', ('debsources', 'sourceslist', 'sources.list'), ('sources.list',), ()),
|
||||
|
|
@ -507,12 +477,9 @@ LEXERS = {
|
|||
'SwiftLexer': ('pip._vendor.pygments.lexers.objective', 'Swift', ('swift',), ('*.swift',), ('text/x-swift',)),
|
||||
'SwigLexer': ('pip._vendor.pygments.lexers.c_like', 'SWIG', ('swig',), ('*.swg', '*.i'), ('text/swig',)),
|
||||
'SystemVerilogLexer': ('pip._vendor.pygments.lexers.hdl', 'systemverilog', ('systemverilog', 'sv'), ('*.sv', '*.svh'), ('text/x-systemverilog',)),
|
||||
'SystemdLexer': ('pip._vendor.pygments.lexers.configs', 'Systemd', ('systemd',), ('*.service', '*.socket', '*.device', '*.mount', '*.automount', '*.swap', '*.target', '*.path', '*.timer', '*.slice', '*.scope'), ()),
|
||||
'TAPLexer': ('pip._vendor.pygments.lexers.testing', 'TAP', ('tap',), ('*.tap',), ()),
|
||||
'TNTLexer': ('pip._vendor.pygments.lexers.tnt', 'Typographic Number Theory', ('tnt',), ('*.tnt',), ()),
|
||||
'TOMLLexer': ('pip._vendor.pygments.lexers.configs', 'TOML', ('toml',), ('*.toml', 'Pipfile', 'poetry.lock'), ('application/toml',)),
|
||||
'TableGenLexer': ('pip._vendor.pygments.lexers.tablegen', 'TableGen', ('tablegen', 'td'), ('*.td',), ()),
|
||||
'TactLexer': ('pip._vendor.pygments.lexers.tact', 'Tact', ('tact',), ('*.tact',), ()),
|
||||
'TOMLLexer': ('pip._vendor.pygments.lexers.configs', 'TOML', ('toml',), ('*.toml', 'Pipfile', 'poetry.lock'), ()),
|
||||
'Tads3Lexer': ('pip._vendor.pygments.lexers.int_fiction', 'TADS 3', ('tads3',), ('*.t',), ()),
|
||||
'TalLexer': ('pip._vendor.pygments.lexers.tal', 'Tal', ('tal', 'uxntal'), ('*.tal',), ('text/x-uxntal',)),
|
||||
'TasmLexer': ('pip._vendor.pygments.lexers.asm', 'TASM', ('tasm',), ('*.asm', '*.ASM', '*.tasm'), ('text/x-tasm',)),
|
||||
|
|
@ -531,11 +498,9 @@ LEXERS = {
|
|||
'ThriftLexer': ('pip._vendor.pygments.lexers.dsls', 'Thrift', ('thrift',), ('*.thrift',), ('application/x-thrift',)),
|
||||
'TiddlyWiki5Lexer': ('pip._vendor.pygments.lexers.markup', 'tiddler', ('tid',), ('*.tid',), ('text/vnd.tiddlywiki',)),
|
||||
'TlbLexer': ('pip._vendor.pygments.lexers.tlb', 'Tl-b', ('tlb',), ('*.tlb',), ()),
|
||||
'TlsLexer': ('pip._vendor.pygments.lexers.tls', 'TLS Presentation Language', ('tls',), (), ()),
|
||||
'TodotxtLexer': ('pip._vendor.pygments.lexers.textfmts', 'Todotxt', ('todotxt',), ('todo.txt', '*.todotxt'), ('text/x-todo',)),
|
||||
'TransactSqlLexer': ('pip._vendor.pygments.lexers.sql', 'Transact-SQL', ('tsql', 't-sql'), ('*.sql',), ('text/x-tsql',)),
|
||||
'TreetopLexer': ('pip._vendor.pygments.lexers.parsers', 'Treetop', ('treetop',), ('*.treetop', '*.tt'), ()),
|
||||
'TsxLexer': ('pip._vendor.pygments.lexers.jsx', 'TSX', ('tsx',), ('*.tsx',), ('text/typescript-tsx',)),
|
||||
'TurtleLexer': ('pip._vendor.pygments.lexers.rdf', 'Turtle', ('turtle',), ('*.ttl',), ('text/turtle', 'application/x-turtle')),
|
||||
'TwigHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Twig', ('html+twig',), ('*.twig',), ('text/html+twig',)),
|
||||
'TwigLexer': ('pip._vendor.pygments.lexers.templates', 'Twig', ('twig',), (), ('application/x-twig',)),
|
||||
|
|
@ -543,13 +508,11 @@ LEXERS = {
|
|||
'TypoScriptCssDataLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScriptCssData', ('typoscriptcssdata',), (), ()),
|
||||
'TypoScriptHtmlDataLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScriptHtmlData', ('typoscripthtmldata',), (), ()),
|
||||
'TypoScriptLexer': ('pip._vendor.pygments.lexers.typoscript', 'TypoScript', ('typoscript',), ('*.typoscript',), ('text/x-typoscript',)),
|
||||
'TypstLexer': ('pip._vendor.pygments.lexers.typst', 'Typst', ('typst',), ('*.typ',), ('text/x-typst',)),
|
||||
'UL4Lexer': ('pip._vendor.pygments.lexers.ul4', 'UL4', ('ul4',), ('*.ul4',), ()),
|
||||
'UcodeLexer': ('pip._vendor.pygments.lexers.unicon', 'ucode', ('ucode',), ('*.u', '*.u1', '*.u2'), ()),
|
||||
'UniconLexer': ('pip._vendor.pygments.lexers.unicon', 'Unicon', ('unicon',), ('*.icn',), ('text/unicon',)),
|
||||
'UnixConfigLexer': ('pip._vendor.pygments.lexers.configs', 'Unix/Linux config files', ('unixconfig', 'linuxconfig'), (), ()),
|
||||
'UrbiscriptLexer': ('pip._vendor.pygments.lexers.urbi', 'UrbiScript', ('urbiscript',), ('*.u',), ('application/x-urbiscript',)),
|
||||
'UrlEncodedLexer': ('pip._vendor.pygments.lexers.html', 'urlencoded', ('urlencoded',), (), ('application/x-www-form-urlencoded',)),
|
||||
'UsdLexer': ('pip._vendor.pygments.lexers.usd', 'USD', ('usd', 'usda'), ('*.usd', '*.usda'), ()),
|
||||
'VBScriptLexer': ('pip._vendor.pygments.lexers.basic', 'VBScript', ('vbscript',), ('*.vbs', '*.VBS'), ()),
|
||||
'VCLLexer': ('pip._vendor.pygments.lexers.varnish', 'VCL', ('vcl',), ('*.vcl',), ('text/x-vclsrc',)),
|
||||
|
|
@ -558,18 +521,13 @@ LEXERS = {
|
|||
'VGLLexer': ('pip._vendor.pygments.lexers.dsls', 'VGL', ('vgl',), ('*.rpf',), ()),
|
||||
'ValaLexer': ('pip._vendor.pygments.lexers.c_like', 'Vala', ('vala', 'vapi'), ('*.vala', '*.vapi'), ('text/x-vala',)),
|
||||
'VbNetAspxLexer': ('pip._vendor.pygments.lexers.dotnet', 'aspx-vb', ('aspx-vb',), ('*.aspx', '*.asax', '*.ascx', '*.ashx', '*.asmx', '*.axd'), ()),
|
||||
'VbNetLexer': ('pip._vendor.pygments.lexers.dotnet', 'VB.net', ('vb.net', 'vbnet', 'lobas', 'oobas', 'sobas', 'visual-basic', 'visualbasic'), ('*.vb', '*.bas'), ('text/x-vbnet', 'text/x-vba')),
|
||||
'VbNetLexer': ('pip._vendor.pygments.lexers.dotnet', 'VB.net', ('vb.net', 'vbnet', 'lobas', 'oobas', 'sobas'), ('*.vb', '*.bas'), ('text/x-vbnet', 'text/x-vba')),
|
||||
'VelocityHtmlLexer': ('pip._vendor.pygments.lexers.templates', 'HTML+Velocity', ('html+velocity',), (), ('text/html+velocity',)),
|
||||
'VelocityLexer': ('pip._vendor.pygments.lexers.templates', 'Velocity', ('velocity',), ('*.vm', '*.fhtml'), ()),
|
||||
'VelocityXmlLexer': ('pip._vendor.pygments.lexers.templates', 'XML+Velocity', ('xml+velocity',), (), ('application/xml+velocity',)),
|
||||
'VerifpalLexer': ('pip._vendor.pygments.lexers.verifpal', 'Verifpal', ('verifpal',), ('*.vp',), ('text/x-verifpal',)),
|
||||
'VerilogLexer': ('pip._vendor.pygments.lexers.hdl', 'verilog', ('verilog', 'v'), ('*.v',), ('text/x-verilog',)),
|
||||
'VhdlLexer': ('pip._vendor.pygments.lexers.hdl', 'vhdl', ('vhdl',), ('*.vhdl', '*.vhd'), ('text/x-vhdl',)),
|
||||
'VimLexer': ('pip._vendor.pygments.lexers.textedit', 'VimL', ('vim',), ('*.vim', '.vimrc', '.exrc', '.gvimrc', '_vimrc', '_exrc', '_gvimrc', 'vimrc', 'gvimrc'), ('text/x-vim',)),
|
||||
'VisualPrologGrammarLexer': ('pip._vendor.pygments.lexers.vip', 'Visual Prolog Grammar', ('visualprologgrammar',), ('*.vipgrm',), ()),
|
||||
'VisualPrologLexer': ('pip._vendor.pygments.lexers.vip', 'Visual Prolog', ('visualprolog',), ('*.pro', '*.cl', '*.i', '*.pack', '*.ph'), ()),
|
||||
'VueLexer': ('pip._vendor.pygments.lexers.html', 'Vue', ('vue',), ('*.vue',), ()),
|
||||
'VyperLexer': ('pip._vendor.pygments.lexers.vyper', 'Vyper', ('vyper',), ('*.vy',), ()),
|
||||
'WDiffLexer': ('pip._vendor.pygments.lexers.diff', 'WDiff', ('wdiff',), ('*.wdiff',), ()),
|
||||
'WatLexer': ('pip._vendor.pygments.lexers.webassembly', 'WebAssembly', ('wast', 'wat'), ('*.wat', '*.wast'), ()),
|
||||
'WebIDLLexer': ('pip._vendor.pygments.lexers.webidl', 'Web IDL', ('webidl',), ('*.webidl',), ()),
|
||||
|
|
@ -594,7 +552,6 @@ LEXERS = {
|
|||
'YamlJinjaLexer': ('pip._vendor.pygments.lexers.templates', 'YAML+Jinja', ('yaml+jinja', 'salt', 'sls'), ('*.sls', '*.yaml.j2', '*.yml.j2', '*.yaml.jinja2', '*.yml.jinja2'), ('text/x-yaml+jinja', 'text/x-sls')),
|
||||
'YamlLexer': ('pip._vendor.pygments.lexers.data', 'YAML', ('yaml',), ('*.yaml', '*.yml'), ('text/x-yaml',)),
|
||||
'YangLexer': ('pip._vendor.pygments.lexers.yang', 'YANG', ('yang',), ('*.yang',), ('application/yang',)),
|
||||
'YaraLexer': ('pip._vendor.pygments.lexers.yara', 'YARA', ('yara', 'yar'), ('*.yar',), ('text/x-yara',)),
|
||||
'ZeekLexer': ('pip._vendor.pygments.lexers.dsls', 'Zeek', ('zeek', 'bro'), ('*.zeek', '*.bro'), ()),
|
||||
'ZephirLexer': ('pip._vendor.pygments.lexers.php', 'Zephir', ('zephir',), ('*.zep',), ()),
|
||||
'ZigLexer': ('pip._vendor.pygments.lexers.zig', 'Zig', ('zig',), ('*.zig',), ('text/zig',)),
|
||||
|
|
|
|||
|
|
@ -4,14 +4,15 @@
|
|||
|
||||
Lexers for Python and related languages.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
import re
|
||||
import keyword
|
||||
|
||||
from pip._vendor.pygments.lexer import DelegatingLexer, RegexLexer, include, \
|
||||
bygroups, using, default, words, combined, this
|
||||
from pip._vendor.pygments.lexer import DelegatingLexer, Lexer, RegexLexer, include, \
|
||||
bygroups, using, default, words, combined, do_insertions, this, line_re
|
||||
from pip._vendor.pygments.util import get_bool_opt, shebang_matches
|
||||
from pip._vendor.pygments.token import Text, Comment, Operator, Keyword, Name, String, \
|
||||
Number, Punctuation, Generic, Other, Error, Whitespace
|
||||
|
|
@ -26,14 +27,16 @@ class PythonLexer(RegexLexer):
|
|||
"""
|
||||
For Python source code (version 3.x).
|
||||
|
||||
.. versionadded:: 0.10
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
This is now the default ``PythonLexer``. It is still available as the
|
||||
alias ``Python3Lexer``.
|
||||
"""
|
||||
|
||||
name = 'Python'
|
||||
url = 'https://www.python.org'
|
||||
aliases = ['python', 'py', 'sage', 'python3', 'py3', 'bazel', 'starlark', 'pyi']
|
||||
url = 'http://www.python.org'
|
||||
aliases = ['python', 'py', 'sage', 'python3', 'py3']
|
||||
filenames = [
|
||||
'*.py',
|
||||
'*.pyw',
|
||||
|
|
@ -58,9 +61,8 @@ class PythonLexer(RegexLexer):
|
|||
]
|
||||
mimetypes = ['text/x-python', 'application/x-python',
|
||||
'text/x-python3', 'application/x-python3']
|
||||
version_added = '0.10'
|
||||
|
||||
uni_name = f"[{uni.xid_start}][{uni.xid_continue}]*"
|
||||
uni_name = "[%s][%s]*" % (uni.xid_start, uni.xid_continue)
|
||||
|
||||
def innerstring_rules(ttype):
|
||||
return [
|
||||
|
|
@ -109,11 +111,11 @@ class PythonLexer(RegexLexer):
|
|||
(r'\\', Text),
|
||||
include('keywords'),
|
||||
include('soft-keywords'),
|
||||
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'funcname'),
|
||||
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'classname'),
|
||||
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
||||
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'funcname'),
|
||||
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'classname'),
|
||||
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
|
||||
'fromimport'),
|
||||
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
||||
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
|
||||
'import'),
|
||||
include('expr'),
|
||||
],
|
||||
|
|
@ -222,8 +224,7 @@ class PythonLexer(RegexLexer):
|
|||
r'(match|case)\b' # a possible keyword
|
||||
r'(?![ \t]*(?:' # not followed by...
|
||||
r'[:,;=^&|@~)\]}]|(?:' + # characters and keywords that mean this isn't
|
||||
# pattern matching (but None/True/False is ok)
|
||||
r'|'.join(k for k in keyword.kwlist if k[0].islower()) + r')\b))',
|
||||
r'|'.join(keyword.kwlist) + r')\b))', # pattern matching
|
||||
bygroups(Text, Keyword), 'soft-keywords-inner'),
|
||||
],
|
||||
'soft-keywords-inner': [
|
||||
|
|
@ -329,14 +330,14 @@ class PythonLexer(RegexLexer):
|
|||
(uni_name, Name.Class, '#pop'),
|
||||
],
|
||||
'import': [
|
||||
(r'(\s+)(as)(\s+)', bygroups(Whitespace, Keyword, Whitespace)),
|
||||
(r'(\s+)(as)(\s+)', bygroups(Text, Keyword, Text)),
|
||||
(r'\.', Name.Namespace),
|
||||
(uni_name, Name.Namespace),
|
||||
(r'(\s*)(,)(\s*)', bygroups(Whitespace, Operator, Whitespace)),
|
||||
(r'(\s*)(,)(\s*)', bygroups(Text, Operator, Text)),
|
||||
default('#pop') # all else: go back
|
||||
],
|
||||
'fromimport': [
|
||||
(r'(\s+)(import)\b', bygroups(Whitespace, Keyword.Namespace), '#pop'),
|
||||
(r'(\s+)(import)\b', bygroups(Text, Keyword.Namespace), '#pop'),
|
||||
(r'\.', Name.Namespace),
|
||||
# if None occurs here, it's "raise x from None", since None can
|
||||
# never be a module name
|
||||
|
|
@ -424,11 +425,10 @@ class Python2Lexer(RegexLexer):
|
|||
"""
|
||||
|
||||
name = 'Python 2.x'
|
||||
url = 'https://www.python.org'
|
||||
url = 'http://www.python.org'
|
||||
aliases = ['python2', 'py2']
|
||||
filenames = [] # now taken over by PythonLexer (3.x)
|
||||
mimetypes = ['text/x-python2', 'application/x-python2']
|
||||
version_added = ''
|
||||
|
||||
def innerstring_rules(ttype):
|
||||
return [
|
||||
|
|
@ -459,11 +459,11 @@ class Python2Lexer(RegexLexer):
|
|||
(r'(in|is|and|or|not)\b', Operator.Word),
|
||||
(r'!=|==|<<|>>|[-~+/*%=<>&^|.]', Operator),
|
||||
include('keywords'),
|
||||
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'funcname'),
|
||||
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Whitespace), 'classname'),
|
||||
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
||||
(r'(def)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'funcname'),
|
||||
(r'(class)((?:\s|\\\s)+)', bygroups(Keyword, Text), 'classname'),
|
||||
(r'(from)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
|
||||
'fromimport'),
|
||||
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Whitespace),
|
||||
(r'(import)((?:\s|\\\s)+)', bygroups(Keyword.Namespace, Text),
|
||||
'import'),
|
||||
include('builtins'),
|
||||
include('magicfuncs'),
|
||||
|
|
@ -635,10 +635,9 @@ class Python2Lexer(RegexLexer):
|
|||
def analyse_text(text):
|
||||
return shebang_matches(text, r'pythonw?2(\.\d)?')
|
||||
|
||||
|
||||
class _PythonConsoleLexerBase(RegexLexer):
|
||||
name = 'Python console session'
|
||||
aliases = ['pycon', 'python-console']
|
||||
aliases = ['pycon']
|
||||
mimetypes = ['text/x-python-doctest']
|
||||
|
||||
"""Auxiliary lexer for `PythonConsoleLexer`.
|
||||
|
|
@ -672,7 +671,6 @@ class _PythonConsoleLexerBase(RegexLexer):
|
|||
],
|
||||
}
|
||||
|
||||
|
||||
class PythonConsoleLexer(DelegatingLexer):
|
||||
"""
|
||||
For Python console output or doctests, such as:
|
||||
|
|
@ -698,10 +696,8 @@ class PythonConsoleLexer(DelegatingLexer):
|
|||
"""
|
||||
|
||||
name = 'Python console session'
|
||||
aliases = ['pycon', 'python-console']
|
||||
aliases = ['pycon']
|
||||
mimetypes = ['text/x-python-doctest']
|
||||
url = 'https://python.org'
|
||||
version_added = ''
|
||||
|
||||
def __init__(self, **options):
|
||||
python3 = get_bool_opt(options, 'python3', True)
|
||||
|
|
@ -721,11 +717,12 @@ class PythonConsoleLexer(DelegatingLexer):
|
|||
super().__init__(pylexer, _PythonConsoleLexerBase, Other.Code, **options)
|
||||
super().__init__(tblexer, _ReplaceInnerCode, Other.Traceback, **options)
|
||||
|
||||
|
||||
class PythonTracebackLexer(RegexLexer):
|
||||
"""
|
||||
For Python 3.x tracebacks, with support for chained exceptions.
|
||||
|
||||
.. versionadded:: 1.0
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
This is now the default ``PythonTracebackLexer``. It is still available
|
||||
as the alias ``Python3TracebackLexer``.
|
||||
|
|
@ -735,8 +732,6 @@ class PythonTracebackLexer(RegexLexer):
|
|||
aliases = ['pytb', 'py3tb']
|
||||
filenames = ['*.pytb', '*.py3tb']
|
||||
mimetypes = ['text/x-python-traceback', 'text/x-python3-traceback']
|
||||
url = 'https://python.org'
|
||||
version_added = '1.0'
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
|
|
@ -783,6 +778,8 @@ class Python2TracebackLexer(RegexLexer):
|
|||
"""
|
||||
For Python tracebacks.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
|
||||
.. versionchanged:: 2.5
|
||||
This class has been renamed from ``PythonTracebackLexer``.
|
||||
``PythonTracebackLexer`` now refers to the Python 3 variant.
|
||||
|
|
@ -792,8 +789,6 @@ class Python2TracebackLexer(RegexLexer):
|
|||
aliases = ['py2tb']
|
||||
filenames = ['*.py2tb']
|
||||
mimetypes = ['text/x-python2-traceback']
|
||||
url = 'https://python.org'
|
||||
version_added = '0.7'
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
|
|
@ -830,14 +825,15 @@ class Python2TracebackLexer(RegexLexer):
|
|||
class CythonLexer(RegexLexer):
|
||||
"""
|
||||
For Pyrex and Cython source code.
|
||||
|
||||
.. versionadded:: 1.1
|
||||
"""
|
||||
|
||||
name = 'Cython'
|
||||
url = 'https://cython.org'
|
||||
url = 'http://cython.org'
|
||||
aliases = ['cython', 'pyx', 'pyrex']
|
||||
filenames = ['*.pyx', '*.pxd', '*.pxi']
|
||||
mimetypes = ['text/x-cython', 'application/x-cython']
|
||||
version_added = '1.1'
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
|
|
@ -854,16 +850,16 @@ class CythonLexer(RegexLexer):
|
|||
bygroups(Punctuation, Keyword.Type, Punctuation)),
|
||||
(r'!=|==|<<|>>|[-~+/*%=<>&^|.?]', Operator),
|
||||
(r'(from)(\d+)(<=)(\s+)(<)(\d+)(:)',
|
||||
bygroups(Keyword, Number.Integer, Operator, Whitespace, Operator,
|
||||
bygroups(Keyword, Number.Integer, Operator, Name, Operator,
|
||||
Name, Punctuation)),
|
||||
include('keywords'),
|
||||
(r'(def|property)(\s+)', bygroups(Keyword, Whitespace), 'funcname'),
|
||||
(r'(cp?def)(\s+)', bygroups(Keyword, Whitespace), 'cdef'),
|
||||
(r'(def|property)(\s+)', bygroups(Keyword, Text), 'funcname'),
|
||||
(r'(cp?def)(\s+)', bygroups(Keyword, Text), 'cdef'),
|
||||
# (should actually start a block with only cdefs)
|
||||
(r'(cdef)(:)', bygroups(Keyword, Punctuation)),
|
||||
(r'(class|struct)(\s+)', bygroups(Keyword, Whitespace), 'classname'),
|
||||
(r'(from)(\s+)', bygroups(Keyword, Whitespace), 'fromimport'),
|
||||
(r'(c?import)(\s+)', bygroups(Keyword, Whitespace), 'import'),
|
||||
(r'(class|struct)(\s+)', bygroups(Keyword, Text), 'classname'),
|
||||
(r'(from)(\s+)', bygroups(Keyword, Text), 'fromimport'),
|
||||
(r'(c?import)(\s+)', bygroups(Keyword, Text), 'import'),
|
||||
include('builtins'),
|
||||
include('backtick'),
|
||||
('(?:[rR]|[uU][rR]|[rR][uU])"""', String, 'tdqs'),
|
||||
|
|
@ -941,9 +937,9 @@ class CythonLexer(RegexLexer):
|
|||
(r'(public|readonly|extern|api|inline)\b', Keyword.Reserved),
|
||||
(r'(struct|enum|union|class)\b', Keyword),
|
||||
(r'([a-zA-Z_]\w*)(\s*)(?=[(:#=]|$)',
|
||||
bygroups(Name.Function, Whitespace), '#pop'),
|
||||
bygroups(Name.Function, Text), '#pop'),
|
||||
(r'([a-zA-Z_]\w*)(\s*)(,)',
|
||||
bygroups(Name.Function, Whitespace, Punctuation)),
|
||||
bygroups(Name.Function, Text, Punctuation)),
|
||||
(r'from\b', Keyword, '#pop'),
|
||||
(r'as\b', Keyword),
|
||||
(r':', Punctuation, '#pop'),
|
||||
|
|
@ -955,13 +951,13 @@ class CythonLexer(RegexLexer):
|
|||
(r'[a-zA-Z_]\w*', Name.Class, '#pop')
|
||||
],
|
||||
'import': [
|
||||
(r'(\s+)(as)(\s+)', bygroups(Whitespace, Keyword, Whitespace)),
|
||||
(r'(\s+)(as)(\s+)', bygroups(Text, Keyword, Text)),
|
||||
(r'[a-zA-Z_][\w.]*', Name.Namespace),
|
||||
(r'(\s*)(,)(\s*)', bygroups(Whitespace, Operator, Whitespace)),
|
||||
(r'(\s*)(,)(\s*)', bygroups(Text, Operator, Text)),
|
||||
default('#pop') # all else: go back
|
||||
],
|
||||
'fromimport': [
|
||||
(r'(\s+)(c?import)\b', bygroups(Whitespace, Keyword), '#pop'),
|
||||
(r'(\s+)(c?import)\b', bygroups(Text, Keyword), '#pop'),
|
||||
(r'[a-zA-Z_.][\w.]*', Name.Namespace),
|
||||
# ``cdef foo from "header"``, or ``for foo from 0 < i < 10``
|
||||
default('#pop'),
|
||||
|
|
@ -1011,13 +1007,13 @@ class DgLexer(RegexLexer):
|
|||
Lexer for dg,
|
||||
a functional and object-oriented programming language
|
||||
running on the CPython 3 VM.
|
||||
|
||||
.. versionadded:: 1.6
|
||||
"""
|
||||
name = 'dg'
|
||||
aliases = ['dg']
|
||||
filenames = ['*.dg']
|
||||
mimetypes = ['text/x-dg']
|
||||
url = 'http://pyos.github.io/dg'
|
||||
version_added = '1.6'
|
||||
|
||||
tokens = {
|
||||
'root': [
|
||||
|
|
@ -1108,12 +1104,13 @@ class DgLexer(RegexLexer):
|
|||
class NumPyLexer(PythonLexer):
|
||||
"""
|
||||
A Python lexer recognizing Numerical Python builtins.
|
||||
|
||||
.. versionadded:: 0.10
|
||||
"""
|
||||
|
||||
name = 'NumPy'
|
||||
url = 'https://numpy.org/'
|
||||
aliases = ['numpy']
|
||||
version_added = '0.10'
|
||||
|
||||
# override the mimetypes to not inherit them from python
|
||||
mimetypes = []
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
A simple modeline parser (based on pymodeline).
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -19,7 +19,7 @@ modeline_re = re.compile(r'''
|
|||
''', re.VERBOSE)
|
||||
|
||||
|
||||
def get_filetype_from_line(l): # noqa: E741
|
||||
def get_filetype_from_line(l):
|
||||
m = modeline_re.search(l)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
|
@ -30,8 +30,8 @@ def get_filetype_from_buffer(buf, max_lines=5):
|
|||
Scan the buffer for modelines and return filetype if one is found.
|
||||
"""
|
||||
lines = buf.splitlines()
|
||||
for line in lines[-1:-max_lines-1:-1]:
|
||||
ret = get_filetype_from_line(line)
|
||||
for l in lines[-1:-max_lines-1:-1]:
|
||||
ret = get_filetype_from_line(l)
|
||||
if ret:
|
||||
return ret
|
||||
for i in range(max_lines, -1, -1):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@
|
|||
pygments.plugin
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Pygments plugin interface.
|
||||
Pygments plugin interface. By default, this tries to use
|
||||
``importlib.metadata``, which is in the Python standard
|
||||
library since Python 3.8, or its ``importlib_metadata``
|
||||
backport for earlier versions of Python. It falls back on
|
||||
``pkg_resources`` if not found. Finally, if ``pkg_resources``
|
||||
is not found either, no plugins are loaded at all.
|
||||
|
||||
lexer plugins::
|
||||
|
||||
|
|
@ -29,10 +34,9 @@
|
|||
yourfilter = yourfilter:YourFilter
|
||||
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
from importlib.metadata import entry_points
|
||||
|
||||
LEXER_ENTRY_POINT = 'pygments.lexers'
|
||||
FORMATTER_ENTRY_POINT = 'pygments.formatters'
|
||||
|
|
@ -41,6 +45,18 @@ FILTER_ENTRY_POINT = 'pygments.filters'
|
|||
|
||||
|
||||
def iter_entry_points(group_name):
|
||||
try:
|
||||
from importlib.metadata import entry_points
|
||||
except ImportError:
|
||||
try:
|
||||
from importlib_metadata import entry_points
|
||||
except ImportError:
|
||||
try:
|
||||
from pip._vendor.pkg_resources import iter_entry_points
|
||||
except (ImportError, OSError):
|
||||
return []
|
||||
else:
|
||||
return iter_entry_points(group_name)
|
||||
groups = entry_points()
|
||||
if hasattr(groups, 'select'):
|
||||
# New interface in Python 3.10 and newer versions of the
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
An algorithm that generates optimized regexes for matching long lists of
|
||||
literal strings.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
Have a look at the `DelphiLexer` to get an idea of how to use
|
||||
this scanner.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
import re
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
Sphinx extension to generate automatic documentation of lexers,
|
||||
formatters and filters.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -33,8 +33,6 @@ LEXERDOC = '''
|
|||
|
||||
%s
|
||||
|
||||
%s
|
||||
|
||||
'''
|
||||
|
||||
FMTERDOC = '''
|
||||
|
|
@ -121,11 +119,11 @@ class PygmentsDoc(Directive):
|
|||
def write_row(*columns):
|
||||
"""Format a table row"""
|
||||
out = []
|
||||
for length, col in zip(column_lengths, columns):
|
||||
if col:
|
||||
out.append(col.ljust(length))
|
||||
for l, c in zip(column_lengths, columns):
|
||||
if c:
|
||||
out.append(c.ljust(l))
|
||||
else:
|
||||
out.append(' '*length)
|
||||
out.append(' '*l)
|
||||
|
||||
return ' '.join(out)
|
||||
|
||||
|
|
@ -149,10 +147,6 @@ class PygmentsDoc(Directive):
|
|||
|
||||
def document_lexers(self):
|
||||
from pip._vendor.pygments.lexers._mapping import LEXERS
|
||||
from pip._vendor import pygments
|
||||
import inspect
|
||||
import pathlib
|
||||
|
||||
out = []
|
||||
modules = {}
|
||||
moduledocstrings = {}
|
||||
|
|
@ -162,40 +156,16 @@ class PygmentsDoc(Directive):
|
|||
self.filenames.add(mod.__file__)
|
||||
cls = getattr(mod, classname)
|
||||
if not cls.__doc__:
|
||||
print(f"Warning: {classname} does not have a docstring.")
|
||||
print("Warning: %s does not have a docstring." % classname)
|
||||
docstring = cls.__doc__
|
||||
if isinstance(docstring, bytes):
|
||||
docstring = docstring.decode('utf8')
|
||||
|
||||
example_file = getattr(cls, '_example', None)
|
||||
if example_file:
|
||||
p = pathlib.Path(inspect.getabsfile(pygments)).parent.parent /\
|
||||
'tests' / 'examplefiles' / example_file
|
||||
content = p.read_text(encoding='utf-8')
|
||||
if not content:
|
||||
raise Exception(
|
||||
f"Empty example file '{example_file}' for lexer "
|
||||
f"{classname}")
|
||||
|
||||
if data[2]:
|
||||
lexer_name = data[2][0]
|
||||
docstring += '\n\n .. admonition:: Example\n'
|
||||
docstring += f'\n .. code-block:: {lexer_name}\n\n'
|
||||
for line in content.splitlines():
|
||||
docstring += f' {line}\n'
|
||||
|
||||
if cls.version_added:
|
||||
version_line = f'.. versionadded:: {cls.version_added}'
|
||||
else:
|
||||
version_line = ''
|
||||
|
||||
modules.setdefault(module, []).append((
|
||||
classname,
|
||||
', '.join(data[2]) or 'None',
|
||||
', '.join(data[3]).replace('*', '\\*').replace('_', '\\') or 'None',
|
||||
', '.join(data[4]) or 'None',
|
||||
docstring,
|
||||
version_line))
|
||||
docstring))
|
||||
if module not in moduledocstrings:
|
||||
moddoc = mod.__doc__
|
||||
if isinstance(moddoc, bytes):
|
||||
|
|
@ -204,7 +174,7 @@ class PygmentsDoc(Directive):
|
|||
|
||||
for module, lexers in sorted(modules.items(), key=lambda x: x[0]):
|
||||
if moduledocstrings[module] is None:
|
||||
raise Exception(f"Missing docstring for {module}")
|
||||
raise Exception("Missing docstring for %s" % (module,))
|
||||
heading = moduledocstrings[module].splitlines()[4].strip().rstrip('.')
|
||||
out.append(MODULEDOC % (module, heading, '-'*len(heading)))
|
||||
for data in lexers:
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Basic style object.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -76,7 +76,7 @@ class StyleMeta(type):
|
|||
return ''
|
||||
elif text.startswith('var') or text.startswith('calc'):
|
||||
return text
|
||||
assert False, f"wrong color format {text!r}"
|
||||
assert False, "wrong color format %r" % text
|
||||
|
||||
_styles = obj._styles = {}
|
||||
|
||||
|
|
@ -190,12 +190,6 @@ class Style(metaclass=StyleMeta):
|
|||
#: Style definitions for individual token types.
|
||||
styles = {}
|
||||
|
||||
#: user-friendly style name (used when selecting the style, so this
|
||||
# should be all-lowercase, no spaces, hyphens)
|
||||
name = 'unnamed'
|
||||
|
||||
aliases = []
|
||||
|
||||
# Attribute for lexers defined within Pygments. If set
|
||||
# to True, the style is not shown in the style gallery
|
||||
# on the website. This is intended for language-specific
|
||||
|
|
|
|||
|
|
@ -4,21 +4,65 @@
|
|||
|
||||
Contains built-in styles.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
from pip._vendor.pygments.plugin import find_plugin_styles
|
||||
from pip._vendor.pygments.util import ClassNotFound
|
||||
from pip._vendor.pygments.styles._mapping import STYLES
|
||||
|
||||
#: A dictionary of built-in styles, mapping style names to
|
||||
#: ``'submodule::classname'`` strings.
|
||||
#: This list is deprecated. Use `pygments.styles.STYLES` instead
|
||||
STYLE_MAP = {v[1]: v[0].split('.')[-1] + '::' + k for k, v in STYLES.items()}
|
||||
|
||||
#: Internal reverse mapping to make `get_style_by_name` more efficient
|
||||
_STYLE_NAME_TO_MODULE_MAP = {v[1]: (v[0], k) for k, v in STYLES.items()}
|
||||
STYLE_MAP = {
|
||||
'default': 'default::DefaultStyle',
|
||||
'emacs': 'emacs::EmacsStyle',
|
||||
'friendly': 'friendly::FriendlyStyle',
|
||||
'friendly_grayscale': 'friendly_grayscale::FriendlyGrayscaleStyle',
|
||||
'colorful': 'colorful::ColorfulStyle',
|
||||
'autumn': 'autumn::AutumnStyle',
|
||||
'murphy': 'murphy::MurphyStyle',
|
||||
'manni': 'manni::ManniStyle',
|
||||
'material': 'material::MaterialStyle',
|
||||
'monokai': 'monokai::MonokaiStyle',
|
||||
'perldoc': 'perldoc::PerldocStyle',
|
||||
'pastie': 'pastie::PastieStyle',
|
||||
'borland': 'borland::BorlandStyle',
|
||||
'trac': 'trac::TracStyle',
|
||||
'native': 'native::NativeStyle',
|
||||
'fruity': 'fruity::FruityStyle',
|
||||
'bw': 'bw::BlackWhiteStyle',
|
||||
'vim': 'vim::VimStyle',
|
||||
'vs': 'vs::VisualStudioStyle',
|
||||
'tango': 'tango::TangoStyle',
|
||||
'rrt': 'rrt::RrtStyle',
|
||||
'xcode': 'xcode::XcodeStyle',
|
||||
'igor': 'igor::IgorStyle',
|
||||
'paraiso-light': 'paraiso_light::ParaisoLightStyle',
|
||||
'paraiso-dark': 'paraiso_dark::ParaisoDarkStyle',
|
||||
'lovelace': 'lovelace::LovelaceStyle',
|
||||
'algol': 'algol::AlgolStyle',
|
||||
'algol_nu': 'algol_nu::Algol_NuStyle',
|
||||
'arduino': 'arduino::ArduinoStyle',
|
||||
'rainbow_dash': 'rainbow_dash::RainbowDashStyle',
|
||||
'abap': 'abap::AbapStyle',
|
||||
'solarized-dark': 'solarized::SolarizedDarkStyle',
|
||||
'solarized-light': 'solarized::SolarizedLightStyle',
|
||||
'sas': 'sas::SasStyle',
|
||||
'staroffice' : 'staroffice::StarofficeStyle',
|
||||
'stata': 'stata_light::StataLightStyle',
|
||||
'stata-light': 'stata_light::StataLightStyle',
|
||||
'stata-dark': 'stata_dark::StataDarkStyle',
|
||||
'inkpot': 'inkpot::InkPotStyle',
|
||||
'zenburn': 'zenburn::ZenburnStyle',
|
||||
'gruvbox-dark': 'gruvbox::GruvboxDarkStyle',
|
||||
'gruvbox-light': 'gruvbox::GruvboxLightStyle',
|
||||
'dracula': 'dracula::DraculaStyle',
|
||||
'one-dark': 'onedark::OneDarkStyle',
|
||||
'lilypond' : 'lilypond::LilyPondStyle',
|
||||
'nord': 'nord::NordStyle',
|
||||
'nord-darker': 'nord::NordDarkerStyle',
|
||||
'github-dark': 'gh_dark::GhDarkStyle'
|
||||
}
|
||||
|
||||
|
||||
def get_style_by_name(name):
|
||||
|
|
@ -29,8 +73,8 @@ def get_style_by_name(name):
|
|||
Will raise :exc:`pygments.util.ClassNotFound` if no style of that name is
|
||||
found.
|
||||
"""
|
||||
if name in _STYLE_NAME_TO_MODULE_MAP:
|
||||
mod, cls = _STYLE_NAME_TO_MODULE_MAP[name]
|
||||
if name in STYLE_MAP:
|
||||
mod, cls = STYLE_MAP[name].split('::')
|
||||
builtin = "yes"
|
||||
else:
|
||||
for found_name, style in find_plugin_styles():
|
||||
|
|
@ -38,24 +82,22 @@ def get_style_by_name(name):
|
|||
return style
|
||||
# perhaps it got dropped into our styles package
|
||||
builtin = ""
|
||||
mod = 'pygments.styles.' + name
|
||||
mod = name
|
||||
cls = name.title() + "Style"
|
||||
|
||||
try:
|
||||
mod = __import__(mod, None, None, [cls])
|
||||
mod = __import__('pygments.styles.' + mod, None, None, [cls])
|
||||
except ImportError:
|
||||
raise ClassNotFound(f"Could not find style module {mod!r}" +
|
||||
(builtin and ", though it should be builtin")
|
||||
+ ".")
|
||||
raise ClassNotFound("Could not find style module %r" % mod +
|
||||
(builtin and ", though it should be builtin") + ".")
|
||||
try:
|
||||
return getattr(mod, cls)
|
||||
except AttributeError:
|
||||
raise ClassNotFound(f"Could not find style class {cls!r} in style module.")
|
||||
raise ClassNotFound("Could not find style class %r in style module." % cls)
|
||||
|
||||
|
||||
def get_all_styles():
|
||||
"""Return a generator for all styles by name, both builtin and plugin."""
|
||||
for v in STYLES.values():
|
||||
yield v[1]
|
||||
yield from STYLE_MAP
|
||||
for name, _ in find_plugin_styles():
|
||||
yield name
|
||||
|
|
|
|||
Binary file not shown.
Binary file not shown.
|
|
@ -1,54 +0,0 @@
|
|||
# Automatically generated by scripts/gen_mapfiles.py.
|
||||
# DO NOT EDIT BY HAND; run `tox -e mapfiles` instead.
|
||||
|
||||
STYLES = {
|
||||
'AbapStyle': ('pygments.styles.abap', 'abap', ()),
|
||||
'AlgolStyle': ('pygments.styles.algol', 'algol', ()),
|
||||
'Algol_NuStyle': ('pygments.styles.algol_nu', 'algol_nu', ()),
|
||||
'ArduinoStyle': ('pygments.styles.arduino', 'arduino', ()),
|
||||
'AutumnStyle': ('pygments.styles.autumn', 'autumn', ()),
|
||||
'BlackWhiteStyle': ('pygments.styles.bw', 'bw', ()),
|
||||
'BorlandStyle': ('pygments.styles.borland', 'borland', ()),
|
||||
'CoffeeStyle': ('pygments.styles.coffee', 'coffee', ()),
|
||||
'ColorfulStyle': ('pygments.styles.colorful', 'colorful', ()),
|
||||
'DefaultStyle': ('pygments.styles.default', 'default', ()),
|
||||
'DraculaStyle': ('pygments.styles.dracula', 'dracula', ()),
|
||||
'EmacsStyle': ('pygments.styles.emacs', 'emacs', ()),
|
||||
'FriendlyGrayscaleStyle': ('pygments.styles.friendly_grayscale', 'friendly_grayscale', ()),
|
||||
'FriendlyStyle': ('pygments.styles.friendly', 'friendly', ()),
|
||||
'FruityStyle': ('pygments.styles.fruity', 'fruity', ()),
|
||||
'GhDarkStyle': ('pygments.styles.gh_dark', 'github-dark', ()),
|
||||
'GruvboxDarkStyle': ('pygments.styles.gruvbox', 'gruvbox-dark', ()),
|
||||
'GruvboxLightStyle': ('pygments.styles.gruvbox', 'gruvbox-light', ()),
|
||||
'IgorStyle': ('pygments.styles.igor', 'igor', ()),
|
||||
'InkPotStyle': ('pygments.styles.inkpot', 'inkpot', ()),
|
||||
'LightbulbStyle': ('pygments.styles.lightbulb', 'lightbulb', ()),
|
||||
'LilyPondStyle': ('pygments.styles.lilypond', 'lilypond', ()),
|
||||
'LovelaceStyle': ('pygments.styles.lovelace', 'lovelace', ()),
|
||||
'ManniStyle': ('pygments.styles.manni', 'manni', ()),
|
||||
'MaterialStyle': ('pygments.styles.material', 'material', ()),
|
||||
'MonokaiStyle': ('pygments.styles.monokai', 'monokai', ()),
|
||||
'MurphyStyle': ('pygments.styles.murphy', 'murphy', ()),
|
||||
'NativeStyle': ('pygments.styles.native', 'native', ()),
|
||||
'NordDarkerStyle': ('pygments.styles.nord', 'nord-darker', ()),
|
||||
'NordStyle': ('pygments.styles.nord', 'nord', ()),
|
||||
'OneDarkStyle': ('pygments.styles.onedark', 'one-dark', ()),
|
||||
'ParaisoDarkStyle': ('pygments.styles.paraiso_dark', 'paraiso-dark', ()),
|
||||
'ParaisoLightStyle': ('pygments.styles.paraiso_light', 'paraiso-light', ()),
|
||||
'PastieStyle': ('pygments.styles.pastie', 'pastie', ()),
|
||||
'PerldocStyle': ('pygments.styles.perldoc', 'perldoc', ()),
|
||||
'RainbowDashStyle': ('pygments.styles.rainbow_dash', 'rainbow_dash', ()),
|
||||
'RrtStyle': ('pygments.styles.rrt', 'rrt', ()),
|
||||
'SasStyle': ('pygments.styles.sas', 'sas', ()),
|
||||
'SolarizedDarkStyle': ('pygments.styles.solarized', 'solarized-dark', ()),
|
||||
'SolarizedLightStyle': ('pygments.styles.solarized', 'solarized-light', ()),
|
||||
'StarofficeStyle': ('pygments.styles.staroffice', 'staroffice', ()),
|
||||
'StataDarkStyle': ('pygments.styles.stata_dark', 'stata-dark', ()),
|
||||
'StataLightStyle': ('pygments.styles.stata_light', 'stata-light', ()),
|
||||
'TangoStyle': ('pygments.styles.tango', 'tango', ()),
|
||||
'TracStyle': ('pygments.styles.trac', 'trac', ()),
|
||||
'VimStyle': ('pygments.styles.vim', 'vim', ()),
|
||||
'VisualStudioStyle': ('pygments.styles.vs', 'vs', ()),
|
||||
'XcodeStyle': ('pygments.styles.xcode', 'xcode', ()),
|
||||
'ZenburnStyle': ('pygments.styles.zenburn', 'zenburn', ()),
|
||||
}
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Basic token types and the standard tokens.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -209,6 +209,5 @@ STANDARD_TYPES = {
|
|||
Generic.Prompt: 'gp',
|
||||
Generic.Strong: 'gs',
|
||||
Generic.Subheading: 'gu',
|
||||
Generic.EmphStrong: 'ges',
|
||||
Generic.Traceback: 'gt',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
Inspired by chartypes_create.py from the MoinMoin project.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ def _handle_runs(char_list): # pragma: no cover
|
|||
if a == b:
|
||||
yield a
|
||||
else:
|
||||
yield f'{a}-{b}'
|
||||
yield '%s-%s' % (a, b)
|
||||
|
||||
|
||||
if __name__ == '__main__': # pragma: no cover
|
||||
|
|
@ -141,13 +141,13 @@ if __name__ == '__main__': # pragma: no cover
|
|||
|
||||
for cat in sorted(categories):
|
||||
val = ''.join(_handle_runs(categories[cat]))
|
||||
fp.write(f'{cat} = {val!a}\n\n')
|
||||
fp.write('%s = %a\n\n' % (cat, val))
|
||||
|
||||
cats = sorted(categories)
|
||||
cats.remove('xid_start')
|
||||
cats.remove('xid_continue')
|
||||
fp.write(f'cats = {cats!r}\n\n')
|
||||
fp.write('cats = %r\n\n' % cats)
|
||||
|
||||
fp.write(f'# Generated from unidata {unicodedata.unidata_version}\n\n')
|
||||
fp.write('# Generated from unidata %s\n\n' % (unicodedata.unidata_version,))
|
||||
|
||||
fp.write(footer)
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Utility functions.
|
||||
|
||||
:copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS.
|
||||
:copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS.
|
||||
:license: BSD, see LICENSE for details.
|
||||
"""
|
||||
|
||||
|
|
@ -46,7 +46,8 @@ def get_choice_opt(options, optname, allowed, default=None, normcase=False):
|
|||
if normcase:
|
||||
string = string.lower()
|
||||
if string not in allowed:
|
||||
raise OptionError('Value for option {} must be one of {}'.format(optname, ', '.join(map(str, allowed))))
|
||||
raise OptionError('Value for option %s must be one of %s' %
|
||||
(optname, ', '.join(map(str, allowed))))
|
||||
return string
|
||||
|
||||
|
||||
|
|
@ -68,15 +69,17 @@ def get_bool_opt(options, optname, default=None):
|
|||
elif isinstance(string, int):
|
||||
return bool(string)
|
||||
elif not isinstance(string, str):
|
||||
raise OptionError(f'Invalid type {string!r} for option {optname}; use '
|
||||
'1/0, yes/no, true/false, on/off')
|
||||
raise OptionError('Invalid type %r for option %s; use '
|
||||
'1/0, yes/no, true/false, on/off' % (
|
||||
string, optname))
|
||||
elif string.lower() in ('1', 'yes', 'true', 'on'):
|
||||
return True
|
||||
elif string.lower() in ('0', 'no', 'false', 'off'):
|
||||
return False
|
||||
else:
|
||||
raise OptionError(f'Invalid value {string!r} for option {optname}; use '
|
||||
'1/0, yes/no, true/false, on/off')
|
||||
raise OptionError('Invalid value %r for option %s; use '
|
||||
'1/0, yes/no, true/false, on/off' % (
|
||||
string, optname))
|
||||
|
||||
|
||||
def get_int_opt(options, optname, default=None):
|
||||
|
|
@ -85,11 +88,13 @@ def get_int_opt(options, optname, default=None):
|
|||
try:
|
||||
return int(string)
|
||||
except TypeError:
|
||||
raise OptionError(f'Invalid type {string!r} for option {optname}; you '
|
||||
'must give an integer value')
|
||||
raise OptionError('Invalid type %r for option %s; you '
|
||||
'must give an integer value' % (
|
||||
string, optname))
|
||||
except ValueError:
|
||||
raise OptionError(f'Invalid value {string!r} for option {optname}; you '
|
||||
'must give an integer value')
|
||||
raise OptionError('Invalid value %r for option %s; you '
|
||||
'must give an integer value' % (
|
||||
string, optname))
|
||||
|
||||
def get_list_opt(options, optname, default=None):
|
||||
"""
|
||||
|
|
@ -103,8 +108,9 @@ def get_list_opt(options, optname, default=None):
|
|||
elif isinstance(val, (list, tuple)):
|
||||
return list(val)
|
||||
else:
|
||||
raise OptionError(f'Invalid type {val!r} for option {optname}; you '
|
||||
'must give a list value')
|
||||
raise OptionError('Invalid type %r for option %s; you '
|
||||
'must give a list value' % (
|
||||
val, optname))
|
||||
|
||||
|
||||
def docstring_headline(obj):
|
||||
|
|
@ -175,7 +181,7 @@ def shebang_matches(text, regex):
|
|||
if x and not x.startswith('-')][-1]
|
||||
except IndexError:
|
||||
return False
|
||||
regex = re.compile(rf'^{regex}(\.(exe|cmd|bat|bin))?$', re.IGNORECASE)
|
||||
regex = re.compile(r'^%s(\.(exe|cmd|bat|bin))?$' % regex, re.IGNORECASE)
|
||||
if regex.search(found) is not None:
|
||||
return True
|
||||
return False
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue