render system-user-interruption as a styled yellow box with warning icon
This commit is contained in:
parent
cf4313165b
commit
1fdae741c3
|
|
@ -193,18 +193,35 @@ QString ChatBlockModel::highlightCode(const QString &code, const QString &langua
|
||||||
|
|
||||||
QString ChatBlockModel::renderMarkdown(const QString &markdown) const
|
QString ChatBlockModel::renderMarkdown(const QString &markdown) const
|
||||||
{
|
{
|
||||||
|
// Pre-process: render <system-user-interruption> blocks as styled boxes.
|
||||||
|
static const QRegularExpression interruptionRe(
|
||||||
|
R"(<system-user-interruption>\n([\s\S]*?)\n</system-user-interruption>)");
|
||||||
|
QString processed = markdown;
|
||||||
|
processed.replace(interruptionRe, [](const QString &match) -> QString {
|
||||||
|
// Extract content between the tags (after opening "<system-user-interruption>\n"
|
||||||
|
// and before trailing "\n</system-user-interruption>").
|
||||||
|
const int start = QStringLiteral("<system-user-interruption>\n").size();
|
||||||
|
const int end = match.size() - QStringLiteral("\n</system-user-interruption>").size();
|
||||||
|
const QString content = match.mid(start, end - start).toHtmlEscaped();
|
||||||
|
return QStringLiteral(
|
||||||
|
"<div style=\"background:#fff8e1;border:1px solid #ffca28;"
|
||||||
|
"border-radius:4px;padding:8px;margin:8px 0;white-space:pre-wrap;\">"
|
||||||
|
"\u26A0\uFE0F <strong>User interruption</strong>\n") + content +
|
||||||
|
QStringLiteral("</div>");
|
||||||
|
});
|
||||||
|
|
||||||
static const QRegularExpression fenceRe(
|
static const QRegularExpression fenceRe(
|
||||||
R"(```([A-Za-z0-9_+.-]*)[^\n]*\n([\s\S]*?)\n```(\n|$))");
|
R"(```([A-Za-z0-9_+.-]*)[^\n]*\n([\s\S]*?)\n```(\n|$))");
|
||||||
|
|
||||||
QString result;
|
QString result;
|
||||||
int cursor = 0;
|
int cursor = 0;
|
||||||
auto it = fenceRe.globalMatch(markdown);
|
auto it = fenceRe.globalMatch(processed);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
const auto match = it.next();
|
const auto match = it.next();
|
||||||
// Prose before this fence: HTML-escape and wrap in pre-wrap div to
|
// Prose before this fence: HTML-escape and wrap in pre-wrap div to
|
||||||
// preserve newlines and whitespace. QTextDocument::setMarkdown would
|
// preserve newlines and whitespace. QTextDocument::setMarkdown would
|
||||||
// collapse single newlines (standard Markdown behavior).
|
// collapse single newlines (standard Markdown behavior).
|
||||||
const QString prose = markdown.mid(cursor, match.capturedStart() - cursor);
|
const QString prose = processed.mid(cursor, match.capturedStart() - cursor);
|
||||||
if (!prose.isEmpty())
|
if (!prose.isEmpty())
|
||||||
result += QStringLiteral("<div style=\"white-space:pre-wrap\">")
|
result += QStringLiteral("<div style=\"white-space:pre-wrap\">")
|
||||||
+ prose.toHtmlEscaped() + QStringLiteral("</div>");
|
+ prose.toHtmlEscaped() + QStringLiteral("</div>");
|
||||||
|
|
@ -218,7 +235,7 @@ QString ChatBlockModel::renderMarkdown(const QString &markdown) const
|
||||||
static const QRegularExpression openFenceRe(
|
static const QRegularExpression openFenceRe(
|
||||||
R"(^```([A-Za-z0-9_+.-]*)[^\n]*\n([\s\S]*)$)",
|
R"(^```([A-Za-z0-9_+.-]*)[^\n]*\n([\s\S]*)$)",
|
||||||
QRegularExpression::MultilineOption);
|
QRegularExpression::MultilineOption);
|
||||||
const auto tail = markdown.mid(cursor);
|
const auto tail = processed.mid(cursor);
|
||||||
if (!tail.isEmpty()) {
|
if (!tail.isEmpty()) {
|
||||||
const auto open = openFenceRe.match(tail);
|
const auto open = openFenceRe.match(tail);
|
||||||
if (open.hasMatch()) {
|
if (open.hasMatch()) {
|
||||||
|
|
|
||||||
Reference in New Issue