##// 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
/ IPython / frontend / qt / console / ansi_code_processor.py
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 # Standard library imports
import re
# System library imports
from PyQt4 import QtCore, QtGui
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 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
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 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):
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 self.actions = []
self.reset_sgr()
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 def reset_sgr(self):
""" Reset graphics attributs to their default values.
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 """
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.
"""
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 self.actions = []
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 start = 0
for match in self._ansi_pattern.finditer(string):
substring = string[start:match.start()]
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 if substring or self.actions:
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 yield substring
start = match.end()
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 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)
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716
substring = string[start:]
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 if substring or self.actions:
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 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.
"""
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 if command == 'm': # SGR - Select Graphic Rendition
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 for code in params:
self.set_sgr_code(code)
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783
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))
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716
def set_sgr_code(self, code):
""" Set attributes based on SGR (Select Graphic Rendition) code.
"""
if code == 0:
epatters
Added support for ANSI erase codes. Clearing the console via ANSI escape sequences is now supported.
r2783 self.reset_sgr()
epatters
* Moved AnsiCodeProcessor to separate file, refactored its API, and added unit tests....
r2716 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