Autocomplete of enum members and handling of opSlice and opIndex

This commit is contained in:
Hackerpilot 2013-08-11 17:39:26 +00:00
parent fe11e9d359
commit bf3c7ba500
5 changed files with 63 additions and 40 deletions

View File

@ -17,14 +17,13 @@ back to the client.
* Autocompletion of class, struct, and interface instances. * Autocompletion of class, struct, and interface instances.
* Display of call tips (but only for the first overload) * Display of call tips (but only for the first overload)
* Not working: * 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) * Windows support (I don't know that it won't work, but this program is not tested on Windows yet)
* UFCS * UFCS
* Templates * Templated declarations
* *auto* declarations * *auto* declarations
* Operator overloading (opIndex, opSlice, etc) when autocompleting * Determining the type of an enum member when no base type is specified, but the first member has an initialaizer
* Instances of enum types resolve to the enum itself instead of the enum base type
* Public imports * Public imports
* Array and associative array indexing in autocompletion
* That one feature that you *REALLY* needed * That one feature that you *REALLY* needed
#Setup #Setup

View File

@ -216,17 +216,19 @@ public:
*/ */
void resolveSymbolTypes() void resolveSymbolTypes()
{ {
// TODO: auto declarations.
// We only care about resolving types of variables, all other symbols // We only care about resolving types of variables, all other symbols
// don't have any indirection // don't have any indirection
// TODO: Resolve types of enum members
foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName foreach (ref s; symbols.filter!(a => (a.kind == CompletionKind.variableName
|| a.kind == CompletionKind.functionName || a.kind == CompletionKind.functionName || a.kind == CompletionKind.memberVariableName
|| a.kind == CompletionKind.memberVariableName) && a.resolvedType is null)()) || a.kind == CompletionKind.enumMember) && a.resolvedType is null)())
{ {
//writeln("Resolving type of symbol ", s.name); //writeln("Resolving type of symbol ", s.name);
Type type = s.type; Type type = s.type;
if (type is null) if (type is null)
continue; continue;
if (type.type2.builtinType != TokenType.invalid) if (type.type2.builtinType != TokenType.invalid)
{ {
// This part is easy. Autocomplete properties of built-in types // This part is easy. Autocomplete properties of built-in types
@ -264,21 +266,19 @@ public:
} }
else else
{ {
// ormal array // normal array
s.resolvedType.qualifier = SymbolQualifier.array; s.resolvedType.qualifier = SymbolQualifier.array;
s.resolvedType.parts ~= arraySymbols; s.resolvedType.parts ~= arraySymbols;
} }
} }
else if (suffix.delegateOrFunction.type != TokenType.invalid) else if (suffix.delegateOrFunction.type != TokenType.invalid)
{ {
// TODO: figure out how to handle this, if necessary
s.resolvedType.qualifier = SymbolQualifier.func; s.resolvedType.qualifier = SymbolQualifier.func;
} }
} }
} }
foreach (c; children) foreach (c; children)
{ {
assert (c !is null);
c.resolveSymbolTypes(); c.resolveSymbolTypes();
} }
} }

View File

