Added documentation. Removed duplicated code from autocompletion module

This commit is contained in:
Hackerpilot 2014-02-08 20:56:13 -08:00
parent e6c03b6610
commit f52cb6ad2a
11 changed files with 397 additions and 254 deletions

6
.gitignore vendored
View File

@ -5,8 +5,10 @@
# *nix binaries
dcd-client
dcd-server
dcd-client.o
dcd-server.o
*.o
# Perf reports
perf.data
# Valgrind reports
callgrind.*

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -28,6 +28,9 @@ import std.array;
import std.typecons;
import std.container;
/**
* Compares symbols by their name
*/
bool comparitor(const(ACSymbol)* a, const(ACSymbol)* b) pure nothrow
{
return a.name < b.name;
@ -150,8 +153,16 @@ public:
SymbolQualifier qualifier;
}
/**
* Contains symbols and supports lookup of symbols by cursor position.
*/
struct Scope
{
/**
* Params:
* begin = the beginning byte index
* end = the ending byte index
*/
this (size_t begin, size_t end)
{
this.startLocation = begin;
@ -159,6 +170,12 @@ struct Scope
this.symbols = new RedBlackTree!(ACSymbol*, comparitor, true);
}
/**
* Params:
* cursorPosition = the cursor position in bytes
* Returns:
* the innermost scope that contains the given cursor position
*/
Scope* getScopeByCursor(size_t cursorPosition) const
{
if (cursorPosition < startLocation) return null;
@ -172,6 +189,13 @@ struct Scope
return cast(typeof(return)) &this;
}
/**
* Params:
* cursorPosition = the cursor position in bytes
* Returns:
* all symbols in the scope containing the cursor position, as well as
* the symbols in parent scopes of that scope.
*/
ACSymbol*[] getSymbolsInCursorScope(size_t cursorPosition) const
{
auto s = getScopeByCursor(cursorPosition);
@ -188,14 +212,18 @@ struct Scope
return symbols.array();
}
/**
* Params:
* name = the symbol name to search for
* Returns:
* all symbols in this scope or parent scopes with the given name
*/
ACSymbol*[] getSymbolsByName(string name) const
{
import std.range;
ACSymbol s = ACSymbol(name);
RedBlackTree!(ACSymbol*, comparitor, true) t = cast() symbols;
auto r = t.equalRange(&s).array();
version(assert) foreach (n; r)
assert (n.name == name, name);
if (r.length > 0)
return cast(typeof(return)) r;
if (parent is null)
@ -203,6 +231,14 @@ struct Scope
return parent.getSymbolsByName(name);
}
/**
* Params:
* name = the symbol name to search for
* cursorPosition = the cursor position in bytes
* Returns:
* all symbols with the given name in the scope containing the cursor
* and its parent scopes
*/
ACSymbol*[] getSymbolsByNameAndCursor(string name, size_t cursorPosition) const
{
auto s = getScopeByCursor(cursorPosition);
@ -230,6 +266,9 @@ struct Scope
RedBlackTree!(ACSymbol*, comparitor, true) symbols;
}
/**
* Import information
*/
struct ImportInformation
{
/// Import statement parts
@ -243,6 +282,41 @@ struct ImportInformation
}
/**
* Symbols for the built in types
*/
RedBlackTree!(ACSymbol*, comparitor, true) builtinSymbols;
/**
* Array properties
*/
RedBlackTree!(ACSymbol*, comparitor, true) arraySymbols;
/**
* Associative array properties
*/
RedBlackTree!(ACSymbol*, comparitor, true) assocArraySymbols;
/**
* Enum, union, class, and interface properties
*/
RedBlackTree!(ACSymbol*, comparitor, true) aggregateSymbols;
/**
* Class properties
*/
RedBlackTree!(ACSymbol*, comparitor, true) classSymbols;
/**
* Type of the _argptr variable
*/
Type argptrType;
/**
* Type of _arguments
*/
Type argumentsType;
/**
* Initializes builtin types and the various properties of builtin types
*/
@ -406,10 +480,3 @@ static this()
classSymbols = clSym;
}
RedBlackTree!(ACSymbol*, comparitor, true) builtinSymbols;
RedBlackTree!(ACSymbol*, comparitor, true) arraySymbols;
RedBlackTree!(ACSymbol*, comparitor, true) assocArraySymbols;
RedBlackTree!(ACSymbol*, comparitor, true) aggregateSymbols;
RedBlackTree!(ACSymbol*, comparitor, true) classSymbols;
Type argptrType;
Type argumentsType;

View File

@ -1,9 +1,7 @@
/*******************************************************************************
* Authors: Brian Schott
* Copyright: Brian Schott
* Date: Sep 21 2013
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2014 Brian Schott
*
* License:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -16,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
*/
module astconverter;

