@@ -277,7 +277,7 @@ impl EventProcessor {
277277 }
278278
279279 async fn handle_file_event ( & mut self , event : & FsEvent ) -> Result < ( ) > {
280- use lsp_types:: { DidChangeTextDocumentParams , VersionedTextDocumentIdentifier , TextDocumentContentChangeEvent , DidChangeWatchedFilesParams , FileEvent , FileChangeType } ;
280+ use lsp_types:: { DidChangeTextDocumentParams , VersionedTextDocumentIdentifier , TextDocumentContentChangeEvent , DidChangeWatchedFilesParams , FileEvent , FileChangeType , DidCloseTextDocumentParams , TextDocumentIdentifier } ;
281281
282282 // Convert relative URI to absolute path
283283 if let Ok ( relative_path) = event. uri . to_file_path ( ) {
@@ -288,6 +288,98 @@ impl EventProcessor {
288288 } ;
289289
290290 match event. kind {
291+ FsEventKind :: Created => {
292+ // Send workspace/didChangeWatchedFiles for new files (only if not already open)
293+ unsafe {
294+ let workspace_manager = & mut * self . workspace_manager ;
295+ if !workspace_manager. is_file_opened ( & absolute_path) {
296+ if let Ok ( Some ( client) ) = workspace_manager. get_client_for_file ( & absolute_path) . await {
297+ // 1. Send didChangeWatchedFiles notification
298+ let params = DidChangeWatchedFilesParams {
299+ changes : vec ! [ FileEvent {
300+ uri: absolute_uri. clone( ) ,
301+ typ: FileChangeType :: CREATED ,
302+ } ] ,
303+ } ;
304+
305+ tracing:: info!( "📄 File created, sending didChangeWatchedFiles: {:?}" , absolute_path) ;
306+ let _ = client. did_change_watched_files ( params) . await ;
307+
308+ // 2. Force parsing by sending didOpen (cross-server way to guarantee indexing)
309+ if let Ok ( content) = std:: fs:: read_to_string ( & absolute_path) {
310+ // Determine language ID from file extension using ConfigManager
311+ let language_id = if let Some ( ext) = absolute_path. extension ( ) . and_then ( |ext| ext. to_str ( ) ) {
312+ crate :: config:: ConfigManager :: get_language_for_extension ( ext)
313+ . unwrap_or_else ( || "plaintext" . to_string ( ) )
314+ } else {
315+ "plaintext" . to_string ( )
316+ } ;
317+
318+ let open_params = lsp_types:: DidOpenTextDocumentParams {
319+ text_document : lsp_types:: TextDocumentItem {
320+ uri : absolute_uri. clone ( ) ,
321+ language_id : language_id. clone ( ) ,
322+ version : 1 ,
323+ text : content,
324+ } ,
325+ } ;
326+
327+ tracing:: info!( "📂 Forcing parse with didOpen ({}): {:?}" , language_id, absolute_path) ;
328+ let _ = client. did_open ( open_params) . await ;
329+
330+ // Mark as opened in workspace manager
331+ workspace_manager. mark_file_opened ( absolute_path. clone ( ) ) ;
332+ }
333+ }
334+ } else {
335+ tracing:: info!( "📄 File created but already open, skipping notification: {:?}" , absolute_path) ;
336+ }
337+ }
338+ }
339+
340+ FsEventKind :: Deleted => {
341+ unsafe {
342+ let workspace_manager = & mut * self . workspace_manager ;
343+
344+ if workspace_manager. is_file_opened ( & absolute_path) {
345+ // File was opened - send didClose AND didChangeWatchedFiles
346+ if let Ok ( Some ( client) ) = workspace_manager. get_client_for_file ( & absolute_path) . await {
347+ // 1. Close the opened file
348+ let close_params = DidCloseTextDocumentParams {
349+ text_document : TextDocumentIdentifier {
350+ uri : absolute_uri. clone ( ) ,
351+ } ,
352+ } ;
353+ tracing:: info!( "🗑️ Opened file deleted, sending didClose: {:?}" , absolute_path) ;
354+ let _ = client. did_close ( close_params) . await ;
355+
356+ // 2. Notify filesystem deletion
357+ let watch_params = DidChangeWatchedFilesParams {
358+ changes : vec ! [ FileEvent {
359+ uri: absolute_uri,
360+ typ: FileChangeType :: DELETED ,
361+ } ] ,
362+ } ;
363+ tracing:: info!( "🗑️ Sending didChangeWatchedFiles for deleted file: {:?}" , absolute_path) ;
364+ let _ = client. did_change_watched_files ( watch_params) . await ;
365+ }
366+ workspace_manager. mark_file_closed ( & absolute_path) ;
367+ } else {
368+ // File was closed - just send didChangeWatchedFiles
369+ if let Ok ( Some ( client) ) = workspace_manager. get_client_for_file ( & absolute_path) . await {
370+ let params = DidChangeWatchedFilesParams {
371+ changes : vec ! [ FileEvent {
372+ uri: absolute_uri,
373+ typ: FileChangeType :: DELETED ,
374+ } ] ,
375+ } ;
376+ tracing:: info!( "🗑️ File deleted, sending didChangeWatchedFiles: {:?}" , absolute_path) ;
377+ let _ = client. did_change_watched_files ( params) . await ;
378+ }
379+ }
380+ }
381+ }
382+
291383 FsEventKind :: Modified => {
292384 // SAFETY: We know workspace_manager is valid during EventProcessor lifetime
293385 unsafe {
@@ -331,12 +423,44 @@ impl EventProcessor {
331423 }
332424 }
333425 }
334- FsEventKind :: Created => tracing:: info!( "📄 File created: {:?}" , absolute_path) ,
335- FsEventKind :: Deleted => tracing:: info!( "🗑️ File deleted: {:?}" , absolute_path) ,
426+
336427 FsEventKind :: Renamed { ref from } => {
337428 if let Ok ( from_path) = from. to_file_path ( ) {
338429 let from_absolute = self . workspace_root . join ( & from_path) ;
339430 tracing:: info!( "📋 File renamed: {:?} -> {:?}" , from_absolute, absolute_path) ;
431+
432+ unsafe {
433+ let workspace_manager = & mut * self . workspace_manager ;
434+
435+ // Handle as Delete(old) + Create(new)
436+ if workspace_manager. is_file_opened ( & from_absolute) {
437+ // Old file was opened - send didClose
438+ if let Ok ( Some ( client) ) = workspace_manager. get_client_for_file ( & from_absolute) . await {
439+ if let Ok ( from_uri) = Url :: from_file_path ( & from_absolute) {
440+ let params = DidCloseTextDocumentParams {
441+ text_document : TextDocumentIdentifier {
442+ uri : from_uri,
443+ } ,
444+ } ;
445+ tracing:: info!( "📋 Renamed file was opened, sending didClose for old path: {:?}" , from_absolute) ;
446+ let _ = client. did_close ( params) . await ;
447+ }
448+ }
449+ workspace_manager. mark_file_closed ( & from_absolute) ;
450+ }
451+
452+ // Send didChangeWatchedFiles for new file
453+ if let Ok ( Some ( client) ) = workspace_manager. get_client_for_file ( & absolute_path) . await {
454+ let params = DidChangeWatchedFilesParams {
455+ changes : vec ! [ FileEvent {
456+ uri: absolute_uri,
457+ typ: FileChangeType :: CREATED ,
458+ } ] ,
459+ } ;
460+ tracing:: info!( "📋 Sending didChangeWatchedFiles for renamed file: {:?}" , absolute_path) ;
461+ let _ = client. did_change_watched_files ( params) . await ;
462+ }
463+ }
340464 }
341465 }
342466 }
0 commit comments