diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 7ffc811cb3e..d4c79d833ec 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -289,9 +289,10 @@ public: ~OpenedDocument() { QObject::disconnect(contentsChangedConnection); + delete document; } QMetaObject::Connection contentsChangedConnection; - QString documentContents; + QTextDocument *document = nullptr; }; QMap 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 = connect(document, &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::Incremental) { // 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, // this will save a lot of TextDocumentContentChangeEvent elements in the data stream, // as otherwise we'd send tons of single-character changes. - const QString &text = document->textAt(position, charsAdded); auto &queue = d->m_documentsToUpdate[document]; bool append = true; if (!queue.isEmpty() && charsRemoved == 0) { @@ -1096,17 +1109,6 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document, } } 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; change.setRange(Range(cursor)); change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart()); @@ -1117,8 +1119,8 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document, d->m_documentsToUpdate[document] = { DidChangeTextDocumentParams::TextDocumentContentChangeEvent(document->plainText())}; } - d->m_openedDocument[document].documentContents = document->plainText(); } + cursor.insertText(text); ++d->m_documentVersions[document->filePath()]; using namespace TextEditor;