#! /usr/bin/env python # -*- coding: iso-8859-1 -*- ## Copyright 2000-2007 by LivingLogic AG, Bayreuth/Germany. ## Copyright 2000-2007 by Walter Dörwald ## ## All Rights Reserved ## ## See __init__.py for the license r""" ll.ansistyle is a module that helps colorize terminal output with &ansi; escape sequences. Color values are integers between -1 and 511 (octal 0777). The lowest 3 bits are used for the background colors 0-7. Bits 3-5 are used for the foreground color. Bit 6 (0100) is used for bold (or other shades of the color 0-7, depending on your terminal). Bit 7 (0200) is used for underlined text and bit 8 (0400) is used for blinking text. The color value -1 means don't change the color. To add color switching escape sequences to normal output test, use a Colorizer object like this: >>> from ll import ansistyle >>> c = ansistyle.Colorizer() >>> list(c.feed("spam", 0157, "eggs", None)) ['spam', '\x1b[1;35;47m', 'eggs', '\x1b[0m'] For more info see the description of the feed. There is a second level &api; for ansistyle.Colorizer, which can be used like this: >>> from ll import ansistyle >>> list(ansistyle.Text("spam", 0157, "eggs").parts()) ['spam', '\x1b[1;35;47m', 'eggs', '\x1b[0m'] Furthermore you can print ansistyle.Text instances directly to get colored output. For more information see the documentation for ansistyle.Text. """ __version__ = tuple(map(int, "$Revision: 1.2 $"[11:-2].split("."))) # $Source: /data/cvsroot/LivingLogic/Python/core/src/ll/ansistyle.py,v $ from _ansistyle import switchcolor class Colorizer(object): """ A Colorizer object manages the current color and style and will intersperse normal output text with &ansi; escape sequences for switching output color and style. """ def __init__(self, colored=True): """ Create a Colorizer instance. If colored is false, output will never contain any color/style switching escape sequences. """ self.colored = colored self._colors = [0070] self._activecolor = 0070 def pushcolor(self, color): """ Push color onto the color stack """ self._colors.append(color) def popcolor(self): """ Pop a color from the color stack. """ return self._colors.pop(-1) def _switchcolor(self, color): if self.colored and color != -1: result = switchcolor(self._activecolor, color) self._activecolor = color return result return "" def feed(self, *strings): """ This method is a generator and will yield all the strings in strings with interspersed color switching escape sequences. Items in strings can be the following: Strings (str and unicode) Strings will be output by feed in the appropriate spot. Numbers A number in the argument sequence will switch to that color value. None This will switch back to the default color (This is different from using the color number 0070, because 0070 will only switch colors if there is some output string afterwards). Sequences Those will be recursively fed to feed with the following added functionality: The color that was active before the start of the sequence will be restored after the end. """ for string in strings: if isinstance(string, (int, long)): if string != -1: self._colors[-1] = string elif string is None: part = self._switchcolor(0070) if part: yield part elif isinstance(string, basestring): if string: part = self._switchcolor(self._colors[-1]) if part: yield part yield string else: self.pushcolor(self._colors[-1]) # duplicate current color for part in self.feed(*string): yield part self.popcolor() class Text(list): """ A colored string. A Text object is a sequence, the sequence items may either be strings or Text objects themselves. """ def __init__(self, *content): list.__init__(self, content) def append(self, *others): list.extend(self, others) def __call__(self, *others): list.extend(self, others) return self def insert(self, index, *others): list.__setslice__(self, index, index, list(others)) def __repr__(self): return "%s.%s(%s)" % (self.__class__.__module__, self.__class__.__name__, list.__repr__(self)[1:-1]) def parts(self, colored=True): """ This generator yields the strings that will make up the final colorized string. """ colorizer = Colorizer(colored) for part in colorizer.feed(self, None): yield part def string(self, colored=True): """ Return the resulting string (with escape sequences, if colored is true). """ return "".join(self.parts(colored)) def __str__(self): """ Return the resulting string with &ansi; color escape sequences. """ return self.string(True) class EscapedText(Text): """ An extension to the Text class. Special characters can be replaced by customized Text objects via the escapechar method. """ def __init__(self, *content): newcontent = [] for text in content: if isinstance(text, basestring): wasstr = None for c in text: c = self.escapechar(c) isstr = isinstance(c, basestring) if wasstr and isstr: newcontent[-1] += c else: newcontent.append(c) wasstr = isstr else: newcontent.append(text) Text.__init__(self, *newcontent) def escapechar(self, char): """ Return a replacement Text object for the character char or char itself, if the character should be used as is. This method should be overwritten by subclasses. """ return char