Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/scapy/themes.py: 75%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

294 statements  

1# SPDX-License-Identifier: GPL-2.0-only 

2# This file is part of Scapy 

3# See https://scapy.net/ for more information 

4# Copyright (C) Philippe Biondi <phil@secdev.org> 

5 

6""" 

7Color themes for the interactive console. 

8""" 

9 

10################## 

11# Color themes # 

12################## 

13 

14import html 

15import sys 

16 

17from typing import ( 

18 Any, 

19 List, 

20 Optional, 

21 Tuple, 

22 cast, 

23) 

24from scapy.compat import Protocol 

25 

26 

27class ColorTable: 

28 colors = { # Format: (ansi, pygments) 

29 # foreground 

30 "black": ("\033[30m", "#ansiblack"), 

31 "red": ("\033[31m", "#ansired"), 

32 "green": ("\033[32m", "#ansigreen"), 

33 "yellow": ("\033[33m", "#ansiyellow"), 

34 "blue": ("\033[34m", "#ansiblue"), 

35 "purple": ("\033[35m", "#ansipurple"), 

36 "cyan": ("\033[36m", "#ansicyan"), 

37 "white": ("\033[37m", "#ansiwhite"), 

38 "grey": ("\033[38;5;246m", "#ansiwhite"), 

39 "reset": ("\033[39m", "noinherit"), 

40 # background 

41 "bg_black": ("\033[40m", "bg:#ansiblack"), 

42 "bg_red": ("\033[41m", "bg:#ansired"), 

43 "bg_green": ("\033[42m", "bg:#ansigreen"), 

44 "bg_yellow": ("\033[43m", "bg:#ansiyellow"), 

45 "bg_blue": ("\033[44m", "bg:#ansiblue"), 

46 "bg_purple": ("\033[45m", "bg:#ansipurple"), 

47 "bg_cyan": ("\033[46m", "bg:#ansicyan"), 

48 "bg_white": ("\033[47m", "bg:#ansiwhite"), 

49 "bg_reset": ("\033[49m", "noinherit"), 

50 # specials 

51 "normal": ("\033[0m", "noinherit"), # color & brightness 

52 "bold": ("\033[1m", "bold"), 

53 "uline": ("\033[4m", "underline"), 

54 "blink": ("\033[5m", ""), 

55 "invert": ("\033[7m", ""), 

56 } 

57 inv_map = {v[0]: v[1] for k, v in colors.items()} 

58 

59 def __repr__(self): 

60 # type: () -> str 

61 return "<ColorTable>" 

62 

63 def __getattr__(self, attr): 

64 # type: (str) -> str 

65 return self.colors.get(attr, [""])[0] 

66 

67 def ansi_to_pygments(self, x): 

68 # type: (str) -> str 

69 """ 

70 Transform ansi encoded text to Pygments text 

71 """ 

72 for k, v in self.inv_map.items(): 

73 x = x.replace(k, " " + v) 

74 return x.strip() 

75 

76 

77Color = ColorTable() 

78 

79 

80class _ColorFormatterType(Protocol): 

81 def __call__(self, 

82 val: Any, 

83 fmt: Optional[str] = None, 

84 fmt2: str = "", 

85 before: str = "", 

86 after: str = "") -> str: 

87 pass 

88 

89 

90def create_styler(fmt=None, # type: Optional[str] 

91 before="", # type: str 

92 after="", # type: str 

93 fmt2="%s" # type: str 

94 ): 

95 # type: (...) -> _ColorFormatterType 

96 def do_style(val: Any, 

97 fmt: Optional[str] = fmt, 

98 fmt2: str = fmt2, 

99 before: str = before, 

100 after: str = after) -> str: 

101 if fmt is None: 

102 sval = str(val) 

103 else: 

104 sval = fmt % val 

105 return fmt2 % (before + sval + after) 

106 return do_style 

107 

108 

109class ColorTheme: 

110 style_normal = "" 

111 style_prompt = "" 

112 style_punct = "" 

