xdgkit 3.2.5

A command line kit for XDG specs. As well as a Rust library
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
/*!
# Generating the menus

*from the freedesktop website*

After merging the menus, the result should be a single menu layout description. For each <Menu>, we have a list of directories where desktop entries can be found, a list of directories where directory entries can be found, and a series of <Include> and <Exclude> directives.

For each <Menu> element, build a pool of desktop entries by collecting entries found in each <AppDir> for the menu element. If two entries have the same desktop-file id, the entry for the earlier (closer to the top of the file) <AppDir> must be discarded. Next, add to the pool the entries for any <AppDir>s specified by ancestor <Menu> elements. If a parent menu has a duplicate entry (same desktop-file id), the entry for the child menu has priority.

Next, walk through all <Include> and <Exclude> statements. For each <Include>, match the rules against the pool of all desktop entries. For each desktop entry that matches one of the rules, add it to the menu to be displayed and mark it as having been allocated. For each <Exclude>, match the rules against the currently-included desktop entries. For each desktop entry that matches, remove it again from the menu. Note that an entry that is included in a menu but excluded again by a later <Exclude> is still considered allocated (for the purposes of <OnlyUnallocated>) even though that entry no longer appears in the menu.

Two passes are necessary, once for regular menus where any entry may be matched, and once for <OnlyUnallocated> menus where only entries which have not been marked as allocated may be matched.

The result is a tree of desktop entries, of course.
*/
// desktop_menu.rs
// Rusified in 2021 Copyright Israel Dahl. All rights reserved.
// 
//        /VVVV\
//      /V      V\
//    /V          V\
//   /      0 0     \
//   \|\|\</\/\>/|/|/
//        \_/\_/
// 
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
extern crate serde;
use quick_xml::{Reader, events::Event};
use serde::{Deserialize, Serialize};

//TODO:fixme
//use std::path::PathBuf;
//use crate::desktop_entry::*;
//use crate::basedir::*;


#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
pub enum MenuEnum{
    DefaultAppDirs,
    DefaultDirectoryDirs,
    OnlyUnallocated,
    NotOnlyUnallocated,
    Deleted,
    NotDeleted,
    DefaultMergeDirs,
    Separator,
}
#[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq, Eq)]
#[serde(rename_all = "lowercase")]
pub enum MergeType {
    Menus,
    Files,
    All,    
}
impl MergeType {
    #[allow(dead_code)]
    /// Convert a string to MergeType enum
    pub fn from_string(item:String) -> MergeType{
        if item == "menus" {
            return MergeType::Menus
        } else if item == "files" {
            return MergeType::Files
        }
        MergeType::All
    }
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
/*
The `<Layout>` element is an optional part of this specification. Implementations that do not support the `<Layout>` element should preserve any `<Layout>` elements and their contents as far as possible. Each `<Menu>` may optionally contain a `<Layout>` element. If multiple elements appear then only the last such element is relevant. The purpose of this element is to offer suggestions for the presentation of the menu. If a menu does not contain a `<Layout>` element or if it contains an empty `<Layout>` element then the default layout should be used. The `<Layout>` element may contain `<Filename>`, <Menuname>, <Separator> and <Merge> elements. The `<Layout>` element defines a suggested layout for the menu starting from top to bottom. References to desktop entries that are not contained in this menu as defined by the `<Include>` and `<Exclude>` elements should be ignored. References to sub-menus that are not directly contained in this menu as defined by the `<Menu>` elements should be ignored.
*/
pub struct Layout {
    pub filename:Option<String>,
    pub menuname:Option<String>,
    pub separator:Option<String>,
    pub merge:Option<Merge>,
}
/*
`type="menus"|"files"|"all"`

This element may only appear as a child of a `<Layout>` or `<DefaultLayout>` menu. It indicates the point where desktop entries and sub-menus that are not explicitly mentioned within the `<Layout>` or `<DefaultLayout>` element are to be inserted. It has a type attribute that indicates which elements should be inserted: type="menus" means that all sub-menus that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. `type="files"` means that all desktop entries contained in this menu that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. `type="all"` means that a mix of all sub-menus and all desktop entries that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. Each `<Layout>` or ``<DefaultLayout>`` element shall have exactly one <Merge type="all">` element or it shall have exactly one `<Merge type="files">` and exactly one `<Merge type="menus">` element. An exception is made for a completely empty `<Layout>` element which may be used to indicate that the default-layout should be used instead.
*/
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Merge {
    pub r#type:MergeType,
}
/*
   Any number of `<MergeFile>` elements may be listed below a `<Menu>` element, giving the name of another menu file to be merged into this one. The section called [“Merging”](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html) specifies how merging is done. The root `<Menu>` of the merged file will be merged into the immediate parent of the `<MergeFile>` element. The `<Name>` element of the root `<Menu>` of the merged file are ignored.
 
    If the type attribute is missing or set to "path" then the contents of the `<MergeFile>` element indicates the file to be merged. If this is not an absolute path then the file to be merged should be located relative to the location of the menu file that contains this `<MergeFile>` element.

    Duplicate `<MergeFile>` elements (that specify the same file) are handled as with duplicate `<AppDir>` elements (the last duplicate is used).

    If the type attribute is set to `parent` and the file that contains this `<MergeFile>` element is located under one of the paths specified by `$XDG_CONFIG_DIRS`, the contents of the element should be ignored and the remaining paths specified by `$XDG_CONFIG_DIRS` are searched for a file with the same relative filename. The first file encountered should be merged. There should be no merging at all if no matching file is found.

    *Compatibility note:* The filename specified inside the `<MergeFile>` element should be ignored if the type attribute is set to `parent`, it should however be expected that implementations based on previous versions of this specification will ignore the type attribute and that such implementations will use the filename inside the `<MergeFile>` element instead.

    Example 1: If `$XDG_CONFIG_HOME` is `~/.config/` and `$XDG_CONFIG_DIRS` is `/opt/gnome/:/etc/xdg/` and the file `~/.config/menus/applications.menu` contains `<MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile>` then the file `/opt/gnome/menus/applications.menu` should be merged if it exists. If that file does not exists then the file `/etc/xdg/menus/applications.menu` should be merged instead.
    
    Example 2: If `$XDG_CONFIG_HOME` is `~/.config/` and `$XDG_CONFIG_DIRS` is `/opt/gnome/:/etc/xdg/` and the file `/opt/gnome/menus/applications.menu` contains `<MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile>` then the file `/etc/xdg/menus/applications.menu` should be merged if it exists. 
*/
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct MergeFile {
    pub r#type:Option<MergeFileType>,
    //TODO
    #[serde(rename = "$value")]
    pub text:String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize,)]
