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