113 style_id = "" 

114 style_not_printable = "" 

115 style_layer_name = "" 

116 style_field_name = "" 

117 style_field_value = "" 

118 style_emph_field_name = "" 

119 style_emph_field_value = "" 

120 style_depreciate_field_name = "" 

121 style_packetlist_name = "" 

122 style_packetlist_proto = "" 

123 style_packetlist_value = "" 

124 style_fail = "" 

125 style_success = "" 

126 style_odd = "" 

127 style_even = "" 

128 style_opening = "" 

129 style_active = "" 

130 style_closed = "" 

131 style_left = "" 

132 style_right = "" 

133 style_logo = "" 

134 

135 def __repr__(self): 

136 # type: () -> str 

137 return "<%s>" % self.__class__.__name__ 

138 

139 def __reduce__(self): 

140 # type: () -> Tuple[type, Any, Any] 

141 return (self.__class__, (), ()) 

142 

143 def __getattr__(self, attr): 

144 # type: (str) -> _ColorFormatterType 

145 if attr in ["__getstate__", "__setstate__", "__getinitargs__", 

146 "__reduce_ex__"]: 

147 raise AttributeError() 

148 return create_styler() 

149 

150 def format(self, string, fmt): 

151 # type: (str, str) -> str 

152 for style in fmt.split("+"): 

153 string = getattr(self, style)(string) 

154 return string 

155 

156 

157class NoTheme(ColorTheme): 

158 pass 

159 

160 

161class AnsiColorTheme(ColorTheme): 

162 def __getattr__(self, attr): 

163 # type: (str) -> _ColorFormatterType 

164 if attr.startswith("__"): 

165 raise AttributeError(attr) 

166 s = "style_%s" % attr 

167 if s in self.__class__.__dict__: 

168 before = getattr(self, s) 

169 after = self.style_normal 

170 elif not isinstance(self, BlackAndWhite) and attr in Color.colors: 

171 before = Color.colors[attr][0] 

172 after = Color.colors["normal"][0] 

173 else: 

174 before = after = "" 

175 

176 return create_styler(before=before, after=after) 

177 

178 

179class BlackAndWhite(AnsiColorTheme, NoTheme): 

180 pass 

181 

182 

183class DefaultTheme(AnsiColorTheme): 

184 style_normal = Color.normal 

185 style_prompt = Color.blue + Color.bold 

186 style_punct = Color.normal 

187 style_id = Color.blue + Color.bold 

188 style_not_printable = Color.white 

189 style_depreciate_field_name = Color.grey 

190 style_layer_name = Color.red + Color.bold 

191 style_field_name = Color.blue 

192 style_field_value = Color.purple 

193 style_emph_field_name = Color.blue + Color.uline + Color.bold 

194 style_emph_field_value = Color.purple + Color.uline + Color.bold 

195 style_packetlist_name = Color.red + Color.bold 

196 style_packetlist_proto = Color.blue 

197 style_packetlist_value = Color.purple 

198 style_fail = Color.red + Color.bold 

199 style_success = Color.blue + Color.bold 

200 style_even = Color.black + Color.bold 

201 style_odd = Color.black 

202 style_opening = Color.yellow 

203 style_active = Color.black 

204 style_closed = Color.white 

205 style_left = Color.blue + Color.invert 

206 style_right = Color.red + Color.invert 

207 style_logo = Color.green + Color.bold 

208 

209 

210class BrightTheme(AnsiColorTheme): 

211 style_normal = Color.normal 

212 style_punct = Color.normal 

213 style_id = Color.yellow + Color.bold 

214 style_layer_name = Color.red + Color.bold 

215 style_field_name = Color.yellow + Color.bold 

216 style_field_value = Color.purple + Color.bold 

217 style_emph_field_name = Color.yellow + Color.bold 

218 style_emph_field_value = Color.green + Color.bold 

219 style_packetlist_name = Color.red + Color.bold 

220 style_packetlist_proto = Color.yellow + Color.bold 

