LSP: Implement SymbolTag support

Change-Id: I6e57d315a5ecd7402c0082df68e083e33dfeab7e
Reviewed-by: David Schulz <david.schulz@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
Christian Kandeler
2024-03-01 17:36:32 +01:00
parent 1de045f687
commit e01909a8a1
9 changed files with 85 additions and 1 deletions

View File

@@ -25,4 +25,9 @@ CallHierarchyOutgoingCallsRequest::CallHierarchyOutgoingCallsRequest(
: Request(methodName, params) : Request(methodName, params)
{} {}
std::optional<QList<SymbolTag>> CallHierarchyItem::symbolTags() const
{
return Internal::getSymbolTags(*this);
}
} // namespace LanguageServerProtocol } // namespace LanguageServerProtocol

View File

@@ -18,6 +18,8 @@ public:
SymbolKind symbolKind() const { return SymbolKind(typedValue<int>(kindKey)); } SymbolKind symbolKind() const { return SymbolKind(typedValue<int>(kindKey)); }
void setSymbolKind(const SymbolKind &symbolKind) { insert(kindKey, int(symbolKind)); } void setSymbolKind(const SymbolKind &symbolKind) { insert(kindKey, int(symbolKind)); }
std::optional<QList<SymbolTag>> symbolTags() const;
Range range() const { return typedValue<Range>(rangeKey); } Range range() const { return typedValue<Range>(rangeKey); }
void setRange(const Range &range) { insert(rangeKey, range); } void setRange(const Range &range) { insert(rangeKey, range); }

View File

@@ -19,6 +19,20 @@ void SymbolCapabilities::SymbolKindCapabilities::setValueSet(const QList<SymbolK
insert(valueSetKey, enumArrayToJsonArray<SymbolKind>(valueSet)); insert(valueSetKey, enumArrayToJsonArray<SymbolKind>(valueSet));
} }
std::optional<QList<SymbolTag> > SymbolCapabilities::SymbolTagCapabilities::valueSet() const
{
if (std::optional<QList<int>> array = optionalArray<int>(valueSetKey)) {
return std::make_optional(
Utils::transform(*array, [](int value) { return static_cast<SymbolTag>(value); }));
}
return std::nullopt;
}
void SymbolCapabilities::SymbolTagCapabilities::setValueSet(const QList<SymbolTag> &valueSet)
{
insert(valueSetKey, enumArrayToJsonArray<SymbolTag>(valueSet));
}
WorkspaceClientCapabilities::WorkspaceClientCapabilities() WorkspaceClientCapabilities::WorkspaceClientCapabilities()
{ {
setWorkspaceFolders(true); setWorkspaceFolders(true);

View File

@@ -131,12 +131,31 @@ public:
void clearValueSet() { remove(valueSetKey); } void clearValueSet() { remove(valueSetKey); }
}; };
class LANGUAGESERVERPROTOCOL_EXPORT SymbolTagCapabilities : public JsonObject
{
public:
using JsonObject::JsonObject;
/*
* The client supports tags on `SymbolInformation` and `WorkspaceSymbol`.
* Clients supporting tags have to handle unknown tags gracefully.
*/
std::optional<QList<SymbolTag>> valueSet() const;
void setValueSet(const QList<SymbolTag> &valueSet);
void clearValueSet() { remove(valueSetKey); }
};
// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. // Specific capabilities for the `SymbolKind` in the `workspace/symbol` request.
std::optional<SymbolKindCapabilities> symbolKind() const std::optional<SymbolKindCapabilities> symbolKind() const
{ return optionalValue<SymbolKindCapabilities>(symbolKindKey); } { return optionalValue<SymbolKindCapabilities>(symbolKindKey); }
void setSymbolKind(const SymbolKindCapabilities &symbolKind) { insert(symbolKindKey, symbolKind); } void setSymbolKind(const SymbolKindCapabilities &symbolKind) { insert(symbolKindKey, symbolKind); }
void clearSymbolKind() { remove(symbolKindKey); } void clearSymbolKind() { remove(symbolKindKey); }
std::optional<SymbolTagCapabilities> symbolTag() const
{ return optionalValue<SymbolTagCapabilities>(tagSupportKey); }
void setSymbolTag(const SymbolTagCapabilities &symbolTag) { insert(tagSupportKey, symbolTag); }
void clearSymbolTag() { remove(tagSupportKey); }
std::optional<bool> hierarchicalDocumentSymbolSupport() const std::optional<bool> hierarchicalDocumentSymbolSupport() const
{ return optionalValue<bool>(hierarchicalDocumentSymbolSupportKey); } { return optionalValue<bool>(hierarchicalDocumentSymbolSupportKey); }
void setHierarchicalDocumentSymbolSupport(bool hierarchicalDocumentSymbolSupport) void setHierarchicalDocumentSymbolSupport(bool hierarchicalDocumentSymbolSupport)

View File

@@ -193,10 +193,12 @@ constexpr Key startKey{"start"};
constexpr Key supportedKey{"supported"}; constexpr Key supportedKey{"supported"};
constexpr Key symbolKey{"symbol"}; constexpr Key symbolKey{"symbol"};
constexpr Key symbolKindKey{"symbolKind"}; constexpr Key symbolKindKey{"symbolKind"};
constexpr Key symbolTagKey{"symbolTag"};
constexpr Key syncKindKey{"syncKind"}; constexpr Key syncKindKey{"syncKind"};
constexpr Key synchronizationKey{"synchronization"}; constexpr Key synchronizationKey{"synchronization"};
constexpr Key tabSizeKey{"tabSize"}; constexpr Key tabSizeKey{"tabSize"};
constexpr Key tagsKey{"tags"}; constexpr Key tagsKey{"tags"};
constexpr Key tagSupportKey{"tagSupport"};
constexpr Key targetKey{"target"}; constexpr Key targetKey{"target"};
constexpr Key textDocumentKey{"textDocument"}; constexpr Key textDocumentKey{"textDocument"};
constexpr Key textDocumentSyncKey{"textDocumentSync"}; constexpr Key textDocumentSyncKey{"textDocumentSync"};

