diff --git a/acvisitor.d b/acvisitor.d index 24cfc2b..b083882 100644 --- a/acvisitor.d +++ b/acvisitor.d @@ -23,6 +23,10 @@ import stdx.d.parser; import stdx.d.ast; import stdx.d.lexer; import std.stdio; +import std.algorithm; +import std.path; +import std.range; +import std.conv; import actypes; import messages; @@ -34,6 +38,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(Unittest dec) { +// writeln("Unitttest visit"); auto symbol = new ACSymbol("*unittest*"); auto p = parentSymbol; parentSymbol = symbol; @@ -43,6 +48,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(StructDeclaration dec) { +// writeln("StructDeclaration visit"); auto symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; @@ -52,6 +58,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(ClassDeclaration dec) { +// writeln("ClassDeclaration visit"); auto symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; @@ -61,6 +68,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(InterfaceDeclaration dec) { +// writeln("InterfaceDeclaration visit"); auto symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; @@ -70,6 +78,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(StructBody structBody) { +// writeln("StructBody visit"); auto s = scope_; scope_ = new Scope(structBody.startLocation, structBody.endLocation); scope_.symbols ~= new ACSymbol("this", CompletionKind.variableName, @@ -82,17 +91,43 @@ class AutocompleteVisitor : ASTVisitor override void visit(EnumDeclaration dec) { - // TODO: Store type +// writeln("EnumDeclaration visit"); auto symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; symbol.kind = CompletionKind.enumName; - mixin (visitAndAdd); + auto type = dec.type; + auto p = parentSymbol; + parentSymbol = symbol; + + if (dec.enumBody !is null) + { + foreach (member; dec.enumBody.enumMembers) + { + auto s = new ACSymbol; + s.kind = CompletionKind.enumMember; + s.name = member.name.value; + s.location = member.name.startIndex; + if (type is null) + s.resolvedType = scope_.findSymbolInScope("int"); + else + s.type = type; + if (parentSymbol !is null) + parentSymbol.parts ~= s; + } + } + + parentSymbol = p; + if (parentSymbol is null) + symbols ~= symbol; + else + parentSymbol.parts ~= symbol; + scope_.symbols ~= symbol; } override void visit(FunctionDeclaration dec) { - // TODO: Parameters need to be added to the function body scope +// writeln("FunctionDeclaration visit"); ACSymbol symbol = new ACSymbol; symbol.name = dec.name.value; symbol.location = dec.name.startIndex; @@ -115,13 +150,14 @@ class AutocompleteVisitor : ASTVisitor } // writeln("Parameter symbols added"); - if (dec.returnType !is null) + if (dec.returnType !is null && dec.parameters !is null) { symbol.calltip = format("%s %s%s", dec.returnType.toString(), dec.name.value, dec.parameters.toString()); } auto p = parentSymbol; parentSymbol = symbol; +// writeln("Call tip created"); BlockStatement functionBody = dec.functionBody is null ? null : (dec.functionBody.bodyStatement !is null @@ -153,18 +189,9 @@ class AutocompleteVisitor : ASTVisitor scope_.symbols ~= symbol; } - override void visit(EnumMember member) - { - auto s = new ACSymbol; - s.kind = CompletionKind.enumMember; - s.name = member.name.value; - s.location = member.name.startIndex; - if (parentSymbol !is null) - parentSymbol.parts ~= s; - } - override void visit(VariableDeclaration dec) { +// writeln("VariableDeclaration visit"); foreach (d; dec.declarators) { auto symbol = new ACSymbol; @@ -216,17 +243,7 @@ class AutocompleteVisitor : ASTVisitor private static string convertChainToImportPath(IdentifierChain chain) { - string rVal; - bool first = true; - foreach (identifier; chain.identifiers) - { - if (!first) - rVal ~= "/"; - rVal ~= identifier.value; - first = false; - } - rVal ~= ".d"; - return rVal; + return to!string(chain.identifiers.map!"a.value"().join(dirSeparator).array) ~ ".d"; } ACSymbol[] symbols; diff --git a/client.d b/client.d index 3bde6eb..a66bfa4 100644 --- a/client.d +++ b/client.d @@ -22,6 +22,9 @@ import std.socket; import std.stdio; import std.getopt; import std.array; +import std.process; +import std.algorithm; +import std.path; import msgpack; import messages; @@ -51,8 +54,7 @@ int main(string[] args) printHelp(args[0]); return 0; } - - if (shutdown || clearCache) + else if (shutdown || clearCache) { AutocompleteRequest request; if (shutdown) @@ -71,10 +73,26 @@ int main(string[] args) messageBuffer[8 .. $] = message[]; return socket.send(messageBuffer) == messageBuffer.length ? 0 : 1; } - - // cursor position is a required argument - if (cursorPos == size_t.max) + else if (importPaths.length > 0) + { + AutocompleteRequest request; + request.kind = RequestKind.addImport; + request.importPaths = importPaths.map!(a => isRooted(a) ? a : absolutePath(a)).array; + auto socket = new TcpSocket(AddressFamily.INET); + scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } + socket.connect(new InternetAddress("127.0.0.1", port)); + socket.blocking = true; + socket.setOption(SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, 1); + ubyte[] message = msgpack.pack(request); + ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof]; + auto messageLength = message.length; + messageBuffer[0 .. 8] = (cast(ubyte*) &messageLength)[0 .. 8]; + messageBuffer[8 .. $] = message[]; + return socket.send(messageBuffer) == messageBuffer.length ? 0 : 1; + } + else if (cursorPos == size_t.max) { + // cursor position is a required argument printHelp(args[0]); return 1; } @@ -112,9 +130,9 @@ int main(string[] args) // Send message to server auto socket = new TcpSocket(AddressFamily.INET); scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } - socket.connect(new InternetAddress("127.0.0.1", port)); + socket.connect(new InternetAddress("127.0.0.1", port)); socket.blocking = true; - socket.setOption(SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, 1); + //socket.setOption(SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, 1); ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof]; auto messageLength = message.length; messageBuffer[0 .. 8] = (cast(ubyte*) &messageLength)[0 .. 8]; diff --git a/editors/textadept/modules/dmd/dcd.lua b/editors/textadept/modules/dmd/dcd.lua index a69422d..9b14c85 100644 --- a/editors/textadept/modules/dmd/dcd.lua +++ b/editors/textadept/modules/dmd/dcd.lua @@ -75,7 +75,6 @@ function M.autocomplete(ch) local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName local p = io.popen(command, "r") local r = p:read("*a") - print(r) if r ~= "\n" then if r:match("^identifiers.*") then showCompletionList(r) diff --git a/modulecache.d b/modulecache.d index a4c9280..f26bb44 100644 --- a/modulecache.d +++ b/modulecache.d @@ -25,6 +25,7 @@ import stdx.d.parser; import stdx.d.ast; import std.stdio; import std.array; +import std.path; import acvisitor; import actypes; @@ -56,6 +57,11 @@ struct ModuleCache static void addImportPath(string path) { importPaths ~= path; + foreach (fileName; dirEntries(path, "*.{d,di}", SpanMode.depth)) + { + writeln("Loading and caching completions for ", fileName); + getSymbolsInModule(fileName); + } } /** @@ -66,23 +72,32 @@ struct ModuleCache */ static ACSymbol[] getSymbolsInModule(string moduleName) { - writeln("Getting symbols for module", moduleName); + writeln("Getting symbols for module ", moduleName); string location = resolveImportLoctation(moduleName); if (location is null) return []; if (!needsReparsing(location)) return cache[location].symbols; - File f = File(location); - ubyte[] source = uninitializedArray!(ubyte[])(f.size); - f.rawRead(source); - - LexerConfig config; - auto tokens = source.byToken(config).array(); - Module mod = parseModule(tokens, location, &doesNothing); auto visitor = new AutocompleteVisitor; - visitor.visit(mod); - visitor.scope_.resolveSymbolTypes(); + try + { + File f = File(location); + ubyte[] source = uninitializedArray!(ubyte[])(f.size); + f.rawRead(source); + + LexerConfig config; + auto tokens = source.byToken(config).array(); + Module mod = parseModule(tokens, location, &doesNothing); + + visitor.visit(mod); + visitor.scope_.resolveSymbolTypes(); + } + catch (Exception ex) + { + writeln("Couln't parse ", location); + return []; + } SysTime access; SysTime modification; getTimes(location, access, modification); @@ -103,6 +118,9 @@ struct ModuleCache static string resolveImportLoctation(string moduleName) { writeln("Resolving location of ", moduleName); + if (isRooted(moduleName)) + return moduleName; + foreach (path; importPaths) { string filePath = path ~ "/" ~ moduleName; diff --git a/server.d b/server.d index c2b39d7..b5d606b 100644 --- a/server.d +++ b/server.d @@ -64,8 +64,10 @@ int main(string[] args) socket.listen(0); scope (exit) { + writeln("Shutting down sockets..."); socket.shutdown(SocketShutdown.BOTH); socket.close(); + writeln("Sockets shut down."); } ubyte[1024 * 1024 * 4] buffer = void; // 4 megabytes should be enough for anybody... while (true) @@ -102,7 +104,11 @@ int main(string[] args) msgpack.unpack(buffer[8 .. bytesReceived], request); if (request.kind == RequestKind.addImport) { - //ModuleCache.addImportPath(); + foreach (path; request.importPaths) + { + ModuleCache.addImportPath(path); + } + } else if (request.kind == RequestKind.clearCache) {