xDg

git clone git://xatko.vsos.ethz.ch/xDg.git
Log | Files | Refs

desktop.d (3530B)


      1 module xdg.desktop;
      2 import std.stdio;
      3 import std.string;
      4 import std.path;
      5 import std.process;
      6 import std.algorithm:joiner,splitter,startsWith,skipOver,findSplit,map;
      7 import std.range;
      8 import std.file;
      9 import std.format;
     10 import std.array;
     11 import xdg.mime;
     12 
     13 
     14 auto file_url_to_path(inout(char)[] uri){
     15 	uri.skipOver("file://localhost");
     16 	uri.skipOver("file://");
     17 	return uri;
     18 }
     19 
     20 auto xdg_user_dir(){
     21 	auto home = environment.get("XDG_DATA_HOME", buildPath(environment.get("HOME"), ".local/share"));
     22 	auto sys = environment.get("XDG_DATA_DIRS", "/usr/local/share/:/usr/share/");
     23 	return chain(home.splitter(":"),sys.splitter(":")).map!(a=>buildPath(a,"applications"));
     24 }
     25 
     26 struct Database{
     27 	struct Entry{
     28 		string path;
     29 		string baseName;
     30 		string name;
     31 		string icon;
     32 		string exec;
     33 		string[] mimeTypes;
     34 		
     35 		auto format(in char[] path){
     36 			Appender!string app;
     37 			auto fmt = exec;
     38 			while(fmt.length>0){
     39 				auto s = fmt.findSplit("%");
     40 				app ~= s[0];
     41 				if(s[1].length==0){
     42 					break;
     43 				}
     44 				switch(s[2][0]){
     45 					case '%':
     46 						app ~= "%";
     47 					break;
     48 					case 'i':
     49 						app ~= "--icon "~icon;
     50 					break;
     51 					case 'f':
     52 					case 'F':
     53 					case 'u':
     54 					case 'U':
     55 						app ~= '"'~path.replace("\"","\\\"")~'"';
     56 					break;
     57 					default:
     58 						throw new Exception("Unknown format literal {}".format(s[2]));
     59 					break;
     60 				}
     61 				fmt = s[2][1..$];
     62 			}
     63 			return app.data;
     64 		}
     65 		
     66 		void fromFile(in char[] file){
     67 			auto f = File(file, "r");
     68 			scope(exit){
     69 				f.close();
     70 			}
     71 			path = file.idup;
     72 			baseName = .baseName(path);
     73 			string entry = "";
     74 			foreach(l; f.byLine){
     75 				if(l[0]=='['){
     76 					entry = l[1..$-1].idup;
     77 				}
     78 				if(entry == "Desktop Entry"){
     79 					auto s = l.findSplit("=");
     80 					switch(s[0]){
     81 						case "Name":
     82 							name = s[2].idup;
     83 						break;
     84 						case "Exec":
     85 							exec = s[2].idup;
     86 						break;
     87 						case "Icon":
     88 							icon = s[2].idup;
     89 						break;
     90 						case "MimeType":
     91 							mimeTypes = s[2].idup.split(";");
     92 						break;
     93 						default:
     94 						break;
     95 					}
     96 				}
     97 			}
     98 		}
     99 	}
    100 	
    101 	Entry[][string] entries;
    102 	Entry[][string] entries_by_basename;
    103 	Entry[string] preferred;
    104 	void index(in char[] path){
    105 		writeln("Indexing ", path);
    106 		auto de = dirEntries(cast(string)path, "*.desktop", SpanMode.breadth);
    107 		foreach(entry; de){
    108 			Entry e;
    109 			try{
    110 				e.fromFile(entry);
    111 			}
    112 			catch(Exception exc){
    113 				
    114 				writeln(exc);
    115 			}
    116 			foreach(mt; e.mimeTypes){
    117 				entries[mt] ~= e;
    118 			}
    119 			entries_by_basename[e.baseName] ~= e;
    120 		}
    121 	}
    122 	
    123 	void index(){
    124 		auto paths = xdg_user_dir();
    125 		foreach(path; paths){
    126 			if(!exists(path))
    127 				continue;
    128 			try{
    129 				index(path);
    130 			}
    131 			catch(Exception e){
    132 				writeln(e);
    133 			}
    134 		}
    135 		
    136 	}
    137 	
    138 	void loadPreferred(){
    139 		auto config_home = environment.get("XDG_CONFIG_HOME",buildPath(environment.get("HOME"), ".config"));
    140 		auto config = buildPath(config_home, "mimeapps.list");
    141 		if(exists(config)){
    142 			auto f = File(config);
    143 			scope(exit){
    144 				f.close();
    145 			}
    146 			foreach(l; f.byLine()){
    147 				auto s = l.findSplit("=");
    148 				if(s[1].length > 0){
    149 					auto de = s[2].findSplit(";")[0];
    150 					if(auto entries = de in entries_by_basename){
    151 						preferred[s[0].idup] = (*entries)[0];
    152 					}
    153 					else{
    154 						stderr.writeln("No entry for %s found".format(de));
    155 					}
    156 				}
    157 			}
    158 		}
    159 	}
    160 	
    161 	void init(){
    162 		index();
    163 		loadPreferred();
    164 	}
    165 	
    166 	Entry get(in char[] mime){
    167 		if(auto e = mime in preferred){
    168 			return *e;
    169 		}
    170 		else if(auto e = mime in entries){
    171 			return (*e)[0];
    172 		}
    173 		else{
    174 			throw new Exception("Mime type %s not found".format(mime));
    175 		}
    176 	}
    177 }
    178