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