@@ -11,7 +11,7 @@ use tower_lsp_server::{
1111} ;
1212
1313use crate :: {
14- ConcurrentHashMap ,
14+ ConcurrentHashMap , FORMAT_CONFIG_FILE ,
1515 code_actions:: { apply_all_fix_code_action, apply_fix_code_actions, fix_all_text_edit} ,
1616 formatter:: server_formatter:: ServerFormatter ,
1717 linter:: {
@@ -104,6 +104,19 @@ impl WorkspaceWorker {
104104 kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
105105 } ) ;
106106
107+ watchers. push ( FileSystemWatcher {
108+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
109+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
110+ pattern : options
111+ . lint
112+ . config_path
113+ . as_ref ( )
114+ . map_or ( FORMAT_CONFIG_FILE , |v| v)
115+ . to_owned ( ) ,
116+ } ) ,
117+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
118+ } ) ;
119+
107120 let Some ( root_path) = & self . root_uri . to_file_path ( ) else {
108121 return watchers;
109122 } ;
@@ -296,6 +309,7 @@ impl WorkspaceWorker {
296309 & self ,
297310 _file_event : & FileEvent ,
298311 ) -> Option < ConcurrentHashMap < String , Vec < DiagnosticReport > > > {
312+ // TODO: the tools should implement a helper function to detect if the changed file is relevant
299313 let files = {
300314 let server_linter_guard = self . server_linter . read ( ) . await ;
301315 let server_linter = server_linter_guard. as_ref ( ) ?;
@@ -320,8 +334,10 @@ impl WorkspaceWorker {
320334 ) -> (
321335 // Diagnostic reports that need to be revalidated
322336 Option < ConcurrentHashMap < String , Vec < DiagnosticReport > > > ,
323- // File system watcher for lint config changes
324- Option < FileSystemWatcher > ,
337+ // File system watcher for lint/fmt config changes
338+ // - `None` if no watcher changes are needed
339+ // - empty vector if all watchers should be removed
340+ Option < Vec < FileSystemWatcher > > ,
325341 // Is true, when the formatter was added to the workspace worker
326342 bool ,
327343 ) {
@@ -346,13 +362,35 @@ impl WorkspaceWorker {
346362 }
347363
348364 let mut formatting = false ;
365+
366+ // create all watchers again, because maybe one tool configuration is changed
367+ // and we unregister the workspace watcher and register a new one.
368+ // Without adding the old watchers back, the client would not watch them anymore.
369+ //
370+ // TODO: create own watcher for each tool with its own id,
371+ // so we can unregister only the watcher that changed.
372+ let mut watchers = Vec :: new ( ) ;
373+
349374 if current_option. format != changed_options. format {
350375 if changed_options. format . experimental {
351376 debug ! ( "experimental formatter enabled/restarted" ) ;
352377 // restart the formatter
353378 * self . server_formatter . write ( ) . await =
354379 Some ( ServerFormatter :: new ( & self . root_uri , & changed_options. format ) ) ;
355380 formatting = true ;
381+
382+ watchers. push ( FileSystemWatcher {
383+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
384+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
385+ pattern : changed_options
386+ . format
387+ . config_path
388+ . as_ref ( )
389+ . map_or ( FORMAT_CONFIG_FILE , |v| v)
390+ . to_owned ( ) ,
391+ } ) ,
392+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
393+ } ) ;
356394 } else {
357395 debug ! ( "experimental formatter disabled" ) ;
358396 * self . server_formatter . write ( ) . await = None ;
@@ -371,29 +409,25 @@ impl WorkspaceWorker {
371409 } ;
372410 self . refresh_server_linter ( & changed_options. lint ) . await ;
373411
374- if current_option. lint . config_path != changed_options. lint . config_path {
375- return (
376- Some ( self . revalidate_diagnostics ( files) . await ) ,
377- Some ( FileSystemWatcher {
378- glob_pattern : GlobPattern :: Relative ( RelativePattern {
379- base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
380- pattern : changed_options
381- . lint
382- . config_path
383- . as_ref ( )
384- . unwrap_or ( & "**/.oxlintrc.json" . to_string ( ) )
385- . to_owned ( ) ,
386- } ) ,
387- kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
388- } ) ,
389- formatting,
390- ) ;
391- }
412+ watchers. push ( FileSystemWatcher {
413+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
414+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
415+ pattern : changed_options
416+ . lint
417+ . config_path
418+ . as_ref ( )
419+ . unwrap_or ( & "**/.oxlintrc.json" . to_string ( ) )
420+ . to_owned ( ) ,
421+ } ) ,
422+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
423+ } ) ;
392424
393- return ( Some ( self . revalidate_diagnostics ( files) . await ) , None , formatting) ;
425+ return ( Some ( self . revalidate_diagnostics ( files) . await ) , Some ( watchers ) , formatting) ;
394426 }
395427
396- ( None , None , formatting)
428+ let watchers = if watchers. is_empty ( ) { None } else { Some ( watchers) } ;
429+
430+ ( None , watchers, formatting)
397431 }
398432}
399433
@@ -471,7 +505,7 @@ mod test_watchers {
471505 . block_on ( async { self . worker . init_watchers ( ) . await } )
472506 }
473507
474- fn did_change_configuration ( & self , options : & Options ) -> Option < FileSystemWatcher > {
508+ fn did_change_configuration ( & self , options : & Options ) -> Option < Vec < FileSystemWatcher > > {
475509 let ( _, watchers, _) = tokio:: runtime:: Runtime :: new ( )
476510 . unwrap ( )
477511 . block_on ( async { self . worker . did_change_configuration ( options) . await } ) ;
@@ -582,6 +616,68 @@ mod test_watchers {
582616 } )
583617 ) ;
584618 }
619+
620+ #[ test]
621+ fn test_formatter_experimental_enabled ( ) {
622+ let tester = Tester :: new (
623+ "fixtures/watcher/default" ,
624+ & Options {
625+ format : crate :: formatter:: options:: FormatOptions {
626+ experimental : true ,
627+ ..Default :: default ( )
628+ } ,
629+ ..Default :: default ( )
630+ } ,
631+ ) ;
632+ let watchers = tester. init_watchers ( ) ;
633+
634+ assert_eq ! ( watchers. len( ) , 2 ) ;
635+ assert_eq ! (
636+ watchers[ 0 ] . glob_pattern,
637+ GlobPattern :: Relative ( RelativePattern {
638+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
639+ pattern: "**/.oxlintrc.json" . to_string( ) ,
640+ } )
641+ ) ;
642+ assert_eq ! (
643+ watchers[ 1 ] . glob_pattern,
644+ GlobPattern :: Relative ( RelativePattern {
645+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
646+ pattern: "oxfmtrc.json" . to_string( ) ,
647+ } )
648+ ) ;
649+ }
650+
651+ #[ test]
652+ fn test_formatter_custom_config_path ( ) {
653+ let tester = Tester :: new (
654+ "fixtures/watcher/default" ,
655+ & Options {
656+ format : crate :: formatter:: options:: FormatOptions {
657+ experimental : true ,
658+ config_path : Some ( "configs/formatter.json" . to_string ( ) ) ,
659+ } ,
660+ ..Default :: default ( )
661+ } ,
662+ ) ;
663+ let watchers = tester. init_watchers ( ) ;
664+
665+ assert_eq ! ( watchers. len( ) , 2 ) ;
666+ assert_eq ! (
667+ watchers[ 0 ] . glob_pattern,
668+ GlobPattern :: Relative ( RelativePattern {
669+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
670+ pattern: "**/.oxlintrc.json" . to_string( ) ,
671+ } )
672+ ) ;
673+ assert_eq ! (
674+ watchers[ 1 ] . glob_pattern,
675+ GlobPattern :: Relative ( RelativePattern {
676+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
677+ pattern: "configs/formatter.json" . to_string( ) ,
678+ } )
679+ ) ;
680+ }
585681 }
586682
587683 mod did_change_configuration {
@@ -613,8 +709,9 @@ mod test_watchers {
613709 } )
614710 . unwrap ( ) ;
615711
712+ assert_eq ! ( watchers. len( ) , 1 ) ;
616713 assert_eq ! (
617- watchers. glob_pattern,
714+ watchers[ 0 ] . glob_pattern,
618715 GlobPattern :: Relative ( RelativePattern {
619716 base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
620717 pattern: "configs/lint.json" . to_string( ) ,
0 commit comments