##// END OF EJS Templates
Set more tolerable default colors for ANSI color codes.
epatters -
Show More
@@ -1,177 +1,177 b''
1 # Standard library imports
1 # Standard library imports
2 import re
2 import re
3
3
4 # System library imports
4 # System library imports
5 from PyQt4 import QtCore, QtGui
5 from PyQt4 import QtCore, QtGui
6
6
7
7
8 class AnsiAction(object):
8 class AnsiAction(object):
9 """ Represents an action requested by an ANSI escape sequence.
9 """ Represents an action requested by an ANSI escape sequence.
10 """
10 """
11 def __init__(self, kind):
11 def __init__(self, kind):
12 self.kind = kind
12 self.kind = kind
13
13
14 class MoveAction(AnsiAction):
14 class MoveAction(AnsiAction):
15 """ An AnsiAction for cursor move requests (CUU, CUD, CUF, CUB, CNL, CPL,
15 """ An AnsiAction for cursor move requests (CUU, CUD, CUF, CUB, CNL, CPL,
16 CHA, and CUP commands).
16 CHA, and CUP commands).
17 """
17 """
18 def __init__(self):
18 def __init__(self):
19 raise NotImplementedError
19 raise NotImplementedError
20
20
21 class EraseAction(AnsiAction):
21 class EraseAction(AnsiAction):
22 """ An AnsiAction for erase requests (ED and EL commands).
22 """ An AnsiAction for erase requests (ED and EL commands).
23 """
23 """
24 def __init__(self, area, erase_to):
24 def __init__(self, area, erase_to):
25 super(EraseAction, self).__init__('erase')
25 super(EraseAction, self).__init__('erase')
26 self.area = area
26 self.area = area
27 self.erase_to = erase_to
27 self.erase_to = erase_to
28
28
29
29
30 class AnsiCodeProcessor(object):
30 class AnsiCodeProcessor(object):
31 """ Translates ANSI escape codes into readable attributes.
31 """ Translates ANSI escape codes into readable attributes.
32 """
32 """
33
33
34 # Protected class variables.
34 # Protected class variables.
35 _ansi_commands = 'ABCDEFGHJKSTfmnsu'
35 _ansi_commands = 'ABCDEFGHJKSTfmnsu'
36 _ansi_pattern = re.compile('\x01?\x1b\[(.*?)([%s])\x02?' % _ansi_commands)
36 _ansi_pattern = re.compile('\x01?\x1b\[(.*?)([%s])\x02?' % _ansi_commands)
37
37
38 def __init__(self):
38 def __init__(self):
39 self.actions = []
39 self.actions = []
40 self.reset_sgr()
40 self.reset_sgr()
41
41
42 def reset_sgr(self):
42 def reset_sgr(self):
43 """ Reset graphics attributs to their default values.
43 """ Reset graphics attributs to their default values.
44 """
44 """
45 self.intensity = 0
45 self.intensity = 0
46 self.italic = False
46 self.italic = False
47 self.bold = False
47 self.bold = False
48 self.underline = False
48 self.underline = False
49 self.foreground_color = None
49 self.foreground_color = None
50 self.background_color = None
50 self.background_color = None
51
51
52 def split_string(self, string):
52 def split_string(self, string):
53 """ Yields substrings for which the same escape code applies.
53 """ Yields substrings for which the same escape code applies.
54 """
54 """
55 self.actions = []
55 self.actions = []
56 start = 0
56 start = 0
57
57
58 for match in self._ansi_pattern.finditer(string):
58 for match in self._ansi_pattern.finditer(string):
59 substring = string[start:match.start()]
59 substring = string[start:match.start()]
60 if substring or self.actions:
60 if substring or self.actions:
61 yield substring
61 yield substring
62 start = match.end()
62 start = match.end()
63
63
64 self.actions = []
64 self.actions = []
65 try:
65 try:
66 params = []
66 params = []
67 for param in match.group(1).split(';'):
67 for param in match.group(1).split(';'):
68 if param:
68 if param:
69 params.append(int(param))
69 params.append(int(param))
70 except ValueError:
70 except ValueError:
71 # Silently discard badly formed escape codes.
71 # Silently discard badly formed escape codes.
72 pass
72 pass
73 else:
73 else:
74 self.set_csi_code(match.group(2), params)
74 self.set_csi_code(match.group(2), params)
75
75
76 substring = string[start:]
76 substring = string[start:]
77 if substring or self.actions:
77 if substring or self.actions:
78 yield substring
78 yield substring
79
79
80 def set_csi_code(self, command, params=[]):
80 def set_csi_code(self, command, params=[]):
81 """ Set attributes based on CSI (Control Sequence Introducer) code.
81 """ Set attributes based on CSI (Control Sequence Introducer) code.
82
82
83 Parameters
83 Parameters
84 ----------
84 ----------
85 command : str
85 command : str
86 The code identifier, i.e. the final character in the sequence.
86 The code identifier, i.e. the final character in the sequence.
87
87
88 params : sequence of integers, optional
88 params : sequence of integers, optional
89 The parameter codes for the command.
89 The parameter codes for the command.
90 """
90 """
91 if command == 'm': # SGR - Select Graphic Rendition
91 if command == 'm': # SGR - Select Graphic Rendition
92 for code in params:
92 for code in params:
93 self.set_sgr_code(code)
93 self.set_sgr_code(code)
94
94
95 elif (command == 'J' or # ED - Erase Data
95 elif (command == 'J' or # ED - Erase Data
96 command == 'K'): # EL - Erase in Line
96 command == 'K'): # EL - Erase in Line
97 code = params[0] if params else 0
97 code = params[0] if params else 0
98 if 0 <= code <= 2:
98 if 0 <= code <= 2:
99 area = 'screen' if command == 'J' else 'line'
99 area = 'screen' if command == 'J' else 'line'
100 if code == 0:
100 if code == 0:
101 erase_to = 'end'
101 erase_to = 'end'
102 elif code == 1:
102 elif code == 1:
103 erase_to = 'start'
103 erase_to = 'start'
104 elif code == 2:
104 elif code == 2:
105 erase_to = 'all'
105 erase_to = 'all'
106 self.actions.append(EraseAction(area, erase_to))
106 self.actions.append(EraseAction(area, erase_to))
107
107
108 def set_sgr_code(self, code):
108 def set_sgr_code(self, code):
109 """ Set attributes based on SGR (Select Graphic Rendition) code.
109 """ Set attributes based on SGR (Select Graphic Rendition) code.
110 """
110 """
111 if code == 0:
111 if code == 0:
112 self.reset_sgr()
112 self.reset_sgr()
113 elif code == 1:
113 elif code == 1:
114 self.intensity = 1
114 self.intensity = 1
115 self.bold = True
115 self.bold = True
116 elif code == 2:
116 elif code == 2:
117 self.intensity = 0
117 self.intensity = 0
118 elif code == 3:
118 elif code == 3:
119 self.italic = True
119 self.italic = True
120 elif code == 4:
120 elif code == 4:
121 self.underline = True
121 self.underline = True
122 elif code == 22:
122 elif code == 22:
123 self.intensity = 0
123 self.intensity = 0
124 self.bold = False
124 self.bold = False
125 elif code == 23:
125 elif code == 23:
126 self.italic = False
126 self.italic = False
127 elif code == 24:
127 elif code == 24:
128 self.underline = False
128 self.underline = False
129 elif code >= 30 and code <= 37:
129 elif code >= 30 and code <= 37:
130 self.foreground_color = code - 30
130 self.foreground_color = code - 30
131 elif code == 39:
131 elif code == 39:
132 self.foreground_color = None
132 self.foreground_color = None
133 elif code >= 40 and code <= 47:
133 elif code >= 40 and code <= 47:
134 self.background_color = code - 40
134 self.background_color = code - 40
135 elif code == 49:
135 elif code == 49:
136 self.background_color = None
136 self.background_color = None
137
137
138
138
139 class QtAnsiCodeProcessor(AnsiCodeProcessor):
139 class QtAnsiCodeProcessor(AnsiCodeProcessor):
140 """ Translates ANSI escape codes into QTextCharFormats.
140 """ Translates ANSI escape codes into QTextCharFormats.
141 """
141 """
142
142
143 # A map from color codes to RGB colors.
143 # A map from color codes to RGB colors.
144 ansi_colors = ( # Normal, Bright/Light
144 ansi_colors = (# Normal, Bright/Light ANSI color code
145 ('#000000', '#7f7f7f'), # 0: black
145 ('black', 'grey'), # 0: black
146 ('#cd0000', '#ff0000'), # 1: red
146 ('darkred', 'red'), # 1: red
147 ('#00cd00', '#00ff00'), # 2: green
147 ('darkgreen', 'green'), # 2: green
148 ('#cdcd00', '#ffff00'), # 3: yellow
148 ('gold', 'yellow'), # 3: yellow
149 ('#0000ee', '#0000ff'), # 4: blue
149 ('darkblue', 'blue'), # 4: blue
150 ('#cd00cd', '#ff00ff'), # 5: magenta
150 ('darkviolet', 'magenta'), # 5: magenta
151 ('#00cdcd', '#00ffff'), # 6: cyan
151 ('steelblue', 'cyan'), # 6: cyan
152 ('#e5e5e5', '#ffffff')) # 7: white
152 ('grey', 'white')) # 7: white
153
153
154 def get_format(self):
154 def get_format(self):
155 """ Returns a QTextCharFormat that encodes the current style attributes.
155 """ Returns a QTextCharFormat that encodes the current style attributes.
156 """
156 """
157 format = QtGui.QTextCharFormat()
157 format = QtGui.QTextCharFormat()
158
158
159 # Set foreground color
159 # Set foreground color
160 if self.foreground_color is not None:
160 if self.foreground_color is not None:
161 color = self.ansi_colors[self.foreground_color][self.intensity]
161 color = self.ansi_colors[self.foreground_color][self.intensity]
162 format.setForeground(QtGui.QColor(color))
162 format.setForeground(QtGui.QColor(color))
163
163
164 # Set background color
164 # Set background color
165 if self.background_color is not None:
165 if self.background_color is not None:
166 color = self.ansi_colors[self.background_color][self.intensity]
166 color = self.ansi_colors[self.background_color][self.intensity]
167 format.setBackground(QtGui.QColor(color))
167 format.setBackground(QtGui.QColor(color))
168
168
169 # Set font weight/style options
169 # Set font weight/style options
170 if self.bold:
170 if self.bold:
171 format.setFontWeight(QtGui.QFont.Bold)
171 format.setFontWeight(QtGui.QFont.Bold)
172 else:
172 else:
173 format.setFontWeight(QtGui.QFont.Normal)
173 format.setFontWeight(QtGui.QFont.Normal)
174 format.setFontItalic(self.italic)
174 format.setFontItalic(self.italic)
175 format.setFontUnderline(self.underline)
175 format.setFontUnderline(self.underline)
176
176
177 return format
177 return format
General Comments 0
You need to be logged in to leave comments. Login now