From 6118463d39dd34a4e1e71446a5a37e2d8dd7ac50 Mon Sep 17 00:00:00 2001 From: Alexis Murzeau Date: Sun, 26 Apr 2020 22:35:26 +0200 Subject: [PATCH] LSP: Fix language server desynchronisation when whole file contents change When the whole file contents are changed, for example because of changing the highlight definition when there is several candidates, the language server will behave as if the file's content was the result of concatenating two times the file's content (leading to duplicate declarations errors for C++). The issue is that when this happens, the didChange message indicate only the added portion of the change without the removal of the whole file beforehand (ie: the range is empty and the text is the whole file content). This is because charRemoved and charAdded are equal to the length of the document which is not exactly the number of /visibles/ characters, but also including some invisible formating characters according to QTBUG-80662. This causes the QTextCursor to ignore the second setPosition because of invalid position out of range. Fix this using the same code as QWidgetTextControlPrivate::_q_contentsChanged that is to use qMin to ensure the end position is not after the end of the document according to QTextCursor. For charsAdded, document->textAt takes care of that itself, via Utils::Text::textAt. See also: QTBUG-32583, QTBUG-80662 Change-Id: If781707d42253f4659005754efa73d872577f738 Reviewed-by: David Schulz --- src/plugins/languageclient/client.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index e3b8adc6d58..6ee1e58a060 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -506,7 +506,14 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document, DidChangeTextDocumentParams::TextDocumentContentChangeEvent change; QTextDocument oldDoc(m_openedDocument[document]); QTextCursor cursor(&oldDoc); - cursor.setPosition(position + charsRemoved); + // 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); change.setRange(Range(cursor)); change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart());