@@ -13,7 +13,7 @@ use tower_lsp::lsp_types::{
1313 DidSaveTextDocumentParams , ExecuteCommandParams , InitializeParams , InitializeResult ,
1414 InitializedParams , MessageType , Position , SaveOptions , ServerCapabilities ,
1515 TextDocumentSyncCapability , TextDocumentSyncKind , TextDocumentSyncOptions ,
16- TextDocumentSyncSaveOptions ,
16+ TextDocumentSyncSaveOptions , Url ,
1717} ;
1818
1919use tower_lsp:: { Client , LanguageServer , LspService , Server } ;
@@ -34,7 +34,7 @@ struct LspFileService {
3434 eager : bool ,
3535 port : Arc < Mutex < u16 > > ,
3636 root : Arc < PathBuf > ,
37- files : Arc < Mutex < HashMap < String , String > > > ,
37+ files : Arc < Mutex < HashMap < PathBuf , String > > > ,
3838 sig : Signal ,
3939}
4040
@@ -49,18 +49,14 @@ enum LspFile {
4949
5050impl LspFile {
5151 async fn new (
52- files : Arc < Mutex < HashMap < String , String > > > ,
52+ files : Arc < Mutex < HashMap < PathBuf , String > > > ,
5353 path : & Path ,
5454 eager : bool ,
5555 ) -> Result < Self , Error > {
5656 if !eager {
5757 return Ok ( LspFile :: File ( TokioFile :: open ( path) . await ?) ) ;
5858 }
59- let content = files
60- . lock ( )
61- . await
62- . get ( & format ! ( "file://{}" , path. to_str( ) . unwrap_or_default( ) ) )
63- . cloned ( ) ;
59+ let content = files. lock ( ) . await . get ( path) . cloned ( ) ;
6460 Ok ( match content {
6561 Some ( v) => LspFile :: Content ( v. to_string ( ) ) ,
6662 None => LspFile :: File ( TokioFile :: open ( path) . await ?) ,
@@ -95,45 +91,54 @@ impl Dir for LspDir {
9591}
9692
9793impl FileSystemInterface for LspFileService {
98- async fn get_dir ( & self , path : & Path ) -> Result < impl Dir , rusty_live_server :: Error > {
94+ async fn get_dir ( & self , path : & Path ) -> Result < impl Dir , Error > {
9995 LspDir :: new ( path) . await
10096 }
10197
102- async fn get_file ( & self , path : & Path ) -> Result < impl File , rusty_live_server :: Error > {
98+ async fn get_file ( & self , path : & Path ) -> Result < impl File , Error > {
10399 LspFile :: new ( self . files . clone ( ) , path, self . eager ) . await
104100 }
105101}
106102
107103#[ tower_lsp:: async_trait]
108104impl LanguageServer for Backend {
109105 async fn did_open ( & self , params : DidOpenTextDocumentParams ) {
110- let uri = params. text_document . uri . to_string ( ) ;
106+ let uri = params. text_document . uri ;
107+ let Some ( file_path) = self . uri_to_file_path ( & uri) . await else {
108+ return ;
109+ } ;
111110 let content = params. text_document . text ;
112111
113- if let Some ( ( _, service) ) = self . get_workspace_for_file ( & uri ) . await {
112+ if let Some ( ( _, service) ) = self . get_workspace_for_file ( & file_path ) . await {
114113 let mut files = service. files . lock ( ) . await ;
115114 if * self . eager . read ( ) . await {
116- files. insert ( uri . clone ( ) , content. clone ( ) ) ;
115+ files. insert ( file_path . clone ( ) , content. clone ( ) ) ;
117116 }
118- self . update_file ( & uri , & service, false ) . await ;
117+ self . update_file ( & file_path , & service, false ) . await ;
119118 }
120119 }
121120
122121 async fn did_save ( & self , params : DidSaveTextDocumentParams ) {
123- let uri = params. text_document . uri . to_string ( ) ;
124- if let Some ( ( _, service) ) = self . get_workspace_for_file ( & uri) . await {
122+ let uri = params. text_document . uri ;
123+ let Some ( file_path) = self . uri_to_file_path ( & uri) . await else {
124+ return ;
125+ } ;
126+ if let Some ( ( _, service) ) = self . get_workspace_for_file ( & file_path) . await {
125127 let message = format ! ( "File saved: {}" , uri) ;
126128 self . client . log_message ( MessageType :: INFO , message) . await ;
127- self . update_file ( & uri , & service, true ) . await ;
129+ self . update_file ( & file_path , & service, true ) . await ;
128130 }
129131 }
130132
131133 async fn did_change ( & self , params : DidChangeTextDocumentParams ) {
132- let uri = params. text_document . uri . to_string ( ) ;
134+ let uri = params. text_document . uri ;
135+ let Some ( file_path) = self . uri_to_file_path ( & uri) . await else {
136+ return ;
137+ } ;
133138
134- if let Some ( ( _, service) ) = self . get_workspace_for_file ( & uri ) . await {
139+ if let Some ( ( _, service) ) = self . get_workspace_for_file ( & file_path ) . await {
135140 let mut files = service. files . lock ( ) . await ;
136- if let Some ( file) = files. get_mut ( & uri ) {
141+ if let Some ( file) = files. get_mut ( & file_path ) {
137142 if * self . eager . read ( ) . await {
138143 for change in params. content_changes {
139144 if let Some ( range) = change. range {
@@ -147,7 +152,7 @@ impl LanguageServer for Backend {
147152 }
148153 }
149154 }
150- self . update_file ( & uri , & service, false ) . await ;
155+ self . update_file ( & file_path , & service, false ) . await ;
151156 }
152157 }
153158
@@ -276,15 +281,15 @@ impl LanguageServer for Backend {
276281 ) -> tower_lsp:: jsonrpc:: Result < Option < CodeActionResponse > > {
277282 let mut actions = vec ! [ ] ;
278283
279- let uri = params. text_document . uri . to_string ( ) ;
284+ let uri = params. text_document . uri ;
285+ let Some ( file_path) = self . uri_to_file_path ( & uri) . await else {
286+ return Err ( tower_lsp:: jsonrpc:: Error :: invalid_params (
287+ "URL argument invalid" ,
288+ ) ) ;
289+ } ;
280290
281- if let Some ( ( _, service) ) = self . get_workspace_for_file ( & uri ) . await {
291+ if let Some ( ( _, service) ) = self . get_workspace_for_file ( & file_path ) . await {
282292 let port = * service. port . lock ( ) . await ;
283- let file = uri. strip_prefix ( "file://" ) . unwrap_or ( & uri) ;
284- let file = file
285- . strip_prefix ( service. root . to_str ( ) . unwrap_or_default ( ) )
286- . unwrap_or ( file) ;
287- let file = file. strip_prefix ( "/" ) . unwrap_or ( file) ;
288293 let action = CodeActionOrCommand :: CodeAction ( CodeAction {
289294 title : format ! ( "Open in Browser({})" , port) ,
290295 kind : Some ( CodeActionKind :: EMPTY ) ,
@@ -293,7 +298,7 @@ impl LanguageServer for Backend {
293298 command : "openProjectWeb" . to_string ( ) ,
294299 arguments : Some ( vec ! [
295300 Value :: from( service. root. to_str( ) . unwrap_or_default( ) . to_string( ) ) ,
296- Value :: from( file ) ,
301+ Value :: from( file_path . to_str ( ) . unwrap_or_default ( ) . to_string ( ) ) ,
297302 ] ) ,
298303 } ) ,
299304 edit : None ,
@@ -343,11 +348,14 @@ impl LanguageServer for Backend {
343348 }
344349
345350 async fn did_close ( & self , params : DidCloseTextDocumentParams ) {
346- let uri = params. text_document . uri . to_string ( ) ;
351+ let uri = params. text_document . uri ;
352+ let Some ( file_path) = self . uri_to_file_path ( & uri) . await else {
353+ return ;
354+ } ;
347355
348- if let Some ( ( _, service) ) = self . get_workspace_for_file ( & uri ) . await {
356+ if let Some ( ( _, service) ) = self . get_workspace_for_file ( & file_path ) . await {
349357 let mut files = service. files . lock ( ) . await ;
350- files. remove ( & uri ) ;
358+ files. remove ( & file_path ) ;
351359 }
352360 }
353361
@@ -358,25 +366,39 @@ impl LanguageServer for Backend {
358366}
359367
360368impl Backend {
361- async fn get_workspace_for_file ( & self , uri : & str ) -> Option < ( PathBuf , LspFileService ) > {
369+ async fn uri_to_file_path ( & self , uri : & Url ) -> Option < PathBuf > {
370+ let Ok ( file_path) = uri. to_file_path ( ) else {
371+ self . client
372+ . log_message (
373+ MessageType :: ERROR ,
374+ format ! ( "Could not convert URI to file path: {}" , uri. to_string( ) ) ,
375+ )
376+ . await ;
377+ return None ;
378+ } ;
379+ Some ( file_path)
380+ }
381+
382+ async fn get_workspace_for_file ( & self , file_path : & Path ) -> Option < ( PathBuf , LspFileService ) > {
362383 let folders = self . workspace_folders . lock ( ) . await ;
363384 for ( path, ( _, service) ) in folders. iter ( ) {
364- let file_path = Path :: new ( uri. strip_prefix ( "file://" ) . unwrap_or ( uri) ) ;
365385 if file_path. starts_with ( & service. root . as_ref ( ) ) {
366386 return Some ( ( path. clone ( ) , service. clone ( ) ) ) ;
367387 }
368388 }
369389 None
370390 }
371391
372- async fn update_file ( & self , uri : & str , service : & LspFileService , saved : bool ) {
392+ async fn update_file ( & self , file_path : & Path , service : & LspFileService , saved : bool ) {
373393 self . client
374- . log_message ( MessageType :: INFO , format ! ( "File updated: {}" , uri) )
394+ . log_message (
395+ MessageType :: INFO ,
396+ format ! ( "File updated: {}" , file_path. display( ) ) ,
397+ )
375398 . await ;
376- let abs = uri. strip_prefix ( "file://" ) . unwrap_or ( uri) ;
377- let rel = abs
378- . strip_prefix ( service. root . to_str ( ) . unwrap_or_default ( ) )
379- . unwrap_or ( abs) ;
399+ let rel = file_path
400+ . strip_prefix ( service. root . as_ref ( ) )
401+ . unwrap_or ( & file_path) ;
380402 self . call_custom_function ( & service. root , Path :: new ( rel) , saved)
381403 . await ;
382404 }
@@ -426,7 +448,10 @@ pub fn get_byte_index_from_position(s: &str, position: Position) -> usize {
426448 if char_index >= char_count {
427449 s. char_indices ( ) . last ( ) . map ( |( i, _) | i) . unwrap_or ( 0 )
428450 } else {
429- s. char_indices ( ) . nth ( char_index) . map ( |( i, _) | i) . unwrap_or ( s. len ( ) )
451+ s. char_indices ( )
452+ . nth ( char_index)
453+ . map ( |( i, _) | i)
454+ . unwrap_or ( s. len ( ) )
430455 }
431456}
432457
0 commit comments