summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--AUTHORS1
-rw-r--r--CHANGES5
-rw-r--r--doc/docs/styles.rst51
-rw-r--r--pygments/formatters/terminal256.py20
-rw-r--r--pygments/style.py18
-rw-r--r--tests/test_lexers_other.py49
-rw-r--r--tests/test_terminal_formatter.py71
7 files changed, 84 insertions, 131 deletions
diff --git a/AUTHORS b/AUTHORS
index 600f6b22..9f45d8ea 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -33,6 +33,7 @@ Other contributors, listed alphabetically, are:
* Adam Blinkinsop -- Haskell, Redcode lexers
* Frits van Bommel -- assembler lexers
* Pierre Bourdon -- bugfixes
+* Matthias Bussonnier -- ANSI style handling for terminal-256 formatter
* chebee7i -- Python traceback lexer improvements
* Hiram Chirino -- Scaml and Jade lexers
* Ian Cooper -- VGL lexer
diff --git a/CHANGES b/CHANGES
index 0205c912..4eab214c 100644
--- a/CHANGES
+++ b/CHANGES
@@ -17,7 +17,7 @@ Version 2.2
* TypoScript (#1173)
* Varnish config (PR#554)
-- Added `lexers.find_lexer_class_by_name()` (#1203)
+- Added `lexers.find_lexer_class_by_name()`. (#1203)
- Added new token types and lexing for magic methods and variables in Python
and PHP.
@@ -28,6 +28,9 @@ Version 2.2
- Added a new token type for heredoc (and similar) string delimiters and
lexing for them in C++, Perl, PHP, Postgresql and Ruby lexers.
+- Styles can now define colors with ANSI colors for use in the 256-color
+ terminal formatter. (PR#531)
+
Version 2.1.1
-------------
diff --git a/doc/docs/styles.rst b/doc/docs/styles.rst
index 0076d062..394c8ed2 100644
--- a/doc/docs/styles.rst
+++ b/doc/docs/styles.rst
@@ -152,19 +152,19 @@ Terminal Styles
.. versionadded:: 2.2
-Custom styles used with `Terminal256` formatter can also defines colors using
-ansi-color. To do so use the `#ansigreen`, `#ansired` or any other colors
-defined in ``pygments.style.ansilist``. Foreground ANSI colors will be mapped
-to the corresponding `escape codes 30 to 37
-<https://en.wikipedia.org/wiki/ANSI_escape_code#Colors>`_ thus respecting any
-custom color mapping and themes provided by many terminal emulators. Light
-variant are treated for foreground color with and extra bold flag.
-`bg:#ansi<color>` will also be respected, except the light variant will be the
-same shade as their light variant.
-
-See following example where the color of the string `"hello world"` is governed
-by the escape sequence `\x1b34;01m` (Ansi Blue, Bold, `41` beeing red background)
-instead of an extended foreground & background color.
+Custom styles used with the 256-color terminal formatter can also map colors to
+use the 8 default ANSI colors. To do so, use ``#ansigreen``, ``#ansired`` or
+any other colors defined in :attr:`pygments.style.ansilist`. Foreground ANSI
+colors will be mapped to the corresponding `escape codes 30 to 37
+<https://en.wikipedia.org/wiki/ANSI_escape_code#Colors>`_ thus respecting any
+custom color mapping and themes provided by many terminal emulators. Light
+variants are treated as foreground color with and an added bold flag.
+``bg:#ansi<color>`` will also be respected, except the light variant will be the
+same shade as their dark variant.
+
+See the following example where the color of the string ``"hello world"`` is
+governed by the escape sequence ``\x1b[34;01m`` (Ansi Blue, Bold, 41 being red
+background) instead of an extended foreground & background color.
.. sourcecode:: pycon
@@ -182,23 +182,20 @@ instead of an extended foreground & background color.
>>> code = 'print("Hello World")'
>>> result = highlight(code, Python3Lexer(), Terminal256Formatter(style=MyStyle))
>>> print(result.encode())
- b'print(\x1b[34;41;01m"\x1b[39;49;00m\x1b[34;41;01mHello World\x1b[39;49;00m\x1b[34;41;01m"\x1b[39;49;00m)\n'
+ b'\x1b[34;41;01m"\x1b[39;49;00m\x1b[34;41;01mHello World\x1b[39;49;00m\x1b[34;41;01m"\x1b[39;49;00m'
-Style that use `#ansi*` colors might not correctly work with
-formatters others than ``Terminal256``. `HtmlFormatter` is capable of handling
-some `#ansi*` code and will map to a fixed HTML/CSS color. For example,
-`#ansiblue` will be converted to `color:#0000ff` , `#ansired` to `color:#ff0000`.
+Colors specified using ``#ansi*`` are converted to a default set of RGB colors
+when used with formatters other than the terminal-256 formatter.
-By definition of Ansi color the following color are considered "light" colors,
-and will be rendered by most terminal as bold:
+By definition of ANSI, the following colors are considered "light" colors, and
+will be rendered by most terminals as bold:
- - "darkgray", "red", "green", "yellow", "blue", "fuchsia", "turquoise",
- "white"
+- "darkgray", "red", "green", "yellow", "blue", "fuchsia", "turquoise", "white"
+The following are considered "dark" colors and will be rendered as non-bold:
-The following are considered "dark" color and will be rendered as non-bold:
-
- - "black", "darkred", "darkgreen", "brown", "darkblue", "purple", "teal",
- "lightgray"
+- "black", "darkred", "darkgreen", "brown", "darkblue", "purple", "teal",
+ "lightgray"
-Exact behavior might depends on the terminal emulator you are using, and its settings.
+Exact behavior might depends on the terminal emulator you are using, and its
+settings.
diff --git a/pygments/formatters/terminal256.py b/pygments/formatters/terminal256.py
index 1aa19f25..03c3a42a 100644
--- a/pygments/formatters/terminal256.py
+++ b/pygments/formatters/terminal256.py
@@ -55,14 +55,14 @@ class EscapeSequence:
self.bold = True
# extract fg color code.
attrs.append(esc[2:4])
- else :
+ else:
attrs.extend(("38", "5", "%i" % self.fg))
if self.bg is not None:
if self.bg in ansilist:
esc = codes[self.bg[5:]]
# extract fg color code, add 10 for bg.
attrs.append(str(int(esc[2:4])+10))
- else :
+ else:
attrs.extend(("48", "5", "%i" % self.bg))
if self.bold:
attrs.append("01")
@@ -103,15 +103,13 @@ class Terminal256Formatter(Formatter):
and converts them to nearest ANSI 256-color escape sequences. Bold and
underline attributes from the style are preserved (and displayed).
- .. versionadded:: 2.2
-
- If the used style defined foreground colors in the form `#ansi*`, then
- `Terminal256Formatter` will map these to non extended foreground color.
-
- See AnsiTerminalStyle_ for more informations.
-
.. 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.
+
Options accepted:
`style`
@@ -190,8 +188,8 @@ class Terminal256Formatter(Formatter):
def _color_index(self, color):
index = self.best_match.get(color, None)
- if color in ansilist:
- # strip the `#ansi` part an look up code
+ if color in ansilist:
+ # strip the `#ansi` part and look up code
index = color
self.best_match[color] = index
if index is None:
diff --git a/pygments/style.py b/pygments/style.py
index 8c7de528..797a1d34 100644
--- a/pygments/style.py
+++ b/pygments/style.py
@@ -12,10 +12,9 @@
from pygments.token import Token, STANDARD_TYPES
from pygments.util import add_metaclass
-
-
+# Default mapping of #ansixxx to RGB colors.
_ansimap = {
- ##
+ # dark
'#ansiblack': '000000',
'#ansidarkred': '7f0000',
'#ansidarkgreen': '007f00',
@@ -24,7 +23,7 @@ _ansimap = {
'#ansipurple': '7f007f',
'#ansiteal': '007f7f',
'#ansilightgray': 'e5e5e5',
- ### normal
+ # normal
'#ansidarkgray': '555555',
'#ansired': 'ff0000',
'#ansigreen': '00ff00',
@@ -33,8 +32,9 @@ _ansimap = {
'#ansifuchsia': 'ff00ff',
'#ansiturquoise': '00ffff',
'#ansiwhite': 'ffffff',
- }
-ansilist = set(_ansimap.keys())
+}
+ansilist = set(_ansimap)
+
class StyleMeta(type):
@@ -104,12 +104,11 @@ class StyleMeta(type):
def style_for_token(cls, token):
t = cls._styles[token]
- ansicolor = None
+ ansicolor = bgansicolor = None
color = t[0]
if color.startswith('#ansi'):
ansicolor = color
color = _ansimap[color]
- bgansicolor = None
bgcolor = t[4]
if bgcolor.startswith('#ansi'):
bgansicolor = bgcolor
@@ -126,8 +125,7 @@ class StyleMeta(type):
'sans': bool(t[7]) or None,
'mono': bool(t[8]) or None,
'ansicolor': ansicolor,
- 'bgansicolor': bgansicolor,
-
+ 'bgansicolor': bgansicolor,
}
def list_styles(cls):
diff --git a/tests/test_lexers_other.py b/tests/test_lexers_other.py
index 4c5132ad..90d05ef8 100644
--- a/tests/test_lexers_other.py
+++ b/tests/test_lexers_other.py
@@ -13,29 +13,10 @@ import unittest
from pygments.lexers import guess_lexer
from pygments.lexers.scripting import EasytrieveLexer, JclLexer, RexxLexer
+
def _exampleFilePath(filename):
return os.path.join(os.path.dirname(__file__), 'examplefiles', filename)
-_MAX_LENGTH = 80
-
-def safe_repr(obj, short=False):
- try:
- result = repr(obj)
- except Exception:
- result = object.__repr__(obj)
- if not short or len(result) < _MAX_LENGTH:
- return result
- return result[:_MAX_LENGTH] + ' [truncated]...'
-
-
-class MyTestCase(unittest.TestCase):
- ### Assert less is 2.7+ only.
- def assertLess(self, a, b, msg=None):
- """Just like self.assertTrue(a < b), but with a nicer default message."""
- if not a < b:
- standardMsg = '%s not less than %s' % (safe_repr(a), safe_repr(b))
- self.fail(self._formatMessage(msg, standardMsg))
-
class AnalyseTextTest(unittest.TestCase):
def _testCanRecognizeAndGuessExampleFiles(self, lexer):
@@ -48,8 +29,8 @@ class AnalyseTextTest(unittest.TestCase):
text = fp.read().decode('utf-8')
probability = lexer.analyse_text(text)
self.assertTrue(probability > 0,
- '%s must recognize %r' % (
- lexer.name, exampleFilePath))
+ '%s must recognize %r' % (
+ lexer.name, exampleFilePath))
guessedLexer = guess_lexer(text)
self.assertEqual(guessedLexer.name, lexer.name)
@@ -62,27 +43,27 @@ class AnalyseTextTest(unittest.TestCase):
for lexerToTest in LEXERS_TO_TEST:
self._testCanRecognizeAndGuessExampleFiles(lexerToTest)
-class EasyTrieveLexerTest(MyTestCase):
+
+class EasyTrieveLexerTest(unittest.TestCase):
def testCanGuessFromText(self):
- self.assertLess(0, EasytrieveLexer.analyse_text('MACRO'))
- self.assertLess(0, EasytrieveLexer.analyse_text('\nMACRO'))
- self.assertLess(0, EasytrieveLexer.analyse_text(' \nMACRO'))
- self.assertLess(0, EasytrieveLexer.analyse_text(' \n MACRO'))
- self.assertLess(0, EasytrieveLexer.analyse_text('*\nMACRO'))
- self.assertLess(0, EasytrieveLexer.analyse_text(
+ self.assertTrue(EasytrieveLexer.analyse_text('MACRO'))
+ self.assertTrue(EasytrieveLexer.analyse_text('\nMACRO'))
+ self.assertTrue(EasytrieveLexer.analyse_text(' \nMACRO'))
+ self.assertTrue(EasytrieveLexer.analyse_text(' \n MACRO'))
+ self.assertTrue(EasytrieveLexer.analyse_text('*\nMACRO'))
+ self.assertTrue(EasytrieveLexer.analyse_text(
'*\n *\n\n \n*\n MACRO'))
class RexxLexerTest(unittest.TestCase):
def testCanGuessFromText(self):
- self.assertAlmostEqual(0.01,
- RexxLexer.analyse_text('/* */'))
+ self.assertAlmostEqual(0.01, RexxLexer.analyse_text('/* */'))
self.assertAlmostEqual(1.0,
- RexxLexer.analyse_text('''/* Rexx */
+ RexxLexer.analyse_text('''/* Rexx */
say "hello world"'''))
val = RexxLexer.analyse_text('/* */\n'
- 'hello:pRoceduRe\n'
- ' say "hello world"')
+ 'hello:pRoceduRe\n'
+ ' say "hello world"')
self.assertTrue(val > 0.5, val)
val = RexxLexer.analyse_text('''/* */
if 1 > 0 then do
diff --git a/tests/test_terminal_formatter.py b/tests/test_terminal_formatter.py
index 84373790..cb5c6c44 100644
--- a/tests/test_terminal_formatter.py
+++ b/tests/test_terminal_formatter.py
@@ -14,7 +14,8 @@ import re
from pygments.util import StringIO
from pygments.lexers.sql import PlPgsqlLexer
-from pygments.formatters import TerminalFormatter,Terminal256Formatter, HtmlFormatter, LatexFormatter
+from pygments.formatters import TerminalFormatter, Terminal256Formatter, \
+ HtmlFormatter, LatexFormatter
from pygments.style import Style
from pygments.token import Token
@@ -31,9 +32,11 @@ DEMO_TOKENS = list(DEMO_LEXER().get_tokens(DEMO_TEXT))
ANSI_RE = re.compile(r'\x1b[\w\W]*?m')
+
def strip_ansi(x):
return ANSI_RE.sub('', x)
+
class TerminalFormatterTest(unittest.TestCase):
def test_reasonable_output(self):
out = StringIO()
@@ -56,22 +59,17 @@ class TerminalFormatterTest(unittest.TestCase):
self.assertTrue(a in b)
-
-
-
-
class MyStyle(Style):
-
styles = {
Token.Comment: '#ansidarkgray',
- Token.String: '#ansiblue bg:#ansidarkred',
- Token.Number : '#ansigreen bg:#ansidarkgreen',
- Token.Number.Hex: '#ansidarkgreen bg:#ansired',
+ Token.String: '#ansiblue bg:#ansidarkred',
+ Token.Number: '#ansigreen bg:#ansidarkgreen',
+ Token.Number.Hex: '#ansidarkgreen bg:#ansired',
}
-
-code = '''
+class Terminal256FormatterTest(unittest.TestCase):
+ code = '''
# this should be a comment
print("Hello World")
async def function(a,b,c, *d, **kwarg:Bool)->Bool:
@@ -79,49 +77,26 @@ async def function(a,b,c, *d, **kwarg:Bool)->Bool:
return 123, 0xb3e3
'''
-_MAX_LENGTH = 80
-
-def safe_repr(obj, short=False):
- try:
- result = repr(obj)
- except Exception:
- result = object.__repr__(obj)
- if not short or len(result) < _MAX_LENGTH:
- return result
- return result[:_MAX_LENGTH] + ' [truncated]...'
-
-class MyTest(unittest.TestCase):
-
- def assertIn(self, member, container, msg=None):
- """Just like self.assertTrue(a in b), but with a nicer default message."""
- if member not in container:
- standardMsg = '%s not found in %s' % (safe_repr(member),
- safe_repr(container))
- self.fail(self._formatMessage(msg, standardMsg))
-
-
-termtest = lambda x: highlight(x, Python3Lexer(), Terminal256Formatter(style=MyStyle))
-class Terminal256FormatterTest(MyTest):
-
def test_style_html(self):
style = HtmlFormatter(style=MyStyle).get_style_defs()
- self.assertIn('#555555',style, "ansigray for comment not html css style")
+ self.assertTrue('#555555' in style,
+ "ansigray for comment not html css style")
- def test_tex_works(self):
- """check tex Formatter don't crash"""
- highlight(code, Python3Lexer(), LatexFormatter(style=MyStyle))
-
- def test_html_works(self):
- highlight(code, Python3Lexer(), HtmlFormatter(style=MyStyle))
+ def test_others_work(self):
+ """check other formatters don't crash"""
+ highlight(self.code, Python3Lexer(), LatexFormatter(style=MyStyle))
+ highlight(self.code, Python3Lexer(), HtmlFormatter(style=MyStyle))
def test_256esc_seq(self):
"""
test that a few escape sequences are actualy used when using #ansi<> color codes
"""
- self.assertIn('32;41',termtest('0x123'))
- self.assertIn('32;42',termtest('123'))
- self.assertIn('30;01',termtest('#comment'))
- self.assertIn('34;41',termtest('"String"'))
-
-
+ def termtest(x):
+ return highlight(x, Python3Lexer(),
+ Terminal256Formatter(style=MyStyle))
+
+ self.assertTrue('32;41' in termtest('0x123'))
+ self.assertTrue('32;42' in termtest('123'))
+ self.assertTrue('30;01' in termtest('#comment'))
+ self.assertTrue('34;41' in termtest('"String"'))