Only split server code, no changes

This commit is contained in:
WebFreak001 2017-08-16 07:39:08 +02:00
parent cd4a027eac
commit 6c310d2d5e
5 changed files with 342 additions and 270 deletions

View File

@ -50,7 +50,8 @@ import common.messages;
* Returns:
* the autocompletion response
*/
public AutocompleteResponse complete(const AutocompleteRequest request, ref ModuleCache moduleCache)
public AutocompleteResponse complete(const AutocompleteRequest request,
ref ModuleCache moduleCache)
{
const(Token)[] tokenArray;
auto stringCache = StringCache(StringCache.defaultBucketCount);
@ -58,8 +59,12 @@ public AutocompleteResponse complete(const AutocompleteRequest request, ref Modu
request.cursorPosition, stringCache, tokenArray);
if (beforeTokens.length >= 2)
{
if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"["
|| beforeTokens[$ - 1] == tok!",")
if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"[")
{
return parenCompletion(beforeTokens, tokenArray, request.cursorPosition,
moduleCache);
}
else if (beforeTokens[$ - 1] == tok!",")
{
immutable size_t end = goBackToOpenParen(beforeTokens);
if (end != size_t.max)
@ -72,8 +77,9 @@ public AutocompleteResponse complete(const AutocompleteRequest request, ref Modu
if (kind == ImportKind.neither)
{
if (beforeTokens.isUdaExpression)
beforeTokens = beforeTokens[$ - 1 .. $];
return dotCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache);
beforeTokens = beforeTokens[$-1 .. $];
return dotCompletion(beforeTokens, tokenArray, request.cursorPosition,
moduleCache);
}
else
return importCompletion(beforeTokens, kind, moduleCache);
@ -123,7 +129,9 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
switch (significantTokenType)
{
mixin(STRING_LITERAL_CASES);
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"dstringLiteral":
foreach (symbol; arraySymbols)
{
response.completionKinds ~= symbol.kind;
@ -131,15 +139,39 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
}
response.completionType = CompletionType.identifiers;
break;
mixin(TYPE_IDENT_CASES);
case tok!"int":
case tok!"uint":
case tok!"long":
case tok!"ulong":
case tok!"char":
case tok!"wchar":
case tok!"dchar":
case tok!"bool":
case tok!"byte":
case tok!"ubyte":
case tok!"short":
case tok!"ushort":
case tok!"cent":
case tok!"ucent":
case tok!"float":
case tok!"ifloat":
case tok!"cfloat":
case tok!"idouble":
case tok!"cdouble":
case tok!"double":
case tok!"real":
case tok!"ireal":
case tok!"creal":
case tok!"identifier":
case tok!")":
case tok!"]":
case tok!"this":
case tok!"super":
auto allocator = scoped!(ASTAllocator)();
RollbackAllocator rba;
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
&rba, cursorPosition, moduleCache);
scope (exit)
pair.destroy();
scope(exit) pair.destroy();
response.setCompletions(pair.scope_, getExpression(beforeTokens),
cursorPosition, CompletionType.identifiers, false, partial);
break;
@ -195,6 +227,7 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
break;
case tok!"characterLiteral":
case tok!"doubleLiteral":
case tok!"dstringLiteral":
case tok!"floatLiteral":
case tok!"identifier":
case tok!"idoubleLiteral":
@ -203,22 +236,22 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
case tok!"irealLiteral":
case tok!"longLiteral":
case tok!"realLiteral":
case tok!"stringLiteral":
case tok!"uintLiteral":
case tok!"ulongLiteral":
case tok!"wstringLiteral":
case tok!"this":
case tok!"super":
case tok!")":
case tok!"]":
mixin(STRING_LITERAL_CASES);
auto allocator = scoped!(ASTAllocator)();
RollbackAllocator rba;
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
&rba, cursorPosition, moduleCache);
scope (exit)
pair.destroy();
scope(exit) pair.destroy();
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
response.setCompletions(pair.scope_, expression, cursorPosition,
CompletionType.calltips, beforeTokens[$ - 1] == tok!"[");
response.setCompletions(pair.scope_, expression,
cursorPosition, CompletionType.calltips, beforeTokens[$ - 1] == tok!"[");
break;
default:
break;
@ -236,7 +269,7 @@ AutocompleteResponse importCompletion(T)(T beforeTokens, ImportKind kind,
ref ModuleCache moduleCache)
in
{
assert(beforeTokens.length >= 2);
assert (beforeTokens.length >= 2);
}
body
{
@ -249,8 +282,8 @@ body
if (kind == ImportKind.normal)
{
while (beforeTokens[i].type != tok!","
&& beforeTokens[i].type != tok!"import" && beforeTokens[i].type != tok!"=")
while (beforeTokens[i].type != tok!"," && beforeTokens[i].type != tok!"import"
&& beforeTokens[i].type != tok!"=" )
i--;
setImportCompletions(beforeTokens[i .. $], response, moduleCache);
return response;
@ -276,11 +309,8 @@ body
size_t j = i;
loop2: while (j <= beforeTokens.length) switch (beforeTokens[j].type)
{
case tok!":":
break loop2;
default:
j++;
break;
case tok!":": break loop2;
default: j++; break;
}
if (i >= j)
@ -289,8 +319,11 @@ body
return response;
}
immutable string path = beforeTokens[i + 1 .. j].filter!(token => token.type == tok!"identifier")
.map!(token => cast() token.text).joiner(dirSeparator).text();
immutable string path = beforeTokens[i + 1 .. j]
.filter!(token => token.type == tok!"identifier")
.map!(token => cast() token.text)
.joiner(dirSeparator)
.text();
string resolvedLocation = moduleCache.resolveImportLocation(path);
if (resolvedLocation is null)
@ -301,15 +334,14 @@ body
auto symbols = moduleCache.getModuleSymbol(internString(resolvedLocation));
import containers.hashset : HashSet;
HashSet!string h;
void addSymbolToResponses(const(DSymbol)* sy)
{
auto a = DSymbol(sy.name);
if (!builtinSymbols.contains(&a) && sy.name !is null
&& !h.contains(sy.name) && !sy.skipOver
&& sy.name != CONSTRUCTOR_SYMBOL_NAME && isPublicCompletionKind(sy.kind))
if (!builtinSymbols.contains(&a) && sy.name !is null && !h.contains(sy.name)
&& !sy.skipOver && sy.name != CONSTRUCTOR_SYMBOL_NAME
&& isPublicCompletionKind(sy.kind))
{
response.completionKinds ~= sy.kind;
response.completions ~= sy.name;
@ -335,7 +367,8 @@ body
* tokens = the tokens after the "import" keyword and before the cursor
* response = the response that should be populated
*/
void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, ref ModuleCache cache)
void setImportCompletions(T)(T tokens, ref AutocompleteResponse response,
ref ModuleCache cache)
{
response.completionType = CompletionType.identifiers;
string partial = null;
@ -359,8 +392,8 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, ref Mo
found = true;
auto n = importPath.baseName(".d").baseName(".di");
if (isFile(importPath) && (importPath.endsWith(".d")
|| importPath.endsWith(".di")) && (partial is null || n.startsWith(partial)))
if (isFile(importPath) && (importPath.endsWith(".d") || importPath.endsWith(".di"))
&& (partial is null || n.startsWith(partial)))
{
response.completions ~= n;
response.completionKinds ~= CompletionKind.moduleName;
@ -374,11 +407,9 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, ref Mo
found = true;
try
foreach (string name; dirEntries(p, SpanMode.shallow))
try foreach (string name; dirEntries(p, SpanMode.shallow))
{
import std.path : baseName;
import std.path: baseName;
if (name.baseName.startsWith(".#"))
continue;
@ -394,12 +425,13 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, ref Mo
if (n[0] != '.' && (partial is null || n.startsWith(partial)))
{
response.completions ~= n;
response.completionKinds ~= exists(buildPath(name, "package.d")) || exists(buildPath(name,
"package.di")) ? CompletionKind.moduleName : CompletionKind.packageName;
response.completionKinds ~=
exists(buildPath(name, "package.d")) || exists(buildPath(name, "package.di"))
? CompletionKind.moduleName : CompletionKind.packageName;
}
}
}
catch (FileException)
catch(FileException)
{
warning("Cannot access import path: ", importPath);
}
@ -412,21 +444,21 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response, ref Mo
/**
*
*/
void setCompletions(T)(ref AutocompleteResponse response, Scope* completionScope, T tokens,
size_t cursorPosition, CompletionType completionType,
bool isBracket = false, string partial = null)
void setCompletions(T)(ref AutocompleteResponse response,
Scope* completionScope, T tokens, size_t cursorPosition,
CompletionType completionType, bool isBracket = false, string partial = null)
{
static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r,
string p, size_t[] circularGuard = [])
static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r, string p,
size_t[] circularGuard = [])
{
if (circularGuard.canFind(cast(size_t) s))
return;
foreach (sym; s.opSlice())
{
if (sym.name !is null && sym.name.length > 0
&& isPublicCompletionKind(sym.kind) && (p is null ? true
: toUpper(sym.name.data).startsWith(toUpper(p)))
&& !r.completions.canFind(sym.name) && sym.name[0] != '*')
if (sym.name !is null && sym.name.length > 0 && isPublicCompletionKind(sym.kind)
&& (p is null ? true : toUpper(sym.name.data).startsWith(toUpper(p)))
&& !r.completions.canFind(sym.name)
&& sym.name[0] != '*')
{
r.completionKinds ~= sym.kind;
r.completions ~= sym.name.dup;
@ -467,7 +499,8 @@ void setCompletions(T)(ref AutocompleteResponse response, Scope* completionScope
|| symbols[0].kind == CompletionKind.importSymbol
|| symbols[0].kind == CompletionKind.aliasName)
{
symbols = symbols[0].type is null || symbols[0].type is symbols[0] ? [] : [symbols[0].type];
symbols = symbols[0].type is null || symbols[0].type is symbols[0] ? []
: [symbols[0].type];
if (symbols.length == 0)
return;
}
@ -477,7 +510,8 @@ void setCompletions(T)(ref AutocompleteResponse response, Scope* completionScope
else if (completionType == CompletionType.calltips)
{
//trace("Showing call tips for ", symbols[0].name, " of kind ", symbols[0].kind);
if (symbols[0].kind != CompletionKind.functionName && symbols[0].callTip is null)
if (symbols[0].kind != CompletionKind.functionName
&& symbols[0].callTip is null)
{
if (symbols[0].kind == CompletionKind.aliasName)
{
@ -512,8 +546,8 @@ void setCompletions(T)(ref AutocompleteResponse response, Scope* completionScope
}
}
}
if (symbols[0].kind == CompletionKind.structName || symbols[0].kind
== CompletionKind.className)
if (symbols[0].kind == CompletionKind.structName
|| symbols[0].kind == CompletionKind.className)
{
auto constructor = symbols[0].getPartsByName(CONSTRUCTOR_SYMBOL_NAME);
if (constructor.length == 0)

View File

@ -40,7 +40,8 @@ import common.messages;
* Returns:
* the autocompletion response.
*/
public AutocompleteResponse findLocalUse(AutocompleteRequest request, ref ModuleCache moduleCache)
public AutocompleteResponse findLocalUse(AutocompleteRequest request,
ref ModuleCache moduleCache)
{
AutocompleteResponse response;
RollbackAllocator rba;
@ -53,7 +54,8 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, ref Module
// getSymbolsForCompletion() copy to avoid repetitive parsing
LexerConfig config;
config.fileName = "";
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode, config, &cache);
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
config, &cache);
SymbolStuff getSymbolsAtCursor(size_t cursorPosition)
{
auto sortedTokens = assumeSorted(tokenArray);
@ -66,9 +68,8 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, ref Module
}
// gets the symbol matching to cursor pos
SymbolStuff stuff = getSymbolsAtCursor(cast(size_t) request.cursorPosition);
scope (exit)
stuff.destroy();
SymbolStuff stuff = getSymbolsAtCursor(cast(size_t)request.cursorPosition);
scope(exit) stuff.destroy();
// starts searching only if no ambiguity with the symbol
if (stuff.symbols.length == 1)
@ -79,11 +80,12 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, ref Module
// gets the source token to avoid too much getSymbolsAtCursor()
const(Token)* sourceToken;
foreach (i, t; tokenArray)
foreach(i, t; tokenArray)
{
if (t.type != tok!"identifier")
continue;
if (request.cursorPosition >= t.index && request.cursorPosition < t.index + t.text.length)
if (request.cursorPosition >= t.index &&
request.cursorPosition < t.index + t.text.length)
{
sourceToken = tokenArray.ptr + i;
break;
@ -91,17 +93,16 @@ public AutocompleteResponse findLocalUse(AutocompleteRequest request, ref Module
}
// finds the tokens that match to the source symbol
if (sourceToken != null)
foreach (t; tokenArray)
if (sourceToken != null) foreach (t; tokenArray)
{
if (t.type == tok!"identifier" && t.text == sourceToken.text)
{
size_t pos = cast(size_t) t.index + 1; // place cursor inside the token
SymbolStuff candidate = getSymbolsAtCursor(pos);
scope (exit)
candidate.destroy();
if (candidate.symbols.length == 1 && candidate.symbols[0].location == sourceSymbol.location
&& candidate.symbols[0].symbolFile == sourceSymbol.symbolFile)
scope(exit) candidate.destroy();
if (candidate.symbols.length == 1 &&
candidate.symbols[0].location == sourceSymbol.location &&
candidate.symbols[0].symbolFile == sourceSymbol.symbolFile)
{
response.locations ~= t.index;
}

View File

@ -49,10 +49,9 @@ public AutocompleteResponse findDeclaration(const AutocompleteRequest request,
RollbackAllocator rba;
auto allocator = scoped!(ASTAllocator)();
auto cache = StringCache(StringCache.defaultBucketCount);
SymbolStuff stuff = getSymbolsForCompletion(request, CompletionType.location,
allocator, &rba, cache, moduleCache);
scope (exit)
stuff.destroy();
SymbolStuff stuff = getSymbolsForCompletion(request,
CompletionType.location, allocator, &rba, cache, moduleCache);
scope(exit) stuff.destroy();
if (stuff.symbols.length > 0)
{
response.symbolLocation = stuff.symbols[0].location;
@ -74,13 +73,13 @@ public AutocompleteResponse symbolSearch(const AutocompleteRequest request,
LexerConfig config;
config.fileName = "";
auto cache = StringCache(StringCache.defaultBucketCount);
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode, config, &cache);
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
config, &cache);
auto allocator = scoped!(ASTAllocator)();
RollbackAllocator rba;
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
&rba, request.cursorPosition, moduleCache);
scope (exit)
pair.destroy();
scope(exit) pair.destroy();
static struct SearchResults
{

View File

@ -147,15 +147,36 @@ SymbolStuff getSymbolsForCompletion(const AutocompleteRequest request,
request.cursorPosition, type), pair.symbol, pair.scope_);
}
static void skip(alias O, alias C, T)(T t, ref size_t i)
{
int depth = 1;
while (i < t.length) switch (t[i].type)
{
case O:
i++;
depth++;
break;
case C:
i++;
depth--;
if (depth <= 0)
return;
break;
default:
i++;
break;
}
}
bool isSliceExpression(T)(T tokens, size_t index)
{
while (index < tokens.length) switch (tokens[index].type)
{
case tok!"[":
tokens.skipParen(index, tok!"[", tok!"]");
skip!(tok!"[", tok!"]")(tokens, index);
break;
case tok!"(":
tokens.skipParen(index, tok!"(", tok!")");
skip!(tok!"(", tok!")")(tokens, index);
break;
case tok!"]":
case tok!"}":
@ -179,6 +200,22 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
//dumpTokens(tokens.release);
//writeln(">>>");
static size_t skipEnd(T tokenSlice, size_t i, IdType open, IdType close)
{
size_t j = i + 1;
for (int depth = 1; depth > 0 && j < tokenSlice.length; j++)
{
if (tokenSlice[j].type == open)
depth++;
else if (tokenSlice[j].type == close)
{
depth--;
if (depth == 0) break;
}
}
return j;
}
// Find the symbol corresponding to the beginning of the chain
DSymbol*[] symbols;
if (tokens.length == 0)
@ -187,8 +224,7 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
// e.g. (a.b!c).d
if (tokens[0] == tok!"(")
{
size_t j = 0;
tokens.skipParen(j, tok!"(", tok!")");
immutable j = skipEnd(tokens, 0, tok!"(", tok!")");
symbols = getSymbolsByTokenChain(completionScope, tokens[1 .. j],
cursorPosition, completionType);
tokens = tokens[j + 1 .. $];
@ -271,7 +307,7 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
{
void skip(IdType open, IdType close)
{
tokens.skipParen(i, open, close);
i = skipEnd(tokens, i, open, close);
}
switch (tokens[i].type)
@ -402,7 +438,7 @@ DSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
return symbols;
}
enum TYPE_IDENT_CASES = q{
private enum TYPE_IDENT_AND_LITERAL_CASES = q{
case tok!"int":
case tok!"uint":
case tok!"long":
@ -429,16 +465,11 @@ enum TYPE_IDENT_CASES = q{
case tok!"this":
case tok!"super":
case tok!"identifier":
};
enum STRING_LITERAL_CASES = q{
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"dstringLiteral":
};
enum TYPE_IDENT_AND_LITERAL_CASES = TYPE_IDENT_CASES ~ STRING_LITERAL_CASES;
/**
*
*/
@ -485,7 +516,18 @@ T getExpression(T)(T beforeTokens)
skip:
mixin (EXPRESSION_LOOP_BREAK);
immutable bookmark = i;
beforeTokens.skipParenReverse(i, open, close);
int depth = 1;
do
{
if (depth == 0 || i == 0)
break;
else
i--;
if (beforeTokens[i].type == open)
depth++;
else if (beforeTokens[i].type == close)
depth--;
} while (true);
skipCount++;
@ -532,7 +574,7 @@ T getExpression(T)(T beforeTokens)
*/
ImportKind determineImportKind(T)(T tokens)
{
assert(tokens.length > 1);
assert (tokens.length > 1);
size_t i = tokens.length - 1;
if (!(tokens[i] == tok!":" || tokens[i] == tok!"," || tokens[i] == tok!"."
|| tokens[i] == tok!"identifier"))
@ -580,7 +622,7 @@ bool isUdaExpression(T)(ref T tokens)
{
bool result;
ptrdiff_t skip;
auto i = cast(ptrdiff_t) tokens.length - 2;
ptrdiff_t i = tokens.length - 2;
if (i < 1)
return result;
@ -588,13 +630,13 @@ bool isUdaExpression(T)(ref T tokens)
// skips the UDA ctor
if (tokens[i].type == tok!")")
{
skip++;
i--;
++skip;
--i;
while (i >= 2)
{
skip += tokens[i].type == tok!")";
skip -= tokens[i].type == tok!"(";
i--;
--i;
if (skip == 0)
{
// @UDA!(TemplateParameters)(FunctionParameters)
@ -613,20 +655,20 @@ bool isUdaExpression(T)(ref T tokens)
{
// @UDA!SingleTemplateParameter
if (i > 2 && tokens[i].type == tok!"identifier" && tokens[i-1].type == tok!"!")
{
i -= 2;
}
// @UDA
if (i > 0 && tokens[i].type == tok!"identifier" && tokens[i-1].type == tok!"@")
{
result = true;
}
}
return result;
}
/**
* Traverses a token slice in reverse to find the opening parentheses or square bracket
* that begins the block the last token is in.
*/
size_t goBackToOpenParen(T)(T beforeTokens)
in
{
@ -635,7 +677,8 @@ in
body
{
size_t i = beforeTokens.length - 1;
IdType open;
IdType close;
while (true) switch (beforeTokens[i].type)
{
case tok!",":
@ -663,69 +706,36 @@ body
case tok!"[":
return i + 1;
case tok!")":
beforeTokens.skipParenReverse!true(i, tok!")", tok!"(");
break;
open = tok!")";
close = tok!"(";
goto skip;
case tok!"}":
beforeTokens.skipParenReverse!true(i, tok!"}", tok!"{");
break;
open = tok!"}";
close = tok!"{";
goto skip;
case tok!"]":
beforeTokens.skipParenReverse!true(i, tok!"]", tok!"[");
break;
default:
return size_t.max;
}
}
/**
* Skips blocks of parentheses until the starting block has been closed
*/
void skipParen(T)(T tokenSlice, ref size_t i, IdType open, IdType close)
{
if (i >= tokenSlice.length || tokenSlice.length <= 0)
return;
int depth = 1;
while (depth != 0 && i + 1 != tokenSlice.length)
{
i++;
if (tokenSlice[i].type == open)
depth++;
else if (tokenSlice[i].type == close)
depth--;
}
}
/**
* Skips blocks of parentheses in reverse until the starting block has been opened
*/
void skipParenReverse(bool before = false, T)(T beforeTokens, ref size_t i, IdType open, IdType close)
{
open = tok!"]";
close = tok!"[";
skip:
if (i == 0)
return;
return size_t.max;
else
i--;
int depth = 1;
while (depth != 0 && i != 0)
do
{
if (depth == 0 || i == 0)
break;
else
i--;
if (beforeTokens[i].type == open)
depth++;
else if (beforeTokens[i].type == close)
depth--;
} while (true);
break;
default:
return size_t.max;
}
static if (before)
if (i != 0)
i--;
}
///
unittest
{
Token[] t = [
Token(tok!"identifier"), Token(tok!"identifier"), Token(tok!"("),
Token(tok!"identifier"), Token(tok!"("), Token(tok!")"), Token(tok!",")
];
size_t i = t.length - 1;
skipParenReverse!false(t, i, tok!")", tok!"(");
assert(i == 2);
i = t.length - 1;
skipParenReverse!true(t, i, tok!")", tok!"(");
assert(i == 1);
return size_t.max;
}

View File

@ -211,8 +211,7 @@ int main(string[] args)
s.shutdown(SocketShutdown.BOTH);
s.close();
}
auto bytesReceived = s.receive(buffer);
ptrdiff_t bytesReceived = s.receive(buffer);
auto requestWatch = StopWatch(AutoStart.yes);
@ -238,7 +237,6 @@ int main(string[] args)
AutocompleteRequest request;
msgpack.unpack(buffer[size_t.sizeof .. bytesReceived], request);
if (request.kind & RequestKind.clearCache)
{
info("Clearing cache.");
@ -251,39 +249,77 @@ int main(string[] args)
}
else if (request.kind & RequestKind.query)
{
s.sendResponse(AutocompleteResponse.ack);
AutocompleteResponse response;
response.completionType = "ack";
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
continue;
}
if (request.kind & RequestKind.addImport)
{
cache.addImportPaths(request.importPaths);
}
if (request.kind & RequestKind.listImports)
{
AutocompleteResponse response;
response.importPaths = cache.getImportPaths().map!(a => cast() a).array();
ubyte[] responseBytes = msgpack.pack(response);
info("Returning import path list");
s.sendResponse(response);
s.send(responseBytes);
}
else if (request.kind & RequestKind.autocomplete)
{
info("Getting completions");
s.sendResponse(complete(request, cache));
AutocompleteResponse response = complete(request, cache);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
else if (request.kind & RequestKind.doc)
{
info("Getting doc comment");
s.trySendResponse(getDoc(request, cache), "Could not get DDoc information");
try
{
AutocompleteResponse response = getDoc(request, cache);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
warning("Could not get DDoc information", e.msg);
}
}
else if (request.kind & RequestKind.symbolLocation)
s.trySendResponse(findDeclaration(request, cache), "Could not get symbol location");
{
try
{
AutocompleteResponse response = findDeclaration(request, cache);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
warning("Could not get symbol location", e.msg);
}
}
else if (request.kind & RequestKind.search)
s.sendResponse(symbolSearch(request, cache));
{
AutocompleteResponse response = symbolSearch(request, cache);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
else if (request.kind & RequestKind.localUse)
s.trySendResponse(findLocalUse(request, cache), "Could not find local usage");
{
try
{
AutocompleteResponse response = findLocalUse(request, cache);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
warning("Could not find local usage", e.msg);
}
}
info("Request processed in ", requestWatch.peek().to!("msecs", float), " milliseconds");
}
return 0;
@ -298,24 +334,16 @@ union IPv4Union
uint i;
}
/// Lazily evaluates a response with an exception handler and sends it to a socket or logs msg if evaluating response fails.
void trySendResponse(Socket socket, lazy AutocompleteResponse response, string msg)
{
try
{
sendResponse(socket, response);
}
catch (Exception e)
{
warningf("%s: %s", msg, e.msg);
}
}
import std.regex : ctRegex;
alias envVarRegex = ctRegex!(`\$\{([_a-zA-Z][_a-zA-Z 0-9]*)\}`);
/// Packs an AutocompleteResponse and sends it to a socket.
void sendResponse(Socket socket, AutocompleteResponse response)
private unittest
{
ubyte[] responseBytes = msgpack.pack(response);
socket.send(responseBytes);
import std.regex : replaceAll;
enum input = `${HOME}/aaa/${_bb_b}/ccc`;
assert(replaceAll!(m => m[1])(input, envVarRegex) == `HOME/aaa/_bb_b/ccc`);
}
/**