PageRenderTime 50ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/4Suite-XML-1.0.2/Ft/Lib/Terminal.py

#
Python | 302 lines | 201 code | 41 blank | 60 comment | 43 complexity | 9198733e7cd004fcf68a3017b750be7b MD5 | raw file
  1. ########################################################################
  2. # $Header: /var/local/cvsroot/4Suite/Ft/Lib/Terminal.py,v 1.6.4.1 2006/09/18 17:05:25 jkloth Exp $
  3. """
  4. Provides some of the information from the terminfo database.
  5. Copyright 2005 Fourthought, Inc. (USA).
  6. Detailed license and copyright information: http://4suite.org/COPYRIGHT
  7. Project home, documentation, distributions: http://4suite.org/
  8. """
  9. import os, re, sys
  10. from Ft.Lib.Terminfo import TERMTYPES as _ANSITERMS
  11. from Ft.Lib.Terminfo import DEFAULT_LINES as _LINES
  12. from Ft.Lib.Terminfo import DEFAULT_COLUMNS as _COLUMNS
  13. if sys.platform == 'win32':
  14. import msvcrt
  15. from Ft.Lib import _win32con
  16. elif os.name == 'posix':
  17. _HAVE_TIOCGWINSZ = False
  18. try:
  19. import fcntl, termios, struct
  20. except ImportError:
  21. pass
  22. else:
  23. _HAVE_TIOCGWINSZ = hasattr(termios, 'TIOCGWINSZ')
  24. # ISO 6429 color sequences are composed of sequences of numbers
  25. # separated by semicolons. The most common codes are:
  26. #
  27. # 0 to restore default color
  28. # 1 for brighter colors
  29. # 4 for underlined text
  30. # 5 for flashing text
  31. # 30 for black foreground
  32. # 31 for red foreground
  33. # 32 for green foreground
  34. # 33 for yellow (or brown) foreground
  35. # 34 for blue foreground
  36. # 35 for purple foreground
  37. # 36 for cyan foreground
  38. # 37 for white (or gray) foreground
  39. # 40 for black background
  40. # 41 for red background
  41. # 42 for green background
  42. # 43 for yellow (or brown) background
  43. # 44 for blue background
  44. # 45 for purple background
  45. # 46 for cyan background
  46. # 47 for white (or gray) background
  47. class AnsiEscapes:
  48. class Colors:
  49. DEFAULT = '\033[0m'
  50. BOLD = '\033[1m'
  51. FOREGROUND_BLACK = '\033[30m'
  52. FOREGROUND_MAROON = '\033[31m'
  53. FOREGROUND_GREEN = '\033[32m'
  54. FOREGROUND_BROWN = FOREGROUND_OLIVE = '\033[33m'
  55. FOREGROUND_NAVY = '\033[34m'
  56. FOREGROUND_PURPLE = '\033[35m'
  57. FOREGROUND_TEAL = '\033[36m'
  58. FOREGROUND_SILVER = '\033[37m'
  59. FOREGROUND_GRAY = '\033[1;30m'
  60. FOREGROUND_RED = '\033[1;31m'
  61. FOREGROUND_LIME = '\033[1;32m'
  62. FOREGROUND_YELLOW = '\033[1;33m'
  63. FOREGROUND_BLUE = '\033[1;34m'
  64. FOREGROUND_MAGENTA = FOREGROUND_FUCHSIA = '\033[1;35m'
  65. FOREGROUND_CYAN = FOREGROUND_AQUA = '\033[1;36m'
  66. FOREGROUND_WHITE = '\033[1;37m'
  67. BACKGROUND_BLACK = '\033[40m'
  68. BACKGROUND_MAROON = '\033[41m'
  69. BACKGROUND_GREEN = '\033[42m'
  70. BACKGROUND_BROWN = BACKGROUND_OLIVE = '\033[43m'
  71. BACKGROUND_NAVY = '\033[44m'
  72. BACKGROUND_PURPLE = '\033[45m'
  73. BACKGROUND_TEAL = '\033[46m'
  74. BACKGROUND_SILVER = '\033[47m'
  75. # Methods/members a Terminal instance should expose from its underly stream.
  76. _file_methods = ('flush', 'write', 'read', 'isatty', 'encoding')
  77. class Terminal:
  78. def __init__(self, stream, keepAnsiEscapes=True):
  79. self._stream = stream
  80. for name in _file_methods:
  81. method = getattr(stream, name, None)
  82. if method is not None:
  83. setattr(self, name, method)
  84. if self.isatty():
  85. if sys.platform == 'win32':
  86. self._init_win32(stream, keepAnsiEscapes)
  87. elif os.name == 'posix' and os.environ.get('TERM') in _ANSITERMS:
  88. self._init_posix(stream, keepAnsiEscapes)
  89. return
  90. def _init_win32(self, stream, keepAnsiEscapes):
  91. # Apparently there exists an IDE where isatty() is True, but
  92. # the stream doesn't have a backing file descriptor.
  93. try:
  94. fileno = stream.fileno()
  95. except AttributeError:
  96. return
  97. # Get the Windows console handle of the file descriptor.
  98. try:
  99. self._handle = msvcrt.get_osfhandle(fileno)
  100. except IOError:
  101. return
  102. if keepAnsiEscapes:
  103. self._write_escape = self._escape_win32
  104. self._default_attribute = \
  105. _win32con.GetConsoleScreenBufferInfo(self._handle)[2]
  106. self.size = self._size_win32
  107. return
  108. def _init_posix(self, stream, keepAnsiEscapes):
  109. if keepAnsiEscapes:
  110. # stream handles ANSI escapes natively
  111. self.writetty = stream.write
  112. if _HAVE_TIOCGWINSZ:
  113. self.size = self._size_termios
  114. return
  115. def lines(self):
  116. return self.size()[0]
  117. def columns(self):
  118. return self.size()[1]
  119. def size(self):
  120. return (_LINES, _COLUMNS)
  121. # noop method for underlying streams which do not implement it
  122. def flush(self):
  123. return
  124. # noop method for underlying streams which do not implement it
  125. def write(self, str):
  126. return
  127. # noop method for underlying streams which do not implement it
  128. def read(self, size=-1):
  129. return ''
  130. # noop method for underlying streams which do not implement it
  131. def isatty(self):
  132. return False
  133. def close(self):
  134. # don't attempt to close a tty streams
  135. if self.isatty():
  136. return
  137. # ignore any errors closing the underlying stream
  138. try:
  139. self._stream.close()
  140. except:
  141. pass
  142. return
  143. # ANSI Set Display Mode: ESC[#;...;#m
  144. _ansi_sdm = re.compile('\033\\[([0-9]+)(?:;([0-9]+))*m')
  145. def writetty(self, bytes):
  146. start = 0
  147. match = self._ansi_sdm.search(bytes)
  148. while match is not None:
  149. # write everything up to the escape sequence
  150. self._stream.write(bytes[start:match.start()])
  151. # process the color codes
  152. self._write_escape(match.groups())
  153. # skip over the escape sequence
  154. start = match.end()
  155. # find the next sequence
  156. match = self._ansi_sdm.search(bytes, start)
  157. # write the remainder
  158. self._stream.write(bytes[start:])
  159. return
  160. def _write_escape(self, codes):
  161. """
  162. Escape function for handling ANSI Set Display Mode.
  163. Default behavior is to simply ignore the call (e.g. nothing is added
  164. to the output).
  165. """
  166. return
  167. # -- Terminal specific functions -----------------------------------
  168. def _size_termios(self):
  169. ws = struct.pack("HHHH", 0, 0, 0, 0)
  170. ws = fcntl.ioctl(self._stream.fileno(), termios.TIOCGWINSZ, ws)
  171. lines, columns, x, y = struct.unpack("HHHH", ws)
  172. return (lines, columns)
  173. def _escape_win32(self, codes):
  174. """Translates the ANSI color codes into the Win32 API equivalents."""
  175. # get the current text attributes for the stream
  176. size, cursor, attributes, window = \
  177. _win32con.GetConsoleScreenBufferInfo(self._handle)
  178. for code in map(int, filter(None, codes)):
  179. if code == 0: # normal
  180. # the default attribute
  181. attributes = self._default_attribute
  182. elif code == 1: # bold
  183. # bold only applies to the foreground color
  184. attributes |= _win32con.FOREGROUND_INTENSITY
  185. elif code == 30: # black
  186. attributes &= _win32con.BACKGROUND
  187. elif code == 31: # red
  188. attributes &= (_win32con.FOREGROUND_INTENSITY |
  189. _win32con.BACKGROUND)
  190. attributes |= _win32con.FOREGROUND_RED
  191. elif code == 32: # green
  192. attributes &= (_win32con.FOREGROUND_INTENSITY |
  193. _win32con.BACKGROUND)
  194. attributes |= _win32con.FOREGROUND_GREEN
  195. elif code == 33: # brown (bold: yellow)
  196. attributes &= (_win32con.FOREGROUND_INTENSITY |
  197. _win32con.BACKGROUND)
  198. attributes |= (_win32con.FOREGROUND_RED |
  199. _win32con.FOREGROUND_GREEN)
  200. elif code == 34: # blue
  201. attributes &= (_win32con.FOREGROUND_INTENSITY |
  202. _win32con.BACKGROUND)
  203. attributes |= _win32con.FOREGROUND_BLUE
  204. elif code == 35: # purple (bold: magenta)
  205. attributes &= (_win32con.FOREGROUND_INTENSITY |
  206. _win32con.BACKGROUND)
  207. attributes |= (_win32con.FOREGROUND_RED |
  208. _win32con.FOREGROUND_BLUE)
  209. elif code == 36: # cyan
  210. attributes &= (_win32con.FOREGROUND_INTENSITY |
  211. _win32con.BACKGROUND)
  212. attributes |= (_win32con.FOREGROUND_BLUE |
  213. _win32con.FOREGROUND_GREEN)
  214. elif code == 37: # gray (bold: white)
  215. attributes &= (_win32con.FOREGROUND_INTENSITY |
  216. _win32con.BACKGROUND)
  217. attributes |= (_win32con.FOREGROUND_RED |
  218. _win32con.FOREGROUND_GREEN |
  219. _win32con.FOREGROUND_BLUE)
  220. elif code == 40: # black
  221. attributes &= _win32con.FOREGROUND
  222. elif code == 41: # red
  223. attributes &= _win32con.FOREGROUND
  224. attributes |= _win32con.BACKGROUND_RED
  225. elif code == 42: # green
  226. attributes &= _win32con.FOREGROUND
  227. attributes |= _win32con.BACKGROUND_GREEN
  228. elif code == 43: # brown
  229. attributes &= _win32con.FOREGROUND
  230. attributes |= (_win32con.BACKGROUND_RED |
  231. _win32con.BACKGROUND_GREEN)
  232. elif code == 44: # blue
  233. attributes &= _win32con.FOREGROUND
  234. attributes |= _win32con.BACKGROUND_BLUE
  235. elif code == 45: # purple
  236. attributes &= _win32con.FOREGROUND
  237. attributes |= (_win32con.BACKGROUND_RED |
  238. _win32con.BACKGROUND_BLUE)
  239. elif code == 46: # cyan
  240. attributes &= _win32con.FOREGROUND
  241. attributes |= (_win32con.BACKGROUND_BLUE |
  242. _win32con.BACKGROUND_GREEN)
  243. elif code == 47: # gray
  244. attributes &= _win32con.FOREGROUND
  245. attributes |= (_win32con.BACKGROUND_RED |
  246. _win32con.BACKGROUND_GREEN |
  247. _win32con.BACKGROUND_BLUE)
  248. _win32con.SetConsoleTextAttribute(self._handle, attributes)
  249. return
  250. def _size_win32(self):
  251. size, cursor, attributes, window = \
  252. _win32con.GetConsoleScreenBufferInfo(self._handle)
  253. left, top, right, bottom = window
  254. # use the buffer size for the column width as Windows wraps text
  255. # there instead of at the displayed window size
  256. columns, lines = size
  257. return (bottom - top, columns - 1)