View File

@ -1,9 +1,7 @@
/*******************************************************************************
* Authors: Brian Schott
* Copyright: Brian Schott
* Date: Jul 19 2013
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2014 Brian Schott
*
* License:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -16,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
*/
module autocomplete;
@ -40,35 +38,18 @@ import modulecache;
import astconverter;
import stupidlog;
/**
* Gets documentation for the symbol at the cursor
* Params:
* request = the autocompletion request
* Returns:
* the autocompletion response
*/
AutocompleteResponse getDoc(const AutocompleteRequest request)
{
Log.trace("Getting doc comments");
AutocompleteResponse response;
LexerConfig config;
config.fileName = "stdin";
StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) request.sourceCode, config, cache);
const(Token)[] tokenArray = void;
try {
tokenArray = tokens.array();
} catch (Exception e) {
Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
return response;
}
auto sortedTokens = assumeSorted(tokenArray);
string partial;
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
Log.trace("Token at cursor: ", beforeTokens[$ - 1].text);
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
auto expression = getExpression(beforeTokens);
ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
request.cursorPosition, CompletionType.ddoc);
ACSymbol*[] symbols = getSymbolsForCompletion(request, CompletionType.ddoc);
if (symbols.length == 0)
Log.error("Could not find symbol");
else foreach (symbol; symbols)
@ -86,76 +67,213 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
/**
* Finds the declaration of the symbol at the cursor position.
* Params:
* request = the autocompletion request
* Returns:
* the autocompletion response
*/
AutocompleteResponse findDeclaration(const AutocompleteRequest request)
{
Log.trace("Finding declaration");
AutocompleteResponse response;
LexerConfig config;
config.fileName = "stdin";
StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) request.sourceCode, config, cache);
const(Token)[] tokenArray = void;
try {
tokenArray = tokens.array();
} catch (Exception e) {
Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
return response;
}
auto sortedTokens = assumeSorted(tokenArray);
string partial;
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
Log.trace("Token at cursor: ", beforeTokens[$ - 1].text);
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
auto expression = getExpression(beforeTokens);
ACSymbol*[] symbols = getSymbolsByTokenChain(completionScope, expression,
request.cursorPosition, CompletionType.location);
ACSymbol*[] symbols = getSymbolsForCompletion(request, CompletionType.location);
if (symbols.length > 0)
{
response.symbolLocation = symbols[0].location;
response.symbolFilePath = symbols[0].symbolFile;
Log.info(beforeTokens[$ - 1].text, " declared in ",
Log.info(symbols[0].name, " declared in ",
response.symbolFilePath, " at ", response.symbolLocation);
}
else
{
Log.error("Could not find symbol");
}
return response;
}
bool shouldSwapWithType(CompletionType completionType, CompletionKind kind,
size_t current, size_t max) pure nothrow @safe
/**
* Handles autocompletion
* Params:
* request = the autocompletion request
* Returns:
* the autocompletion response
*/
AutocompleteResponse complete(const AutocompleteRequest request)
{
// Modules and packages never have types, so always return false
if (kind == CompletionKind.moduleName
|| kind == CompletionKind.packageName
|| kind == CompletionKind.className
|| kind == CompletionKind.structName
|| kind == CompletionKind.interfaceName
|| kind == CompletionKind.enumName
|| kind == CompletionKind.unionName)
Log.info("Got a completion request");
const(Token)[] tokenArray;
auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
request.cursorPosition, tokenArray);
string partial;
IdType tokenType;
if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!"(")
return parenCompletion(beforeTokens, tokenArray, request.cursorPosition);
AutocompleteResponse response;
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
{
return false;
partial = beforeTokens[$ - 1].text;
tokenType = beforeTokens[$ - 1].type;
beforeTokens = beforeTokens[0 .. $ - 1];
}
// Swap out every part of a chain with its type except the last part
if (current < max)
return true;
// Only swap out types for these kinds
immutable bool isInteresting =
kind == CompletionKind.variableName
|| kind == CompletionKind.memberVariableName
|| kind == CompletionKind.enumMember
|| kind == CompletionKind.functionName;
return completionType == CompletionType.identifiers && isInteresting;
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!".")
tokenType = beforeTokens[$ - 2].type;
else
return response;
switch (tokenType)
{
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"dstringLiteral":
foreach (symbol; (cast() arraySymbols)[])
{
response.completionKinds ~= symbol.kind;
response.completions ~= symbol.name;
}
response.completionType = CompletionType.identifiers;
break;
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":
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
"stdin");
auto expression = getExpression(beforeTokens);
response.setCompletions(completionScope, expression,
request.cursorPosition, CompletionType.identifiers, partial);
break;
case tok!"(":
case tok!"{":
case tok!"[":
case tok!";":
case tok!":":
// TODO: global scope
break;
default:
break;
}
return response;
}
/**
* Params:
* sourceCode = the source code of the file being edited
* cursorPosition = the cursor position in bytes
* Returns:
* a sorted range of tokens before the cursor position
*/
auto getTokensBeforeCursor(const(ubyte[]) sourceCode, size_t cursorPosition,
out const(Token)[] tokenArray)
{
LexerConfig config;
config.fileName = "stdin";
StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) sourceCode, config, cache);
tokenArray = tokens.array();
auto sortedTokens = assumeSorted(tokenArray);
return sortedTokens.lowerBound(cast(size_t) cursorPosition);
}
/**
* Params:
* request = the autocompletion request
* type = type the autocompletion type
* Returns:
* all symbols that should be considered for the autocomplete list based on
* the request's source code, cursor position, and completion type.
*/
ACSymbol*[] getSymbolsForCompletion(const AutocompleteRequest request,
const CompletionType type)
{
const(Token)[] tokenArray;
auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
request.cursorPosition, tokenArray);
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray, "stdin");
auto expression = getExpression(beforeTokens);
return getSymbolsByTokenChain(completionScope, expression,
request.cursorPosition, type);
}
/**
* Handles paren completion for function calls and some keywords
* Params:
* beforeTokens = the tokens before the cursor
* tokenArray = all tokens in the file
* cursorPosition = the cursor position in bytes
* Returns:
* the autocompletion response
*/
AutocompleteResponse parenCompletion(T)(T beforeTokens,
const(Token)[] tokenArray, size_t cursorPosition)
{
AutocompleteResponse response;
immutable(string)[] completions;
switch (beforeTokens[$ - 2].type)
{
case tok!"__traits":
completions = traits;
goto fillResponse;
case tok!"scope":
completions = scopes;
goto fillResponse;
case tok!"version":
completions = versions;
goto fillResponse;
case tok!"extern":
completions = linkages;
goto fillResponse;
case tok!"pragma":
completions = pragmas;
fillResponse:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < completions.length; i++)
{
response.completions ~= completions[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case tok!"identifier":
case tok!")":
case tok!"]":
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
"stdin");
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
response.setCompletions(completionScope, expression,
cursorPosition, CompletionType.calltips);
break;
default:
break;
}
return response;
}
/**
*
*/
ACSymbol*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
T tokens, size_t cursorPosition, CompletionType completionType)
{
@ -315,140 +433,9 @@ ACSymbol*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
return symbols;
}
AutocompleteResponse complete(const AutocompleteRequest request)
{
Log.info("Got a completion request");
AutocompleteResponse response;
LexerConfig config;
config.fileName = "stdin";
StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) request.sourceCode, config,
cache);
const(Token)[] tokenArray = void;
try {
tokenArray = tokens.array();
} catch (Exception e) {
Log.error("Could not provide autocomplete due to lexing exception: ", e.msg);
return response;
}
auto sortedTokens = assumeSorted(tokenArray);
string partial;
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
IdType tokenType;
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
{
partial = beforeTokens[$ - 1].text;
tokenType = beforeTokens[$ - 1].type;
beforeTokens = beforeTokens[0 .. $ - 1];
goto dotCompletion;
}
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!"(")
{
immutable(string)[] completions;
switch (beforeTokens[$ - 2].type)
{
case tok!"__traits":
completions = traits;
goto fillResponse;
case tok!"scope":
completions = scopes;
goto fillResponse;
case tok!"version":
completions = versions;
goto fillResponse;
case tok!"extern":
completions = linkages;
goto fillResponse;
case tok!"pragma":
completions = pragmas;
fillResponse:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < completions.length; i++)
{
response.completions ~= completions[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case tok!"identifier":
case tok!")":
case tok!"]":
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
"stdin");
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
response.setCompletions(completionScope, expression,
request.cursorPosition, CompletionType.calltips);
break;
default:
break;
}
}
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!".")
{
tokenType = beforeTokens[$ - 2].type;
dotCompletion:
switch (tokenType)
{
case tok!"stringLiteral":
case tok!"wstringLiteral":
case tok!"dstringLiteral":
foreach (symbol; (cast() arraySymbols)[])
{
response.completionKinds ~= symbol.kind;
response.completions ~= symbol.name;
}
response.completionType = CompletionType.identifiers;
break;
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":
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
"stdin");
auto expression = getExpression(beforeTokens);
response.setCompletions(completionScope, expression,
request.cursorPosition, CompletionType.identifiers, partial);
break;
case tok!"(":
case tok!"{":
case tok!"[":
case tok!";":
case tok!":":
// TODO: global scope
break;
default:
break;
}
}
return response;
}
/**
*
*/
void setCompletions(T)(ref AutocompleteResponse response,
const(Scope)* completionScope, T tokens, size_t cursorPosition,
CompletionType completionType, string partial = null)
@ -538,6 +525,9 @@ void setCompletions(T)(ref AutocompleteResponse response,
}
}
/**
*
*/
T getExpression(T)(T beforeTokens)
{
if (beforeTokens.length == 0)
@ -641,6 +631,12 @@ T getExpression(T)(T beforeTokens)
return beforeTokens[i .. $];
}
/**
* Populates the response with completion information for an import statement
* Params:
* 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)
{
response.completionType = CompletionType.identifiers;
@ -650,7 +646,7 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
string path = buildPath(moduleParts);
foreach (importDirectory; ModuleCache.getImportPaths())
{
string p = format("%s%s%s", importDirectory, dirSeparator, path);
string p = buildPath(importDirectory, path);
Log.trace("Checking for ", p);
if (!exists(p))
continue;
@ -672,6 +668,47 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
}
}
/**
* Params:
* completionType = the completion type being requested
* kind = the kind of the current item in the completion chain
* current = the index of the current item in the symbol chain
* max = the number of items in the symbol chain
* Returns:
* true if the symbol should be swapped with its type field
*/
bool shouldSwapWithType(CompletionType completionType, CompletionKind kind,
size_t current, size_t max) pure nothrow @safe
{
// Modules and packages never have types, so always return false
if (kind == CompletionKind.moduleName
|| kind == CompletionKind.packageName
|| kind == CompletionKind.className
|| kind == CompletionKind.structName
|| kind == CompletionKind.interfaceName
|| kind == CompletionKind.enumName
|| kind == CompletionKind.unionName)
{
return false;
}
// Swap out every part of a chain with its type except the last part
if (current < max)
return true;
// Only swap out types for these kinds
immutable bool isInteresting =
kind == CompletionKind.variableName
|| kind == CompletionKind.memberVariableName
|| kind == CompletionKind.enumMember
|| kind == CompletionKind.functionName;
return completionType == CompletionType.identifiers && isInteresting;
}
/**
* Params:
* comment = the comment to format
* Returns
* the comment with the comment characters removed
*/
string formatComment(string comment)
{
import std.string;

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -34,6 +34,13 @@ public:
@disable this();
/**
* Params:
* name = the name
* kind = the completion kind
* symbolFile = the file name for this symbol
* location = the location of this symbol
*/
this(string name, CompletionKind kind, string symbolFile,
size_t location = size_t.max)
{
@ -42,6 +49,9 @@ public:
acSymbol.symbolFile = symbolFile;
}
/**
* Adds a child to the children field and updates the acSymbol's parts field
*/
void addChild(SemanticSymbol* child)
{
children ~= child;
@ -66,7 +76,9 @@ public:
/// Protection level for this symobol
IdType protection;
/// Parent symbol
SemanticSymbol* parent;
/// Child symbols
SemanticSymbol*[] children;
}

View File

@ -1,6 +1,6 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2013 Brian Schott
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -151,19 +151,42 @@ int main(string[] args)
Log.info("Shutting down.");
break serverLoop;
case RequestKind.autocomplete:
AutocompleteResponse response = complete(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
try
{
AutocompleteResponse response = complete(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
Log.error("Could not handle autocomplete request due to an exception:",
e.msg);
}
break;
case RequestKind.doc:
AutocompleteResponse response = getDoc(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
try
{
AutocompleteResponse response = getDoc(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
Log.error("Could not get DDoc information", e.msg);
}
break;
case RequestKind.symbolLocation:
AutocompleteResponse response = findDeclaration(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
try
{
AutocompleteResponse response = findDeclaration(request);
ubyte[] responseBytes = msgpack.pack(response);
s.send(responseBytes);
}
catch (Exception e)
{
Log.error("Could not get symbol location", e.msg);
}
break;
}
Log.info("Request processed in ", requestWatch.peek().to!("msecs", float), " milliseconds");
@ -171,6 +194,9 @@ int main(string[] args)
return 0;
}
/**
* Locates the configuration file
*/
string getConfigurationLocation()
{
version (useXDG)
@ -208,6 +234,9 @@ void warnAboutOldConfigLocation()
}
}
/**
* Loads import directories from the configuration file
*/
string[] loadConfiguredImportDirs()
{
warnAboutOldConfigLocation();

View File

@ -1,9 +1,7 @@
/*******************************************************************************
* Authors: Brian Schott
* Copyright: Brian Schott
* Date: Oct 5 2013
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2014 Brian Schott
*
* License:
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
@ -16,7 +14,7 @@
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
*/
module stupidlog;