xdgkit/
lib.rs

1/*!
2# XDGkit
3[![Documentation](https://docs.rs/xdgkit/badge.svg)](https://docs.rs/xdgkit)
4[![Crates.io](https://img.shields.io/crates/v/xdgkit.svg)](https://crates.io/crates/xdgkit)
5
6
7The XDG library and command line tool kit!
8
9Much has been copy-pasted from [freedesktop.org](http://freedesktop.org) and rustified as enums and structs with implementations in main for a binary tool to use the specs.
10
11xdgkit follows SemVer
12
13For Example:
14 * 0.0.1 was the initial release
15 * 0.1.0 saw the addition of `icon-theme` to the CLI subcommands
16 * 0.2.0 saw the addition of `desktop-menu` to the CLI subcommands
17 * 2.0.0 saw a breaking change: renaming libxdgkit to xdgkit
18
19
20 ## basedir
21
22This uses `std::env` and returns` Result<String, VarError>` as does `std::env`
23This provides all the normal XDG variables, as well as locations for icons, menu/directory files, desktop files, and the autostart directories
24The command line parser will automatically check for existing directories.
25The functions that have `Vec` like properties (applications directory for example) can all be easily expanded
26```
27use xdgkit::basedir::*;
28
29// simple use
30let app_dirs:Vec<String> = convert_to_vec(applications());
31```
32This will return an empty vector with an empty string if nothing exists
33
34** this implements `autostart-spec`, `basedir-spec`, and `trash-spec`** from the [XDG specifications](https://specifications.freedesktop.org/)
35
36## desktop-entry
37
38Reads in a desktop file and turns it into a struct which can be accessed for any of the desktop file features you will find in the freedesktop spec.
39
40As a library this returns a struct of mostly `Option<whatever>`
41
42As a CLI utility it returns a String printed on a new line (or a blank line if the field is empty that you are looking for. In other words, you will need something like:
43
44## icon_finder
45
46Based off of the psuedo code on freedesktop.org
47```
48use xdgkit::icon_finder;
49use std::path::PathBuf;
50
51let icon_name = "firefox";
52// look for the 48px icon
53let icon = match icon_finder::find_icon(icon_name.to_string(),48,1){
54    Some(icon)=>icon,
55    None=>PathBuf::new(),
56};
57// this will show the path to the icon in the current theme
58println!("Firefox icon:{:?}", icon);
59```
60
61
62## icon_theme/icon-theme
63
64Reads an `index.theme` ini-style file and turns it into a struct of `Option<whatever>` which can be accessed for any of the icon theme spec features you will find in the freedesktop spec, or the documentation of this library/program.
65
66As a CLI utility it returns a String printed on a new line (or a blank line if the field is empty that you are looking for.
67
68# WORKS IN PROGRESS
69
70serde does not work for any xml library currently, due to "repeated, out of order elements", which is required for most xml files.  This will not be fixed in `serde-xml-rs`, so who knows if there will be a rust serde xml library that supports serde and xml and rust....
71This effects:
72
73 * recently_used
74 * desktop_menu/desktop-menu
75 * user_places
76
77
78Until then, I may get around to manually reading it all...
79
80*/
81
82// xdgkit
83// Rusified in 2021 Copyright Israel Dahl. All rights reserved.
84// 
85//        /VVVV\
86//      /V      V\
87//    /V          V\
88//   /      0 0     \
89//   \|\|\</\/\>/|/|/
90//        \_/\_/
91// 
92// This program is free software; you can redistribute it and/or modify
93// it under the terms of the GNU General Public License version 2 as
94// published by the Free Software Foundation.
95//
96// This program is distributed in the hope that it will be useful,
97// but WITHOUT ANY WARRANTY; without even the implied warranty of
98// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
99// GNU General Public License for more details.
100// 
101// You should have received a copy of the GNU General Public License
102// along with this program; if not, write to the Free Software
103// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
104
105pub mod utils;
106pub mod categories;
107pub mod desktop_entry;
108pub mod basedir;
109pub mod icon_theme;
110pub mod desktop_menu;
111pub mod icon_finder;
112pub mod user_dirs;
113//pub mod recently_used;
114
115#[cfg(test)]
116mod tests {
117    use crate::utils::*;
118    use crate::basedir::*;
119    extern crate tini;
120    use tini::Ini;
121    //use crate::desktop_entry::*;
122    //use crate::categories::*;
123//basedir.rs
124    #[test]
125    fn basedir_test(){
126        if cfg!(target_os = "linux") {
127            let res = data_dirs();
128            let result2 = res.unwrap().to_owned();
129            let vec:Vec<String> = convert_to_vec(data_dirs());
130            assert!(!result2.is_empty() && !vec.is_empty());
131        }
132    }
133// desktop_entry.rs
134    const TEST_DESKTOP_FILE:&str = r#"[Desktop Entry]
135Name=Test
136Name[en_US]=Test
137Name[en_GB]=Test
138Name[en]=Test
139GenericName=Generic Test
140Comment=A general test desktop file
141Icon=text-editor
142Exec=ls -lah
143Terminal=true
144Type=Application
145Categories=Utility;Core;System"#;
146    #[test]
147    fn desktop_entry_test_good() {
148let conf = Ini::from_string(TEST_DESKTOP_FILE).unwrap();
149// manual test
150let res:Option<String> = conf.get("Desktop Entry", "Categories");
151let res = res.unwrap();
152let mut split = res.split(";");
153let result:Vec<&str> = split.collect();
154// ALSO FAILS :(
155assert_eq!(result, vec![
156                                "Utility",
157                                "Core",
158                                "System",
159                                ]);
160        //TODO make desktop file to test
161
162    }
163    #[test]
164    fn desktop_entry_test_bad() {
165        //TODO make bad desktop file to test
166    }
167// utils.rs
168    #[test]
169    fn utils_converter() {
170        let true_bool:String = "true".to_string();
171        assert_eq!(Some(true), to_bool(Some(true_bool)));
172        let one_int:String = "1".to_string();
173        assert_eq!(Some(1), to_int(Some(one_int)));
174        if cfg!(target_os = "linux") {
175            let lang = get_language();
176            assert_ne!(None, lang);
177        }
178    }
179    #[test]
180    fn recent_test() {
181        /*use crate::recently_used::Xbel;
182        let file = "tests/recently-used.xbel";
183        let recent = match Xbel::read(file) {
184            Some(recent) => {
185                let bookmark = recent.items[0].clone();
186                let href = bookmark.href;
187                assert_eq!(href.as_str(), "file:///home/israel/programming/rs/vectorview/assets/blank.svg");
188                recent
189            },
190            None => {
191                assert_eq!(0,1);
192                return
193            },
194        };*/
195        
196    }
197const TEST_MENU_XML:&str = "<!DOCTYPE Menu PUBLIC \"-//freedesktop//DTD Menu 1.0//EN\"           \"http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd\">
198<Menu>
199    <Name>Test</Name>
200    <Menu>
201        <Name>Testing</Name>
202    </Menu>
203</Menu>";
204//
205    #[test]
206    fn menu_test() {
207        use crate::desktop_menu::DesktopMenu;
208        let menu = DesktopMenu::read("/etc/xdg/menus/applications.menu");
209        // Sub menu
210        //assert_eq!(menu.submenus[0].name, String::from("Testing"));
211    }
212}