qml: fix hang in ChatView by processing text explicitly (#2543)

Fixes #2519

Signed-off-by: Adam Treat <treat.adam@gmail.com>
Signed-off-by: Jared Van Bortel <jared@nomic.ai>
Co-authored-by: Jared Van Bortel <jared@nomic.ai>
This commit is contained in:
AT 2024-07-08 17:24:02 -04:00 committed by GitHub
parent 64359e68e6
commit c11e0f4a98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 26 additions and 27 deletions

View File

@ -188,11 +188,6 @@ public:
}
}
Q_INVOKABLE void forceUpdate(int index)
{
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {ValueRole});
}
Q_INVOKABLE void updateValue(int index, const QString &value)
{
if (index < 0 || index >= m_chatItems.size()) return;
@ -201,6 +196,7 @@ public:
if (item.value != value) {
item.value = value;
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {ValueRole});
emit valueChanged(index, value);
}
}
@ -468,6 +464,7 @@ public:
Q_SIGNALS:
void countChanged();
void valueChanged(int index, const QString &value);
private:

View File

@ -771,9 +771,8 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
// chat class to populate the clipboard.
ChatViewTextProcessor::ChatViewTextProcessor(QObject *parent)
: QObject{parent}
, m_textDocument(nullptr)
, m_quickTextDocument(nullptr)
, m_syntaxHighlighter(new SyntaxHighlighter(this))
, m_isProcessingText(false)
, m_shouldProcessText(true)
, m_fontPixelSize(QGuiApplication::font().pointSizeF())
{
@ -781,17 +780,19 @@ ChatViewTextProcessor::ChatViewTextProcessor(QObject *parent)
QQuickTextDocument* ChatViewTextProcessor::textDocument() const
{
return m_textDocument;
return m_quickTextDocument;
}
void ChatViewTextProcessor::setTextDocument(QQuickTextDocument* textDocument)
void ChatViewTextProcessor::setTextDocument(QQuickTextDocument* quickTextDocument)
{
if (m_textDocument)
disconnect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ChatViewTextProcessor::handleTextChanged);
m_quickTextDocument = quickTextDocument;
m_syntaxHighlighter->setDocument(m_quickTextDocument->textDocument());
handleTextChanged();
}
m_textDocument = textDocument;
m_syntaxHighlighter->setDocument(m_textDocument->textDocument());
connect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ChatViewTextProcessor::handleTextChanged);
void ChatViewTextProcessor::setValue(const QString &value)
{
m_quickTextDocument->textDocument()->setPlainText(value);
handleTextChanged();
}
@ -881,14 +882,12 @@ void traverseDocument(QTextDocument *doc, QTextFrame *frame)
void ChatViewTextProcessor::handleTextChanged()
{
if (!m_textDocument || m_isProcessingText || !m_shouldProcessText)
if (!m_quickTextDocument || !m_shouldProcessText)
return;
m_isProcessingText = true;
// Force full layout of the text document to work around a bug in Qt
// TODO(jared): report the Qt bug and link to the report here
QTextDocument* doc = m_textDocument->textDocument();
QTextDocument* doc = m_quickTextDocument->textDocument();
(void)doc->documentLayout()->documentSize();
handleCodeBlocks();
@ -899,12 +898,11 @@ void ChatViewTextProcessor::handleTextChanged()
QTextCursor cursor(doc);
QString invisibleCharacter = QString(QChar(0xFEFF));
cursor.insertText(invisibleCharacter, QTextCharFormat());
m_isProcessingText = false;
}
void ChatViewTextProcessor::handleCodeBlocks()
{
QTextDocument* doc = m_textDocument->textDocument();
QTextDocument* doc = m_quickTextDocument->textDocument();
QTextCursor cursor(doc);
QTextCharFormat textFormat;
@ -1081,7 +1079,7 @@ void replaceAndInsertMarkdown(int startIndex, int endIndex, QTextDocument *doc)
void ChatViewTextProcessor::handleMarkdown()
{
QTextDocument* doc = m_textDocument->textDocument();
QTextDocument* doc = m_quickTextDocument->textDocument();
QTextCursor cursor(doc);
QVector<QPair<int, int>> codeBlockPositions;

View File

@ -96,6 +96,7 @@ public:
QQuickTextDocument* textDocument() const;
void setTextDocument(QQuickTextDocument* textDocument);
Q_INVOKABLE void setValue(const QString &value);
Q_INVOKABLE bool tryCopyAtPosition(int position) const;
bool shouldProcessText() const;
@ -119,12 +120,11 @@ private Q_SLOTS:
void handleMarkdown();
private:
QQuickTextDocument *m_textDocument;
QQuickTextDocument *m_quickTextDocument;
SyntaxHighlighter *m_syntaxHighlighter;
QVector<ContextLink> m_links;
QVector<CodeCopy> m_copies;
bool m_shouldProcessText = false;
bool m_isProcessingText = false;
qreal m_fontPixelSize;
};

View File

@ -879,7 +879,6 @@ Rectangle {
Layout.fillWidth: true
TextArea {
id: myTextArea
text: value
Layout.fillWidth: true
padding: 0
color: {
@ -953,7 +952,7 @@ Rectangle {
height: enabled ? implicitHeight : 0
onTriggered: {
textProcessor.shouldProcessText = !textProcessor.shouldProcessText;
myTextArea.text = value
textProcessor.setValue(value);
}
}
}
@ -974,11 +973,16 @@ Rectangle {
textProcessor.codeColors.headerColor = theme.codeHeaderColor
textProcessor.codeColors.backgroundColor = theme.codeBackgroundColor
textProcessor.textDocument = textDocument
chatModel.forceUpdate(index); // called to trigger a reprocessing of the text
textProcessor.setValue(value);
}
Component.onCompleted: {
resetChatViewTextProcessor();
chatModel.valueChanged.connect(function(i, value) {
if (index === i)
textProcessor.setValue(value);
}
);
}
Connections {

View File

@ -272,7 +272,7 @@ Rectangle {
color: theme.conversationBackground
width: subscribeLink.width
RowLayout {
anchors.fill: parent
anchors.centerIn: parent
MyFancyLink {
id: subscribeLink
Layout.alignment: Qt.AlignCenter