This commit is contained in:
Hackerpilot 2014-07-11 18:51:48 +00:00
commit fb46f25560
6 changed files with 105 additions and 27 deletions

View File

@ -3,12 +3,14 @@ The D Completion Daemon is an auto-complete program for the D programming langua
![Teaser](teaser.png "This is what the future looks like - Jayce, League of Legends")
(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.
The server (dcd-server) is responsible for caching imported files, calculating autocomplete information, and sending it
back to the client.
#Status
*This program is still in an alpha state.*
This program is reasonably stable.
* Working:
* 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
* *import* statement completions
* Display of documentation comments in function call tips
* *alias this*
* Not working:
* Automatic starting of the server by the client
* UFCS
* Autocompletion of declarations with template arguments
* *auto* declarations
* *alias this*
* 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
#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 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.

View File

@ -107,7 +107,11 @@ public:
ACSymbol*[] getPartsByName(string 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;
/**
* Symbols included due to an alias this.
*/
TTree!(ACSymbol*, true, "a < b", false) aliasThisParts;
/**
* Calltip to display if this is a function
*/
@ -233,14 +242,9 @@ struct Scope
{
import std.range;
ACSymbol s = ACSymbol(name);
auto r = array(symbols.equalRange(&s));
foreach (i; r)
{
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;
auto er = symbols.equalRange(&s);
if (!er.empty)
return cast(typeof(return)) array(er);
if (parent is null)
return [];
return parent.getSymbolsByName(name);
@ -262,6 +266,13 @@ struct Scope
return s.getSymbolsByName(name);
}
ACSymbol*[] getSymbolsAtGlobalScope(string name)
{
if (parent !is null)
return parent.getSymbolsAtGlobalScope(name);
return getSymbolsByName(name);
}
/// Imports contained in this scope
UnrolledList!(ImportInformation*) importInformation;
@ -313,7 +324,7 @@ TTree!(ACSymbol*, true, "a < b", false) arraySymbols;
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;
@ -506,7 +517,7 @@ static this()
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(alignof_);
aggregateSymbols.insert(sizeof_);

View File

@ -185,7 +185,6 @@ AutocompleteResponse complete(const AutocompleteRequest request)
case tok!"[":
case tok!";":
case tok!":":
// TODO: global scope
break;
default:
break;
@ -299,8 +298,16 @@ ACSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
Log.trace("Getting symbols from token chain",
tokens.map!stringToken);
// Find the symbol corresponding to the beginning of the chain
ACSymbol*[] symbols = completionScope.getSymbolsByNameAndCursor(
stringToken(tokens[0]), cursorPosition);
ACSymbol*[] symbols;
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)
{
Log.error("Could not find declaration of ", stringToken(tokens[0]),
@ -493,6 +500,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (completionType == CompletionType.identifiers)
{
import containers.ttree;
if (symbols[0].qualifier == SymbolQualifier.func
|| symbols[0].kind == CompletionKind.functionName)
{
@ -501,7 +509,10 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (symbols.length == 0)
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] != '*'
&& (partial is null ? true : a.name.toUpper().startsWith(partial.toUpper()))
&& !response.completions.canFind(a.name)))
@ -542,7 +553,15 @@ void setCompletions(T)(ref AutocompleteResponse response,
{
auto constructor = symbols[0].getPartsByName("*constructor*");
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
{
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;
}
/**
*
*/

View File

@ -37,6 +37,7 @@ dmd\
containers/src/containers/unrolledlist.d\
containers/src/containers/hashset.d\
containers/src/containers/internal/hash.d\
containers/src/containers/internal/node.d\
containers/src/containers/slist.d\
msgpack-d/src/msgpack.d\
-Icontainers/src\

@ -1 +1 @@
Subproject commit 2a72525f649850f452f21e7f362f70440f487a61
Subproject commit 74b394404947f8c1ea9c6e769fdb413db049d27d

View File

@ -69,11 +69,6 @@ private:
case className:
case interfaceName:
resolveInheritance(currentSymbol);
goto case structName;
case structName:
case unionName:
resolveAliasThis(currentSymbol);
resolveMixinTemplates(currentSymbol);
break;
case variableName:
case memberVariableName:
@ -85,6 +80,8 @@ private:
t = t.type;
currentSymbol.acSymbol.type = t;
break;
case structName:
case unionName:
case enumName:
case keyword:
case enumMember:
@ -97,10 +94,24 @@ private:
case mixinTemplateName:
break;
}
foreach (child; currentSymbol.children)
{
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)
@ -129,10 +140,16 @@ private:
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:
}