221 style_packetlist_value = Color.purple + Color.bold 

222 style_fail = Color.red + Color.bold 

223 style_success = Color.blue + Color.bold 

224 style_even = Color.black + Color.bold 

225 style_odd = Color.black 

226 style_left = Color.cyan + Color.invert 

227 style_right = Color.purple + Color.invert 

228 style_logo = Color.green + Color.bold 

229 

230 

231class RastaTheme(AnsiColorTheme): 

232 style_normal = Color.normal + Color.green + Color.bold 

233 style_prompt = Color.yellow + Color.bold 

234 style_punct = Color.red 

235 style_id = Color.green + Color.bold 

236 style_not_printable = Color.green 

237 style_layer_name = Color.red + Color.bold 

238 style_field_name = Color.yellow + Color.bold 

239 style_field_value = Color.green + Color.bold 

240 style_emph_field_name = Color.green 

241 style_emph_field_value = Color.green 

242 style_packetlist_name = Color.red + Color.bold 

243 style_packetlist_proto = Color.yellow + Color.bold 

244 style_packetlist_value = Color.green + Color.bold 

245 style_fail = Color.red 

246 style_success = Color.red + Color.bold 

247 style_even = Color.yellow 

248 style_odd = Color.green 

249 style_left = Color.yellow + Color.invert 

250 style_right = Color.red + Color.invert 

251 style_logo = Color.green + Color.bold 

252 

253 

254class ColorOnBlackTheme(AnsiColorTheme): 

255 """Color theme for black backgrounds""" 

256 style_normal = Color.normal 

257 style_prompt = Color.green + Color.bold 

258 style_punct = Color.normal 

259 style_id = Color.green 

260 style_not_printable = Color.black + Color.bold 

261 style_layer_name = Color.yellow + Color.bold 

262 style_field_name = Color.cyan 

263 style_field_value = Color.purple + Color.bold 

264 style_emph_field_name = Color.cyan + Color.bold 

265 style_emph_field_value = Color.red + Color.bold 

266 style_packetlist_name = Color.black + Color.bold 

267 style_packetlist_proto = Color.yellow + Color.bold 

268 style_packetlist_value = Color.purple + Color.bold 

269 style_fail = Color.red + Color.bold 

270 style_success = Color.green 

271 style_even = Color.black + Color.bold 

272 style_odd = Color.white 

273 style_opening = Color.yellow 

274 style_active = Color.white + Color.bold 

275 style_closed = Color.black + Color.bold 

276 style_left = Color.cyan + Color.bold 

277 style_right = Color.red + Color.bold 

278 style_logo = Color.green + Color.bold 

279 

280 

281class FormatTheme(ColorTheme): 

282 def __getattr__(self, attr: str) -> _ColorFormatterType: 

283 if attr.startswith("__"): 

284 raise AttributeError(attr) 

285 colfmt = self.__class__.__dict__.get("style_%s" % attr, "%s") 

286 return create_styler(fmt2=colfmt) 

287 

288 

289class LatexTheme(FormatTheme): 

290 r""" 

291 You can prepend the output from this theme with 

292 \tt\obeyspaces\obeylines\tiny\noindent 

293 """ 

294 style_prompt = r"\textcolor{blue}{%s}" 

295 style_not_printable = r"\textcolor{gray}{%s}" 

296 style_layer_name = r"\textcolor{red}{\bf %s}" 

297 style_field_name = r"\textcolor{blue}{%s}" 

298 style_field_value = r"\textcolor{purple}{%s}" 

299 style_emph_field_name = r"\textcolor{blue}{\underline{%s}}" # ul 

300 style_emph_field_value = r"\textcolor{purple}{\underline{%s}}" # ul 

301 style_packetlist_name = r"\textcolor{red}{\bf %s}" 

302 style_packetlist_proto = r"\textcolor{blue}{%s}" 

303 style_packetlist_value = r"\textcolor{purple}{%s}" 

304 style_fail = r"\textcolor{red}{\bf %s}" 

