0001"""Secondary abstractions for terminal control
0002
0003The code here is mostly a front-end to the ``control`` module. The OutputStream class
0004acts as a wrapper for tty pseudo files like sys.stdout and sys.stder and can
0005handle several ANSI control codes on multiple platforms.
0006
0007Here is an example usage.
0008
0009.. code-block:: Python
0010
0011 import os
0012 stdout.write('spam' +
0013 color('bright','yellow','white') +
0014 'eggs' +
0015 color('default') + os.linesep
0016 )
0017
0018Warning: on IPython setting sys.stdout to the stdout object in this
0019module will break readline.
0020"""
0021
0022__all__ = ['color', 'OutputStream', 'stdout', 'stderr']
0023
0024import sys, os, re, control
0025
0026escape_parts = re.compile('\x01?\x1b\\[([0-9;]*)m\x02?')
0027
0028def color(codes=[], fg=None, bg=None):
0029 """Returns an ANSI control code. This is useful when writing to an OutputStream.
0030
0031 codes
0032 A list containing strings. The strings should one of the keys in
0033 the DISPLAY_CODES constant in the ``control`` module. It can also
0034 be just a single string.
0035 fg, bg
0036 A string. Explicitly for setting the foreground or background. Use
0037 one of the keys in the COLORS constant in the ``control`` module.
0038
0039 color(('bright','underline'),'blue','white')
0040 give bright blue foreground and white background with underline
0041 color(fg='blue')
0042 gives a blue foreground
0043 color('default')
0044 resets the color to the default.
0045
0046 Avoid using black or white. Depending on the situation the default
0047 background/foreground is normally black or white, but it's hard to
0048 tell which. Bare terminals are normally white on black, but virtual
0049 terminals run from X or another GUI system are often black on white.
0050 This can lead to unpredicatble results. If you want reversed
0051 colours, use the 'reverse' code, and if you want to set the
0052 colors back to their original colors, use the 'default' code.
0053
0054 Also, be prudent with your use of 'hidden' and 'blink'. Several terminals
0055 do not support them (and for good reason too), they can be really
0056 annoying and make reading difficult.
0057 """
0058 return control.ANSI.displaycode(codes, fg, bg)
0059
0060class OutputStream(object):
0061
0062 def __init__(self, stream):
0063 self.stream = stream
0064
0065 def raw_write(self, text):
0066 self.stream.write(text)
0067
0068
0069
0070 def write(self, text):
0071 chunks = escape_parts.split(text)
0072 i = 0
0073 for chunk in chunks:
0074 if chunk != '':
0075 if i % 2 == 0:
0076 self.stream.write(chunk)
0077 else:
0078 c=chunk.split(';')
0079 r=control.ANSI.readcodes(c)
0080 control.display(**r)
0081
0082
0083
0084
0085
0086 self.flush()
0087 i += 1
0088
0089 def writelines(self, lines):
0090 self.write(lines.join(os.linesep))
0091
0092 def flush(self):
0093 return self.stream.flush()
0094
0095 def isatty(self,*args,**kwargs):
0096 return self.stream.isatty(*args,**kwargs)
0097
0098
0099
0100 def tell(self,*args,**kwargs):
0101 return self.stream.tell(*args,**kwargs)
0102 def truncate(self,*args,**kwargs):
0103 return self.stream.truncate(*args,**kwargs)
0104 def readinto(self,*args,**kwargs):
0105 return self.stream.readinto(*args,**kwargs)
0106 def readline(self,*args,**kwargs):
0107 return self.stream.readline(*args,**kwargs)
0108 def readlines(self,*args,**kwargs):
0109 return self.stream.readlines(*args,**kwargs)
0110 def next(self,*args,**kwargs):
0111 return self.stream.next(*args,**kwargs)
0112 def read(self,*args,**kwargs):
0113 return self.stream.read(*args,**kwargs)
0114 def close(self,*args,**kwargs):
0115 return self.stream.close(*args,**kwargs)
0116 def fileno(self,*args,**kwargs):
0117 return self.stream.fileno(*args,**kwargs)
0118 def xreadlines(self,*args,**kwargs):
0119 return self.stream.xreadlines(*args,**kwargs)
0120
0121 def _get_mode(self): return self.stream.mode
0122 def _set_mode(self, value): self.stream.mode = value
0123 mode = property(_get_mode, _set_mode)
0124
0125 def _get_newlines(self): return self.stream.newlines
0126 def _set_newlines(self, value): self.stream.newlines = value
0127 newlines = property(_get_newlines, _set_newlines)
0128
0129 def _get_encoding(self): return self.stream.encoding
0130 def _set_encoding(self, value): self.stream.encoding = value
0131 encoding = property(_get_encoding, _set_encoding)
0132
0133 def _get_softspace(self): return self.stream.softspace
0134 def _set_softspace(self, value): self.stream.softspace = value
0135 softspace = property(_get_softspace, _set_softspace)
0136
0137 def _get_name(self): return self.stream.name
0138 def _set_name(self, value): self.stream.name = value
0139 name = property(_get_name, _set_name)
0140
0141
0142stdout = OutputStream(sys.stdout)
0143
0144
0145stderr = OutputStream(sys.stderr)