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