2026-02-06 09:52:23 +08:00

84 lines
2.9 KiB
Python

from __future__ import annotations
from collections import deque
from typing import Iterable, List
from PySide6.QtGui import QColor, QFont, QTextCharFormat, QTextCursor, QTextOption
from PySide6.QtWidgets import QTextEdit
from ameba_control_panel.services.log_buffer import LogLine
class LogView(QTextEdit):
"""Fast-ish append-only log with selectable text and match highlighting."""
def __init__(self, max_items: int, parent=None) -> None:
super().__init__(parent)
self.setReadOnly(True)
self.setWordWrapMode(QTextOption.NoWrap)
self.setLineWrapMode(QTextEdit.NoWrap)
self.setHorizontalScrollBarPolicy(self.horizontalScrollBarPolicy())
font = QFont("JetBrains Mono")
font.setStyleHint(QFont.Monospace)
font.setPointSize(10)
self.setFont(font)
self._max_items = max_items
self._lines = deque()
self._colors = {
"rx": QColor("#1b5e20"),
"tx": QColor("#0d47a1"),
"info": QColor("#424242"),
}
self._match_rows: List[int] = []
def set_colors(self, rx: str, tx: str, info: str) -> None:
self._colors = {"rx": QColor(rx), "tx": QColor(tx), "info": QColor(info)}
def append_lines(self, lines: Iterable[LogLine]) -> None:
cursor = self.textCursor()
cursor.movePosition(QTextCursor.End)
doc = self.document()
for line in lines:
self._lines.append(line)
fmt = QTextCharFormat()
fmt.setForeground(self._colors.get(line.direction, self._colors["info"]))
cursor.insertText(line.as_display(), fmt)
cursor.insertBlock()
self.setTextCursor(cursor)
# Trim overflow blocks and mirror deque
while len(self._lines) > self._max_items and doc.blockCount() > 0:
self._lines.popleft()
block = doc.firstBlock()
cur = QTextCursor(block)
cur.select(QTextCursor.BlockUnderCursor)
cur.removeSelectedText()
cur.deleteChar()
self._apply_matches()
self.verticalScrollBar().setValue(self.verticalScrollBar().maximum())
def clear_log(self) -> None:
self._lines.clear()
self.clear()
self._match_rows = []
def set_matches(self, rows: List[int]) -> None:
self._match_rows = rows
self._apply_matches()
def _apply_matches(self) -> None:
extra = []
doc = self.document()
for row in self._match_rows:
block = doc.findBlockByNumber(row)
if not block.isValid():
continue
cursor = QTextCursor(block)
sel = QTextEdit.ExtraSelection()
sel.cursor = cursor
sel.format.setBackground(QColor("#fff59d"))
extra.append(sel)
self.setExtraSelections(extra)
def copy_selected(self) -> None:
self.copy()