84 lines
2.9 KiB
Python
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()
|