##// END OF EJS Templates
fix ansi coloring...
MinRK -
Show More
@@ -1,157 +1,158
1 """Filters for processing ANSI colors within Jinja templates.
1 """Filters for processing ANSI colors within Jinja templates.
2 """
2 """
3 #-----------------------------------------------------------------------------
3 #-----------------------------------------------------------------------------
4 # Copyright (c) 2013, the IPython Development Team.
4 # Copyright (c) 2013, the IPython Development Team.
5 #
5 #
6 # Distributed under the terms of the Modified BSD License.
6 # Distributed under the terms of the Modified BSD License.
7 #
7 #
8 # The full license is in the file COPYING.txt, distributed with this software.
8 # The full license is in the file COPYING.txt, distributed with this software.
9 #-----------------------------------------------------------------------------
9 #-----------------------------------------------------------------------------
10
10
11 #-----------------------------------------------------------------------------
11 #-----------------------------------------------------------------------------
12 # Imports
12 # Imports
13 #-----------------------------------------------------------------------------
13 #-----------------------------------------------------------------------------
14
14
15 import re
15 import re
16 from IPython.utils import coloransi
16 from IPython.utils import coloransi
17
17
18 #-----------------------------------------------------------------------------
18 #-----------------------------------------------------------------------------
19 # Classes and functions
19 # Classes and functions
20 #-----------------------------------------------------------------------------
20 #-----------------------------------------------------------------------------
21
21
22 __all__ = [
22 __all__ = [
23 'strip_ansi',
23 'strip_ansi',
24 'ansi2html',
24 'ansi2html',
25 'single_ansi2latex',
25 'single_ansi2latex',
26 'ansi2latex'
26 'ansi2latex'
27 ]
27 ]
28
28
29 def strip_ansi(source):
29 def strip_ansi(source):
30 """
30 """
31 Remove ansi from text
31 Remove ansi from text
32
32
33 Parameters
33 Parameters
34 ----------
34 ----------
35 source : str
35 source : str
36 Source to remove the ansi from
36 Source to remove the ansi from
37 """
37 """
38
38
39 return re.sub(r'\033\[(\d|;)+?m', '', source)
39 return re.sub(r'\033\[(\d|;)+?m', '', source)
40
40
41
41
42 def ansi2html(text):
42 def ansi2html(text):
43 """
43 """
44 Conver ansi colors to html colors.
44 Conver ansi colors to html colors.
45
45
46 Parameters
46 Parameters
47 ----------
47 ----------
48 text : str
48 text : str
49 Text containing ansi colors to convert to html
49 Text containing ansi colors to convert to html
50 """
50 """
51
51
52 ansi_colormap = {
52 ansi_colormap = {
53 '30': 'ansiblack',
53 '30': 'ansiblack',
54 '31': 'ansired',
54 '31': 'ansired',
55 '32': 'ansigreen',
55 '32': 'ansigreen',
56 '33': 'ansiyellow',
56 '33': 'ansiyellow',
57 '34': 'ansiblue',
57 '34': 'ansiblue',
58 '35': 'ansipurple',
58 '35': 'ansipurple',
59 '36': 'ansicyan',
59 '36': 'ansicyan',
60 '37': 'ansigrey',
60 '37': 'ansigrey',
61 '01': 'ansibold',
61 '01': 'ansibold',
62 }
62 }
63
63
64 # do ampersand first
64 # do ampersand first
65 text = text.replace('&', '&')
65 text = text.replace('&', '&')
66 html_escapes = {
66 html_escapes = {
67 '<': '&lt;',
67 '<': '&lt;',
68 '>': '&gt;',
68 '>': '&gt;',
69 "'": '&apos;',
69 "'": '&apos;',
70 '"': '&quot;',
70 '"': '&quot;',
71 '`': '&#96;',
71 '`': '&#96;',
72 }
72 }
73
73
74 for c, escape in html_escapes.items():
74 for c, escape in html_escapes.items():
75 text = text.replace(c, escape)
75 text = text.replace(c, escape)
76
76
77 ansi_re = re.compile('\x1b' + r'\[([\dA-Fa-f;]*?)m')
77 ansi_re = re.compile('\x1b' + r'\[([\dA-Fa-f;]*?)m')
78 m = ansi_re.search(text)
78 m = ansi_re.search(text)
79 opened = False
79 opened = False
80 cmds = []
80 cmds = []
81 opener = ''
81 opener = ''
82 closer = ''
82 closer = ''
83 while m:
83 while m:
84 cmds = m.groups()[0].split(';')
84 cmds = m.groups()[0].split(';')
85 closer = '</span>' if opened else ''
85 closer = '</span>' if opened else ''
86
86
87 # True if there is there more than one element in cmds, *or*
87 # True if there is there more than one element in cmds, *or*
88 # if there is only one but it is not equal to a string of zeroes.
88 # if there is only one but it is not equal to a string of zeroes.
89 opened = len(cmds) > 1 or cmds[0] != '0' * len(cmds[0])
89 opened = len(cmds) > 1 or cmds[0] != '0' * len(cmds[0])
90 classes = []
90 classes = []
91 for cmd in cmds:
91 for cmd in cmds:
92 if cmd in ansi_colormap:
92 if cmd in ansi_colormap:
93 classes.append(ansi_colormap.get(cmd))
93 classes.append(ansi_colormap.get(cmd))
94
94
95 if classes:
95 if classes:
96 opener = '<span class="%s">' % (' '.join(classes))
96 opener = '<span class="%s">' % (' '.join(classes))
97 else:
97 else:
98 opener = ''
98 opener = ''
99 text = re.sub(ansi_re, closer + opener, text, 1)
99 text = re.sub(ansi_re, closer + opener, text, 1)
100
100
101 m = ansi_re.search(text)
101 m = ansi_re.search(text)
102
102
103 if opened:
103 if opened:
104 text += '</span>'
104 text += '</span>'
105 return text
105 return text
106
106
107
107
108 def single_ansi2latex(code):
108 def single_ansi2latex(code):
109 """Converts single ansi markup to latex format
109 """Converts single ansi markup to latex format
110
110
111 Return latex code and number of open brackets.
111 Return latex code and number of open brackets.
112 """
112 """
113 for color in coloransi.color_templates:
113 for color in coloransi.color_templates:
114
114
115 #Make sure to get the color code (which is a part of the overall style)
115 #Make sure to get the color code (which is a part of the overall style)
116 # i.e. 0;31 is valid
116 # i.e. 0;31 is valid
117 # 31 is also valid, and means the same thing
117 # 31 is also valid, and means the same thing
118 #coloransi.color_templates stores the longer of the two formats %d;%d
118 #coloransi.color_templates stores the longer of the two formats %d;%d
119 #Get the short format so we can parse that too. Short format only exist
119 #Get the short format so we can parse that too. Short format only exist
120 #if no other formating is applied (the other number must be a 0)!
120 #if no other formating is applied (the other number must be a 0)!
121 style_code = getattr(coloransi.TermColors, color[0])
121 style_code = getattr(coloransi.TermColors, color[0])
122 color_code = style_code.split(';')[1]
122 color_code = style_code.split(';')[1]
123 is_normal = style_code.split(';')[0] == '0'
123 is_normal = style_code.split(';')[0] == '0'
124
124
125 # regular fonts
125 # regular weight
126 if (code == style_code) or (is_normal and code == color_code):
126 if (code == style_code) or (is_normal and code == color_code):
127 return '\\'+color[0].lower()+'{', 1
127
128 # bold fonts
128 return r'{\color{'+color[0].lower()+'}', 1
129 # bold
129 if code == style_code[:3]+str(1)+style_code[3:]:
130 if code == style_code[:3]+str(1)+style_code[3:]:
130 return '\\textbf{\\textcolor{'+color[0].lower()+'}{', 2
131 return r'\textbf{\color{'+color[0].lower()+'}', 1
131 return '', 0
132 return '', 0
132
133
133 def ansi2latex(text):
134 def ansi2latex(text):
134 """Converts ansi formated text to latex version
135 """Converts ansi formated text to latex version
135
136
136 based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
137 based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
137 """
138 """
138 color_pattern = re.compile('\x1b\\[([^m]+)m')
139 color_pattern = re.compile('\x1b\\[([^m]+)m')
139 last_end = 0
140 last_end = 0
140 openbrack = 0
141 openbrack = 0
141 outstring = ''
142 outstring = ''
142 for match in color_pattern.finditer(text):
143 for match in color_pattern.finditer(text):
143 head = text[last_end:match.start()]
144 head = text[last_end:match.start()]
144 outstring += head
145 outstring += head
145 if openbrack:
146 if openbrack:
146 outstring += '}'*openbrack
147 outstring += '}'*openbrack
147 openbrack = 0
148 openbrack = 0
148 if not (match.group() == coloransi.TermColors.Normal or openbrack):
149 if not (match.group() == coloransi.TermColors.Normal or openbrack):
149 texform, openbrack = single_ansi2latex(match.group())
150 texform, openbrack = single_ansi2latex(match.group())
150 outstring += texform
151 outstring += texform
151 last_end = match.end()
152 last_end = match.end()
152
153
153 #Add the remainer of the string and THEN close any remaining color brackets.
154 # Add the remainer of the string and THEN close any remaining color brackets.
154 outstring += text[last_end:]
155 outstring += text[last_end:]
155 if openbrack:
156 if openbrack:
156 outstring += '}'*openbrack
157 outstring += '}'*openbrack
157 return outstring.strip()
158 return outstring.strip()
General Comments 0
You need to be logged in to leave comments. Login now