1 module served.lsp.uri; 2 3 import served.lsp.protocol; 4 import std.path; 5 import std..string; 6 7 DocumentUri uriFromFile(string file) 8 { 9 import std.uri : encodeComponent; 10 11 if (!isAbsolute(file)) 12 throw new Exception("Tried to pass relative path '" ~ file ~ "' to uriFromFile"); 13 file = file.buildNormalizedPath.replace("\\", "/"); 14 if (file.length == 0) 15 return ""; 16 if (file[0] != '/') 17 file = '/' ~ file; // always triple slash at start but never quad slash 18 if (file.length >= 2 && file[0 .. 2] == "//") // Shares (\\share\bob) are different somehow 19 file = file[2 .. $]; 20 return "file://" ~ file.encodeComponent.replace("%2F", "/"); 21 } 22 23 string uriToFile(DocumentUri uri) 24 { 25 import std.uri : decodeComponent; 26 import std..string : startsWith; 27 28 if (uri.startsWith("file://")) 29 { 30 string ret = uri["file://".length .. $].decodeComponent; 31 if (ret.length >= 3 && ret[0] == '/' && ret[2] == ':') 32 return ret[1 .. $].replace("/", "\\"); 33 else if (ret.length >= 1 && ret[0] != '/') 34 return "\\\\" ~ ret.replace("/", "\\"); 35 return ret; 36 } 37 else 38 return null; 39 } 40 41 @system unittest 42 { 43 void testUri(string a, string b) 44 { 45 void assertEqual(A, B)(A a, B b) 46 { 47 import std.conv : to; 48 49 assert(a == b, a.to!string ~ " is not equal to " ~ b.to!string); 50 } 51 52 assertEqual(a.uriFromFile, b); 53 assertEqual(a, b.uriToFile); 54 assertEqual(a.uriFromFile.uriToFile, a); 55 } 56 57 version (Windows) 58 { 59 // taken from vscode-uri 60 testUri(`c:\test with %\path`, `file:///c%3A/test%20with%20%25/path`); 61 testUri(`c:\test with %25\path`, `file:///c%3A/test%20with%20%2525/path`); 62 testUri(`c:\test with %25\c#code`, `file:///c%3A/test%20with%20%2525/c%23code`); 63 testUri(`\\shäres\path\c#\plugin.json`, `file://sh%C3%A4res/path/c%23/plugin.json`); 64 testUri(`\\localhost\c$\GitDevelopment\express`, `file://localhost/c%24/GitDevelopment/express`); 65 } 66 else version (Posix) 67 { 68 testUri(`/home/pi/.bashrc`, `file:///home/pi/.bashrc`); 69 testUri(`/home/pi/Development Projects/D-code`, `file:///home/pi/Development%20Projects/D-code`); 70 } 71 } 72 73 DocumentUri uri(string scheme, string authority, string path, string query, string fragment) 74 { 75 return scheme ~ "://" 76 ~ (authority.length ? authority : "") 77 ~ (path.length ? path : "/") 78 ~ (query.length ? "?" ~ query : "") 79 ~ (fragment.length ? "#" ~ fragment : ""); 80 }