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
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
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>
6"""
7Color themes for the interactive console.
8"""
10##################
11# Color themes #
12##################
14import html
15import sys
17from typing import (
18 Any,
19 List,
20 Optional,
21 Tuple,
22 cast,
23)
24from scapy.compat import Protocol
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()}
59 def __repr__(self):
60 # type: () -> str
61 return "<ColorTable>"
63 def __getattr__(self, attr):
64 # type: (str) -> str
65 return self.colors.get(attr, [""])[0]
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()
77Color = ColorTable()
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
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
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 = ""
135 def __repr__(self):
136 # type: () -> str
137 return "<%s>" % self.__class__.__name__
139 def __reduce__(self):
140 # type: () -> Tuple[type, Any, Any]
141 return (self.__class__, (), ())
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()
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
157class NoTheme(ColorTheme):
158 pass
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 = ""
176 return create_styler(before=before, after=after)
179class BlackAndWhite(AnsiColorTheme, NoTheme):
180 pass
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
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
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
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
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)
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}"
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 )
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@]@"
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>"
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#]#"
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 )
434 class ClassicPrompt(Prompts):
435 def in_prompt_tokens(self, cli=None):
436 # type: (Any) -> List[Tuple[Any, str]]
437 return [(Token.Prompt, prompt), ]
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