Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/nbconvert/filters/ansi.py: 7%

169 statements  

« prev     ^ index     » next       coverage.py v7.2.7, created at 2023-07-01 06:54 +0000

1"""Filters for processing ANSI colors within Jinja templates.""" 

2 

3# Copyright (c) IPython Development Team. 

4# Distributed under the terms of the Modified BSD License. 

5 

6import re 

7 

8import markupsafe 

9 

10__all__ = ["strip_ansi", "ansi2html", "ansi2latex"] 

11 

12_ANSI_RE = re.compile("\x1b\\[(.*?)([@-~])") 

13 

14_ANSI_COLORS = ( 

15 "ansi-black", 

16 "ansi-red", 

17 "ansi-green", 

18 "ansi-yellow", 

19 "ansi-blue", 

20 "ansi-magenta", 

21 "ansi-cyan", 

22 "ansi-white", 

23 "ansi-black-intense", 

24 "ansi-red-intense", 

25 "ansi-green-intense", 

26 "ansi-yellow-intense", 

27 "ansi-blue-intense", 

28 "ansi-magenta-intense", 

29 "ansi-cyan-intense", 

30 "ansi-white-intense", 

31) 

32 

33 

34def strip_ansi(source): 

35 """ 

36 Remove ANSI escape codes from text. 

37 

38 Parameters 

39 ---------- 

40 source : str 

41 Source to remove the ANSI from 

42 

43 """ 

44 return _ANSI_RE.sub("", source) 

45 

46 

47def ansi2html(text): 

48 """ 

49 Convert ANSI colors to HTML colors. 

50 

51 Parameters 

52 ---------- 

53 text : unicode 

54 Text containing ANSI colors to convert to HTML 

55 

56 """ 

57 text = markupsafe.escape(text) 

58 return _ansi2anything(text, _htmlconverter) 

59 

60 

61def ansi2latex(text): 

62 """ 

63 Convert ANSI colors to LaTeX colors. 

64 

65 Parameters 

66 ---------- 

67 text : unicode 

68 Text containing ANSI colors to convert to LaTeX 

69 

70 """ 

71 return _ansi2anything(text, _latexconverter) 

72 

73 

74def _htmlconverter(fg, bg, bold, underline, inverse): # noqa 

75 """ 

76 Return start and end tags for given foreground/background/bold/underline. 

77 

78 """ 

79 if (fg, bg, bold, underline, inverse) == (None, None, False, False, False): 

80 return "", "" 

81 

82 classes = [] 

83 styles = [] 

84 

85 if inverse: 

86 fg, bg = bg, fg 

87 

88 if isinstance(fg, int): 

89 classes.append(_ANSI_COLORS[fg] + "-fg") 

90 elif fg: 

91 styles.append("color: rgb({},{},{})".format(*fg)) 

92 elif inverse: 

93 classes.append("ansi-default-inverse-fg") 

94 

95 if isinstance(bg, int): 

96 classes.append(_ANSI_COLORS[bg] + "-bg") 

97 elif bg: 

98 styles.append("background-color: rgb({},{},{})".format(*bg)) 

99 elif inverse: 

100 classes.append("ansi-default-inverse-bg") 

101 

102 if bold: 

103 classes.append("ansi-bold") 

104 

105 if underline: 

106 classes.append("ansi-underline") 

107 

108 starttag = "<span" 

109 if classes: 

110 starttag += ' class="' + " ".join(classes) + '"' 

111 if styles: 

112 starttag += ' style="' + "; ".join(styles) + '"' 

113 starttag += ">" 

114 return starttag, "</span>" 

115 

116 

117def _latexconverter(fg, bg, bold, underline, inverse): # noqa 

118 """ 

119 Return start and end markup given foreground/background/bold/underline. 

120 

121 """ 

122 if (fg, bg, bold, underline, inverse) == (None, None, False, False, False): 

123 return "", "" 

124 

125 starttag, endtag = "", "" 

126 

127 if inverse: 

128 fg, bg = bg, fg 

129 

130 if isinstance(fg, int): 

131 starttag += r"\textcolor{" + _ANSI_COLORS[fg] + "}{" 

132 endtag = "}" + endtag 

133 elif fg: 

134 # See http://tex.stackexchange.com/a/291102/13684 

135 starttag += r"\def\tcRGB{\textcolor[RGB]}\expandafter" 

136 starttag += r"\tcRGB\expandafter{{\detokenize{{{},{},{}}}}}{{".format(*fg) 

137 endtag = "}" + endtag 

138 elif inverse: 

139 starttag += r"\textcolor{ansi-default-inverse-fg}{" 

140 endtag = "}" + endtag 

141 

142 if isinstance(bg, int): 

143 starttag += r"\setlength{\fboxsep}{0pt}" 

144 starttag += r"\colorbox{" + _ANSI_COLORS[bg] + "}{" 

145 endtag = r"\strut}" + endtag 

146 elif bg: 

147 starttag += r"\setlength{\fboxsep}{0pt}" 

