44#[ cfg( feature = "desktop" ) ]
55use cosmic:: desktop;
66use cosmic:: widget;
7+ use freedesktop_entry_parser:: Section ;
78pub use mime_guess:: Mime ;
89use rustc_hash:: FxHashMap ;
910use std:: {
@@ -48,35 +49,29 @@ pub fn exec_to_command(
4849 let field_code_pos = args_vec
4950 . iter ( )
5051 . position ( |arg| EXEC_HANDLERS . contains ( & arg. as_str ( ) ) ) ;
51- let args_handler = field_code_pos. and_then ( |i| args_vec . get ( i ) ) ;
52- // msrv
53- // .inspect(|handler| log::trace!("Found paths handler: {handler} for exec: {exec}"));
52+ let args_handler = field_code_pos
53+ . and_then ( |i| args_vec . get ( i ) )
54+ . inspect ( |& handler| log:: trace!( "Found paths handler: {handler} for exec: {exec}" ) ) ;
5455 // Number of args before the field code.
5556 // This won't be an off by one err below because take is not zero indexed.
5657 let field_code_pos = field_code_pos. unwrap_or_default ( ) ;
5758 let mut processes = match args_handler. map ( String :: as_str) {
5859 Some ( "%f" ) => {
59- let mut processes = Vec :: with_capacity ( path_opt. len ( ) ) ;
60-
61- for path in path_opt. iter ( ) . map ( AsRef :: as_ref) {
62- // TODO: %f and %F need to handle non-file URLs (see spec)
63- if from_file_or_dir ( path) . is_none ( ) {
64- log:: warn!( "Desktop file expects a file path instead of a URL: {path:?}" ) ;
65- }
66-
67- // Passing multiple paths to %f should open an instance per path
68- let mut process = process:: Command :: new ( program) ;
69- process. args (
70- args_vec
71- . iter ( )
72- . map ( AsRef :: as_ref)
73- . take ( field_code_pos)
74- . chain ( std:: iter:: once ( path) ) ,
75- ) ;
76- processes. push ( process) ;
77- }
60+ path_opt
61+ . iter ( )
62+ . map ( |path| {
63+ let path = path. as_ref ( ) ;
64+ // TODO: %f and %F need to handle non-file URLs (see spec)
65+ if from_file_or_dir ( path) . is_none ( ) {
66+ log:: warn!( "Desktop file expects a file path instead of a URL: {path:?}" ) ;
67+ }
7868
79- processes
69+ // Passing multiple paths to %f should open an instance per path
70+ let mut process = process:: Command :: new ( program) ;
71+ process. args ( args_vec. iter ( ) . take ( field_code_pos) ) . arg ( path) ;
72+ process
73+ } )
74+ . collect ( )
8075 }
8176 Some ( "%F" ) => {
8277 // TODO: %f and %F need to handle non-file URLs (see spec)
@@ -90,39 +85,25 @@ pub fn exec_to_command(
9085
9186 // Launch one instance with all args
9287 let mut process = process:: Command :: new ( program) ;
93- process. args (
94- args_vec
95- . iter ( )
96- . map ( OsStr :: new)
97- . take ( field_code_pos)
98- . chain ( path_opt. iter ( ) . map ( AsRef :: as_ref) ) ,
99- ) ;
88+ process
89+ . args ( args_vec. iter ( ) . take ( field_code_pos) )
90+ . args ( path_opt) ;
10091
10192 vec ! [ process]
10293 }
10394 Some ( "%u" ) => path_opt
10495 . iter ( )
10596 . map ( |path| {
10697 let mut process = process:: Command :: new ( program) ;
107- process. args (
108- args_vec
109- . iter ( )
110- . map ( OsStr :: new)
111- . take ( field_code_pos)
112- . chain ( std:: iter:: once ( path. as_ref ( ) ) ) ,
113- ) ;
98+ process. args ( args_vec. iter ( ) . take ( field_code_pos) ) . arg ( path) ;
11499 process
115100 } )
116101 . collect ( ) ,
117102 Some ( "%U" ) => {
118103 let mut process = process:: Command :: new ( program) ;
119- process. args (
120- args_vec
121- . iter ( )
122- . map ( OsStr :: new)
123- . take ( field_code_pos)
124- . chain ( path_opt. iter ( ) . map ( AsRef :: as_ref) ) ,
125- ) ;
104+ process
105+ . args ( args_vec. iter ( ) . take ( field_code_pos) )
106+ . args ( path_opt) ;
126107 vec ! [ process]
127108 }
128109 Some ( invalid) => unreachable ! ( "All valid variants were checked; got: {invalid}" ) ,
@@ -315,39 +296,42 @@ impl MimeAppCache {
315296 }
316297 } ;
317298
318- for attr in entry
319- . section ( "Added Associations" )
320- . attrs ( )
321- . chain ( entry. section ( "Default Applications" ) . attrs ( ) )
299+ let added_iter = entry. section ( "Added Associations" ) . map ( Section :: attrs) ;
300+ let default_iter = entry. section ( "Default Applications" ) . map ( Section :: attrs) ;
301+ // TODO: replace with Option::into_flat_iter when stable and within MSRV
302+ // https://github.com/rust-lang/rust/issues/148441
303+ for attr in added_iter
304+ . into_iter ( )
305+ . flatten ( )
306+ . chain ( default_iter. into_iter ( ) . flatten ( ) )
322307 {
323- if let Ok ( mime) = attr. name . parse :: < Mime > ( ) {
324- if let Some ( filenames) = attr. value {
325- for filename in filenames. split_terminator ( ';' ) {
326- log:: trace!( "add {mime}={filename}" ) ;
327- let apps = self
328- . cache
329- . entry ( mime. clone ( ) )
330- . or_insert_with ( || Vec :: with_capacity ( 1 ) ) ;
331- if !apps. iter ( ) . any ( |x| filename_eq ( & x. path , filename) ) {
332- if let Some ( app) =
333- all_apps. iter ( ) . find ( |& x| filename_eq ( & x. path , filename) )
334- {
335- apps. push ( MimeApp :: from ( app) ) ;
336- } else {
337- log:: info!(
338- "failed to add association for {mime:?}: application {filename:?} not found"
339- ) ;
340- }
308+ if let Ok ( mime) = attr. 0 . key . parse :: < Mime > ( ) {
309+ let mime_str = mime. as_ref ( ) ;
310+ for filename in attr. 1 {
311+ log:: trace!( "add {mime_str}={filename}" ) ;
312+ let apps = self
313+ . cache
314+ . entry ( mime. clone ( ) )
315+ . or_insert_with ( || Vec :: with_capacity ( 1 ) ) ;
316+ if !apps. iter ( ) . any ( |x| filename_eq ( & x. path , filename) ) {
317+ if let Some ( app) =
318+ all_apps. iter ( ) . find ( |& x| filename_eq ( & x. path , filename) )
319+ {
320+ apps. push ( MimeApp :: from ( app) ) ;
321+ } else {
322+ log:: info!(
323+ "failed to add association for {mime_str}: application {filename} not found"
324+ ) ;
341325 }
342326 }
343327 }
344328 }
345329 }
346330
347- for attr in entry. section ( "Removed Associations" ) . attrs ( ) {
348- if let Ok ( mime ) = attr . name . parse :: < Mime > ( ) {
349- if let Some ( filenames ) = attr. value {
350- for filename in filenames . split_terminator ( ';' ) {
331+ if let Some ( removed_associations ) = entry. section ( "Removed Associations" ) {
332+ for attr in removed_associations . attrs ( ) {
333+ if let Ok ( mime ) = attr. 0 . key . parse :: < Mime > ( ) {
334+ for filename in attr . 1 {
351335 log:: trace!( "remove {mime}={filename}" ) ;
352336 if let Some ( apps) = self . cache . get_mut ( & mime) {
353337 apps. retain ( |x| !filename_eq ( & x. path , filename) ) ;
@@ -357,14 +341,14 @@ impl MimeAppCache {
357341 }
358342 }
359343
360- for attr in entry. section ( "Default Applications" ) . attrs ( ) {
361- if let Ok ( mime ) = attr . name . parse :: < Mime > ( ) {
362- if let Some ( filenames ) = attr. value {
363- for filename in filenames . split_terminator ( ';' ) {
344+ if let Some ( default_applications ) = entry. section ( "Default Applications" ) {
345+ for attr in default_applications . attrs ( ) {
346+ if let Ok ( mime ) = attr. 0 . key . parse :: < Mime > ( ) {
347+ for filename in attr . 1 {
364348 log:: trace!( "default {mime}={filename}" ) ;
365349 if let Some ( apps) = self . cache . get_mut ( & mime) {
366350 let mut found = false ;
367- for app in apps. iter_mut ( ) {
351+ for app in apps {
368352 if filename_eq ( & app. path , filename) {
369353 app. is_default = true ;
370354 found = true ;
@@ -376,7 +360,7 @@ impl MimeAppCache {
376360 break ;
377361 }
378362 log:: debug!(
379- "failed to set default for {mime:? }: application {filename:? } not found"
363+ "failed to set default for {mime}: application {filename} not found"
380364 ) ;
381365 }
382366 }
0 commit comments