From b6a7d93d0e8101c1ca338134646253946c21a5ce Mon Sep 17 00:00:00 2001 From: Levi Neely <141506390+lneely@users.noreply.github.com> Date: Sun, 9 Aug 2026 12:14:04 +0200 Subject: [PATCH] gui: fix prose-after-fence overwriting finalized code segment MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In incrementalAppend(), when a prose line follows a closed code fence, the code checked only whether the last segment was type Text (which code fences also are) and then tried to append. Since the finalized fence HTML ends in not , it fell into the 'shouldn't happen' branch and overwrote the segment with escapeForHtml(proseLines) — destroying the rendered tool output. Tool blocks are always shaped: ``` ``` so the trailing blank lines triggered this on every tool call, leaving only
\n
in renderedHtml. Fix: gate extension on the segment actually being an in-progress prose segment (trailing ). Otherwise start a new prose segment. Verified: tool blocks now render 'hi\nexit: 0', file_glob results, and syntax-highlighted diffs correctly. --- gui/chatblockmodel.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/gui/chatblockmodel.cpp b/gui/chatblockmodel.cpp index 69a46da..fc82600 100644 --- a/gui/chatblockmodel.cpp +++ b/gui/chatblockmodel.cpp @@ -538,20 +538,21 @@ void ChatBlockModel::incrementalAppend(int blockIndex, const QString &line) const QString defaultColor = getDefaultTextColor(); const QString escapedLine = line.toHtmlEscaped(); - if (!block.segments.isEmpty() && block.segments.last().type == BlockSegment::Text - && !rs.inFence) { - // Append to existing prose segment — strip closing , add newline + content + // Only extend the last segment if it is an in-progress prose segment + // (identified by its trailing ). A finalized code fence segment + // ends in and must not be overwritten. + bool canExtend = !block.segments.isEmpty() + && block.segments.last().type == BlockSegment::Text + && block.segments.last().html.endsWith(QStringLiteral("")); + + if (canExtend) { QString &segHtml = block.segments.last().html; - // Remove trailing to append - if (segHtml.endsWith(QStringLiteral(""))) { - segHtml.chop(6); - segHtml += '\n' + escapedLine + QStringLiteral(""); - } else { - // Shouldn't happen, but fall back to full rebuild - segHtml = escapeForHtml(rs.proseLines.join('\n')); - } + segHtml.chop(6); // remove trailing + segHtml += '\n' + escapedLine + QStringLiteral(""); } else { - // Start a new text segment + // Start a new prose segment + rs.proseLines.clear(); + rs.proseLines.append(line); BlockSegment seg; seg.type = BlockSegment::Text; seg.html = QStringLiteral("
")