@@ -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,27 +141,25 @@ 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.
145
- /// - Returns: The snapshot of the document before the edit and the snapshot
146
- /// of the document after the edit .
144
+ /// - Returns: The snapshot of the document before the edit, the snapshot
145
+ /// of the document after the edit, and the edits. The edits are sequential, ie .
146
+ /// the edits are expected to be applied in order and later values in this array
147
+ /// assume that previous edits are already applied .
147
148
@discardableResult
148
149
public func edit(
149
150
_ uri: DocumentURI ,
150
151
newVersion: Int ,
151
- edits: [ TextDocumentContentChangeEvent ] ,
152
- willEditDocument: ( ( _ before: LineTable , TextDocumentContentChangeEvent ) -> Void ) ? = nil
153
- ) throws -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot ) {
152
+ edits: [ TextDocumentContentChangeEvent ]
153
+ ) throws -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot , edits: [ SourceEdit ] ) {
154
154
return try queue. sync {
155
155
guard let document = documents [ uri] else {
156
156
throw Error . missingDocument ( uri)
157
157
}
158
158
let preEditSnapshot = document. latestSnapshot
159
159
160
+ var sourceEdits : [ SourceEdit ] = [ ]
160
161
for edit in edits {
161
- if let willEditDocument {
162
- willEditDocument ( document. latestLineTable, edit)
163
- }
162
+ sourceEdits. append ( SourceEdit ( edit: edit, lineTableBeforeEdit: document. latestLineTable) )
164
163
165
164
if let range = edit. range {
166
165
document. latestLineTable. replace (
@@ -180,7 +179,7 @@ public final class DocumentManager {
180
179
logger. error ( " Document version did not increase on edit from \( document. latestVersion) to \( newVersion) " )
181
180
}
182
181
document. latestVersion = newVersion
183
- return ( preEditSnapshot, document. latestSnapshot)
182
+ return ( preEditSnapshot, document. latestSnapshot, sourceEdits )
184
183
}
185
184
}
186
185
@@ -214,19 +213,45 @@ extension DocumentManager {
214
213
}
215
214
}
216
215
217
- /// Convenience wrapper for `edit(_:newVersion:edits:willEditDocument: updateDocumentTokens:)`
216
+ /// Convenience wrapper for `edit(_:newVersion:edits:updateDocumentTokens:)`
218
217
/// that logs on failure.
219
218
@discardableResult
220
219
func edit(
221
- _ note: DidChangeTextDocumentNotification ,
222
- willEditDocument: ( ( _ before: LineTable , TextDocumentContentChangeEvent ) -> Void ) ? = nil
223
- ) -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot ) ? {
220
+ _ note: DidChangeTextDocumentNotification
221
+ ) -> ( preEditSnapshot: DocumentSnapshot , postEditSnapshot: DocumentSnapshot , edits: [ SourceEdit ] ) ? {
224
222
return orLog ( " failed to edit document " , level: . error) {
225
223
return try edit (
226
224
note. textDocument. uri,
227
225
newVersion: note. textDocument. version,
228
- edits: note. contentChanges,
229
- willEditDocument: willEditDocument
226
+ edits: note. contentChanges
227
+ )
228
+ }
229
+ }
230
+ }
231
+
232
+ fileprivate extension SourceEdit {
233
+ init ( edit: TextDocumentContentChangeEvent , lineTableBeforeEdit: LineTable ) {
234
+ if let range = edit. range {
235
+ guard
236
+ let offset = lineTableBeforeEdit. utf8OffsetOf (
237
+ line: range. lowerBound. line,
238
+ utf16Column: range. lowerBound. utf16index
239
+ ) ,
240
+ let end = lineTableBeforeEdit. utf8OffsetOf (
241
+ line: range. upperBound. line,
242
+ utf16Column: range. upperBound. utf16index
243
+ )
244
+ else {
245
+ fatalError ( " invalid edit \( range) " )
246
+ }
247
+ self . init (
248
+ range: AbsolutePosition ( utf8Offset: offset) ..< AbsolutePosition ( utf8Offset: end) ,
249
+ replacement: edit. text
250
+ )
251
+ } else {
252
+ self . init (
253
+ range: AbsolutePosition ( utf8Offset: 0 ) ..< AbsolutePosition ( utf8Offset: lineTableBeforeEdit. content. utf8. count) ,
254
+ replacement: edit. text
230
255
)
231
256
}
232
257
}
0 commit comments