2
2
//! requests/replies and notifications back to the client.
3
3
use std:: {
4
4
fmt,
5
+ ops:: Deref ,
5
6
sync:: Arc ,
6
7
time:: { Duration , Instant } ,
7
8
} ;
8
9
9
10
use always_assert:: always;
10
11
use crossbeam_channel:: { select, Receiver } ;
11
- use ide_db:: base_db:: { SourceDatabaseExt , VfsPath } ;
12
+ use ide_db:: base_db:: { SourceDatabase , SourceDatabaseExt , VfsPath } ;
13
+ use itertools:: Itertools ;
12
14
use lsp_server:: { Connection , Notification , Request } ;
13
15
use lsp_types:: notification:: Notification as _;
14
16
use vfs:: { ChangeKind , FileId } ;
@@ -371,7 +373,7 @@ impl GlobalState {
371
373
let _p = profile:: span ( "GlobalState::handle_event/flycheck" ) ;
372
374
loop {
373
375
match task {
374
- flycheck:: Message :: AddDiagnostic { workspace_root, diagnostic } => {
376
+ flycheck:: Message :: AddDiagnostic { id , workspace_root, diagnostic } => {
375
377
let snap = self . snapshot ( ) ;
376
378
let diagnostics =
377
379
crate :: diagnostics:: to_proto:: map_rust_diagnostic_to_lsp (
@@ -383,6 +385,7 @@ impl GlobalState {
383
385
for diag in diagnostics {
384
386
match url_to_file_id ( & self . vfs . read ( ) . 0 , & diag. url ) {
385
387
Ok ( file_id) => self . diagnostics . add_check_diagnostic (
388
+ id,
386
389
file_id,
387
390
diag. diagnostic ,
388
391
diag. fix ,
@@ -400,7 +403,7 @@ impl GlobalState {
400
403
flycheck:: Message :: Progress { id, progress } => {
401
404
let ( state, message) = match progress {
402
405
flycheck:: Progress :: DidStart => {
403
- self . diagnostics . clear_check ( ) ;
406
+ self . diagnostics . clear_check ( id ) ;
404
407
( Progress :: Begin , None )
405
408
}
406
409
flycheck:: Progress :: DidCheckCrate ( target) => {
@@ -444,7 +447,10 @@ impl GlobalState {
444
447
let memdocs_added_or_removed = self . mem_docs . take_changes ( ) ;
445
448
446
449
if self . is_quiescent ( ) {
447
- if !was_quiescent {
450
+ if !was_quiescent
451
+ && !self . fetch_workspaces_queue . op_requested ( )
452
+ && !self . fetch_build_data_queue . op_requested ( )
453
+ {
448
454
for flycheck in & self . flycheck {
449
455
flycheck. update ( ) ;
450
456
}
@@ -734,13 +740,76 @@ impl GlobalState {
734
740
Ok ( ( ) )
735
741
} ) ?
736
742
. on :: < lsp_types:: notification:: DidSaveTextDocument > ( |this, params| {
737
- for flycheck in & this. flycheck {
738
- flycheck. update ( ) ;
743
+ let mut updated = false ;
744
+ if let Ok ( vfs_path) = from_proto:: vfs_path ( & params. text_document . uri ) {
745
+ let ( vfs, _) = & * this. vfs . read ( ) ;
746
+ if let Some ( file_id) = vfs. file_id ( & vfs_path) {
747
+ let analysis = this. analysis_host . analysis ( ) ;
748
+ // Crates containing or depending on the saved file
749
+ let crate_ids: Vec < _ > = analysis
750
+ . crate_for ( file_id) ?
751
+ . into_iter ( )
752
+ . flat_map ( |id| {
753
+ this. analysis_host
754
+ . raw_database ( )
755
+ . crate_graph ( )
756
+ . transitive_rev_deps ( id)
757
+ } )
758
+ . sorted ( )
759
+ . unique ( )
760
+ . collect ( ) ;
761
+
762
+ let crate_root_paths: Vec < _ > = crate_ids
763
+ . iter ( )
764
+ . filter_map ( |& crate_id| {
765
+ analysis
766
+ . crate_root ( crate_id)
767
+ . map ( |file_id| {
768
+ vfs. file_path ( file_id) . as_path ( ) . map ( ToOwned :: to_owned)
769
+ } )
770
+ . transpose ( )
771
+ } )
772
+ . collect :: < ide:: Cancellable < _ > > ( ) ?;
773
+ let crate_root_paths: Vec < _ > =
774
+ crate_root_paths. iter ( ) . map ( Deref :: deref) . collect ( ) ;
775
+
776
+ // Find all workspaces that have at least one target containing the saved file
777
+ let workspace_ids =
778
+ this. workspaces . iter ( ) . enumerate ( ) . filter ( |( _, ws) | match ws {
779
+ project_model:: ProjectWorkspace :: Cargo { cargo, .. } => {
780
+ cargo. packages ( ) . any ( |pkg| {
781
+ cargo[ pkg] . targets . iter ( ) . any ( |& it| {
782
+ crate_root_paths. contains ( & cargo[ it] . root . as_path ( ) )
783
+ } )
784
+ } )
785
+ }
786
+ project_model:: ProjectWorkspace :: Json { project, .. } => project
787
+ . crates ( )
788
+ . any ( |( c, _) | crate_ids. iter ( ) . any ( |& crate_id| crate_id == c) ) ,
789
+ project_model:: ProjectWorkspace :: DetachedFiles { .. } => false ,
790
+ } ) ;
791
+
792
+ // Find and trigger corresponding flychecks
793
+ for flycheck in & this. flycheck {
794
+ for ( id, _) in workspace_ids. clone ( ) {
795
+ if id == flycheck. id ( ) {
796
+ updated = true ;
797
+ flycheck. update ( ) ;
798
+ continue ;
799
+ }
800
+ }
801
+ }
802
+ }
803
+ if let Some ( abs_path) = vfs_path. as_path ( ) {
804
+ if reload:: should_refresh_for_change ( & abs_path, ChangeKind :: Modify ) {
805
+ this. fetch_workspaces_queue
806
+ . request_op ( format ! ( "DidSaveTextDocument {}" , abs_path. display( ) ) ) ;
807
+ }
808
+ }
739
809
}
740
- if let Ok ( abs_path) = from_proto:: abs_path ( & params. text_document . uri ) {
741
- if reload:: should_refresh_for_change ( & abs_path, ChangeKind :: Modify ) {
742
- this. fetch_workspaces_queue
743
- . request_op ( format ! ( "DidSaveTextDocument {}" , abs_path. display( ) ) ) ;
810
+ if !updated {
811
+ for flycheck in & this. flycheck {
812
+ flycheck. update ( ) ;
744
813
}
745
814
}
746
815
Ok ( ( ) )
0 commit comments