@@ -6,12 +6,10 @@ mod iter;
6
6
7
7
pub mod matching;
8
8
9
- #[ cfg( test) ]
10
- mod test;
11
-
12
9
pub use self :: iter:: Iter ;
13
10
use std:: borrow:: Cow ;
14
11
use std:: collections:: BTreeMap ;
12
+ use std:: hash:: { Hash , Hasher } ;
15
13
16
14
use std:: path:: { Path , PathBuf } ;
17
15
use xdg:: BaseDirectories ;
@@ -24,18 +22,30 @@ pub type Locale<'a> = Cow<'a, str>;
24
22
pub type LocaleMap < ' a > = BTreeMap < Locale < ' a > , Value < ' a > > ;
25
23
pub type Value < ' a > = Cow < ' a , str > ;
26
24
27
- #[ derive( Debug , Clone ) ]
25
+ #[ derive( Debug , Clone , Eq ) ]
28
26
pub struct DesktopEntry < ' a > {
29
27
pub appid : Cow < ' a , str > ,
30
28
pub groups : Groups < ' a > ,
31
29
pub path : Cow < ' a , Path > ,
32
30
pub ubuntu_gettext_domain : Option < Cow < ' a , str > > ,
33
31
}
34
32
33
+ impl Hash for DesktopEntry < ' _ > {
34
+ fn hash < H : Hasher > ( & self , state : & mut H ) {
35
+ self . appid . hash ( state) ;
36
+ }
37
+ }
38
+
39
+ impl PartialEq for DesktopEntry < ' _ > {
40
+ fn eq ( & self , other : & Self ) -> bool {
41
+ self . appid == other. appid
42
+ }
43
+ }
44
+
35
45
impl DesktopEntry < ' _ > {
36
46
/// Construct a new [`DesktopEntry`] from an appid. The name field will be
37
47
/// set to that appid.
38
- pub fn from_appid < ' a > ( appid : & ' a str ) -> DesktopEntry < ' a > {
48
+ pub fn from_appid ( appid : & str ) -> DesktopEntry < ' _ > {
39
49
let mut de = DesktopEntry {
40
50
appid : Cow :: Borrowed ( appid) ,
41
51
groups : Groups :: default ( ) ,
@@ -77,12 +87,10 @@ impl<'a> DesktopEntry<'a> {
77
87
DesktopEntry {
78
88
appid : Cow :: Owned ( self . appid . to_string ( ) ) ,
79
89
groups : new_groups,
80
- ubuntu_gettext_domain : if let Some ( ubuntu_gettext_domain) = & self . ubuntu_gettext_domain
81
- {
82
- Some ( Cow :: Owned ( ubuntu_gettext_domain. to_string ( ) ) )
83
- } else {
84
- None
85
- } ,
90
+ ubuntu_gettext_domain : self
91
+ . ubuntu_gettext_domain
92
+ . as_ref ( )
93
+ . map ( |ubuntu_gettext_domain| Cow :: Owned ( ubuntu_gettext_domain. to_string ( ) ) ) ,
86
94
path : Cow :: Owned ( self . path . to_path_buf ( ) ) ,
87
95
}
88
96
}
@@ -93,9 +101,9 @@ impl<'a> DesktopEntry<'a> {
93
101
self . appid . as_ref ( )
94
102
}
95
103
96
- /// A desktop entry field is any field under the `[Desktop Entry]` section.
104
+ /// A desktop entry field if any field under the `[Desktop Entry]` section.
97
105
pub fn desktop_entry ( & ' a self , key : & str ) -> Option < & ' a str > {
98
- Self :: entry ( self . groups . get ( "Desktop Entry" ) , key) . map ( |e| e . as_ref ( ) )
106
+ Self :: entry ( self . groups . get ( "Desktop Entry" ) , key)
99
107
}
100
108
101
109
pub fn desktop_entry_localized < L : AsRef < str > > (
@@ -154,27 +162,35 @@ impl<'a> DesktopEntry<'a> {
154
162
self . desktop_entry ( "Exec" )
155
163
}
156
164
157
- /// Return categories separated by `;`
158
- pub fn categories ( & ' a self ) -> Option < & ' a str > {
165
+ /// Return categories
166
+ pub fn categories ( & ' a self ) -> Option < Vec < & ' a str > > {
159
167
self . desktop_entry ( "Categories" )
168
+ . map ( |e| e. split ( ';' ) . collect ( ) )
160
169
}
161
170
162
- /// Return keywords separated by `;`
163
- pub fn keywords < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Cow < ' a , str > > {
164
- self . desktop_entry_localized ( "Keywords" , locales)
171
+ /// Return keywords
172
+ pub fn keywords < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Vec < Cow < ' a , str > > > {
173
+ self . localized_entry_splitted ( self . groups . get ( "Desktop Entry" ) , "Keywords" , locales)
165
174
}
166
175
167
- /// Return mime types separated by `;`
168
- pub fn mime_type ( & ' a self ) -> Option < & ' a str > {
176
+ /// Return mime types
177
+ pub fn mime_type ( & ' a self ) -> Option < Vec < & ' a str > > {
169
178
self . desktop_entry ( "MimeType" )
179
+ . map ( |e| e. split ( ';' ) . collect ( ) )
170
180
}
171
181
172
182
pub fn no_display ( & ' a self ) -> bool {
173
183
self . desktop_entry_bool ( "NoDisplay" )
174
184
}
175
185
176
- pub fn only_show_in ( & ' a self ) -> Option < & ' a str > {
186
+ pub fn only_show_in ( & ' a self ) -> Option < Vec < & ' a str > > {
177
187
self . desktop_entry ( "OnlyShowIn" )
188
+ . map ( |e| e. split ( ';' ) . collect ( ) )
189
+ }
190
+
191
+ pub fn not_show_in ( & ' a self ) -> Option < Vec < & ' a str > > {
192
+ self . desktop_entry ( "NotShowIn" )
193
+ . map ( |e| e. split ( ';' ) . collect ( ) )
178
194
}
179
195
180
196
pub fn flatpak ( & ' a self ) -> Option < & ' a str > {
@@ -201,9 +217,9 @@ impl<'a> DesktopEntry<'a> {
201
217
self . desktop_entry ( "Type" )
202
218
}
203
219
204
- /// Return actions separated by `;`
205
- pub fn actions ( & ' a self ) -> Option < & ' a str > {
220
+ pub fn actions ( & ' a self ) -> Option < Vec < & ' a str > > {
206
221
self . desktop_entry ( "Actions" )
222
+ . map ( |e| e. split ( ';' ) . collect ( ) )
207
223
}
208
224
209
225
/// An action is defined as `[Desktop Action actions-name]` where `action-name`
@@ -214,7 +230,7 @@ impl<'a> DesktopEntry<'a> {
214
230
/// Name=Open a New Window
215
231
/// ```
216
232
/// you will need to call
217
- /// ```rust
233
+ /// ```ignore
218
234
/// entry.action_entry("new-window", "Name")
219
235
/// ```
220
236
pub fn action_entry ( & ' a self , action : & str , key : & str ) -> Option < & ' a str > {
@@ -266,13 +282,7 @@ impl<'a> DesktopEntry<'a> {
266
282
key : & str ,
267
283
locales : & [ L ] ,
268
284
) -> Option < Cow < ' a , str > > {
269
- let Some ( group) = group else {
270
- return None ;
271
- } ;
272
-
273
- let Some ( ( default_value, locale_map) ) = group. get ( key) else {
274
- return None ;
275
- } ;
285
+ let ( default_value, locale_map) = group?. get ( key) ?;
276
286
277
287
for locale in locales {
278
288
match locale_map. get ( locale. as_ref ( ) ) {
@@ -287,9 +297,43 @@ impl<'a> DesktopEntry<'a> {
287
297
}
288
298
}
289
299
if let Some ( domain) = ubuntu_gettext_domain {
290
- return Some ( Cow :: Owned ( dgettext ( domain, & default_value) ) ) ;
300
+ return Some ( Cow :: Owned ( dgettext ( domain, default_value) ) ) ;
301
+ }
302
+ Some ( default_value. clone ( ) )
303
+ }
304
+
305
+ pub fn localized_entry_splitted < L : AsRef < str > > (
306
+ & self ,
307
+ group : Option < & ' a KeyMap < ' a > > ,
308
+ key : & str ,
309
+ locales : & [ L ] ,
310
+ ) -> Option < Vec < Cow < ' a , str > > > {
311
+ let ( default_value, locale_map) = group?. get ( key) ?;
312
+
313
+ for locale in locales {
314
+ match locale_map. get ( locale. as_ref ( ) ) {
315
+ Some ( value) => {
316
+ return Some ( value. split ( ';' ) . map ( Cow :: Borrowed ) . collect ( ) ) ;
317
+ }
318
+ None => {
319
+ if let Some ( pos) = memchr:: memchr ( b'_' , locale. as_ref ( ) . as_bytes ( ) ) {
320
+ if let Some ( value) = locale_map. get ( & locale. as_ref ( ) [ ..pos] ) {
321
+ return Some ( value. split ( ';' ) . map ( Cow :: Borrowed ) . collect ( ) ) ;
322
+ }
323
+ }
324
+ }
325
+ }
326
+ }
327
+ if let Some ( domain) = & self . ubuntu_gettext_domain {
328
+ return Some (
329
+ dgettext ( domain, default_value)
330
+ . split ( ';' )
331
+ . map ( |e| Cow :: Owned ( e. to_string ( ) ) )
332
+ . collect ( ) ,
333
+ ) ;
291
334
}
292
- return Some ( default_value. clone ( ) ) ;
335
+
336
+ Some ( default_value. split ( ';' ) . map ( Cow :: Borrowed ) . collect ( ) )
293
337
}
294
338
}
295
339
@@ -403,9 +447,40 @@ pub fn get_languages_from_env() -> Vec<String> {
403
447
l
404
448
}
405
449
450
+ pub fn current_desktop ( ) -> Option < Vec < String > > {
451
+ std:: env:: var ( "XDG_CURRENT_DESKTOP" ) . ok ( ) . map ( |x| {
452
+ let x = x. to_ascii_lowercase ( ) ;
453
+ if x == "unity" {
454
+ vec ! [ "gnome" . to_string( ) ]
455
+ } else {
456
+ x. split ( ':' ) . map ( |e| e. to_string ( ) ) . collect ( )
457
+ }
458
+ } )
459
+ }
460
+
406
461
#[ test]
407
- fn locales_env_test ( ) {
462
+ fn add_field ( ) {
463
+ let appid = "appid" ;
464
+ let de = DesktopEntry :: from_appid ( appid) ;
465
+
466
+ assert_eq ! ( de. appid, appid) ;
467
+ assert_eq ! ( de. name( & [ ] as & [ & str ] ) . unwrap( ) , appid) ;
468
+
408
469
let s = get_languages_from_env ( ) ;
409
470
410
471
println ! ( "{:?}" , s) ;
411
472
}
473
+
474
+ #[ test]
475
+ fn env_with_locale ( ) {
476
+ let locales = & [ "fr_FR" ] ;
477
+
478
+ let de = DesktopEntry :: from_path ( PathBuf :: from ( "tests/org.mozilla.firefox.desktop" ) , locales)
479
+ . unwrap ( ) ;
480
+
481
+ assert_eq ! ( de. generic_name( locales) . unwrap( ) , "Navigateur Web" ) ;
482
+
483
+ let locales = & [ "nb" ] ;
484
+
485
+ assert_eq ! ( de. generic_name( locales) . unwrap( ) , "Web Browser" ) ;
486
+ }
0 commit comments