pub enum MergeFileType {
    Path,
    Parent,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct LegacyDir {
    pub prefix:Option<String>,
    //TODO
    #[serde(rename = "$value")]
    pub text:String,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct KDELegacyDirs {
    //TODO
    #[serde(rename = "$value")]
    pub text:String,
}
/// #### Attributes
/// `[show_empty="false"] [inline="false"] [inline_limit="4"] [inline_header="true"] [inline_alias="false"]`
/// 
/// The `<DefaultLayout>` element is an optional part of this specificatPath::new(ion. Implementations that do not support the `<DefaultLayout>` element should preserve any `<DefaultLayout>` elements and their contents as far as possible. Each `<Menu>` may optionally contain a `<DefaultLayout>` element which defines the default-layout for the current menu and all its sub-menus. If a menu has a `<DefaultLayout>` element then this will override any default-layout specified by a parent menu. The default-layout defines the suggested layout if a `<Menu>` element does either not have `<Layout>` element or if it has an empty `<Layout>` element. For explanations of the various attributes see the <Menuname> element. If no default-layout has been specified then the layout as specified by the following elements should be assumed:
/// ```xml
/// <DefaultLayout show_empty="false" inline="false" inline_limit="4" inline_header="true" inline_alias="false">
///   <Merge type="menus"/><Merge type="files"/>
/// </DefaultLayout>
///```
 #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
pub struct DefaultLayout {
    pub show_empty:Option<bool>,
    pub inline:Option<bool>,
    pub inline_header:Option<bool>,
    pub inline_alias:Option<bool>,
    pub inline_limit:Option<u32>,
}

/// #### Attributes
/// `[show_empty="..."] [inline="..."] [inline_limit="..."] [inline_header="..."] [inline_alias="..."]`
/// 
/// This element may only appear as a child of a `<Layout>` or `<DefaultLayout>` menu. Its contents references an immediate sub-menu of the current menu as defined with the `<Menu>` element, as such it should never contain a slash. If no such sub-menu exists the element should be ignored. This element may have various attributes, the default values are taken from the DefaultLayout key. The show_empty attribute defines whether a menu that contains no desktop entries and no sub-menus should be shown at all. The show_empty attribute can be "true" or "false". It may have an inline attribute that can be either "true" or "false". If the inline attribute is "true" the menu that is referenced may be copied into the current menu at the current point instead of being inserted as sub-menu of the current menu. The optional inline_limit attribute defines the maximum number of entries that can be inlined. If the sub-menu has more entries than inline_limit, the sub-menu will not be inlined. If the inline_limit is 0 (zero) there is no limit. The optional inline_header attribute defines whether an inlined menu should be preceded with a header entry listing the caption of the sub-menu. The inline_header attribute can be either "true" or "false". The optional inline_alias attribute defines whether a single inlined entry should adopt the caption of the inlined menu. In such case no additional header entry will be added regardless of the value of the inline_header attribute. The inline_alias attribute can be either "true" or "false".
/// 
///  Example: if a menu has a sub-menu titled "WordProcessor" with a single entry "OpenOffice 4.2", and both inline="true" and inline_alias="true" are specified then this would result in the "OpenOffice 4.2" entry being inlined in the current menu but the "OpenOffice 4.2" caption of the entry would be replaced with "WordProcessor".
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Menuname {
    pub show_empty:Option<bool>,
    pub inline:Option<bool>,
    pub inline_header:Option<bool>,
    pub inline_alias:Option<bool>,
    pub inline_limit:Option<u32>,
    #[serde(rename = "$value")]
    pub text:Option<String>, //TODO
}

#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
/// This element may only appear below `<Menu>`. The `<Move>` element contains pairs of `<Old>`/`<New>` elements indicating how to rename a descendant of the current `<Menu>`. If the destination path already exists, the moved menu is merged with the destination menu [see the section called “Merging” for details](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html).
/// 
/// `<Move>` is used primarily to fix up legacy directories. For example, say you are merging a `<LegacyDir>` with folder names that don't match the current hierarchy; the legacy folder names can be moved to the new names, where they will be merged with the new folders.
/// 
/// `<Move>` is also useful for implementing menu editing, [see the section called “Menu editing”](https://specifications.freedesktop.org/menu-spec/latest/apd.html#menu-editing).
pub struct Move {
    /// This element may only appear below `<Move>`, and must be followed by a `<New>` element. The content of both `<Old>` and `<New>` should be a menu path, slash-separated concatenation of `<Name>` fields, [see Menu path](https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-menu-path). Paths are interpreted relative to the menu containing the `<Move>` element.
    pub old:Vec<String>,
    /// This element may only appear below `<Move>`, and must be preceded by an `<Old>` element. The `<New>` element specifies the new path for the preceding `<Old>` element. 
    pub new:Vec<String>,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
#[serde(rename_all = "PascalCase")]
pub struct Rules {
    /// The `<Filename>` element is the most basic matching rule. It matches a desktop entry if the desktop entry has the given desktop-file id. [See Desktop-File Id](https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-desktop-file-id).
    pub filename:Option<String>,
    /// The `<Category>` element is another basic matching predicate. It matches a desktop entry if the desktop entry has the given category in its `DesktopMenu` field.
    pub category:Option<String>,
    /// The `<All>` element is a matching rule that matches all desktop entries. 
    pub all:Vec<Rules>,
    /// The `<And>` element contains a list of matching rules. If each of the matching rules inside the `<And>` element match a desktop entry, then the entire `<And>` rule matches the desktop entry.
    pub and:Vec<Rules>,
    /// The `<Or>` element contains a list of matching rules. If any of the matching rules inside the `<Or>` element match a desktop entry, then the entire `<Or>` rule matches the desktop entry. 
    pub or:Vec<Rules>,
    /// The `<Not>` element contains a list of matching rules. If any of the matching rules inside the `<Not>` element matches a desktop entry, then the entire `<Not>` rule does not match the desktop entry. That is, matching rules below `<Not>` have a logical OR relationship. 
    pub not:Vec<Rules>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
/// # Format of menu files
///
/// Menu files must be well-formed XML files and end in the extension ".menu". They should also conform to the menu file DTD which implies that implementation-specific extensions to the file format are not allowed. Implementations may stop processing if they encounter a menu file which does not comply with the associated DTD. Note that the associated DTD may differ in version from the one defined in this document.
///
/// When an implementation updates an existing menu file it may need to update the identifier to a newer version of the DTD. Implementations should never update the identifier of an existing menu file to an older version. In order to remain compatible with newer versions, implementations should ignore and preserve any XML elements, attributes and attribute values that it does not know how to handle.
///
/// # Document Type Declaration
/// Menu files for this version of the specification must use the following namespace, public and system identifiers:
/// * Namespace `http://www.freedesktop.org/standards/menu`
/// * Public Identifier for 1.1 `PUBLIC "-//freedesktop//DTD Menu 1.0//EN"`
/// * System Identifier for 1.1 `http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd`
///
/// Here is a sample document type declaration:
/// ```xml
///<!DOCTYPE Menu PUBLIC "-//freedesktop//DTD Menu 1.0//EN" "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd">
///```
/// All menu files *MUST* include the document type declaration, so that implementations can adapt to different versions of this specification (and so implementations can validate the menu file against the DTD).
///
/// ## NOTES:
/// And, Or, All, Not are capitalized since `Not` cannot be used, I opted for another standard convention ALL CAPS for those words in programming
#[allow(dead_code)]
#[serde(rename_all = "PascalCase")]
pub struct Menu {
    /// The root element is `<Menu>`. Each `<Menu>` element may contain any number of nested `<Menu>` elements, indicating submenus.
    pub menu:Option<Vec<Menu>>,
    /// This element may only appear below `<Menu>`. The content of this element is a directory name. Desktop entries in this directory are scanned and added to the pool of entries which can be included in this `<Menu>` and its submenus. Only files ending in `.desktop` should be used, other files are ignored.
///
    ///Desktop entries in the pool of available entries are identified by their desktop-file id [see Desktop-File Id](https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-desktop-file-id). The desktop-file id of a desktop entry is equal to its filename, with any path components removed. So given a `<AppDir>` `/foo/bar` and desktop entry `/foo/bar/Hello.desktop` the desktop entry would get a desktop-file id of `Hello.desktop`
///
    ///If the directory contains sub-directories then these sub-directories should be (recursively) scanned as well. The name of the subdirectory should be added as prefix to the desktop-file id together with a dash character ("-") So given a `<AppDir>` `/foo/bar` and desktop entry `/foo/bar/booz/Hello.desktop` the desktop entry would get a desktop-file id of `booz-Hello.desktop` A desktop entry `/foo/bar/bo/oz/Hello.desktop` would result in a desktop-file id of `bo-oz-Hello.desktop`
///
    ///`<AppDir>` elements appearing later in the menu file have priority in case of collisions between desktop-file ids.
///
    ///If the filename given as an `<AppDir>` is not an absolute path, it should be located relative to the location of the menu file being parsed.
///
    ///Duplicate `<AppDir>` elements (that specify the same directory) should be ignored, but the last duplicate in the file should be used when establishing the order in which to scan the directories. This is important when merging [see the section called “Merging”](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html). The order of `<AppDir>` elements with respect to `<Include>` and `<Exclude>` elements is not relevant, also to facilitate merging. 
    pub app_dir:Option<String>,
    ///This element may only appear below `<Menu>`. The element has no content. The element should be treated as if it were a list of `<AppDir>` elements containing the default app dir locations (datadir/applications/ etc.). When expanding `<DefaultAppDirs>` to a list of `<AppDir>`, the default locations that are earlier in the search path go later in the `<Menu>` so that they have priority.
    #[serde(rename = "DefaultAppDirs")]
    pub default_app_dirs:Option<MenuEnum>,
    /// This element may only appear below `<Menu>`. The content of this element is a directory name. Each directory listed in a `<DirectoryDir>` element will be searched for directory entries to be used when resolving the `<Directory>` element for this menu and its submenus. If the filename given as a `<DirectoryDir>` is not an absolute path, it should be located relative to the location of the menu file being parsed.
///
///    Directory entries in the pool of available entries are identified by their relative path [see Relative path](https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-relative-path).
///
///    If two directory entries have duplicate relative paths, the one from the last (furthest down) element in the menu file must be used. Only files ending in the extension `.directory` should be loaded, other files should be ignored.
///
///    Duplicate `<DirectoryDir>` elements (that specify the same directory) are handled as with duplicate `<AppDir>` elements (the last duplicate is used). 
    pub directory_dir:Option<Vec<String>>,
    /// This element may only appear below `<Menu>`. The element has no content. The element should be treated as if it were a list of `<DirectoryDir>` elements containing the default desktop dir locations (`datadir`/desktop-directories/ etc.). The default locations that are earlier in the search path go later in the `<Menu>` so that they have priority. 
    #[serde(rename = "DefaultDirectoryDirs")]
    pub default_directory_dirs:Option<MenuEnum>,
    /// Each `<Menu>` element must have a single `<Name>` element. The content of the `<Name>` element is a name to be used when referring to the given menu. Each submenu of a given `<Menu>` must have a unique name. `<Menu>` elements can thus be referenced by a menu path, for example `Applications/Graphics`. The `<Name>` field must not contain the slash character ("/"); implementations should discard any name containing a slash. [See also Menu path](https://specifications.freedesktop.org/menu-spec/latest/go01.html#term-menu-path).
    pub name:Option<String>,
    /// Each `<Menu>` element has any number of `<Directory>` elements. The content of the `<Directory>` element is the relative path of a directory entry containing meta information about the `<Menu>`, such as its icon and localized name. If no `<Directory>` is specified for a `<Menu>`, its `<Name>` field should be used as the user-visible name of the menu.
///
    /// Duplicate `<Directory>` elements are allowed in order to simplify menu merging, and allow user menus to override system menus. The last `<Directory>` element to appear in the menu file "wins" and other elements are ignored, unless the last element points to a nonexistent directory entry, in which case the previous element should be tried instead, and so on. 
    pub directory:Option<String>,
    ///Each `<Menu>` may contain any number of `<OnlyUnallocated>` and <NotOnlyUnallocated> elements. Only the last such element to appear is relevant, as it determines whether the `<Menu>` can contain any desktop entries, or only those desktop entries that do not match other menus. If neither `<OnlyUnallocated>` nor <NotOnlyUnallocated> elements are present, the default is <NotOnlyUnallocated>.
///
    ///To handle `<OnlyUnallocated>`, the menu file must be analyzed in two conceptual passes. The first pass processes `<Menu>` elements that can match any desktop entry. During this pass, each desktop entry is marked as allocated according to whether it was matched by an `<Include>` rule in some `<Menu>`. The second pass processes only `<Menu>` elements that are restricted to unallocated desktop entries. During the second pass, queries may only match desktop entries that were not marked as allocated during the first pass. [See the section called “Generating the menus”](https://specifications.freedesktop.org/menu-spec/latest/ar01s06.html).
    #[serde(rename = "OnlyUnallocated")]
    pub only_unallocated:Option<MenuEnum>,
    #[serde(rename = "NotOnlyUnallocated")]
    pub not_only_unallocated:Option<MenuEnum>,
    /// Each `<Menu>` may contain any number of '<Deleted>' and `<NotDeleted>` elements. Only the last such element to appear is relevant, as it determines whether the `<Menu>` has been deleted. If neither '<Deleted>' nor `<NotDeleted>` elements are present, the default is `<NotDeleted>`. The purpose of this element is to support menu editing. If a menu contains a '<Deleted>' element not followed by a `<NotDeleted>` element, that menu should be ignored. 
    #[serde(rename = "Deleted")]
    pub deleted:Option<Vec<MenuEnum>>,
    #[serde(rename = "NotDeleted")]
    pub not_deleted:Option<Vec<MenuEnum>>,
    /// An `<Include>` element is a set of rules attempting to match some of the known desktop entries. The `<Include>` element contains a list of any number of matching rules. Matching rules are specified using the elements `<And>`, `<Or>`, `<Not>`, `<All>`, `<Filename>`, and `<Category>`. Each rule in a list of rules has a logical OR relationship, that is, desktop entries which match any rule are included in the menu.
/// 
    /// `<Include>` elements must appear immediately under `<Menu>` elements. The desktop entries they match are included in the menu. `<Include>` and `<Exclude>` elements for a given `<Menu>` are processed in order, with queries earlier in the file handled first. This has implications for merging, [see the section called “Merging”](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html). [See the section called “Generating the menus” for full details on how to process `<Include>` and `<Exclude>` elements](https://specifications.freedesktop.org/menu-spec/latest/ar01s06.html).
    pub include:Option<Vec<Rules>>, //TODO
    /// Any number of `<Exclude>` elements may appear below a `<Menu>` element. The content of an `<Exclude>` element is a list of matching rules, just as with an `<Include>`. However, the desktop entries matched are removed from the list of desktop entries included so far. (Thus an `<Exclude>` element that appears before any `<Include>` elements will have no effect, for example, as no desktop entries have been included yet.)
    pub exclude:Option<Vec<Rules>>,
    /// Any number of `<MergeFile>` elements may be listed below a `<Menu>` element, giving the name of another menu file to be merged into this one. The section called [“Merging”](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html) specifies how merging is done. The root `<Menu>` of the merged file will be merged into the immediate parent of the `<MergeFile>` element. The `<Name>` element of the root `<Menu>` of the merged file are ignored.
/// 
    /// If the type attribute is missing or set to "path" then the contents of the `<MergeFile>` element indicates the file to be merged. If this is not an absolute path then the file to be merged should be located relative to the location of the menu file that contains this `<MergeFile>` element.
/// 
    /// Duplicate `<MergeFile>` elements (that specify the same file) are handled as with duplicate `<AppDir>` elements (the last duplicate is used).
/// 
    /// If the type attribute is set to `parent` and the file that contains this `<MergeFile>` element is located under one of the paths specified by `$XDG_CONFIG_DIRS`, the contents of the element should be ignored and the remaining paths specified by `$XDG_CONFIG_DIRS` are searched for a file with the same relative filename. The first file encountered should be merged. There should be no merging at all if no matching file is found.
/// 
    /// *Compatibility note:* The filename specified inside the `<MergeFile>` element should be ignored if the type attribute is set to `parent`, it should however be expected that implementations based on previous versions of this specification will ignore the type attribute and that such implementations will use the filename inside the `<MergeFile>` element instead.
/// 
    /// Example 1: If `$XDG_CONFIG_HOME` is `~/.config/` and `$XDG_CONFIG_DIRS` is `/opt/gnome/:/etc/xdg/` and the file `~/.config/menus/applications.menu` contains `<MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile>` then the file `/opt/gnome/menus/applications.menu` should be merged if it exists. If that file does not exists then the file `/etc/xdg/menus/applications.menu` should be merged instead.
/// 
    /// Example 2: If `$XDG_CONFIG_HOME` is `~/.config/` and `$XDG_CONFIG_DIRS` is `/opt/gnome/:/etc/xdg/` and the file `/opt/gnome/menus/applications.menu` contains `<MergeFile type="parent">/opt/kde3/etc/xdg/menus/applications.menu</MergeFile>` then the file `/etc/xdg/menus/applications.menu` should be merged if it exists. 
    pub merge_file:Option<Vec<MergeFile>>,
    /// Any number of `<MergeDir>` elements may be listed below a `<Menu>` element. A `<MergeDir>` contains the name of a directory. Each file in the given directory which ends in the ".menu" extension should be merged in the same way that a `<MergeFile>` would be. If the filename given as a `<MergeDir>` is not an absolute path, it should be located relative to the location of the menu file being parsed. The files inside the merged directory are not merged in any specified order.
/// 
    /// Duplicate `<MergeDir>` elements (that specify the same directory) are handled as with duplicate `<AppDir>` elements (the last duplicate is used). 
    pub merge_dir:Option<Vec<String>>,
    /// This element may only appear below `<Menu>`. The element has no content. The element should be treated as if it were a list of `<MergeDir>` elements containing the default merge directory locations. When expanding `<DefaultMergeDirs>` to a list of `<MergeDir>`, the default locations that are earlier in the search path go later in the `<Menu>` so that they have priority. 
    #[serde(rename = "DefaultMergeDirs")]
    pub default_merge_dirs:Option<MenuEnum>,
    /// This element may only appear below `<Menu>`. The text content of this element is a directory name. Each directory listed in a `<LegacyDir>` element will be an old-style legacy hierarchy of desktop entries, [see the section called “Legacy Menu Hierarchies”](https://specifications.freedesktop.org/menu-spec/latest/ar01s07.html) for how to load such a hierarchy. Implementations must not load legacy hierarchies that are not explicitly specified in the menu file (because for example the menu file may not be the main menu). If the filename given as a `<LegacyDir>` is not an absolute path, it should be located relative to the location of the menu file being parsed.
/// 
    /// Duplicate `<LegacyDir>` elements (that specify the same directory) are handled as with duplicate `<AppDir>` elements (the last duplicate is used).
/// 
    /// The `<LegacyDir>` element may have one attribute, `prefix`. Normally, given a `<LegacyDir>` `/foo/bar` and desktop entry `/foo/bar/baz/Hello.desktop` the desktop entry would get a desktop-file id of `Hello.desktop`. Given a prefix of `boo-`, it would instead be assigned the desktop-file id `boo-Hello.desktop`. The prefix should not contain path separator ('/') characters. 
    pub legacy_dir:Option<LegacyDir>,
    /// This element may only appear below `<Menu>`. The element has no content. The element should be treated as if it were a list of `<LegacyDir>` elements containing the traditional desktop file locations supported by KDE with a hard coded prefix of "kde-". When expanding `<KDELegacyDirs>` to a list of `<LegacyDir>`, the locations that are earlier in the search path go later in the `<Menu>` so that they have priority. The search path can be obtained by running `kde-config --path apps`
    #[serde(rename = "KDELegacyDirs", default)]
    pub kde_legacy_dirs:Option<KDELegacyDirs>,
    /// This element may only appear below `<Menu>`. The `<Move>` element contains pairs of `<Old>`/`<New>` elements indicating how to rename a descendant of the current `<Menu>`. If the destination path already exists, the moved menu is merged with the destination menu [see the section called “Merging” for details](https://specifications.freedesktop.org/menu-spec/latest/ar01s05.html).
/// 
    /// `<Move>` is used primarily to fix up legacy directories. For example, say you are merging a `<LegacyDir>` with folder names that don't match the current hierarchy; the legacy folder names can be moved to the new names, where they will be merged with the new folders.
/// 
    /// `<Move>` is also useful for implementing menu editing, [see the section called “Menu editing”](https://specifications.freedesktop.org/menu-spec/latest/apd.html#menu-editing).
    pub r#move:Option<Vec<Move>>,
    /// The `<Layout>` element is an optional part of this specification. Implementations that do not support the `<Layout>` element should preserve any `<Layout>` elements and their contents as far as possible. Each `<Menu>` may optionally contain a `<Layout>` element. If multiple elements appear then only the last such element is relevant. The purpose of this element is to offer suggestions for the presentation of the menu. If a menu does not contain a `<Layout>` element or if it contains an empty `<Layout>` element then the default layout should be used. The `<Layout>` element may contain `<Filename>`, <Menuname>, <Separator> and <Merge> elements. The `<Layout>` element defines a suggested layout for the menu starting from top to bottom. References to desktop entries that are not contained in this menu as defined by the `<Include>` and `<Exclude>` elements should be ignored. References to sub-menus that are not directly contained in this menu as defined by the `<Menu>` elements should be ignored.
    pub layout:Option<Layout>,
    /// #### Attributes
    /// `[show_empty="false"] [inline="false"] [inline_limit="4"] [inline_header="true"] [inline_alias="false"]`
/// 
    /// The `<DefaultLayout>` element is an optional part of this specificatPath::new(ion. Implementations that do not support the `<DefaultLayout>` element should preserve any `<DefaultLayout>` elements and their contents as far as possible. Each `<Menu>` may optionally contain a `<DefaultLayout>` element which defines the default-layout for the current menu and all its sub-menus. If a menu has a `<DefaultLayout>` element then this will override any default-layout specified by a parent menu. The default-layout defines the suggested layout if a `<Menu>` element does either not have `<Layout>` element or if it has an empty `<Layout>` element. For explanations of the various attributes see the <Menuname> element. If no default-layout has been specified then the layout as specified by the following elements should be assumed:
    /// ```xml
    /// <DefaultLayout show_empty="false" inline="false" inline_limit="4" inline_header="true" inline_alias="false">
    ///   <Merge type="menus"/><Merge type="files"/>
    /// </DefaultLayout>
    ///```
    pub default_layout:Option<DefaultLayout>,
    /// #### Attributes
    /// `[show_empty="..."] [inline="..."] [inline_limit="..."] [inline_header="..."] [inline_alias="..."]`
/// 
    /// This element may only appear as a child of a `<Layout>` or `<DefaultLayout>` menu. Its contents references an immediate sub-menu of the current menu as defined with the `<Menu>` element, as such it should never contain a slash. If no such sub-menu exists the element should be ignored. This element may have various attributes, the default values are taken from the DefaultLayout key. The show_empty attribute defines whether a menu that contains no desktop entries and no sub-menus should be shown at all. The show_empty attribute can be "true" or "false". It may have an inline attribute that can be either "true" or "false". If the inline attribute is "true" the menu that is referenced may be copied into the current menu at the current point instead of being inserted as sub-menu of the current menu. The optional inline_limit attribute defines the maximum number of entries that can be inlined. If the sub-menu has more entries than inline_limit, the sub-menu will not be inlined. If the inline_limit is 0 (zero) there is no limit. The optional inline_header attribute defines whether an inlined menu should be preceded with a header entry listing the caption of the sub-menu. The inline_header attribute can be either "true" or "false". The optional inline_alias attribute defines whether a single inlined entry should adopt the caption of the inlined menu. In such case no additional header entry will be added regardless of the value of the inline_header attribute. The inline_alias attribute can be either "true" or "false".
/// 
    ///  Example: if a menu has a sub-menu titled "WordProcessor" with a single entry "OpenOffice 4.2", and both inline="true" and inline_alias="true" are specified then this would result in the "OpenOffice 4.2" entry being inlined in the current menu but the "OpenOffice 4.2" caption of the entry would be replaced with "WordProcessor".
    pub menuname:Option<Vec<Menuname>>,
    /// This element may only appear as a child of a `<Layout>` or `<DefaultLayout>` menu. It indicates a suggestion to draw a visual separator at this point in the menu. `<Separator>` elements at the start of a menu, at the end of a menu or that directly follow other `<Separator>` elements may be ignored. 
    #[serde(rename = "Separator")]
    pub separator:Vec<MenuEnum>, //TODO
    /// `type="menus"|"files"|"all"`
    /// 
    /// This element may only appear as a child of a `<Layout>` or `<DefaultLayout>` menu. It indicates the point where desktop entries and sub-menus that are not explicitly mentioned within the `<Layout>` or `<DefaultLayout>` element are to be inserted. It has a type attribute that indicates which elements should be inserted: type="menus" means that all sub-menus that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. `type="files"` means that all desktop entries contained in this menu that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. `type="all"` means that a mix of all sub-menus and all desktop entries that are not explicitly mentioned should be inserted in alphabetical order of their visual caption at this point. Each `<Layout>` or ``<DefaultLayout>`` element shall have exactly one <Merge type="all">` element or it shall have exactly one `<Merge type="files">` and exactly one `<Merge type="menus">` element. An exception is made for a completely empty `<Layout>` element which may be used to indicate that the default-layout should be used instead.
    pub merge:Option<Vec<Merge>>,
}
impl Menu {

    /// Read in a menu file
    #[allow(dead_code)]
    pub fn read<P: Clone + AsRef<std::path::Path> + std::fmt::Debug>(filename:P) -> Option<Menu> {
        let file_string = match std::fs::read_to_string(filename.clone()) {
            Ok(fs) => fs,
            Err(e) => {
                println!("Error reading file:{}", e);
                return None;
            },
        };
        let mut reader = Reader::from_str(file_string.as_str());
        let mut events = vec![];
        loop {
            match reader.read_event(&mut events) {
                Ok(Event::Start(ref e)) => {
                    match e.name() {
                        b"AppDir" => {
                            //
                        },
                        _=>(),
                    }
                },
                //TODO log this?
                Err(_e) => {
                    //println!("Error:{:?}\nposition:{}",e,events.buffer_position());
                },
                _=> (),
            }
        }
    }
}
#[derive(Debug, Clone)]
pub struct MenuItem {
    /// Name
    pub name:String,
    /// Icon 
    pub icon:String,
    ///  Tooltip
    pub tooltip:String,
    ///  Executable
    pub executable:String,
    ///  Is this a separator?
    pub separator:bool,
    /// Does this need a terminal?
    pub terminal:bool,
}
impl Default for MenuItem {
    fn default() -> Self {
        MenuItem {
            name:String::from(""),
            icon:String::from(""),
            tooltip:String::from(""),
            executable:String::from(""),
            separator:false,
            terminal:false,
        }
    }
}
impl MenuItem {
    #[allow(dead_code)]
    pub fn make_separator() -> Self {
        let mut m = Self::default();
        m.separator = true;
        m
    }
    #[allow(dead_code)]
    pub fn empty_app() -> Self {
        let mut m = Self::default();
        m.icon = String::from("application-default-icon");
        m
    }
}

#[derive(Debug, Clone)]
/*
# App menu

```
use xdgkit::desktop_menu::AppMenu;

```
*/
pub struct AppMenu {
    /// The name of the menu
    pub name:String,
    // Icon
    pub icon:String,
    pub items:Vec<MenuItem>,
    pub submenus:Vec<AppMenu>,
    
}