Tons of hacking, but not necessarily tons of progress
This commit is contained in:
parent
267dbab208
commit
814dcbd26a
19
README.md
19
README.md
|
@ -1,8 +1,15 @@
|
|||
DCD
|
||||
===
|
||||
#Overview
|
||||
The D Completion Daemon is an auto-complete program for the D programming language.
|
||||
|
||||
The D Completion Daemon is an auto-complete program for the D programming language
|
||||
#Status
|
||||
* Working:
|
||||
* Autocomplete class, struct, interface, and enum members if the class, struct, or
|
||||
enum was declared in the current file.
|
||||
* Autocompletion of properties of built-in types such as int, float, double, etc.
|
||||
* Not working:
|
||||
* Everything else
|
||||
|
||||
Or at least it will be once I write it.
|
||||
|
||||
Be sure to run ```git submodule update --init``` after cloning this repository.
|
||||
#Setup
|
||||
Don't. This code is not ready for you to use yet. If you're going to ignore this
|
||||
warning, be sure to run ```git submodule update --init``` after cloning this
|
||||
repository to grab the MessagePack library.
|
||||
|
|
112
actypes.d
112
actypes.d
|
@ -23,26 +23,99 @@ import std.algorithm;
|
|||
import std.stdio;
|
||||
import messages;
|
||||
|
||||
/**
|
||||
* Autocompletion symbol
|
||||
*/
|
||||
class ACSymbol
|
||||
{
|
||||
public:
|
||||
|
||||
this()
|
||||
{
|
||||
}
|
||||
|
||||
this(string name)
|
||||
{
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
this(string name, CompletionKind kind)
|
||||
{
|
||||
this.name = name;
|
||||
this.kind = kind;
|
||||
}
|
||||
|
||||
this(string name, CompletionKind kind, ACSymbol resolvedType)
|
||||
{
|
||||
this.name = name;
|
||||
this.kind = kind;
|
||||
this.resolvedType = resolvedType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Symbols that compose this symbol, such as enum members, class variables,
|
||||
* methods, etc.
|
||||
*/
|
||||
ACSymbol[] parts;
|
||||
|
||||
/**
|
||||
* Symbol's name
|
||||
*/
|
||||
string name;
|
||||
|
||||
size_t location;
|
||||
|
||||
/**
|
||||
* The kind of symbol
|
||||
*/
|
||||
CompletionKind kind;
|
||||
Type[string] templateParameters;
|
||||
|
||||
/**
|
||||
* The return type if this is a function, or the element type if this is an
|
||||
* array or associative array, or the variable type if this is a variable.
|
||||
* This field is null if this symbol is a class
|
||||
*/
|
||||
Type type;
|
||||
|
||||
ACSymbol resolvedType;
|
||||
|
||||
/**
|
||||
* Finds symbol parts by name
|
||||
*/
|
||||
ACSymbol getPartByName(string name)
|
||||
{
|
||||
foreach (part; parts)
|
||||
{
|
||||
if (part.name == name)
|
||||
return part;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Scope such as a block statement, struct body, etc.
|
||||
*/
|
||||
class Scope
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* start = the index of the opening brace
|
||||
* end = the index of the closing brace
|
||||
*/
|
||||
this(size_t start, size_t end)
|
||||
{
|
||||
this.start = start;
|
||||
this.end = end;
|
||||
}
|
||||
|
||||
const(ACSymbol) findSymbolInCurrentScope(size_t cursorPosition, string name) const
|
||||
/**
|
||||
* Finds the scope containing the cursor position, then searches for a
|
||||
* symbol with the given name.
|
||||
*/
|
||||
ACSymbol findSymbolInCurrentScope(size_t cursorPosition, string name)
|
||||
{
|
||||
auto s = findCurrentScope(cursorPosition);
|
||||
if (s is null)
|
||||
|
@ -55,11 +128,11 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* @return the innermost Scope that contains the given cursor position.
|
||||
* Returns: the innermost Scope that contains the given cursor position.
|
||||
*/
|
||||
const(Scope) findCurrentScope(size_t cursorPosition) const
|
||||
Scope findCurrentScope(size_t cursorPosition)
|
||||
{
|
||||
if (cursorPosition < start || cursorPosition > end)
|
||||
if (start != size_t.max && (cursorPosition < start || cursorPosition > end))
|
||||
return null;
|
||||
foreach (sc; children)
|
||||
{
|
||||
|
@ -72,7 +145,11 @@ public:
|
|||
return this;
|
||||
}
|
||||
|
||||
const(ACSymbol) findSymbolInScope(string name) const
|
||||
/**
|
||||
* Finds a symbol with the given name in this scope or one of its parent
|
||||
* scopes.
|
||||
*/
|
||||
ACSymbol findSymbolInScope(string name)
|
||||
{
|
||||
foreach (symbol; symbols)
|
||||
{
|
||||
|
@ -84,9 +161,28 @@ public:
|
|||
return null;
|
||||
}
|
||||
|
||||
size_t start;
|
||||
size_t end;
|
||||
/**
|
||||
* Index of the opening brace
|
||||
*/
|
||||
size_t start = size_t.max;
|
||||
|
||||
/**
|
||||
* Index of the closing brace
|
||||
*/
|
||||
size_t end = size_t.max;
|
||||
|
||||
/**
|
||||
* Symbols contained in this scope
|
||||
*/
|
||||
ACSymbol[] symbols;
|
||||
|
||||
/**
|
||||
* The parent scope
|
||||
*/
|
||||
Scope parent;
|
||||
|
||||
/**
|
||||
* Child scopes
|
||||
*/
|
||||
Scope[] children;
|
||||
}
|
||||
|
|
162
acvisitor.d
162
acvisitor.d
|
@ -1,20 +1,20 @@
|
|||
/**
|
||||
* This file is part of DCD, a development tool for the D programming language.
|
||||
* Copyright (C) 2013 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
* This file is part of DCD, a development tool for the D programming language.
|
||||
* Copyright (C) 2013 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
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* 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 acvisitor;
|
||||
|
||||
|
@ -31,21 +31,54 @@ class AutoCompleteVisitor : ASTVisitor
|
|||
{
|
||||
alias ASTVisitor.visit visit;
|
||||
|
||||
override void visit(EnumDeclaration enumDec)
|
||||
override void visit(StructDeclaration dec)
|
||||
{
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.name = enumDec.name.value;
|
||||
symbol.name = dec.name.value;
|
||||
symbol.kind = CompletionKind.structName;
|
||||
mixin (visitAndAdd);
|
||||
}
|
||||
|
||||
override void visit(ClassDeclaration dec)
|
||||
{
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.name = dec.name.value;
|
||||
symbol.kind = CompletionKind.className;
|
||||
mixin (visitAndAdd);
|
||||
}
|
||||
|
||||
override void visit(InterfaceDeclaration dec)
|
||||
{
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.name = dec.name.value;
|
||||
symbol.kind = CompletionKind.interfaceName;
|
||||
mixin (visitAndAdd);
|
||||
}
|
||||
|
||||
override void visit(StructBody structBody)
|
||||
{
|
||||
auto s = scope_;
|
||||
scope_ = new Scope(structBody.startLocation, structBody.endLocation);
|
||||
scope_.parent = s;
|
||||
structBody.accept(this);
|
||||
scope_ = s;
|
||||
}
|
||||
|
||||
override void visit(EnumDeclaration dec)
|
||||
{
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.name = dec.name.value;
|
||||
symbol.kind = CompletionKind.enumName;
|
||||
auto p = parentSymbol;
|
||||
parentSymbol = symbol;
|
||||
enumDec.accept(this);
|
||||
parentSymbol = p;
|
||||
writeln("Added ", symbol.name);
|
||||
if (parentSymbol is null)
|
||||
symbols ~= symbol;
|
||||
else
|
||||
parentSymbol.parts ~= symbol;
|
||||
scope_.symbols ~= symbol;
|
||||
mixin (visitAndAdd);
|
||||
}
|
||||
|
||||
override void visit(FunctionDeclaration dec)
|
||||
{
|
||||
writeln("Found function declaration ", dec.name.value);
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.name = dec.name.value;
|
||||
symbol.kind = CompletionKind.functionName;
|
||||
mixin (visitAndAdd);
|
||||
}
|
||||
|
||||
override void visit(EnumMember member)
|
||||
|
@ -53,28 +86,47 @@ class AutoCompleteVisitor : ASTVisitor
|
|||
auto s = new ACSymbol;
|
||||
s.kind = CompletionKind.enumMember;
|
||||
s.name = member.name.value;
|
||||
writeln("Added enum member ", s.name);
|
||||
// writeln("Added enum member ", s.name);
|
||||
if (parentSymbol !is null)
|
||||
parentSymbol.parts ~= s;
|
||||
}
|
||||
|
||||
override void visit(VariableDeclaration dec)
|
||||
{
|
||||
foreach (d; dec.declarators)
|
||||
{
|
||||
writeln("Found variable declaration ", d.name.value);
|
||||
auto symbol = new ACSymbol;
|
||||
symbol.type = dec.type;
|
||||
symbol.name = d.name.value;
|
||||
symbol.kind = CompletionKind.variableName;
|
||||
if (parentSymbol is null)
|
||||
symbols ~= symbol;
|
||||
else
|
||||
parentSymbol.parts ~= symbol;
|
||||
scope_.symbols ~= symbol;
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(ImportDeclaration dec)
|
||||
{
|
||||
foreach (singleImport; dec.singleImports)
|
||||
{
|
||||
imports ~= flattenIdentifierChain(singleImport.identifierChain);
|
||||
imports ~= convertChainToImportPath(singleImport.identifierChain);
|
||||
}
|
||||
if (dec.importBindings !is null)
|
||||
{
|
||||
imports ~= flattenIdentifierChain(dec.importBindings.singleImport.identifierChain);
|
||||
imports ~= convertChainToImportPath(dec.importBindings.singleImport.identifierChain);
|
||||
}
|
||||
}
|
||||
|
||||
override void visit(BlockStatement blockStatement)
|
||||
{
|
||||
writeln("Processing block statement");
|
||||
auto s = scope_;
|
||||
scope_ = new Scope(blockStatement.startLocation,
|
||||
blockStatement.endLocation);
|
||||
scope_.parent = s;
|
||||
blockStatement.accept(this);
|
||||
s.children ~= scope_;
|
||||
scope_ = s;
|
||||
|
@ -86,7 +138,7 @@ class AutoCompleteVisitor : ASTVisitor
|
|||
mod.accept(this);
|
||||
}
|
||||
|
||||
private static string flattenIdentifierChain(IdentifierChain chain)
|
||||
private static string convertChainToImportPath(IdentifierChain chain)
|
||||
{
|
||||
string rVal;
|
||||
bool first = true;
|
||||
|
@ -104,44 +156,28 @@ class AutoCompleteVisitor : ASTVisitor
|
|||
ACSymbol[] symbols;
|
||||
ACSymbol parentSymbol;
|
||||
Scope scope_;
|
||||
string[] imports;
|
||||
string[] imports = ["object"];
|
||||
|
||||
private:
|
||||
static enum string visitAndAdd = q{
|
||||
auto p = parentSymbol;
|
||||
parentSymbol = symbol;
|
||||
dec.accept(this);
|
||||
parentSymbol = p;
|
||||
if (parentSymbol is null)
|
||||
symbols ~= symbol;
|
||||
else
|
||||
parentSymbol.parts ~= symbol;
|
||||
scope_.symbols ~= symbol;
|
||||
};
|
||||
}
|
||||
|
||||
void doesNothing(string, int, int, string) {}
|
||||
|
||||
AutoCompleteVisitor processModule(const(Token)[] tokens)
|
||||
{
|
||||
Module mod = parseModule(tokens, "", &doesNothing);
|
||||
Module mod = parseModule(tokens, "", null/*&doesNothing*/);
|
||||
auto visitor = new AutoCompleteVisitor;
|
||||
visitor.visit(mod);
|
||||
return visitor;
|
||||
}
|
||||
|
||||
string[] getImportedFiles(string[] imports, string[] importPaths)
|
||||
{
|
||||
string[] importedFiles;
|
||||
foreach (imp; imports)
|
||||
{
|
||||
bool found = false;
|
||||
foreach (path; importPaths)
|
||||
{
|
||||
string filePath = path ~ "/" ~ imp;
|
||||
if (filePath.exists())
|
||||
{
|
||||
importedFiles ~= filePath;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
filePath ~= "i"; // check for x.di if x.d isn't found
|
||||
if (filePath.exists())
|
||||
{
|
||||
importedFiles ~= filePath;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
writeln("Could not locate ", imp);
|
||||
}
|
||||
return importedFiles;
|
||||
}
|
||||
|
|
272
autocomplete.d
272
autocomplete.d
|
@ -90,6 +90,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
|||
{
|
||||
switch (beforeTokens[$ - 2].type)
|
||||
{
|
||||
case TokenType.stringLiteral:
|
||||
case TokenType.wstringLiteral:
|
||||
case TokenType.dstringLiteral:
|
||||
// TODO
|
||||
break;
|
||||
case TokenType.int_:
|
||||
case TokenType.uint_:
|
||||
case TokenType.long_:
|
||||
|
@ -104,13 +109,6 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
|||
case TokenType.ushort_:
|
||||
case TokenType.cent_:
|
||||
case TokenType.ucent_:
|
||||
response.completionType = CompletionType.identifiers;
|
||||
for (size_t i = 0; i < integerProperties.length; i++)
|
||||
{
|
||||
response.completions ~= integerProperties[i];
|
||||
response.completionKinds ~= CompletionKind.keyword;
|
||||
}
|
||||
break;
|
||||
case TokenType.float_:
|
||||
case TokenType.ifloat_:
|
||||
case TokenType.cfloat_:
|
||||
|
@ -120,27 +118,11 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
|||
case TokenType.real_:
|
||||
case TokenType.ireal_:
|
||||
case TokenType.creal_:
|
||||
response.completionType = CompletionType.identifiers;
|
||||
for (size_t i = 0; i < floatProperties.length; i++)
|
||||
{
|
||||
response.completions ~= floatProperties[i];
|
||||
response.completionKinds ~= CompletionKind.keyword;
|
||||
}
|
||||
break;
|
||||
case TokenType.stringLiteral:
|
||||
case TokenType.wstringLiteral:
|
||||
case TokenType.dstringLiteral:
|
||||
response.completionType = CompletionType.identifiers;
|
||||
for (size_t i = 0; i < arrayProperties.length; i++)
|
||||
{
|
||||
response.completions ~= arrayProperties[i];
|
||||
response.completionKinds ~= CompletionKind.keyword;
|
||||
}
|
||||
break;
|
||||
case TokenType.identifier:
|
||||
case TokenType.rParen:
|
||||
case TokenType.rBracket:
|
||||
auto visitor = processModule(tokenArray);
|
||||
visitor.scope_.symbols ~= builtinSymbols;
|
||||
auto expression = getExpression(beforeTokens[0..$]);
|
||||
response.setCompletions(visitor, expression, request.cursorPosition);
|
||||
break;
|
||||
|
@ -160,23 +142,116 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
|||
}
|
||||
|
||||
void setCompletions(T)(ref AutocompleteResponse response,
|
||||
ref const AutoCompleteVisitor visitor, T tokens, size_t cursorPosition)
|
||||
AutoCompleteVisitor visitor, T tokens, size_t cursorPosition)
|
||||
{
|
||||
// TODO: Completely hacked together.
|
||||
if (tokens[0] != TokenType.identifier) return;
|
||||
writeln("Getting completions for ", tokens[0].value);
|
||||
auto symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
|
||||
writeln("Getting completions for ", map!"a.value"(tokens));
|
||||
ACSymbol symbol = visitor.scope_.findSymbolInCurrentScope(cursorPosition, tokens[0].value);
|
||||
if (symbol is null)
|
||||
{
|
||||
writeln("Could not find declaration of ", tokens[0].value);
|
||||
return;
|
||||
}
|
||||
|
||||
writeln(symbol.kind);
|
||||
if (symbol.kind == CompletionKind.variableName
|
||||
|| symbol.kind == CompletionKind.memberVariableName)
|
||||
{
|
||||
symbol = resolveType(cursorPosition, symbol, visitor.scope_);
|
||||
}
|
||||
loop: for (size_t i = 1; i < tokens.length; i++)
|
||||
{
|
||||
TokenType open;
|
||||
TokenType close;
|
||||
with (TokenType) switch (tokens[i].type)
|
||||
{
|
||||
case TokenType.int_:
|
||||
case TokenType.uint_:
|
||||
case TokenType.long_:
|
||||
case TokenType.ulong_:
|
||||
case TokenType.char_:
|
||||
case TokenType.wchar_:
|
||||
case TokenType.dchar_:
|
||||
case TokenType.bool_:
|
||||
case TokenType.byte_:
|
||||
case TokenType.ubyte_:
|
||||
case TokenType.short_:
|
||||
case TokenType.ushort_:
|
||||
case TokenType.cent_:
|
||||
case TokenType.ucent_:
|
||||
case TokenType.float_:
|
||||
case TokenType.ifloat_:
|
||||
case TokenType.cfloat_:
|
||||
case TokenType.idouble_:
|
||||
case TokenType.cdouble_:
|
||||
case TokenType.double_:
|
||||
case TokenType.real_:
|
||||
case TokenType.ireal_:
|
||||
case TokenType.creal_:
|
||||
case this_:
|
||||
symbol = symbol.getPartByName(getTokenValue(tokens[i].type));
|
||||
if (symbol is null)
|
||||
break loop;
|
||||
break;
|
||||
case identifier:
|
||||
symbol = symbol.getPartByName(tokens[i].value);
|
||||
if (symbol is null)
|
||||
break loop;
|
||||
break;
|
||||
case lParen:
|
||||
open = TokenType.lParen;
|
||||
close = TokenType.rParen;
|
||||
goto skip;
|
||||
case lBracket:
|
||||
open = TokenType.lBracket;
|
||||
close = TokenType.rBracket;
|
||||
skip:
|
||||
i++;
|
||||
for (int depth = 1; depth > 0 && i < tokens.length; i++)
|
||||
{
|
||||
if (tokens[i].type == open)
|
||||
depth++;
|
||||
else if (tokens[i].type == close)
|
||||
{
|
||||
depth--;
|
||||
if (depth == 0) break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case dot:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (s; symbol.parts)
|
||||
{
|
||||
writeln("Adding ", s.name, " to the completion list");
|
||||
//writeln("Adding ", s.name, " to the completion list");
|
||||
response.completionKinds ~= s.kind;
|
||||
response.completions ~= s.name;
|
||||
}
|
||||
response.completionType = CompletionType.identifiers;
|
||||
}
|
||||
|
||||
ACSymbol resolveType(size_t cursorPosition, ACSymbol symbol, Scope scope_)
|
||||
{
|
||||
writeln("Resolving type of ", symbol.name);
|
||||
Type type = symbol.type;
|
||||
|
||||
// Simple case
|
||||
if (type.type2.builtinType != TokenType.invalid && type.typeSuffixes.length == 0)
|
||||
{
|
||||
return scope_.findSymbolInCurrentScope(cursorPosition, getTokenValue(type.type2.builtinType));
|
||||
}
|
||||
if (type.type2.symbol !is null && type.typeSuffixes.length == 0)
|
||||
{
|
||||
return scope_.findSymbolInCurrentScope(cursorPosition,
|
||||
type.type2.symbol.identifierOrTemplateChain.identifiersOrTemplateInstances[0].identifier.value);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
T getExpression(T)(T beforeTokens)
|
||||
{
|
||||
size_t i = beforeTokens.length - 1;
|
||||
|
@ -187,6 +262,30 @@ T getExpression(T)(T beforeTokens)
|
|||
{
|
||||
with (TokenType) switch (beforeTokens[i].type)
|
||||
{
|
||||
case TokenType.int_:
|
||||
case TokenType.uint_:
|
||||
case TokenType.long_:
|
||||
case TokenType.ulong_:
|
||||
case TokenType.char_:
|
||||
case TokenType.wchar_:
|
||||
case TokenType.dchar_:
|
||||
case TokenType.bool_:
|
||||
case TokenType.byte_:
|
||||
case TokenType.ubyte_:
|
||||
case TokenType.short_:
|
||||
case TokenType.ushort_:
|
||||
case TokenType.cent_:
|
||||
case TokenType.ucent_:
|
||||
case TokenType.float_:
|
||||
case TokenType.ifloat_:
|
||||
case TokenType.cfloat_:
|
||||
case TokenType.idouble_:
|
||||
case TokenType.cdouble_:
|
||||
case TokenType.double_:
|
||||
case TokenType.real_:
|
||||
case TokenType.ireal_:
|
||||
case TokenType.creal_:
|
||||
case this_:
|
||||
case identifier:
|
||||
if (hasSpecialPrefix)
|
||||
{
|
||||
|
@ -257,3 +356,118 @@ unittest
|
|||
{
|
||||
assert("ClNa".createCamelCaseRegex() == "Cl.*Na.*");
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes builtin types and the various properties of builtin types
|
||||
*/
|
||||
static this()
|
||||
{
|
||||
auto bool_ = new ACSymbol("bool", CompletionKind.keyword);
|
||||
auto int_ = new ACSymbol("int", CompletionKind.keyword);
|
||||
auto long_ = new ACSymbol("long", CompletionKind.keyword);
|
||||
auto byte_ = new ACSymbol("byte", CompletionKind.keyword);
|
||||
auto dchar_ = new ACSymbol("dchar", CompletionKind.keyword);
|
||||
auto short_ = new ACSymbol("short", CompletionKind.keyword);
|
||||
auto ubyte_ = new ACSymbol("ubyte", CompletionKind.keyword);
|
||||
auto uint_ = new ACSymbol("uint", CompletionKind.keyword);
|
||||
auto ulong_ = new ACSymbol("ulong", CompletionKind.keyword);
|
||||
auto ushort_ = new ACSymbol("ushort", CompletionKind.keyword);
|
||||
auto wchar_ = new ACSymbol("wchar", CompletionKind.keyword);
|
||||
|
||||
auto alignof_ = new ACSymbol("alignof", CompletionKind.keyword, ulong_);
|
||||
auto mangleof_ = new ACSymbol("mangleof", CompletionKind.keyword);
|
||||
auto sizeof_ = new ACSymbol("sizeof", CompletionKind.keyword, ulong_);
|
||||
auto stringof_ = new ACSymbol("stringof", CompletionKind.keyword);
|
||||
|
||||
arraySymbols ~= alignof_;
|
||||
arraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
|
||||
arraySymbols ~= new ACSymbol("idup", CompletionKind.keyword);
|
||||
arraySymbols ~= new ACSymbol("init", CompletionKind.keyword);
|
||||
arraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
|
||||
arraySymbols ~= mangleof_;
|
||||
arraySymbols ~= new ACSymbol("ptr", CompletionKind.keyword);
|
||||
arraySymbols ~= new ACSymbol("reverse", CompletionKind.keyword);
|
||||
arraySymbols ~= sizeof_;
|
||||
arraySymbols ~= new ACSymbol("sort", CompletionKind.keyword);
|
||||
arraySymbols ~= stringof_;
|
||||
|
||||
assocArraySymbols ~= alignof_;
|
||||
assocArraySymbols ~= new ACSymbol("byKey", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("byValue", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("dup", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("get", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("init", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("keys", CompletionKind.keyword);
|
||||
assocArraySymbols ~= new ACSymbol("length", CompletionKind.keyword, ulong_);
|
||||
assocArraySymbols ~= mangleof_;
|
||||
assocArraySymbols ~= new ACSymbol("rehash", CompletionKind.keyword);
|
||||
arraySymbols ~= sizeof_;
|
||||
arraySymbols ~= stringof_;
|
||||
assocArraySymbols ~= new ACSymbol("values", CompletionKind.keyword);
|
||||
|
||||
foreach (s; [bool_, int_, long_, byte_, dchar_, short_, ubyte_, uint_,
|
||||
ulong_, ushort_, wchar_])
|
||||
{
|
||||
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
|
||||
s.parts ~= alignof_;
|
||||
s.parts ~= sizeof_;
|
||||
s.parts ~= stringof_;
|
||||
s.parts ~= mangleof_;
|
||||
}
|
||||
|
||||
auto cdouble_ = new ACSymbol("cdouble", CompletionKind.keyword);
|
||||
auto cent_ = new ACSymbol("cent", CompletionKind.keyword);
|
||||
auto cfloat_ = new ACSymbol("cfloat", CompletionKind.keyword);
|
||||
auto char_ = new ACSymbol("char", CompletionKind.keyword);
|
||||
auto creal_ = new ACSymbol("creal", CompletionKind.keyword);
|
||||
auto double_ = new ACSymbol("double", CompletionKind.keyword);
|
||||
auto float_ = new ACSymbol("float", CompletionKind.keyword);
|
||||
auto idouble_ = new ACSymbol("idouble", CompletionKind.keyword);
|
||||
auto ifloat_ = new ACSymbol("ifloat", CompletionKind.keyword);
|
||||
auto ireal_ = new ACSymbol("ireal", CompletionKind.keyword);
|
||||
auto real_ = new ACSymbol("real", CompletionKind.keyword);
|
||||
auto ucent_ = new ACSymbol("ucent", CompletionKind.keyword);
|
||||
|
||||
foreach (s; [cdouble_, cent_, cfloat_, char_, creal_, double_, float_,
|
||||
idouble_, ifloat_, ireal_, real_, ucent_])
|
||||
{
|
||||
s.parts ~= alignof_;
|
||||
s.parts ~= new ACSymbol("dig", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("episilon", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("infinity", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("init", CompletionKind.keyword, s);
|
||||
s.parts ~= mangleof_;
|
||||
s.parts ~= new ACSymbol("mant_dig", CompletionKind.keyword, int_);
|
||||
s.parts ~= new ACSymbol("max", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("max_10_exp", CompletionKind.keyword, int_);
|
||||
s.parts ~= new ACSymbol("max_exp", CompletionKind.keyword, int_);
|
||||
s.parts ~= new ACSymbol("min", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("min_exp", CompletionKind.keyword, int_);
|
||||
s.parts ~= new ACSymbol("min_10_exp", CompletionKind.keyword, int_);
|
||||
s.parts ~= new ACSymbol("min_normal", CompletionKind.keyword, s);
|
||||
s.parts ~= new ACSymbol("nan", CompletionKind.keyword, s);
|
||||
s.parts ~= sizeof_;
|
||||
s.parts ~= stringof_;
|
||||
}
|
||||
|
||||
ireal_.parts ~= new ACSymbol("im", CompletionKind.keyword, real_);
|
||||
ifloat_.parts ~= new ACSymbol("im", CompletionKind.keyword, float_);
|
||||
idouble_.parts ~= new ACSymbol("im", CompletionKind.keyword, double_);
|
||||
ireal_.parts ~= new ACSymbol("re", CompletionKind.keyword, real_);
|
||||
ifloat_.parts ~= new ACSymbol("re", CompletionKind.keyword, float_);
|
||||
idouble_.parts ~= new ACSymbol("re", CompletionKind.keyword, double_);
|
||||
|
||||
auto void_ = new ACSymbol("void", CompletionKind.keyword);
|
||||
|
||||
builtinSymbols = [bool_, int_, long_, byte_, dchar_, short_, ubyte_, uint_,
|
||||
ulong_, ushort_, wchar_, cdouble_, cent_, cfloat_, char_, creal_, double_,
|
||||
float_, idouble_, ifloat_, ireal_, real_, ucent_, void_];
|
||||
}
|
||||
|
||||
ACSymbol[] builtinSymbols;
|
||||
ACSymbol[] arraySymbols;
|
||||
ACSymbol[] assocArraySymbols;
|
||||
ACSymbol[] classSymbols;
|
||||
ACSymbol[] structSymbols;
|
||||
|
|
84
constants.d
84
constants.d
|
@ -173,54 +173,6 @@ immutable string[] versions = [
|
|||
"X86_64"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of all types
|
||||
*/
|
||||
immutable string[] allProperties = [
|
||||
"alignof",
|
||||
"init",
|
||||
"mangleof",
|
||||
"sizeof",
|
||||
"stringof"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of integer types
|
||||
*/
|
||||
immutable string[] integerProperties = [
|
||||
"alignof",
|
||||
"init",
|
||||
"mangleof",
|
||||
"max",
|
||||
"min",
|
||||
"sizeof",
|
||||
"stringof"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of floating point types
|
||||
*/
|
||||
immutable string[] floatProperties = [
|
||||
"alignof",
|
||||
"dig",
|
||||
"epsilon",
|
||||
"im",
|
||||
"infinity",
|
||||
"init",
|
||||
"mangleof",
|
||||
"mant_dig",
|
||||
"max",
|
||||
"max_10_exp",
|
||||
"max_exp",
|
||||
"min_10_exp",
|
||||
"min_exp",
|
||||
"min_normal",
|
||||
"nan",
|
||||
"re",
|
||||
"sizeof",
|
||||
"stringof"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of class types
|
||||
*/
|
||||
|
@ -247,39 +199,3 @@ immutable string[] structProperties = [
|
|||
"sizeof",
|
||||
"stringof"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of arrays
|
||||
*/
|
||||
immutable string[] arrayProperties = [
|
||||
"alignof",
|
||||
"dup",
|
||||
"idup",
|
||||
"init",
|
||||
"length",
|
||||
"mangleof",
|
||||
"ptr",
|
||||
"reverse",
|
||||
"sizeof",
|
||||
"sort",
|
||||
"stringof"
|
||||
];
|
||||
|
||||
/**
|
||||
* Properties of associative arrays
|
||||
*/
|
||||
immutable string[] associativeArrayProperties = [
|
||||
"alignof",
|
||||
"byKey",
|
||||
"byValue",
|
||||
"dup",
|
||||
"get",
|
||||
"init",
|
||||
"keys",
|
||||
"length",
|
||||
"mangleof",
|
||||
"rehash",
|
||||
"sizeof",
|
||||
"stringof",
|
||||
"values"
|
||||
];
|
||||
|
|
23
messages.d
23
messages.d
|
@ -32,6 +32,9 @@ enum CompletionKind : char
|
|||
/// structure names
|
||||
structName = 's',
|
||||
|
||||
/// union name
|
||||
unionName = 'u',
|
||||
|
||||
/// variable name
|
||||
variableName = 'v',
|
||||
|
||||
|
@ -54,7 +57,13 @@ enum CompletionKind : char
|
|||
packageName = 'P',
|
||||
|
||||
// module name
|
||||
moduleName = 'M'
|
||||
moduleName = 'M',
|
||||
|
||||
// array
|
||||
array = 'a',
|
||||
|
||||
// associative array
|
||||
assocArray = 'A',
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,6 +83,13 @@ enum CompletionType : string
|
|||
calltips = "calltips"
|
||||
}
|
||||
|
||||
enum RequestKind
|
||||
{
|
||||
autocomplete,
|
||||
clearCache,
|
||||
addImport
|
||||
}
|
||||
|
||||
/**
|
||||
* Autocompletion request message
|
||||
*/
|
||||
|
@ -84,6 +100,11 @@ struct AutocompleteRequest
|
|||
*/
|
||||
string fileName;
|
||||
|
||||
/**
|
||||
* Command coming from the client
|
||||
*/
|
||||
RequestKind kind;
|
||||
|
||||
/**
|
||||
* Paths to be searched for import files
|
||||
*/
|
||||
|
|
|
@ -21,23 +21,97 @@ module modulecache;
|
|||
import std.file;
|
||||
import std.datetime;
|
||||
|
||||
import acvisitor;
|
||||
|
||||
struct CacheEntry
|
||||
{
|
||||
ACSymbol[] symbols;
|
||||
SysTime modificationTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Caches pre-parsed module information.
|
||||
*/
|
||||
struct ModuleCache
|
||||
{
|
||||
@disable this();
|
||||
|
||||
/**
|
||||
* Clears the completion cache
|
||||
*/
|
||||
void clear()
|
||||
{
|
||||
cache = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given path to the list of directories checked for imports
|
||||
*/
|
||||
void addImportPath(string path)
|
||||
{
|
||||
importPaths ~= path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* moduleName = the name of the module in "a.b.c" form
|
||||
* Returns:
|
||||
* The symbols defined in the given module
|
||||
*/
|
||||
ACSymbol[] getSymbolsInModule(string moduleName)
|
||||
{
|
||||
string location = resolveImportLoctation(moduleName);
|
||||
if (!needsReparsing(location))
|
||||
return;
|
||||
|
||||
Module mod = parseModule(tokens, location, &doesNothing);
|
||||
auto visitor = new AutocompleteVisitor;
|
||||
visitor.visit(mod);
|
||||
cache[location].mod = visitor.symbols;
|
||||
}
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* moduleName the name of the module being imported, in "a.b.c" style
|
||||
* Returns:
|
||||
* The absolute path to the file that contains the module, or null if
|
||||
* not found.
|
||||
*/
|
||||
string resolveImportLoctation(string moduleName)
|
||||
{
|
||||
foreach (path; importPaths)
|
||||
{
|
||||
string filePath = path ~ "/" ~ imp;
|
||||
if (filePath.exists())
|
||||
return filePath;
|
||||
filePath ~= "i"; // check for x.di if x.d isn't found
|
||||
if (filePath.exists())
|
||||
return filePath;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Params:
|
||||
* mod = the path to the module
|
||||
* Returns:
|
||||
* true if the module needs to be reparsed, false otherwise
|
||||
*/
|
||||
bool needsReparsing(string mod)
|
||||
{
|
||||
if (!exists(mod))
|
||||
return false;
|
||||
if (mod !in modificationTimes)
|
||||
if (!exists(mod) || mod !in cache)
|
||||
return true;
|
||||
SysTime access;
|
||||
SysTime modification;
|
||||
getTimes(mod, access, modification);
|
||||
if (modificationTimes[mod] != modification)
|
||||
return true;
|
||||
return false;
|
||||
return cache[mod].modificationTime != modification;
|
||||
}
|
||||
|
||||
SysTime[string] modificationTimes;
|
||||
// Mapping of file paths to their cached symbols.
|
||||
CacheEntry[string] cache;
|
||||
|
||||
// Listing of paths to check for imports
|
||||
string[] importPaths;
|
||||
}
|
||||
|
|
13
server.d
13
server.d
|
@ -79,10 +79,19 @@ int main(string[] args)
|
|||
writeln("Socket recieve failed");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
AutocompleteRequest request;
|
||||
msgpack.unpack(buffer[8 .. bytesReceived], request);
|
||||
if (request.kind == RequestKind.addImport)
|
||||
{
|
||||
|
||||
}
|
||||
else if (request.kind == RequestKind.clearCache)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
AutocompleteResponse response = complete(request, importPaths);
|
||||
ubyte[] responseBytes = msgpack.pack(response);
|
||||
assert(s.send(responseBytes) == responseBytes.length);
|
||||
|
|
Loading…
Reference in New Issue