Import directories are handled much better now

This commit is contained in:
Hackerpilot 2013-08-11 14:38:56 +00:00
parent 126e101e78
commit fe11e9d359
5 changed files with 102 additions and 44 deletions

View File

@ -23,6 +23,10 @@ import stdx.d.parser;
import stdx.d.ast; import stdx.d.ast;
import stdx.d.lexer; import stdx.d.lexer;
import std.stdio; import std.stdio;
import std.algorithm;
import std.path;
import std.range;
import std.conv;
import actypes; import actypes;
import messages; import messages;
@ -34,6 +38,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(Unittest dec) override void visit(Unittest dec)
{ {
// writeln("Unitttest visit");
auto symbol = new ACSymbol("*unittest*"); auto symbol = new ACSymbol("*unittest*");
auto p = parentSymbol; auto p = parentSymbol;
parentSymbol = symbol; parentSymbol = symbol;
@ -43,6 +48,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(StructDeclaration dec) override void visit(StructDeclaration dec)
{ {
// writeln("StructDeclaration visit");
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
symbol.location = dec.name.startIndex; symbol.location = dec.name.startIndex;
@ -52,6 +58,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(ClassDeclaration dec) override void visit(ClassDeclaration dec)
{ {
// writeln("ClassDeclaration visit");
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
symbol.location = dec.name.startIndex; symbol.location = dec.name.startIndex;
@ -61,6 +68,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(InterfaceDeclaration dec) override void visit(InterfaceDeclaration dec)
{ {
// writeln("InterfaceDeclaration visit");
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
symbol.location = dec.name.startIndex; symbol.location = dec.name.startIndex;
@ -70,6 +78,7 @@ class AutocompleteVisitor : ASTVisitor
override void visit(StructBody structBody) override void visit(StructBody structBody)
{ {
// writeln("StructBody visit");
auto s = scope_; auto s = scope_;
scope_ = new Scope(structBody.startLocation, structBody.endLocation); scope_ = new Scope(structBody.startLocation, structBody.endLocation);
scope_.symbols ~= new ACSymbol("this", CompletionKind.variableName, scope_.symbols ~= new ACSymbol("this", CompletionKind.variableName,
@ -82,17 +91,43 @@ class AutocompleteVisitor : ASTVisitor
override void visit(EnumDeclaration dec) override void visit(EnumDeclaration dec)
{ {
// TODO: Store type // writeln("EnumDeclaration visit");
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
symbol.location = dec.name.startIndex; symbol.location = dec.name.startIndex;
symbol.kind = CompletionKind.enumName; 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) override void visit(FunctionDeclaration dec)
{ {
// TODO: Parameters need to be added to the function body scope // writeln("FunctionDeclaration visit");
ACSymbol symbol = new ACSymbol; ACSymbol symbol = new ACSymbol;
symbol.name = dec.name.value; symbol.name = dec.name.value;
symbol.location = dec.name.startIndex; symbol.location = dec.name.startIndex;
@ -115,13 +150,14 @@ class AutocompleteVisitor : ASTVisitor
} }
// writeln("Parameter symbols added"); // 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(), symbol.calltip = format("%s %s%s", dec.returnType.toString(),
dec.name.value, dec.parameters.toString()); dec.name.value, dec.parameters.toString());
} }
auto p = parentSymbol; auto p = parentSymbol;
parentSymbol = symbol; parentSymbol = symbol;
// writeln("Call tip created");
BlockStatement functionBody = dec.functionBody is null ? null BlockStatement functionBody = dec.functionBody is null ? null
: (dec.functionBody.bodyStatement !is null : (dec.functionBody.bodyStatement !is null
@ -153,18 +189,9 @@ class AutocompleteVisitor : ASTVisitor
scope_.symbols ~= symbol; 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) override void visit(VariableDeclaration dec)
{ {
// writeln("VariableDeclaration visit");
foreach (d; dec.declarators) foreach (d; dec.declarators)
{ {
auto symbol = new ACSymbol; auto symbol = new ACSymbol;
@ -216,17 +243,7 @@ class AutocompleteVisitor : ASTVisitor
private static string convertChainToImportPath(IdentifierChain chain) private static string convertChainToImportPath(IdentifierChain chain)
{ {
string rVal; return to!string(chain.identifiers.map!"a.value"().join(dirSeparator).array) ~ ".d";
bool first = true;
foreach (identifier; chain.identifiers)
{
if (!first)
rVal ~= "/";
rVal ~= identifier.value;
first = false;
}
rVal ~= ".d";
return rVal;
} }
ACSymbol[] symbols; ACSymbol[] symbols;

View File

@ -22,6 +22,9 @@ import std.socket;
import std.stdio; import std.stdio;
import std.getopt; import std.getopt;
import std.array; import std.array;
import std.process;
import std.algorithm;
import std.path;
import msgpack; import msgpack;
import messages; import messages;
@ -51,8 +54,7 @@ int main(string[] args)
printHelp(args[0]); printHelp(args[0]);
return 0; return 0;
} }
else if (shutdown || clearCache)
if (shutdown || clearCache)
{ {
AutocompleteRequest request; AutocompleteRequest request;
if (shutdown) if (shutdown)
@ -71,10 +73,26 @@ int main(string[] args)
messageBuffer[8 .. $] = message[]; messageBuffer[8 .. $] = message[];
return socket.send(messageBuffer) == messageBuffer.length ? 0 : 1; return socket.send(messageBuffer) == messageBuffer.length ? 0 : 1;
} }
else if (importPaths.length > 0)
// cursor position is a required argument
if (cursorPos == size_t.max)
{ {
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]); printHelp(args[0]);
return 1; return 1;
} }
@ -114,7 +132,7 @@ int main(string[] args)
scope (exit) { socket.shutdown(SocketShutdown.BOTH); socket.close(); } 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.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]; ubyte[] messageBuffer = new ubyte[message.length + message.length.sizeof];
auto messageLength = message.length; auto messageLength = message.length;
messageBuffer[0 .. 8] = (cast(ubyte*) &messageLength)[0 .. 8]; messageBuffer[0 .. 8] = (cast(ubyte*) &messageLength)[0 .. 8];

View File

@ -75,7 +75,6 @@ function M.autocomplete(ch)
local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName
local p = io.popen(command, "r") local p = io.popen(command, "r")
local r = p:read("*a") local r = p:read("*a")
print(r)
if r ~= "\n" then if r ~= "\n" then
if r:match("^identifiers.*") then if r:match("^identifiers.*") then
showCompletionList(r) showCompletionList(r)

View File

@ -25,6 +25,7 @@ import stdx.d.parser;
import stdx.d.ast; import stdx.d.ast;
import std.stdio; import std.stdio;
import std.array; import std.array;
import std.path;
import acvisitor; import acvisitor;
import actypes; import actypes;
@ -56,6 +57,11 @@ struct ModuleCache
static void addImportPath(string path) static void addImportPath(string path)
{ {
importPaths ~= path; importPaths ~= path;
foreach (fileName; dirEntries(path, "*.{d,di}", SpanMode.depth))
{
writeln("Loading and caching completions for ", fileName);
getSymbolsInModule(fileName);
}
} }
/** /**
@ -66,13 +72,16 @@ struct ModuleCache
*/ */
static ACSymbol[] getSymbolsInModule(string moduleName) static ACSymbol[] getSymbolsInModule(string moduleName)
{ {
writeln("Getting symbols for module", moduleName); writeln("Getting symbols for module ", moduleName);
string location = resolveImportLoctation(moduleName); string location = resolveImportLoctation(moduleName);
if (location is null) if (location is null)
return []; return [];
if (!needsReparsing(location)) if (!needsReparsing(location))
return cache[location].symbols; return cache[location].symbols;
auto visitor = new AutocompleteVisitor;
try
{
File f = File(location); File f = File(location);
ubyte[] source = uninitializedArray!(ubyte[])(f.size); ubyte[] source = uninitializedArray!(ubyte[])(f.size);
f.rawRead(source); f.rawRead(source);
@ -80,9 +89,15 @@ struct ModuleCache
LexerConfig config; LexerConfig config;
auto tokens = source.byToken(config).array(); auto tokens = source.byToken(config).array();
Module mod = parseModule(tokens, location, &doesNothing); Module mod = parseModule(tokens, location, &doesNothing);
auto visitor = new AutocompleteVisitor;
visitor.visit(mod); visitor.visit(mod);
visitor.scope_.resolveSymbolTypes(); visitor.scope_.resolveSymbolTypes();
}
catch (Exception ex)
{
writeln("Couln't parse ", location);
return [];
}
SysTime access; SysTime access;
SysTime modification; SysTime modification;
getTimes(location, access, modification); getTimes(location, access, modification);
@ -103,6 +118,9 @@ struct ModuleCache
static string resolveImportLoctation(string moduleName) static string resolveImportLoctation(string moduleName)
{ {
writeln("Resolving location of ", moduleName); writeln("Resolving location of ", moduleName);
if (isRooted(moduleName))
return moduleName;
foreach (path; importPaths) foreach (path; importPaths)
{ {
string filePath = path ~ "/" ~ moduleName; string filePath = path ~ "/" ~ moduleName;

View File

@ -64,8 +64,10 @@ int main(string[] args)
socket.listen(0); socket.listen(0);
scope (exit) scope (exit)
{ {
writeln("Shutting down sockets...");
socket.shutdown(SocketShutdown.BOTH); socket.shutdown(SocketShutdown.BOTH);
socket.close(); socket.close();
writeln("Sockets shut down.");
} }
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...
while (true) while (true)
@ -102,7 +104,11 @@ int main(string[] args)
msgpack.unpack(buffer[8 .. bytesReceived], request); msgpack.unpack(buffer[8 .. bytesReceived], request);
if (request.kind == RequestKind.addImport) if (request.kind == RequestKind.addImport)
{ {
//ModuleCache.addImportPath(); foreach (path; request.importPaths)
{
ModuleCache.addImportPath(path);
}
} }
else if (request.kind == RequestKind.clearCache) else if (request.kind == RequestKind.clearCache)
{ {