forked from qt-creator/qt-creator
LanguageClient: pimpl DiagnosticManager
Change-Id: I4b5a2b0fe9818b676d08fd00f33b70366394539d Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -46,9 +46,35 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
DiagnosticManager::DiagnosticManager(Client *client)
|
struct VersionedDiagnostics
|
||||||
|
{
|
||||||
|
std::optional<int> version;
|
||||||
|
QList<LanguageServerProtocol::Diagnostic> diagnostics;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Marks
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
~Marks() { qDeleteAll(marks); }
|
||||||
|
bool enabled = true;
|
||||||
|
QList<TextEditor::TextMark *> marks;
|
||||||
|
};
|
||||||
|
|
||||||
|
class DiagnosticManager::DiagnosticManagerPrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DiagnosticManagerPrivate(Client *client)
|
||||||
: m_client(client)
|
: m_client(client)
|
||||||
, m_extraSelectionsId(TextEditorWidget::CodeWarningsSelection)
|
{}
|
||||||
|
|
||||||
|
QMap<Utils::FilePath, VersionedDiagnostics> m_diagnostics;
|
||||||
|
QMap<Utils::FilePath, Marks> m_marks;
|
||||||
|
Client *m_client;
|
||||||
|
Utils::Id m_extraSelectionsId = TextEditorWidget::CodeWarningsSelection;
|
||||||
|
};
|
||||||
|
|
||||||
|
DiagnosticManager::DiagnosticManager(Client *client)
|
||||||
|
: d(std::make_unique<DiagnosticManagerPrivate>(client))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,16 +88,16 @@ void DiagnosticManager::setDiagnostics(const FilePath &filePath,
|
|||||||
const std::optional<int> &version)
|
const std::optional<int> &version)
|
||||||
{
|
{
|
||||||
hideDiagnostics(filePath);
|
hideDiagnostics(filePath);
|
||||||
m_diagnostics[filePath] = {version, filteredDiagnostics(diagnostics)};
|
d->m_diagnostics[filePath] = {version, filteredDiagnostics(diagnostics)};
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath)
|
void DiagnosticManager::hideDiagnostics(const Utils::FilePath &filePath)
|
||||||
{
|
{
|
||||||
if (auto doc = TextDocument::textDocumentForFilePath(filePath)) {
|
if (auto doc = TextDocument::textDocumentForFilePath(filePath)) {
|
||||||
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
||||||
editor->editorWidget()->setExtraSelections(m_extraSelectionsId, {});
|
editor->editorWidget()->setExtraSelections(d->m_extraSelectionsId, {});
|
||||||
}
|
}
|
||||||
m_marks.remove(filePath);
|
d->m_marks.remove(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Diagnostic> DiagnosticManager::filteredDiagnostics(const QList<Diagnostic> &diagnostics) const
|
QList<Diagnostic> DiagnosticManager::filteredDiagnostics(const QList<Diagnostic> &diagnostics) const
|
||||||
@@ -82,7 +108,7 @@ QList<Diagnostic> DiagnosticManager::filteredDiagnostics(const QList<Diagnostic>
|
|||||||
void DiagnosticManager::disableDiagnostics(TextEditor::TextDocument *document)
|
void DiagnosticManager::disableDiagnostics(TextEditor::TextDocument *document)
|
||||||
{
|
{
|
||||||
|
|
||||||
Marks &marks = m_marks[document->filePath()];
|
Marks &marks = d->m_marks[document->filePath()];
|
||||||
if (!marks.enabled)
|
if (!marks.enabled)
|
||||||
return;
|
return;
|
||||||
for (TextEditor::TextMark *mark : marks.marks)
|
for (TextEditor::TextMark *mark : marks.marks)
|
||||||
@@ -94,11 +120,11 @@ void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version)
|
|||||||
{
|
{
|
||||||
if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) {
|
if (TextDocument *doc = TextDocument::textDocumentForFilePath(filePath)) {
|
||||||
QList<QTextEdit::ExtraSelection> extraSelections;
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
||||||
const VersionedDiagnostics &versionedDiagnostics = m_diagnostics.value(filePath);
|
const VersionedDiagnostics &versionedDiagnostics = d->m_diagnostics.value(filePath);
|
||||||
if (versionedDiagnostics.version.value_or(version) == version
|
if (versionedDiagnostics.version.value_or(version) == version
|
||||||
&& !versionedDiagnostics.diagnostics.isEmpty()) {
|
&& !versionedDiagnostics.diagnostics.isEmpty()) {
|
||||||
Marks &marks = m_marks[filePath];
|
Marks &marks = d->m_marks[filePath];
|
||||||
const bool isProjectFile = m_client->fileBelongsToProject(filePath);
|
const bool isProjectFile = d->m_client->fileBelongsToProject(filePath);
|
||||||
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
for (const Diagnostic &diagnostic : versionedDiagnostics.diagnostics) {
|
||||||
const QTextEdit::ExtraSelection selection
|
const QTextEdit::ExtraSelection selection
|
||||||
= createDiagnosticSelection(diagnostic, doc->document());
|
= createDiagnosticSelection(diagnostic, doc->document());
|
||||||
@@ -112,17 +138,22 @@ void DiagnosticManager::showDiagnostics(const FilePath &filePath, int version)
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
for (BaseTextEditor *editor : BaseTextEditor::textEditorsForDocument(doc))
|
||||||
editor->editorWidget()->setExtraSelections(m_extraSelectionsId, extraSelections);
|
editor->editorWidget()->setExtraSelections(d->m_extraSelectionsId, extraSelections);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Client *DiagnosticManager::client() const
|
||||||
|
{
|
||||||
|
return d->m_client;
|
||||||
|
}
|
||||||
|
|
||||||
TextEditor::TextMark *DiagnosticManager::createTextMark(TextDocument *doc,
|
TextEditor::TextMark *DiagnosticManager::createTextMark(TextDocument *doc,
|
||||||
const Diagnostic &diagnostic,
|
const Diagnostic &diagnostic,
|
||||||
bool /*isProjectFile*/) const
|
bool /*isProjectFile*/) const
|
||||||
{
|
{
|
||||||
static const QIcon icon = Icon::fromTheme("edit-copy");
|
static const QIcon icon = Icon::fromTheme("edit-copy");
|
||||||
static const QString tooltip = Tr::tr("Copy to Clipboard");
|
static const QString tooltip = Tr::tr("Copy to Clipboard");
|
||||||
auto mark = new TextMark(doc, diagnostic, m_client);
|
auto mark = new TextMark(doc, diagnostic, d->m_client);
|
||||||
mark->setActionsProvider([text = diagnostic.message()] {
|
mark->setActionsProvider([text = diagnostic.message()] {
|
||||||
QAction *action = new QAction();
|
QAction *action = new QAction();
|
||||||
action->setIcon(icon);
|
action->setIcon(icon);
|
||||||
@@ -153,13 +184,13 @@ QTextEdit::ExtraSelection DiagnosticManager::createDiagnosticSelection(
|
|||||||
void DiagnosticManager::setExtraSelectionsId(const Utils::Id &extraSelectionsId)
|
void DiagnosticManager::setExtraSelectionsId(const Utils::Id &extraSelectionsId)
|
||||||
{
|
{
|
||||||
// this function should be called before any diagnostics are handled
|
// this function should be called before any diagnostics are handled
|
||||||
QTC_CHECK(m_diagnostics.isEmpty());
|
QTC_CHECK(d->m_diagnostics.isEmpty());
|
||||||
m_extraSelectionsId = extraSelectionsId;
|
d->m_extraSelectionsId = extraSelectionsId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DiagnosticManager::forAllMarks(std::function<void (TextEditor::TextMark *)> func)
|
void DiagnosticManager::forAllMarks(std::function<void (TextEditor::TextMark *)> func)
|
||||||
{
|
{
|
||||||
for (const Marks &marks : std::as_const(m_marks)) {
|
for (const Marks &marks : std::as_const(d->m_marks)) {
|
||||||
for (TextEditor::TextMark *mark : marks.marks)
|
for (TextEditor::TextMark *mark : marks.marks)
|
||||||
func(mark);
|
func(mark);
|
||||||
}
|
}
|
||||||
@@ -167,18 +198,18 @@ void DiagnosticManager::forAllMarks(std::function<void (TextEditor::TextMark *)>
|
|||||||
|
|
||||||
void DiagnosticManager::clearDiagnostics()
|
void DiagnosticManager::clearDiagnostics()
|
||||||
{
|
{
|
||||||
for (const Utils::FilePath &path : m_diagnostics.keys())
|
for (const Utils::FilePath &path : d->m_diagnostics.keys())
|
||||||
hideDiagnostics(path);
|
hideDiagnostics(path);
|
||||||
m_diagnostics.clear();
|
d->m_diagnostics.clear();
|
||||||
QTC_ASSERT(m_marks.isEmpty(), m_marks.clear());
|
QTC_ASSERT(d->m_marks.isEmpty(), d->m_marks.clear());
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<Diagnostic> DiagnosticManager::diagnosticsAt(const FilePath &filePath,
|
QList<Diagnostic> DiagnosticManager::diagnosticsAt(const FilePath &filePath,
|
||||||
const QTextCursor &cursor) const
|
const QTextCursor &cursor) const
|
||||||
{
|
{
|
||||||
const int documentRevision = m_client->documentVersion(filePath);
|
const int documentRevision = d->m_client->documentVersion(filePath);
|
||||||
auto it = m_diagnostics.find(filePath);
|
auto it = d->m_diagnostics.find(filePath);
|
||||||
if (it == m_diagnostics.end())
|
if (it == d->m_diagnostics.end())
|
||||||
return {};
|
return {};
|
||||||
if (documentRevision != it->version.value_or(documentRevision))
|
if (documentRevision != it->version.value_or(documentRevision))
|
||||||
return {};
|
return {};
|
||||||
@@ -193,10 +224,10 @@ bool DiagnosticManager::hasDiagnostic(const FilePath &filePath,
|
|||||||
{
|
{
|
||||||
if (!doc)
|
if (!doc)
|
||||||
return false;
|
return false;
|
||||||
const auto it = m_diagnostics.find(filePath);
|
const auto it = d->m_diagnostics.find(filePath);
|
||||||
if (it == m_diagnostics.end())
|
if (it == d->m_diagnostics.end())
|
||||||
return {};
|
return {};
|
||||||
const int revision = m_client->documentVersion(filePath);
|
const int revision = d->m_client->documentVersion(filePath);
|
||||||
if (revision != it->version.value_or(revision))
|
if (revision != it->version.value_or(revision))
|
||||||
return false;
|
return false;
|
||||||
return it->diagnostics.contains(diag);
|
return it->diagnostics.contains(diag);
|
||||||
@@ -205,18 +236,13 @@ bool DiagnosticManager::hasDiagnostic(const FilePath &filePath,
|
|||||||
bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const
|
bool DiagnosticManager::hasDiagnostics(const TextDocument *doc) const
|
||||||
{
|
{
|
||||||
const FilePath docPath = doc->filePath();
|
const FilePath docPath = doc->filePath();
|
||||||
const auto it = m_diagnostics.find(docPath);
|
const auto it = d->m_diagnostics.find(docPath);
|
||||||
if (it == m_diagnostics.end())
|
if (it == d->m_diagnostics.end())
|
||||||
return {};
|
return {};
|
||||||
const int revision = m_client->documentVersion(docPath);
|
const int revision = d->m_client->documentVersion(docPath);
|
||||||
if (revision != it->version.value_or(revision))
|
if (revision != it->version.value_or(revision))
|
||||||
return false;
|
return false;
|
||||||
return !it->diagnostics.isEmpty();
|
return !it->diagnostics.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
DiagnosticManager::Marks::~Marks()
|
|
||||||
{
|
|
||||||
qDeleteAll(marks);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
@@ -54,7 +54,7 @@ signals:
|
|||||||
void textMarkCreated(const Utils::FilePath &path);
|
void textMarkCreated(const Utils::FilePath &path);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Client *client() const { return m_client; }
|
Client *client() const;
|
||||||
virtual TextEditor::TextMark *createTextMark(TextEditor::TextDocument *doc,
|
virtual TextEditor::TextMark *createTextMark(TextEditor::TextDocument *doc,
|
||||||
const LanguageServerProtocol::Diagnostic &diagnostic,
|
const LanguageServerProtocol::Diagnostic &diagnostic,
|
||||||
bool isProjectFile) const;
|
bool isProjectFile) const;
|
||||||
@@ -64,24 +64,9 @@ protected:
|
|||||||
void setExtraSelectionsId(const Utils::Id &extraSelectionsId);
|
void setExtraSelectionsId(const Utils::Id &extraSelectionsId);
|
||||||
|
|
||||||
void forAllMarks(std::function<void (TextEditor::TextMark *)> func);
|
void forAllMarks(std::function<void (TextEditor::TextMark *)> func);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct VersionedDiagnostics
|
class DiagnosticManagerPrivate;
|
||||||
{
|
std::unique_ptr<DiagnosticManagerPrivate> d;
|
||||||
std::optional<int> version;
|
|
||||||
QList<LanguageServerProtocol::Diagnostic> diagnostics;
|
|
||||||
};
|
|
||||||
QMap<Utils::FilePath, VersionedDiagnostics> m_diagnostics;
|
|
||||||
class Marks
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
~Marks();
|
|
||||||
bool enabled = true;
|
|
||||||
QList<TextEditor::TextMark *> marks;
|
|
||||||
};
|
|
||||||
QMap<Utils::FilePath, Marks> m_marks;
|
|
||||||
Client *m_client;
|
|
||||||
Utils::Id m_extraSelectionsId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace LanguageClient
|
} // namespace LanguageClient
|
||||||
|
Reference in New Issue
Block a user