1 module ws.x.desktop;
2 
3 
4 import
5 	std.file,
6 	std.algorithm,
7 	std.array,
8 	std.path,
9 	std.regex,
10 	std.stdio,
11 	std.string;
12 
13 
14 const string[] desktopPaths = [
15 	"/usr",
16 	"/usr/local",
17 	"~/.local"
18 ];
19 
20 
21 class DesktopEntry {
22 
23 	string path;
24 	string exec;
25 	string type;
26 	string name;
27 	string comment;
28 	string terminal;
29 	string[] categories;
30 	bool noDisplay;
31 
32 	this(string path, string text){
33 		bool validSection;
34 		this.path = path;
35 		foreach(line; text.splitLines){
36 			if(line.startsWith("["))
37 				validSection = line == "[Desktop Entry]";
38 			else if(validSection && line.startsWith("Exec="))
39 				exec = line.chompPrefix("Exec=");
40 			else if(validSection && line.startsWith("Name="))
41 				name = line.chompPrefix("Name=");
42 			else if(validSection && line.startsWith("Categories="))
43 				categories = line.chompPrefix("Categories=").split(";").filter!"a.length".array;
44 			else if(validSection && line.startsWith("NoDisplay="))
45 				noDisplay = line.canFind("true");
46 		}
47 	}
48 
49 }
50 
51 DesktopEntry[] readDesktop(string path){
52 	DesktopEntry[] result;
53 	if(!path.isFile)
54 		return result;
55 	foreach(section; matchAll(path.readText, `\[[^\]\r\n]+\](?:\r?\n(?:[^\[\r\n].*)?)*`)){
56 		result ~= new DesktopEntry(path, section.hit);
57 	}
58 	return result;
59 }
60 
61 DesktopEntry[] getAll(){
62 	DesktopEntry[] result;
63 	foreach(path; desktopPaths){
64 		if((path.expandTilde~"/share/applications").exists)
65 			foreach(entry; (path.expandTilde~"/share/applications").dirEntries(SpanMode.breadth))
66 				try
67 					result ~= readDesktop(entry);
68 				catch(FileException e){}
69 				catch(Throwable t)
70 					writeln("DESKTOP_ERROR %s: %s".format(entry, t));
71 	}
72 	return result;
73 }
74