Skip to content

Commit 5471f7e

Browse files
authored
Merge pull request #1105 from mustiikhalil/issue-939-refactor-will-edit-doc
Refactor willEditDocument in favor of SourceEdits
2 parents cbb5693 + f7f2cea commit 5471f7e

File tree

2 files changed

+52
-49
lines changed

2 files changed

+52
-49
lines changed

Sources/SourceKitLSP/DocumentManager.swift

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import Dispatch
1414
import LSPLogging
1515
import LanguageServerProtocol
1616
import SKSupport
17+
import SwiftSyntax
1718

1819
/// An immutable snapshot of a document at a given time.
1920
///
@@ -140,27 +141,25 @@ public final class DocumentManager {
140141
/// - newVersion: The new version of the document. Must be greater than the
141142
/// latest version of the document.
142143
/// - 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.
147148
@discardableResult
148149
public func edit(
149150
_ uri: DocumentURI,
150151
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]) {
154154
return try queue.sync {
155155
guard let document = documents[uri] else {
156156
throw Error.missingDocument(uri)
157157
}
158158
let preEditSnapshot = document.latestSnapshot
159159

160+
var sourceEdits: [SourceEdit] = []
160161
for edit in edits {
161-
if let willEditDocument {
162-
willEditDocument(document.latestLineTable, edit)
163-
}
162+
sourceEdits.append(SourceEdit(edit: edit, lineTableBeforeEdit: document.latestLineTable))
164163

165164
if let range = edit.range {
166165
document.latestLineTable.replace(
@@ -180,7 +179,7 @@ public final class DocumentManager {
180179
logger.error("Document version did not increase on edit from \(document.latestVersion) to \(newVersion)")
181180
}
182181
document.latestVersion = newVersion
183-
return (preEditSnapshot, document.latestSnapshot)
182+
return (preEditSnapshot, document.latestSnapshot, sourceEdits)
184183
}
185184
}
186185

@@ -214,19 +213,45 @@ extension DocumentManager {
214213
}
215214
}
216215

217-
/// Convenience wrapper for `edit(_:newVersion:edits:willEditDocument:updateDocumentTokens:)`
216+
/// Convenience wrapper for `edit(_:newVersion:edits:updateDocumentTokens:)`
218217
/// that logs on failure.
219218
@discardableResult
220219
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])? {
224222
return orLog("failed to edit document", level: .error) {
225223
return try edit(
226224
note.textDocument.uri,
227225
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
230255
)
231256
}
232257
}

Sources/SourceKitLSP/Swift/SwiftLanguageServer.swift

Lines changed: 10 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -497,33 +497,10 @@ extension SwiftLanguageServer {
497497
let replacement: String
498498
}
499499

500-
var edits: [Edit] = []
501-
502-
let editResult = self.documentManager.edit(note) {
503-
(before: LineTable, edit: TextDocumentContentChangeEvent) in
504-
if let range = edit.range {
505-
guard let offset = before.utf8OffsetOf(line: range.lowerBound.line, utf16Column: range.lowerBound.utf16index),
506-
let end = before.utf8OffsetOf(line: range.upperBound.line, utf16Column: range.upperBound.utf16index)
507-
else {
508-
fatalError("invalid edit \(range)")
509-
}
510-
edits.append(
511-
Edit(
512-
offset: offset,
513-
length: end - offset,
514-
replacement: edit.text
515-
)
516-
)
517-
} else {
518-
edits.append(
519-
Edit(
520-
offset: 0,
521-
length: before.content.utf8.count,
522-
replacement: edit.text
523-
)
524-
)
525-
}
500+
guard let (preEditSnapshot, postEditSnapshot, edits) = self.documentManager.edit(note) else {
501+
return
526502
}
503+
527504
for edit in edits {
528505
let req = sourcekitd.dictionary([
529506
keys.request: self.requests.editorReplaceText,
@@ -532,8 +509,8 @@ extension SwiftLanguageServer {
532509
keys.enableStructure: 0,
533510
keys.enableDiagnostics: 0,
534511
keys.syntacticOnly: 1,
535-
keys.offset: edit.offset,
536-
keys.length: edit.length,
512+
keys.offset: edit.range.lowerBound.utf8Offset,
513+
keys.length: edit.length.utf8Length,
537514
keys.sourceText: edit.replacement,
538515
])
539516
do {
@@ -543,12 +520,13 @@ extension SwiftLanguageServer {
543520
}
544521
}
545522

546-
guard let (preEditSnapshot, postEditSnapshot) = editResult else {
547-
return
548-
}
549523
let concurrentEdits = ConcurrentEdits(
550524
fromSequential: edits.map {
551-
IncrementalEdit(offset: $0.offset, length: $0.length, replacementLength: $0.replacement.utf8.count)
525+
IncrementalEdit(
526+
offset: $0.range.lowerBound.utf8Offset,
527+
length: $0.length.utf8Length,
528+
replacementLength: $0.replacement.utf8.count
529+
)
552530
}
553531
)
554532
await syntaxTreeManager.registerEdit(

0 commit comments

Comments
 (0)