@@ -16,38 +16,240 @@ public struct WorkspaceEdit: Hashable, ResponseType {
16
16
/// The edits to be applied to existing resources.
17
17
public var changes : [ DocumentURI : [ TextEdit ] ] ?
18
18
19
- public init ( changes: [ DocumentURI : [ TextEdit ] ] ? ) {
19
+ public var documentChanges : [ WorkspaceEditDocumentChange ] ?
20
+
21
+ public init ( changes: [ DocumentURI : [ TextEdit ] ] ? = nil , documentChanges: [ WorkspaceEditDocumentChange ] ? = nil ) {
20
22
self . changes = changes
23
+ self . documentChanges = documentChanges
21
24
}
22
25
}
23
26
24
27
// Workaround for Codable not correctly encoding dictionaries whose keys aren't strings.
25
28
extension WorkspaceEdit : Codable {
26
29
private enum CodingKeys : String , CodingKey {
27
30
case changes
31
+ case documentChanges
28
32
}
29
33
30
34
public init ( from decoder: Decoder ) throws {
31
35
let container = try decoder. container ( keyedBy: CodingKeys . self)
32
- let changesDict = try container. decode ( [ String : [ TextEdit ] ] . self, forKey: . changes)
33
- var changes = [ DocumentURI: [ TextEdit] ] ( )
34
- for change in changesDict {
35
- let uri = DocumentURI ( string: change. key)
36
- changes [ uri] = change. value
36
+ if let changesDict = try container. decodeIfPresent ( [ String : [ TextEdit ] ] . self, forKey: . changes) {
37
+ var changes = [ DocumentURI: [ TextEdit] ] ( )
38
+ for change in changesDict {
39
+ let uri = DocumentURI ( string: change. key)
40
+ changes [ uri] = change. value
41
+ }
42
+ self . changes = changes
43
+ } else {
44
+ self . changes = nil
37
45
}
38
- self . changes = changes
46
+ self . documentChanges = try container . decodeIfPresent ( [ WorkspaceEditDocumentChange ] . self , forKey : . documentChanges )
39
47
}
40
48
41
49
public func encode( to encoder: Encoder ) throws {
42
- guard let changes = changes else {
43
- return
50
+ var container = encoder. container ( keyedBy: CodingKeys . self)
51
+ if let changes = changes {
52
+ var stringDictionary = [ String: [ TextEdit] ] ( )
53
+ for (key, value) in changes {
54
+ stringDictionary [ key. stringValue] = value
55
+ }
56
+ try container. encodeIfPresent ( stringDictionary, forKey: . changes)
57
+ }
58
+ try container. encodeIfPresent ( documentChanges, forKey: . documentChanges)
59
+ }
60
+ }
61
+
62
+ public enum WorkspaceEditDocumentChange : Codable , Hashable {
63
+ case textDocumentEdit( TextDocumentEdit )
64
+ case createFile( CreateFile )
65
+ case renameFile( RenameFile )
66
+ case deleteFile( DeleteFile )
67
+
68
+ public init ( from decoder: Decoder ) throws {
69
+ if let edit = try ? TextDocumentEdit ( from: decoder) {
70
+ self = . textDocumentEdit( edit)
71
+ } else if let createFile = try ? CreateFile ( from: decoder) {
72
+ self = . createFile( createFile)
73
+ } else if let renameFile = try ? RenameFile ( from: decoder) {
74
+ self = . renameFile( renameFile)
75
+ } else if let deleteFile = try ? DeleteFile ( from: decoder) {
76
+ self = . deleteFile( deleteFile)
77
+ } else {
78
+ let context = DecodingError . Context ( codingPath: decoder. codingPath, debugDescription: " Could neither decode WorkspaceEditDocumentChange as TextDocumentEdit, nor CreateFile, nor RenameFile, nor DeleteFile " )
79
+ throw DecodingError . dataCorrupted ( context)
80
+ }
81
+ }
82
+
83
+ public func encode( to encoder: Encoder ) throws {
84
+ switch self {
85
+ case . textDocumentEdit( let textDocumentEdit) :
86
+ try textDocumentEdit. encode ( to: encoder)
87
+ case . createFile( let createFile) :
88
+ try createFile. encode ( to: encoder)
89
+ case . renameFile( let renameFile) :
90
+ try renameFile. encode ( to: encoder)
91
+ case . deleteFile( let deleteFile) :
92
+ try deleteFile. encode ( to: encoder)
93
+ }
94
+ }
95
+ }
96
+
97
+ /// Options to create a file.
98
+ public struct CreateFileOptions : Codable , Hashable {
99
+ /// Overwrite existing file. Overwrite wins over `ignoreIfExists`
100
+ public var overwrite : Bool ?
101
+ /// Ignore if exists.
102
+ public var ignoreIfExists : Bool ?
103
+
104
+ public init ( overwrite: Bool ? = nil , ignoreIfExists: Bool ? = nil ) {
105
+ self . overwrite = overwrite
106
+ self . ignoreIfExists = ignoreIfExists
107
+ }
108
+ }
109
+
110
+ /// Create file operation
111
+ public struct CreateFile : Codable , Hashable {
112
+ /// The resource to create.
113
+ public var uri : DocumentURI
114
+ /// Additional options
115
+ public var options : CreateFileOptions ?
116
+
117
+ public init ( uri: DocumentURI , options: CreateFileOptions ? = nil ) {
118
+ self . uri = uri
119
+ self . options = options
120
+ }
121
+
122
+ // MARK: Codable conformance
123
+
124
+ public enum CodingKeys : String , CodingKey {
125
+ case kind
126
+ case uri
127
+ case options
128
+ }
129
+
130
+ public init ( from decoder: Decoder ) throws {
131
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
132
+ let kind = try container. decode ( String . self, forKey: . kind)
133
+ guard kind == " create " else {
134
+ throw DecodingError . dataCorruptedError ( forKey: . kind, in: container, debugDescription: " Kind of CreateFile is not 'create' " )
135
+ }
136
+ self . uri = try container. decode ( DocumentURI . self, forKey: . uri)
137
+ self . options = try container. decodeIfPresent ( CreateFileOptions . self, forKey: . options)
138
+ }
139
+
140
+ public func encode( to encoder: Encoder ) throws {
141
+ var container = encoder. container ( keyedBy: CodingKeys . self)
142
+ try container. encode ( " create " , forKey: . kind)
143
+ try container. encode ( self . uri, forKey: . uri)
144
+ try container. encodeIfPresent ( self . options, forKey: . options)
145
+ }
146
+ }
147
+
148
+ /// Rename file options
149
+ public struct RenameFileOptions : Codable , Hashable {
150
+ /// Overwrite target if existing. Overwrite wins over `ignoreIfExists`
151
+ public var overwrite : Bool ?
152
+ /// Ignores if target exists.
153
+ public var ignoreIfExists : Bool ?
154
+
155
+ public init ( overwrite: Bool ? = nil , ignoreIfExists: Bool ? = nil ) {
156
+ self . overwrite = overwrite
157
+ self . ignoreIfExists = ignoreIfExists
158
+ }
159
+ }
160
+
161
+ /// Rename file operation
162
+ public struct RenameFile : Codable , Hashable {
163
+ /// The old (existing) location.
164
+ public var oldUri : DocumentURI
165
+ /// The new location.
166
+ public var newUri : DocumentURI
167
+ /// Rename options.
168
+ public var options : RenameFileOptions ?
169
+
170
+ public init ( oldUri: DocumentURI , newUri: DocumentURI , options: RenameFileOptions ? = nil ) {
171
+ self . oldUri = oldUri
172
+ self . newUri = newUri
173
+ self . options = options
174
+ }
175
+
176
+ // MARK: Codable conformance
177
+
178
+ public enum CodingKeys : String , CodingKey {
179
+ case kind
180
+ case oldUri
181
+ case newUri
182
+ case options
183
+ }
184
+
185
+ public init ( from decoder: Decoder ) throws {
186
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
187
+ let kind = try container. decode ( String . self, forKey: . kind)
188
+ guard kind == " rename " else {
189
+ throw DecodingError . dataCorruptedError ( forKey: . kind, in: container, debugDescription: " Kind of RenameFile is not 'rename' " )
44
190
}
45
- var stringDictionary = [ String: [ TextEdit] ] ( )
46
- for (key, value) in changes {
47
- stringDictionary [ key. stringValue] = value
191
+ self . oldUri = try container. decode ( DocumentURI . self, forKey: . oldUri)
192
+ self . newUri = try container. decode ( DocumentURI . self, forKey: . newUri)
193
+ self . options = try container. decodeIfPresent ( RenameFileOptions . self, forKey: . options)
194
+ }
195
+
196
+ public func encode( to encoder: Encoder ) throws {
197
+ var container = encoder. container ( keyedBy: CodingKeys . self)
198
+ try container. encode ( " rename " , forKey: . kind)
199
+ try container. encode ( self . oldUri, forKey: . oldUri)
200
+ try container. encode ( self . newUri, forKey: . newUri)
201
+ try container. encodeIfPresent ( self . options, forKey: . options)
202
+ }
203
+ }
204
+
205
+ /// Delete file options
206
+ public struct DeleteFileOptions : Codable , Hashable {
207
+ /// Delete the content recursively if a folder is denoted.
208
+ public var recursive : Bool ?
209
+ /// Ignore the operation if the file doesn't exist.
210
+ public var ignoreIfNotExists : Bool ?
211
+
212
+ public init ( recursive: Bool ? = nil , ignoreIfNotExists: Bool ? = nil ) {
213
+ self . recursive = recursive
214
+ self . ignoreIfNotExists = ignoreIfNotExists
215
+ }
216
+ }
217
+
218
+ /// Delete file operation
219
+ public struct DeleteFile : Codable , Hashable {
220
+ /// The file to delete.
221
+ public var uri : DocumentURI
222
+ /// Delete options.
223
+ public var options : DeleteFileOptions ?
224
+
225
+ public init ( uri: DocumentURI , options: DeleteFileOptions ? = nil ) {
226
+ self . uri = uri
227
+ self . options = options
228
+ }
229
+
230
+ // MARK: Codable conformance
231
+
232
+ public enum CodingKeys : String , CodingKey {
233
+ case kind
234
+ case uri
235
+ case options
236
+ }
237
+
238
+ public init ( from decoder: Decoder ) throws {
239
+ let container = try decoder. container ( keyedBy: CodingKeys . self)
240
+ let kind = try container. decode ( String . self, forKey: . kind)
241
+ guard kind == " delete " else {
242
+ throw DecodingError . dataCorruptedError ( forKey: . kind, in: container, debugDescription: " Kind of DeleteFile is not 'delete' " )
48
243
}
244
+ self . uri = try container. decode ( DocumentURI . self, forKey: . uri)
245
+ self . options = try container. decodeIfPresent ( DeleteFileOptions . self, forKey: . options)
246
+ }
247
+
248
+ public func encode( to encoder: Encoder ) throws {
49
249
var container = encoder. container ( keyedBy: CodingKeys . self)
50
- try container. encode ( stringDictionary, forKey: . changes)
250
+ try container. encode ( " delete " , forKey: . kind)
251
+ try container. encode ( self . uri, forKey: . uri)
252
+ try container. encodeIfPresent ( self . options, forKey: . options)
51
253
}
52
254
}
53
255
0 commit comments