Source code for pyqt_reactive.core.rich_text_appender

"""Utility for appending HTML content to QTextEdit with proper cursor/scroll handling."""

import html
from typing import Optional
from PyQt6.QtWidgets import QTextEdit
from PyQt6.QtGui import QTextCursor

from pyqt_reactive.theming import ColorScheme


[docs] class RichTextAppender: """ Utility for appending HTML content to QTextEdit with proper cursor/scroll handling. Usage: appender = RichTextAppender(self.chat_history, color_scheme=self.color_scheme) appender.append_html("<b>User:</b> Hello") appender.append_code("def foo(): pass") appender.append_error("Something went wrong") """
[docs] def __init__(self, text_edit: QTextEdit, color_scheme: ColorScheme = None): self._text_edit = text_edit self._color_scheme = color_scheme or ColorScheme() self._border_color = self._color_scheme.to_hex(self._color_scheme.border_color) self._success_color = self._color_scheme.to_hex(self._color_scheme.status_success) self._error_color = self._color_scheme.to_hex(self._color_scheme.status_error)
[docs] def append_html(self, html_content: str, add_spacing: bool = True): """ Append HTML content at end, scroll to bottom. Args: html_content: HTML string to append add_spacing: Whether to add blank line after """ cursor = self._text_edit.textCursor() cursor.movePosition(QTextCursor.MoveOperation.End) self._text_edit.setTextCursor(cursor) self._text_edit.insertHtml(html_content) if add_spacing: self._text_edit.insertHtml("<br><br>") self._scroll_to_bottom()
[docs] def append_text(self, text: str, bold: bool = False, color: Optional[str] = None): """ Append plain text (escaped) with optional styling. Args: text: Plain text to append bold: Whether to make text bold color: Optional text color (hex) """ escaped = html.escape(text) if bold: escaped = f"<b>{escaped}</b>" if color: escaped = f"<span style='color: {color};'>{escaped}</span>" self.append_html(escaped)
[docs] def append_code(self, code: str, language: str = None): """ Append code block with border styling. Args: code: Code string to display language: Optional language hint (for future syntax highlighting) """ escaped = html.escape(code) html_block = f""" <pre style=" border: 1px solid {self._border_color}; padding: 8px; margin: 4px 0; font-family: 'Courier New', monospace; white-space: pre-wrap; word-wrap: break-word; ">{escaped}</pre> """ self.append_html(html_block, add_spacing=False)
[docs] def append_error(self, message: str): """Append error message in red.""" self.append_text(message, bold=True, color=self._error_color)
[docs] def append_success(self, message: str): """Append success message in green.""" self.append_text(message, bold=True, color=self._success_color)
[docs] def clear(self): """Clear all content.""" self._text_edit.clear()
def _scroll_to_bottom(self): """Scroll text edit to bottom.""" scrollbar = self._text_edit.verticalScrollBar() scrollbar.setValue(scrollbar.maximum())