Merge branch 'master' of https://github.com/Hackerpilot/DCD
This commit is contained in:
commit
fb46f25560
|
|
@ -3,12 +3,14 @@ The D Completion Daemon is an auto-complete program for the D programming langua
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
(The above is a screenshot of [Textadept](http://foicica.com/textadept/))
|
||||||
|
|
||||||
DCD consists of a client and a server. The client (dcd-client) is used by a text editor script or from the command line.
|
DCD consists of a client and a server. The client (dcd-client) is used by a text editor script or from the command line.
|
||||||
The server (dcd-server) is responsible for caching imported files, calculating autocomplete information, and sending it
|
The server (dcd-server) is responsible for caching imported files, calculating autocomplete information, and sending it
|
||||||
back to the client.
|
back to the client.
|
||||||
|
|
||||||
#Status
|
#Status
|
||||||
*This program is still in an alpha state.*
|
This program is reasonably stable.
|
||||||
|
|
||||||
* Working:
|
* Working:
|
||||||
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
||||||
|
|
@ -21,17 +23,17 @@ back to the client.
|
||||||
* Finding the declaration location of a symbol at the cursor
|
* Finding the declaration location of a symbol at the cursor
|
||||||
* *import* statement completions
|
* *import* statement completions
|
||||||
* Display of documentation comments in function call tips
|
* Display of documentation comments in function call tips
|
||||||
|
* *alias this*
|
||||||
* Not working:
|
* Not working:
|
||||||
* Automatic starting of the server by the client
|
* Automatic starting of the server by the client
|
||||||
* UFCS
|
* UFCS
|
||||||
* Autocompletion of declarations with template arguments
|
* Autocompletion of declarations with template arguments
|
||||||
* *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
|
||||||
* That one feature that you *REALLY* needed
|
* That one feature that you *REALLY* needed
|
||||||
|
|
||||||
#Setup
|
#Setup
|
||||||
1. Install a recent D compiler. DCD is only tested with DMD 2.064.2
|
1. Install a recent D compiler. DCD is tested with 2.065 and the 2.066 betas.
|
||||||
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack and Datapacked libraries and the parser from DScanner.
|
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack and Datapacked libraries and the parser from DScanner.
|
||||||
1. run the ```build.sh``` script to build the client and server. (Or build.bat on Windows)
|
1. run the ```build.sh``` script to build the client and server. (Or build.bat on Windows)
|
||||||
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.
|
||||||
|
|
|
||||||
33
actypes.d
33
actypes.d
|
|
@ -107,7 +107,11 @@ public:
|
||||||
ACSymbol*[] getPartsByName(string name)
|
ACSymbol*[] getPartsByName(string name)
|
||||||
{
|
{
|
||||||
ACSymbol s = ACSymbol(name);
|
ACSymbol s = ACSymbol(name);
|
||||||
return array(parts.equalRange(&s));
|
auto er = parts.equalRange(&s);
|
||||||
|
if (er.empty)
|
||||||
|
return array(aliasThisParts.equalRange(&s));
|
||||||
|
else
|
||||||
|
return array(er);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -121,6 +125,11 @@ public:
|
||||||
*/
|
*/
|
||||||
TTree!(ACSymbol*, true, "a < b", false) parts;
|
TTree!(ACSymbol*, true, "a < b", false) parts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Symbols included due to an alias this.
|
||||||
|
*/
|
||||||
|
TTree!(ACSymbol*, true, "a < b", false) aliasThisParts;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calltip to display if this is a function
|
* Calltip to display if this is a function
|
||||||
*/
|
*/
|
||||||
|
|
@ -233,14 +242,9 @@ struct Scope
|
||||||
{
|
{
|
||||||
import std.range;
|
import std.range;
|
||||||
ACSymbol s = ACSymbol(name);
|
ACSymbol s = ACSymbol(name);
|
||||||
auto r = array(symbols.equalRange(&s));
|
auto er = symbols.equalRange(&s);
|
||||||
foreach (i; r)
|
if (!er.empty)
|
||||||
{
|
return cast(typeof(return)) array(er);
|
||||||
import std.string;
|
|
||||||
assert (i.name == name, format("%s %s %d", i.name, name, r.length));
|
|
||||||
}
|
|
||||||
if (r.length > 0)
|
|
||||||
return cast(typeof(return)) r;
|
|
||||||
if (parent is null)
|
if (parent is null)
|
||||||
return [];
|
return [];
|
||||||
return parent.getSymbolsByName(name);
|
return parent.getSymbolsByName(name);
|
||||||
|
|
@ -262,6 +266,13 @@ struct Scope
|
||||||
return s.getSymbolsByName(name);
|
return s.getSymbolsByName(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ACSymbol*[] getSymbolsAtGlobalScope(string name)
|
||||||
|
{
|
||||||
|
if (parent !is null)
|
||||||
|
return parent.getSymbolsAtGlobalScope(name);
|
||||||
|
return getSymbolsByName(name);
|
||||||
|
}
|
||||||
|
|
||||||
/// Imports contained in this scope
|
/// Imports contained in this scope
|
||||||
UnrolledList!(ImportInformation*) importInformation;
|
UnrolledList!(ImportInformation*) importInformation;
|
||||||
|
|
||||||
|
|
@ -313,7 +324,7 @@ TTree!(ACSymbol*, true, "a < b", false) arraySymbols;
|
||||||
TTree!(ACSymbol*, true, "a < b", false) assocArraySymbols;
|
TTree!(ACSymbol*, true, "a < b", false) assocArraySymbols;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enum, union, class, and interface properties
|
* Struct, enum, union, class, and interface properties
|
||||||
*/
|
*/
|
||||||
TTree!(ACSymbol*, true, "a < b", false) aggregateSymbols;
|
TTree!(ACSymbol*, true, "a < b", false) aggregateSymbols;
|
||||||
|
|
||||||
|
|
@ -506,7 +517,7 @@ static this()
|
||||||
s.parts.insert(stringof_);
|
s.parts.insert(stringof_);
|
||||||
}
|
}
|
||||||
|
|
||||||
aggregateSymbols.insert(allocate!ACSymbol(Mallocator.it, "tupleof", CompletionKind.variableName));
|
aggregateSymbols.insert(allocate!ACSymbol(Mallocator.it, "tupleof", CompletionKind.keyword));
|
||||||
aggregateSymbols.insert(mangleof_);
|
aggregateSymbols.insert(mangleof_);
|
||||||
aggregateSymbols.insert(alignof_);
|
aggregateSymbols.insert(alignof_);
|
||||||
aggregateSymbols.insert(sizeof_);
|
aggregateSymbols.insert(sizeof_);
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,6 @@ AutocompleteResponse complete(const AutocompleteRequest request)
|
||||||
case tok!"[":
|
case tok!"[":
|
||||||
case tok!";":
|
case tok!";":
|
||||||
case tok!":":
|
case tok!":":
|
||||||
// TODO: global scope
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
@ -299,8 +298,16 @@ ACSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
|
||||||
Log.trace("Getting symbols from token chain",
|
Log.trace("Getting symbols from token chain",
|
||||||
tokens.map!stringToken);
|
tokens.map!stringToken);
|
||||||
// Find the symbol corresponding to the beginning of the chain
|
// Find the symbol corresponding to the beginning of the chain
|
||||||
ACSymbol*[] symbols = completionScope.getSymbolsByNameAndCursor(
|
ACSymbol*[] symbols;
|
||||||
stringToken(tokens[0]), cursorPosition);
|
if (tokens[0] == tok!"." && tokens.length > 1)
|
||||||
|
{
|
||||||
|
tokens = tokens[1 .. $];
|
||||||
|
Log.info("Looking for ", stringToken(tokens[0]), " at global scope");
|
||||||
|
symbols = completionScope.getSymbolsAtGlobalScope(stringToken(tokens[0]));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
symbols = completionScope.getSymbolsByNameAndCursor(stringToken(tokens[0]), cursorPosition);
|
||||||
|
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
{
|
{
|
||||||
Log.error("Could not find declaration of ", stringToken(tokens[0]),
|
Log.error("Could not find declaration of ", stringToken(tokens[0]),
|
||||||
|
|
@ -493,6 +500,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
|
|
||||||
if (completionType == CompletionType.identifiers)
|
if (completionType == CompletionType.identifiers)
|
||||||
{
|
{
|
||||||
|
import containers.ttree;
|
||||||
if (symbols[0].qualifier == SymbolQualifier.func
|
if (symbols[0].qualifier == SymbolQualifier.func
|
||||||
|| symbols[0].kind == CompletionKind.functionName)
|
|| symbols[0].kind == CompletionKind.functionName)
|
||||||
{
|
{
|
||||||
|
|
@ -501,7 +509,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
foreach (s; symbols[0].parts[].filter!(a => a.name !is null
|
TTree!(ACSymbol*, true, "a < b", false) parts;
|
||||||
|
parts.insert(symbols[0].parts[]);
|
||||||
|
parts.insert(symbols[0].aliasThisParts[]);
|
||||||
|
foreach (s; parts[].filter!(a => a.name !is null
|
||||||
&& a.name.length > 0 && a.name[0] != '*'
|
&& a.name.length > 0 && a.name[0] != '*'
|
||||||
&& (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper()))
|
&& (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper()))
|
||||||
&& !response.completions.canFind(a.name)))
|
&& !response.completions.canFind(a.name)))
|
||||||
|
|
@ -542,7 +553,15 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
{
|
{
|
||||||
auto constructor = symbols[0].getPartsByName("*constructor*");
|
auto constructor = symbols[0].getPartsByName("*constructor*");
|
||||||
if (constructor.length == 0)
|
if (constructor.length == 0)
|
||||||
return;
|
{
|
||||||
|
// Build a call tip out of the struct fields
|
||||||
|
if (symbols[0].kind == CompletionKind.structName)
|
||||||
|
{
|
||||||
|
response.completionType = CompletionType.calltips;
|
||||||
|
response.completions = [generateStructConstructorCalltip(symbols[0])];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
symbols = constructor;
|
symbols = constructor;
|
||||||
|
|
@ -560,6 +579,34 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string generateStructConstructorCalltip(const ACSymbol* symbol)
|
||||||
|
in
|
||||||
|
{
|
||||||
|
assert (symbol.kind == CompletionKind.structName);
|
||||||
|
}
|
||||||
|
body
|
||||||
|
{
|
||||||
|
string generatedStructConstructorCalltip = "this(";
|
||||||
|
size_t i = 0;
|
||||||
|
immutable c = count(symbol.parts[].filter!(a => a.kind == CompletionKind.variableName));
|
||||||
|
foreach (part; array(symbol.parts[]).sort!((a, b) => a.location < b.location))
|
||||||
|
{
|
||||||
|
if (part.kind != CompletionKind.variableName)
|
||||||
|
continue;
|
||||||
|
i++;
|
||||||
|
if (part.type !is null)
|
||||||
|
{
|
||||||
|
generatedStructConstructorCalltip ~= part.type.name;
|
||||||
|
generatedStructConstructorCalltip ~= " ";
|
||||||
|
}
|
||||||
|
generatedStructConstructorCalltip ~= part.name;
|
||||||
|
if (i < c)
|
||||||
|
generatedStructConstructorCalltip ~= ", ";
|
||||||
|
}
|
||||||
|
generatedStructConstructorCalltip ~= ")";
|
||||||
|
return generatedStructConstructorCalltip;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
1
build.sh
1
build.sh
|
|
@ -37,6 +37,7 @@ dmd\
|
||||||
containers/src/containers/unrolledlist.d\
|
containers/src/containers/unrolledlist.d\
|
||||||
containers/src/containers/hashset.d\
|
containers/src/containers/hashset.d\
|
||||||
containers/src/containers/internal/hash.d\
|
containers/src/containers/internal/hash.d\
|
||||||
|
containers/src/containers/internal/node.d\
|
||||||
containers/src/containers/slist.d\
|
containers/src/containers/slist.d\
|
||||||
msgpack-d/src/msgpack.d\
|
msgpack-d/src/msgpack.d\
|
||||||
-Icontainers/src\
|
-Icontainers/src\
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2a72525f649850f452f21e7f362f70440f487a61
|
Subproject commit 74b394404947f8c1ea9c6e769fdb413db049d27d
|
||||||
|
|
@ -69,11 +69,6 @@ private:
|
||||||
case className:
|
case className:
|
||||||
case interfaceName:
|
case interfaceName:
|
||||||
resolveInheritance(currentSymbol);
|
resolveInheritance(currentSymbol);
|
||||||
goto case structName;
|
|
||||||
case structName:
|
|
||||||
case unionName:
|
|
||||||
resolveAliasThis(currentSymbol);
|
|
||||||
resolveMixinTemplates(currentSymbol);
|
|
||||||
break;
|
break;
|
||||||
case variableName:
|
case variableName:
|
||||||
case memberVariableName:
|
case memberVariableName:
|
||||||
|
|
@ -85,6 +80,8 @@ private:
|
||||||
t = t.type;
|
t = t.type;
|
||||||
currentSymbol.acSymbol.type = t;
|
currentSymbol.acSymbol.type = t;
|
||||||
break;
|
break;
|
||||||
|
case structName:
|
||||||
|
case unionName:
|
||||||
case enumName:
|
case enumName:
|
||||||
case keyword:
|
case keyword:
|
||||||
case enumMember:
|
case enumMember:
|
||||||
|
|
@ -97,10 +94,24 @@ private:
|
||||||
case mixinTemplateName:
|
case mixinTemplateName:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (child; currentSymbol.children)
|
foreach (child; currentSymbol.children)
|
||||||
{
|
{
|
||||||
thirdPass(child);
|
thirdPass(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
with (CompletionKind) switch (currentSymbol.acSymbol.kind)
|
||||||
|
{
|
||||||
|
case className:
|
||||||
|
case interfaceName:
|
||||||
|
case structName:
|
||||||
|
case unionName:
|
||||||
|
resolveAliasThis(currentSymbol);
|
||||||
|
resolveMixinTemplates(currentSymbol);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolveInheritance(SemanticSymbol* currentSymbol)
|
void resolveInheritance(SemanticSymbol* currentSymbol)
|
||||||
|
|
@ -129,10 +140,16 @@ private:
|
||||||
|
|
||||||
void resolveAliasThis(SemanticSymbol* currentSymbol)
|
void resolveAliasThis(SemanticSymbol* currentSymbol)
|
||||||
{
|
{
|
||||||
// TODO:
|
foreach (aliasThis; currentSymbol.aliasThis)
|
||||||
|
{
|
||||||
|
auto parts = currentSymbol.acSymbol.getPartsByName(aliasThis);
|
||||||
|
if (parts.length == 0 || parts[0].type is null)
|
||||||
|
continue;
|
||||||
|
currentSymbol.acSymbol.aliasThisParts.insert(parts[0].type.parts[]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void resolveMixinTemplates(SemanticSymbol* currentSymbol)
|
void resolveMixinTemplates(SemanticSymbol*)
|
||||||
{
|
{
|
||||||
// TODO:
|
// TODO:
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue