Import directories are handled much better now
This commit is contained in:
parent
126e101e78
commit
fe11e9d359
67
acvisitor.d
67
acvisitor.d
|
|
@ -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;
|
||||||
|
|
|
||||||
32
client.d
32
client.d
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
@ -112,9 +130,9 @@ int main(string[] args)
|
||||||
// Send message to server
|
// Send message to server
|
||||||
auto socket = new TcpSocket(AddressFamily.INET);
|
auto socket = new TcpSocket(AddressFamily.INET);
|
||||||
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];
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,23 +72,32 @@ 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;
|
||||||
|
|
||||||
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;
|
auto visitor = new AutocompleteVisitor;
|
||||||
visitor.visit(mod);
|
try
|
||||||
visitor.scope_.resolveSymbolTypes();
|
{
|
||||||
|
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 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;
|
||||||
|
|
|
||||||
8
server.d
8
server.d
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue