@@ -70,61 +70,80 @@ impl<'a> DesktopEntry<'a> {
70
70
}
71
71
72
72
impl < ' a > DesktopEntry < ' a > {
73
- pub fn action_entry ( & ' a self , action : & str , key : & str ) -> Option < & ' a Cow < ' a , str > > {
73
+ /// An action is defined as `[Desktop Action actions-name]` where `action-name`
74
+ /// is defined in the `Actions` field of `[Desktop Entry]`.
75
+ /// Example: to get the `Name` field of this `new-window` action
76
+ /// ```txt
77
+ /// [Desktop Action new-window]
78
+ /// Name=Open a New Window
79
+ /// ```
80
+ /// you will need to call
81
+ /// ```rust
82
+ /// entry.action_entry("new-window", "Name")
83
+ /// ```
84
+ pub fn action_entry ( & ' a self , action : & str , key : & str ) -> Option < & ' a str > {
74
85
let group = self
75
86
. groups
76
87
. get ( [ "Desktop Action " , action] . concat ( ) . as_str ( ) ) ;
77
88
78
89
Self :: entry ( group, key)
79
90
}
80
91
81
- pub fn action_entry_localized (
92
+ pub fn action_entry_localized < L : AsRef < str > > (
82
93
& ' a self ,
83
94
action : & str ,
84
95
key : & str ,
85
- locale : Option < & str > ,
96
+ locales : & [ L ] ,
86
97
) -> Option < Cow < ' a , str > > {
87
98
let group = self
88
99
. groups
89
100
. get ( [ "Desktop Action " , action] . concat ( ) . as_str ( ) ) ;
90
101
91
- Self :: localized_entry ( self . ubuntu_gettext_domain . as_deref ( ) , group, key, locale )
102
+ Self :: localized_entry ( self . ubuntu_gettext_domain . as_deref ( ) , group, key, locales )
92
103
}
93
104
94
- pub fn action_exec ( & ' a self , action : & str ) -> Option < & ' a Cow < ' a , str > > {
105
+ pub fn action_exec ( & ' a self , action : & str ) -> Option < & ' a str > {
95
106
self . action_entry ( action, "Exec" )
96
107
}
97
108
98
- pub fn action_name ( & ' a self , action : & str , locale : Option < & str > ) -> Option < Cow < ' a , str > > {
99
- self . action_entry_localized ( action, "Name" , locale)
109
+ pub fn action_name < L : AsRef < str > > (
110
+ & ' a self ,
111
+ action : & str ,
112
+ locales : & [ L ] ,
113
+ ) -> Option < Cow < ' a , str > > {
114
+ self . action_entry_localized ( action, "Name" , locales)
100
115
}
101
116
117
+ /// Return actions separated by `;`
102
118
pub fn actions ( & ' a self ) -> Option < & ' a str > {
103
119
self . desktop_entry ( "Actions" )
104
120
}
105
121
122
+ /// Return categories separated by `;`
106
123
pub fn categories ( & ' a self ) -> Option < & ' a str > {
107
124
self . desktop_entry ( "Categories" )
108
125
}
109
126
110
- pub fn comment ( & ' a self , locale : Option < & str > ) -> Option < Cow < ' a , str > > {
111
- self . desktop_entry_localized ( "Comment" , locale )
127
+ pub fn comment < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Cow < ' a , str > > {
128
+ self . desktop_entry_localized ( "Comment" , locales )
112
129
}
113
130
131
+ /// A desktop entry field is any field under the
132
+ /// `[Desktop Entry]` line
114
133
pub fn desktop_entry ( & ' a self , key : & str ) -> Option < & ' a str > {
115
134
Self :: entry ( self . groups . get ( "Desktop Entry" ) , key) . map ( |e| e. as_ref ( ) )
116
135
}
117
136
118
- pub fn desktop_entry_localized (
137
+ pub fn desktop_entry_localized < L : AsRef < str > > (
119
138
& ' a self ,
120
139
key : & str ,
121
- locale : Option < & str > ,
140
+ locales : & [ L ] ,
122
141
) -> Option < Cow < ' a , str > > {
123
142
Self :: localized_entry (
124
143
self . ubuntu_gettext_domain . as_deref ( ) ,
125
144
self . groups . get ( "Desktop Entry" ) ,
126
145
key,
127
- locale ,
146
+ locales ,
128
147
)
129
148
}
130
149
@@ -136,8 +155,8 @@ impl<'a> DesktopEntry<'a> {
136
155
self . desktop_entry ( "X-Flatpak" )
137
156
}
138
157
139
- pub fn generic_name ( & ' a self , locale : Option < & str > ) -> Option < Cow < ' a , str > > {
140
- self . desktop_entry_localized ( "GenericName" , locale )
158
+ pub fn generic_name < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Cow < ' a , str > > {
159
+ self . desktop_entry_localized ( "GenericName" , locales )
141
160
}
142
161
143
162
pub fn icon ( & ' a self ) -> Option < & ' a str > {
@@ -148,16 +167,18 @@ impl<'a> DesktopEntry<'a> {
148
167
self . appid . as_ref ( )
149
168
}
150
169
151
- pub fn keywords ( & ' a self ) -> Option < Cow < ' a , str > > {
152
- self . desktop_entry_localized ( "Keywords" , None )
170
+ /// Return keywords separated by `;`
171
+ pub fn keywords < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Cow < ' a , str > > {
172
+ self . desktop_entry_localized ( "Keywords" , locales)
153
173
}
154
174
175
+ /// Return mime types separated by `;`
155
176
pub fn mime_type ( & ' a self ) -> Option < & ' a str > {
156
177
self . desktop_entry ( "MimeType" )
157
178
}
158
179
159
- pub fn name ( & ' a self , locale : Option < & str > ) -> Option < Cow < ' a , str > > {
160
- self . desktop_entry_localized ( "Name" , locale )
180
+ pub fn name < L : AsRef < str > > ( & ' a self , locales : & [ L ] ) -> Option < Cow < ' a , str > > {
181
+ self . desktop_entry_localized ( "Name" , locales )
161
182
}
162
183
163
184
pub fn no_display ( & ' a self ) -> bool {
@@ -192,33 +213,42 @@ impl<'a> DesktopEntry<'a> {
192
213
self . desktop_entry ( key) . map_or ( false , |v| v == "true" )
193
214
}
194
215
195
- fn entry ( group : Option < & ' a KeyMap < ' a > > , key : & str ) -> Option < & ' a Cow < ' a , str > > {
196
- group. and_then ( |group| group. get ( key) ) . map ( |key| & key. 0 )
216
+ fn entry ( group : Option < & ' a KeyMap < ' a > > , key : & str ) -> Option < & ' a str > {
217
+ group
218
+ . and_then ( |group| group. get ( key) )
219
+ . map ( |key| key. 0 . as_ref ( ) )
197
220
}
198
221
199
- pub ( crate ) fn localized_entry (
222
+ pub ( crate ) fn localized_entry < L : AsRef < str > > (
200
223
ubuntu_gettext_domain : Option < & ' a str > ,
201
224
group : Option < & ' a KeyMap < ' a > > ,
202
225
key : & str ,
203
- locale : Option < & str > ,
226
+ locales : & [ L ] ,
204
227
) -> Option < Cow < ' a , str > > {
205
- group. and_then ( |group| group. get ( key) ) . and_then ( |key| {
206
- locale
207
- . and_then ( |locale| match key. 1 . get ( locale) . cloned ( ) {
208
- Some ( value) => Some ( value) ,
209
- None => {
210
- if let Some ( pos) = locale. find ( '_' ) {
211
- key. 1 . get ( & locale[ ..pos] ) . cloned ( )
212
- } else {
213
- None
228
+ let Some ( group) = group else {
229
+ return None ;
230
+ } ;
231
+
232
+ let Some ( ( default_value, locale_map) ) = group. get ( key) else {
233
+ return None ;
234
+ } ;
235
+
236
+ for locale in locales {
237
+ match locale_map. get ( locale. as_ref ( ) ) {
238
+ Some ( value) => return Some ( value. clone ( ) ) ,
239
+ None => {
240
+ if let Some ( pos) = memchr:: memchr ( b'_' , locale. as_ref ( ) . as_bytes ( ) ) {
241
+ if let Some ( value) = locale_map. get ( & locale. as_ref ( ) [ ..pos] ) {
242
+ return Some ( value. clone ( ) ) ;
214
243
}
215
244
}
216
- } )
217
- . or_else ( || {
218
- ubuntu_gettext_domain. map ( |domain| Cow :: Owned ( dgettext ( domain, & key. 0 ) ) )
219
- } )
220
- . or ( Some ( key. 0 . clone ( ) ) )
221
- } )
245
+ }
246
+ }
247
+ }
248
+ if let Some ( domain) = ubuntu_gettext_domain {
249
+ return Some ( Cow :: Owned ( dgettext ( domain, & default_value) ) ) ;
250
+ }
251
+ return Some ( default_value. clone ( ) ) ;
222
252
}
223
253
}
224
254
@@ -292,6 +322,7 @@ impl PathSource {
292
322
293
323
/// Returns the default paths in which desktop entries should be searched for based on the current
294
324
/// environment.
325
+ /// Paths are sorted by priority, in reverse, e.i the path with the greater priority will be at the end.
295
326
///
296
327
/// Panics in case determining the current home directory fails.
297
328
pub fn default_paths ( ) -> Vec < PathBuf > {
@@ -300,40 +331,31 @@ pub fn default_paths() -> Vec<PathBuf> {
300
331
data_dirs. push ( base_dirs. get_data_home ( ) ) ;
301
332
data_dirs. append ( & mut base_dirs. get_data_dirs ( ) ) ;
302
333
303
- data_dirs. iter ( ) . map ( |d| d. join ( "applications" ) ) . collect ( )
334
+ data_dirs
335
+ . iter ( )
336
+ . map ( |d| d. join ( "applications" ) )
337
+ . rev ( )
338
+ . collect ( )
304
339
}
305
340
306
- fn dgettext ( domain : & str , message : & str ) -> String {
341
+ pub ( crate ) fn dgettext ( domain : & str , message : & str ) -> String {
307
342
use gettextrs:: { setlocale, LocaleCategory } ;
308
343
setlocale ( LocaleCategory :: LcAll , "" ) ;
309
344
gettextrs:: dgettext ( domain, message)
310
345
}
311
346
312
- // todo: support more variable syntax like fr_FR.
313
- // This will require some work in decode and values query
314
- // for now, just remove the _* part, cause it seems more common
315
-
316
347
/// Get the configured user language env variables.
317
348
/// See https://wiki.archlinux.org/title/Locale#LANG:_default_locale for more information
318
349
pub fn get_languages_from_env ( ) -> Vec < String > {
319
350
let mut l = Vec :: new ( ) ;
320
351
321
- if let Ok ( mut lang) = std:: env:: var ( "LANG" ) {
322
- if let Some ( start) = memchr:: memchr ( b'_' , lang. as_bytes ( ) ) {
323
- lang. truncate ( start) ;
324
- l. push ( lang)
325
- } else {
326
- l. push ( lang) ;
327
- }
352
+ if let Ok ( lang) = std:: env:: var ( "LANG" ) {
353
+ l. push ( lang) ;
328
354
}
329
355
330
356
if let Ok ( lang) = std:: env:: var ( "LANGUAGES" ) {
331
357
lang. split ( ':' ) . for_each ( |lang| {
332
- if let Some ( start) = memchr:: memchr ( b'_' , lang. as_bytes ( ) ) {
333
- l. push ( lang. split_at ( start) . 0 . to_owned ( ) )
334
- } else {
335
- l. push ( lang. to_owned ( ) ) ;
336
- }
358
+ l. push ( lang. to_owned ( ) ) ;
337
359
} )
338
360
}
339
361
0 commit comments