@@ -14,6 +14,7 @@ import Dispatch
14
14
import LSPLogging
15
15
import LanguageServerProtocol
16
16
import SKSupport
17
+ import SwiftSyntax
17
18
18
19
/// An immutable snapshot of a document at a given time.
19
20
///
@@ -140,26 +141,27 @@ public final class DocumentManager {
140
141
/// - newVersion: The new version of the document. Must be greater than the
141
142
/// latest version of the document.
142
143
/// - edits: The edits to apply to the document
143
- /// - willEditDocument: Optional closure to call before each edit . Will be
144
- /// called multiple times if there are multiple edits.
144
+ /// - requiresUpcomingEdits: Flag to return upcoming editst . Will be
145
+ /// calling ``willEditDocument`` for each edit made
145
146
/// - Returns: The snapshot of the document before the edit and the snapshot
146
- /// of the document after the edit.
147
+ /// of the document after the edit, including all edits that were made .
147
148
@discardableResult
148
149
public func edit(
149
150
_ uri: DocumentURI ,
150
151
newVersion: Int ,
151
152
edits: [ TextDocumentContentChangeEvent ] ,
152
- willEditDocument : ( ( _ before : LineTable , TextDocumentContentChangeEvent ) -> Void ) ? = nil
153
- ) throws -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot ) {
153
+ requiresUpcomingEdits : Bool = false
154
+ ) throws -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot , edits : [ SourceEdit ] ) {
154
155
return try queue. sync {
155
156
guard let document = documents [ uri] else {
156
157
throw Error . missingDocument ( uri)
157
158
}
158
159
let preEditSnapshot = document. latestSnapshot
159
160
161
+ var upcomingEdits : [ SourceEdit ] = [ ]
160
162
for edit in edits {
161
- if let willEditDocument {
162
- willEditDocument ( document. latestLineTable, edit)
163
+ if requiresUpcomingEdits {
164
+ upcomingEdits . append ( willEditDocument ( document. latestLineTable, edit: edit ) )
163
165
}
164
166
165
167
if let range = edit. range {
@@ -180,7 +182,7 @@ public final class DocumentManager {
180
182
logger. error ( " Document version did not increase on edit from \( document. latestVersion) to \( newVersion) " )
181
183
}
182
184
document. latestVersion = newVersion
183
- return ( preEditSnapshot, document. latestSnapshot)
185
+ return ( preEditSnapshot, document. latestSnapshot, upcomingEdits )
184
186
}
185
187
}
186
188
@@ -192,6 +194,35 @@ public final class DocumentManager {
192
194
return document. latestSnapshot
193
195
}
194
196
}
197
+
198
+ private func willEditDocument( _ before: LineTable , edit: TextDocumentContentChangeEvent ) -> SourceEdit {
199
+ guard let range = edit. range else {
200
+ return SourceEdit (
201
+ range: Range (
202
+ uncheckedBounds: (
203
+ AbsolutePosition ( utf8Offset: 0 ) ,
204
+ upper: AbsolutePosition ( utf8Offset: before. content. utf8. count)
205
+ )
206
+ ) ,
207
+ replacement: edit. text
208
+ )
209
+ }
210
+ guard let offset = before. utf8OffsetOf ( line: range. lowerBound. line, utf16Column: range. lowerBound. utf16index) ,
211
+ let end = before. utf8OffsetOf ( line: range. upperBound. line, utf16Column: range. upperBound. utf16index)
212
+ else {
213
+ fatalError ( " invalid edit \( range) " )
214
+ }
215
+ return SourceEdit (
216
+ range: Range (
217
+ uncheckedBounds: (
218
+ AbsolutePosition ( utf8Offset: offset) ,
219
+ upper: AbsolutePosition ( utf8Offset: end)
220
+ )
221
+ ) ,
222
+ replacement: edit. text
223
+ )
224
+ }
225
+
195
226
}
196
227
197
228
extension DocumentManager {
@@ -214,19 +245,19 @@ extension DocumentManager {
214
245
}
215
246
}
216
247
217
- /// Convenience wrapper for `edit(_:newVersion:edits:willEditDocument :updateDocumentTokens:)`
248
+ /// Convenience wrapper for `edit(_:newVersion:edits:requiresUpcomingEdits :updateDocumentTokens:)`
218
249
/// that logs on failure.
219
250
@discardableResult
220
251
func edit(
221
252
_ note: DidChangeTextDocumentNotification ,
222
- willEditDocument : ( ( _ before : LineTable , TextDocumentContentChangeEvent ) -> Void ) ? = nil
223
- ) -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot ) ? {
253
+ requiresUpcomingEdits : Bool = false
254
+ ) -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot , edits : [ SourceEdit ] ) ? {
224
255
return orLog ( " failed to edit document " , level: . error) {
225
256
return try edit (
226
257
note. textDocument. uri,
227
258
newVersion: note. textDocument. version,
228
259
edits: note. contentChanges,
229
- willEditDocument : willEditDocument
260
+ requiresUpcomingEdits : requiresUpcomingEdits
230
261
)
231
262
}
232
263
}
0 commit comments