@@ -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,21 @@ impl WorkspaceWorker {
104104 kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
105105 } ) ;
106106
107+ if options. format . experimental {
108+ watchers. push ( FileSystemWatcher {
109+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
110+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
111+ pattern : options
112+ . format
113+ . config_path
114+ . as_ref ( )
115+ . map_or ( FORMAT_CONFIG_FILE , |v| v)
116+ . to_owned ( ) ,
117+ } ) ,
118+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
119+ } ) ;
120+ }
121+
107122 let Some ( root_path) = & self . root_uri . to_file_path ( ) else {
108123 return watchers;
109124 } ;
@@ -296,6 +311,7 @@ impl WorkspaceWorker {
296311 & self ,
297312 _file_event : & FileEvent ,
298313 ) -> Option < ConcurrentHashMap < String , Vec < DiagnosticReport > > > {
314+ // TODO: the tools should implement a helper function to detect if the changed file is relevant
299315 let files = {
300316 let server_linter_guard = self . server_linter . read ( ) . await ;
301317 let server_linter = server_linter_guard. as_ref ( ) ?;
@@ -320,8 +336,10 @@ impl WorkspaceWorker {
320336 ) -> (
321337 // Diagnostic reports that need to be revalidated
322338 Option < ConcurrentHashMap < String , Vec < DiagnosticReport > > > ,
323- // File system watcher for lint config changes
324- Option < FileSystemWatcher > ,
339+ // File system watcher for lint/fmt config changes
340+ // - `None` if no watcher changes are needed
341+ // - empty vector if all watchers should be removed
342+ Option < Vec < FileSystemWatcher > > ,
325343 // Is true, when the formatter was added to the workspace worker
326344 bool ,
327345 ) {
@@ -346,13 +364,35 @@ impl WorkspaceWorker {
346364 }
347365
348366 let mut formatting = false ;
367+
368+ // create all watchers again, because maybe one tool configuration is changed
369+ // and we unregister the workspace watcher and register a new one.
370+ // Without adding the old watchers back, the client would not watch them anymore.
371+ //
372+ // TODO: create own watcher for each tool with its own id,
373+ // so we can unregister only the watcher that changed.
374+ let mut watchers = Vec :: new ( ) ;
375+
349376 if current_option. format != changed_options. format {
350377 if changed_options. format . experimental {
351378 debug ! ( "experimental formatter enabled/restarted" ) ;
352379 // restart the formatter
353380 * self . server_formatter . write ( ) . await =
354381 Some ( ServerFormatter :: new ( & self . root_uri , & changed_options. format ) ) ;
355382 formatting = true ;
383+
384+ watchers. push ( FileSystemWatcher {
385+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
386+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
387+ pattern : changed_options
388+ . format
389+ . config_path
390+ . as_ref ( )
391+ . map_or ( FORMAT_CONFIG_FILE , |v| v)
392+ . to_owned ( ) ,
393+ } ) ,
394+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
395+ } ) ;
356396 } else {
357397 debug ! ( "experimental formatter disabled" ) ;
358398 * self . server_formatter . write ( ) . await = None ;
@@ -371,29 +411,25 @@ impl WorkspaceWorker {
371411 } ;
372412 self . refresh_server_linter ( & changed_options. lint ) . await ;
373413
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- }
414+ watchers. push ( FileSystemWatcher {
415+ glob_pattern : GlobPattern :: Relative ( RelativePattern {
416+ base_uri : OneOf :: Right ( self . root_uri . clone ( ) ) ,
417+ pattern : changed_options
418+ . lint
419+ . config_path
420+ . as_ref ( )
421+ . unwrap_or ( & "**/.oxlintrc.json" . to_string ( ) )
422+ . to_owned ( ) ,
423+ } ) ,
424+ kind : Some ( WatchKind :: all ( ) ) , // created, deleted, changed
425+ } ) ;
392426
393- return ( Some ( self . revalidate_diagnostics ( files) . await ) , None , formatting) ;
427+ return ( Some ( self . revalidate_diagnostics ( files) . await ) , Some ( watchers ) , formatting) ;
394428 }
395429
396- ( None , None , formatting)
430+ let watchers = if watchers. is_empty ( ) { None } else { Some ( watchers) } ;
431+
432+ ( None , watchers, formatting)
397433 }
398434}
399435
@@ -471,7 +507,7 @@ mod test_watchers {
471507 . block_on ( async { self . worker . init_watchers ( ) . await } )
472508 }
473509
474- fn did_change_configuration ( & self , options : & Options ) -> Option < FileSystemWatcher > {
510+ fn did_change_configuration ( & self , options : & Options ) -> Option < Vec < FileSystemWatcher > > {
475511 let ( _, watchers, _) = tokio:: runtime:: Runtime :: new ( )
476512 . unwrap ( )
477513 . block_on ( async { self . worker . did_change_configuration ( options) . await } ) ;
@@ -483,7 +519,8 @@ mod test_watchers {
483519 use tower_lsp_server:: lsp_types:: { GlobPattern , OneOf , RelativePattern } ;
484520
485521 use crate :: {
486- linter:: options:: LintOptions , options:: Options , worker:: test_watchers:: Tester ,
522+ formatter:: options:: FormatOptions , linter:: options:: LintOptions , options:: Options ,
523+ worker:: test_watchers:: Tester ,
487524 } ;
488525
489526 #[ test]
@@ -582,6 +619,68 @@ mod test_watchers {
582619 } )
583620 ) ;
584621 }
622+
623+ #[ test]
624+ fn test_formatter_experimental_enabled ( ) {
625+ let tester = Tester :: new (
626+ "fixtures/watcher/default" ,
627+ & Options {
628+ format : crate :: formatter:: options:: FormatOptions {
629+ experimental : true ,
630+ ..Default :: default ( )
631+ } ,
632+ ..Default :: default ( )
633+ } ,
634+ ) ;
635+ let watchers = tester. init_watchers ( ) ;
636+
637+ assert_eq ! ( watchers. len( ) , 2 ) ;
638+ assert_eq ! (
639+ watchers[ 0 ] . glob_pattern,
640+ GlobPattern :: Relative ( RelativePattern {
641+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
642+ pattern: "**/.oxlintrc.json" . to_string( ) ,
643+ } )
644+ ) ;
645+ assert_eq ! (
646+ watchers[ 1 ] . glob_pattern,
647+ GlobPattern :: Relative ( RelativePattern {
648+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
649+ pattern: ".oxfmtrc.json" . to_string( ) ,
650+ } )
651+ ) ;
652+ }
653+
654+ #[ test]
655+ fn test_formatter_custom_config_path ( ) {
656+ let tester = Tester :: new (
657+ "fixtures/watcher/default" ,
658+ & Options {
659+ format : FormatOptions {
660+ experimental : true ,
661+ config_path : Some ( "configs/formatter.json" . to_string ( ) ) ,
662+ } ,
663+ ..Default :: default ( )
664+ } ,
665+ ) ;
666+ let watchers = tester. init_watchers ( ) ;
667+
668+ assert_eq ! ( watchers. len( ) , 2 ) ;
669+ assert_eq ! (
670+ watchers[ 0 ] . glob_pattern,
671+ GlobPattern :: Relative ( RelativePattern {
672+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
673+ pattern: "**/.oxlintrc.json" . to_string( ) ,
674+ } )
675+ ) ;
676+ assert_eq ! (
677+ watchers[ 1 ] . glob_pattern,
678+ GlobPattern :: Relative ( RelativePattern {
679+ base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
680+ pattern: "configs/formatter.json" . to_string( ) ,
681+ } )
682+ ) ;
683+ }
585684 }
586685
587686 mod did_change_configuration {
@@ -613,8 +712,9 @@ mod test_watchers {
613712 } )
614713 . unwrap ( ) ;
615714
715+ assert_eq ! ( watchers. len( ) , 1 ) ;
616716 assert_eq ! (
617- watchers. glob_pattern,
717+ watchers[ 0 ] . glob_pattern,
618718 GlobPattern :: Relative ( RelativePattern {
619719 base_uri: OneOf :: Right ( tester. worker. get_root_uri( ) . clone( ) ) ,
620720 pattern: "configs/lint.json" . to_string( ) ,
0 commit comments