From 4a271ac4d81affe5897e178494401c1fba1c257b Mon Sep 17 00:00:00 2001 From: Makesesama Date: Mon, 4 May 2026 23:05:23 +0200 Subject: [PATCH] feat: notification markup support --- sims/utils/markup.py | 28 ++++++++++++++++++++++ sims/widgets/notification.py | 6 ++++- sims/widgets/notification_history_entry.py | 5 +++- 3 files changed, 37 insertions(+), 2 deletions(-) create mode 100644 sims/utils/markup.py diff --git a/sims/utils/markup.py b/sims/utils/markup.py new file mode 100644 index 0000000..e9edc8d --- /dev/null +++ b/sims/utils/markup.py @@ -0,0 +1,28 @@ +import re +from html import escape as html_escape + +import gi + +gi.require_version("Pango", "1.0") +from gi.repository import GLib, Pango + +# Pango cannot render from the freedesktop notification spec; strip it. +_IMG_RE = re.compile(r"]*/?>", re.IGNORECASE) + + +def render_body_markup(body: str) -> tuple[str, bool]: + """Return ``(text, is_markup)`` for a notification body. + + If the body parses as Pango markup, ``text`` is the cleaned-up markup + string and ``is_markup`` is True. Otherwise ``text`` is the XML-escaped + plain text and ``is_markup`` is False. + """ + if not body: + return "", False + + candidate = _IMG_RE.sub("", body) + try: + Pango.parse_markup(candidate, -1, "\0") + except GLib.Error: + return html_escape(body, quote=False), False + return candidate, True diff --git a/sims/widgets/notification.py b/sims/widgets/notification.py index be2b90e..5fcc888 100644 --- a/sims/widgets/notification.py +++ b/sims/widgets/notification.py @@ -6,6 +6,8 @@ from fabric.widgets.image import Image from fabric.widgets.label import Label from gi.repository import GdkPixbuf +from sims.utils.markup import render_body_markup + NOTIFICATION_IMAGE_SIZE = 64 @@ -76,9 +78,11 @@ class NotificationWidget(Box): ) if body: + body_text, body_is_markup = render_body_markup(body) + body_kwargs = {"markup": body_text} if body_is_markup else {"label": body_text} text_children.append( Label( - label=body, + **body_kwargs, line_wrap="word-char", v_align="start", h_align="start", diff --git a/sims/widgets/notification_history_entry.py b/sims/widgets/notification_history_entry.py index 7ce475a..f24ace0 100644 --- a/sims/widgets/notification_history_entry.py +++ b/sims/widgets/notification_history_entry.py @@ -7,6 +7,7 @@ from fabric.widgets.image import Image from fabric.widgets.label import Label from sims.services.notification_history import HistoryEntry +from sims.utils.markup import render_body_markup def _time_ago(ts: float, now: float | None = None) -> str: @@ -71,9 +72,11 @@ class NotificationHistoryEntryWidget(Box): text_children.append(header) if entry.body: + body_text, body_is_markup = render_body_markup(entry.body) + body_kwargs = {"markup": body_text} if body_is_markup else {"label": body_text} text_children.append( Label( - label=entry.body, + **body_kwargs, line_wrap="word-char", h_align="start", v_align="start",