1 module workspaced.com.snippets.smart;
2 
3 import workspaced.api;
4 import workspaced.com.snippets;
5 
6 import std.conv;
7 
8 class SmartSnippetProvider : SnippetProvider
9 {
10 	Future!(Snippet[]) provideSnippets(scope const WorkspaceD.Instance instance,
11 			scope const(char)[] file, scope const(char)[] code, int position, const SnippetInfo info)
12 	{
13 		if (info.loopScope.supported)
14 		{
15 			Snippet[] res;
16 			if (info.loopScope.numItems > 1)
17 			{
18 				res ~= ndForeach(info.loopScope.numItems, info.loopScope.iterator);
19 				res ~= simpleForeach();
20 				res ~= stringIterators();
21 			}
22 			else if (info.loopScope.stringIterator)
23 			{
24 				res ~= simpleForeach();
25 				res ~= stringIterators(info.loopScope.iterator);
26 			}
27 			else
28 			{
29 				res ~= simpleForeach(info.loopScope.iterator, info.loopScope.type);
30 				res ~= stringIterators();
31 			}
32 			return Future!(Snippet[]).fromResult(res);
33 		}
34 		else
35 			return Future!(Snippet[]).fromResult(null);
36 	}
37 
38 	Future!Snippet resolveSnippet(scope const WorkspaceD.Instance instance,
39 			scope const(char)[] file, scope const(char)[] code, int position,
40 			const SnippetInfo info, Snippet snippet)
41 	{
42 		return Future!Snippet.fromResult(snippet);
43 	}
44 
45 	Snippet ndForeach(int n, string name = null)
46 	{
47 		Snippet ret;
48 		ret.providerId = typeid(this).name;
49 		ret.id = "nd";
50 		ret.title = "foreach over " ~ n.to!string ~ " keys";
51 		if (name.length)
52 			ret.title ~= " (over " ~ name ~ ")";
53 		ret.shortcut = "foreach";
54 		ret.documentation = "Foreach over locally defined variable with " ~ n.to!string ~ " keys.";
55 		string keys;
56 		if (n == 2)
57 		{
58 			keys = "key, value";
59 		}
60 		else if (n <= 4)
61 		{
62 			foreach (i; 0 .. n - 1)
63 			{
64 				keys ~= cast(char)('i' + i) ~ ", ";
65 			}
66 			keys ~= "value";
67 		}
68 		else
69 		{
70 			foreach (i; 0 .. n - 1)
71 			{
72 				keys ~= "k" ~ (i + 1).to!string ~ ", ";
73 			}
74 			keys ~= "value";
75 		}
76 
77 		if (name.length)
78 		{
79 			ret.plain = "foreach (" ~ keys ~ "; " ~ name ~ ") {\n\t\n}";
80 			ret.snippet = "foreach (${1:" ~ keys ~ "}; ${2:" ~ name ~ "}) {\n\t$0\n}";
81 		}
82 		else
83 		{
84 			ret.plain = "foreach (" ~ keys ~ "; map) {\n\t\n}";
85 			ret.snippet = "foreach (${1:" ~ keys ~ "}; ${2:map}) {\n\t$0\n}";
86 		}
87 		ret.resolved = true;
88 		return ret;
89 	}
90 
91 	Snippet simpleForeach(string name = null, string type = null)
92 	{
93 		Snippet ret;
94 		ret.providerId = typeid(this).name;
95 		ret.id = "simple";
96 		ret.title = "foreach loop";
97 		if (name.length)
98 			ret.title ~= " (over " ~ name ~ ")";
99 		ret.shortcut = "foreach";
100 		ret.documentation = name.length
101 			? "Foreach over locally defined variable." : "Foreach over a variable or range.";
102 		string t = type.length ? type ~ " " : null;
103 		if (name.length)
104 		{
105 			ret.plain = "foreach (" ~ t ~ "key; " ~ name ~ ") {\n\t\n}";
106 			ret.snippet = "foreach (" ~ t ~ "${1:key}; ${2:" ~ name ~ "}) {\n\t$0\n}";
107 		}
108 		else
109 		{
110 			ret.plain = "foreach (" ~ t ~ "key; list) {\n\t\n}";
111 			ret.snippet = "foreach (" ~ t ~ "${1:key}; ${2:list}) {\n\t$0\n}";
112 		}
113 		ret.resolved = true;
114 		return ret;
115 	}
116 
117 	Snippet stringIterators(string name = null)
118 	{
119 		Snippet ret;
120 		ret.providerId = typeid(this).name;
121 		ret.id = "str";
122 		ret.title = "foreach loop";
123 		if (name.length)
124 			ret.title ~= " (unicode over " ~ name ~ ")";
125 		else
126 			ret.title ~= " (unicode)";
127 		ret.shortcut = "foreach_utf";
128 		ret.documentation = name.length
129 			? "Foreach over locally defined variable." : "Foreach over a variable or range.";
130 		if (name.length)
131 		{
132 			ret.plain = "foreach (char key; " ~ name ~ ") {\n\t\n}";
133 			ret.snippet = "foreach (${1|char,wchar,dchar|} ${2:key}; ${3:" ~ name ~ "}) {\n\t$0\n}";
134 		}
135 		else
136 		{
137 			ret.plain = "foreach (char key; str) {\n\t\n}";
138 			ret.snippet = "foreach (${1|char,wchar,dchar|} ${2:key}; ${3:str}) {\n\t$0\n}";
139 		}
140 		ret.resolved = true;
141 		return ret;
142 	}
143 }