mirror of
https://github.com/nomic-ai/gpt4all.git
synced 2025-08-10 20:31:46 +00:00
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:
parent
64359e68e6
commit
c11e0f4a98
@ -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)
|
Q_INVOKABLE void updateValue(int index, const QString &value)
|
||||||
{
|
{
|
||||||
if (index < 0 || index >= m_chatItems.size()) return;
|
if (index < 0 || index >= m_chatItems.size()) return;
|
||||||
@ -201,6 +196,7 @@ public:
|
|||||||
if (item.value != value) {
|
if (item.value != value) {
|
||||||
item.value = value;
|
item.value = value;
|
||||||
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {ValueRole});
|
emit dataChanged(createIndex(index, 0), createIndex(index, 0), {ValueRole});
|
||||||
|
emit valueChanged(index, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,6 +464,7 @@ public:
|
|||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void countChanged();
|
void countChanged();
|
||||||
|
void valueChanged(int index, const QString &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -771,9 +771,8 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
|
|||||||
// chat class to populate the clipboard.
|
// chat class to populate the clipboard.
|
||||||
ChatViewTextProcessor::ChatViewTextProcessor(QObject *parent)
|
ChatViewTextProcessor::ChatViewTextProcessor(QObject *parent)
|
||||||
: QObject{parent}
|
: QObject{parent}
|
||||||
, m_textDocument(nullptr)
|
, m_quickTextDocument(nullptr)
|
||||||
, m_syntaxHighlighter(new SyntaxHighlighter(this))
|
, m_syntaxHighlighter(new SyntaxHighlighter(this))
|
||||||
, m_isProcessingText(false)
|
|
||||||
, m_shouldProcessText(true)
|
, m_shouldProcessText(true)
|
||||||
, m_fontPixelSize(QGuiApplication::font().pointSizeF())
|
, m_fontPixelSize(QGuiApplication::font().pointSizeF())
|
||||||
{
|
{
|
||||||
@ -781,17 +780,19 @@ ChatViewTextProcessor::ChatViewTextProcessor(QObject *parent)
|
|||||||
|
|
||||||
QQuickTextDocument* ChatViewTextProcessor::textDocument() const
|
QQuickTextDocument* ChatViewTextProcessor::textDocument() const
|
||||||
{
|
{
|
||||||
return m_textDocument;
|
return m_quickTextDocument;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatViewTextProcessor::setTextDocument(QQuickTextDocument* textDocument)
|
void ChatViewTextProcessor::setTextDocument(QQuickTextDocument* quickTextDocument)
|
||||||
{
|
{
|
||||||
if (m_textDocument)
|
m_quickTextDocument = quickTextDocument;
|
||||||
disconnect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ChatViewTextProcessor::handleTextChanged);
|
m_syntaxHighlighter->setDocument(m_quickTextDocument->textDocument());
|
||||||
|
handleTextChanged();
|
||||||
|
}
|
||||||
|
|
||||||
m_textDocument = textDocument;
|
void ChatViewTextProcessor::setValue(const QString &value)
|
||||||
m_syntaxHighlighter->setDocument(m_textDocument->textDocument());
|
{
|
||||||
connect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ChatViewTextProcessor::handleTextChanged);
|
m_quickTextDocument->textDocument()->setPlainText(value);
|
||||||
handleTextChanged();
|
handleTextChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -881,14 +882,12 @@ void traverseDocument(QTextDocument *doc, QTextFrame *frame)
|
|||||||
|
|
||||||
void ChatViewTextProcessor::handleTextChanged()
|
void ChatViewTextProcessor::handleTextChanged()
|
||||||
{
|
{
|
||||||
if (!m_textDocument || m_isProcessingText || !m_shouldProcessText)
|
if (!m_quickTextDocument || !m_shouldProcessText)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_isProcessingText = true;
|
|
||||||
|
|
||||||
// Force full layout of the text document to work around a bug in Qt
|
// 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
|
// 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();
|
(void)doc->documentLayout()->documentSize();
|
||||||
|
|
||||||
handleCodeBlocks();
|
handleCodeBlocks();
|
||||||
@ -899,12 +898,11 @@ void ChatViewTextProcessor::handleTextChanged()
|
|||||||
QTextCursor cursor(doc);
|
QTextCursor cursor(doc);
|
||||||
QString invisibleCharacter = QString(QChar(0xFEFF));
|
QString invisibleCharacter = QString(QChar(0xFEFF));
|
||||||
cursor.insertText(invisibleCharacter, QTextCharFormat());
|
cursor.insertText(invisibleCharacter, QTextCharFormat());
|
||||||
m_isProcessingText = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChatViewTextProcessor::handleCodeBlocks()
|
void ChatViewTextProcessor::handleCodeBlocks()
|
||||||
{
|
{
|
||||||
QTextDocument* doc = m_textDocument->textDocument();
|
QTextDocument* doc = m_quickTextDocument->textDocument();
|
||||||
QTextCursor cursor(doc);
|
QTextCursor cursor(doc);
|
||||||
|
|
||||||
QTextCharFormat textFormat;
|
QTextCharFormat textFormat;
|
||||||
@ -1081,7 +1079,7 @@ void replaceAndInsertMarkdown(int startIndex, int endIndex, QTextDocument *doc)
|
|||||||
|
|
||||||
void ChatViewTextProcessor::handleMarkdown()
|
void ChatViewTextProcessor::handleMarkdown()
|
||||||
{
|
{
|
||||||
QTextDocument* doc = m_textDocument->textDocument();
|
QTextDocument* doc = m_quickTextDocument->textDocument();
|
||||||
QTextCursor cursor(doc);
|
QTextCursor cursor(doc);
|
||||||
|
|
||||||
QVector<QPair<int, int>> codeBlockPositions;
|
QVector<QPair<int, int>> codeBlockPositions;
|
||||||
|
@ -96,6 +96,7 @@ public:
|
|||||||
QQuickTextDocument* textDocument() const;
|
QQuickTextDocument* textDocument() const;
|
||||||
void setTextDocument(QQuickTextDocument* textDocument);
|
void setTextDocument(QQuickTextDocument* textDocument);
|
||||||
|
|
||||||
|
Q_INVOKABLE void setValue(const QString &value);
|
||||||
Q_INVOKABLE bool tryCopyAtPosition(int position) const;
|
Q_INVOKABLE bool tryCopyAtPosition(int position) const;
|
||||||
|
|
||||||
bool shouldProcessText() const;
|
bool shouldProcessText() const;
|
||||||
@ -119,12 +120,11 @@ private Q_SLOTS:
|
|||||||
void handleMarkdown();
|
void handleMarkdown();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QQuickTextDocument *m_textDocument;
|
QQuickTextDocument *m_quickTextDocument;
|
||||||
SyntaxHighlighter *m_syntaxHighlighter;
|
SyntaxHighlighter *m_syntaxHighlighter;
|
||||||
QVector<ContextLink> m_links;
|
QVector<ContextLink> m_links;
|
||||||
QVector<CodeCopy> m_copies;
|
QVector<CodeCopy> m_copies;
|
||||||
bool m_shouldProcessText = false;
|
bool m_shouldProcessText = false;
|
||||||
bool m_isProcessingText = false;
|
|
||||||
qreal m_fontPixelSize;
|
qreal m_fontPixelSize;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -879,7 +879,6 @@ Rectangle {
|
|||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
TextArea {
|
TextArea {
|
||||||
id: myTextArea
|
id: myTextArea
|
||||||
text: value
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
padding: 0
|
padding: 0
|
||||||
color: {
|
color: {
|
||||||
@ -953,7 +952,7 @@ Rectangle {
|
|||||||
height: enabled ? implicitHeight : 0
|
height: enabled ? implicitHeight : 0
|
||||||
onTriggered: {
|
onTriggered: {
|
||||||
textProcessor.shouldProcessText = !textProcessor.shouldProcessText;
|
textProcessor.shouldProcessText = !textProcessor.shouldProcessText;
|
||||||
myTextArea.text = value
|
textProcessor.setValue(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -974,11 +973,16 @@ Rectangle {
|
|||||||
textProcessor.codeColors.headerColor = theme.codeHeaderColor
|
textProcessor.codeColors.headerColor = theme.codeHeaderColor
|
||||||
textProcessor.codeColors.backgroundColor = theme.codeBackgroundColor
|
textProcessor.codeColors.backgroundColor = theme.codeBackgroundColor
|
||||||
textProcessor.textDocument = textDocument
|
textProcessor.textDocument = textDocument
|
||||||
chatModel.forceUpdate(index); // called to trigger a reprocessing of the text
|
textProcessor.setValue(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
resetChatViewTextProcessor();
|
resetChatViewTextProcessor();
|
||||||
|
chatModel.valueChanged.connect(function(i, value) {
|
||||||
|
if (index === i)
|
||||||
|
textProcessor.setValue(value);
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
@ -272,7 +272,7 @@ Rectangle {
|
|||||||
color: theme.conversationBackground
|
color: theme.conversationBackground
|
||||||
width: subscribeLink.width
|
width: subscribeLink.width
|
||||||
RowLayout {
|
RowLayout {
|
||||||
anchors.fill: parent
|
anchors.centerIn: parent
|
||||||
MyFancyLink {
|
MyFancyLink {
|
||||||
id: subscribeLink
|
id: subscribeLink
|
||||||
Layout.alignment: Qt.AlignCenter
|
Layout.alignment: Qt.AlignCenter
|
||||||
|
Loading…
Reference in New Issue
Block a user