View File

@@ -6,6 +6,7 @@
#include "languageserverprotocoltr.h" #include "languageserverprotocoltr.h"
#include "lsputils.h" #include "lsputils.h"
#include <utils/algorithm.h>
#include <utils/textutils.h> #include <utils/textutils.h>
#include <QFile> #include <QFile>
@@ -487,4 +488,27 @@ bool DeleteFileOperation::isValid() const
return contains(uriKey) && value(kindKey) == "delete"; return contains(uriKey) && value(kindKey) == "delete";
} }
namespace Internal {
std::optional<QList<SymbolTag>> getSymbolTags(const JsonObject &o)
{
const QJsonObject &obj = o;
const QJsonValue &val = obj.value(tagsKey);
if (val.isUndefined() || !val.isArray())
return std::nullopt;
return Utils::transform<QList<SymbolTag>>(val.toArray(), [](const QJsonValue &v) {
return static_cast<SymbolTag>(v.toInt());
});
}
} // namespace Internal
std::optional<QList<SymbolTag>> SymbolInformation::symbolTags() const
{
return Internal::getSymbolTags(*this);
}
std::optional<QList<SymbolTag>> DocumentSymbol::symbolTags() const
{
return Internal::getSymbolTags(*this);
}
} // namespace LanguageServerProtocol } // namespace LanguageServerProtocol

View File

@@ -574,6 +574,13 @@ public:
{ return contains(uriKey) && contains(nameKey); } { return contains(uriKey) && contains(nameKey); }
}; };
enum class SymbolTag {
Deprecated = 1,
};
namespace Internal {
std::optional<QList<SymbolTag>> getSymbolTags(const JsonObject &o);
} // namespace Internal
class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject
{ {
public: public:
@@ -585,6 +592,8 @@ public:
int kind() const { return typedValue<int>(kindKey); } int kind() const { return typedValue<int>(kindKey); }
void setKind(int kind) { insert(kindKey, kind); } void setKind(int kind) { insert(kindKey, kind); }
std::optional<QList<SymbolTag>> symbolTags() const;
std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); } std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); }
void clearDeprecated() { remove(deprecatedKey); } void clearDeprecated() { remove(deprecatedKey); }
@@ -616,6 +625,8 @@ public:
int kind() const { return typedValue<int>(kindKey); } int kind() const { return typedValue<int>(kindKey); }
void setKind(int kind) { insert(kindKey, kind); } void setKind(int kind) { insert(kindKey, kind); }
std::optional<QList<SymbolTag>> symbolTags() const;
std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); } std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); }
void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); }
void clearDeprecated() { remove(deprecatedKey); } void clearDeprecated() { remove(deprecatedKey); }
@@ -693,4 +704,4 @@ enum Kind {
}; };
} // namespace CompletionItemKind } // namespace CompletionItemKind
} // namespace LanguageClient } // namespace LanguageServerProtocol

View File

@@ -52,6 +52,8 @@ public:
{ {
switch (role) { switch (role) {
case Qt::DecorationRole: case Qt::DecorationRole:
if (m_item.symbolTags().value_or(QList<SymbolTag>()).contains(SymbolTag::Deprecated))
return Utils::Icons::WARNING.icon();
return symbolIcon(int(m_item.symbolKind())); return symbolIcon(int(m_item.symbolKind()));
case Qt::DisplayRole: case Qt::DisplayRole:
return m_item.name(); return m_item.name();
@@ -158,6 +160,8 @@ public:
{ {
switch (role) { switch (role) {
case Qt::DecorationRole: case Qt::DecorationRole:
if (m_item.symbolTags().value_or(QList<SymbolTag>()).contains(SymbolTag::Deprecated))
return Utils::Icons::WARNING.icon();
return symbolIcon(int(m_item.symbolKind())); return symbolIcon(int(m_item.symbolKind()));
case Qt::DisplayRole: case Qt::DisplayRole:
return m_item.name(); return m_item.name();

View File

@@ -437,6 +437,9 @@ static ClientCapabilities generateClientCapabilities()
SymbolKind::EnumMember, SymbolKind::Struct, SymbolKind::Event, SymbolKind::EnumMember, SymbolKind::Struct, SymbolKind::Event,
SymbolKind::Operator, SymbolKind::TypeParameter}); SymbolKind::Operator, SymbolKind::TypeParameter});
symbolCapabilities.setSymbolKind(symbolKindCapabilities); symbolCapabilities.setSymbolKind(symbolKindCapabilities);
SymbolCapabilities::SymbolTagCapabilities symbolTagCapabilities;
symbolTagCapabilities.setValueSet({SymbolTag::Deprecated});
symbolCapabilities.setSymbolTag(symbolTagCapabilities);
symbolCapabilities.setHierarchicalDocumentSymbolSupport(true); symbolCapabilities.setHierarchicalDocumentSymbolSupport(true);
documentCapabilities.setDocumentSymbol(symbolCapabilities); documentCapabilities.setDocumentSymbol(symbolCapabilities);