@@ -152,6 +152,19 @@ fn extract_paths_from_drag_drop(format: &str, data: &[u8]) -> Vec<PathBuf> {
152152 paths
153153}
154154
155+ #[ cfg( test) ]
156+ mod tests {
157+ use super :: file_uri_to_pathbuf;
158+ use std:: path:: PathBuf ;
159+
160+ #[ test]
161+ fn converts_macos_document_urls_to_paths ( ) {
162+ assert_eq ! ( file_uri_to_pathbuf( "file:///Users/test/My%20File.pcb" ) , Some ( PathBuf :: from( "/Users/test/My File.pcb" ) ) ) ;
163+ assert_eq ! ( file_uri_to_pathbuf( "file://localhost/Users/test/foo.pcb" ) , Some ( PathBuf :: from( "/Users/test/foo.pcb" ) ) ) ;
164+ assert_eq ! ( file_uri_to_pathbuf( "https://example.com/foo.pcb" ) , None ) ;
165+ }
166+ }
167+
155168#[ derive( Clone , Debug ) ]
156169pub enum WindowManagerMessage {
157170 OpenWindow ,
@@ -185,6 +198,8 @@ pub enum WindowManagerMessage {
185198 McpCommand ( Arc < McpCommand > ) ,
186199 /// File was dropped onto the window (with Ctrl state for new window)
187200 FileDropped ( window:: Id , PathBuf , bool ) ,
201+ /// Document URL received from Finder or Launch Services on macOS.
202+ OpenDocumentUrl ( String ) ,
188203}
189204
190205fn start_session_save_worker ( ) -> mpsc:: Sender < SaveRequest > {
@@ -934,6 +949,35 @@ impl WindowManager {
934949 // No unsaved changes - open directly
935950 return Task :: done ( WindowManagerMessage :: WindowMessage ( window_id, crate :: ui:: Message :: FileOpened ( path) ) ) ;
936951 }
952+
953+ WindowManagerMessage :: OpenDocumentUrl ( url) => {
954+ let Some ( path) = file_uri_to_pathbuf ( & url) else {
955+ return Task :: batch ( [ mcp_task] ) ;
956+ } ;
957+
958+ // Reuse the initial empty window when the application has just
959+ // been launched by Finder. Otherwise, preserve the current
960+ // document and open the requested file in a new window.
961+ if self . windows . len ( ) == 1 {
962+ let ( & window_id, window) = self . windows . first_key_value ( ) . expect ( "one window" ) ;
963+ if window. file_path ( ) . is_none ( ) && !window. is_modified ( ) {
964+ return Task :: done ( WindowManagerMessage :: WindowMessage (
965+ window_id,
966+ crate :: ui:: Message :: FileOpened ( path) ,
967+ ) ) ;
968+ }
969+ }
970+
971+ self . pending_restores . push ( WindowRestoreInfo {
972+ original_path : Some ( path) ,
973+ load_path : None ,
974+ mark_dirty : false ,
975+ position : None ,
976+ size : ( DEFAULT_SIZE . width , DEFAULT_SIZE . height ) ,
977+ session_data_path : None ,
978+ } ) ;
979+ return Task :: done ( WindowManagerMessage :: OpenWindow ) ;
980+ }
937981 } ;
938982
939983 Task :: batch ( [ main_task, mcp_task] )
@@ -1017,6 +1061,7 @@ impl WindowManager {
10171061 _ => None ,
10181062 }
10191063 } ) ,
1064+ icy_ui:: event:: listen_url( ) . map( WindowManagerMessage :: OpenDocumentUrl ) ,
10201065 // Autosave tick - check every second
10211066 icy_ui:: time:: every( std:: time:: Duration :: from_secs( 1 ) ) . map( |_| WindowManagerMessage :: AutosaveTick ) ,
10221067 ] ;
0 commit comments