@@ -22,16 +22,17 @@ use span;
22
22
use Span ;
23
23
24
24
use actions:: post_build:: { BuildResults , PostBuildHandler , DiagnosticsNotifier } ;
25
- use actions:: notifications:: { PublishDiagnostics , Progress } ;
25
+ use actions:: notifications:: { PublishDiagnostics , Progress , ShowMessage } ;
26
26
use build:: * ;
27
27
use lsp_data;
28
28
use lsp_data:: * ;
29
+ use ls_types:: MessageType ;
29
30
use server:: { Output , Notification } ;
30
31
31
32
use std:: collections:: HashMap ;
32
33
use std:: path:: { Path , PathBuf } ;
33
34
use std:: sync:: { Arc , Mutex } ;
34
- use std:: sync:: atomic:: { AtomicUsize , Ordering } ;
35
+ use std:: sync:: atomic:: { AtomicUsize , AtomicBool , Ordering } ;
35
36
use std:: thread;
36
37
37
38
@@ -119,6 +120,7 @@ pub struct InitActionContext {
119
120
current_project : PathBuf ,
120
121
121
122
previous_build_results : Arc < Mutex < BuildResults > > ,
123
+ previous_was_build_error : Arc < AtomicBool > ,
122
124
build_queue : BuildQueue ,
123
125
// Keep a record of builds/post-build tasks currently in flight so that
124
126
// mutating actions can block until the data is ready.
@@ -165,6 +167,7 @@ impl InitActionContext {
165
167
config,
166
168
current_project,
167
169
previous_build_results : Arc :: new ( Mutex :: new ( HashMap :: new ( ) ) ) ,
170
+ previous_was_build_error : Arc :: new ( AtomicBool :: new ( false ) ) ,
168
171
build_queue,
169
172
active_build_count : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
170
173
client_capabilities : Arc :: new ( client_capabilities) ,
@@ -219,6 +222,10 @@ impl InitActionContext {
219
222
out : O ,
220
223
active_build_count : Arc < AtomicUsize > ,
221
224
progress_params : ProgressParams ,
225
+ // shared bool in the entire context
226
+ previous_was_build_error : Arc < AtomicBool > ,
227
+ // whether this current build encountered an error.
228
+ current_is_build_error : AtomicBool ,
222
229
}
223
230
224
231
// base progress parameters for notification of the analysis.
@@ -235,11 +242,39 @@ impl InitActionContext {
235
242
fn notify_publish_diagnostics ( & self , params : PublishDiagnosticsParams ) {
236
243
self . out . notify ( Notification :: < PublishDiagnostics > :: new ( params) ) ;
237
244
}
245
+ fn notify_build_error ( & self , message : String ) {
246
+ // This current build is definitely an error. Mark it and
247
+ // propagate to the shrared state in notify_end_diagnostics()
248
+ self . current_is_build_error . store ( true , Ordering :: SeqCst ) ;
249
+
250
+ // We only want to notify a build error to the user one time,
251
+ // not on every keystroke. As long as a previous build error
252
+ // hasn't cleared, we stay silent.
253
+ if !self . previous_was_build_error . load ( Ordering :: SeqCst ) {
254
+ let params = ShowMessageParams {
255
+ typ : MessageType :: Error ,
256
+ message,
257
+ } ;
258
+ self . out . notify ( Notification :: < ShowMessage > :: new ( params) ) ;
259
+ }
260
+ }
238
261
fn notify_end_diagnostics ( & self ) {
239
262
self . active_build_count . fetch_sub ( 1 , Ordering :: SeqCst ) ;
240
263
let mut params = self . progress_params . clone ( ) ;
241
264
params. done = Some ( true ) ;
242
265
self . out . notify ( Notification :: < Progress > :: new ( params) ) ;
266
+
267
+ // If the diagnostics for this build were fully reported without
268
+ // any current_is_build_error, we know the build is clear, and
269
+ // that is propagated to the shared previous_was_build_error.
270
+ //
271
+ // This is not perfectly thread safe. There's a chance two threads
272
+ // may be in contention propagating the local current_is_build_error
273
+ // to the shared previous_was_build_error. Whether this happens
274
+ // in practice is to be seen...
275
+ let is_build_error = self . current_is_build_error . load ( Ordering :: SeqCst ) ;
276
+ self . previous_was_build_error
277
+ . compare_and_swap ( !is_build_error, is_build_error, Ordering :: SeqCst ) ;
243
278
}
244
279
}
245
280
@@ -287,6 +322,8 @@ impl InitActionContext {
287
322
out : out. clone ( ) ,
288
323
active_build_count : self . active_build_count . clone ( ) ,
289
324
progress_params : diganostics_progress_params,
325
+ previous_was_build_error : self . previous_was_build_error . clone ( ) ,
326
+ current_is_build_error : AtomicBool :: new ( false ) ,
290
327
} ) ,
291
328
blocked_threads : vec ! [ ] ,
292
329
}
0 commit comments