Skip to content

Commit ca80ff3

Browse files
authored
Merge pull request #1992 from ahoppen/in-process-cancellation
Support cancellation of requests in `InProcessClient`
2 parents b3ac424 + 632accb commit ca80ff3

File tree

1 file changed

+30
-5
lines changed

1 file changed

+30
-5
lines changed

Sources/InProcessClient/InProcessSourceKitLSPClient.swift

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,41 @@ public final class InProcessSourceKitLSPClient: Sendable {
9292
/// necessary and the response of the request is not awaited, use the version of the function that takes a
9393
/// completion handler
9494
public func send<R: RequestType>(_ request: R) async throws -> R.Response {
95-
return try await withCheckedThrowingContinuation { continuation in
96-
self.send(request) {
97-
continuation.resume(with: $0)
95+
let requestId = ThreadSafeBox<RequestID?>(initialValue: nil)
96+
return try await withTaskCancellationHandler {
97+
return try await withCheckedThrowingContinuation { continuation in
98+
if Task.isCancelled {
99+
// Check if the task has been cancelled before we send the request to LSP to avoid any kind of work if
100+
// possible.
101+
return continuation.resume(throwing: CancellationError())
102+
}
103+
requestId.value = self.send(request) {
104+
continuation.resume(with: $0)
105+
}
106+
if Task.isCancelled, let requestId = requestId.takeValue() {
107+
// The task might have been cancelled after the above cancellation check but before `requestId` was assigned
108+
// a value. To cover that case, check for cancellation here again. Note that we won't cancel twice from here
109+
// and the `onCancel` handler because we take the request ID out of the `ThreadSafeBox` before sending the
110+
// `CancelRequestNotification`.
111+
self.send(CancelRequestNotification(id: requestId))
112+
}
113+
}
114+
} onCancel: {
115+
if let requestId = requestId.takeValue() {
116+
self.send(CancelRequestNotification(id: requestId))
98117
}
99118
}
100119
}
101120

102121
/// Send the request to `server` and return the request result via a completion handler.
103-
public func send<R: RequestType>(_ request: R, reply: @Sendable @escaping (LSPResult<R.Response>) -> Void) {
104-
server.handle(request, id: .number(Int(nextRequestID.fetchAndIncrement())), reply: reply)
122+
@discardableResult
123+
public func send<R: RequestType>(
124+
_ request: R,
125+
reply: @Sendable @escaping (LSPResult<R.Response>) -> Void
126+
) -> RequestID {
127+
let requestID = RequestID.number(Int(nextRequestID.fetchAndIncrement()))
128+
server.handle(request, id: requestID, reply: reply)
129+
return requestID
105130
}
106131

107132
/// Send the notification to `server`.

0 commit comments

Comments
 (0)