305 style_success = r"\textcolor{blue}{\bf %s}" 

306 style_left = r"\textcolor{blue}{%s}" 

307 style_right = r"\textcolor{red}{%s}" 

308# style_even = r"}{\bf " 

309# style_odd = "" 

310 style_logo = r"\textcolor{green}{\bf %s}" 

311 

312 def __getattr__(self, attr: str) -> _ColorFormatterType: 

313 from scapy.utils import tex_escape 

314 styler = super(LatexTheme, self).__getattr__(attr) 

315 return cast( 

316 _ColorFormatterType, 

317 lambda x, *args, **kwargs: styler(tex_escape(str(x)), *args, **kwargs), 

318 ) 

319 

320 

321class LatexTheme2(FormatTheme): 

322 style_prompt = r"@`@textcolor@[@blue@]@@[@%s@]@" 

323 style_not_printable = r"@`@textcolor@[@gray@]@@[@%s@]@" 

324 style_layer_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" 

325 style_field_name = r"@`@textcolor@[@blue@]@@[@%s@]@" 

326 style_field_value = r"@`@textcolor@[@purple@]@@[@%s@]@" 

327 style_emph_field_name = r"@`@textcolor@[@blue@]@@[@@`@underline@[@%s@]@@]@" 

328 style_emph_field_value = r"@`@textcolor@[@purple@]@@[@@`@underline@[@%s@]@@]@" # noqa: E501 

329 style_packetlist_name = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" 

330 style_packetlist_proto = r"@`@textcolor@[@blue@]@@[@%s@]@" 

331 style_packetlist_value = r"@`@textcolor@[@purple@]@@[@%s@]@" 

332 style_fail = r"@`@textcolor@[@red@]@@[@@`@bfseries@[@@]@%s@]@" 

333 style_success = r"@`@textcolor@[@blue@]@@[@@`@bfseries@[@@]@%s@]@" 

334 style_even = r"@`@textcolor@[@gray@]@@[@@`@bfseries@[@@]@%s@]@" 

335# style_odd = r"@`@textcolor@[@black@]@@[@@`@bfseries@[@@]@%s@]@" 

336 style_left = r"@`@textcolor@[@blue@]@@[@%s@]@" 

337 style_right = r"@`@textcolor@[@red@]@@[@%s@]@" 

338 style_logo = r"@`@textcolor@[@green@]@@[@@`@bfseries@[@@]@%s@]@" 

339 

340 

341class HTMLTheme(FormatTheme): 

342 style_prompt = "<span class=prompt>%s</span>" 

343 style_not_printable = "<span class=not_printable>%s</span>" 

344 style_layer_name = "<span class=layer_name>%s</span>" 

345 style_field_name = "<span class=field_name>%s</span>" 

346 style_field_value = "<span class=field_value>%s</span>" 

347 style_emph_field_name = "<span class=emph_field_name>%s</span>" 

348 style_emph_field_value = "<span class=emph_field_value>%s</span>" 

349 style_packetlist_name = "<span class=packetlist_name>%s</span>" 

350 style_packetlist_proto = "<span class=packetlist_proto>%s</span>" 

351 style_packetlist_value = "<span class=packetlist_value>%s</span>" 

352 style_fail = "<span class=fail>%s</span>" 

353 style_success = "<span class=success>%s</span>" 

354 style_even = "<span class=even>%s</span>" 

355 style_odd = "<span class=odd>%s</span>" 

356 style_left = "<span class=left>%s</span>" 

357 style_right = "<span class=right>%s</span>" 

358 

359 

360class HTMLTheme2(HTMLTheme): 

361 style_prompt = "#[#span class=prompt#]#%s#[#/span#]#" 

362 style_not_printable = "#[#span class=not_printable#]#%s#[#/span#]#" 

363 style_layer_name = "#[#span class=layer_name#]#%s#[#/span#]#" 

364 style_field_name = "#[#span class=field_name#]#%s#[#/span#]#" 

