##// END OF EJS Templates
Fix, ansi2latex style-less code support...
Jonathan Frederic -
Show More
@@ -1,145 +1,155
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 'remove_ansi',
23 'remove_ansi',
24 'ansi2html',
24 'ansi2html',
25 'single_ansi2latex',
25 'single_ansi2latex',
26 'ansi2latex'
26 'ansi2latex'
27 ]
27 ]
28
28
29 def remove_ansi(source):
29 def remove_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.iteritems():
74 for c, escape in html_escapes.iteritems():
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 colcode = getattr(coloransi.TermColors,color[0])
114
115 #Make sure to get the color code (which is a part of the overall style)
116 # i.e. 0;31 is valid
117 # 31 is also valid, and means the same thing
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
120 #if no other formating is applied (the other number must be a 0)!
121 style_code = getattr(coloransi.TermColors, color[0])
122 color_code = style_code.split(';')[1]
123 is_normal = style_code.split(';')[0] == '0'
124
115 # regular fonts
125 # regular fonts
116 if code == colcode:
126 if (code == style_code) or (is_normal and code == color_code):
117 return '\\'+color[0].lower()+'{', 1
127 return '\\'+color[0].lower()+'{', 1
118 # bold fonts
128 # bold fonts
119 if code == colcode[:3]+str(1)+colcode[3:]:
129 if code == style_code[:3]+str(1)+style_code[3:]:
120 return '\\textbf{\\textcolor{'+color[0].lower()+'}{', 2
130 return '\\textbf{\\textcolor{'+color[0].lower()+'}{', 2
121 return '', 0
131 return '', 0
122
132
123 def ansi2latex(text):
133 def ansi2latex(text):
124 """Converts ansi formated text to latex version
134 """Converts ansi formated text to latex version
125
135
126 based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
136 based on https://bitbucket.org/birkenfeld/sphinx-contrib/ansi.py
127 """
137 """
128 color_pattern = re.compile('\x1b\\[([^m]+)m')
138 color_pattern = re.compile('\x1b\\[([^m]+)m')
129 last_end = 0
139 last_end = 0
130 openbrack = 0
140 openbrack = 0
131 outstring = ''
141 outstring = ''
132 for match in color_pattern.finditer(text):
142 for match in color_pattern.finditer(text):
133 head = text[last_end:match.start()]
143 head = text[last_end:match.start()]
134 outstring += head
144 outstring += head
135 if openbrack:
145 if openbrack:
136 outstring += '}'*openbrack
146 outstring += '}'*openbrack
137 openbrack = 0
147 openbrack = 0
138 if match.group() <> coloransi.TermColors.Normal and not openbrack:
148 if match.group() <> coloransi.TermColors.Normal and not openbrack:
139 texform, openbrack = single_ansi2latex(match.group())
149 texform, openbrack = single_ansi2latex(match.group())
140 outstring += texform
150 outstring += texform
141 last_end = match.end()
151 last_end = match.end()
142 if openbrack:
152 if openbrack:
143 outstring += '}'*openbrack
153 outstring += '}'*openbrack
144 outstring += text[last_end:]
154 outstring += text[last_end:]
145 return outstring.strip()
155 return outstring.strip()
General Comments 0
You need to be logged in to leave comments. Login now