22
33use std:: collections:: { BTreeMap , VecDeque } ;
44use std:: ops:: { Deref , DerefMut } ;
5+ use std:: panic:: RefUnwindSafe ;
56use std:: sync:: Arc ;
67
78use anyhow:: { Context , anyhow} ;
89use index:: DocumentQueryError ;
910use lsp_server:: Message ;
11+ use lsp_types:: notification:: { Exit , Notification } ;
12+ use lsp_types:: request:: { Request , Shutdown } ;
1013use lsp_types:: { ClientCapabilities , TextDocumentContentChangeEvent , Url } ;
1114use options:: GlobalOptions ;
1215use ruff_db:: Db ;
@@ -36,6 +39,9 @@ mod settings;
3639
3740/// The global state for the LSP
3841pub ( crate ) struct Session {
42+ /// A fallback system to use with the [`LSPSystem`].
43+ fallback_system : Option < Arc < dyn System + ' static + Send + Sync + RefUnwindSafe > > ,
44+
3945 /// Used to retrieve information about open documents and settings.
4046 ///
4147 /// This will be [`None`] when a mutable reference is held to the index via [`index_mut`]
@@ -79,6 +85,7 @@ impl Session {
7985 position_encoding : PositionEncoding ,
8086 global_options : GlobalOptions ,
8187 workspace_folders : Vec < ( Url , ClientOptions ) > ,
88+ fallback_system : Option < Arc < dyn System + ' static + Send + Sync + RefUnwindSafe > > ,
8289 ) -> crate :: Result < Self > {
8390 let index = Arc :: new ( Index :: new ( global_options. into_settings ( ) ) ) ;
8491
@@ -88,6 +95,7 @@ impl Session {
8895 }
8996
9097 Ok ( Self {
98+ fallback_system,
9199 position_encoding,
92100 workspaces,
93101 deferred_messages : VecDeque :: new ( ) ,
@@ -137,6 +145,9 @@ impl Session {
137145 } else {
138146 match & message {
139147 Message :: Request ( request) => {
148+ if request. method == Shutdown :: METHOD {
149+ return Some ( message) ;
150+ }
140151 tracing:: debug!(
141152 "Deferring `{}` request until all workspaces are initialized" ,
142153 request. method
@@ -147,6 +158,9 @@ impl Session {
147158 return Some ( message) ;
148159 }
149160 Message :: Notification ( notification) => {
161+ if notification. method == Exit :: METHOD {
162+ return Some ( message) ;
163+ }
150164 tracing:: debug!(
151165 "Deferring `{}` notification until all workspaces are initialized" ,
152166 notification. method
@@ -171,9 +185,12 @@ impl Session {
171185 /// If the path is a virtual path, it will return the first project database in the session.
172186 pub ( crate ) fn project_db ( & self , path : & AnySystemPath ) -> & ProjectDatabase {
173187 match path {
174- AnySystemPath :: System ( system_path) => self
175- . project_db_for_path ( system_path)
176- . unwrap_or_else ( || self . default_project . get ( self . index . as_ref ( ) ) ) ,
188+ AnySystemPath :: System ( system_path) => {
189+ self . project_db_for_path ( system_path) . unwrap_or_else ( || {
190+ self . default_project
191+ . get ( self . index . as_ref ( ) , self . fallback_system . as_ref ( ) )
192+ } )
193+ }
177194 AnySystemPath :: SystemVirtual ( _virtual_path) => {
178195 // TODO: Currently, ty only supports single workspace but we need to figure out
179196 // which project should this virtual path belong to when there are multiple
@@ -196,7 +213,10 @@ impl Session {
196213 . range_mut ( ..=system_path. to_path_buf ( ) )
197214 . next_back ( )
198215 . map ( |( _, db) | db)
199- . unwrap_or_else ( || self . default_project . get_mut ( self . index . as_ref ( ) ) ) ,
216+ . unwrap_or_else ( || {
217+ self . default_project
218+ . get_mut ( self . index . as_ref ( ) , self . fallback_system . as_ref ( ) )
219+ } ) ,
200220 AnySystemPath :: SystemVirtual ( _virtual_path) => {
201221 // TODO: Currently, ty only supports single workspace but we need to figure out
202222 // which project should this virtual path belong to when there are multiple
@@ -268,7 +288,10 @@ impl Session {
268288 // For now, create one project database per workspace.
269289 // In the future, index the workspace directories to find all projects
270290 // and create a project database for each.
271- let system = LSPSystem :: new ( self . index . as_ref ( ) . unwrap ( ) . clone ( ) ) ;
291+ let system = LSPSystem :: new (
292+ self . index . as_ref ( ) . unwrap ( ) . clone ( ) ,
293+ self . fallback_system . clone ( ) ,
294+ ) ;
272295
273296 let project = ProjectMetadata :: discover ( & root, & system)
274297 . context ( "Failed to discover project configuration" )
@@ -663,11 +686,15 @@ impl DefaultProject {
663686 DefaultProject ( std:: sync:: OnceLock :: new ( ) )
664687 }
665688
666- pub ( crate ) fn get ( & self , index : Option < & Arc < Index > > ) -> & ProjectDatabase {
689+ pub ( crate ) fn get (
690+ & self ,
691+ index : Option < & Arc < Index > > ,
692+ fallback_system : Option < & Arc < dyn System + ' static + Send + Sync + RefUnwindSafe > > ,
693+ ) -> & ProjectDatabase {
667694 self . 0 . get_or_init ( || {
668695 tracing:: info!( "Initialize default project" ) ;
669696
670- let system = LSPSystem :: new ( index. unwrap ( ) . clone ( ) ) ;
697+ let system = LSPSystem :: new ( index. unwrap ( ) . clone ( ) , fallback_system . cloned ( ) ) ;
671698 let metadata = ProjectMetadata :: from_options (
672699 Options :: default ( ) ,
673700 system. current_directory ( ) . to_path_buf ( ) ,
@@ -678,8 +705,12 @@ impl DefaultProject {
678705 } )
679706 }
680707
681- pub ( crate ) fn get_mut ( & mut self , index : Option < & Arc < Index > > ) -> & mut ProjectDatabase {
682- let _ = self . get ( index) ;
708+ pub ( crate ) fn get_mut (
709+ & mut self ,
710+ index : Option < & Arc < Index > > ,
711+ fallback_system : Option < & Arc < dyn System + ' static + Send + Sync + RefUnwindSafe > > ,
712+ ) -> & mut ProjectDatabase {
713+ let _ = self . get ( index, fallback_system) ;
683714
684715 // SAFETY: The `OnceLock` is guaranteed to be initialized at this point because
685716 // we called `get` above, which initializes it if it wasn't already.
0 commit comments