diff options
author | David Schulz <david.schulz@qt.io> | 2020-09-09 08:15:11 +0200 |
---|---|---|
committer | David Schulz <david.schulz@qt.io> | 2020-09-15 10:45:49 +0000 |
commit | 116fb0895d054b13d3cc99763ed1569a0964eb85 (patch) | |
tree | 12d6a8c2a43a36b9023692bf63f5c9a3ba42c2dc | |
parent | ee8e102cbc8a0c8fa96f872afb89538b48357a23 (diff) |
LSP: move diagnostic handling from client in a separate class
Change-Id: Id70a7b82137d3a4591de521380199e546e8685f4
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
-rw-r--r-- | src/plugins/languageclient/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/languageclient/client.cpp | 117 | ||||
-rw-r--r-- | src/plugins/languageclient/client.h | 9 | ||||
-rw-r--r-- | src/plugins/languageclient/diagnosticmanager.cpp | 144 | ||||
-rw-r--r-- | src/plugins/languageclient/diagnosticmanager.h | 62 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclient.pro | 2 | ||||
-rw-r--r-- | src/plugins/languageclient/languageclient.qbs | 2 |
7 files changed, 221 insertions, 116 deletions
diff --git a/src/plugins/languageclient/CMakeLists.txt b/src/plugins/languageclient/CMakeLists.txt index 85d2227e12..bda78b7cbb 100644 --- a/src/plugins/languageclient/CMakeLists.txt +++ b/src/plugins/languageclient/CMakeLists.txt @@ -3,6 +3,7 @@ add_qtc_plugin(LanguageClient PLUGIN_DEPENDS ProjectExplorer Core TextEditor SOURCES client.cpp client.h + diagnosticmanager.cpp diagnosticmanager.h documentsymbolcache.cpp documentsymbolcache.h dynamiccapabilities.cpp dynamiccapabilities.h languageclient.qrc diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index d8b340c1d8..fd39b03d37 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -30,6 +30,7 @@ #include "languageclientutils.h" #include "semantichighlightsupport.h" +#include <coreplugin/editormanager/documentmodel.h> #include <coreplugin/icore.h> #include <coreplugin/idocument.h> #include <coreplugin/messagemanager.h> @@ -48,11 +49,9 @@ #include <texteditor/texteditor.h> #include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditorsettings.h> -#include <texteditor/textmark.h> #include <utils/mimetypes/mimedatabase.h> #include <utils/qtcprocess.h> #include <utils/synchronousprocess.h> -#include <utils/utilsicons.h> #include <QDebug> #include <QLoggingCategory> @@ -71,34 +70,10 @@ namespace LanguageClient { static Q_LOGGING_CATEGORY(LOGLSPCLIENT, "qtc.languageclient.client", QtWarningMsg); -class TextMark : public TextEditor::TextMark -{ -public: - TextMark(const Utils::FilePath &fileName, const Diagnostic &diag, const Utils::Id &clientId) - : TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId) - , m_diagnostic(diag) - { - using namespace Utils; - setLineAnnotation(diag.message()); - setToolTip(diag.message()); - const bool isError - = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; - setColor(isError ? Theme::CodeModel_Error_TextMarkColor - : Theme::CodeModel_Warning_TextMarkColor); - - setIcon(isError ? Icons::CODEMODEL_ERROR.icon() - : Icons::CODEMODEL_WARNING.icon()); - } - - const Diagnostic &diagnostic() const { return m_diagnostic; } - -private: - const Diagnostic m_diagnostic; -}; - Client::Client(BaseClientInterface *clientInterface) : m_id(Utils::Id::fromString(QUuid::createUuid().toString())) , m_clientInterface(clientInterface) + , m_diagnosticManager(m_id) , m_documentSymbolCache(this) , m_hoverHandler(this) , m_symbolSupport(this) @@ -145,8 +120,6 @@ Client::~Client() widget->removeHoverHandler(&m_hoverHandler); } } - for (const DocumentUri &uri : m_diagnostics.keys()) - removeDiagnostics(uri); for (const DocumentUri &uri : m_highlights.keys()) { if (TextDocument *doc = TextDocument::textDocumentForFilePath(uri.toFilePath())) { if (TextEditor::SyntaxHighlighter *highlighter = doc->syntaxHighlighter()) @@ -387,7 +360,7 @@ void Client::closeDocument(TextEditor::TextDocument *document) void Client::activateDocument(TextEditor::TextDocument *document) { auto uri = DocumentUri::fromFilePath(document->filePath()); - showDiagnostics(uri); + m_diagnosticManager.showDiagnostics(uri); SemanticHighligtingSupport::applyHighlight(document, m_highlights.value(uri), capabilities()); // only replace the assist provider if the language server support it if (m_serverCapabilities.completionProvider()) { @@ -417,7 +390,7 @@ void Client::activateDocument(TextEditor::TextDocument *document) void Client::deactivateDocument(TextEditor::TextDocument *document) { - hideDiagnostics(document); + m_diagnosticManager.hideDiagnostics(document); resetAssistProviders(document); document->setFormatter(nullptr); if (m_serverCapabilities.semanticHighlighting().has_value()) { @@ -924,12 +897,7 @@ bool Client::needsRestart(const BaseSettings *settings) const QList<Diagnostic> Client::diagnosticsAt(const DocumentUri &uri, const Range &range) const { - QList<Diagnostic> diagnostics; - for (const Diagnostic &diagnostic : m_diagnostics[uri]) { - if (diagnostic.range().overlaps(range)) - diagnostics << diagnostic; - } - return diagnostics; + return m_diagnosticManager.diagnosticsAt(uri, range); } bool Client::start() @@ -948,8 +916,7 @@ bool Client::reset() updateEditorToolBar(m_openedDocument.keys()); m_serverCapabilities = ServerCapabilities(); m_dynamicCapabilities.reset(); - for (const DocumentUri &uri : m_diagnostics.keys()) - removeDiagnostics(uri); + m_diagnosticManager.clearDiagnostics(); for (TextEditor::TextDocument *document : m_openedDocument.keys()) document->disconnect(this); for (TextEditor::TextDocument *document : m_resetAssistProvider.keys()) @@ -990,18 +957,6 @@ void Client::log(const QString &message, Core::MessageManager::PrintToOutputPane Core::MessageManager::write(QString("LanguageClient %1: %2").arg(name(), message), flag); } -void Client::showDiagnostics(Core::IDocument *doc) -{ - showDiagnostics(DocumentUri::fromFilePath(doc->filePath())); -} - -void Client::hideDiagnostics(TextEditor::TextDocument *doc) -{ - if (!doc) - return; - qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextEditor::TextMark::category, id()))); -} - const ServerCapabilities &Client::capabilities() const { return m_serverCapabilities; @@ -1060,61 +1015,6 @@ void Client::showMessageBox(const ShowMessageRequestParams &message, const Messa box->show(); } -static void addDiagnosticsSelections(const Diagnostic &diagnostic, - QTextDocument *textDocument, - QList<QTextEdit::ExtraSelection> &extraSelections) -{ - QTextCursor cursor(textDocument); - cursor.setPosition(::Utils::Text::positionInText(textDocument, - diagnostic.range().start().line() + 1, - diagnostic.range().start().character() + 1)); - cursor.setPosition(::Utils::Text::positionInText(textDocument, - diagnostic.range().end().line() + 1, - diagnostic.range().end().character() + 1), - QTextCursor::KeepAnchor); - - QTextCharFormat format; - const TextEditor::FontSettings& fontSettings = TextEditor::TextEditorSettings::instance()->fontSettings(); - DiagnosticSeverity severity = diagnostic.severity().value_or(DiagnosticSeverity::Warning); - - if (severity == DiagnosticSeverity::Error) { - format = fontSettings.toTextCharFormat(TextEditor::C_ERROR); - } else { - format = fontSettings.toTextCharFormat(TextEditor::C_WARNING); - } - - extraSelections.push_back(std::move(QTextEdit::ExtraSelection{cursor, format})); -} - -void Client::showDiagnostics(const DocumentUri &uri) -{ - const FilePath &filePath = uri.toFilePath(); - if (TextEditor::TextDocument *doc = TextEditor::TextDocument::textDocumentForFilePath( - filePath)) { - QList<QTextEdit::ExtraSelection> extraSelections; - - for (const Diagnostic &diagnostic : m_diagnostics.value(uri)) { - doc->addMark(new TextMark(filePath, diagnostic, id())); - addDiagnosticsSelections(diagnostic, doc->document(), extraSelections); - } - - for (Core::IEditor *editor : Core::DocumentModel::editorsForDocument(doc)) { - if (auto textEditor = qobject_cast<TextEditor::BaseTextEditor *>(editor)) { - TextEditor::TextEditorWidget *widget = textEditor->editorWidget(); - - widget->setExtraSelections(TextEditor::TextEditorWidget::CodeWarningsSelection, - extraSelections); - } - } - } -} - -void Client::removeDiagnostics(const DocumentUri &uri) -{ - hideDiagnostics(TextEditor::TextDocument::textDocumentForFilePath(uri.toFilePath())); - m_diagnostics.remove(uri); -} - void Client::resetAssistProviders(TextEditor::TextDocument *document) { const AssistProviders providers = m_resetAssistProvider.take(document); @@ -1269,11 +1169,10 @@ void Client::handleDiagnostics(const PublishDiagnosticsParams ¶ms) { const DocumentUri &uri = params.uri(); - removeDiagnostics(uri); const QList<Diagnostic> &diagnostics = params.diagnostics(); - m_diagnostics[uri] = diagnostics; + m_diagnosticManager.setDiagnostics(uri, params.diagnostics()); if (LanguageClientManager::clientForUri(uri) == this) { - showDiagnostics(uri); + m_diagnosticManager.showDiagnostics(uri); requestCodeActions(uri, diagnostics); } } diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index f31d18087d..d264898474 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -25,6 +25,7 @@ #pragma once +#include "diagnosticmanager.h" #include "documentsymbolcache.h" #include "dynamiccapabilities.h" #include "languageclient_global.h" @@ -64,13 +65,11 @@ namespace TextEditor class IAssistProcessor; class TextDocument; class TextEditorWidget; -class TextMark; } namespace LanguageClient { class BaseClientInterface; -class TextMark; class LANGUAGECLIENT_EXPORT Client : public QObject { @@ -169,9 +168,6 @@ public: Core::MessageManager::PrintToOutputPaneFlag flag = Core::MessageManager::NoModeSwitch) { log(responseError.toString(), flag); } - void showDiagnostics(Core::IDocument *doc); - void hideDiagnostics(TextEditor::TextDocument *doc); - const LanguageServerProtocol::ServerCapabilities &capabilities() const; const DynamicCapabilities &dynamicCapabilities() const; const BaseClientInterface *clientInterface() const; @@ -208,7 +204,6 @@ private: void showMessageBox(const LanguageServerProtocol::ShowMessageRequestParams &message, const LanguageServerProtocol::MessageId &id); - void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri); void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri); void resetAssistProviders(TextEditor::TextDocument *document); void sendPostponedDocumentUpdates(); @@ -243,7 +238,7 @@ private: QHash<LanguageServerProtocol::DocumentUri, LanguageServerProtocol::MessageId> m_highlightRequests; int m_restartsLeft = 5; QScopedPointer<BaseClientInterface> m_clientInterface; - QMap<LanguageServerProtocol::DocumentUri, QList<LanguageServerProtocol::Diagnostic>> m_diagnostics; + DiagnosticManager m_diagnosticManager; DocumentSymbolCache m_documentSymbolCache; HoverHandler m_hoverHandler; QHash<LanguageServerProtocol::DocumentUri, TextEditor::HighlightingResults> m_highlights; diff --git a/src/plugins/languageclient/diagnosticmanager.cpp b/src/plugins/languageclient/diagnosticmanager.cpp new file mode 100644 index 0000000000..562c2e3c75 --- /dev/null +++ b/src/plugins/languageclient/diagnosticmanager.cpp @@ -0,0 +1,144 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#include "diagnosticmanager.h" + +#include <coreplugin/editormanager/documentmodel.h> +#include <texteditor/fontsettings.h> +#include <texteditor/textdocument.h> +#include <texteditor/texteditor.h> +#include <texteditor/texteditorsettings.h> +#include <texteditor/textmark.h> +#include <texteditor/textstyles.h> +#include <utils/utilsicons.h> + +#include <QTextEdit> + +using namespace LanguageServerProtocol; +using namespace Utils; +using namespace TextEditor; + +namespace LanguageClient { + +class TextMark : public TextEditor::TextMark +{ +public: + TextMark(const FilePath &fileName, const Diagnostic &diag, const Id &clientId) + : TextEditor::TextMark(fileName, diag.range().start().line() + 1, clientId) + , m_diagnostic(diag) + { + setLineAnnotation(diag.message()); + setToolTip(diag.message()); + const bool isError + = diag.severity().value_or(DiagnosticSeverity::Hint) == DiagnosticSeverity::Error; + setColor(isError ? Theme::CodeModel_Error_TextMarkColor + : Theme::CodeModel_Warning_TextMarkColor); + + setIcon(isError ? Icons::CODEMODEL_ERROR.icon() + : Icons::CODEMODEL_WARNING.icon()); + } + + const Diagnostic &diagnostic() const { return m_diagnostic; } + +private: + const Diagnostic m_diagnostic; +}; + +DiagnosticManager::DiagnosticManager(const Id &clientId) + : m_clientId(clientId) +{} + +DiagnosticManager::~DiagnosticManager() +{ + clearDiagnostics(); +} + +void DiagnosticManager::setDiagnostics(const LanguageServerProtocol::DocumentUri &uri, + const QList<LanguageServerProtocol::Diagnostic> &diagnostics) +{ + removeDiagnostics(uri); + m_diagnostics[uri] = diagnostics; +} + +void DiagnosticManager::hideDiagnostics(TextDocument *doc) +{ + if (!doc) + return; + qDeleteAll(Utils::filtered(doc->marks(), Utils::equal(&TextMark::category, m_clientId))); +} + +void DiagnosticManager::removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri) +{ + hideDiagnostics(TextDocument::textDocumentForFilePath(uri.toFilePath())); + m_diagnostics.remove(uri); +} + +static QTextEdit::ExtraSelection toDiagnosticsSelections(const Diagnostic &diagnostic, + QTextDocument *textDocument) +{ + QTextCursor cursor(textDocument); + cursor.setPosition(diagnostic.range().start().toPositionInDocument(textDocument)); + cursor.setPosition(diagnostic.range().end().toPositionInDocument(textDocument), + QTextCursor::KeepAnchor); + + const FontSettings &fontSettings = TextEditorSettings::instance()->fontSettings(); + const DiagnosticSeverity severity = diagnostic.severity().value_or(DiagnosticSeverity::Warning); + const TextStyle style = severity == DiagnosticSeverity::Error ? C_ERROR : C_WARNING; + + return QTextEdit::ExtraSelection{cursor, fontSettings.toTextCharFormat(style)}; +} + +void DiagnosticManager::showDiagnostics(const DocumentUri &uri) +{ + const FilePath &filePath = uri.toFilePath(); + if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) { + QList<QTextEdit::ExtraSelection> extraSelections; + + for (const Diagnostic &diagnostic : m_diagnostics.value(uri)) { + doc->addMark(new TextMark(filePath, diagnostic, m_clientId)); + extraSelections << toDiagnosticsSelections(diagnostic, doc->document()); + } + + for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc)) { + editor->editorWidget()->setExtraSelections(TextEditorWidget::CodeWarningsSelection, + extraSelections); + } + } +} + +void DiagnosticManager::clearDiagnostics() +{ + for (const DocumentUri &uri : m_diagnostics.keys()) + removeDiagnostics(uri); +} + +QList<Diagnostic> DiagnosticManager::diagnosticsAt(const DocumentUri &uri, const Range &range) const +{ + return Utils::filtered(m_diagnostics.value(uri), [range](const Diagnostic &diagnostic) { + return diagnostic.range().overlaps(range); + }); +} + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/diagnosticmanager.h b/src/plugins/languageclient/diagnosticmanager.h new file mode 100644 index 0000000000..9b83f0019d --- /dev/null +++ b/src/plugins/languageclient/diagnosticmanager.h @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ + +#pragma once + +#include <languageserverprotocol/lsptypes.h> + +#include <utils/id.h> + +#include <QMap> + +namespace TextEditor { class TextDocument; } + +namespace LanguageClient { + +class DiagnosticManager +{ +public: + explicit DiagnosticManager(const Utils::Id &clientId); + ~DiagnosticManager(); + + void setDiagnostics(const LanguageServerProtocol::DocumentUri &uri, + const QList<LanguageServerProtocol::Diagnostic> &diagnostics); + void removeDiagnostics(const LanguageServerProtocol::DocumentUri &uri); + + void showDiagnostics(const LanguageServerProtocol::DocumentUri &uri); + void hideDiagnostics(TextEditor::TextDocument *doc); + + void clearDiagnostics(); + + QList<LanguageServerProtocol::Diagnostic> diagnosticsAt( + const LanguageServerProtocol::DocumentUri &uri, + const LanguageServerProtocol::Range &range) const; + +private: + QMap<LanguageServerProtocol::DocumentUri, QList<LanguageServerProtocol::Diagnostic>> m_diagnostics; + Utils::Id m_clientId; +}; + +} // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclient.pro b/src/plugins/languageclient/languageclient.pro index 25fe9b5fcc..c60cf4dca8 100644 --- a/src/plugins/languageclient/languageclient.pro +++ b/src/plugins/languageclient/languageclient.pro @@ -4,6 +4,7 @@ DEFINES += LANGUAGECLIENT_LIBRARY HEADERS += \ client.h \ + diagnosticmanager.h \ documentsymbolcache.h \ dynamiccapabilities.h \ languageclient_global.h \ @@ -26,6 +27,7 @@ HEADERS += \ SOURCES += \ client.cpp \ + diagnosticmanager.cpp \ documentsymbolcache.cpp \ dynamiccapabilities.cpp \ languageclientcompletionassist.cpp \ diff --git a/src/plugins/languageclient/languageclient.qbs b/src/plugins/languageclient/languageclient.qbs index 18b34c963c..c4d3385f29 100644 --- a/src/plugins/languageclient/languageclient.qbs +++ b/src/plugins/languageclient/languageclient.qbs @@ -16,6 +16,8 @@ QtcPlugin { files: [ "client.cpp", "client.h", + "diagnosticmanager.cpp", + "diagnosticmanager.h", "documentsymbolcache.cpp", "documentsymbolcache.h", "dynamiccapabilities.cpp", |