/4Suite-XML-1.0.2/Ft/Lib/Terminal.py
Python | 302 lines | 201 code | 41 blank | 60 comment | 43 complexity | 9198733e7cd004fcf68a3017b750be7b MD5 | raw file
- ########################################################################
- # $Header: /var/local/cvsroot/4Suite/Ft/Lib/Terminal.py,v 1.6.4.1 2006/09/18 17:05:25 jkloth Exp $
- """
- Provides some of the information from the terminfo database.
- Copyright 2005 Fourthought, Inc. (USA).
- Detailed license and copyright information: http://4suite.org/COPYRIGHT
- Project home, documentation, distributions: http://4suite.org/
- """
- import os, re, sys
- from Ft.Lib.Terminfo import TERMTYPES as _ANSITERMS
- from Ft.Lib.Terminfo import DEFAULT_LINES as _LINES
- from Ft.Lib.Terminfo import DEFAULT_COLUMNS as _COLUMNS
- if sys.platform == 'win32':
- import msvcrt
- from Ft.Lib import _win32con
- elif os.name == 'posix':
- _HAVE_TIOCGWINSZ = False
- try:
- import fcntl, termios, struct
- except ImportError:
- pass
- else:
- _HAVE_TIOCGWINSZ = hasattr(termios, 'TIOCGWINSZ')
- # ISO 6429 color sequences are composed of sequences of numbers
- # separated by semicolons. The most common codes are:
- #
- # 0 to restore default color
- # 1 for brighter colors
- # 4 for underlined text
- # 5 for flashing text
- # 30 for black foreground
- # 31 for red foreground
- # 32 for green foreground
- # 33 for yellow (or brown) foreground
- # 34 for blue foreground
- # 35 for purple foreground
- # 36 for cyan foreground
- # 37 for white (or gray) foreground
- # 40 for black background
- # 41 for red background
- # 42 for green background
- # 43 for yellow (or brown) background
- # 44 for blue background
- # 45 for purple background
- # 46 for cyan background
- # 47 for white (or gray) background
- class AnsiEscapes:
- class Colors:
- DEFAULT = '\033[0m'
- BOLD = '\033[1m'
- FOREGROUND_BLACK = '\033[30m'
- FOREGROUND_MAROON = '\033[31m'
- FOREGROUND_GREEN = '\033[32m'
- FOREGROUND_BROWN = FOREGROUND_OLIVE = '\033[33m'
- FOREGROUND_NAVY = '\033[34m'
- FOREGROUND_PURPLE = '\033[35m'
- FOREGROUND_TEAL = '\033[36m'
- FOREGROUND_SILVER = '\033[37m'
- FOREGROUND_GRAY = '\033[1;30m'
- FOREGROUND_RED = '\033[1;31m'
- FOREGROUND_LIME = '\033[1;32m'
- FOREGROUND_YELLOW = '\033[1;33m'
- FOREGROUND_BLUE = '\033[1;34m'
- FOREGROUND_MAGENTA = FOREGROUND_FUCHSIA = '\033[1;35m'
- FOREGROUND_CYAN = FOREGROUND_AQUA = '\033[1;36m'
- FOREGROUND_WHITE = '\033[1;37m'
- BACKGROUND_BLACK = '\033[40m'
- BACKGROUND_MAROON = '\033[41m'
- BACKGROUND_GREEN = '\033[42m'
- BACKGROUND_BROWN = BACKGROUND_OLIVE = '\033[43m'
- BACKGROUND_NAVY = '\033[44m'
- BACKGROUND_PURPLE = '\033[45m'
- BACKGROUND_TEAL = '\033[46m'
- BACKGROUND_SILVER = '\033[47m'
- # Methods/members a Terminal instance should expose from its underly stream.
- _file_methods = ('flush', 'write', 'read', 'isatty', 'encoding')
- class Terminal:
- def __init__(self, stream, keepAnsiEscapes=True):
- self._stream = stream
- for name in _file_methods:
- method = getattr(stream, name, None)
- if method is not None:
- setattr(self, name, method)
- if self.isatty():
- if sys.platform == 'win32':
- self._init_win32(stream, keepAnsiEscapes)
- elif os.name == 'posix' and os.environ.get('TERM') in _ANSITERMS:
- self._init_posix(stream, keepAnsiEscapes)
- return
- def _init_win32(self, stream, keepAnsiEscapes):
- # Apparently there exists an IDE where isatty() is True, but
- # the stream doesn't have a backing file descriptor.
- try:
- fileno = stream.fileno()
- except AttributeError:
- return
- # Get the Windows console handle of the file descriptor.
- try:
- self._handle = msvcrt.get_osfhandle(fileno)
- except IOError:
- return
- if keepAnsiEscapes:
- self._write_escape = self._escape_win32
- self._default_attribute = \
- _win32con.GetConsoleScreenBufferInfo(self._handle)[2]
- self.size = self._size_win32
- return
- def _init_posix(self, stream, keepAnsiEscapes):
- if keepAnsiEscapes:
- # stream handles ANSI escapes natively
- self.writetty = stream.write
- if _HAVE_TIOCGWINSZ:
- self.size = self._size_termios
- return
- def lines(self):
- return self.size()[0]
- def columns(self):
- return self.size()[1]
- def size(self):
- return (_LINES, _COLUMNS)
- # noop method for underlying streams which do not implement it
- def flush(self):
- return
- # noop method for underlying streams which do not implement it
- def write(self, str):
- return
- # noop method for underlying streams which do not implement it
- def read(self, size=-1):
- return ''
- # noop method for underlying streams which do not implement it
- def isatty(self):
- return False
- def close(self):
- # don't attempt to close a tty streams
- if self.isatty():
- return
- # ignore any errors closing the underlying stream
- try:
- self._stream.close()
- except:
- pass
- return
- # ANSI Set Display Mode: ESC[#;...;#m
- _ansi_sdm = re.compile('\033\\[([0-9]+)(?:;([0-9]+))*m')
- def writetty(self, bytes):
- start = 0
- match = self._ansi_sdm.search(bytes)
- while match is not None:
- # write everything up to the escape sequence
- self._stream.write(bytes[start:match.start()])
- # process the color codes
- self._write_escape(match.groups())
- # skip over the escape sequence
- start = match.end()
- # find the next sequence
- match = self._ansi_sdm.search(bytes, start)
- # write the remainder
- self._stream.write(bytes[start:])
- return
- def _write_escape(self, codes):
- """
- Escape function for handling ANSI Set Display Mode.
- Default behavior is to simply ignore the call (e.g. nothing is added
- to the output).
- """
- return
- # -- Terminal specific functions -----------------------------------
- def _size_termios(self):
- ws = struct.pack("HHHH", 0, 0, 0, 0)
- ws = fcntl.ioctl(self._stream.fileno(), termios.TIOCGWINSZ, ws)
- lines, columns, x, y = struct.unpack("HHHH", ws)
- return (lines, columns)
- def _escape_win32(self, codes):
- """Translates the ANSI color codes into the Win32 API equivalents."""
- # get the current text attributes for the stream
- size, cursor, attributes, window = \
- _win32con.GetConsoleScreenBufferInfo(self._handle)
- for code in map(int, filter(None, codes)):
- if code == 0: # normal
- # the default attribute
- attributes = self._default_attribute
- elif code == 1: # bold
- # bold only applies to the foreground color
- attributes |= _win32con.FOREGROUND_INTENSITY
- elif code == 30: # black
- attributes &= _win32con.BACKGROUND
- elif code == 31: # red
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= _win32con.FOREGROUND_RED
- elif code == 32: # green
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= _win32con.FOREGROUND_GREEN
- elif code == 33: # brown (bold: yellow)
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= (_win32con.FOREGROUND_RED |
- _win32con.FOREGROUND_GREEN)
- elif code == 34: # blue
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= _win32con.FOREGROUND_BLUE
- elif code == 35: # purple (bold: magenta)
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= (_win32con.FOREGROUND_RED |
- _win32con.FOREGROUND_BLUE)
- elif code == 36: # cyan
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= (_win32con.FOREGROUND_BLUE |
- _win32con.FOREGROUND_GREEN)
- elif code == 37: # gray (bold: white)
- attributes &= (_win32con.FOREGROUND_INTENSITY |
- _win32con.BACKGROUND)
- attributes |= (_win32con.FOREGROUND_RED |
- _win32con.FOREGROUND_GREEN |
- _win32con.FOREGROUND_BLUE)
- elif code == 40: # black
- attributes &= _win32con.FOREGROUND
- elif code == 41: # red
- attributes &= _win32con.FOREGROUND
- attributes |= _win32con.BACKGROUND_RED
- elif code == 42: # green
- attributes &= _win32con.FOREGROUND
- attributes |= _win32con.BACKGROUND_GREEN
- elif code == 43: # brown
- attributes &= _win32con.FOREGROUND
- attributes |= (_win32con.BACKGROUND_RED |
- _win32con.BACKGROUND_GREEN)
- elif code == 44: # blue
- attributes &= _win32con.FOREGROUND
- attributes |= _win32con.BACKGROUND_BLUE
- elif code == 45: # purple
- attributes &= _win32con.FOREGROUND
- attributes |= (_win32con.BACKGROUND_RED |
- _win32con.BACKGROUND_BLUE)
- elif code == 46: # cyan
- attributes &= _win32con.FOREGROUND
- attributes |= (_win32con.BACKGROUND_BLUE |
- _win32con.BACKGROUND_GREEN)
- elif code == 47: # gray
- attributes &= _win32con.FOREGROUND
- attributes |= (_win32con.BACKGROUND_RED |
- _win32con.BACKGROUND_GREEN |
- _win32con.BACKGROUND_BLUE)
- _win32con.SetConsoleTextAttribute(self._handle, attributes)
- return
- def _size_win32(self):
- size, cursor, attributes, window = \
- _win32con.GetConsoleScreenBufferInfo(self._handle)
- left, top, right, bottom = window
- # use the buffer size for the column width as Windows wraps text
- # there instead of at the displayed window size
- columns, lines = size
- return (bottom - top, columns - 1)