colorama-0.2.5/0000775000175000017500000000000012157046256015013 5ustar jhartleyjhartley00000000000000colorama-0.2.5/colorama/0000775000175000017500000000000012157046256016610 5ustar jhartleyjhartley00000000000000colorama-0.2.5/colorama/ansi.py0000666000175000017500000000176511374216664020131 0ustar jhartleyjhartley00000000000000''' This module generates ANSI character codes to printing colors to terminals. See: http://en.wikipedia.org/wiki/ANSI_escape_code ''' CSI = '\033[' def code_to_chars(code): return CSI + str(code) + 'm' class AnsiCodes(object): def __init__(self, codes): for name in dir(codes): if not name.startswith('_'): value = getattr(codes, name) setattr(self, name, code_to_chars(value)) class AnsiFore: BLACK = 30 RED = 31 GREEN = 32 YELLOW = 33 BLUE = 34 MAGENTA = 35 CYAN = 36 WHITE = 37 RESET = 39 class AnsiBack: BLACK = 40 RED = 41 GREEN = 42 YELLOW = 43 BLUE = 44 MAGENTA = 45 CYAN = 46 WHITE = 47 RESET = 49 class AnsiStyle: BRIGHT = 1 DIM = 2 NORMAL = 22 RESET_ALL = 0 Fore = AnsiCodes( AnsiFore ) Back = AnsiCodes( AnsiBack ) Style = AnsiCodes( AnsiStyle ) colorama-0.2.5/colorama/__init__.py0000666000175000017500000000021212111226007020676 0ustar jhartleyjhartley00000000000000from .initialise import init, deinit, reinit from .ansi import Fore, Back, Style from .ansitowin32 import AnsiToWin32 VERSION = '0.2.5' colorama-0.2.5/colorama/win32.py0000666000175000017500000000730312111225557020122 0ustar jhartleyjhartley00000000000000 # from winbase.h STDOUT = -11 STDERR = -12 try: from ctypes import windll except ImportError: windll = None SetConsoleTextAttribute = lambda *_: None else: from ctypes import ( byref, Structure, c_char, c_short, c_uint32, c_ushort ) handles = { STDOUT: windll.kernel32.GetStdHandle(STDOUT), STDERR: windll.kernel32.GetStdHandle(STDERR), } SHORT = c_short WORD = c_ushort DWORD = c_uint32 TCHAR = c_char class COORD(Structure): """struct in wincon.h""" _fields_ = [ ('X', SHORT), ('Y', SHORT), ] class SMALL_RECT(Structure): """struct in wincon.h.""" _fields_ = [ ("Left", SHORT), ("Top", SHORT), ("Right", SHORT), ("Bottom", SHORT), ] class CONSOLE_SCREEN_BUFFER_INFO(Structure): """struct in wincon.h.""" _fields_ = [ ("dwSize", COORD), ("dwCursorPosition", COORD), ("wAttributes", WORD), ("srWindow", SMALL_RECT), ("dwMaximumWindowSize", COORD), ] def __str__(self): return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( self.dwSize.Y, self.dwSize.X , self.dwCursorPosition.Y, self.dwCursorPosition.X , self.wAttributes , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X ) def GetConsoleScreenBufferInfo(stream_id=STDOUT): handle = handles[stream_id] csbi = CONSOLE_SCREEN_BUFFER_INFO() success = windll.kernel32.GetConsoleScreenBufferInfo( handle, byref(csbi)) return csbi def SetConsoleTextAttribute(stream_id, attrs): handle = handles[stream_id] return windll.kernel32.SetConsoleTextAttribute(handle, attrs) def SetConsoleCursorPosition(stream_id, position): position = COORD(*position) # If the position is out of range, do nothing. if position.Y <= 0 or position.X <= 0: return # Adjust for Windows' SetConsoleCursorPosition: # 1. being 0-based, while ANSI is 1-based. # 2. expecting (x,y), while ANSI uses (y,x). adjusted_position = COORD(position.Y - 1, position.X - 1) # Adjust for viewport's scroll position sr = GetConsoleScreenBufferInfo(STDOUT).srWindow adjusted_position.Y += sr.Top adjusted_position.X += sr.Left # Resume normal processing handle = handles[stream_id] return windll.kernel32.SetConsoleCursorPosition(handle, adjusted_position) def FillConsoleOutputCharacter(stream_id, char, length, start): handle = handles[stream_id] char = TCHAR(char) length = DWORD(length) num_written = DWORD(0) # Note that this is hard-coded for ANSI (vs wide) bytes. success = windll.kernel32.FillConsoleOutputCharacterA( handle, char, length, start, byref(num_written)) return num_written.value def FillConsoleOutputAttribute(stream_id, attr, length, start): ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' handle = handles[stream_id] attribute = WORD(attr) length = DWORD(length) num_written = DWORD(0) # Note that this is hard-coded for ANSI (vs wide) bytes. return windll.kernel32.FillConsoleOutputAttribute( handle, attribute, length, start, byref(num_written)) colorama-0.2.5/colorama/ansitowin32.py0000666000175000017500000001512011646370660021344 0ustar jhartleyjhartley00000000000000 import re import sys from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style from .winterm import WinTerm, WinColor, WinStyle from .win32 import windll if windll is not None: winterm = WinTerm() def is_a_tty(stream): return hasattr(stream, 'isatty') and stream.isatty() class StreamWrapper(object): ''' Wraps a stream (such as stdout), acting as a transparent proxy for all attribute access apart from method 'write()', which is delegated to our Converter instance. ''' def __init__(self, wrapped, converter): # double-underscore everything to prevent clashes with names of # attributes on the wrapped stream object. self.__wrapped = wrapped self.__convertor = converter def __getattr__(self, name): return getattr(self.__wrapped, name) def write(self, text): self.__convertor.write(text) class AnsiToWin32(object): ''' Implements a 'write()' method which, on Windows, will strip ANSI character sequences from the text, and if outputting to a tty, will convert them into win32 function calls. ''' ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') def __init__(self, wrapped, convert=None, strip=None, autoreset=False): # The wrapped stream (normally sys.stdout or sys.stderr) self.wrapped = wrapped # should we reset colors to defaults after every .write() self.autoreset = autoreset # create the proxy wrapping our output stream self.stream = StreamWrapper(wrapped, self) on_windows = sys.platform.startswith('win') # should we strip ANSI sequences from our output? if strip is None: strip = on_windows self.strip = strip # should we should convert ANSI sequences into win32 calls? if convert is None: convert = on_windows and is_a_tty(wrapped) self.convert = convert # dict of ansi codes to win32 functions and parameters self.win32_calls = self.get_win32_calls() # are we wrapping stderr? self.on_stderr = self.wrapped is sys.stderr def should_wrap(self): ''' True if this class is actually needed. If false, then the output stream will not be affected, nor will win32 calls be issued, so wrapping stdout is not actually required. This will generally be False on non-Windows platforms, unless optional functionality like autoreset has been requested using kwargs to init() ''' return self.convert or self.strip or self.autoreset def get_win32_calls(self): if self.convert and winterm: return { AnsiStyle.RESET_ALL: (winterm.reset_all, ), AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), AnsiFore.RED: (winterm.fore, WinColor.RED), AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), AnsiFore.WHITE: (winterm.fore, WinColor.GREY), AnsiFore.RESET: (winterm.fore, ), AnsiBack.BLACK: (winterm.back, WinColor.BLACK), AnsiBack.RED: (winterm.back, WinColor.RED), AnsiBack.GREEN: (winterm.back, WinColor.GREEN), AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), AnsiBack.BLUE: (winterm.back, WinColor.BLUE), AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), AnsiBack.CYAN: (winterm.back, WinColor.CYAN), AnsiBack.WHITE: (winterm.back, WinColor.GREY), AnsiBack.RESET: (winterm.back, ), } def write(self, text): if self.strip or self.convert: self.write_and_convert(text) else: self.wrapped.write(text) self.wrapped.flush() if self.autoreset: self.reset_all() def reset_all(self): if self.convert: self.call_win32('m', (0,)) elif is_a_tty(self.wrapped): self.wrapped.write(Style.RESET_ALL) def write_and_convert(self, text): ''' Write the given text to our wrapped stream, stripping any ANSI sequences from the text, and optionally converting them into win32 calls. ''' cursor = 0 for match in self.ANSI_RE.finditer(text): start, end = match.span() self.write_plain_text(text, cursor, start) self.convert_ansi(*match.groups()) cursor = end self.write_plain_text(text, cursor, len(text)) def write_plain_text(self, text, start, end): if start < end: self.wrapped.write(text[start:end]) self.wrapped.flush() def convert_ansi(self, paramstring, command): if self.convert: params = self.extract_params(paramstring) self.call_win32(command, params) def extract_params(self, paramstring): def split(paramstring): for p in paramstring.split(';'): if p != '': yield int(p) return tuple(split(paramstring)) def call_win32(self, command, params): if params == []: params = [0] if command == 'm': for param in params: if param in self.win32_calls: func_args = self.win32_calls[param] func = func_args[0] args = func_args[1:] kwargs = dict(on_stderr=self.on_stderr) func(*args, **kwargs) elif command in ('H', 'f'): # set cursor position func = winterm.set_cursor_position func(params, on_stderr=self.on_stderr) elif command in ('J'): func = winterm.erase_data func(params, on_stderr=self.on_stderr) elif command == 'A': if params == () or params == None: num_rows = 1 else: num_rows = params[0] func = winterm.cursor_up func(num_rows, on_stderr=self.on_stderr) colorama-0.2.5/colorama/winterm.py0000666000175000017500000001023412111225601020630 0ustar jhartleyjhartley00000000000000 from . import win32 # from wincon.h class WinColor(object): BLACK = 0 BLUE = 1 GREEN = 2 CYAN = 3 RED = 4 MAGENTA = 5 YELLOW = 6 GREY = 7 # from wincon.h class WinStyle(object): NORMAL = 0x00 # dim text, dim background BRIGHT = 0x08 # bright text, dim background class WinTerm(object): def __init__(self): self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes self.set_attrs(self._default) self._default_fore = self._fore self._default_back = self._back self._default_style = self._style def get_attrs(self): return self._fore + self._back * 16 + self._style def set_attrs(self, value): self._fore = value & 7 self._back = (value >> 4) & 7 self._style = value & WinStyle.BRIGHT def reset_all(self, on_stderr=None): self.set_attrs(self._default) self.set_console(attrs=self._default) def fore(self, fore=None, on_stderr=False): if fore is None: fore = self._default_fore self._fore = fore self.set_console(on_stderr=on_stderr) def back(self, back=None, on_stderr=False): if back is None: back = self._default_back self._back = back self.set_console(on_stderr=on_stderr) def style(self, style=None, on_stderr=False): if style is None: style = self._default_style self._style = style self.set_console(on_stderr=on_stderr) def set_console(self, attrs=None, on_stderr=False): if attrs is None: attrs = self.get_attrs() handle = win32.STDOUT if on_stderr: handle = win32.STDERR win32.SetConsoleTextAttribute(handle, attrs) def get_position(self, handle): position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition # Because Windows coordinates are 0-based, # and win32.SetConsoleCursorPosition expects 1-based. position.X += 1 position.Y += 1 return position def set_cursor_position(self, position=None, on_stderr=False): if position is None: #I'm not currently tracking the position, so there is no default. #position = self.get_position() return handle = win32.STDOUT if on_stderr: handle = win32.STDERR win32.SetConsoleCursorPosition(handle, position) def cursor_up(self, num_rows=0, on_stderr=False): if num_rows == 0: return handle = win32.STDOUT if on_stderr: handle = win32.STDERR position = self.get_position(handle) adjusted_position = (position.Y - num_rows, position.X) self.set_cursor_position(adjusted_position, on_stderr) def erase_data(self, mode=0, on_stderr=False): # 0 (or None) should clear from the cursor to the end of the screen. # 1 should clear from the cursor to the beginning of the screen. # 2 should clear the entire screen. (And maybe move cursor to (1,1)?) # # At the moment, I only support mode 2. From looking at the API, it # should be possible to calculate a different number of bytes to clear, # and to do so relative to the cursor position. if mode[0] not in (2,): return handle = win32.STDOUT if on_stderr: handle = win32.STDERR # here's where we'll home the cursor coord_screen = win32.COORD(0,0) csbi = win32.GetConsoleScreenBufferInfo(handle) # get the number of character cells in the current buffer dw_con_size = csbi.dwSize.X * csbi.dwSize.Y # fill the entire screen with blanks win32.FillConsoleOutputCharacter(handle, ' ', dw_con_size, coord_screen) # now set the buffer's attributes accordingly win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen ); # put the cursor at (0, 0) win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y)) colorama-0.2.5/colorama/initialise.py0000666000175000017500000000237511611536660021322 0ustar jhartleyjhartley00000000000000import atexit import sys from .ansitowin32 import AnsiToWin32 orig_stdout = sys.stdout orig_stderr = sys.stderr wrapped_stdout = sys.stdout wrapped_stderr = sys.stderr atexit_done = False def reset_all(): AnsiToWin32(orig_stdout).reset_all() def init(autoreset=False, convert=None, strip=None, wrap=True): if not wrap and any([autoreset, convert, strip]): raise ValueError('wrap=False conflicts with any other arg=True') global wrapped_stdout, wrapped_stderr sys.stdout = wrapped_stdout = \ wrap_stream(orig_stdout, convert, strip, autoreset, wrap) sys.stderr = wrapped_stderr = \ wrap_stream(orig_stderr, convert, strip, autoreset, wrap) global atexit_done if not atexit_done: atexit.register(reset_all) atexit_done = True def deinit(): sys.stdout = orig_stdout sys.stderr = orig_stderr def reinit(): sys.stdout = wrapped_stdout sys.stderr = wrapped_stdout def wrap_stream(stream, convert, strip, autoreset, wrap): if wrap: wrapper = AnsiToWin32(stream, convert=convert, strip=strip, autoreset=autoreset) if wrapper.should_wrap(): stream = wrapper.stream return stream colorama-0.2.5/setup.py0000666000175000017500000000247412111223363016520 0ustar jhartleyjhartley00000000000000#!/usr/bin/env python from os.path import dirname, join from distutils.core import setup from colorama import VERSION NAME = 'colorama' def get_long_description(filename): readme = join(dirname(__file__), filename) return open(readme).read() setup( name=NAME, version=VERSION, description='Cross-platform colored terminal text.', long_description=get_long_description('README.txt'), keywords='color colour terminal text ansi windows crossplatform xplatform', author='Jonathan Hartley', author_email='tartley@tartley.com', url='http://code.google.com/p/colorama/', license='BSD', packages=[NAME], # see classifiers http://pypi.python.org/pypi?%3Aaction=list_classifiers classifiers=[ 'Development Status :: 4 - Beta', 'Environment :: Console', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.5', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Topic :: Terminals', ] ) colorama-0.2.5/LICENSE.txt0000666000175000017500000000333211366612356016642 0ustar jhartleyjhartley00000000000000Copyright (c) 2010 Jonathan Hartley Released under the New BSD license (reproduced below), or alternatively you may use this software under any OSI approved open source license such as those at http://opensource.org/licenses/alphabetical 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. * Neither the name(s) of the copyright holders, nor those of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 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 HOLDER 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. colorama-0.2.5/demos/0000775000175000017500000000000012157046256016122 5ustar jhartleyjhartley00000000000000colorama-0.2.5/demos/demo.sh0000666000175000017500000000070411601330451017367 0ustar jhartleyjhartley00000000000000#!/usr/bin/env bash # Script to demonstrate features of colorama. # This demo is also used to verify correctness visually, because we don't have automated tests. # Implemented as a bash script which invokes python so that we can test the # behaviour on exit, which resets default colors again. python demo01.py python demo02.py python demo03.py rm -f demo04.out python demo04.py 2> demo04.out cat demo04.out python demo05.py python demo06.py colorama-0.2.5/demos/demo06.py0000666000175000017500000000314511577437325017601 0ustar jhartleyjhartley00000000000000import fixpath import colorama from colorama import Fore, Back, Style from random import randint, choice from string import printable # Fore, Back and Style are convenience classes for the constant ANSI strings that set # the foreground, background and style. The don't have any magic of their own. FORES = [ Fore.BLACK, Fore.RED, Fore.GREEN, Fore.YELLOW, Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.WHITE ] BACKS = [ Back.BLACK, Back.RED, Back.GREEN, Back.YELLOW, Back.BLUE, Back.MAGENTA, Back.CYAN, Back.WHITE ] STYLES = [ Style.DIM, Style.NORMAL, Style.BRIGHT ] # This assumes your terminal is 80x24. Ansi minimum coordinate is (1,1). MINY, MAXY = 1, 24 MINX, MAXX = 1, 80 # set of printable ASCII characters, including a space. CHARS = ' ' + printable.strip() PASSES = 1000 def main(): colorama.init() # gratuitous use of lambda. pos = lambda y, x: '\x1b[%d;%dH' % (y, x) # draw a white border. print(Back.WHITE, end='') print('%s%s' % (pos(MINY, MINX), ' '*MAXX), end='') for y in range(MINY, 1+MAXY): print('%s %s ' % (pos(y, MINX), pos(y, MAXX)), end='') print('%s%s' % (pos(MAXY, MINX), ' '*MAXX), end='') # draw some blinky lights for a while. for i in range(PASSES): print('%s%s%s%s%s' % (pos(randint(1+MINY,MAXY-1), randint(1+MINX,MAXX-1)), choice(FORES), choice(BACKS), choice(STYLES), choice(CHARS)), end='') # put cursor to top, left, and set color to white-on-black with normal brightness. print('%s%s%s%s' % (pos(MINY, MINX), Fore.WHITE, Back.BLACK, Style.NORMAL), end='') if __name__ == '__main__': main() colorama-0.2.5/demos/demo04.py0000666000175000017500000000062011601330451017546 0ustar jhartleyjhartley00000000000000#!/usr/bin/python # check that stripped ANSI in redirected stderr does not affect stdout from __future__ import print_function import sys import fixpath from colorama import init, Fore init() print(Fore.GREEN + 'GREEN set on stdout. ', end='') print(Fore.RED + 'RED redirected stderr', file=sys.stderr) print('Further stdout should be GREEN, i.e., the stderr redirection should not affect stdout.') colorama-0.2.5/demos/demo01.py0000666000175000017500000000362611577436644017603 0ustar jhartleyjhartley00000000000000#!/usr/bin/python # print grid of all colors and brightnesses # uses stdout.write to write chars with no newline nor spaces between them # This should run more-or-less identically on Windows and Unix. from __future__ import print_function import sys # Add parent dir to sys path, so the following 'import colorama' always finds # the local source in preference to any installed version of colorama. import fixpath from colorama import init, Fore, Back, Style init() # Fore, Back and Style are convenience classes for the constant ANSI strings that set # the foreground, background and style. The don't have any magic of their own. FORES = [ Fore.BLACK, Fore.RED, Fore.GREEN, Fore.YELLOW, Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.WHITE ] BACKS = [ Back.BLACK, Back.RED, Back.GREEN, Back.YELLOW, Back.BLUE, Back.MAGENTA, Back.CYAN, Back.WHITE ] STYLES = [ Style.DIM, Style.NORMAL, Style.BRIGHT ] NAMES = { Fore.BLACK: 'black', Fore.RED: 'red', Fore.GREEN: 'green', Fore.YELLOW: 'yellow', Fore.BLUE: 'blue', Fore.MAGENTA: 'magenta', Fore.CYAN: 'cyan', Fore.WHITE: 'white' , Fore.RESET: 'reset', Back.BLACK: 'black', Back.RED: 'red', Back.GREEN: 'green', Back.YELLOW: 'yellow', Back.BLUE: 'blue', Back.MAGENTA: 'magenta', Back.CYAN: 'cyan', Back.WHITE: 'white', Back.RESET: 'reset' } # show the color names sys.stdout.write(' ') for foreground in FORES: sys.stdout.write('%s%-7s' % (foreground, NAMES[foreground])) print() # make a row for each background color for background in BACKS: sys.stdout.write('%s%-7s%s %s' % (background, NAMES[background], Back.RESET, background)) # make a column for each foreground color for foreground in FORES: sys.stdout.write(foreground) # show dim, normal bright for brightness in STYLES: sys.stdout.write('%sX ' % brightness) sys.stdout.write(Style.RESET_ALL + ' ' + background) print(Style.RESET_ALL) print() colorama-0.2.5/demos/fixpath.py0000666000175000017500000000046511577437003020145 0ustar jhartleyjhartley00000000000000# Add demo dir's parent to sys path, so that 'import colorama' always finds # the local source in preference to any installed version of colorama. import sys from os.path import normpath, dirname, join local_colorama_module = normpath(join(dirname(__file__), '..')) sys.path.insert(0, local_colorama_module) colorama-0.2.5/demos/demo07.py0000666000175000017500000000312611577432724017577 0ustar jhartleyjhartley00000000000000import colorama from colorama import Fore, Back, Style from random import randint, choice from string import printable # Fore, Back and Style are convenience classes for the constant ANSI strings that set # the foreground, background and style. The don't have any magic of their own. FORES = [ Fore.BLACK, Fore.RED, Fore.GREEN, Fore.YELLOW, Fore.BLUE, Fore.MAGENTA, Fore.CYAN, Fore.WHITE ] BACKS = [ Back.BLACK, Back.RED, Back.GREEN, Back.YELLOW, Back.BLUE, Back.MAGENTA, Back.CYAN, Back.WHITE ] STYLES = [ Style.DIM, Style.NORMAL, Style.BRIGHT ] # This assumes your terminal is 80x24. Ansi minimum coordinate is (1,1). MINY, MAXY = 1, 24 MINX, MAXX = 1, 80 # set of printable ASCII characters, including a space. CHARS = ' ' + printable.strip() PASSES = 1000 def main(): colorama.init() # gratuitous use of lambda. pos = lambda y, x: '\x1b[%d;%dH' % (y, x) # draw a white border. print(Back.WHITE, end='') print('%s%s' % (pos(MINY, MINX), ' '*MAXX), end='') for y in range(MINY, 1+MAXY): print('%s %s ' % (pos(y, MINX), pos(y, MAXX)), end='') print('%s%s' % (pos(MAXY, MINX), ' '*MAXX), end='') # draw some blinky lights for a while. for i in range(PASSES): print('%s%s%s%s%s' % (pos(randint(1+MINY,MAXY-1), randint(1+MINX,MAXX-1)), choice(FORES), choice(BACKS), choice(STYLES), choice(CHARS)), end='') # put cursor to top, left, and set color to white-on-black with normal brightness. print('%s%s%s%s' % (pos(MINY, MINX), Fore.WHITE, Back.BLACK, Style.NORMAL), end='') if __name__ == '__main__': main() colorama-0.2.5/demos/demo05.py0000666000175000017500000000161211577437132017571 0ustar jhartleyjhartley00000000000000#!/usr/bin/python # Demonstrate the difference between colorama intialized with wrapping on and off. # The point of the demonstration is to show how the ANSI wrapping on Windows can be disabled. # The unwrapped cases will be interpreted with ANSI on Unix, but not on Windows. from __future__ import print_function import sys import fixpath from colorama import AnsiToWin32, init, Fore init() print('%sWrapped yellow going to stdout, via the default print function.' % Fore.YELLOW) init(wrap=False) print('%sUnwrapped CYAN going to stdout, via the default print function.' % Fore.CYAN) print('%sUnwrapped CYAN, using the file parameter to write via colorama the AnsiToWin32 function.' % Fore.CYAN, file=AnsiToWin32(sys.stdout)) print('%sUnwrapped RED going to stdout, via the default print function.' % Fore.RED) init() print('%sWrapped RED going to stdout, via the default print function.' % Fore.RED) colorama-0.2.5/demos/demo02.py0000666000175000017500000000075211577437047017577 0ustar jhartleyjhartley00000000000000#!/usr/bin/python # Simple demo of changing foreground, background and brightness. from __future__ import print_function import fixpath from colorama import init, Fore, Back, Style init() print(Fore.GREEN + 'green, ' + Fore.RED + 'red, ' + Fore.RESET + 'normal, ' , end='') print(Back.GREEN + 'green, ' + Back.RED + 'red, ' + Back.RESET + 'normal, ' , end='') print(Style.DIM + 'dim, ' + Style.BRIGHT + 'bright, ' + Style.NORMAL + 'normal' , end=' ') colorama-0.2.5/demos/demo.bat0000666000175000017500000000074311577437413017550 0ustar jhartleyjhartley00000000000000 @rem Script to demonstrate features of colorama. @rem This demo is also used to verify correctness visually, because we don't have automated tests. @rem Implemented as a bash script which invokes python so that we can test the @rem behaviour on exit, which resets default colors again. python demo01.py python demo02.py python demo03.py if exist demo04.out del demo04.out python demo04.py 2> demo04.out type demo04.out python demo05.py python demo06.py colorama-0.2.5/demos/demo03.py0000666000175000017500000000113611577437061017571 0ustar jhartleyjhartley00000000000000#!/usr/bin/python # Demonstrate the different behavior when autoreset is True and False. from __future__ import print_function import fixpath from colorama import init, Fore, Back, Style init(autoreset=True) print(Fore.CYAN + Back.MAGENTA + Style.BRIGHT + 'Line 1: colored, with autoreset=True') print('Line 2: When auto reset is True, the color settings need to be set with every print.') init(autoreset=False) print(Fore.YELLOW + Back.BLUE + Style.BRIGHT + 'Line 3: colored, with autoreset=False') print('Line 4: When autoreset=False, the prior color settings linger (this is the default behavior).') colorama-0.2.5/CHANGELOG.rst0000666000175000017500000000635211601330620017024 0ustar jhartleyjhartley000000000000000.2.3 Split changelog out into separate file. 0.2.2 Fix bug which caused init() to raise, introduced in 0.2.1. Remove asserts which cause problems in various circumstances. At least some users saw asserts fail on 'success' returned from win32 functions, even though the win32 functions appear to have worked correctly. 0.2.1 Completely broken: I added a bug which caused init() to raise. Added some documentation for cursor positioning and clear screen to README. Add 'reinit' and 'deinit' functions, as suggested by Charles FOL and Romanov DA. 0.2 Merge in changes from Daniel Griffith: Add ANSI cursor positioning & partial support for clear screen. Patch submitted by Oscar Lester, don't send RESET_ALL to non-tty. Demos split into separate files and moved into their own directory. Tweak sys.path in demos so they run against local source, not installed version of Colorama. 0.1.18 Fix README (no such attr as Fore.DEFAULT, etc), kindly reported by nodakai. 0.1.17 Prevent printing of garbage ANSI codes upon installing with pip 0.1.16 Re-upload to fix previous error. Make clean now removes old MANIFEST. 0.1.15 Completely broken. Distribution was empty due to leftover invalid MANIFEST file from building on a different platform. Fix python3 incompatibility kindly reported by G |uumlaut| nter Kolousek 0.1.14 Fix hard-coded reset to white-on-black colors. Fore.RESET, Back.RESET and Style.RESET_ALL now revert to the colors as they were when init() was called. Some lessons hopefully learned about testing prior to release. 0.1.13 Completely broken: barfed when installed using pip. 0.1.12 Completely broken: contained no source code. double oops. 0.1.11 Completely broken: fatal import errors on Ubuntu. oops. 0.1.10 Stop emulating 'bright' text with bright backgrounds. Display 'normal' text using win32 normal foreground instead of bright. Drop support for 'dim' text. 0.1.9 Fix incompatibility with Python 2.5 and earlier. Remove setup.py dependency on setuptools, now uses stdlib distutils. 0.1.8 Fix ghastly errors all over the place on Ubuntu. Add init kwargs 'convert' and 'strip', which supercede the old 'wrap'. 0.1.7 Python 3 compatible. Fix: Now strips ansi on windows without necessarily converting it to win32 calls (eg. if output is not a tty.) Fix: Flaky interaction of interleaved ansi sent to stdout and stderr. Improved demo.sh (hg checkout only.) 0.1.6 Fix ansi sequences with no params now default to parmlist of [0]. Fix flaky behaviour of autoreset and reset_all atexit. Fix stacking of repeated atexit calls - now just called once. Fix ghastly import problems while running tests. 'demo.py' (hg checkout only) now demonstrates autoreset and reset atexit. Provide colorama.VERSION, used by setup.py. Tests defanged so they no longer actually change terminal color when run. 0.1.5 Now works on Ubuntu. 0.1.4 Implemented RESET_ALL on application exit 0.1.3 Implemented init(wrap=False) 0.1.2 Implemented init(autoreset=True) 0.1.1 Minor tidy 0.1 Works on Windows for foreground color, background color, bright or dim .. |uumlaut| unicode:: U+00FC .. u with umlaut :trim: colorama-0.2.5/PKG-INFO0000664000175000017500000003140212157046256016110 0ustar jhartleyjhartley00000000000000Metadata-Version: 1.1 Name: colorama Version: 0.2.5 Summary: Cross-platform colored terminal text. Home-page: http://code.google.com/p/colorama/ Author: Jonathan Hartley Author-email: tartley@tartley.com License: BSD Description: Download and docs: http://pypi.python.org/pypi/colorama Development: http://code.google.com/p/colorama Discussion group: https://groups.google.com/forum/#!forum/python-colorama Description =========== Makes ANSI escape character sequences, for producing colored terminal text and cursor positioning, work under MS Windows. ANSI escape character sequences have long been used to produce colored terminal text and cursor positioning on Unix and Macs. Colorama makes this work on Windows, too. It also provides some shortcuts to help generate ANSI sequences, and works fine in conjunction with any other ANSI sequence generation library, such as Termcolor (http://pypi.python.org/pypi/termcolor.) This has the upshot of providing a simple cross-platform API for printing colored terminal text from Python, and has the happy side-effect that existing applications or libraries which use ANSI sequences to produce colored output on Linux or Macs can now also work on Windows, simply by calling ``colorama.init()``. Demo scripts in the source code repository prints some colored text using ANSI sequences. Compare their output under Gnome-terminal's built in ANSI handling, versus on Windows Command-Prompt using Colorama: .. image:: http://colorama.googlecode.com/hg/screenshots/ubuntu-demo.png :width: 661 :height: 357 :alt: ANSI sequences on Ubuntu under gnome-terminal. .. image:: http://colorama.googlecode.com/hg/screenshots/windows-demo.png :width: 668 :height: 325 :alt: Same ANSI sequences on Windows, using Colorama. These screengrabs show that Colorama on Windows does not support ANSI 'dim text': it looks the same as 'normal text'. Dependencies ============ None, other than Python. Tested on Python 2.5.5, 2.6.5, 2.7, 3.1.2, and 3.2 Usage ===== Initialisation -------------- Applications should initialise Colorama using:: from colorama import init init() If you are on Windows, the call to ``init()`` will start filtering ANSI escape sequences out of any text sent to stdout or stderr, and will replace them with equivalent Win32 calls. Calling ``init()`` has no effect on other platforms (unless you request other optional functionality, see keyword args below.) The intention is that applications can call ``init()`` unconditionally on all platforms, after which ANSI output should just work. To stop using colorama before your program exits, simply call ``deinit()``. This will restore stdout and stderr to their original values, so that Colorama is disabled. To start using Colorama again, call ``reinit()``, which wraps stdout and stderr again, but is cheaper to call than doing ``init()`` all over again. Colored Output -------------- Cross-platform printing of colored text can then be done using Colorama's constant shorthand for ANSI escape sequences:: from colorama import Fore, Back, Style print(Fore.RED + 'some red text') print(Back.GREEN + 'and with a green background') print(Style.DIM + 'and in dim text') print(Fore.RESET + Back.RESET + Style.RESET_ALL) print('back to normal now') or simply by manually printing ANSI sequences from your own code:: print('/033[31m' + 'some red text') print('/033[30m' # and reset to default color) or Colorama can be used happily in conjunction with existing ANSI libraries such as Termcolor:: from colorama import init from termcolor import colored # use Colorama to make Termcolor work on Windows too init() # then use Termcolor for all colored text output print(colored('Hello, World!', 'green', 'on_red')) Available formatting constants are:: Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Style: DIM, NORMAL, BRIGHT, RESET_ALL Style.RESET_ALL resets foreground, background and brightness. Colorama will perform this reset automatically on program exit. Cursor Positioning ------------------ ANSI codes to reposition the cursor are supported. See demos/demo06.py for an example of how to generate them. Init Keyword Args ----------------- ``init()`` accepts some kwargs to override default behaviour. init(autoreset=False): If you find yourself repeatedly sending reset sequences to turn off color changes at the end of every print, then ``init(autoreset=True)`` will automate that:: from colorama import init init(autoreset=True) print(Fore.RED + 'some red text') print('automatically back to default color again') init(strip=None): Pass ``True`` or ``False`` to override whether ansi codes should be stripped from the output. The default behaviour is to strip if on Windows. init(convert=None): Pass ``True`` or ``False`` to override whether to convert ansi codes in the output into win32 calls. The default behaviour is to convert if on Windows and output is to a tty (terminal). init(wrap=True): On Windows, colorama works by replacing ``sys.stdout`` and ``sys.stderr`` with proxy objects, which override the .write() method to do their work. If this wrapping causes you problems, then this can be disabled by passing ``init(wrap=False)``. The default behaviour is to wrap if autoreset or strip or convert are True. When wrapping is disabled, colored printing on non-Windows platforms will continue to work as normal. To do cross-platform colored output, you can use Colorama's ``AnsiToWin32`` proxy directly:: import sys from colorama import init, AnsiToWin32 init(wrap=False) stream = AnsiToWin32(sys.stderr).stream # Python 2 print >>stream, Fore.BLUE + 'blue text on stderr' # Python 3 print(Fore.BLUE + 'blue text on stderr', file=stream) Status & Known Problems ======================= I've personally only tested it on WinXP (CMD, Console2), Ubuntu (gnome-terminal, xterm), and OSX. Some presumably valid ANSI sequences aren't recognised (see details below) but to my knowledge nobody has yet complained about this. Puzzling. See outstanding issues and wishlist at: http://code.google.com/p/colorama/issues/list If anything doesn't work for you, or doesn't do what you expected or hoped for, I'd love to hear about it on that issues list, would be delighted by patches, and would be happy to grant commit access to anyone who submits a working patch or two. Recognised ANSI Sequences ========================= ANSI sequences generally take the form: ESC [ ; ... Where is an integer, and is a single letter. Zero or more params are passed to a . If no params are passed, it is generally synonymous with passing a single zero. No spaces exist in the sequence, they have just been inserted here to make it easy to read. The only ANSI sequences that colorama converts into win32 calls are:: ESC [ 0 m # reset all (colors and brightness) ESC [ 1 m # bright ESC [ 2 m # dim (looks same as normal brightness) ESC [ 22 m # normal brightness # FOREGROUND: ESC [ 30 m # black ESC [ 31 m # red ESC [ 32 m # green ESC [ 33 m # yellow ESC [ 34 m # blue ESC [ 35 m # magenta ESC [ 36 m # cyan ESC [ 37 m # white ESC [ 39 m # reset # BACKGROUND ESC [ 40 m # black ESC [ 41 m # red ESC [ 42 m # green ESC [ 43 m # yellow ESC [ 44 m # blue ESC [ 45 m # magenta ESC [ 46 m # cyan ESC [ 47 m # white ESC [ 49 m # reset # cursor positioning ESC [ y;x H # position cursor at x across, y down # clear the screen ESC [ mode J # clear the screen. Only mode 2 (clear entire screen) # is supported. It should be easy to add other modes, # let me know if that would be useful. Multiple numeric params to the 'm' command can be combined into a single sequence, eg:: ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background All other ANSI sequences of the form ``ESC [ ; ... `` are silently stripped from the output on Windows. Any other form of ANSI sequence, such as single-character codes or alternative initial characters, are not recognised nor stripped. It would be cool to add them though. Let me know if it would be useful for you, via the issues on google code. Development =========== Running tests requires: - Michael Foord's 'mock' module to be installed. - Tests are written using the 2010 era updates to 'unittest', and require to be run either using Python2.7 or greater, or else to have Michael Foord's 'unittest2' module installed. unittest2 test discovery doesn't work for colorama, so I use 'nose':: nosetests -s The -s is required because 'nosetests' otherwise applies a proxy of its own to stdout, which confuses the unit tests. Thanks ====== | Jesse@EmptySquare for submitting a fix for examples in the README. | User 'jamessp', an observant documentation fix for cursor positioning. | User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 fix. | Julien Stuyck, for wisely suggesting Python3 compatible updates to README. | Daniel Griffith for multiple fabulous patches. | Oscar Lesta for valuable fix to stop ANSI chars being sent to non-tty output. | Roger Binns, for many suggestions, valuable feedback, & bug reports. | Tim Golden for thought and much appreciated feedback on the initial idea. Keywords: color colour terminal text ansi windows crossplatform xplatform Platform: UNKNOWN Classifier: Development Status :: 4 - Beta Classifier: Environment :: Console Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.5 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.1 Classifier: Programming Language :: Python :: 3.2 Classifier: Topic :: Terminals colorama-0.2.5/README.txt0000666000175000017500000002325212157045363016515 0ustar jhartleyjhartley00000000000000Download and docs: http://pypi.python.org/pypi/colorama Development: http://code.google.com/p/colorama Discussion group: https://groups.google.com/forum/#!forum/python-colorama Description =========== Makes ANSI escape character sequences, for producing colored terminal text and cursor positioning, work under MS Windows. ANSI escape character sequences have long been used to produce colored terminal text and cursor positioning on Unix and Macs. Colorama makes this work on Windows, too. It also provides some shortcuts to help generate ANSI sequences, and works fine in conjunction with any other ANSI sequence generation library, such as Termcolor (http://pypi.python.org/pypi/termcolor.) This has the upshot of providing a simple cross-platform API for printing colored terminal text from Python, and has the happy side-effect that existing applications or libraries which use ANSI sequences to produce colored output on Linux or Macs can now also work on Windows, simply by calling ``colorama.init()``. Demo scripts in the source code repository prints some colored text using ANSI sequences. Compare their output under Gnome-terminal's built in ANSI handling, versus on Windows Command-Prompt using Colorama: .. image:: http://colorama.googlecode.com/hg/screenshots/ubuntu-demo.png :width: 661 :height: 357 :alt: ANSI sequences on Ubuntu under gnome-terminal. .. image:: http://colorama.googlecode.com/hg/screenshots/windows-demo.png :width: 668 :height: 325 :alt: Same ANSI sequences on Windows, using Colorama. These screengrabs show that Colorama on Windows does not support ANSI 'dim text': it looks the same as 'normal text'. Dependencies ============ None, other than Python. Tested on Python 2.5.5, 2.6.5, 2.7, 3.1.2, and 3.2 Usage ===== Initialisation -------------- Applications should initialise Colorama using:: from colorama import init init() If you are on Windows, the call to ``init()`` will start filtering ANSI escape sequences out of any text sent to stdout or stderr, and will replace them with equivalent Win32 calls. Calling ``init()`` has no effect on other platforms (unless you request other optional functionality, see keyword args below.) The intention is that applications can call ``init()`` unconditionally on all platforms, after which ANSI output should just work. To stop using colorama before your program exits, simply call ``deinit()``. This will restore stdout and stderr to their original values, so that Colorama is disabled. To start using Colorama again, call ``reinit()``, which wraps stdout and stderr again, but is cheaper to call than doing ``init()`` all over again. Colored Output -------------- Cross-platform printing of colored text can then be done using Colorama's constant shorthand for ANSI escape sequences:: from colorama import Fore, Back, Style print(Fore.RED + 'some red text') print(Back.GREEN + 'and with a green background') print(Style.DIM + 'and in dim text') print(Fore.RESET + Back.RESET + Style.RESET_ALL) print('back to normal now') or simply by manually printing ANSI sequences from your own code:: print('/033[31m' + 'some red text') print('/033[30m' # and reset to default color) or Colorama can be used happily in conjunction with existing ANSI libraries such as Termcolor:: from colorama import init from termcolor import colored # use Colorama to make Termcolor work on Windows too init() # then use Termcolor for all colored text output print(colored('Hello, World!', 'green', 'on_red')) Available formatting constants are:: Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. Style: DIM, NORMAL, BRIGHT, RESET_ALL Style.RESET_ALL resets foreground, background and brightness. Colorama will perform this reset automatically on program exit. Cursor Positioning ------------------ ANSI codes to reposition the cursor are supported. See demos/demo06.py for an example of how to generate them. Init Keyword Args ----------------- ``init()`` accepts some kwargs to override default behaviour. init(autoreset=False): If you find yourself repeatedly sending reset sequences to turn off color changes at the end of every print, then ``init(autoreset=True)`` will automate that:: from colorama import init init(autoreset=True) print(Fore.RED + 'some red text') print('automatically back to default color again') init(strip=None): Pass ``True`` or ``False`` to override whether ansi codes should be stripped from the output. The default behaviour is to strip if on Windows. init(convert=None): Pass ``True`` or ``False`` to override whether to convert ansi codes in the output into win32 calls. The default behaviour is to convert if on Windows and output is to a tty (terminal). init(wrap=True): On Windows, colorama works by replacing ``sys.stdout`` and ``sys.stderr`` with proxy objects, which override the .write() method to do their work. If this wrapping causes you problems, then this can be disabled by passing ``init(wrap=False)``. The default behaviour is to wrap if autoreset or strip or convert are True. When wrapping is disabled, colored printing on non-Windows platforms will continue to work as normal. To do cross-platform colored output, you can use Colorama's ``AnsiToWin32`` proxy directly:: import sys from colorama import init, AnsiToWin32 init(wrap=False) stream = AnsiToWin32(sys.stderr).stream # Python 2 print >>stream, Fore.BLUE + 'blue text on stderr' # Python 3 print(Fore.BLUE + 'blue text on stderr', file=stream) Status & Known Problems ======================= I've personally only tested it on WinXP (CMD, Console2), Ubuntu (gnome-terminal, xterm), and OSX. Some presumably valid ANSI sequences aren't recognised (see details below) but to my knowledge nobody has yet complained about this. Puzzling. See outstanding issues and wishlist at: http://code.google.com/p/colorama/issues/list If anything doesn't work for you, or doesn't do what you expected or hoped for, I'd love to hear about it on that issues list, would be delighted by patches, and would be happy to grant commit access to anyone who submits a working patch or two. Recognised ANSI Sequences ========================= ANSI sequences generally take the form: ESC [ ; ... Where is an integer, and is a single letter. Zero or more params are passed to a . If no params are passed, it is generally synonymous with passing a single zero. No spaces exist in the sequence, they have just been inserted here to make it easy to read. The only ANSI sequences that colorama converts into win32 calls are:: ESC [ 0 m # reset all (colors and brightness) ESC [ 1 m # bright ESC [ 2 m # dim (looks same as normal brightness) ESC [ 22 m # normal brightness # FOREGROUND: ESC [ 30 m # black ESC [ 31 m # red ESC [ 32 m # green ESC [ 33 m # yellow ESC [ 34 m # blue ESC [ 35 m # magenta ESC [ 36 m # cyan ESC [ 37 m # white ESC [ 39 m # reset # BACKGROUND ESC [ 40 m # black ESC [ 41 m # red ESC [ 42 m # green ESC [ 43 m # yellow ESC [ 44 m # blue ESC [ 45 m # magenta ESC [ 46 m # cyan ESC [ 47 m # white ESC [ 49 m # reset # cursor positioning ESC [ y;x H # position cursor at x across, y down # clear the screen ESC [ mode J # clear the screen. Only mode 2 (clear entire screen) # is supported. It should be easy to add other modes, # let me know if that would be useful. Multiple numeric params to the 'm' command can be combined into a single sequence, eg:: ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background All other ANSI sequences of the form ``ESC [ ; ... `` are silently stripped from the output on Windows. Any other form of ANSI sequence, such as single-character codes or alternative initial characters, are not recognised nor stripped. It would be cool to add them though. Let me know if it would be useful for you, via the issues on google code. Development =========== Running tests requires: - Michael Foord's 'mock' module to be installed. - Tests are written using the 2010 era updates to 'unittest', and require to be run either using Python2.7 or greater, or else to have Michael Foord's 'unittest2' module installed. unittest2 test discovery doesn't work for colorama, so I use 'nose':: nosetests -s The -s is required because 'nosetests' otherwise applies a proxy of its own to stdout, which confuses the unit tests. Thanks ====== | Jesse@EmptySquare for submitting a fix for examples in the README. | User 'jamessp', an observant documentation fix for cursor positioning. | User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 fix. | Julien Stuyck, for wisely suggesting Python3 compatible updates to README. | Daniel Griffith for multiple fabulous patches. | Oscar Lesta for valuable fix to stop ANSI chars being sent to non-tty output. | Roger Binns, for many suggestions, valuable feedback, & bug reports. | Tim Golden for thought and much appreciated feedback on the initial idea.