365 style_field_value = "#[#span class=field_value#]#%s#[#/span#]#" 

366 style_emph_field_name = "#[#span class=emph_field_name#]#%s#[#/span#]#" 

367 style_emph_field_value = "#[#span class=emph_field_value#]#%s#[#/span#]#" 

368 style_packetlist_name = "#[#span class=packetlist_name#]#%s#[#/span#]#" 

369 style_packetlist_proto = "#[#span class=packetlist_proto#]#%s#[#/span#]#" 

370 style_packetlist_value = "#[#span class=packetlist_value#]#%s#[#/span#]#" 

371 style_fail = "#[#span class=fail#]#%s#[#/span#]#" 

372 style_success = "#[#span class=success#]#%s#[#/span#]#" 

373 style_even = "#[#span class=even#]#%s#[#/span#]#" 

374 style_odd = "#[#span class=odd#]#%s#[#/span#]#" 

375 style_left = "#[#span class=left#]#%s#[#/span#]#" 

376 style_right = "#[#span class=right#]#%s#[#/span#]#" 

377 

378 

379def apply_ipython_style(shell): 

380 # type: (Any) -> None 

381 """Updates the specified IPython console shell with 

382 the conf.color_theme scapy theme.""" 

383 try: 

384 from IPython.terminal.prompts import Prompts, Token 

385 except Exception: 

386 from scapy.error import log_loading 

387 log_loading.warning( 

388 "IPython too old. Shell color won't be handled." 

389 ) 

390 return 

391 from scapy.config import conf 

392 scapy_style = {} 

393 # Overwrite colors 

394 if isinstance(conf.color_theme, NoTheme): 

395 shell.colors = 'nocolor' 

396 elif isinstance(conf.color_theme, BrightTheme): 

397 # lightbg is optimized for light backgrounds 

398 shell.colors = 'lightbg' 

399 elif isinstance(conf.color_theme, ColorOnBlackTheme): 

400 # linux is optimised for dark backgrounds 

401 shell.colors = 'linux' 

402 else: 

403 # default 

404 shell.colors = 'neutral' 

405 try: 

406 get_ipython() # type: ignore 

407 # This function actually contains tons of hacks 

408 color_magic = shell.magics_manager.magics["line"]["colors"] 

409 color_magic(shell.colors) 

410 except NameError: 

411 pass 

412 # Prompt Style 

413 if isinstance(conf.prompt, Prompts): 

414 # Set custom prompt style 

415 shell.prompts_class = conf.prompt 

416 else: 

417 if isinstance(conf.color_theme, (FormatTheme, NoTheme)): 

418 # Formatable 

419 if isinstance(conf.color_theme, HTMLTheme): 

420 prompt = html.escape(conf.prompt) 

421 elif isinstance(conf.color_theme, LatexTheme): 

422 from scapy.utils import tex_escape 

423 prompt = tex_escape(conf.prompt) 

424 else: 

425 prompt = conf.prompt 

426 prompt = conf.color_theme.prompt(prompt) 

427 else: 

428 # Needs to be manually set 

429 prompt = str(conf.prompt) 

430 scapy_style[Token.Prompt] = Color.ansi_to_pygments( 

431 conf.color_theme.style_prompt 

432 ) 

433 

434 class ClassicPrompt(Prompts): 

435 def in_prompt_tokens(self, cli=None): 

436 # type: (Any) -> List[Tuple[Any, str]] 

437 return [(Token.Prompt, prompt), ] 

438 

439 def out_prompt_tokens(self): 

440 # type: () -> List[Tuple[Any, str]] 

441 return [(Token.OutPrompt, ''), ] 

442 # Apply classic prompt style 

443 shell.prompts_class = ClassicPrompt 

444 sys.ps1 = prompt 

445 # Register scapy color style 

446 shell.highlighting_style_overrides = scapy_style 

447 # Apply if Live 

448 try: 

449 get_ipython().refresh_style() # type: ignore 

450 except NameError: 

451 pass