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.
* 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

View File

@ -216,17 +216,19 @@ 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
@ -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();
}
}

View File

@ -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;

View File

@ -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;
@ -266,8 +264,25 @@ void setCompletions(T)(ref AutocompleteResponse response,
symbol = symbol.resolvedType;
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
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;
}

View File

@ -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();