diff --git a/src/libs/languageserverprotocol/callhierarchy.cpp b/src/libs/languageserverprotocol/callhierarchy.cpp index 4b19d71fa82..49b789c28ac 100644 --- a/src/libs/languageserverprotocol/callhierarchy.cpp +++ b/src/libs/languageserverprotocol/callhierarchy.cpp @@ -25,4 +25,9 @@ CallHierarchyOutgoingCallsRequest::CallHierarchyOutgoingCallsRequest( : Request(methodName, params) {} +std::optional> CallHierarchyItem::symbolTags() const +{ + return Internal::getSymbolTags(*this); +} + } // namespace LanguageServerProtocol diff --git a/src/libs/languageserverprotocol/callhierarchy.h b/src/libs/languageserverprotocol/callhierarchy.h index 1cc022d6d1f..27e241b8ba9 100644 --- a/src/libs/languageserverprotocol/callhierarchy.h +++ b/src/libs/languageserverprotocol/callhierarchy.h @@ -18,6 +18,8 @@ public: SymbolKind symbolKind() const { return SymbolKind(typedValue(kindKey)); } void setSymbolKind(const SymbolKind &symbolKind) { insert(kindKey, int(symbolKind)); } + std::optional> symbolTags() const; + Range range() const { return typedValue(rangeKey); } void setRange(const Range &range) { insert(rangeKey, range); } diff --git a/src/libs/languageserverprotocol/clientcapabilities.cpp b/src/libs/languageserverprotocol/clientcapabilities.cpp index acae7ad554a..60ea4523fd8 100644 --- a/src/libs/languageserverprotocol/clientcapabilities.cpp +++ b/src/libs/languageserverprotocol/clientcapabilities.cpp @@ -19,6 +19,20 @@ void SymbolCapabilities::SymbolKindCapabilities::setValueSet(const QList(valueSet)); } +std::optional > SymbolCapabilities::SymbolTagCapabilities::valueSet() const +{ + if (std::optional> array = optionalArray(valueSetKey)) { + return std::make_optional( + Utils::transform(*array, [](int value) { return static_cast(value); })); + } + return std::nullopt; +} + +void SymbolCapabilities::SymbolTagCapabilities::setValueSet(const QList &valueSet) +{ + insert(valueSetKey, enumArrayToJsonArray(valueSet)); +} + WorkspaceClientCapabilities::WorkspaceClientCapabilities() { setWorkspaceFolders(true); diff --git a/src/libs/languageserverprotocol/clientcapabilities.h b/src/libs/languageserverprotocol/clientcapabilities.h index 367e1b3fe4c..b2311d7e726 100644 --- a/src/libs/languageserverprotocol/clientcapabilities.h +++ b/src/libs/languageserverprotocol/clientcapabilities.h @@ -131,12 +131,31 @@ public: 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> valueSet() const; + void setValueSet(const QList &valueSet); + void clearValueSet() { remove(valueSetKey); } + }; + // Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. std::optional symbolKind() const { return optionalValue(symbolKindKey); } void setSymbolKind(const SymbolKindCapabilities &symbolKind) { insert(symbolKindKey, symbolKind); } void clearSymbolKind() { remove(symbolKindKey); } + std::optional symbolTag() const + { return optionalValue(tagSupportKey); } + void setSymbolTag(const SymbolTagCapabilities &symbolTag) { insert(tagSupportKey, symbolTag); } + void clearSymbolTag() { remove(tagSupportKey); } + std::optional hierarchicalDocumentSymbolSupport() const { return optionalValue(hierarchicalDocumentSymbolSupportKey); } void setHierarchicalDocumentSymbolSupport(bool hierarchicalDocumentSymbolSupport) diff --git a/src/libs/languageserverprotocol/jsonkeys.h b/src/libs/languageserverprotocol/jsonkeys.h index 236d28bfda1..c2b5e545f29 100644 --- a/src/libs/languageserverprotocol/jsonkeys.h +++ b/src/libs/languageserverprotocol/jsonkeys.h @@ -193,10 +193,12 @@ constexpr Key startKey{"start"}; constexpr Key supportedKey{"supported"}; constexpr Key symbolKey{"symbol"}; constexpr Key symbolKindKey{"symbolKind"}; +constexpr Key symbolTagKey{"symbolTag"}; constexpr Key syncKindKey{"syncKind"}; constexpr Key synchronizationKey{"synchronization"}; constexpr Key tabSizeKey{"tabSize"}; constexpr Key tagsKey{"tags"}; +constexpr Key tagSupportKey{"tagSupport"}; constexpr Key targetKey{"target"}; constexpr Key textDocumentKey{"textDocument"}; constexpr Key textDocumentSyncKey{"textDocumentSync"}; diff --git a/src/libs/languageserverprotocol/lsptypes.cpp b/src/libs/languageserverprotocol/lsptypes.cpp index ddd9b0e66c0..cb327642e36 100644 --- a/src/libs/languageserverprotocol/lsptypes.cpp +++ b/src/libs/languageserverprotocol/lsptypes.cpp @@ -6,6 +6,7 @@ #include "languageserverprotocoltr.h" #include "lsputils.h" +#include #include #include @@ -487,4 +488,27 @@ bool DeleteFileOperation::isValid() const return contains(uriKey) && value(kindKey) == "delete"; } +namespace Internal { +std::optional> 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>(val.toArray(), [](const QJsonValue &v) { + return static_cast(v.toInt()); + }); +} +} // namespace Internal + +std::optional> SymbolInformation::symbolTags() const +{ + return Internal::getSymbolTags(*this); +} + +std::optional> DocumentSymbol::symbolTags() const +{ + return Internal::getSymbolTags(*this); +} } // namespace LanguageServerProtocol diff --git a/src/libs/languageserverprotocol/lsptypes.h b/src/libs/languageserverprotocol/lsptypes.h index ae19f36145b..6e25fcb49d0 100644 --- a/src/libs/languageserverprotocol/lsptypes.h +++ b/src/libs/languageserverprotocol/lsptypes.h @@ -574,6 +574,13 @@ public: { return contains(uriKey) && contains(nameKey); } }; +enum class SymbolTag { + Deprecated = 1, +}; +namespace Internal { +std::optional> getSymbolTags(const JsonObject &o); +} // namespace Internal + class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject { public: @@ -585,6 +592,8 @@ public: int kind() const { return typedValue(kindKey); } void setKind(int kind) { insert(kindKey, kind); } + std::optional> symbolTags() const; + std::optional deprecated() const { return optionalValue(deprecatedKey); } void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } void clearDeprecated() { remove(deprecatedKey); } @@ -616,6 +625,8 @@ public: int kind() const { return typedValue(kindKey); } void setKind(int kind) { insert(kindKey, kind); } + std::optional> symbolTags() const; + std::optional deprecated() const { return optionalValue(deprecatedKey); } void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } void clearDeprecated() { remove(deprecatedKey); } @@ -693,4 +704,4 @@ enum Kind { }; } // namespace CompletionItemKind -} // namespace LanguageClient +} // namespace LanguageServerProtocol diff --git a/src/plugins/languageclient/callhierarchy.cpp b/src/plugins/languageclient/callhierarchy.cpp index 32023e6a98f..dcb47f595ee 100644 --- a/src/plugins/languageclient/callhierarchy.cpp +++ b/src/plugins/languageclient/callhierarchy.cpp @@ -52,6 +52,8 @@ public: { switch (role) { case Qt::DecorationRole: + if (m_item.symbolTags().value_or(QList()).contains(SymbolTag::Deprecated)) + return Utils::Icons::WARNING.icon(); return symbolIcon(int(m_item.symbolKind())); case Qt::DisplayRole: return m_item.name(); @@ -158,6 +160,8 @@ public: { switch (role) { case Qt::DecorationRole: + if (m_item.symbolTags().value_or(QList()).contains(SymbolTag::Deprecated)) + return Utils::Icons::WARNING.icon(); return symbolIcon(int(m_item.symbolKind())); case Qt::DisplayRole: return m_item.name(); diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index 1b16e9dfb00..15a71adae37 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -437,6 +437,9 @@ static ClientCapabilities generateClientCapabilities() SymbolKind::EnumMember, SymbolKind::Struct, SymbolKind::Event, SymbolKind::Operator, SymbolKind::TypeParameter}); symbolCapabilities.setSymbolKind(symbolKindCapabilities); + SymbolCapabilities::SymbolTagCapabilities symbolTagCapabilities; + symbolTagCapabilities.setValueSet({SymbolTag::Deprecated}); + symbolCapabilities.setSymbolTag(symbolTagCapabilities); symbolCapabilities.setHierarchicalDocumentSymbolSupport(true); documentCapabilities.setDocumentSymbol(symbolCapabilities);