@@ -22,6 +22,19 @@ final class WorkDoneProgressManager {
22
22
private let token : ProgressToken
23
23
private let queue = AsyncQueue < Serial > ( )
24
24
private let server : SourceKitLSPServer
25
+ /// `true` if the client returned without an error from the `CreateWorkDoneProgressRequest`.
26
+ ///
27
+ /// Since all work done progress reports are being sent on `queue`, we never access it in a state where the
28
+ /// `CreateWorkDoneProgressRequest` is still in progress.
29
+ ///
30
+ /// Must be a reference because `deinit` captures it and wants to observe changes to it from `init` eg. in the
31
+ /// following:
32
+ /// - `init` is called
33
+ /// - `deinit` is called
34
+ /// - The task from `init` gets executed
35
+ /// - The task from `deinit` gets executed
36
+ /// - This should have `workDoneProgressCreated == true` so that it can send the work progress end.
37
+ private let workDoneProgressCreated : ThreadSafeBox < Bool > & AnyObject = ThreadSafeBox < Bool > ( initialValue: false )
25
38
26
39
convenience init ? ( server: SourceKitLSPServer , title: String , message: String ? = nil , percentage: Int ? = nil ) async {
27
40
guard let capabilityRegistry = await server. capabilityRegistry else {
@@ -42,25 +55,29 @@ final class WorkDoneProgressManager {
42
55
}
43
56
self . token = . string( " WorkDoneProgress- \( UUID ( ) ) " )
44
57
self . server = server
45
- queue. async { [ server, token] in
58
+ queue. async { [ server, token, workDoneProgressCreated ] in
46
59
await server. waitUntilInitialized ( )
47
- await withCheckedContinuation { ( continuation : CheckedContinuation < Void , Never > ) in
48
- _ = server. client. send ( CreateWorkDoneProgressRequest ( token: token) ) { result in
49
- continuation . resume ( )
50
- }
60
+ do {
61
+ _ = try await server. client. send ( CreateWorkDoneProgressRequest ( token: token) )
62
+ } catch {
63
+ return
51
64
}
52
- await server. sendNotificationToClient (
65
+ server. sendNotificationToClient (
53
66
WorkDoneProgress (
54
67
token: token,
55
68
value: . begin( WorkDoneProgressBegin ( title: title, message: message, percentage: percentage) )
56
69
)
57
70
)
71
+ workDoneProgressCreated. value = true
58
72
}
59
73
}
60
74
61
75
func update( message: String ? = nil , percentage: Int ? = nil ) {
62
- queue. async { [ server, token] in
63
- await server. sendNotificationToClient (
76
+ queue. async { [ server, token, workDoneProgressCreated] in
77
+ guard workDoneProgressCreated. value else {
78
+ return
79
+ }
80
+ server. sendNotificationToClient (
64
81
WorkDoneProgress (
65
82
token: token,
66
83
value: . report( WorkDoneProgressReport ( cancellable: false , message: message, percentage: percentage) )
@@ -70,8 +87,11 @@ final class WorkDoneProgressManager {
70
87
}
71
88
72
89
deinit {
73
- queue. async { [ server, token] in
74
- await server. sendNotificationToClient ( WorkDoneProgress ( token: token, value: . end( WorkDoneProgressEnd ( ) ) ) )
90
+ queue. async { [ server, token, workDoneProgressCreated] in
91
+ guard workDoneProgressCreated. value else {
92
+ return
93
+ }
94
+ server. sendNotificationToClient ( WorkDoneProgress ( token: token, value: . end( WorkDoneProgressEnd ( ) ) ) )
75
95
}
76
96
}
77
97
}
0 commit comments