Skip to content

Commit b7cc49b

Browse files
Decode RegistrationOptions (#980)
1 parent 49d4db3 commit b7cc49b

File tree

5 files changed

+377
-72
lines changed

5 files changed

+377
-72
lines changed

Sources/LanguageServerProtocol/SupportTypes/LSPAny.swift

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,5 +171,15 @@ extension Array: LSPAnyCodable where Element: LSPAnyCodable {
171171
}
172172
}
173173

174+
extension String: LSPAnyCodable {
175+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
176+
nil
177+
}
178+
179+
public func encodeToLSPAny() -> LSPAny {
180+
.string(self)
181+
}
182+
}
183+
174184
public typealias LSPObject = [String: LSPAny]
175185
public typealias LSPArray = [LSPAny]

Sources/LanguageServerProtocol/SupportTypes/RegistrationOptions.swift

Lines changed: 145 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,8 @@ import Foundation
1414

1515
/// Protocol for capability registration options, which must be encodable to
1616
/// `LSPAny` so they can be included in a `Registration`.
17-
public protocol RegistrationOptions: Hashable {
18-
func encodeIntoLSPAny(dict: inout [String: LSPAny])
19-
}
17+
public protocol RegistrationOptions: Hashable, LSPAnyCodable {
2018

21-
fileprivate func encode(strings: [String]) -> LSPAny {
22-
var values = [LSPAny]()
23-
values.reserveCapacity(strings.count)
24-
for str in strings {
25-
values.append(.string(str))
26-
}
27-
return .array(values)
2819
}
2920

3021
/// General text document registration options.
@@ -37,9 +28,20 @@ public struct TextDocumentRegistrationOptions: RegistrationOptions, Hashable {
3728
self.documentSelector = documentSelector
3829
}
3930

40-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
41-
guard let documentSelector = documentSelector else { return }
42-
dict["documentSelector"] = documentSelector.encodeToLSPAny()
31+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
32+
if let value = dictionary["documentSelector"] {
33+
self.documentSelector = DocumentSelector(fromLSPArray: value)
34+
} else {
35+
self.documentSelector = nil
36+
}
37+
}
38+
39+
public func encodeToLSPAny() -> LSPAny {
40+
guard let documentSelector = documentSelector else {
41+
return .dictionary([:])
42+
}
43+
44+
return .dictionary(["documentSelector": documentSelector.encodeToLSPAny()])
4345
}
4446
}
4547

@@ -59,18 +61,32 @@ public struct CompletionRegistrationOptions: RegistrationOptions, TextDocumentRe
5961
self.completionOptions = completionOptions
6062
}
6163

62-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
63-
textDocumentRegistrationOptions.encodeIntoLSPAny(dict: &dict)
64+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
65+
guard let completionOptions = CompletionOptions(fromLSPDictionary: dictionary) else {
66+
return nil
67+
}
6468

65-
if let resolveProvider = completionOptions.resolveProvider {
66-
dict["resolveProvider"] = .bool(resolveProvider)
69+
self.completionOptions = completionOptions
70+
71+
guard let textDocumentRegistrationOptions = TextDocumentRegistrationOptions(fromLSPDictionary: dictionary) else {
72+
return nil
6773
}
68-
if let triggerCharacters = completionOptions.triggerCharacters {
69-
dict["triggerCharacters"] = encode(strings: triggerCharacters)
74+
75+
self.textDocumentRegistrationOptions = textDocumentRegistrationOptions
76+
}
77+
78+
public func encodeToLSPAny() -> LSPAny {
79+
var dict: [String: LSPAny] = [:]
80+
81+
if case .dictionary(let dictionary) = completionOptions.encodeToLSPAny() {
82+
dict.merge(dictionary) { (current, _) in current }
7083
}
71-
if let allCommitCharacters = completionOptions.allCommitCharacters {
72-
dict["allCommitCharacters"] = encode(strings: allCommitCharacters)
84+
85+
if case .dictionary(let dictionary) = textDocumentRegistrationOptions.encodeToLSPAny() {
86+
dict.merge(dictionary) { (current, _) in current }
7387
}
88+
89+
return .dictionary(dict)
7490
}
7591
}
7692

@@ -85,8 +101,19 @@ public struct FoldingRangeRegistrationOptions: RegistrationOptions, TextDocument
85101
self.foldingRangeOptions = foldingRangeOptions
86102
}
87103

