Skip to content

Commit 94a64f8

Browse files
committed
Store the replacement string in IncrementalEdit
IIRC the main reason that `IncrementalEdit` didn’t contain the replacement string was that the edits needed to be transferred over XPC at some point and transferring strings over XPC is always a little tricky. Since the actual contents weren’t actually needed, the actual contents weren’t actually needed. I would like to use `ConcurrentEdits(fromSequential:)` in SourceKit-LSP and for that I need the actual replacement contents. Instead of rolling our own sequential to concurrent replacement (which is non-trivial), let’s re-use the one in SwiftSyntax.
1 parent 25ce3a2 commit 94a64f8

File tree

5 files changed

+119
-94
lines changed

5 files changed

+119
-94
lines changed

Sources/SwiftParser/IncrementalParseTransition.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -347,17 +347,22 @@ public struct ConcurrentEdits: Sendable {
347347
if existingEdit.replacementRange.intersectsOrTouches(editToAdd.range) {
348348
let intersectionLength =
349349
existingEdit.replacementRange.intersected(editToAdd.range).length
350+
let replacement: [UInt8]
351+
replacement =
352+
existingEdit.replacement.prefix(max(0, editToAdd.offset - existingEdit.replacementRange.offset))
353+
+ editToAdd.replacement
354+
+ existingEdit.replacement.suffix(max(0, existingEdit.replacementRange.endOffset - editToAdd.endOffset))
350355
editToAdd = IncrementalEdit(
351356
offset: Swift.min(existingEdit.offset, editToAdd.offset),
352357
length: existingEdit.length + editToAdd.length - intersectionLength,
353-
replacementLength: existingEdit.replacementLength + editToAdd.replacementLength - intersectionLength
358+
replacement: replacement
354359
)
355360
editIndicesMergedWithNewEdit.append(index)
356361
} else if existingEdit.offset < editToAdd.endOffset {
357362
editToAdd = IncrementalEdit(
358363
offset: editToAdd.offset - existingEdit.replacementLength + existingEdit.length,
359364
length: editToAdd.length,
360-
replacementLength: editToAdd.replacementLength
365+
replacement: editToAdd.replacement
361366
)
362367
}
363368
}

Sources/SwiftSyntax/Utils.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,12 @@ public struct ByteSourceRange: Equatable, Sendable {
5050
public struct IncrementalEdit: Equatable, Sendable {
5151
/// The byte range of the original source buffer that the edit applies to.
5252
public let range: ByteSourceRange
53+
54+
/// The UTF-8 bytes that should be inserted as part of the edit
55+
public let replacement: [UInt8]
56+
5357
/// The length of the edit replacement in UTF8 bytes.
54-
public let replacementLength: Int
58+
public var replacementLength: Int { replacement.count }
5559

5660
public var offset: Int { return range.offset }
5761

@@ -64,14 +68,25 @@ public struct IncrementalEdit: Equatable, Sendable {
6468
return ByteSourceRange(offset: offset, length: replacementLength)
6569
}
6670

71+
@available(*, deprecated, message: "Use IncrementalEdit(range:replacement:) instead")
6772
public init(range: ByteSourceRange, replacementLength: Int) {
6873
self.range = range
69-
self.replacementLength = replacementLength
74+
self.replacement = Array(repeating: UInt8(ascii: " "), count: replacementLength)
7075
}
7176

77+
@available(*, deprecated, message: "Use IncrementalEdit(offset:length:replacement:) instead")
7278
public init(offset: Int, length: Int, replacementLength: Int) {
7379
self.range = ByteSourceRange(offset: offset, length: length)
74-
self.replacementLength = replacementLength
80+
self.replacement = Array(repeating: UInt8(ascii: " "), count: replacementLength)
81+
}
82+
83+
public init(offset: Int, length: Int, replacement: [UInt8]) {
84+
self.range = ByteSourceRange(offset: offset, length: length)
85+
self.replacement = replacement
86+
}
87+
88+
public init(offset: Int, length: Int, replacement: String) {
89+
self.init(offset: offset, length: length, replacement: Array(replacement.utf8))
7590
}
7691

7792
public func intersectsOrTouchesRange(_ other: ByteSourceRange) -> Bool {

Sources/_SwiftSyntaxTestSupport/IncrementalParseTestUtils.swift

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,7 @@ public func extractEditsAndSources(from source: String) -> (edits: ConcurrentEdi
182182
from: source.index(after: startIndex),
183183
to: separateIndex
184184
),
185-
replacementLength: source.utf8.distance(
186-
from: source.index(after: separateIndex),
187-
to: endIndex
188-
)
185+
replacement: Array(source.utf8[source.index(after: separateIndex)..<endIndex])
189186
)
190187
originalSource += source[source.index(after: startIndex)..<separateIndex]
191188

@@ -213,12 +210,8 @@ public func extractEditsAndSources(from source: String) -> (edits: ConcurrentEdi
213210
public func applyEdits(
214211
_ edits: [IncrementalEdit],
215212
concurrent: Bool,
216-
to testString: String,
217-
replacementChar: Character = "?"
213+
to testString: String
218214
) -> String {
219-
guard let replacementAscii = replacementChar.asciiValue else {
220-
fatalError("replacementChar must be an ASCII character")
221-
}
222215
var edits = edits
223216
if concurrent {
224217
XCTAssert(ConcurrentEdits._isValidConcurrentEditArray(edits))
@@ -232,7 +225,7 @@ public func applyEdits(
232225
for edit in edits {
233226
assert(edit.endOffset <= bytes.count)
234227
bytes.removeSubrange(edit.offset..<edit.endOffset)
235-
bytes.insert(contentsOf: [UInt8](repeating: replacementAscii, count: edit.replacementLength), at: edit.offset)
228+
bytes.insert(contentsOf: edit.replacement, at: edit.offset)
236229
}
237230
return String(bytes: bytes, encoding: .utf8)!
238231
}

0 commit comments

Comments
 (0)