| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent eba449a commit b024e50
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -68,6 +68,19 @@ class ANSIColors: | |||
| 68 | 68 | ColorCodes = set() | |
| 69 | 69 | NoColors = ANSIColors() | |
| 70 | 70 | ||
| 71 | + | ||
| 72 | + class CursesColors: | ||
| 73 | + """Curses color constants for terminal UI theming.""" | ||
| 74 | + BLACK = 0 | ||
| 75 | + RED = 1 | ||
| 76 | + GREEN = 2 | ||
| 77 | + YELLOW = 3 | ||
| 78 | + BLUE = 4 | ||
| 79 | + MAGENTA = 5 | ||
| 80 | + CYAN = 6 | ||
| 81 | + WHITE = 7 | ||
| 82 | + DEFAULT = -1 | ||
| 83 | + | ||
| 71 | 84 | for attr, code in ANSIColors.__dict__.items(): | |
| 72 | 85 | if not attr.startswith("__"): | |
| 73 | 86 | ColorCodes.add(code) | |
@@ -223,6 +236,119 @@ class Unittest(ThemeSection): | |||
| 223 | 236 | reset: str = ANSIColors.RESET | |
| 224 | 237 | ||
| 225 | 238 | ||
| 239 | + @dataclass(frozen=True, kw_only=True) | ||
| 240 | + class LiveProfiler(ThemeSection): | ||
| 241 | + """Theme section for the live profiling TUI (Tachyon profiler). | ||
| 242 | + | ||
| 243 | + Colors use CursesColors constants (BLACK, RED, GREEN, YELLOW, | ||
| 244 | + BLUE, MAGENTA, CYAN, WHITE, DEFAULT). | ||
| 245 | + """ | ||
| 246 | + # Header colors | ||
| 247 | + title_fg: int = CursesColors.CYAN | ||
| 248 | + title_bg: int = CursesColors.DEFAULT | ||
| 249 | + | ||
| 250 | + # Status display colors | ||
| 251 | + pid_fg: int = CursesColors.CYAN | ||
| 252 | + uptime_fg: int = CursesColors.GREEN | ||
| 253 | + time_fg: int = CursesColors.YELLOW | ||
| 254 | + interval_fg: int = CursesColors.MAGENTA | ||
| 255 | + | ||
| 256 | + # Thread view colors | ||
| 257 | + thread_all_fg: int = CursesColors.GREEN | ||
| 258 | + thread_single_fg: int = CursesColors.MAGENTA | ||
| 259 | + | ||
| 260 | + # Progress bar colors | ||
| 261 | + bar_good_fg: int = CursesColors.GREEN | ||
| 262 | + bar_bad_fg: int = CursesColors.RED | ||
| 263 | + | ||
| 264 | + # Stats colors | ||
| 265 | + on_gil_fg: int = CursesColors.GREEN | ||
| 266 | + off_gil_fg: int = CursesColors.RED | ||
| 267 | + waiting_gil_fg: int = CursesColors.YELLOW | ||
| 268 | + gc_fg: int = CursesColors.MAGENTA | ||
| 269 | + | ||
| 270 | + # Function display colors | ||
| 271 | + func_total_fg: int = CursesColors.CYAN | ||
| 272 | + func_exec_fg: int = CursesColors.GREEN | ||
| 273 | + func_stack_fg: int = CursesColors.YELLOW | ||
| 274 | + func_shown_fg: int = CursesColors.MAGENTA | ||
| 275 | + | ||
| 276 | + # Table header colors | ||
| 277 | + sorted_header_fg: int = CursesColors.BLACK | ||
| 278 | + sorted_header_bg: int = CursesColors.YELLOW | ||
| 279 | + | ||
| 280 | + # Data row colors | ||
| 281 | + samples_fg: int = CursesColors.CYAN | ||
| 282 | + file_fg: int = CursesColors.GREEN | ||
| 283 | + func_fg: int = CursesColors.YELLOW | ||
| 284 | + | ||
| 285 | + # Trend indicator colors | ||
| 286 | + trend_up_fg: int = CursesColors.GREEN | ||
| 287 | + trend_down_fg: int = CursesColors.RED | ||
| 288 | + | ||
| 289 | + # Medal colors for top functions | ||
| 290 | + medal_gold_fg: int = CursesColors.RED | ||
| 291 | + medal_silver_fg: int = CursesColors.YELLOW | ||
| 292 | + medal_bronze_fg: int = CursesColors.GREEN | ||
| 293 | + | ||
| 294 | + # Background style: 'dark' or 'light' | ||
| 295 | + background_style: str = "dark" | ||
| 296 | + | ||
| 297 | + | ||
| 298 | + LiveProfilerLight = LiveProfiler( | ||
| 299 | + # Header colors | ||
| 300 | + title_fg=CursesColors.BLUE, | ||
| 301 | + title_bg=CursesColors.DEFAULT, | ||
| 302 | + | ||
| 303 | + # Status display colors | ||
| 304 | + pid_fg=CursesColors.BLUE, | ||
| 305 | + uptime_fg=CursesColors.GREEN, | ||
| 306 | + time_fg=CursesColors.YELLOW, | ||
| 307 | + interval_fg=CursesColors.MAGENTA, | ||
| 308 | + | ||
| 309 | + # Thread view colors | ||
| 310 | + thread_all_fg=CursesColors.GREEN, | ||
| 311 | + thread_single_fg=CursesColors.MAGENTA, | ||
| 312 | + | ||
| 313 | + # Progress bar colors | ||
| 314 | + bar_good_fg=CursesColors.GREEN, | ||
| 315 | + bar_bad_fg=CursesColors.RED, | ||
| 316 | + | ||
| 317 | + # Stats colors | ||
| 318 | + on_gil_fg=CursesColors.GREEN, | ||
| 319 | + off_gil_fg=CursesColors.RED, | ||
| 320 | + waiting_gil_fg=CursesColors.YELLOW, | ||
| 321 | + gc_fg=CursesColors.MAGENTA, | ||
| 322 | + | ||
| 323 | + # Function display colors | ||
| 324 | + func_total_fg=CursesColors.BLUE, | ||
| 325 | + func_exec_fg=CursesColors.GREEN, | ||
| 326 | + func_stack_fg=CursesColors.YELLOW, | ||
| 327 | + func_shown_fg=CursesColors.MAGENTA, | ||
| 328 | + | ||
| 329 | + # Table header colors | ||
| 330 | + sorted_header_fg=CursesColors.WHITE, | ||
| 331 | + sorted_header_bg=CursesColors.BLUE, | ||
| 332 | + | ||
| 333 | + # Data row colors | ||
| 334 | + samples_fg=CursesColors.BLUE, | ||
| 335 | + file_fg=CursesColors.GREEN, | ||
| 336 | + func_fg=CursesColors.MAGENTA, | ||
| 337 | + | ||
| 338 | + # Trend indicator colors | ||
| 339 | + trend_up_fg=CursesColors.GREEN, | ||
| 340 | + trend_down_fg=CursesColors.RED, | ||
| 341 | + | ||
| 342 | + # Medal colors for top functions | ||
| 343 | + medal_gold_fg=CursesColors.RED, | ||
| 344 | + medal_silver_fg=CursesColors.BLUE, | ||
| 345 | + medal_bronze_fg=CursesColors.GREEN, | ||
| 346 | + | ||
| 347 | + # Background style | ||
| 348 | + background_style="light", | ||
| 349 | + ) | ||
| 350 | + | ||
| 351 | + | ||
| 226 | 352 | @dataclass(frozen=True, kw_only=True) | |
| 227 | 353 | class Theme: | |
| 228 | 354 | """A suite of themes for all sections of Python. | |
@@ -235,6 +361,7 @@ class Theme: | |||
| 235 | 361 | syntax: Syntax = field(default_factory=Syntax) | |
| 236 | 362 | traceback: Traceback = field(default_factory=Traceback) | |
| 237 | 363 | unittest: Unittest = field(default_factory=Unittest) | |
| 364 | + live_profiler: LiveProfiler = field(default_factory=LiveProfiler) | ||
| 238 | 365 | ||
| 239 | 366 | def copy_with( | |
| 240 | 367 | self, | |
@@ -244,6 +371,7 @@ def copy_with( | |||
| 244 | 371 | syntax: Syntax | None = None, | |
| 245 | 372 | traceback: Traceback | None = None, | |
| 246 | 373 | unittest: Unittest | None = None, | |
| 374 | + live_profiler: LiveProfiler | None = None, | ||
| 247 | 375 | ) -> Self: | |
| 248 | 376 | """Return a new Theme based on this instance with some sections replaced. | |
| 249 | 377 | ||
@@ -256,6 +384,7 @@ def copy_with( | |||
| 256 | 384 | syntax=syntax or self.syntax, | |
| 257 | 385 | traceback=traceback or self.traceback, | |
| 258 | 386 | unittest=unittest or self.unittest, | |
| 387 | + live_profiler=live_profiler or self.live_profiler, | ||
| 259 | 388 | ) | |
| 260 | 389 | ||
| 261 | 390 | @classmethod | |
@@ -272,6 +401,7 @@ def no_colors(cls) -> Self: | |||
| 272 | 401 | syntax=Syntax.no_colors(), | |
| 273 | 402 | traceback=Traceback.no_colors(), | |
| 274 | 403 | unittest=Unittest.no_colors(), | |
| 404 | + live_profiler=LiveProfiler.no_colors(), | ||
| 275 | 405 | ) | |
| 276 | 406 | ||
| 277 | 407 | ||
@@ -338,6 +468,9 @@ def _safe_getenv(k: str, fallback: str | None = None) -> str | None: | |||
| 338 | 468 | default_theme = Theme() | |
| 339 | 469 | theme_no_color = default_theme.no_colors() | |
| 340 | 470 | ||
| 471 | + # Convenience theme with light profiler colors (for white/light terminal backgrounds) | ||
| 472 | + light_profiler_theme = default_theme.copy_with(live_profiler=LiveProfilerLight) | ||
| 473 | + | ||
| 341 | 474 | ||
| 342 | 475 | def get_theme( | |
| 343 | 476 | *, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -525,79 +525,57 @@ def _cycle_sort(self, reverse=False): | |||
| 525 | 525 | ||
| 526 | 526 | def _setup_colors(self): | |
| 527 | 527 | """Set up color pairs and return color attributes.""" | |
| 528 | - | ||
| 529 | 528 | A_BOLD = self.display.get_attr("A_BOLD") | |
| 530 | 529 | A_REVERSE = self.display.get_attr("A_REVERSE") | |
| 531 | 530 | A_UNDERLINE = self.display.get_attr("A_UNDERLINE") | |
| 532 | 531 | A_NORMAL = self.display.get_attr("A_NORMAL") | |
| 533 | 532 | ||
| 534 | - # Check both curses color support and _colorize.can_colorize() | ||
| 535 | 533 | if self.display.has_colors() and self._can_colorize: | |
| 536 | 534 | with contextlib.suppress(Exception): | |
| 537 | - # Color constants (using curses values for compatibility) | ||
| 538 | - COLOR_CYAN = 6 | ||
| 539 | - COLOR_GREEN = 2 | ||
| 540 | - COLOR_YELLOW = 3 | ||
| 541 | - COLOR_BLACK = 0 | ||
| 542 | - COLOR_MAGENTA = 5 | ||
| 543 | - COLOR_RED = 1 | ||
| 544 | - | ||
| 545 | - # Initialize all color pairs used throughout the UI | ||
| 546 | - self.display.init_color_pair( | ||
| 547 | - 1, COLOR_CYAN, -1 | ||
| 548 | - ) # Data colors for stats rows | ||
| 549 | - self.display.init_color_pair(2, COLOR_GREEN, -1) | ||
| 550 | - self.display.init_color_pair(3, COLOR_YELLOW, -1) | ||
| 551 | - self.display.init_color_pair( | ||
| 552 | - COLOR_PAIR_HEADER_BG, COLOR_BLACK, COLOR_GREEN | ||
| 553 | - ) | ||
| 554 | - self.display.init_color_pair( | ||
| 555 | - COLOR_PAIR_CYAN, COLOR_CYAN, COLOR_BLACK | ||
| 556 | - ) | ||
| 557 | - self.display.init_color_pair( | ||
| 558 | - COLOR_PAIR_YELLOW, COLOR_YELLOW, COLOR_BLACK | ||
| 559 | - ) | ||
| 535 | + theme = _colorize.get_theme(force_color=True) | ||
| 536 | + profiler_theme = theme.live_profiler | ||
| 537 | + default_bg = -1 | ||
| 538 | + | ||
| 539 | + self.display.init_color_pair(1, profiler_theme.samples_fg, default_bg) | ||
| 540 | + self.display.init_color_pair(2, profiler_theme.file_fg, default_bg) | ||
| 541 | + self.display.init_color_pair(3, profiler_theme.func_fg, default_bg) | ||
| 542 | + | ||
| 543 | + header_bg = 2 if profiler_theme.background_style == "dark" else 4 | ||
| 544 | + self.display.init_color_pair(COLOR_PAIR_HEADER_BG, 0, header_bg) | ||
| 545 | + | ||
| 546 | + self.display.init_color_pair(COLOR_PAIR_CYAN, profiler_theme.pid_fg, default_bg) | ||
| 547 | + self.display.init_color_pair(COLOR_PAIR_YELLOW, profiler_theme.time_fg, default_bg) | ||
| 548 | + self.display.init_color_pair(COLOR_PAIR_GREEN, profiler_theme.uptime_fg, default_bg) | ||
| 549 | + self.display.init_color_pair(COLOR_PAIR_MAGENTA, profiler_theme.interval_fg, default_bg) | ||
| 550 | + self.display.init_color_pair(COLOR_PAIR_RED, profiler_theme.off_gil_fg, default_bg) | ||
| 560 | 551 | self.display.init_color_pair( | |
| 561 | - COLOR_PAIR_GREEN, COLOR_GREEN, COLOR_BLACK | ||
| 562 | - ) | ||
| 563 | - self.display.init_color_pair( | ||
| 564 | - COLOR_PAIR_MAGENTA, COLOR_MAGENTA, COLOR_BLACK | ||
| 565 | - ) | ||
| 566 | - self.display.init_color_pair( | ||
| 567 | - COLOR_PAIR_RED, COLOR_RED, COLOR_BLACK | ||
| 568 | - ) | ||
| 569 | - self.display.init_color_pair( | ||
| 570 | - COLOR_PAIR_SORTED_HEADER, COLOR_BLACK, COLOR_YELLOW | ||
| 552 | + COLOR_PAIR_SORTED_HEADER, | ||
| 553 | + profiler_theme.sorted_header_fg, | ||
| 554 | + profiler_theme.sorted_header_bg, | ||
| 571 | 555 | ) | |
| 572 | 556 | ||
| 557 | + TREND_UP_PAIR = 11 | ||
| 558 | + TREND_DOWN_PAIR = 12 | ||
| 559 | + self.display.init_color_pair(TREND_UP_PAIR, profiler_theme.trend_up_fg, default_bg) | ||
| 560 | + self.display.init_color_pair(TREND_DOWN_PAIR, profiler_theme.trend_down_fg, default_bg) | ||
| 561 | + | ||
| 573 | 562 | return { | |
| 574 | - "header": self.display.get_color_pair(COLOR_PAIR_HEADER_BG) | ||
| 575 | - | A_BOLD, | ||
| 576 | - "cyan": self.display.get_color_pair(COLOR_PAIR_CYAN) | ||
| 577 | - | A_BOLD, | ||
| 578 | - "yellow": self.display.get_color_pair(COLOR_PAIR_YELLOW) | ||
| 579 | - | A_BOLD, | ||
| 580 | - "green": self.display.get_color_pair(COLOR_PAIR_GREEN) | ||
| 581 | - | A_BOLD, | ||
| 582 | - "magenta": self.display.get_color_pair(COLOR_PAIR_MAGENTA) | ||
| 583 | - | A_BOLD, | ||
| 584 | - "red": self.display.get_color_pair(COLOR_PAIR_RED) | ||
| 585 | - | A_BOLD, | ||
| 586 | - "sorted_header": self.display.get_color_pair( | ||
| 587 | - COLOR_PAIR_SORTED_HEADER | ||
| 588 | - ) | ||
| 589 | - | A_BOLD, | ||
| 563 | + "header": self.display.get_color_pair(COLOR_PAIR_HEADER_BG) | A_BOLD, | ||
| 564 | + "cyan": self.display.get_color_pair(COLOR_PAIR_CYAN) | A_BOLD, | ||
| 565 | + "yellow": self.display.get_color_pair(COLOR_PAIR_YELLOW) | A_BOLD, | ||
| 566 | + "green": self.display.get_color_pair(COLOR_PAIR_GREEN) | A_BOLD, | ||
| 567 | + "magenta": self.display.get_color_pair(COLOR_PAIR_MAGENTA) | A_BOLD, | ||
| 568 | + "red": self.display.get_color_pair(COLOR_PAIR_RED) | A_BOLD, | ||
| 569 | + "sorted_header": self.display.get_color_pair(COLOR_PAIR_SORTED_HEADER) | A_BOLD, | ||
| 590 | 570 | "normal_header": A_REVERSE | A_BOLD, | |
| 591 | 571 | "color_samples": self.display.get_color_pair(1), | |
| 592 | 572 | "color_file": self.display.get_color_pair(2), | |
| 593 | 573 | "color_func": self.display.get_color_pair(3), | |
| 594 | - # Trend colors (stock-like indicators) | ||
| 595 | - "trend_up": self.display.get_color_pair(COLOR_PAIR_GREEN) | A_BOLD, | ||
| 596 | - "trend_down": self.display.get_color_pair(COLOR_PAIR_RED) | A_BOLD, | ||
| 574 | + "trend_up": self.display.get_color_pair(TREND_UP_PAIR) | A_BOLD, | ||
| 575 | + "trend_down": self.display.get_color_pair(TREND_DOWN_PAIR) | A_BOLD, | ||
| 597 | 576 | "trend_stable": A_NORMAL, | |
| 598 | 577 | } | |
| 599 | 578 | ||
| 600 | - # Fallback to non-color attributes | ||
| 601 | 579 | return { | |
| 602 | 580 | "header": A_REVERSE | A_BOLD, | |
| 603 | 581 | "cyan": A_BOLD, | |
@@ -610,7 +588,6 @@ def _setup_colors(self): | |||
| 610 | 588 | "color_samples": A_NORMAL, | |
| 611 | 589 | "color_file": A_NORMAL, | |
| 612 | 590 | "color_func": A_NORMAL, | |
| 613 | - # Trend colors (fallback to bold/normal for monochrome) | ||
| 614 | 591 | "trend_up": A_BOLD, | |
| 615 | 592 | "trend_down": A_BOLD, | |
| 616 | 593 | "trend_stable": A_NORMAL, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -639,8 +639,6 @@ def render(self, line, width, **kwargs): | |||
| 639 | 639 | ||
| 640 | 640 | def draw_column_headers(self, line, width): | |
| 641 | 641 | """Draw column headers with sort indicators.""" | |
| 642 | - col = 0 | ||
| 643 | - | ||
| 644 | 642 | # Determine which columns to show based on width | |
| 645 | 643 | show_sample_pct = width >= WIDTH_THRESHOLD_SAMPLE_PCT | |
| 646 | 644 | show_tottime = width >= WIDTH_THRESHOLD_TOTTIME | |
@@ -659,38 +657,38 @@ def draw_column_headers(self, line, width): | |||
| 659 | 657 | "cumtime": 4, | |
| 660 | 658 | }.get(self.collector.sort_by, -1) | |
| 661 | 659 | ||
| 660 | + # Build the full header line first, then draw it | ||
| 661 | + # This avoids gaps between columns when using reverse video | ||
| 662 | + header_parts = [] | ||
| 663 | + col = 0 | ||
| 664 | + | ||
| 662 | 665 | # Column 0: nsamples | |
| 663 | - attr = sorted_header if sort_col == 0 else normal_header | ||
| 664 | - text = f"{'▼nsamples' if sort_col == 0 else 'nsamples':>13}" | ||
| 665 | - self.add_str(line, col, text, attr) | ||
| 666 | + text = f"{'▼nsamples' if sort_col == 0 else 'nsamples':>13} " | ||
| 667 | + header_parts.append((col, text, sorted_header if sort_col == 0 else normal_header)) | ||
| 666 | 668 | col += 15 | |
| 667 | 669 | ||
| 668 | 670 | # Column 1: sample % | |
| 669 | 671 | if show_sample_pct: | |
| 670 | - attr = sorted_header if sort_col == 1 else normal_header | ||
| 671 | - text = f"{'▼%' if sort_col == 1 else '%':>5}" | ||
| 672 | - self.add_str(line, col, text, attr) | ||
| 672 | + text = f"{'▼%' if sort_col == 1 else '%':>5} " | ||
| 673 | + header_parts.append((col, text, sorted_header if sort_col == 1 else normal_header)) | ||
| 673 | 674 | col += 7 | |
| 674 | 675 | ||
| 675 | 676 | # Column 2: tottime | |
| 676 | 677 | if show_tottime: | |
| 677 | - attr = sorted_header if sort_col == 2 else normal_header | ||
| 678 | - text = f"{'▼tottime' if sort_col == 2 else 'tottime':>10}" | ||
| 679 | - self.add_str(line, col, text, attr) | ||
| 678 | + text = f"{'▼tottime' if sort_col == 2 else 'tottime':>10} " | ||
| 679 | + header_parts.append((col, text, sorted_header if sort_col == 2 else normal_header)) | ||
| 680 | 680 | col += 12 | |
| 681 | 681 | ||
| 682 | 682 | # Column 3: cumul % | |
| 683 | 683 | if show_cumul_pct: | |
| 684 | - attr = sorted_header if sort_col == 3 else normal_header | ||
| 685 | - text = f"{'▼%' if sort_col == 3 else '%':>5}" | ||
| 686 | - self.add_str(line, col, text, attr) | ||
| 684 | + text = f"{'▼%' if sort_col == 3 else '%':>5} " | ||
| 685 | + header_parts.append((col, text, sorted_header if sort_col == 3 else normal_header)) | ||
| 687 | 686 | col += 7 | |
| 688 | 687 | ||
| 689 | 688 | # Column 4: cumtime | |
| 690 | 689 | if show_cumtime: | |
| 691 | - attr = sorted_header if sort_col == 4 else normal_header | ||
| 692 | - text = f"{'▼cumtime' if sort_col == 4 else 'cumtime':>10}" | ||
| 693 | - self.add_str(line, col, text, attr) | ||
| 690 | + text = f"{'▼cumtime' if sort_col == 4 else 'cumtime':>10} " | ||
| 691 | + header_parts.append((col, text, sorted_header if sort_col == 4 else normal_header)) | ||
| 694 | 692 | col += 12 | |
| 695 | 693 | ||
| 696 | 694 | # Remaining headers | |
@@ -700,13 +698,22 @@ def draw_column_headers(self, line, width): | |||
| 700 | 698 | MAX_FUNC_NAME_WIDTH, | |
| 701 | 699 | max(MIN_FUNC_NAME_WIDTH, remaining_space // 2), | |
| 702 | 700 | ) | |
| 703 | - self.add_str( | ||
| 704 | - line, col, f"{'function':<{func_width}}", normal_header | ||
| 705 | - ) | ||
| 701 | + text = f"{'function':<{func_width}} " | ||
| 702 | + header_parts.append((col, text, normal_header)) | ||
| 706 | 703 | col += func_width + 2 | |
| 707 | 704 | ||
| 708 | 705 | if col < width - 10: | |
| 709 | - self.add_str(line, col, "file:line", normal_header) | ||
| 706 | + file_text = "file:line" | ||
| 707 | + padding = width - col - len(file_text) | ||
| 708 | + text = file_text + " " * max(0, padding) | ||
| 709 | + header_parts.append((col, text, normal_header)) | ||
| 710 | + | ||
| 711 | + # Draw full-width background first | ||
| 712 | + self.add_str(line, 0, " " * (width - 1), normal_header) | ||
| 713 | + | ||
| 714 | + # Draw each header part on top | ||
| 715 | + for col_pos, text, attr in header_parts: | ||
| 716 | + self.add_str(line, col_pos, text.rstrip(), attr) | ||
| 710 | 717 | ||
| 711 | 718 | return ( | |
| 712 | 719 | line + 1, | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,4 @@ | |||
| 1 | + The Tachyon profiler's live TUI now integrates with the :mod:`!_colorize` | ||
| 2 | + theming system, allowing users to customize colors via | ||
| 3 | + :func:`!_colorize.set_theme`. A :class:`!LiveProfilerLight` theme is provided | ||
| 4 | + for light terminal backgrounds. Patch by Pablo Galindo. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments