"""Renderer for code artifact messages."""
from __future__ import annotations
from rich.console import RenderableType
from rich.panel import Panel
from rich.syntax import Syntax
from rich.text import Text
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 ArtifactRenderer(ContentRenderer):
"""Render a file-like artifact with syntax highlighting."""
def accepts(self, msg: dict) -> bool:
return msg.get("type") == "artifact"
def render(self, msg: dict) -> RenderableType:
theme = get_active_theme()
path = msg.get("path", "artifact")
language = msg.get("language") or _guess_language(path)
content = msg.get("content", "")
if not content.strip():
return Panel(
Text("(empty artifact)", style=theme.text_dim.hex),
title=path,
title_align="left",
border_style=theme.border.hex,
)
code_theme = _theme_aware_code_theme(theme.name)
syntax = Syntax(
content,
language,
theme=code_theme,
background_color=theme.surface.hex,
line_numbers=True,
word_wrap=True,
)
return Panel(
syntax,
title=f"{path} [{language}]",
title_align="left",
border_style=theme.tool_border.hex,
)
def _guess_language(path: str) -> str:
"""Best-effort language tag from a file path."""
mapping = {
".py": "python",
".js": "javascript",
".ts": "typescript",
".tsx": "tsx",
".jsx": "jsx",
".go": "go",
".rs": "rust",
".c": "c",
".cpp": "cpp",
".h": "c",
".java": "java",
".kt": "kotlin",
".sh": "bash",
".zsh": "bash",
".bash": "bash",
".md": "markdown",
".json": "json",
".yaml": "yaml",
".yml": "yaml",
".toml": "toml",
".html": "html",
".css": "css",
".scss": "scss",
".sql": "sql",
".dockerfile": "dockerfile",
".txt": "text",
".env": "bash",
}
lower = path.lower()
for ext, lang in mapping.items():
if lower.endswith(ext):
return lang
return "text"