55// Copyright (c) 2018, Olof Kraigher olof.kraigher@gmail.com
66
77mod completion;
8+ mod diagnostics;
89mod lifecycle;
910mod rename;
1011mod text_document;
@@ -13,7 +14,6 @@ mod workspace;
1314use lsp_types:: * ;
1415
1516use fnv:: FnvHashMap ;
16- use std:: collections:: hash_map:: Entry ;
1717use vhdl_lang:: ast:: ObjectClass ;
1818
1919use crate :: rpc_channel:: SharedRpcChannel ;
@@ -22,8 +22,8 @@ use std::io;
2222use std:: io:: ErrorKind ;
2323use std:: path:: { Path , PathBuf } ;
2424use vhdl_lang:: {
25- AnyEntKind , Concurrent , Config , Diagnostic , EntHierarchy , EntRef , Message , MessageHandler ,
26- Object , Overloaded , Project , Severity , SeverityMap , SrcPos , Token , Type , VHDLStandard ,
25+ AnyEntKind , Concurrent , Config , EntHierarchy , EntRef , Message , MessageHandler , Object ,
26+ Overloaded , Project , SeverityMap , SrcPos , Token , Type , VHDLStandard ,
2727} ;
2828
2929/// Defines how the language server handles files
@@ -61,7 +61,7 @@ pub struct VHDLServer {
6161 // To have well defined unit tests that are not affected by environment
6262 use_external_config : bool ,
6363 project : Project ,
64- files_with_notifications : FnvHashMap < Url , ( ) > ,
64+ diagnostic_cache : FnvHashMap < Url , Vec < vhdl_lang :: Diagnostic > > ,
6565 init_params : Option < InitializeParams > ,
6666 config_file : Option < PathBuf > ,
6767 severity_map : SeverityMap ,
@@ -75,7 +75,7 @@ impl VHDLServer {
7575 settings,
7676 use_external_config : true ,
7777 project : Project :: new ( VHDLStandard :: default ( ) ) ,
78- files_with_notifications : FnvHashMap :: default ( ) ,
78+ diagnostic_cache : FnvHashMap :: default ( ) ,
7979 init_params : None ,
8080 config_file : None ,
8181 severity_map : SeverityMap :: default ( ) ,
@@ -90,7 +90,7 @@ impl VHDLServer {
9090 settings : Default :: default ( ) ,
9191 use_external_config,
9292 project : Project :: new ( VHDLStandard :: default ( ) ) ,
93- files_with_notifications : FnvHashMap :: default ( ) ,
93+ diagnostic_cache : Default :: default ( ) ,
9494 init_params : None ,
9595 config_file : None ,
9696 severity_map : SeverityMap :: default ( ) ,
@@ -230,56 +230,6 @@ impl VHDLServer {
230230 try_fun ( ) . unwrap_or ( false )
231231 }
232232
233- fn publish_diagnostics ( & mut self ) {
234- let diagnostics = self . project . analyse ( ) ;
235-
236- if self . settings . no_lint {
237- return ;
238- }
239-
240- let supports_related_information = self . client_supports_related_information ( ) ;
241- let diagnostics = {
242- if supports_related_information {
243- diagnostics
244- } else {
245- flatten_related ( diagnostics)
246- }
247- } ;
248-
249- let mut files_with_notifications = std:: mem:: take ( & mut self . files_with_notifications ) ;
250- for ( file_uri, diagnostics) in diagnostics_by_uri ( diagnostics) . into_iter ( ) {
251- let lsp_diagnostics = diagnostics
252- . into_iter ( )
253- . filter_map ( |diag| to_lsp_diagnostic ( diag, & self . severity_map ) )
254- . collect ( ) ;
255-
256- let publish_diagnostics = PublishDiagnosticsParams {
257- uri : file_uri. clone ( ) ,
258- diagnostics : lsp_diagnostics,
259- version : None ,
260- } ;
261-
262- self . rpc
263- . send_notification ( "textDocument/publishDiagnostics" , publish_diagnostics) ;
264-
265- self . files_with_notifications . insert ( file_uri. clone ( ) , ( ) ) ;
266- }
267-
268- for ( file_uri, _) in files_with_notifications. drain ( ) {
269- // File has no longer any diagnostics, publish empty notification to clear them
270- if !self . files_with_notifications . contains_key ( & file_uri) {
271- let publish_diagnostics = PublishDiagnosticsParams {
272- uri : file_uri. clone ( ) ,
273- diagnostics : vec ! [ ] ,
274- version : None ,
275- } ;
276-
277- self . rpc
278- . send_notification ( "textDocument/publishDiagnostics" , publish_diagnostics) ;
279- }
280- }
281- }
282-
283233 pub fn document_symbol ( & self , params : & DocumentSymbolParams ) -> Option < DocumentSymbolResponse > {
284234 let source = self
285235 . project
@@ -449,32 +399,6 @@ fn from_lsp_range(range: lsp_types::Range) -> vhdl_lang::Range {
449399 }
450400}
451401
452- fn diagnostics_by_uri ( diagnostics : Vec < Diagnostic > ) -> FnvHashMap < Url , Vec < Diagnostic > > {
453- let mut map: FnvHashMap < Url , Vec < Diagnostic > > = FnvHashMap :: default ( ) ;
454-
455- for diagnostic in diagnostics {
456- let uri = file_name_to_uri ( diagnostic. pos . source . file_name ( ) ) ;
457- match map. entry ( uri) {
458- Entry :: Occupied ( mut entry) => entry. get_mut ( ) . push ( diagnostic) ,
459- Entry :: Vacant ( entry) => {
460- let vec = vec ! [ diagnostic] ;
461- entry. insert ( vec) ;
462- }
463- }
464- }
465-
466- map
467- }
468-
469- fn flatten_related ( diagnostics : Vec < Diagnostic > ) -> Vec < Diagnostic > {
470- let mut flat_diagnostics = Vec :: new ( ) ;
471- for mut diagnostic in diagnostics {
472- flat_diagnostics. extend ( diagnostic. drain_related ( ) ) ;
473- flat_diagnostics. push ( diagnostic) ;
474- }
475- flat_diagnostics
476- }
477-
478402fn file_name_to_uri ( file_name : & Path ) -> Url {
479403 // @TODO return error to client
480404 Url :: from_file_path ( file_name) . unwrap ( )
@@ -485,45 +409,6 @@ fn uri_to_file_name(uri: &Url) -> PathBuf {
485409 uri. to_file_path ( ) . unwrap ( )
486410}
487411
488- fn to_lsp_diagnostic (
489- diagnostic : Diagnostic ,
490- severity_map : & SeverityMap ,
491- ) -> Option < lsp_types:: Diagnostic > {
492- let severity = match severity_map[ diagnostic. code ] ? {
493- Severity :: Error => DiagnosticSeverity :: ERROR ,
494- Severity :: Warning => DiagnosticSeverity :: WARNING ,
495- Severity :: Info => DiagnosticSeverity :: INFORMATION ,
496- Severity :: Hint => DiagnosticSeverity :: HINT ,
497- } ;
498-
499- let related_information = if !diagnostic. related . is_empty ( ) {
500- let mut related_information = Vec :: new ( ) ;
501- for ( pos, msg) in diagnostic. related {
502- let uri = file_name_to_uri ( pos. source . file_name ( ) ) ;
503- related_information. push ( DiagnosticRelatedInformation {
504- location : Location {
505- uri : uri. to_owned ( ) ,
506- range : to_lsp_range ( pos. range ( ) ) ,
507- } ,
508- message : msg,
509- } )
510- }
511- Some ( related_information)
512- } else {
513- None
514- } ;
515-
516- Some ( lsp_types:: Diagnostic {
517- range : to_lsp_range ( diagnostic. pos . range ( ) ) ,
518- severity : Some ( severity) ,
519- code : Some ( NumberOrString :: String ( format ! ( "{}" , diagnostic. code) ) ) ,
520- source : Some ( "vhdl ls" . to_owned ( ) ) ,
521- message : diagnostic. message ,
522- related_information,
523- ..Default :: default ( )
524- } )
525- }
526-
527412fn overloaded_kind ( overloaded : & Overloaded ) -> SymbolKind {
528413 match overloaded {
529414 Overloaded :: SubprogramDecl ( _) => SymbolKind :: FUNCTION ,
@@ -615,7 +500,7 @@ mod tests {
615500 use super :: * ;
616501 use crate :: rpc_channel:: test_support:: * ;
617502
618- fn initialize_server ( server : & mut VHDLServer , root_uri : Url ) {
503+ pub ( crate ) fn initialize_server ( server : & mut VHDLServer , root_uri : Url ) {
619504 let capabilities = ClientCapabilities :: default ( ) ;
620505
621506 #[ allow( deprecated) ]
@@ -636,13 +521,13 @@ mod tests {
636521 server. initialized_notification ( ) ;
637522 }
638523
639- fn temp_root_uri ( ) -> ( tempfile:: TempDir , Url ) {
524+ pub ( crate ) fn temp_root_uri ( ) -> ( tempfile:: TempDir , Url ) {
640525 let tempdir = tempfile:: tempdir ( ) . unwrap ( ) ;
641526 let root_uri = Url :: from_file_path ( tempdir. path ( ) . canonicalize ( ) . unwrap ( ) ) . unwrap ( ) ;
642527 ( tempdir, root_uri)
643528 }
644529
645- fn expect_loaded_config_messages ( mock : & RpcMock , config_uri : & Url ) {
530+ pub ( crate ) fn expect_loaded_config_messages ( mock : & RpcMock , config_uri : & Url ) {
646531 let file_name = config_uri
647532 . to_file_path ( )
648533 . unwrap ( )
@@ -666,7 +551,7 @@ mod tests {
666551 }
667552
668553 /// Create RpcMock and VHDLServer
669- fn setup_server ( ) -> ( Rc < RpcMock > , VHDLServer ) {
554+ pub ( crate ) fn setup_server ( ) -> ( Rc < RpcMock > , VHDLServer ) {
670555 let mock = Rc :: new ( RpcMock :: new ( ) ) ;
671556 let server = VHDLServer :: new_external_config ( SharedRpcChannel :: new ( mock. clone ( ) ) , false ) ;
672557 ( mock, server)
@@ -787,13 +672,17 @@ end entity ent;
787672 server. text_document_did_change_notification ( & did_change) ;
788673 }
789674
790- fn write_file ( root_uri : & Url , file_name : impl AsRef < str > , contents : impl AsRef < str > ) -> Url {
675+ pub ( crate ) fn write_file (
676+ root_uri : & Url ,
677+ file_name : impl AsRef < str > ,
678+ contents : impl AsRef < str > ,
679+ ) -> Url {
791680 let path = root_uri. to_file_path ( ) . unwrap ( ) . join ( file_name. as_ref ( ) ) ;
792681 std:: fs:: write ( & path, contents. as_ref ( ) ) . unwrap ( ) ;
793682 Url :: from_file_path ( path) . unwrap ( )
794683 }
795684
796- fn write_config ( root_uri : & Url , contents : impl AsRef < str > ) -> Url {
685+ pub ( crate ) fn write_config ( root_uri : & Url , contents : impl AsRef < str > ) -> Url {
797686 write_file ( root_uri, "vhdl_ls.toml" , contents)
798687 }
799688
@@ -1086,8 +975,8 @@ lib.files = [
1086975 mock. expect_notification ( "textDocument/publishDiagnostics" , publish_diagnostics1) ;
1087976 mock. expect_message_contains ( "Configuration file has changed, reloading project..." ) ;
1088977 expect_loaded_config_messages ( & mock, & config_uri) ;
1089- mock. expect_notification ( "textDocument/publishDiagnostics" , publish_diagnostics2a) ;
1090978 mock. expect_notification ( "textDocument/publishDiagnostics" , publish_diagnostics2b) ;
979+ mock. expect_notification ( "textDocument/publishDiagnostics" , publish_diagnostics2a) ;
1091980
1092981 initialize_server ( & mut server, root_uri. clone ( ) ) ;
1093982
0 commit comments