148 # See http://tex.stackexchange.com/a/291102/13684 

149 starttag += r"\def\cbRGB{\colorbox[RGB]}\expandafter" 

150 starttag += r"\cbRGB\expandafter{{\detokenize{{{},{},{}}}}}{{".format(*bg) 

151 endtag = r"\strut}" + endtag 

152 elif inverse: 

153 starttag += r"\setlength{\fboxsep}{0pt}" 

154 starttag += r"\colorbox{ansi-default-inverse-bg}{" 

155 endtag = r"\strut}" + endtag 

156 

157 if bold: 

158 starttag += r"\textbf{" 

159 endtag = "}" + endtag 

160 

161 if underline: 

162 starttag += r"\underline{" 

163 endtag = "}" + endtag 

164 

165 return starttag, endtag 

166 

167 

168def _ansi2anything(text, converter): # noqa 

169 r""" 

170 Convert ANSI colors to HTML or LaTeX. 

171 

172 See https://en.wikipedia.org/wiki/ANSI_escape_code 

173 

174 Accepts codes like '\x1b[32m' (red) and '\x1b[1;32m' (bold, red). 

175 

176 Non-color escape sequences (not ending with 'm') are filtered out. 

177 

178 Ideally, this should have the same behavior as the function 

179 fixConsole() in notebook/notebook/static/base/js/utils.js. 

180 

181 """ 

182 fg, bg = None, None 

183 bold = False 

184 underline = False 

185 inverse = False 

186 numbers = [] 

187 out = [] 

188 

189 while text: 

190 m = _ANSI_RE.search(text) 

191 if m: 

192 if m.group(2) == "m": 

193 try: 

194 # Empty code is same as code 0 

195 numbers = [int(n) if n else 0 for n in m.group(1).split(";")] 

196 except ValueError: 

197 pass # Invalid color specification 

198 else: 

199 pass # Not a color code 

200 chunk, text = text[: m.start()], text[m.end() :] 

201 else: 

202 chunk, text = text, "" 

203 

204 if chunk: 

205 starttag, endtag = converter( 

206 fg + 8 if bold and fg in range(8) else fg, # type:ignore 

207 bg, 

208 bold, 

209 underline, 

210 inverse, 

211 ) 

212 out.append(starttag) 

213 out.append(chunk) 

214 out.append(endtag) 

215 

216 while numbers: 

217 n = numbers.pop(0) 

218 if n == 0: 

219 # Code 0 (same as empty code): reset everything 

220 fg = bg = None 

221 bold = underline = inverse = False 

222 elif n == 1: 

223 bold = True 

224 elif n == 4: 

225 underline = True 

226 elif n == 5: 

227 # Code 5: blinking 

228 bold = True 

229 elif n == 7: 

230 inverse = True 

231 elif n in (21, 22): 

232 bold = False 

233 elif n == 24: 

234 underline = False 

235 elif n == 27: 

236 inverse = False 

237 elif 30 <= n <= 37: 

238 fg = n - 30 

239 elif n == 38: 

240 try: 

241 fg = _get_extended_color(numbers) 

242 except ValueError: 

243 numbers.clear() 

244 elif n == 39: 

245 fg = None 

246 elif 40 <= n <= 47: 

247 bg = n - 40 

248 elif n == 48: 

249 try: 

250 bg = _get_extended_color(numbers) 

251 except ValueError: 

252 numbers.clear() 

253 elif n == 49: 

254 bg = None 

255 elif 90 <= n <= 97: 

256 fg = n - 90 + 8 

257 elif 100 <= n <= 107: 

258 bg = n - 100 + 8 

259 else: 

260 pass # Unknown codes are ignored 

261 return "".join(out) 

262 

263 

264def _get_extended_color(numbers): 

265 n = numbers.pop(0) 

266 if n == 2 and len(numbers) >= 3: 

267 # 24-bit RGB 

268 r = numbers.pop(0) 

269 g = numbers.pop(0) 

270 b = numbers.pop(0) 

271 if not all(0 <= c <= 255 for c in (r, g, b)): 

272 raise ValueError() 

273 elif n == 5 and len(numbers) >= 1: 

274 # 256 colors 

275 idx = numbers.pop(0) 

276 if idx < 0: 

277 raise ValueError() 

278 elif idx < 16: 

279 # 16 default terminal colors 

280 return idx 

281 elif idx < 232: 

282 # 6x6x6 color cube, see http://stackoverflow.com/a/27165165/500098 

283 r = (idx - 16) // 36 

284 r = 55 + r * 40 if r > 0 else 0 

285 g = ((idx - 16) % 36) // 6 

286 g = 55 + g * 40 if g > 0 else 0 

287 b = (idx - 16) % 6 

288 b = 55 + b * 40 if b > 0 else 0 

289 elif idx < 256: 

290 # grayscale, see http://stackoverflow.com/a/27165165/500098 

291 r = g = b = (idx - 232) * 10 + 8 

292 else: 

293 raise ValueError() 

294 else: 

295 raise ValueError() 

296 return r, g, b