@@ -58,6 +58,84 @@ enum LanguageServerType: Hashable {
58
58
}
59
59
}
60
60
61
+ /// Keeps track of the state to send work done progress updates to the client
62
+ final class WorkDoneProgressState {
63
+ private enum State {
64
+ /// No `WorkDoneProgress` has been created.
65
+ case noProgress
66
+ /// We have sent the request to create a `WorkDoneProgress` but haven’t received a respose yet.
67
+ case creating
68
+ /// A `WorkDoneProgress` has been created.
69
+ case created
70
+ /// The creation of a `WorkDoneProgress has failed`.
71
+ ///
72
+ /// This causes us to just give up creating any more `WorkDoneProgress` in
73
+ /// the future as those will most likely also fail.
74
+ case progressCreationFailed
75
+ }
76
+
77
+ /// How many active tasks are running.
78
+ ///
79
+ /// A work done progress should be displayed if activeTasks > 0
80
+ private var activeTasks : Int = 0
81
+ private var state : State = . noProgress
82
+
83
+ /// The token by which we track the `WorkDoneProgress`.
84
+ private let token : ProgressToken
85
+
86
+ /// The title that should be displayed to the user in the UI.
87
+ private let title : String
88
+
89
+ init ( _ token: String , title: String ) {
90
+ self . token = ProgressToken . string ( token)
91
+ self . title = title
92
+ }
93
+
94
+ /// Start a new task, creating a new `WorkDoneProgress` if none is running right now.
95
+ ///
96
+ /// - Parameter server: The server that is used to create the `WorkDoneProgress` on the client
97
+ ///
98
+ /// - Important: Must be called on `server.queue`.
99
+ func startProgress( server: SourceKitServer ) {
100
+ dispatchPrecondition ( condition: . onQueue( server. queue) )
101
+ activeTasks += 1
102
+ if state == . noProgress {
103
+ state = . creating
104
+ // Discard the handle. We don't support cancellation of the creation of a work done progress.
105
+ _ = server. client. send ( CreateWorkDoneProgressRequest ( token: token) , queue: server. queue) { result in
106
+ if result. success != nil {
107
+ if self . activeTasks == 0 {
108
+ // ActiveTasks might have been decreased while we created the `WorkDoneProgress`
109
+ self . state = . noProgress
110
+ server. client. send ( WorkDoneProgress ( token: self . token, value: . end( WorkDoneProgressEnd ( ) ) ) )
111
+ } else {
112
+ self . state = . created
113
+ server. client. send ( WorkDoneProgress ( token: self . token, value: . begin( WorkDoneProgressBegin ( title: self . title) ) ) )
114
+ }
115
+ } else {
116
+ self . state = . progressCreationFailed
117
+ }
118
+ }
119
+ }
120
+ }
121
+
122
+ /// End a new task stated using `startProgress`.
123
+ ///
124
+ /// If this drops the active task count to 0, the work done progress is ended on the client.
125
+ ///
126
+ /// - Parameter server: The server that is used to send and update of the `WorkDoneProgress` to the client
127
+ ///
128
+ /// - Important: Must be called on `server.queue`.
129
+ func endProgress( server: SourceKitServer ) {
130
+ dispatchPrecondition ( condition: . onQueue( server. queue) )
131
+ assert ( activeTasks > 0 , " Unbalanced startProgress/endProgress calls " )
132
+ activeTasks -= 1
133
+ if state == . created && activeTasks == 0 {
134
+ server. client. send ( WorkDoneProgress ( token: token, value: . end( WorkDoneProgressEnd ( ) ) ) )
135
+ }
136
+ }
137
+ }
138
+
61
139
/// The SourceKit language server.
62
140
///
63
141
/// This is the client-facing language server implementation, providing indexing, multiple-toolchain
@@ -80,6 +158,8 @@ public final class SourceKitServer: LanguageServer {
80
158
81
159
private let documentManager = DocumentManager ( )
82
160
161
+ private var packageLoadingWorkDoneProgress = WorkDoneProgressState ( " SourceKitLSP.SoruceKitServer.reloadPackage " , title: " Reloading Package " )
162
+
83
163
/// **Public for testing**
84
164
public var _documentManager : DocumentManager {
85
165
return documentManager
@@ -559,7 +639,18 @@ extension SourceKitServer {
559
639
capabilityRegistry: capabilityRegistry,
560
640
toolchainRegistry: self . toolchainRegistry,
561
641
buildSetup: self . options. buildSetup,
562
- indexOptions: self . options. indexOptions)
642
+ indexOptions: self . options. indexOptions,
643
+ reloadPackageStatusCallback: { status in
644
+ self . queue. async {
645
+ switch status {
646
+ case . start:
647
+ self . packageLoadingWorkDoneProgress. startProgress ( server: self )
648
+ case . end:
649
+ self . packageLoadingWorkDoneProgress. endProgress ( server: self )
650
+ }
651
+ }
652
+ }
653
+ )
563
654
}
564
655
565
656
func initialize( _ req: Request < InitializeRequest > ) {
0 commit comments