88-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
89-
textDocumentRegistrationOptions.encodeIntoLSPAny(dict: &dict)
104+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
105+
guard let textDocumentRegistrationOptions = TextDocumentRegistrationOptions(fromLSPDictionary: dictionary) else {
106+
return nil
107+
}
108+
109+
self.textDocumentRegistrationOptions = textDocumentRegistrationOptions
110+
111+
/// Currently empty in the spec.
112+
self.foldingRangeOptions = FoldingRangeOptions()
113+
}
114+
115+
public func encodeToLSPAny() -> LSPAny {
116+
textDocumentRegistrationOptions.encodeToLSPAny()
90117
// foldingRangeOptions is currently empty.
91118
}
92119
}
@@ -106,34 +133,32 @@ public struct SemanticTokensRegistrationOptions: RegistrationOptions, TextDocume
106133
self.semanticTokenOptions = semanticTokenOptions
107134
}
108135

109-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
110-
textDocumentRegistrationOptions.encodeIntoLSPAny(dict: &dict)
111-
let legend = semanticTokenOptions.legend
112-
dict["legend"] = .dictionary([
113-
"tokenTypes": encode(strings: legend.tokenTypes),
114-
"tokenModifiers": encode(strings: legend.tokenModifiers),
115-
])
116-
if let range = semanticTokenOptions.range {
117-
let encodedRange: LSPAny
118-
switch range {
119-
case .bool(let value): encodedRange = .bool(value)
120-
case .value(_): encodedRange = .dictionary([:])
121-
}
122-
dict["range"] = encodedRange
123-
}
124-
if let full = semanticTokenOptions.full {
125-
let encodedFull: LSPAny
126-
switch full {
127-
case .bool(let value): encodedFull = .bool(value)
128-
case .value(let fullOptions):
129-
var encodedOptions: [String: LSPAny] = [:]
130-
if let delta = fullOptions.delta {
131-
encodedOptions["delta"] = .bool(delta)
132-
}
133-
encodedFull = .dictionary(encodedOptions)
134-
}
135-
dict["full"] = encodedFull
136+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
137+
guard let textDocumentRegistrationOptions = TextDocumentRegistrationOptions(fromLSPDictionary: dictionary) else {
138+
return nil
139+
}
140+
141+
self.textDocumentRegistrationOptions = textDocumentRegistrationOptions
142+
143+
guard let semanticTokenOptions = SemanticTokensOptions(fromLSPDictionary: dictionary) else {
144+
return nil
136145
}
146+
147+
self.semanticTokenOptions = semanticTokenOptions
148+
}
149+
150+
public func encodeToLSPAny() -> LSPAny {
151+
var dict: [String: LSPAny] = [:]
152+
153+
if case .dictionary(let dictionary) = textDocumentRegistrationOptions.encodeToLSPAny() {
154+
dict.merge(dictionary) { (current, _) in current }
155+
}
156+
157+
if case .dictionary(let dictionary) = semanticTokenOptions.encodeToLSPAny() {
158+
dict.merge(dictionary) { (current, _) in current }
159+
}
160+
161+
return .dictionary(dict)
137162
}
138163
}
139164

@@ -149,11 +174,32 @@ public struct InlayHintRegistrationOptions: RegistrationOptions, TextDocumentReg
149174
self.inlayHintOptions = inlayHintOptions
150175
}
151176

152-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
153-
textDocumentRegistrationOptions.encodeIntoLSPAny(dict: &dict)
177+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
178+
self.inlayHintOptions = InlayHintOptions()
179+
180+
if case .bool(let resolveProvider) = dictionary["resolveProvider"] {
181+
self.inlayHintOptions.resolveProvider = resolveProvider
182+
}
183+
184+
guard let textDocumentRegistrationOptions = TextDocumentRegistrationOptions(fromLSPDictionary: dictionary) else {
185+
return nil
186+
}
187+
188+
self.textDocumentRegistrationOptions = textDocumentRegistrationOptions
189+
}
190+
191+
public func encodeToLSPAny() -> LSPAny {
192+
var dict: [String: LSPAny] = [:]
193+
154194
if let resolveProvider = inlayHintOptions.resolveProvider {
155195
dict["resolveProvider"] = .bool(resolveProvider)
156196
}
197+
198+
if case .dictionary(let dictionary) = textDocumentRegistrationOptions.encodeToLSPAny() {
199+
dict.merge(dictionary) { (current, _) in current }
200+
}
201+
202+
return .dictionary(dict)
157203
}
158204
}
159205

