aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2021-03-12 13:49:13 +0100
committerDavid Schulz <david.schulz@qt.io>2021-03-16 11:07:09 +0000
commitc218f77f7e1733b9abd03c60a76d9bed782ddf4c (patch)
tree5bf5f8442457d8b919507ef7ef708144c33acf19
parent85533cce0fc3dffc71a4833dc111471c69e3443e (diff)
LanguageClient: compress documentHighlight requests
Change-Id: I98707a61a228c66966c72f6b4da2470b6f53820e Reviewed-by: Christian Stenger <christian.stenger@qt.io>
-rw-r--r--src/plugins/languageclient/client.cpp162
-rw-r--r--src/plugins/languageclient/client.h2
-rw-r--r--src/plugins/languageclient/languageclientmanager.cpp13
3 files changed, 108 insertions, 69 deletions
diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp
index ce2184d303a..39822bccb49 100644
--- a/src/plugins/languageclient/client.cpp
+++ b/src/plugins/languageclient/client.cpp
@@ -140,6 +140,8 @@ Client::~Client()
}
for (IAssistProcessor *processor : qAsConst(m_runningAssistProcessors))
processor->setAsyncProposalAvailable(nullptr);
+ qDeleteAll(m_documentHighlightsTimer);
+ m_documentHighlightsTimer.clear();
updateEditorToolBar(m_openedDocument.keys());
// do not handle messages while shutting down
disconnect(m_clientInterface.data(), &BaseClientInterface::messageReceived,
@@ -431,6 +433,64 @@ void Client::updateFunctionHintProvider(TextEditor::TextDocument *document)
}
}
+void Client::requestDocumentHighlights(TextEditor::TextEditorWidget *widget)
+{
+ const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath());
+ if (m_dynamicCapabilities.isRegistered(DocumentHighlightsRequest::methodName).value_or(false)) {
+ TextDocumentRegistrationOptions option(
+ m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName));
+ if (!option.filterApplies(widget->textDocument()->filePath()))
+ return;
+ } else {
+ Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> provider
+ = m_serverCapabilities.documentHighlightProvider();
+ if (!provider.has_value())
+ return;
+ if (Utils::holds_alternative<bool>(*provider) && !Utils::get<bool>(*provider))
+ return;
+ }
+
+ auto runningRequest = m_highlightRequests.find(uri);
+ if (runningRequest != m_highlightRequests.end())
+ cancelRequest(runningRequest.value());
+
+ DocumentHighlightsRequest request(
+ TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(widget->textCursor())));
+ request.setResponseCallback(
+ [widget = QPointer<TextEditor::TextEditorWidget>(widget), this, uri]
+ (const DocumentHighlightsRequest::Response &response)
+ {
+ m_highlightRequests.remove(uri);
+ if (!widget)
+ return;
+
+ const Id &id = TextEditor::TextEditorWidget::CodeSemanticsSelection;
+ QList<QTextEdit::ExtraSelection> selections;
+ const Utils::optional<DocumentHighlightsResult> &result = response.result();
+ if (!result.has_value() || holds_alternative<std::nullptr_t>(result.value())) {
+ widget->setExtraSelections(id, selections);
+ return;
+ }
+
+ const QTextCharFormat &format =
+ widget->textDocument()->fontSettings().toTextCharFormat(TextEditor::C_OCCURRENCES);
+ QTextDocument *document = widget->document();
+ for (const auto &highlight : get<QList<DocumentHighlight>>(result.value())) {
+ QTextEdit::ExtraSelection selection{widget->textCursor(), format};
+ const int &start = highlight.range().start().toPositionInDocument(document);
+ const int &end = highlight.range().end().toPositionInDocument(document);
+ if (start < 0 || end < 0)
+ continue;
+ selection.cursor.setPosition(start);
+ selection.cursor.setPosition(end, QTextCursor::KeepAnchor);
+ selections << selection;
+ }
+ widget->setExtraSelections(id, selections);
+ });
+ m_highlightRequests[uri] = request.id();
+ sendContent(request);
+}
+
void Client::activateDocument(TextEditor::TextDocument *document)
{
auto uri = DocumentUri::fromFilePath(document->filePath());
@@ -447,11 +507,11 @@ void Client::activateDocument(TextEditor::TextDocument *document)
for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) {
updateEditorToolBar(editor);
if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) {
- textEditor->editorWidget()->addHoverHandler(&m_hoverHandler);
- if (symbolSupport().supportsRename(document)) {
- textEditor->editorWidget()->addOptionalActions(
- TextEditor::TextEditorActionHandler::RenameSymbol);
- }
+ TextEditor::TextEditorWidget *widget = textEditor->editorWidget();
+ widget->addHoverHandler(&m_hoverHandler);
+ requestDocumentHighlights(widget);
+ if (symbolSupport().supportsRename(document))
+ widget->addOptionalActions(TextEditor::TextEditorActionHandler::RenameSymbol);
}
}
}
@@ -466,8 +526,11 @@ void Client::deactivateDocument(TextEditor::TextDocument *document)
highlighter->clearAllExtraFormats();
}
for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(document)) {
- if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor))
- textEditor->editorWidget()->removeHoverHandler(&m_hoverHandler);
+ if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) {
+ TextEditor::TextEditorWidget *widget = textEditor->editorWidget();
+ widget->removeHoverHandler(&m_hoverHandler);
+ widget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, {});
+ }
}
}
@@ -629,61 +692,38 @@ TextEditor::HighlightingResult createHighlightingResult(const SymbolInformation
void Client::cursorPositionChanged(TextEditor::TextEditorWidget *widget)
{
- if (m_documentsToUpdate.contains(widget->textDocument()))
+ TextEditor::TextDocument *document = widget->textDocument();
+ if (m_documentsToUpdate.contains(document))
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(
- m_dynamicCapabilities.option(DocumentHighlightsRequest::methodName));
- if (!option.filterApplies(widget->textDocument()->filePath()))
- return;
- } else {
- Utils::optional<Utils::variant<bool, WorkDoneProgressOptions>> provider
- = m_serverCapabilities.documentHighlightProvider();
- if (!provider.has_value())
- return;
- if (Utils::holds_alternative<bool>(*provider) && !Utils::get<bool>(*provider))
- return;
+ QTimer *timer = m_documentHighlightsTimer[widget];
+ if (!timer) {
+ const auto uri = DocumentUri::fromFilePath(widget->textDocument()->filePath());
+ auto runningRequest = m_highlightRequests.find(uri);
+ if (runningRequest != m_highlightRequests.end())
+ cancelRequest(runningRequest.value());
+ timer = new QTimer;
+ timer->setSingleShot(true);
+ m_documentHighlightsTimer.insert(widget, timer);
+ connect(timer, &QTimer::timeout, this, [this, widget]() {
+ requestDocumentHighlights(widget);
+ m_documentHighlightsTimer.take(widget)->deleteLater();
+ });
+ connect(widget, &QWidget::destroyed, this, [widget, this]() {
+ delete m_documentHighlightsTimer.take(widget);
+ });
}
-
- auto runningRequest = m_highlightRequests.find(uri);
- if (runningRequest != m_highlightRequests.end())
- cancelRequest(runningRequest.value());
-
- DocumentHighlightsRequest request(
- TextDocumentPositionParams(TextDocumentIdentifier(uri), Position(widget->textCursor())));
- request.setResponseCallback(
- [widget = QPointer<TextEditor::TextEditorWidget>(widget), this, uri]
- (DocumentHighlightsRequest::Response response)
- {
- m_highlightRequests.remove(uri);
- if (!widget)
- return;
-
- QList<QTextEdit::ExtraSelection> selections;
- const DocumentHighlightsResult result = response.result().value_or(DocumentHighlightsResult());
- if (!holds_alternative<QList<DocumentHighlight>>(result)) {
- widget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, selections);
- return;
- }
-
- const QTextCharFormat &format =
- widget->textDocument()->fontSettings().toTextCharFormat(TextEditor::C_OCCURRENCES);
- QTextDocument *document = widget->document();
- for (const auto &highlight : get<QList<DocumentHighlight>>(result)) {
- QTextEdit::ExtraSelection selection{widget->textCursor(), format};
- const int &start = highlight.range().start().toPositionInDocument(document);
- const int &end = highlight.range().end().toPositionInDocument(document);
- if (start < 0 || end < 0)
- continue;
- selection.cursor.setPosition(start);
- selection.cursor.setPosition(end, QTextCursor::KeepAnchor);
- selections << selection;
- }
- widget->setExtraSelections(TextEditor::TextEditorWidget::CodeSemanticsSelection, selections);
- });
- m_highlightRequests[uri] = request.id();
- sendContent(request);
+ const Id selectionsId(TextEditor::TextEditorWidget::CodeSemanticsSelection);
+ const QList semanticSelections = widget->extraSelections(selectionsId);
+ if (!semanticSelections.isEmpty()) {
+ auto selectionContainsPos =
+ [pos = widget->position()](const QTextEdit::ExtraSelection &selection) {
+ const QTextCursor cursor = selection.cursor;
+ return cursor.selectionStart() <= pos && cursor.selectionEnd() >= pos;
+ };
+ if (!Utils::anyOf(semanticSelections, selectionContainsPos))
+ widget->setExtraSelections(selectionsId, {});
+ }
+ timer->start(250);
}
SymbolSupport &Client::symbolSupport()
@@ -887,6 +927,8 @@ bool Client::reset()
for (TextEditor::IAssistProcessor *processor : qAsConst(m_runningAssistProcessors))
processor->setAsyncProposalAvailable(nullptr);
m_runningAssistProcessors.clear();
+ qDeleteAll(m_documentHighlightsTimer);
+ m_documentHighlightsTimer.clear();
return true;
}
diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h
index e3edbf88b52..dfb2d660659 100644
--- a/src/plugins/languageclient/client.h
+++ b/src/plugins/languageclient/client.h
@@ -197,6 +197,7 @@ private:
void updateCompletionProvider(TextEditor::TextDocument *document);
void updateFunctionHintProvider(TextEditor::TextDocument *document);
+ void requestDocumentHighlights(TextEditor::TextEditorWidget *widget);
void rehighlight();
using ContentHandler = std::function<void(const QByteArray &, QTextCodec *, QString &,
@@ -214,6 +215,7 @@ private:
QMap<TextEditor::TextDocument *,
QList<LanguageServerProtocol::DidChangeTextDocumentParams::TextDocumentContentChangeEvent>>
m_documentsToUpdate;
+ QMap<TextEditor::TextEditorWidget *, QTimer *> m_documentHighlightsTimer;
QTimer m_documentUpdateTimer;
Utils::Id m_id;
LanguageServerProtocol::ServerCapabilities m_serverCapabilities;
diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp
index 2f69bada526..412c3042d65 100644
--- a/src/plugins/languageclient/languageclientmanager.cpp
+++ b/src/plugins/languageclient/languageclientmanager.cpp
@@ -432,15 +432,10 @@ void LanguageClientManager::editorOpened(Core::IEditor *editor)
if (auto client = clientForDocument(document))
client->symbolSupport().renameSymbol(document, cursor);
});
- connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget]() {
- // TODO This would better be a compressing timer
- QTimer::singleShot(50, this, [widget = QPointer<TextEditorWidget>(widget)]() {
- if (!widget)
- return;
- if (Client *client = clientForDocument(widget->textDocument()))
- if (client->reachable())
- client->cursorPositionChanged(widget);
- });
+ connect(widget, &TextEditorWidget::cursorPositionChanged, this, [widget]() {
+ if (Client *client = clientForDocument(widget->textDocument()))
+ if (client->reachable())
+ client->cursorPositionChanged(widget);
});
updateEditorToolBar(editor);
if (TextEditor::TextDocument *document = textEditor->textDocument()) {