opencode icon indicating copy to clipboard operation
opencode copied to clipboard

feat(opencode): enhanced markdown renderer with tables, themes, and syntax highlighting

Open ryanwyler opened this issue 2 days ago • 5 comments

Related Issues

Tables & Formatting:

  • Closes #3845 - Markdown tables display as plain text instead of formatted tables
  • Closes #7671 - Markdown table formatting
  • Closes #4988 - [FEATURE]: Support Table Rendering in Markdown Format
  • Closes #5675 - markdown user messages aren't formatted

Summary

Comprehensive markdown rendering overhaul for both CLI and TUI with proper table support, theme integration, syntax highlighting, and unified rendering architecture.

Key Features

📊 Table Rendering

  • Box-drawing borders - Unicode characters (┌─┬─┐) instead of ASCII pipes
  • Automatic column sizing - Proportional width distribution based on content
  • Word wrapping - Long content wraps within cells without breaking inline code
  • Backtick preservation - Never breaks `code` across lines
  • Inline markdown in cells - Bold, italic, code, links all work in table cells
  • Escaped pipes - Support for \| to show literal pipes (TypeScript union types: `number | undefined`)
  • Double-width character support - Proper alignment with Unicode/emoji

🎨 Theme Support

  • Unified theme system - CLI and TUI use identical colors from user's theme
  • 12+ built-in themes - opencode, dracula, nord, catppuccin, tokyo-night, etc.
  • Theme loader - Loads theme JSON files and converts to rendering format
  • Automatic detection - Reads from user config, no manual setup needed

💻 Syntax Highlighting

  • Tree-sitter integration - Uses OpenTUI's tree-sitter for code blocks
  • 10+ languages - JavaScript, TypeScript, Python, Go, Rust, Shell, etc.
  • Diff highlighting - Red/green colors for added/removed lines
  • Stable rendering - No flashing during streaming

🎯 Advanced Formatting

  • Inline markdown - **bold**, *italic*, `code`, links, ~~strikethrough~~
  • Lists - Numbered and bulleted with colored markers
  • Blockquotes - Bar with proper formatting
  • Headers - Background color for h1/h2, bold for h3+
  • Horizontal rules - Clean separator lines

🏗️ Architecture

  • Unified rendering - Single source of truth (`renderMarkdownThemedStyled()`)
  • Code deduplication - CLI and TUI share rendering logic
  • TextChunk system - Universal format converted to ANSI (CLI) or StyledText (TUI)
  • Clean codebase - Removed 283 lines of dead legacy code (-18%)

🔧 Smart Behavior

  • TTY detection - Raw text when piped, formatted when interactive
  • Context-aware - GitHub bot doesn't load themes (no overhead for automation)
  • Streaming-friendly - No re-renders or flashing during message streaming

Technical Details

Files Changed

  • `markdown-renderer.ts` (new, 1297 lines) - Core rendering engine
  • `theme-loader.ts` (new, 98 lines) - Theme loading and conversion
  • `session/index.tsx` (+117 lines) - TUI integration with hybrid rendering
  • `run.ts` (+8 lines) - CLI theme integration
  • `ui.ts` (+5 lines) - Theme parameter support

Key Functions

  • `renderMarkdownThemedStyled()` - Main renderer, outputs TextChunks
  • `renderTableThemed()` - Table rendering with word wrap and inline markdown
  • `renderInlineThemed()` - Inline formatting (bold, italic, code, links)
  • `textChunksToAnsi()` - Converts TextChunks to ANSI for CLI
  • `loadTheme()` - Loads and converts theme JSON to rendering format

Rendering Flow

CLI: ``` User config → loadTheme() → MarkdownTheme Markdown → renderMarkdownThemedStyled() → TextChunks TextChunks → textChunksToAnsi() → ANSI string → stdout ```

TUI: ``` User config → Theme context → MarkdownTheme Markdown → parseMarkdownSegments() → [text, code, text, code] Text segments → renderMarkdownThemedStyled() → StyledText → Code segments → tree-sitter → ```

Examples

Before/After: Tables

Before: ``` | Header | Value | | A | B | ```

After: ``` ┌────────┬───────┐ │ Header │ Value │ ├────────┼───────┤ │ A │ B │ └────────┴───────┘ ```

Theme Colors

All colors match user's selected theme:

  • Headers - Accent color with background
  • Code - Monospace with code color
  • Links - Link color + underline
  • Bold/Italic - Distinct from regular text
  • Borders - Border color from theme

Testing

✅ CLI output verified with multiple themes
✅ TUI rendering stable during streaming
✅ Tables with complex content (inline code, word wrap, unicode)
✅ Escaped pipes (\|) for union types
✅ Double-width characters (emoji, CJK)
✅ TTY detection (piped vs interactive)
✅ All 12+ built-in themes load correctly

Breaking Changes

None - backward compatible. Existing markdown rendering continues to work.

Performance

  • Minimal overhead - Only loads theme once per session
  • No flashing - Stable rendering during streaming
  • Smart caching - Theme colors resolved once
  • Efficient word wrap - Token-based wrapping preserves inline code

Migration Notes

No migration needed. The feature is automatically available in both CLI and TUI.

Commits

22 commits with iterative improvements:

  • Initial implementation
  • Stability fixes (flashing, streaming)
  • Feature additions (tables, themes, inline markdown)
  • Code cleanup (removed 283 lines of dead code)
  • Bug fixes (escaped pipes, unicode width)
  • Refactoring (unified architecture)

ryanwyler avatar Jan 12 '26 22:01 ryanwyler