LanguageClient: avoid creating a QTextDocument for every contents change

clone the document when it is opened and adjust it after each contents
change

Change-Id: I4fd511a3b142b1875f1da7d241ab5cddf49322e8
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
David Schulz
2022-08-18 14:51:16 +02:00
parent 825b781a07
commit 8031460734

View File

@@ -289,9 +289,10 @@ public:
~OpenedDocument() ~OpenedDocument()
{ {
QObject::disconnect(contentsChangedConnection); QObject::disconnect(contentsChangedConnection);
delete document;
} }
QMetaObject::Connection contentsChangedConnection; QMetaObject::Connection contentsChangedConnection;
QString documentContents; QTextDocument *document = nullptr;
}; };
QMap<TextEditor::TextDocument *, OpenedDocument> m_openedDocument; QMap<TextEditor::TextDocument *, OpenedDocument> m_openedDocument;
@@ -628,7 +629,7 @@ void Client::openDocument(TextEditor::TextDocument *document)
} }
} }
d->m_openedDocument[document].documentContents = document->plainText(); d->m_openedDocument[document].document = document->document()->clone(this);
d->m_openedDocument[document].contentsChangedConnection d->m_openedDocument[document].contentsChangedConnection
= connect(document, = connect(document,
&TextDocument::contentsChangedWithPosition, &TextDocument::contentsChangedWithPosition,
@@ -1076,6 +1077,19 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
} }
} }
const QString &text = document->textAt(position, charsAdded);
QTextCursor cursor(d->m_openedDocument[document].document);
// Workaround https://bugreports.qt.io/browse/QTBUG-80662
// The contentsChanged gives a character count that can be wrong for QTextCursor
// when there are special characters removed/added (like formating characters).
// Also, characterCount return the number of characters + 1 because of the hidden
// paragraph separator character.
// This implementation is based on QWidgetTextControlPrivate::_q_contentsChanged.
// For charsAdded, textAt handles the case itself.
cursor.setPosition(qMin(d->m_openedDocument[document].document->characterCount() - 1,
position + charsRemoved));
cursor.setPosition(position, QTextCursor::KeepAnchor);
if (syncKind != TextDocumentSyncKind::None) { if (syncKind != TextDocumentSyncKind::None) {
if (syncKind == TextDocumentSyncKind::Incremental) { if (syncKind == TextDocumentSyncKind::Incremental) {
// If the new change is a pure insertion and its range is adjacent to the range of the // If the new change is a pure insertion and its range is adjacent to the range of the
@@ -1083,7 +1097,6 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
// For the typical case of the user typing a continuous sequence of characters, // For the typical case of the user typing a continuous sequence of characters,
// this will save a lot of TextDocumentContentChangeEvent elements in the data stream, // this will save a lot of TextDocumentContentChangeEvent elements in the data stream,
// as otherwise we'd send tons of single-character changes. // as otherwise we'd send tons of single-character changes.
const QString &text = document->textAt(position, charsAdded);
auto &queue = d->m_documentsToUpdate[document]; auto &queue = d->m_documentsToUpdate[document];
bool append = true; bool append = true;
if (!queue.isEmpty() && charsRemoved == 0) { if (!queue.isEmpty() && charsRemoved == 0) {
@@ -1096,17 +1109,6 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
} }
} }
if (append) { if (append) {
QTextDocument oldDoc(d->m_openedDocument[document].documentContents);
QTextCursor cursor(&oldDoc);
// Workaround https://bugreports.qt.io/browse/QTBUG-80662
// The contentsChanged gives a character count that can be wrong for QTextCursor
// when there are special characters removed/added (like formating characters).
// Also, characterCount return the number of characters + 1 because of the hidden
// paragraph separator character.
// This implementation is based on QWidgetTextControlPrivate::_q_contentsChanged.
// For charsAdded, textAt handles the case itself.
cursor.setPosition(qMin(oldDoc.characterCount() - 1, position + charsRemoved));
cursor.setPosition(position, QTextCursor::KeepAnchor);
DidChangeTextDocumentParams::TextDocumentContentChangeEvent change; DidChangeTextDocumentParams::TextDocumentContentChangeEvent change;
change.setRange(Range(cursor)); change.setRange(Range(cursor));
change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart()); change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart());
@@ -1117,8 +1119,8 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
d->m_documentsToUpdate[document] = { d->m_documentsToUpdate[document] = {
DidChangeTextDocumentParams::TextDocumentContentChangeEvent(document->plainText())}; DidChangeTextDocumentParams::TextDocumentContentChangeEvent(document->plainText())};
} }
d->m_openedDocument[document].documentContents = document->plainText();
} }
cursor.insertText(text);
++d->m_documentVersions[document->filePath()]; ++d->m_documentVersions[document->filePath()];
using namespace TextEditor; using namespace TextEditor;