Basic support for inheritance. Import completion. Autocomplete now works with for and foreach
This commit is contained in:
parent
23cc0c123e
commit
11465454d8
13
README.md
13
README.md
|
@ -17,21 +17,22 @@ back to the client.
|
||||||
* Autocompletion of class, struct, and interface instances.
|
* Autocompletion of class, struct, and interface instances.
|
||||||
* Display of call tips for functions, constructors, and variables of function type
|
* Display of call tips for functions, constructors, and variables of function type
|
||||||
* alias declarations
|
* alias declarations
|
||||||
|
* *import* statement completions
|
||||||
* Not working:
|
* Not working:
|
||||||
* Automatic starting of the server by the client
|
* 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
|
||||||
* Templated declarations
|
* Autocompletion of declarations with template arguments
|
||||||
* *import* statement completions
|
|
||||||
* Fields inherited from super classes or implemented interfaces.
|
* Fields inherited from super classes or implemented interfaces.
|
||||||
* *auto* declarations
|
* *auto* declarations
|
||||||
|
* *alias this*
|
||||||
* Determining the type of an enum member when no base type is specified, but the first member has an initialaizer
|
* Determining the type of an enum member when no base type is specified, but the first member has an initialaizer
|
||||||
* Public imports
|
* Public imports
|
||||||
* That one feature that you *REALLY* needed
|
* That one feature that you *REALLY* needed
|
||||||
|
|
||||||
#Setup
|
#Setup
|
||||||
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack library.
|
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack library and the parser from DScanner.
|
||||||
1. The build script assumes that the DScanner project is cloned into a sibling folder. (i.e. "../dscanner" should exist)
|
1. run the ```build.sh``` script to build the client and server.
|
||||||
1. Configure your text editor to call the dcd-client program. See the *editors* folder for directions on configuring your specific editor.
|
1. Configure your text editor to call the dcd-client program. See the *editors* folder for directions on configuring your specific editor.
|
||||||
1. Start the dcd-server program before editing code.
|
1. Start the dcd-server program before editing code.
|
||||||
|
|
||||||
|
@ -46,8 +47,8 @@ cursor position (in bytes).
|
||||||
|
|
||||||
This will cause the client to print a listing of completions to *stdout*.
|
This will cause the client to print a listing of completions to *stdout*.
|
||||||
The client will print either a listing of function call tips, or a listing of of
|
The client will print either a listing of function call tips, or a listing of of
|
||||||
completions depending on if the cursor was directly after a dot character or a
|
completions depending on if the cursor was directly after a dot character or after
|
||||||
left parethesis.
|
a left parethesis.
|
||||||
|
|
||||||
The file name is optional. If it is not specified, input will be read from *stdin*.
|
The file name is optional. If it is not specified, input will be read from *stdin*.
|
||||||
|
|
||||||
|
|
27
actypes.d
27
actypes.d
|
@ -90,6 +90,8 @@ public:
|
||||||
*/
|
*/
|
||||||
ACSymbol[] parts;
|
ACSymbol[] parts;
|
||||||
|
|
||||||
|
string[] superClasses;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Symbol's name
|
* Symbol's name
|
||||||
*/
|
*/
|
||||||
|
@ -209,7 +211,19 @@ public:
|
||||||
*/
|
*/
|
||||||
void resolveSymbolTypes()
|
void resolveSymbolTypes()
|
||||||
{
|
{
|
||||||
// TODO: auto declarations.
|
foreach (ref ACSymbol c; symbols.filter!(a => a.kind == CompletionKind.className
|
||||||
|
|| a.kind == CompletionKind.interfaceName))
|
||||||
|
{
|
||||||
|
foreach (string sc; c.superClasses)
|
||||||
|
{
|
||||||
|
ACSymbol[] s = findSymbolsInScope(sc);
|
||||||
|
if (s.length > 0)
|
||||||
|
{
|
||||||
|
foreach (part; s[0].parts)
|
||||||
|
c.parts ~= part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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
|
||||||
|
@ -218,7 +232,7 @@ public:
|
||||||
|| a.kind == CompletionKind.enumMember || a.kind == CompletionKind.aliasName)
|
|| a.kind == CompletionKind.enumMember || a.kind == CompletionKind.aliasName)
|
||||||
&& a.resolvedType is null)())
|
&& 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)
|
||||||
{
|
{
|
||||||
|
@ -252,15 +266,12 @@ public:
|
||||||
|| resolvedType[0].kind == CompletionKind.unionName
|
|| resolvedType[0].kind == CompletionKind.unionName
|
||||||
|| resolvedType[0].kind == CompletionKind.structName))
|
|| resolvedType[0].kind == CompletionKind.structName))
|
||||||
{
|
{
|
||||||
writeln("Type resolved to ", resolvedType[0].name, " which has kind ",
|
// writeln("Type resolved to ", resolvedType[0].name, " which has kind ",
|
||||||
resolvedType[0].kind, " and call tip ", resolvedType[0].calltip);
|
// resolvedType[0].kind, " and call tip ", resolvedType[0].calltip);
|
||||||
s.resolvedType = resolvedType[0];
|
s.resolvedType = resolvedType[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
writeln(type);
|
|
||||||
}
|
|
||||||
foreach (suffix; type.typeSuffixes)
|
foreach (suffix; type.typeSuffixes)
|
||||||
{
|
{
|
||||||
//writeln("Handling type suffix");
|
//writeln("Handling type suffix");
|
||||||
|
|
111
acvisitor.d
111
acvisitor.d
|
@ -33,6 +33,12 @@ import messages;
|
||||||
import modulecache;
|
import modulecache;
|
||||||
import autocomplete;
|
import autocomplete;
|
||||||
|
|
||||||
|
// TODO: a lot of duplicated code
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts an AST into a simple symbol and scope heirarchy so that the
|
||||||
|
* autocompletion coed can do its job more easily.
|
||||||
|
*/
|
||||||
class AutocompleteVisitor : ASTVisitor
|
class AutocompleteVisitor : ASTVisitor
|
||||||
{
|
{
|
||||||
alias ASTVisitor.visit visit;
|
alias ASTVisitor.visit visit;
|
||||||
|
@ -67,6 +73,100 @@ class AutocompleteVisitor : ASTVisitor
|
||||||
mixin (visitAndAdd);
|
mixin (visitAndAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(ForStatement forStatement)
|
||||||
|
{
|
||||||
|
if (forStatement.declarationOrStatement is null) goto visitBody;
|
||||||
|
if (forStatement.declarationOrStatement.declaration is null) goto visitBody;
|
||||||
|
if (forStatement.declarationOrStatement.declaration.variableDeclaration is null) goto visitBody;
|
||||||
|
if (forStatement.statementNoCaseNoDefault is null) goto visitBody;
|
||||||
|
if (forStatement.statementNoCaseNoDefault.blockStatement is null) goto visitBody;
|
||||||
|
|
||||||
|
// writeln("Visiting for statement");
|
||||||
|
|
||||||
|
ACSymbol[] symbols;
|
||||||
|
VariableDeclaration varDec = forStatement.declarationOrStatement.declaration.variableDeclaration;
|
||||||
|
Type t = varDec.type;
|
||||||
|
foreach (Declarator declarator; varDec.declarators)
|
||||||
|
{
|
||||||
|
ACSymbol symbol = new ACSymbol();
|
||||||
|
symbol.name = declarator.name.value;
|
||||||
|
symbol.type = t;
|
||||||
|
symbol.kind = CompletionKind.variableName;
|
||||||
|
symbols ~= symbol;
|
||||||
|
writeln("For statement variable ", symbol.name, " of type ", symbol.type, " added.");
|
||||||
|
}
|
||||||
|
BlockStatement block = forStatement.statementNoCaseNoDefault.blockStatement;
|
||||||
|
auto s = new Scope(forStatement.startIndex,
|
||||||
|
block.endLocation);
|
||||||
|
s.parent = scope_;
|
||||||
|
scope_.children ~= s;
|
||||||
|
auto p = scope_;
|
||||||
|
scope_ = s;
|
||||||
|
|
||||||
|
foreach (symbol; symbols)
|
||||||
|
{
|
||||||
|
writeln("added ", symbol.name, " to scope");
|
||||||
|
symbol.location = scope_.start;
|
||||||
|
scope_.symbols ~= symbol;
|
||||||
|
|
||||||
|
}
|
||||||
|
if (block.declarationsAndStatements !is null)
|
||||||
|
{
|
||||||
|
writeln("visiting body");
|
||||||
|
visit(block.declarationsAndStatements);
|
||||||
|
}
|
||||||
|
scope_ = p;
|
||||||
|
return;
|
||||||
|
|
||||||
|
visitBody:
|
||||||
|
// writeln("visiting body");
|
||||||
|
if (forStatement.statementNoCaseNoDefault !is null)
|
||||||
|
visit(forStatement.statementNoCaseNoDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ForeachStatement statement)
|
||||||
|
{
|
||||||
|
ACSymbol[] symbols;
|
||||||
|
|
||||||
|
if (statement.foreachTypeList is null)
|
||||||
|
{
|
||||||
|
statement.statementNoCaseNoDefault.accept(this);
|
||||||
|
}
|
||||||
|
else if (statement.foreachType !is null)
|
||||||
|
{
|
||||||
|
ACSymbol loopVariable = new ACSymbol(statement.foreachType.identifier.value);
|
||||||
|
loopVariable.type = statement.foreachType.type;
|
||||||
|
loopVariable.kind = CompletionKind.variableName;
|
||||||
|
symbols ~= loopVariable;
|
||||||
|
}
|
||||||
|
else foreach (ForeachType feType; statement.foreachTypeList.items.filter!(a => a.type !is null))
|
||||||
|
{
|
||||||
|
ACSymbol loopVariable = new ACSymbol(feType.identifier.value);
|
||||||
|
loopVariable.type = feType.type;
|
||||||
|
loopVariable.kind = CompletionKind.variableName;
|
||||||
|
symbols ~= loopVariable;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statement.statementNoCaseNoDefault !is null
|
||||||
|
&& statement.statementNoCaseNoDefault.blockStatement !is null)
|
||||||
|
{
|
||||||
|
BlockStatement block = statement.statementNoCaseNoDefault.blockStatement;
|
||||||
|
auto s = scope_;
|
||||||
|
scope_ = new Scope(statement.startIndex,
|
||||||
|
block.endLocation);
|
||||||
|
scope_.parent = s;
|
||||||
|
foreach (symbol; symbols)
|
||||||
|
{
|
||||||
|
symbol.location = block.startLocation;
|
||||||
|
scope_.symbols ~= symbol;
|
||||||
|
}
|
||||||
|
if (block.declarationsAndStatements !is null)
|
||||||
|
block.declarationsAndStatements.accept(this);
|
||||||
|
s.children ~= scope_;
|
||||||
|
scope_ = s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(InterfaceDeclaration dec)
|
override void visit(InterfaceDeclaration dec)
|
||||||
{
|
{
|
||||||
// writeln("InterfaceDeclaration visit");
|
// writeln("InterfaceDeclaration visit");
|
||||||
|
@ -77,6 +177,15 @@ class AutocompleteVisitor : ASTVisitor
|
||||||
mixin (visitAndAdd);
|
mixin (visitAndAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override void visit(BaseClass baseClass)
|
||||||
|
{
|
||||||
|
// TODO: handle qualified names
|
||||||
|
if (baseClass.identifierOrTemplateChain is null) return;
|
||||||
|
if (baseClass.identifierOrTemplateChain.identifiersOrTemplateInstances.length != 1) return;
|
||||||
|
if (parentSymbol is null) return;
|
||||||
|
parentSymbol.superClasses ~= baseClass.identifierOrTemplateChain.toString();
|
||||||
|
}
|
||||||
|
|
||||||
override void visit(StructBody structBody)
|
override void visit(StructBody structBody)
|
||||||
{
|
{
|
||||||
// writeln("StructBody visit");
|
// writeln("StructBody visit");
|
||||||
|
@ -154,7 +263,7 @@ class AutocompleteVisitor : ASTVisitor
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dec.parameters !is null)
|
if (dec.parameters !is null && parentSymbol !is null)
|
||||||
{
|
{
|
||||||
symbol.calltip = format("%s this%s", parentSymbol.name,
|
symbol.calltip = format("%s this%s", parentSymbol.name,
|
||||||
dec.parameters.toString());
|
dec.parameters.toString());
|
||||||
|
|
|
@ -23,17 +23,20 @@ module autocomplete;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import std.array;
|
import std.array;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import stdx.d.ast;
|
import std.file;
|
||||||
import stdx.d.lexer;
|
import std.path;
|
||||||
import stdx.d.parser;
|
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.uni;
|
import std.uni;
|
||||||
|
import stdx.d.ast;
|
||||||
|
import stdx.d.lexer;
|
||||||
|
import stdx.d.parser;
|
||||||
|
|
||||||
import messages;
|
import messages;
|
||||||
import acvisitor;
|
import acvisitor;
|
||||||
import actypes;
|
import actypes;
|
||||||
import constants;
|
import constants;
|
||||||
|
import modulecache;
|
||||||
|
|
||||||
|
|
||||||
AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
|
@ -151,7 +154,14 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
AutocompleteVisitor visitor, T tokens, size_t cursorPosition,
|
AutocompleteVisitor visitor, T tokens, size_t cursorPosition,
|
||||||
CompletionType completionType)
|
CompletionType completionType)
|
||||||
{
|
{
|
||||||
assert (visitor.scope_);
|
// Autocomplete module imports instead of symbols
|
||||||
|
if (tokens[0].type == TokenType.import_)
|
||||||
|
{
|
||||||
|
if (completionType == CompletionType.identifiers)
|
||||||
|
setImportCompletions(tokens, response);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
visitor.scope_.resolveSymbolTypes();
|
visitor.scope_.resolveSymbolTypes();
|
||||||
ACSymbol[] symbols = visitor.scope_.findSymbolsInCurrentScope(cursorPosition, tokens[0].value);
|
ACSymbol[] symbols = visitor.scope_.findSymbolsInCurrentScope(cursorPosition, tokens[0].value);
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
|
@ -223,11 +233,11 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
break loop;
|
break loop;
|
||||||
break;
|
break;
|
||||||
case identifier:
|
case identifier:
|
||||||
// stderr.writeln("looking for ", tokens[i].value, " in ", symbols[0].name);
|
writeln("looking for ", tokens[i].value, " in ", symbols[0].name);
|
||||||
symbols = symbols[0].getPartsByName(tokens[i].value);
|
symbols = symbols[0].getPartsByName(tokens[i].value);
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
{
|
{
|
||||||
// writeln("Couldn't find it.");
|
writeln("Couldn't find it.");
|
||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
if (symbols[0].kind == CompletionKind.variableName
|
if (symbols[0].kind == CompletionKind.variableName
|
||||||
|
@ -239,6 +249,8 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
{
|
{
|
||||||
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
|
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
|
||||||
}
|
}
|
||||||
|
if (symbols.length == 0)
|
||||||
|
break loop;
|
||||||
if (symbols[0].kind == CompletionKind.aliasName
|
if (symbols[0].kind == CompletionKind.aliasName
|
||||||
&& (completionType == CompletionType.identifiers
|
&& (completionType == CompletionType.identifiers
|
||||||
|| i + 1 < tokens.length))
|
|| i + 1 < tokens.length))
|
||||||
|
@ -246,10 +258,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
|
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
|
||||||
}
|
}
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
{
|
|
||||||
// writeln("Couldn't find it.");
|
|
||||||
break loop;
|
break loop;
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case lParen:
|
case lParen:
|
||||||
open = TokenType.lParen;
|
open = TokenType.lParen;
|
||||||
|
@ -358,6 +367,8 @@ T getExpression(T)(T beforeTokens)
|
||||||
{
|
{
|
||||||
with (TokenType) switch (beforeTokens[i].type)
|
with (TokenType) switch (beforeTokens[i].type)
|
||||||
{
|
{
|
||||||
|
case TokenType.import_:
|
||||||
|
break expressionLoop;
|
||||||
case TokenType.int_:
|
case TokenType.int_:
|
||||||
case TokenType.uint_:
|
case TokenType.uint_:
|
||||||
case TokenType.long_:
|
case TokenType.long_:
|
||||||
|
@ -446,22 +457,36 @@ T getExpression(T)(T beforeTokens)
|
||||||
return beforeTokens[i .. $];
|
return beforeTokens[i .. $];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
|
||||||
|
{
|
||||||
|
writeln("Setting import collections");
|
||||||
|
response.completionType = CompletionType.identifiers;
|
||||||
|
string path = buildPath(tokens.filter!(a => a.type == TokenType.identifier).map!("a.value").array());
|
||||||
|
foreach (importDirectory; ModuleCache.getImportPaths())
|
||||||
|
{
|
||||||
|
string p = format("%s%s%s", importDirectory, dirSeparator, path);
|
||||||
|
writeln("Checking for ", p);
|
||||||
|
if (!exists(p))
|
||||||
|
continue;
|
||||||
|
foreach (string name; dirEntries(p, SpanMode.shallow))
|
||||||
|
{
|
||||||
|
if (isFile(name) && (name.endsWith(".d") || name.endsWith(".di")))
|
||||||
|
{
|
||||||
|
response.completions ~= name.baseName(".d").baseName(".di");
|
||||||
|
response.completionKinds ~= CompletionKind.moduleName;
|
||||||
|
}
|
||||||
|
else if (isDir(name))
|
||||||
|
{
|
||||||
|
response.completions ~= name.baseName();
|
||||||
|
response.completionKinds ~= CompletionKind.packageName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string createCamelCaseRegex(string input)
|
string createCamelCaseRegex(string input)
|
||||||
{
|
{
|
||||||
dstring output;
|
return to!string(input.map!(a => isLower(a) ? [a] : ".*"d ~ a).join());
|
||||||
uint i;
|
|
||||||
foreach (dchar d; input)
|
|
||||||
{
|
|
||||||
if (isLower(d))
|
|
||||||
output ~= d;
|
|
||||||
else if (i > 0)
|
|
||||||
{
|
|
||||||
output ~= ".*";
|
|
||||||
output ~= d;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
return to!string(output ~ ".*");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unittest
|
unittest
|
||||||
|
|
2
build.sh
2
build.sh
|
@ -1,2 +1,2 @@
|
||||||
dmd -wi client.d messages.d msgpack-d/src/msgpack.d -Imsgpack-d/src -ofdcd-client
|
dmd -wi client.d messages.d msgpack-d/src/msgpack.d -Imsgpack-d/src -ofdcd-client
|
||||||
dmd -wi server.d modulecache.d actypes.d messages.d constants.d acvisitor.d autocomplete.d dscanner/stdx/d/ast.d dscanner/stdx/d/parser.d dscanner/stdx/d/lexer.d dscanner/stdx/d/entities.d msgpack-d/src/msgpack.d -Imsgpack-d/src -Idscanner/ -ofdcd-server
|
dmd -wi -g server.d modulecache.d actypes.d messages.d constants.d acvisitor.d autocomplete.d dscanner/stdx/d/ast.d dscanner/stdx/d/parser.d dscanner/stdx/d/lexer.d dscanner/stdx/d/entities.d msgpack-d/src/msgpack.d -Imsgpack-d/src -Idscanner/ -ofdcd-server
|
||||||
|
|
6
client.d
6
client.d
|
@ -25,6 +25,7 @@ import std.array;
|
||||||
import std.process;
|
import std.process;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import std.path;
|
import std.path;
|
||||||
|
import std.file;
|
||||||
|
|
||||||
import msgpack;
|
import msgpack;
|
||||||
import messages;
|
import messages;
|
||||||
|
@ -100,6 +101,11 @@ int main(string[] args)
|
||||||
// Read in the source
|
// Read in the source
|
||||||
bool usingStdin = args.length <= 1;
|
bool usingStdin = args.length <= 1;
|
||||||
string fileName = usingStdin ? "stdin" : args[1];
|
string fileName = usingStdin ? "stdin" : args[1];
|
||||||
|
if (!usingStdin && !exists(args[1]))
|
||||||
|
{
|
||||||
|
stderr.writefln("%s does not exist");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
File f = usingStdin ? stdin : File(args[1]);
|
File f = usingStdin ? stdin : File(args[1]);
|
||||||
ubyte[] sourceCode;
|
ubyte[] sourceCode;
|
||||||
if (usingStdin)
|
if (usingStdin)
|
||||||
|
|
2
dscanner
2
dscanner
|
@ -1 +1 @@
|
||||||
Subproject commit bace5f0a76e27b4837a49dfba8a8e7c60c6344f3
|
Subproject commit 270cd6d9a1196ea802e79958605c9705c5ea22d4
|
|
@ -0,0 +1,36 @@
|
||||||
|
/* XPM */
|
||||||
|
static char * alias_xpm[] = {
|
||||||
|
"16 16 17 1",
|
||||||
|
" c None",
|
||||||
|
". c #547AA0",
|
||||||
|
"+ c #547BA2",
|
||||||
|
"@ c #547CA4",
|
||||||
|
"# c #F0F0F0",
|
||||||
|
"$ c #547DA6",
|
||||||
|
"% c #F5F5F5",
|
||||||
|
"& c #547EA8",
|
||||||
|
"* c #FBFBFB",
|
||||||
|
"= c #F7F7F7",
|
||||||
|
"- c #F2F2F2",
|
||||||
|
"; c #547BA3",
|
||||||
|
"> c #ECECEC",
|
||||||
|
", c #547AA1",
|
||||||
|
"' c #E7E7E7",
|
||||||
|
") c #54799F",
|
||||||
|
"! c #54789D",
|
||||||
|
" ",
|
||||||
|
" ",
|
||||||
|
" .......... ",
|
||||||
|
" ++++++++++++ ",
|
||||||
|
" @@@@@##@@@@@ ",
|
||||||
|
" $$$$%%%%$$$$ ",
|
||||||
|
" &&&&****&&&& ",
|
||||||
|
" &&&==&&==&&& ",
|
||||||
|
" $$$==$$==$$$ ",
|
||||||
|
" @@@------@@@ ",
|
||||||
|
" ;;>>>>>>>>;; ",
|
||||||
|
" ,,'',,,,'',, ",
|
||||||
|
" )))))))))))) ",
|
||||||
|
" !!!!!!!!!! ",
|
||||||
|
" ",
|
||||||
|
" "};
|
|
@ -57,6 +57,8 @@ struct ModuleCache
|
||||||
*/
|
*/
|
||||||
static void addImportPath(string path)
|
static void addImportPath(string path)
|
||||||
{
|
{
|
||||||
|
if (!exists(path))
|
||||||
|
return;
|
||||||
importPaths ~= path;
|
importPaths ~= path;
|
||||||
foreach (fileName; dirEntries(path, "*.{d,di}", SpanMode.depth))
|
foreach (fileName; dirEntries(path, "*.{d,di}", SpanMode.depth))
|
||||||
{
|
{
|
||||||
|
@ -96,7 +98,7 @@ struct ModuleCache
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
writeln("Couln't parse ", location);
|
writeln("Couln't parse ", location, " due to exception: ", ex.msg);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
SysTime access;
|
SysTime access;
|
||||||
|
@ -118,7 +120,7 @@ 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))
|
if (isRooted(moduleName))
|
||||||
return moduleName;
|
return moduleName;
|
||||||
|
|
||||||
|
|
1
server.d
1
server.d
|
@ -56,6 +56,7 @@ int main(string[] args)
|
||||||
|
|
||||||
auto socket = new TcpSocket(AddressFamily.INET);
|
auto socket = new TcpSocket(AddressFamily.INET);
|
||||||
socket.blocking = true;
|
socket.blocking = true;
|
||||||
|
socket.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true);
|
||||||
socket.bind(new InternetAddress("127.0.0.1", port));
|
socket.bind(new InternetAddress("127.0.0.1", port));
|
||||||
socket.listen(0);
|
socket.listen(0);
|
||||||
scope (exit)
|
scope (exit)
|
||||||
|
|
Loading…
Reference in New Issue