move call/tool formatting entirely to C++ via formattedContent role

QML scope issues made JS-based formatting unreliable. New approach:
- FormattedContentRole in the model computes pretty-printed HTML in C++
- Call blocks: always prettyJson()
- Tool blocks: detect JSON/diff and format, otherwise escaped HTML
- QML just binds text: block.formattedContent || ""
This commit is contained in:
Levi Neely 2026-07-16 07:07:51 +02:00
parent 7cd46337a3
commit 93c9bd995e
3 changed files with 23 additions and 12 deletions

View File

@ -61,6 +61,25 @@ QVariant ChatBlockModel::data(const QModelIndex &index, int role) const
block.cachedContent = block.content;
}
return block.cachedSubBlocks;
case FormattedContentRole: {
// For call blocks: always pretty-print JSON
// For tool blocks: detect JSON/diff, format accordingly
// For others: just escape HTML
QString content = block.content;
if (content.isEmpty()) return QString();
if (block.type == ChatBlock::Call) {
return prettyJson(content);
}
QString trimmed = content.trimmed();
if (trimmed.startsWith('{') || trimmed.startsWith('[')) {
return prettyJson(content);
}
if (trimmed.startsWith(QLatin1String("---")) || trimmed.startsWith(QLatin1String("diff "))) {
return highlightedHtml(content, QStringLiteral("Diff"));
}
// Plain text: escape and add line breaks
return content.toHtmlEscaped().replace('\n', QLatin1String("<br>"));
}
}
return {};
}
@ -72,6 +91,7 @@ QHash<int, QByteArray> ChatBlockModel::roleNames() const
{NameRole, "blockName"},
{ContentRole, "blockContent"},
{SubBlocksRole, "subBlocks"},
{FormattedContentRole, "formattedContent"},
};
}

View File

@ -48,6 +48,7 @@ public:
NameRole,
ContentRole,
SubBlocksRole, // QVariantList of sub-block maps
FormattedContentRole, // pre-formatted HTML for call/tool expanded view
};
explicit ChatBlockModel(QObject *parent = nullptr);

View File

@ -624,7 +624,7 @@ ApplicationWindow {
Text {
id: callText
Layout.fillWidth: true
text: visible ? chatModel.prettyJson(String(block.blockContent || "")) : ""
text: block.formattedContent || ""
textFormat: Text.RichText
wrapMode: Text.Wrap
font.family: "monospace"
@ -653,17 +653,7 @@ ApplicationWindow {
Text {
id: toolText
Layout.fillWidth: true
text: {
if (!visible) return ""
let content = String(block.blockContent || "")
if (!content) return ""
let trimmed = content.trim()
if (trimmed.charAt(0) === '{' || trimmed.charAt(0) === '[')
return chatModel.prettyJson(content)
if (trimmed.indexOf("---") === 0 || trimmed.indexOf("diff ") === 0)
return chatModel.highlightedHtml(content, "diff")
return content.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\n/g, '<br>')
}
text: block.formattedContent || ""
textFormat: Text.RichText
wrapMode: Text.Wrap
font.family: "monospace"