forked from qt-creator/qt-creator
LSP: Compress document change notifications
Change-Id: Iaf6cb99784f4e1ed1291ace1f4cc18cf6af88672 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -107,6 +107,10 @@ Client::Client(BaseClientInterface *clientInterface)
|
||||
m_clientProviders.functionHintProvider = new FunctionHintAssistProvider(this);
|
||||
m_clientProviders.quickFixAssistProvider = new LanguageClientQuickFixProvider(this);
|
||||
|
||||
m_documentUpdateTimer.setSingleShot(true);
|
||||
m_documentUpdateTimer.setInterval(500);
|
||||
connect(&m_documentUpdateTimer, &QTimer::timeout, this, &Client::sendPostponedDocumentUpdates);
|
||||
|
||||
m_contentHandler.insert(JsonRpcMessageHandler::jsonRpcMimeType(),
|
||||
&JsonRpcMessageHandler::parseContent);
|
||||
QTC_ASSERT(clientInterface, return);
|
||||
@@ -347,6 +351,7 @@ void Client::sendContent(const IContent &content)
|
||||
{
|
||||
QTC_ASSERT(m_clientInterface, return);
|
||||
QTC_ASSERT(m_state == Initialized, return);
|
||||
sendPostponedDocumentUpdates();
|
||||
content.registerResponseHandler(&m_responseHandlers);
|
||||
QString error;
|
||||
if (!QTC_GUARD(content.isValid(&error)))
|
||||
@@ -514,15 +519,8 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
|
||||
syncKind = option.isValid(nullptr) ? option.syncKind() : syncKind;
|
||||
}
|
||||
}
|
||||
auto textDocument = qobject_cast<TextEditor::TextDocument *>(document);
|
||||
|
||||
const auto uri = DocumentUri::fromFilePath(document->filePath());
|
||||
m_highlights[uri].clear();
|
||||
if (syncKind != TextDocumentSyncKind::None) {
|
||||
VersionedTextDocumentIdentifier docId(uri);
|
||||
docId.setVersion(textDocument ? textDocument->document()->revision() : 0);
|
||||
DidChangeTextDocumentParams params;
|
||||
params.setTextDocument(docId);
|
||||
if (syncKind == TextDocumentSyncKind::Incremental) {
|
||||
DidChangeTextDocumentParams::TextDocumentContentChangeEvent change;
|
||||
QTextDocument oldDoc(m_openedDocument[document]);
|
||||
@@ -539,20 +537,22 @@ void Client::documentContentsChanged(TextEditor::TextDocument *document,
|
||||
change.setRange(Range(cursor));
|
||||
change.setRangeLength(cursor.selectionEnd() - cursor.selectionStart());
|
||||
change.setText(document->textAt(position, charsAdded));
|
||||
params.setContentChanges({change});
|
||||
m_documentsToUpdate[document] << change;
|
||||
} else {
|
||||
params.setContentChanges({document->plainText()});
|
||||
m_documentsToUpdate[document] = {document->plainText()};
|
||||
}
|
||||
m_openedDocument[document] = document->plainText();
|
||||
sendContent(DidChangeTextDocumentNotification(params));
|
||||
}
|
||||
|
||||
if (textDocument) {
|
||||
using namespace TextEditor;
|
||||
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(textDocument))
|
||||
if (TextEditorWidget *widget = editor->editorWidget())
|
||||
widget->setRefactorMarkers(RefactorMarker::filterOutType(widget->refactorMarkers(), id()));
|
||||
using namespace TextEditor;
|
||||
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(document)) {
|
||||
if (TextEditorWidget *widget = editor->editorWidget()) {
|
||||
widget->setRefactorMarkers(
|
||||
RefactorMarker::filterOutType(widget->refactorMarkers(), id()));
|
||||
}
|
||||
}
|
||||
|
||||
m_documentUpdateTimer.start();
|
||||
}
|
||||
|
||||
void Client::registerCapabilities(const QList<Registration> ®istrations)
|
||||
@@ -578,6 +578,8 @@ TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation
|
||||
|
||||
void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget)
|
||||
{
|
||||
if (m_documentsToUpdate.contains(widget->textDocument()))
|
||||
return; // we are currently changing this document so postpone the DocumentHighlightsRequest
|
||||
const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath());
|
||||
if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) {
|
||||
TextDocumentRegistrationOptions option(
|
||||
@@ -1131,6 +1133,30 @@ void Client::resetAssistProviders(TextEditor::TextDocument *document)
|
||||
document->setQuickFixAssistProvider(providers.quickFixAssistProvider);
|
||||
}
|
||||
|
||||
void Client::sendPostponedDocumentUpdates()
|
||||
{
|
||||
m_documentUpdateTimer.stop();
|
||||
if (m_documentsToUpdate.isEmpty())
|
||||
return;
|
||||
TextEditor::TextEditorWidget *currentWidget
|
||||
= TextEditor::TextEditorWidget::currentTextEditorWidget();
|
||||
const QList<TextEditor::TextDocument *> documents = m_documentsToUpdate.keys();
|
||||
for (auto document : documents) {
|
||||
const auto uri = DocumentUri::fromFilePath(document->filePath());
|
||||
m_highlights[uri].clear();
|
||||
VersionedTextDocumentIdentifier docId(uri);
|
||||
docId.setVersion(document->document()->revision());
|
||||
DidChangeTextDocumentParams params;
|
||||
params.setTextDocument(docId);
|
||||
params.setContentChanges(m_documentsToUpdate.take(document));
|
||||
sendContent(DidChangeTextDocumentNotification(params));
|
||||
emit documentUpdated(document);
|
||||
|
||||
if (currentWidget->textDocument() == document)
|
||||
cursorPositionChanged(currentWidget);
|
||||
}
|
||||
}
|
||||
|
||||
void Client::handleResponse(const MessageId &id, const QByteArray &content, QTextCodec *codec)
|
||||
{
|
||||
if (auto handler = m_responseHandlers[id])
|
||||
@@ -1283,6 +1309,13 @@ void Client::rehighlight()
|
||||
}
|
||||
}
|
||||
|
||||
bool Client::documentUpdatePostponed(const QString &fileName) const
|
||||
{
|
||||
return Utils::contains(m_documentsToUpdate.keys(), [fileName](const TextEditor::TextDocument *doc) {
|
||||
return doc->filePath() == Utils::FilePath::fromString(fileName);
|
||||
});
|
||||
}
|
||||
|
||||
void Client::initializeCallback(const InitializeRequest::Response &initResponse)
|
||||
{
|
||||
QTC_ASSERT(m_state == InitializeRequested, return);
|
||||
|
@@ -178,8 +178,11 @@ public:
|
||||
HoverHandler *hoverHandler();
|
||||
void rehighlight();
|
||||
|
||||
bool documentUpdatePostponed(const QString &fileName) const;
|
||||
|
||||
signals:
|
||||
void initialized(LanguageServerProtocol::ServerCapabilities capabilities);
|
||||
void documentUpdated(TextEditor::TextDocument *document);
|
||||
void finished();
|
||||
|
||||
protected:
|
||||
@@ -207,6 +210,7 @@ private:
|
||||
void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
|
||||
void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri);
|
||||
void resetAssistProviders(TextEditor::TextDocument *document);
|
||||
void sendPostponedDocumentUpdates();
|
||||
|
||||
using ContentHandler = std::function<void(const QByteArray &, QTextCodec *, QString &,
|
||||
LanguageServerProtocol::ResponseHandlers,
|
||||
@@ -219,6 +223,10 @@ private:
|
||||
LanguageFilter m_languagFilter;
|
||||
QJsonObject m_initializationOptions;
|
||||
QMap<TextEditor::TextDocument *, QString> m_openedDocument;
|
||||
QMap<TextEditor::TextDocument *,
|
||||
QList<LanguageServerProtocol::DidChangeTextDocumentParams::TextDocumentContentChangeEvent>>
|
||||
m_documentsToUpdate;
|
||||
QTimer m_documentUpdateTimer;
|
||||
Core::Id m_id;
|
||||
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
|
||||
DynamicCapabilities m_dynamicCapabilities;
|
||||
|
@@ -274,6 +274,7 @@ class LanguageClientCompletionAssistProcessor : public IAssistProcessor
|
||||
{
|
||||
public:
|
||||
LanguageClientCompletionAssistProcessor(Client *client);
|
||||
~LanguageClientCompletionAssistProcessor() override;
|
||||
IAssistProposal *perform(const AssistInterface *interface) override;
|
||||
bool running() override;
|
||||
bool needsRestart() const override { return true; }
|
||||
@@ -285,6 +286,7 @@ private:
|
||||
QPointer<QTextDocument> m_document;
|
||||
QPointer<Client> m_client;
|
||||
Utils::optional<MessageId> m_currentRequest;
|
||||
QMetaObject::Connection m_postponedUpdateConnection;
|
||||
int m_pos = -1;
|
||||
};
|
||||
|
||||
@@ -292,6 +294,11 @@ LanguageClientCompletionAssistProcessor::LanguageClientCompletionAssistProcessor
|
||||
: m_client(client)
|
||||
{ }
|
||||
|
||||
LanguageClientCompletionAssistProcessor::~LanguageClientCompletionAssistProcessor()
|
||||
{
|
||||
QTC_ASSERT(!running(), cancel());
|
||||
}
|
||||
|
||||
static QString assistReasonString(AssistReason reason)
|
||||
{
|
||||
switch (reason) {
|
||||
@@ -315,7 +322,20 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
|
||||
++delta;
|
||||
if (delta < 3)
|
||||
return nullptr;
|
||||
if (m_client->documentUpdatePostponed(interface->fileName())) {
|
||||
m_postponedUpdateConnection
|
||||
= QObject::connect(m_client,
|
||||
&Client::documentUpdated,
|
||||
[this, interface](TextEditor::TextDocument *document) {
|
||||
if (document->filePath()
|
||||
== Utils::FilePath::fromString(interface->fileName()))
|
||||
perform(interface);
|
||||
});
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (m_postponedUpdateConnection)
|
||||
QObject::disconnect(m_postponedUpdateConnection);
|
||||
CompletionRequest completionRequest;
|
||||
CompletionParams::CompletionContext context;
|
||||
if (interface->reason() == ActivationCharacter) {
|
||||
@@ -353,15 +373,17 @@ IAssistProposal *LanguageClientCompletionAssistProcessor::perform(const AssistIn
|
||||
|
||||
bool LanguageClientCompletionAssistProcessor::running()
|
||||
{
|
||||
return m_currentRequest.has_value();
|
||||
return m_currentRequest.has_value() || m_postponedUpdateConnection;
|
||||
}
|
||||
|
||||
void LanguageClientCompletionAssistProcessor::cancel()
|
||||
{
|
||||
if (running()) {
|
||||
if (m_currentRequest.has_value()) {
|
||||
m_client->cancelRequest(m_currentRequest.value());
|
||||
m_client->removeAssistProcessor(this);
|
||||
m_currentRequest.reset();
|
||||
} else if (m_postponedUpdateConnection) {
|
||||
QObject::disconnect(m_postponedUpdateConnection);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user