diff --git a/gui/chatblockmodel.cpp b/gui/chatblockmodel.cpp index e9d9e61..de62ad6 100644 --- a/gui/chatblockmodel.cpp +++ b/gui/chatblockmodel.cpp @@ -106,80 +106,17 @@ QHash ChatBlockModel::roleNames() const void ChatBlockModel::setRawText(const QString &text) { if (text == m_rawText) return; - - // If text is just appended (common during streaming), only reparse from the last block - bool isAppend = text.startsWith(m_rawText) && !m_rawText.isEmpty(); m_rawText = text; - - if (isAppend && !m_allBlocks.isEmpty()) { - reparseIncremental(); - } else { - // Full reparse (session switch, initial load) - m_allBlocks.clear(); - m_lastBlockTextOffset = 0; - beginResetModel(); - m_blocks.clear(); - m_visibleStart = 0; - endResetModel(); - reparse(); - } + reparse(); emit rawTextChanged(); } static constexpr int INITIAL_BLOCKS = 20; static constexpr int LOAD_MORE_COUNT = 30; -void ChatBlockModel::reparseIncremental() -{ - // Fast path: just update the last block's content from the raw text tail. - // Only do a full reparse if a new block header appeared. - QString tail = m_rawText.mid(m_lastBlockTextOffset); - - // Check if a new block header appeared in the NEW portion (after old last-block content) - int oldLastBlockLen = m_allBlocks.isEmpty() ? 0 : m_allBlocks.last().content.size(); - // The header itself is at m_lastBlockTextOffset, content starts after it + newline - // Simple heuristic: if the tail contains another header pattern, do full reparse - static const QRegularExpression headerRe( - R"(^\[(user|assistant|reasoning|call|tool|error|info)(?::([^\]]*))\])", - QRegularExpression::MultilineOption); - auto it = headerRe.globalMatch(tail); - int headerCount = 0; - while (it.hasNext()) { it.next(); headerCount++; } - - if (headerCount > 1) { - // New block boundary appeared — fall back to full reparse - reparse(); - return; - } - - // Common case: just the last block grew. Update its content directly. - if (!m_allBlocks.isEmpty()) { - QList tailBlocks = parseBlocks(tail); - if (!tailBlocks.isEmpty()) { - m_allBlocks.last() = tailBlocks.last(); - } - } - - updateVisibleWindow(); -} - void ChatBlockModel::reparse() { m_allBlocks = parseBlocks(m_rawText); - // Track where the last block starts for future incremental parses - if (!m_allBlocks.isEmpty()) { - static const QRegularExpression headerRe( - R"(^\[(user|assistant|reasoning|call|tool|error|info)(?::([^\]]*))\])", - QRegularExpression::MultilineOption); - auto it = headerRe.globalMatch(m_rawText); - int lastPos = 0; - while (it.hasNext()) { - auto match = it.next(); - lastPos = match.capturedStart(); - } - m_lastBlockTextOffset = lastPos; - } - updateVisibleWindow(); } diff --git a/gui/chatblockmodel.h b/gui/chatblockmodel.h index 6f3db54..eb12690 100644 --- a/gui/chatblockmodel.h +++ b/gui/chatblockmodel.h @@ -74,7 +74,6 @@ signals: private: void reparse(); - void reparseIncremental(); void updateVisibleWindow(); QList parseBlocks(const QString &text) const; QVariantList parseSubBlocks(const QString &content) const; @@ -83,7 +82,6 @@ private: QList m_allBlocks; // all parsed blocks QList m_blocks; // visible window (tail of m_allBlocks) int m_visibleStart = 0; // index into m_allBlocks where visible window starts - int m_lastBlockTextOffset = 0; // char offset in m_rawText where last block starts mutable QHash m_highlightCache; };