@ -91,6 +91,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(EnumDeclaration dec) override void visit(EnumDeclaration dec)
{ {
// TODO: Set enum type based on initializer of first member
// writeln("EnumDeclaration visit"); // writeln("EnumDeclaration visit");
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
@ -102,6 +103,8 @@ class AutocompleteVisitor : ASTVisitor
if (dec.enumBody !is null) if (dec.enumBody !is null)
{ {
Scope enumBodyScope = new Scope(dec.enumBody.startLocation,
dec.enumBody.endLocation);
foreach (member; dec.enumBody.enumMembers) foreach (member; dec.enumBody.enumMembers)
{ {
auto s = new ACSymbol; auto s = new ACSymbol;
@ -114,7 +117,10 @@ class AutocompleteVisitor : ASTVisitor
s.type = type; s.type = type;
if (parentSymbol !is null) if (parentSymbol !is null)
parentSymbol.parts ~= s; parentSymbol.parts ~= s;
enumBodyScope.symbols ~= s;
} }
enumBodyScope.parent = scope_;
scope_.children ~= enumBodyScope;
} }
parentSymbol = p; parentSymbol = p;

View File

@ -154,8 +154,6 @@ void setCompletions(T)(ref AutocompleteResponse response,
CompletionType completionType) CompletionType completionType)
{ {
writeln("Getting completions for ", map!"a.value"(tokens));
writeln("Resolving symbols for editor buffer");
visitor.scope_.resolveSymbolTypes(); visitor.scope_.resolveSymbolTypes();
ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value); ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
if (symbol is null) if (symbol is null)
@ -166,7 +164,8 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (completionType == CompletionType.identifiers if (completionType == CompletionType.identifiers
&& symbol.kind == CompletionKind.memberVariableName && symbol.kind == CompletionKind.memberVariableName
|| symbol.kind == CompletionKind.variableName) || symbol.kind == CompletionKind.variableName
|| symbol.kind == CompletionKind.enumMember)
{ {
symbol = symbol.resolvedType; symbol = symbol.resolvedType;
if (symbol is null) if (symbol is null)
@ -233,6 +232,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
if (symbol.kind == CompletionKind.variableName if (symbol.kind == CompletionKind.variableName
|| symbol.kind == CompletionKind.memberVariableName || symbol.kind == CompletionKind.memberVariableName
|| symbol.kind == CompletionKind.enumMember
|| (symbol.kind == CompletionKind.functionName || (symbol.kind == CompletionKind.functionName
&& (completionType == CompletionType.identifiers && (completionType == CompletionType.identifiers
|| i + 1 < tokens.length))) || i + 1 < tokens.length)))
@ -248,8 +248,6 @@ void setCompletions(T)(ref AutocompleteResponse response,
case lBracket: case lBracket:
open = TokenType.lBracket; open = TokenType.lBracket;
close = TokenType.rBracket; close = TokenType.rBracket;
// TODO: handle opIndex
// TODO: handle opSlice
if (symbol.qualifier == SymbolQualifier.array) if (symbol.qualifier == SymbolQualifier.array)
{ {
auto h = i; auto h = i;
@ -266,8 +264,25 @@ void setCompletions(T)(ref AutocompleteResponse response,
symbol = symbol.resolvedType; symbol = symbol.resolvedType;
skip(); skip();
} }
else
{
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 else
return; return;
}
break; break;
case dot: case dot:
break; break;
@ -282,10 +297,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
if (completionType == CompletionType.identifiers) if (completionType == CompletionType.identifiers)
{ {
writeln("Writing out the parts of ", symbol.name); writeln("Writing completions for ", symbol.name);
foreach (s; symbol.parts) 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.completionKinds ~= s.kind;
response.completions ~= s.name; response.completions ~= s.name;
} }
@ -293,7 +308,6 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
else else
{ {
writeln("Adding calltip for ", symbol.name, ": ", symbol.calltip);
response.completions ~= symbol.calltip; response.completions ~= symbol.calltip;
response.completionType = CompletionType.calltips; response.completionType = CompletionType.calltips;
} }

View File

@ -54,10 +54,6 @@ int main(string[] args)
importPaths ~= loadConfiguredImportDirs(); importPaths ~= loadConfiguredImportDirs();
foreach (path; importPaths)
ModuleCache.addImportPath(path);
writeln("Import directories: ", ModuleCache.getImportPaths());
auto socket = new TcpSocket(AddressFamily.INET); auto socket = new TcpSocket(AddressFamily.INET);
socket.blocking = true; socket.blocking = true;
socket.bind(new InternetAddress("127.0.0.1", port)); socket.bind(new InternetAddress("127.0.0.1", port));
@ -69,7 +65,15 @@ int main(string[] args)
socket.close(); socket.close();
writeln("Sockets shut down."); 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... ubyte[1024 * 1024 * 4] buffer = void; // 4 megabytes should be enough for anybody...
writeln("Startup complete");
while (true) while (true)
{ {
auto s = socket.accept(); auto s = socket.accept();