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 }