##// END OF EJS Templates
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.

File last commit:

r2783:3c79c2e7
r2783:3c79c2e7
Show More
ansi_code_processor.py
177 lines | 5.6 KiB | text/x-python | PythonLexer
# Standard library imports
import re
# System library imports
from PyQt4 import QtCore, QtGui
class AnsiAction(object):
""" Represents an action requested by an ANSI escape sequence.
"""
def __init__(self, kind):
self.kind = kind
class MoveAction(AnsiAction):
""" An AnsiAction for cursor move requests (CUU, CUD, CUF, CUB, CNL, CPL,
CHA, and CUP commands).
"""
def __init__(self):
raise NotImplementedError
class EraseAction(AnsiAction):
""" An AnsiAction for erase requests (ED and EL commands).
"""
def __init__(self, area, erase_to):
super(EraseAction, self).__init__('erase')
self.area = area
self.erase_to = erase_to
class AnsiCodeProcessor(object):
""" Translates ANSI escape codes into readable attributes.
"""
# Protected class variables.
_ansi_commands = 'ABCDEFGHJKSTfmnsu'
_ansi_pattern = re.compile('\x01?\x1b\[(.*?)([%s])\x02?' % _ansi_commands)
def __init__(self):
self.actions = []
self.reset_sgr()
def reset_sgr(self):
""" Reset graphics attributs to their default values.
"""
self.intensity = 0
self.italic = False
self.bold = False
self.underline = False
self.foreground_color = None
self.background_color = None
def split_string(self, string):
""" Yields substrings for which the same escape code applies.
"""
self.actions = []
start = 0
for match in self._ansi_pattern.finditer(string):
substring = string[start:match.start()]
if substring or self.actions:
yield substring
start = match.end()
self.actions = []
try:
params = []
for param in match.group(1).split(';'):
if param:
params.append(int(param))
except ValueError:
# Silently discard badly formed escape codes.
pass
else:
self.set_csi_code(match.group(2), params)
substring = string[start:]
if substring or self.actions:
yield substring
def set_csi_code(self, command, params=[]):
""" Set attributes based on CSI (Control Sequence Introducer) code.
Parameters
----------
command : str
The code identifier, i.e. the final character in the sequence.
params : sequence of integers, optional
The parameter codes for the command.
"""
if command == 'm': # SGR - Select Graphic Rendition
for code in params:
self.set_sgr_code(code)
elif (command == 'J' or # ED - Erase Data
command == 'K'): # EL - Erase in Line
code = params[0] if params else 0
if 0 <= code <= 2:
area = 'screen' if command == 'J' else 'line'
if code == 0:
erase_to = 'end'
elif code == 1:
erase_to = 'start'
elif code == 2:
erase_to = 'all'
self.actions.append(EraseAction(area, erase_to))
def set_sgr_code(self, code):
""" Set attributes based on SGR (Select Graphic Rendition) code.
"""
if code == 0:
self.reset_sgr()
elif code == 1:
self.intensity = 1
self.bold = True
elif code == 2:
self.intensity = 0
elif code == 3:
self.italic = True
elif code == 4:
self.underline = True
elif code == 22:
self.intensity = 0
self.bold = False
elif code == 23:
self.italic = False
elif code == 24:
self.underline = False
elif code >= 30 and code <= 37:
self.foreground_color = code - 30
elif code == 39:
self.foreground_color = None
elif code >= 40 and code <= 47:
self.background_color = code - 40
elif code == 49:
self.background_color = None
class QtAnsiCodeProcessor(AnsiCodeProcessor):
""" Translates ANSI escape codes into QTextCharFormats.
"""
# A map from color codes to RGB colors.
ansi_colors = ( # Normal, Bright/Light
('#000000', '#7f7f7f'), # 0: black
('#cd0000', '#ff0000'), # 1: red
('#00cd00', '#00ff00'), # 2: green
('#cdcd00', '#ffff00'), # 3: yellow
('#0000ee', '#0000ff'), # 4: blue
('#cd00cd', '#ff00ff'), # 5: magenta
('#00cdcd', '#00ffff'), # 6: cyan
('#e5e5e5', '#ffffff')) # 7: white
def get_format(self):
""" Returns a QTextCharFormat that encodes the current style attributes.
"""
format = QtGui.QTextCharFormat()
# Set foreground color
if self.foreground_color is not None:
color = self.ansi_colors[self.foreground_color][self.intensity]
format.setForeground(QtGui.QColor(color))
# Set background color
if self.background_color is not None:
color = self.ansi_colors[self.background_color][self.intensity]
format.setBackground(QtGui.QColor(color))
# Set font weight/style options
if self.bold:
format.setFontWeight(QtGui.QFont.Bold)
else:
format.setFontWeight(QtGui.QFont.Normal)
format.setFontItalic(self.italic)
format.setFontUnderline(self.underline)
return format