1 module workspaced.com.snippets.dependencies; 2 3 import workspaced.api; 4 import workspaced.com.dub; 5 import workspaced.com.snippets; 6 7 import std.algorithm; 8 9 /// 10 alias SnippetList = PlainSnippet[]; 11 12 /// A list of dependencies usable in an associative array 13 struct DependencySet 14 { 15 string[] sorted; 16 17 void set(string[] deps) 18 { 19 deps.sort!"a<b"; 20 sorted = deps; 21 } 22 23 bool hasAll(string[] deps) const 24 { 25 deps.sort!"a<b"; 26 int a, b; 27 while (a < sorted.length && b < deps.length) 28 { 29 const as = sorted[a]; 30 const bs = deps[b]; 31 const c = cmp(as, bs); 32 33 if (c == 0) 34 { 35 a++; 36 b++; 37 } 38 else if (c < 0) 39 return false; 40 else 41 b++; 42 } 43 return a == sorted.length; 44 } 45 46 bool opEquals(const ref DependencySet other) const 47 { 48 return sorted == other.sorted; 49 } 50 51 size_t toHash() const @safe nothrow 52 { 53 size_t ret; 54 foreach (v; sorted) 55 ret ^= typeid(v).getHash((() @trusted => &v)()); 56 return ret; 57 } 58 } 59 60 class DependencyBasedSnippetProvider : SnippetProvider 61 { 62 SnippetList[DependencySet] snippets; 63 64 void addSnippet(string[] requiredDependencies, PlainSnippet snippet) 65 { 66 DependencySet set; 67 set.set(requiredDependencies); 68 69 if (auto v = set in snippets) 70 *v ~= snippet; 71 else 72 snippets[set] = [snippet]; 73 } 74 75 Future!(Snippet[]) provideSnippets(scope const WorkspaceD.Instance instance, 76 scope const(char)[] file, scope const(char)[] code, int position, const SnippetInfo info) 77 { 78 if (!instance.has!DubComponent) 79 return Future!(Snippet[]).fromResult(null); 80 else 81 { 82 string id = typeid(this).name; 83 auto dub = instance.get!DubComponent; 84 return Future!(Snippet[]).async(delegate() { 85 string[] deps; 86 foreach (dep; dub.dependencies) 87 { 88 deps ~= dep.name; 89 deps ~= dep.dependencies.keys; 90 } 91 Snippet[] ret; 92 foreach (k, v; snippets) 93 { 94 if (k.hasAll(deps)) 95 { 96 foreach (snip; v) 97 if (snip.levels.canFind(info.level)) 98 ret ~= snip.buildSnippet(id); 99 } 100 } 101 return ret; 102 }); 103 } 104 } 105 106 Future!Snippet resolveSnippet(scope const WorkspaceD.Instance instance, 107 scope const(char)[] file, scope const(char)[] code, int position, 108 const SnippetInfo info, Snippet snippet) 109 { 110 snippet.resolved = true; 111 return Future!Snippet.fromResult(snippet); 112 } 113 } 114 115 unittest 116 { 117 DependencySet set; 118 set.set(["vibe-d", "mir", "serve-d"]); 119 assert(set.hasAll(["vibe-d", "serve-d", "mir"])); 120 assert(set.hasAll(["vibe-d", "serve-d", "serve-d", "serve-d", "mir", "mir"])); 121 assert(set.hasAll(["vibe-d", "serve-d", "mir", "workspace-d"])); 122 assert(set.hasAll(["diet-ng", "vibe-d", "serve-d", "mir", "workspace-d"])); 123 assert(!set.hasAll(["diet-ng", "serve-d", "mir", "workspace-d"])); 124 assert(!set.hasAll(["diet-ng", "serve-d", "vibe-d", "workspace-d"])); 125 assert(!set.hasAll(["diet-ng", "mir", "mir", "vibe-d", "workspace-d"])); 126 assert(!set.hasAll(["diet-ng", "mir", "vibe-d", "workspace-d"])); 127 128 set.set(null); 129 assert(set.hasAll([])); 130 assert(set.hasAll(["foo"])); 131 }