diff options
author | robot-piglet <robot-piglet@yandex-team.com> | 2024-05-20 07:58:40 +0300 |
---|---|---|
committer | robot-piglet <robot-piglet@yandex-team.com> | 2024-05-20 08:05:00 +0300 |
commit | bcd5bcc390793791d293d386b2ebefbe683fb4e1 (patch) | |
tree | c93e3b8c847237e7e7626f4a07f1b657bb34f04d /contrib/python/Pygments/py3/pygments/formatters | |
parent | 1a9f1508fe9c8c5927ffebf33197a6108e70501d (diff) | |
download | ydb-bcd5bcc390793791d293d386b2ebefbe683fb4e1.tar.gz |
Intermediate changes
Diffstat (limited to 'contrib/python/Pygments/py3/pygments/formatters')
13 files changed, 335 insertions, 142 deletions
diff --git a/contrib/python/Pygments/py3/pygments/formatters/__init__.py b/contrib/python/Pygments/py3/pygments/formatters/__init__.py index 6e482a1b73..014de975f5 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/__init__.py +++ b/contrib/python/Pygments/py3/pygments/formatters/__init__.py @@ -4,7 +4,7 @@ Pygments formatters. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 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("no formatter found for name %r" % _alias) + raise ClassNotFound(f"no formatter found for name {_alias!r}") return cls(**options) @@ -103,17 +103,16 @@ 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('no valid %s class found in %s' % - (formattername, filename)) + raise ClassNotFound(f'no valid {formattername} class found in {filename}') formatter_class = custom_namespace[formattername] # And finally instantiate it with the options return formatter_class(**options) except OSError as err: - raise ClassNotFound('cannot read %s: %s' % (filename, err)) + raise ClassNotFound(f'cannot read {filename}: {err}') except ClassNotFound: raise except Exception as err: - raise ClassNotFound('error when loading custom formatter: %s' % err) + raise ClassNotFound(f'error when loading custom formatter: {err}') def get_formatter_for_filename(fn, **options): @@ -135,7 +134,7 @@ def get_formatter_for_filename(fn, **options): for filename in cls.filenames: if _fn_matches(fn, filename): return cls(**options) - raise ClassNotFound("no formatter found for file name %r" % fn) + raise ClassNotFound(f"no formatter found for file name {fn!r}") class _automodule(types.ModuleType): diff --git a/contrib/python/Pygments/py3/pygments/formatters/bbcode.py b/contrib/python/Pygments/py3/pygments/formatters/bbcode.py index 9ce4ebc5a4..9554081062 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/bbcode.py +++ b/contrib/python/Pygments/py3/pygments/formatters/bbcode.py @@ -4,7 +4,7 @@ BBcode formatter. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -60,7 +60,7 @@ class BBCodeFormatter(Formatter): for ttype, ndef in self.style: start = end = '' if ndef['color']: - start += '[color=#%s]' % ndef['color'] + start += '[color=#{}]'.format(ndef['color']) end = '[/color]' + end if ndef['bold']: start += '[b]' diff --git a/contrib/python/Pygments/py3/pygments/formatters/groff.py b/contrib/python/Pygments/py3/pygments/formatters/groff.py index 687fd54967..a9e071128b 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/groff.py +++ b/contrib/python/Pygments/py3/pygments/formatters/groff.py @@ -4,7 +4,7 @@ Formatter for groff output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -63,7 +63,7 @@ class GroffFormatter(Formatter): for ttype, ndef in self.style: start = end = '' if ndef['color']: - start += '\\m[%s]' % ndef['color'] + start += '\\m[{}]'.format(ndef['color']) end = '\\m[]' + end if ndef['bold']: start += bold @@ -72,7 +72,7 @@ class GroffFormatter(Formatter): start += italic end = regular + end if ndef['bgcolor']: - start += '\\M[%s]' % ndef['bgcolor'] + start += '\\M[{}]'.format(ndef['bgcolor']) end = '\\M[]' + end self.styles[ttype] = start, end diff --git a/contrib/python/Pygments/py3/pygments/formatters/html.py b/contrib/python/Pygments/py3/pygments/formatters/html.py index df2469e2a5..3330c1d588 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/html.py +++ b/contrib/python/Pygments/py3/pygments/formatters/html.py @@ -4,7 +4,7 @@ Formatter for HTML output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -62,7 +62,7 @@ def _get_ttype_class(ttype): CSSFILE_TEMPLATE = '''\ /* generated by Pygments <https://pygments.org/> -Copyright 2006-2023 by the Pygments team. +Copyright 2006-2024 by the Pygments team. Licensed under the BSD license, see LICENSE for details. */ %(styledefs)s @@ -73,7 +73,7 @@ DOC_HEADER = '''\ "http://www.w3.org/TR/html4/strict.dtd"> <!-- generated by Pygments <https://pygments.org/> -Copyright 2006-2023 by the Pygments team. +Copyright 2006-2024 by the Pygments team. Licensed under the BSD license, see LICENSE for details. --> <html> @@ -488,7 +488,7 @@ class HtmlFormatter(Formatter): name = self._get_css_class(ttype) style = '' if ndef['color']: - style += 'color: %s; ' % webify(ndef['color']) + style += 'color: {}; '.format(webify(ndef['color'])) if ndef['bold']: style += 'font-weight: bold; ' if ndef['italic']: @@ -496,9 +496,9 @@ class HtmlFormatter(Formatter): if ndef['underline']: style += 'text-decoration: underline; ' if ndef['bgcolor']: - style += 'background-color: %s; ' % webify(ndef['bgcolor']) + style += 'background-color: {}; '.format(webify(ndef['bgcolor'])) if ndef['border']: - style += 'border: 1px solid %s; ' % webify(ndef['border']) + style += 'border: 1px solid {}; '.format(webify(ndef['border'])) if style: t2c[ttype] = name # save len(ttype) to enable ordering the styles by @@ -530,7 +530,7 @@ class HtmlFormatter(Formatter): styles.sort() lines = [ - '%s { %s } /* %s */' % (prefix(cls), style, repr(ttype)[6:]) + f'{prefix(cls)} {{ {style} }} /* {repr(ttype)[6:]} */' for (level, ttype, cls, style) in styles ] @@ -548,24 +548,24 @@ class HtmlFormatter(Formatter): if Text in self.ttype2class: text_style = ' ' + self.class2style[self.ttype2class[Text]][0] lines.insert( - 0, '%s{ background: %s;%s }' % ( + 0, '{}{{ background: {};{} }}'.format( prefix(''), bg_color, text_style ) ) if hl_color is not None: lines.insert( - 0, '%s { background-color: %s }' % (prefix('hll'), hl_color) + 0, '{} {{ background-color: {} }}'.format(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, + f'pre {{ {self._pre_style} }}', + f'td.linenos .normal {{ {self._linenos_style} }}', + f'span.linenos {{ {self._linenos_style} }}', + f'td.linenos .special {{ {self._linenos_special_style} }}', + f'span.linenos.special {{ {self._linenos_special_style} }}', ] return lines @@ -594,17 +594,15 @@ class HtmlFormatter(Formatter): @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 - ) + color = self.style.line_number_color + background_color = self.style.line_number_background_color + return f'color: {color}; background-color: {background_color}; padding-left: 5px; padding-right: 5px;' @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 - ) + color = self.style.line_number_special_color + background_color = self.style.line_number_special_background_color + return f'color: {color}; background-color: {background_color}; padding-left: 5px; padding-right: 5px;' def _decodeifneeded(self, value): if isinstance(value, bytes): @@ -685,9 +683,9 @@ class HtmlFormatter(Formatter): if nocls: if special_line: - style = ' style="%s"' % self._linenos_special_style + style = f' style="{self._linenos_special_style}"' else: - style = ' style="%s"' % self._linenos_style + style = f' style="{self._linenos_style}"' else: if special_line: style = ' class="special"' @@ -695,7 +693,7 @@ class HtmlFormatter(Formatter): style = ' class="normal"' if style: - line = '<span%s>%s</span>' % (style, line) + line = f'<span{style}>{line}</span>' lines.append(line) @@ -744,9 +742,9 @@ class HtmlFormatter(Formatter): if nocls: if special_line: - style = ' style="%s"' % self._linenos_special_style + style = f' style="{self._linenos_special_style}"' else: - style = ' style="%s"' % self._linenos_style + style = f' style="{self._linenos_style}"' else: if special_line: style = ' class="linenos special"' @@ -754,7 +752,7 @@ class HtmlFormatter(Formatter): style = ' class="linenos"' if style: - linenos = '<span%s>%s</span>' % (style, line) + linenos = f'<span{style}>{line}</span>' else: linenos = line @@ -791,13 +789,13 @@ class HtmlFormatter(Formatter): style = [] if (self.noclasses and not self.nobackground and self.style.background_color is not None): - style.append('background: %s' % (self.style.background_color,)) + style.append(f'background: {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 0, ('<div' + (self.cssclass and f' class="{self.cssclass}"') + + (style and (f' style="{style}"')) + '>') yield from inner yield 0, '</div>\n' @@ -814,7 +812,7 @@ class HtmlFormatter(Formatter): # 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 0, ('<pre' + (style and f' style="{style}"') + '><span></span>') yield from inner yield 0, '</pre>' @@ -843,18 +841,18 @@ class HtmlFormatter(Formatter): try: cspan = self.span_element_openers[ttype] except KeyError: - title = ' title="%s"' % '.'.join(ttype) if self.debug_token_types else '' + title = ' title="{}"'.format('.'.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) + cspan = f'<span style="{css_style}"{title}>' else: cspan = '' else: css_class = self._get_css_classes(ttype) if css_class: - cspan = '<span class="%s"%s>' % (css_class, title) + cspan = f'<span class="{css_class}"{title}>' else: cspan = '' self.span_element_openers[ttype] = cspan @@ -927,11 +925,10 @@ class HtmlFormatter(Formatter): 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) + style = (f' style="background-color: {self.style.highlight_color}"') + yield 1, f'<span{style}>{value}</span>' else: - yield 1, '<span class="hll">%s</span>' % value + yield 1, f'<span class="hll">{value}</span>' else: yield 1, value diff --git a/contrib/python/Pygments/py3/pygments/formatters/img.py b/contrib/python/Pygments/py3/pygments/formatters/img.py index dcf09da97f..d5c97d47b5 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/img.py +++ b/contrib/python/Pygments/py3/pygments/formatters/img.py @@ -4,7 +4,7 @@ Formatter for Pixmap output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ import os @@ -90,7 +90,7 @@ class FontManager: self._create_nix() def _get_nix_font_path(self, name, style): - proc = subprocess.Popen(['fc-list', "%s:style=%s" % (name, style), 'file'], + proc = subprocess.Popen(['fc-list', f"{name}:style={style}", 'file'], stdout=subprocess.PIPE, stderr=None) stdout, _ = proc.communicate() if proc.returncode == 0: @@ -110,8 +110,7 @@ class FontManager: self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) break else: - raise FontNotFound('No usable fonts named: "%s"' % - self.font_name) + raise FontNotFound(f'No usable fonts named: "{self.font_name}"') for style in ('ITALIC', 'BOLD', 'BOLDITALIC'): for stylename in STYLES[style]: path = self._get_nix_font_path(self.font_name, stylename) @@ -142,8 +141,7 @@ class FontManager: self.fonts['NORMAL'] = ImageFont.truetype(path, self.font_size) break else: - raise FontNotFound('No usable fonts named: "%s"' % - self.font_name) + raise FontNotFound(f'No usable fonts named: "{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) @@ -160,15 +158,14 @@ class FontManager: for suffix in ('', ' (TrueType)'): for style in styles: try: - valname = '%s%s%s' % (basename, style and ' '+style, suffix) + valname = '{}{}{}'.format(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])) + raise FontNotFound(f'Font {basename} ({styles[0]}) not found in registry') return None def _create_win(self): @@ -633,7 +630,11 @@ class ImageFormatter(Formatter): 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) + # see deprecations https://pillow.readthedocs.io/en/stable/releasenotes/9.2.0.html#font-size-and-offset-methods + if hasattr(draw, 'textsize'): + text_size = draw.textsize(text=value, font=font) + else: + text_size = font.getbbox(value)[2:] 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()) diff --git a/contrib/python/Pygments/py3/pygments/formatters/irc.py b/contrib/python/Pygments/py3/pygments/formatters/irc.py index 334aeef492..a1e3979beb 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/irc.py +++ b/contrib/python/Pygments/py3/pygments/formatters/irc.py @@ -4,7 +4,7 @@ Formatter for IRC output - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/contrib/python/Pygments/py3/pygments/formatters/latex.py b/contrib/python/Pygments/py3/pygments/formatters/latex.py index b130bfaf69..2f7971e8d3 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/latex.py +++ b/contrib/python/Pygments/py3/pygments/formatters/latex.py @@ -4,7 +4,7 @@ Formatter for LaTeX fancyvrb output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -23,21 +23,21 @@ 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) + replace('\x00', rf'\{commandprefix}Zbs{{}}'). \ + replace('\x01', rf'\{commandprefix}Zob{{}}'). \ + replace('\x02', rf'\{commandprefix}Zcb{{}}'). \ + replace('^', rf'\{commandprefix}Zca{{}}'). \ + replace('_', rf'\{commandprefix}Zus{{}}'). \ + replace('&', rf'\{commandprefix}Zam{{}}'). \ + replace('<', rf'\{commandprefix}Zlt{{}}'). \ + replace('>', rf'\{commandprefix}Zgt{{}}'). \ + replace('#', rf'\{commandprefix}Zsh{{}}'). \ + replace('%', rf'\{commandprefix}Zpc{{}}'). \ + replace('$', rf'\{commandprefix}Zdl{{}}'). \ + replace('-', rf'\{commandprefix}Zhy{{}}'). \ + replace("'", rf'\{commandprefix}Zsq{{}}'). \ + replace('"', rf'\{commandprefix}Zdq{{}}'). \ + replace('~', rf'\{commandprefix}Zti{{}}') DOC_TEMPLATE = r''' @@ -304,17 +304,14 @@ class LatexFormatter(Formatter): if ndef['mono']: cmndef += r'\let\$$@ff=\textsf' if ndef['color']: - cmndef += (r'\def\$$@tc##1{\textcolor[rgb]{%s}{##1}}' % - rgbcolor(ndef['color'])) + cmndef += (r'\def\$$@tc##1{{\textcolor[rgb]{{{}}}{{##1}}}}'.format(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']), + cmndef += (r'\def\$$@bc##1{{{{\setlength{{\fboxsep}}{{\string -\fboxrule}}' + r'\fcolorbox[rgb]{{{}}}{{{}}}{{\strut ##1}}}}}}'.format(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'])) + cmndef += (r'\def\$$@bc##1{{{{\setlength{{\fboxsep}}{{0pt}}' + r'\colorbox[rgb]{{{}}}{{\strut ##1}}}}}}'.format(rgbcolor(ndef['bgcolor']))) if cmndef == '': continue cmndef = cmndef.replace('$$', cp) @@ -329,7 +326,7 @@ class LatexFormatter(Formatter): cp = self.commandprefix styles = [] for name, definition in self.cmd2def.items(): - styles.append(r'\@namedef{%s@tok@%s}{%s}' % (cp, name, definition)) + styles.append(rf'\@namedef{{{cp}@tok@{name}}}{{{definition}}}') return STYLE_TEMPLATE % {'cp': self.commandprefix, 'styles': '\n'.join(styles)} @@ -410,10 +407,10 @@ class LatexFormatter(Formatter): spl = value.split('\n') for line in spl[:-1]: if line: - outfile.write("\\%s{%s}{%s}" % (cp, styleval, line)) + outfile.write(f"\\{cp}{{{styleval}}}{{{line}}}") outfile.write('\n') if spl[-1]: - outfile.write("\\%s{%s}{%s}" % (cp, styleval, spl[-1])) + outfile.write(f"\\{cp}{{{styleval}}}{{{spl[-1]}}}") else: outfile.write(value) diff --git a/contrib/python/Pygments/py3/pygments/formatters/other.py b/contrib/python/Pygments/py3/pygments/formatters/other.py index 8004764371..56e8f033ce 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/other.py +++ b/contrib/python/Pygments/py3/pygments/formatters/other.py @@ -4,7 +4,7 @@ Other formatters: NullFormatter, RawTokenFormatter. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -74,8 +74,7 @@ class RawTokenFormatter(Formatter): try: colorize(self.error_color, '') except KeyError: - raise ValueError("Invalid color %r specified" % - self.error_color) + raise ValueError(f"Invalid color {self.error_color!r} specified") def format(self, tokensource, outfile): try: @@ -147,7 +146,7 @@ class TestcaseFormatter(Formatter): outbuf = [] for ttype, value in tokensource: rawbuf.append(value) - outbuf.append('%s(%s, %r),\n' % (indentation, ttype, value)) + outbuf.append(f'{indentation}({ttype}, {value!r}),\n') before = TESTCASE_BEFORE % (''.join(rawbuf),) during = ''.join(outbuf) diff --git a/contrib/python/Pygments/py3/pygments/formatters/pangomarkup.py b/contrib/python/Pygments/py3/pygments/formatters/pangomarkup.py index 50872fe247..550dabb41b 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/pangomarkup.py +++ b/contrib/python/Pygments/py3/pygments/formatters/pangomarkup.py @@ -4,7 +4,7 @@ Formatter for Pango markup output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -45,7 +45,7 @@ class PangoMarkupFormatter(Formatter): start = '' end = '' if style['color']: - start += '<span fgcolor="#%s">' % style['color'] + start += '<span fgcolor="#{}">'.format(style['color']) end = '</span>' + end if style['bold']: start += '<b>' diff --git a/contrib/python/Pygments/py3/pygments/formatters/rtf.py b/contrib/python/Pygments/py3/pygments/formatters/rtf.py index d3a83fa603..7f8b7e4cd7 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/rtf.py +++ b/contrib/python/Pygments/py3/pygments/formatters/rtf.py @@ -4,12 +4,14 @@ A formatter that generates RTF files. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ +from collections import OrderedDict from pygments.formatter import Formatter -from pygments.util import get_int_opt, surrogatepair +from pygments.style import _ansimap +from pygments.util import get_bool_opt, get_int_opt, get_list_opt, surrogatepair __all__ = ['RtfFormatter'] @@ -42,6 +44,59 @@ class RtfFormatter(Formatter): default is 24 half-points, giving a size 12 font. .. versionadded:: 2.0 + + `linenos` + Turn on line numbering (default: ``False``). + + .. versionadded:: 2.18 + + `lineno_fontsize` + Font size for line numbers. Size is specified in half points + (default: `fontsize`). + + .. versionadded:: 2.18 + + `lineno_padding` + Number of spaces between the (inline) line numbers and the + source code (default: ``2``). + + .. versionadded:: 2.18 + + `linenostart` + The line number for the first line (default: ``1``). + + .. versionadded:: 2.18 + + `linenostep` + If set to a number n > 1, only every nth line number is printed. + + .. versionadded:: 2.18 + + `lineno_color` + Color for line numbers specified as a hex triplet, e.g. ``'5e5e5e'``. + Defaults to the style's line number color if it is a hex triplet, + otherwise ansi bright black. + + .. versionadded:: 2.18 + + `hl_lines` + Specify a list of lines to be highlighted, as line numbers separated by + spaces, e.g. ``'3 7 8'``. The line numbers are relative to the input + (i.e. the first line is line 1) unless `hl_linenostart` is set. + + .. versionadded:: 2.18 + + `hl_color` + Color for highlighting the lines specified in `hl_lines`, specified as + a hex triplet (default: style's `highlight_color`). + + .. versionadded:: 2.18 + + `hl_linenostart` + If set to ``True`` line numbers in `hl_lines` are specified + relative to `linenostart` (default ``False``). + + .. versionadded:: 2.18 """ name = 'RTF' aliases = ['rtf'] @@ -62,6 +117,40 @@ class RtfFormatter(Formatter): Formatter.__init__(self, **options) self.fontface = options.get('fontface') or '' self.fontsize = get_int_opt(options, 'fontsize', 0) + self.linenos = get_bool_opt(options, 'linenos', False) + self.lineno_fontsize = get_int_opt(options, 'lineno_fontsize', + self.fontsize) + self.lineno_padding = get_int_opt(options, 'lineno_padding', 2) + self.linenostart = abs(get_int_opt(options, 'linenostart', 1)) + self.linenostep = abs(get_int_opt(options, 'linenostep', 1)) + self.hl_linenostart = get_bool_opt(options, 'hl_linenostart', False) + + self.hl_color = options.get('hl_color', '') + if not self.hl_color: + self.hl_color = self.style.highlight_color + + self.hl_lines = [] + for lineno in get_list_opt(options, 'hl_lines', []): + try: + lineno = int(lineno) + if self.hl_linenostart: + lineno = lineno - self.linenostart + 1 + self.hl_lines.append(lineno) + except ValueError: + pass + + self.lineno_color = options.get('lineno_color', '') + if not self.lineno_color: + if self.style.line_number_color == 'inherit': + # style color is the css value 'inherit' + # default to ansi bright-black + self.lineno_color = _ansimap['ansibrightblack'] + else: + # style color is assumed to be a hex triplet as other + # colors in pygments/style.py + self.lineno_color = self.style.line_number_color + + self.color_mapping = self._create_color_mapping() def _escape(self, text): return text.replace('\\', '\\\\') \ @@ -90,43 +179,145 @@ class RtfFormatter(Formatter): # Force surrogate pairs buf.append('{\\u%d}{\\u%d}' % surrogatepair(cn)) - return ''.join(buf).replace('\n', '\\par\n') + return ''.join(buf).replace('\n', '\\par') - 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 = {} + @staticmethod + def hex_to_rtf_color(hex_color): + if hex_color[0] == "#": + hex_color = hex_color[1:] + + return '\\red%d\\green%d\\blue%d;' % ( + int(hex_color[0:2], 16), + int(hex_color[2:4], 16), + int(hex_color[4:6], 16) + ) + + def _split_tokens_on_newlines(self, tokensource): + """ + Split tokens containing newline characters into multiple token + each representing a line of the input file. Needed for numbering + lines of e.g. multiline comments. + """ + for ttype, value in tokensource: + if value == '\n': + yield (ttype, value) + elif "\n" in value: + lines = value.split("\n") + for line in lines[:-1]: + yield (ttype, line+"\n") + if lines[-1]: + yield (ttype, lines[-1]) + else: + yield (ttype, value) + + def _create_color_mapping(self): + """ + Create a mapping of style hex colors to index/offset in + the RTF color table. + """ + color_mapping = OrderedDict() offset = 1 + + if self.linenos: + color_mapping[self.lineno_color] = offset + offset += 1 + + if self.hl_lines: + color_mapping[self.hl_color] = offset + 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 ') + + return color_mapping + + @property + def _lineno_template(self): + if self.lineno_fontsize != self.fontsize: + return '{{\\fs{} \\cf{} %s{}}}'.format(self.lineno_fontsize, + self.color_mapping[self.lineno_color], + " " * self.lineno_padding) + + return '{{\\cf{} %s{}}}'.format(self.color_mapping[self.lineno_color], + " " * self.lineno_padding) + + @property + def _hl_open_str(self): + return rf'{{\highlight{self.color_mapping[self.hl_color]} ' + + @property + def _rtf_header(self): + lines = [] + # rtf 1.8 header + lines.append('{\\rtf1\\ansi\\uc0\\deff0' + '{\\fonttbl{\\f0\\fmodern\\fprq1\\fcharset0%s;}}' + % (self.fontface and ' ' + + self._escape(self.fontface) or '')) + + # color table + lines.append('{\\colortbl;') + for color, _ in self.color_mapping.items(): + lines.append(self.hex_to_rtf_color(color)) + lines.append('}') + + # font and fontsize + lines.append('\\f0\\sa0') if self.fontsize: - outfile.write('\\fs%d' % self.fontsize) + lines.append('\\fs%d' % self.fontsize) + + # ensure Libre Office Writer imports and renders consecutive + # space characters the same width, needed for line numbering. + # https://bugs.documentfoundation.org/show_bug.cgi?id=144050 + lines.append('\\dntblnsbdb') + + return lines + + def format_unencoded(self, tokensource, outfile): + for line in self._rtf_header: + outfile.write(line + "\n") + + tokensource = self._split_tokens_on_newlines(tokensource) + + # first pass of tokens to count lines, needed for line numbering + if self.linenos: + line_count = 0 + tokens = [] # for copying the token source generator + for ttype, value in tokensource: + tokens.append((ttype, value)) + if value.endswith("\n"): + line_count += 1 + + # width of line number strings (for padding with spaces) + linenos_width = len(str(line_count+self.linenostart-1)) + + tokensource = tokens # highlight stream + lineno = 1 + start_new_line = True for ttype, value in tokensource: + if start_new_line and lineno in self.hl_lines: + outfile.write(self._hl_open_str) + + if start_new_line and self.linenos: + if (lineno-self.linenostart+1)%self.linenostep == 0: + current_lineno = lineno + self.linenostart - 1 + lineno_str = str(current_lineno).rjust(linenos_width) + else: + lineno_str = "".rjust(linenos_width) + outfile.write(self._lineno_template % lineno_str) + 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']]) + buf.append('\\cb%d' % self.color_mapping[style['bgcolor']]) if style['color']: - buf.append('\\cf%d' % color_mapping[style['color']]) + buf.append('\\cf%d' % self.color_mapping[style['color']]) if style['bold']: buf.append('\\b') if style['italic']: @@ -135,12 +326,24 @@ class RtfFormatter(Formatter): buf.append('\\ul') if style['border']: buf.append('\\chbrdr\\chcfpat%d' % - color_mapping[style['border']]) + self.color_mapping[style['border']]) start = ''.join(buf) if start: - outfile.write('{%s ' % start) + outfile.write(f'{{{start} ') outfile.write(self._escape_text(value)) if start: outfile.write('}') + start_new_line = False + + # complete line of input + if value.endswith("\n"): + # close line highlighting + if lineno in self.hl_lines: + outfile.write('}') + # newline in RTF file after closing } + outfile.write("\n") + + start_new_line = True + lineno += 1 - outfile.write('}') + outfile.write('}\n') diff --git a/contrib/python/Pygments/py3/pygments/formatters/svg.py b/contrib/python/Pygments/py3/pygments/formatters/svg.py index e3cd26955a..74019b6961 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/svg.py +++ b/contrib/python/Pygments/py3/pygments/formatters/svg.py @@ -4,7 +4,7 @@ Formatter for SVG output. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ @@ -60,11 +60,11 @@ class SvgFormatter(Formatter): `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). - + for up to 4-digit line numbers. Increase width for longer code blocks). + `xoffset` Starting offset in X direction, defaults to ``0``. @@ -97,10 +97,11 @@ class SvgFormatter(Formatter): 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() + if fs.endswith('px'): + fs = fs[:-2].strip() try: int_fs = int(fs) - except: + except ValueError: int_fs = 20 self.yoffset = get_int_opt(options, 'yoffset', int_fs) self.ystep = get_int_opt(options, 'ystep', int_fs + 5) @@ -122,30 +123,27 @@ class SvgFormatter(Formatter): y = self.yoffset if not self.nowrap: if self.encoding: - outfile.write('<?xml version="1.0" encoding="%s"?>\n' % - self.encoding) + outfile.write(f'<?xml version="1.0" encoding="{self.encoding}"?>\n') 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 + outfile.write(f'<g font-family="{self.fontfamily}" font-size="{self.fontsize}">\n') + + 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)) + outfile.write(f'<text x="{x+self.linenowidth}" y="{y}" {counter_style} text-anchor="end">{counter}</text>') line_x += self.linenowidth + self.ystep counter += 1 - outfile.write('<text x="%s" y="%s" xml:space="preserve">' % (line_x, y)) + outfile.write(f'<text x="{line_x}" y="{y}" xml:space="preserve">') for ttype, value in tokensource: style = self._get_style(ttype) tspan = style and '<tspan' + style + '>' or '' @@ -159,11 +157,10 @@ class SvgFormatter(Formatter): 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)) - + outfile.write(f'<text x="{x+self.linenowidth}" y="{y}" text-anchor="end" {counter_style}>{counter}</text>') + counter += 1 - outfile.write('<text x="%s" y="%s" ' 'xml:space="preserve">' % (line_x,y)) + outfile.write(f'<text x="{line_x}" y="{y}" ' 'xml:space="preserve">') outfile.write(tspan + parts[-1] + tspanend) outfile.write('</text>') diff --git a/contrib/python/Pygments/py3/pygments/formatters/terminal.py b/contrib/python/Pygments/py3/pygments/formatters/terminal.py index 636f3503df..5c38805171 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/terminal.py +++ b/contrib/python/Pygments/py3/pygments/formatters/terminal.py @@ -4,7 +4,7 @@ Formatter for terminal output with ANSI sequences. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ diff --git a/contrib/python/Pygments/py3/pygments/formatters/terminal256.py b/contrib/python/Pygments/py3/pygments/formatters/terminal256.py index dba5b63e21..6402d8c469 100644 --- a/contrib/python/Pygments/py3/pygments/formatters/terminal256.py +++ b/contrib/python/Pygments/py3/pygments/formatters/terminal256.py @@ -10,7 +10,7 @@ Formatter version 1. - :copyright: Copyright 2006-2023 by the Pygments team, see AUTHORS. + :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS. :license: BSD, see LICENSE for details. """ |