From e27653219b397c4fbae88ddcaf460efee55a2dea Mon Sep 17 00:00:00 2001 From: Adam Treat Date: Thu, 21 Dec 2023 13:59:33 -0500 Subject: [PATCH] Fix bugs with the context link text for localdocs to make the context links persistently work across application loads and fix scrolling bug with context links. Signed-off-by: Adam Treat --- gpt4all-chat/responsetext.cpp | 57 +++++++++++++++++++++++++++++------ gpt4all-chat/responsetext.h | 16 ++++++++++ 2 files changed, 64 insertions(+), 9 deletions(-) diff --git a/gpt4all-chat/responsetext.cpp b/gpt4all-chat/responsetext.cpp index 9bdc9a38..3e2f51f9 100644 --- a/gpt4all-chat/responsetext.cpp +++ b/gpt4all-chat/responsetext.cpp @@ -7,6 +7,7 @@ #include #include #include +#include enum Language { None, @@ -845,11 +846,36 @@ void SyntaxHighlighter::highlightBlock(const QString &text) } } +const int ContextLinkFormat = QTextFormat::UserObject + 1; +const int ContextLinkHref = QTextFormat::UserProperty + 1; +const int ContextLinkText = QTextFormat::UserProperty + 2; + +void ContextLinkInterface::drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, + int posInDocument, const QTextFormat &format) +{ + const QString &href = format.property(ContextLinkHref).toString(); + const QString &text = format.property(ContextLinkText).toString(); + painter->setFont(doc->defaultFont()); + painter->setPen(format.foreground().color()); + painter->drawText(rect.bottomLeft(), text); +} + +QSizeF ContextLinkInterface::intrinsicSize(QTextDocument *doc, int posInDocument, + const QTextFormat &format) +{ + const QString &href = format.property(ContextLinkHref).toString(); + const QString &text = format.property(ContextLinkText).toString(); + const QFontMetricsF metrics(doc->defaultFont()); + const QSizeF textSize = metrics.size(Qt::TextSingleLine, text); + return textSize; +} + ResponseText::ResponseText(QObject *parent) : QObject{parent} , m_textDocument(nullptr) , m_syntaxHighlighter(new SyntaxHighlighter(this)) , m_isProcessingText(false) + , m_contextLink(new ContextLinkInterface(this)) { } @@ -864,6 +890,7 @@ void ResponseText::setTextDocument(QQuickTextDocument* textDocument) disconnect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ResponseText::handleTextChanged); m_textDocument = textDocument; + m_textDocument->textDocument()->documentLayout()->registerHandler(ContextLinkFormat, m_contextLink); m_syntaxHighlighter->setDocument(m_textDocument->textDocument()); connect(m_textDocument->textDocument(), &QTextDocument::contentsChanged, this, &ResponseText::handleTextChanged); handleTextChanged(); @@ -871,10 +898,20 @@ void ResponseText::setTextDocument(QQuickTextDocument* textDocument) QString ResponseText::getLinkAtPosition(int position) const { - int i = 0; - for (const auto &link : m_links) { - if (position >= link.startPos && position < link.endPos) - return link.href; + QTextCursor cursor(m_textDocument->textDocument()); + cursor.setPosition(position); + QTextCharFormat format = cursor.charFormat(); + if (format.objectType() == ContextLinkFormat) { + QString href = format.property(ContextLinkHref).toString(); + if (!href.isEmpty()) + return href; + } + cursor.movePosition(QTextCursor::Right, QTextCursor::MoveAnchor); + format = cursor.charFormat(); + if (format.objectType() == ContextLinkFormat) { + QString href = format.property(ContextLinkHref).toString(); + if (!href.isEmpty()) + return href; } return QString(); } @@ -912,9 +949,6 @@ void ResponseText::handleContextLinks() { QTextDocument* doc = m_textDocument->textDocument(); QTextCursor cursor(doc); - QTextCharFormat linkFormat; - linkFormat.setForeground(m_linkColor); - linkFormat.setFontUnderline(true); // Regex for context links static const QRegularExpression reLink("\\[Context\\]\\((context://\\d+)\\)"); @@ -943,8 +977,13 @@ void ResponseText::handleContextLinks() cursor.setPosition(matchesLink.at(index).capturedStart()); cursor.setPosition(matchesLink.at(index).capturedEnd(), QTextCursor::KeepAnchor); cursor.removeSelectedText(); - cursor.setCharFormat(linkFormat); - cursor.insertText(newLinks.at(index).text); + QTextCharFormat objectFormat; + objectFormat.setForeground(m_linkColor); + objectFormat.setFontUnderline(true); + objectFormat.setProperty(ContextLinkHref, newLinks.at(index).href); + objectFormat.setProperty(ContextLinkText, newLinks.at(index).text); + objectFormat.setObjectType(ContextLinkFormat); + cursor.insertText(QString(QChar::ObjectReplacementCharacter), objectFormat); cursor.setCharFormat(QTextCharFormat()); } diff --git a/gpt4all-chat/responsetext.h b/gpt4all-chat/responsetext.h index a5588bd6..216fe3fd 100644 --- a/gpt4all-chat/responsetext.h +++ b/gpt4all-chat/responsetext.h @@ -6,6 +6,7 @@ #include #include #include +#include class SyntaxHighlighter : public QSyntaxHighlighter { Q_OBJECT @@ -28,6 +29,20 @@ struct CodeCopy { QString text; }; +class ContextLinkInterface : public QObject, public QTextObjectInterface +{ + Q_OBJECT + Q_INTERFACES(QTextObjectInterface) + +public: + explicit ContextLinkInterface(QObject *parent) : QObject(parent) {} + void drawObject(QPainter *painter, const QRectF &rect, QTextDocument *doc, int posInDocument, + const QTextFormat &format) override; + + QSizeF intrinsicSize(QTextDocument *doc, int posInDocument, const QTextFormat &format) override; +}; + + class ResponseText : public QObject { Q_OBJECT @@ -61,6 +76,7 @@ private: QColor m_linkColor; QColor m_headerColor; bool m_isProcessingText = false; + ContextLinkInterface *m_contextLink; }; #endif // RESPONSETEXT_H