@@ -170,9 +216,29 @@ public struct DiagnosticRegistrationOptions: RegistrationOptions, TextDocumentRe
170216
self.diagnosticOptions = diagnosticOptions
171217
}
172218

173-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
174-
textDocumentRegistrationOptions.encodeIntoLSPAny(dict: &dict)
175-
diagnosticOptions.encodeIntoLSPAny(dict: &dict)
219+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
220+
guard let textDocumentRegistrationOptions = TextDocumentRegistrationOptions(fromLSPDictionary: dictionary) else {
221+
return nil
222+
}
223+
224+
self.textDocumentRegistrationOptions = textDocumentRegistrationOptions
225+
226+
guard let diagnosticOptions = DiagnosticOptions(fromLSPDictionary: dictionary) else {
227+
return nil
228+
}
229+
self.diagnosticOptions = diagnosticOptions
230+
}
231+
232+
public func encodeToLSPAny() -> LSPAny {
233+
var dict: [String: LSPAny] = [:]
234+
if case .dictionary(let dictionary) = textDocumentRegistrationOptions.encodeToLSPAny() {
235+
dict.merge(dictionary) { (current, _) in current }
236+
}
237+
238+
if case .dictionary(let dictionary) = diagnosticOptions.encodeToLSPAny() {
239+
dict.merge(dictionary) { (current, _) in current }
240+
}
241+
return .dictionary(dict)
176242
}
177243
}
178244

@@ -185,8 +251,18 @@ public struct DidChangeWatchedFilesRegistrationOptions: RegistrationOptions {
185251
self.watchers = watchers
186252
}
187253

188-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
189-
dict["watchers"] = watchers.encodeToLSPAny()
254+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
255+
guard let watchersArray = dictionary["watchers"],
256+
let watchers = [FileSystemWatcher](fromLSPArray: watchersArray)
257+
else {
258+
return nil
259+
}
260+
261+
self.watchers = watchers
262+
}
263+
264+
public func encodeToLSPAny() -> LSPAny {
265+
.dictionary(["watchers": watchers.encodeToLSPAny()])
190266
}
191267
}
192268

@@ -199,7 +275,17 @@ public struct ExecuteCommandRegistrationOptions: RegistrationOptions {
199275
self.commands = commands
200276
}
201277

202-
public func encodeIntoLSPAny(dict: inout [String: LSPAny]) {
203-
dict["commands"] = encode(strings: commands)
278+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
279+
guard let commandsArray = dictionary["commands"],
280+
let commands = [String](fromLSPArray: commandsArray)
281+
else {
282+
return nil
283+
}
284+
285+
self.commands = commands
286+
}
287+
288+
public func encodeToLSPAny() -> LSPAny {
289+
.dictionary(["commands": commands.encodeToLSPAny()])
204290
}
205291
}

Sources/LanguageServerProtocol/SupportTypes/SemanticTokens.swift

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
/// The legend for a server's encoding of semantic tokens.
14-
public struct SemanticTokensLegend: Codable, Hashable {
14+
public struct SemanticTokensLegend: Codable, Hashable, LSPAnyCodable {
1515
/// The token types for a server.
1616
///
1717
/// Token types are looked up by indexing into this array, e.g. a `tokenType`
@@ -31,6 +31,29 @@ public struct SemanticTokensLegend: Codable, Hashable {
3131
self.tokenTypes = tokenTypes
3232
self.tokenModifiers = tokenModifiers
3333
}
34+
35+
public init?(fromLSPDictionary dictionary: [String: LSPAny]) {
36+
self.tokenTypes = []
37+
if let tokenTypesAny = dictionary["tokenTypes"],
38+
let tokenTypes = [String](fromLSPArray: tokenTypesAny)
39+
{
40+
self.tokenTypes = tokenTypes
41+
}
42+
43+
self.tokenModifiers = []
44+
if let tokenModifiersAny = dictionary["tokenModifiers"],
45+
let tokenModifiers = [String](fromLSPArray: tokenModifiersAny)
46+
{
47+
self.tokenModifiers = tokenModifiers
48+
}
49+
}
50+
51+
public func encodeToLSPAny() -> LSPAny {
52+
.dictionary([
53+
"tokenTypes": tokenTypes.encodeToLSPAny(),
54+
"tokenModifiers": tokenModifiers.encodeToLSPAny(),
55+
])
56+
}
3457
}
3558

3659
/// The encoding format for semantic tokens. Currently only `relative` is supported.

0 commit comments

Comments
 (0)