diff --git a/README.md b/README.md index 3774f9d..d04dc98 100644 --- a/README.md +++ b/README.md @@ -17,14 +17,13 @@ back to the client. * Autocompletion of class, struct, and interface instances. * Display of call tips (but only for the first overload) * Not working: + * Automatic starting of the server by the client * Windows support (I don't know that it won't work, but this program is not tested on Windows yet) * UFCS - * Templates + * Templated declarations * *auto* declarations - * Operator overloading (opIndex, opSlice, etc) when autocompleting - * Instances of enum types resolve to the enum itself instead of the enum base type + * Determining the type of an enum member when no base type is specified, but the first member has an initialaizer * Public imports - * Array and associative array indexing in autocompletion * That one feature that you *REALLY* needed #Setup diff --git a/actypes.d b/actypes.d index 03930f0..8950b08 100644 --- a/actypes.d +++ b/actypes.d @@ -216,35 +216,37 @@ public: */ void resolveSymbolTypes() { + // TODO: auto declarations. + // We only care about resolving types of variables, all other symbols // don't have any indirection - // TODO: Resolve types of enum members foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName - || a.kind == CompletionKind.functionName - || a.kind == CompletionKind.memberVariableName) && a.resolvedType is null)()) + || a.kind == CompletionKind.functionName || a.kind == CompletionKind.memberVariableName + || a.kind == CompletionKind.enumMember) && a.resolvedType is null)()) { //writeln("Resolving type of symbol ", s.name); Type type = s.type; if (type is null) continue; - if (type.type2.builtinType != TokenType.invalid) - { - // This part is easy. Autocomplete properties of built-in types - s.resolvedType = findSymbolInCurrentScope(s.location, - getTokenValue(type.type2.builtinType)); - } - else if (type.type2.symbol !is null) - { - // Look up a type by its name for cases like class, enum, - // interface, struct, or union members. - // TODO: Does not work with qualified names or template instances - Symbol sym = type.type2.symbol; - if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) - return; - s.resolvedType = findSymbolInCurrentScope(s.location, - sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); - } + if (type.type2.builtinType != TokenType.invalid) + { + // This part is easy. Autocomplete properties of built-in types + s.resolvedType = findSymbolInCurrentScope(s.location, + getTokenValue(type.type2.builtinType)); + } + else if (type.type2.symbol !is null) + { + // Look up a type by its name for cases like class, enum, + // interface, struct, or union members. + + // TODO: Does not work with qualified names or template instances + Symbol sym = type.type2.symbol; + if (sym.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) + return; + s.resolvedType = findSymbolInCurrentScope(s.location, + sym.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value); + } foreach (suffix; type.typeSuffixes) { // Handle type suffixes for declarations, e.g.: @@ -264,21 +266,19 @@ public: } else { - // ormal array + // normal array s.resolvedType.qualifier = SymbolQualifier.array; s.resolvedType.parts ~= arraySymbols; } } else if (suffix.delegateOrFunction.type != TokenType.invalid) { - // TODO: figure out how to handle this, if necessary s.resolvedType.qualifier = SymbolQualifier.func; } } } foreach (c; children) { - assert (c !is null); c.resolveSymbolTypes(); } } diff --git a/acvisitor.d b/acvisitor.d index b083882..36d5a4c 100644 --- a/acvisitor.d +++ b/acvisitor.d @@ -91,6 +91,7 @@ class AutocompleteVisitor : ASTVisitor override void visit(EnumDeclaration dec) { + // TODO: Set enum type based on initializer of first member // writeln("EnumDeclaration visit"); auto symbol = new ACSymbol; symbol.name = dec.name.value; @@ -102,6 +103,8 @@ class AutocompleteVisitor : ASTVisitor if (dec.enumBody !is null) { + Scope enumBodyScope = new Scope(dec.enumBody.startLocation, + dec.enumBody.endLocation); foreach (member; dec.enumBody.enumMembers) { auto s = new ACSymbol; @@ -114,7 +117,10 @@ class AutocompleteVisitor : ASTVisitor s.type = type; if (parentSymbol !is null) parentSymbol.parts ~= s; + enumBodyScope.symbols ~= s; } + enumBodyScope.parent = scope_; + scope_.children ~= enumBodyScope; } parentSymbol = p; diff --git a/autocomplete.d b/autocomplete.d index a04c7bc..b7bb49f 100644 --- a/autocomplete.d +++ b/autocomplete.d @@ -154,8 +154,6 @@ void setCompletions(T)(ref AutocompleteResponse response, CompletionType completionType) { - writeln("Getting completions for ", map!"a.value"(tokens)); - writeln("Resolving symbols for editor buffer"); visitor.scope_.resolveSymbolTypes(); ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value); if (symbol is null) @@ -166,7 +164,8 @@ void setCompletions(T)(ref AutocompleteResponse response, if (completionType == CompletionType.identifiers && symbol.kind == CompletionKind.memberVariableName - || symbol.kind == CompletionKind.variableName) + || symbol.kind == CompletionKind.variableName + || symbol.kind == CompletionKind.enumMember) { symbol = symbol.resolvedType; if (symbol is null) @@ -233,6 +232,7 @@ void setCompletions(T)(ref AutocompleteResponse response, } if (symbol.kind == CompletionKind.variableName || symbol.kind == CompletionKind.memberVariableName + || symbol.kind == CompletionKind.enumMember || (symbol.kind == CompletionKind.functionName && (completionType == CompletionType.identifiers || i + 1 < tokens.length))) @@ -248,8 +248,6 @@ void setCompletions(T)(ref AutocompleteResponse response, case lBracket: open = TokenType.lBracket; close = TokenType.rBracket; - // TODO: handle opIndex - // TODO: handle opSlice if (symbol.qualifier == SymbolQualifier.array) { auto h = i; @@ -267,7 +265,24 @@ void setCompletions(T)(ref AutocompleteResponse response, skip(); } else - return; + { + auto h = i; + skip(); + Parser p; + p.setTokens(tokens[h .. i].array()); + ACSymbol overload; + if (p.isSliceExpression()) + overload = symbol.getPartByName("opSlice"); + else + overload = symbol.getPartByName("opIndex"); + if (overload !is null) + { + writeln("opIndex or opSlice used, ", overload.name); + symbol = overload.resolvedType; + } + else + return; + } break; case dot: break; @@ -282,10 +297,10 @@ void setCompletions(T)(ref AutocompleteResponse response, } if (completionType == CompletionType.identifiers) { - writeln("Writing out the parts of ", symbol.name); + writeln("Writing completions for ", symbol.name); foreach (s; symbol.parts) { - //writeln("Adding ", s.name, " to the completion list"); + writeln("Adding ", s.name, " to the completion list"); response.completionKinds ~= s.kind; response.completions ~= s.name; } @@ -293,7 +308,6 @@ void setCompletions(T)(ref AutocompleteResponse response, } else { - writeln("Adding calltip for ", symbol.name, ": ", symbol.calltip); response.completions ~= symbol.calltip; response.completionType = CompletionType.calltips; } diff --git a/server.d b/server.d index b5d606b..2ca6330 100644 --- a/server.d +++ b/server.d @@ -54,10 +54,6 @@ int main(string[] args) importPaths ~= loadConfiguredImportDirs(); - foreach (path; importPaths) - ModuleCache.addImportPath(path); - writeln("Import directories: ", ModuleCache.getImportPaths()); - auto socket = new TcpSocket(AddressFamily.INET); socket.blocking = true; socket.bind(new InternetAddress("127.0.0.1", port)); @@ -69,7 +65,15 @@ int main(string[] args) socket.close(); writeln("Sockets shut down."); } + + foreach (path; importPaths) + ModuleCache.addImportPath(path); + writeln("Import directories: ", ModuleCache.getImportPaths()); + ubyte[1024 * 1024 * 4] buffer = void; // 4 megabytes should be enough for anybody... + + writeln("Startup complete"); + while (true) { auto s = socket.accept();