"""Renderer for markdown content."""
from __future__ import annotations
from rich.console import Console, RenderableType, ConsoleOptions, RenderResult
from rich.markdown import Markdown
from rich.segment import Segment
from rich.style import Style
from rich.theme import Theme as RichTheme
from clients.terminal.tui.themes import get_active_theme
from .base import ContentRenderer
def _theme_aware_code_theme(theme_name: str) -> str:
"""Pick a Pygments code theme that matches the Navi theme brightness."""
return "dracula" if theme_name == "gnexus-dark" else "github-light"
class ThemedMarkdownRenderable:
"""Wrap Markdown and render it with Navi theme colors applied."""
def __init__(self, markdown: Markdown, theme_name: str) -> None:
self._markdown = markdown
self._theme_name = theme_name
def __rich_console__(self, console: Console, options: ConsoleOptions) -> RenderResult:
theme = get_active_theme()
themed_console = Console(
width=console.width,
color_system=console.color_system,
theme=RichTheme(theme.rich_theme_styles()),
force_terminal=True,
)
segments = list(themed_console.render(self._markdown))
link_color = Style.parse(theme.link.hex).color
for segment in segments:
style = segment.style
if style and style.link and link_color is not None:
segment = Segment(
segment.text,
Style(color=link_color, underline=True, link=style.link),
)
yield segment
class MarkdownRenderer(ContentRenderer):
"""Render markdown text with syntax highlighting."""
def accepts(self, msg: dict) -> bool:
return msg.get("type") == "markdown"
def render(self, msg: dict) -> RenderableType:
theme = get_active_theme()
text = msg.get("content", "")
code_theme = _theme_aware_code_theme(theme.name)
md = Markdown(
text,
code_theme=code_theme,
inline_code_theme=code_theme,
)
return ThemedMarkdownRenderable(md, theme.name)