Skip to content

Commit 16656e6

Browse files
authored
Merge pull request #4001 from ggozad/fix/textarea-markdown-respect-theme
Make TextArea, MarkdownFence respect theme changes.
2 parents bd20c04 + 690ca0d commit 16656e6

File tree

5 files changed

+598
-16
lines changed

5 files changed

+598
-16
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
### Unreleased
9+
10+
### Added
11+
12+
- Added support for configuring dark and light themes for code in `Markdown` https://github.com/Textualize/textual/issues/3997
13+
814
## [0.49.1] - 2023-02-08
915

1016
### Fixed

src/textual/widgets/_markdown.py

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from markdown_it.token import Token
88
from rich import box
99
from rich.style import Style
10+
from rich.syntax import Syntax
1011
from rich.table import Table
1112
from rich.text import Text
1213
from typing_extensions import TypeAlias
@@ -498,22 +499,41 @@ class MarkdownFence(MarkdownBlock):
498499
"""
499500

500501
def __init__(self, markdown: Markdown, code: str, lexer: str) -> None:
502+
super().__init__(markdown)
501503
self.code = code
502504
self.lexer = lexer
503-
super().__init__(markdown)
505+
self.theme = (
506+
self._markdown.code_dark_theme
507+
if self.app.dark
508+
else self._markdown.code_light_theme
509+
)
504510

505-
def compose(self) -> ComposeResult:
506-
from rich.syntax import Syntax
511+
def _block(self) -> Syntax:
512+
return Syntax(
513+
self.code,
514+
lexer=self.lexer,
515+
word_wrap=False,
516+
indent_guides=True,
517+
padding=(1, 2),
518+
theme=self.theme,
519+
)
520+
521+
def _on_mount(self, _: Mount) -> None:
522+
"""Watch app theme switching."""
523+
self.watch(self.app, "dark", self._retheme)
524+
525+
def _retheme(self) -> None:
526+
"""Rerender when the theme changes."""
527+
self.theme = (
528+
self._markdown.code_dark_theme
529+
if self.app.dark
530+
else self._markdown.code_light_theme
531+
)
532+
self.get_child_by_type(Static).update(self._block())
507533

534+
def compose(self) -> ComposeResult:
508535
yield Static(
509-
Syntax(
510-
self.code,
511-
lexer=self.lexer,
512-
word_wrap=False,
513-
indent_guides=True,
514-
padding=(1, 2),
515-
theme="material",
516-
),
536+
self._block(),
517537
expand=True,
518538
shrink=False,
519539
)
@@ -567,6 +587,12 @@ class Markdown(Widget):
567587

568588
BULLETS = ["\u25CF ", "▪ ", "‣ ", "• ", "⭑ "]
569589

590+
code_dark_theme: reactive[str] = reactive("material")
591+
"""The theme to use for code blocks when in [dark mode][textual.app.App.dark]."""
592+
593+
code_light_theme: reactive[str] = reactive("material-light")
594+
"""The theme to use for code blocks when in [light mode][textual.app.App.dark]."""
595+
570596
def __init__(
571597
self,
572598
markdown: str | None = None,
@@ -653,6 +679,18 @@ def _on_mount(self, _: Mount) -> None:
653679
if self._markdown is not None:
654680
self.update(self._markdown)
655681

682+
def _watch_code_dark_theme(self) -> None:
683+
"""React to the dark theme being changed."""
684+
if self.app.dark:
685+
for block in self.query(MarkdownFence):
686+
block._retheme()
687+
688+
def _watch_code_light_theme(self) -> None:
689+
"""React to the light theme being changed."""
690+
if not self.app.dark:
691+
for block in self.query(MarkdownFence):
692+
block._retheme()
693+
656694
@staticmethod
657695
def sanitize_location(location: str) -> tuple[Path, str]:
658696
"""Given a location, break out the path and any anchor.
@@ -858,11 +896,7 @@ def update(self, markdown: str) -> AwaitComplete:
858896
stack[-1].set_content(content)
859897
elif token.type in ("fence", "code_block"):
860898
(stack[-1]._blocks if stack else output).append(
861-
MarkdownFence(
862-
self,
863-
token.content.rstrip(),
864-
token.info,
865-
)
899+
MarkdownFence(self, token.content.rstrip(), token.info)
866900
)
867901
else:
868902
external = self.unhandled_token(token)

0 commit comments

Comments
 (0)