DCD/autocomplete.d

245 lines
6.6 KiB
D

module autocomplete;
import std.algorithm;
import std.array;
import std.conv;
import std.d.ast;
import std.d.lexer;
import std.d.parser;
import std.range;
import std.stdio;
import std.uni;
import messages;
import importutils;
import constants;
AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
{
writeln("Got a completion request");
AutocompleteResponse response;
LexerConfig config;
auto tokens = request.sourceCode.byToken(config);
auto tokenArray = tokens.array();
auto sortedTokens = assumeSorted(tokenArray);
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
if (beforeTokens[$ - 1] == TokenType.lParen && beforeTokens.length >= 2)
{
switch (beforeTokens[$ - 2].type)
{
case TokenType.traits:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < traits.length; i++)
{
response.completions ~= traits[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case TokenType.scope_:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < scopes.length; i++)
{
response.completions ~= scopes[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case TokenType.version_:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < versions.length; i++)
{
response.completions ~= versions[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case TokenType.pragma_:
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < pragmas.length; i++)
{
response.completions ~= pragmas[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case TokenType.identifier:
// TODO
break;
default:
break;
}
}
else if (beforeTokens[$ - 1] == TokenType.dot && beforeTokens.length >= 2)
{
switch (beforeTokens[$ - 2].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_:
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_:
case TokenType.idouble_:
case TokenType.cdouble_:
case TokenType.double_:
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:
// TODO: This is a placeholder
response.completionType = CompletionType.identifiers;
for (size_t i = 0; i < allProperties.length; i++)
{
response.completions ~= allProperties[i];
response.completionKinds ~= CompletionKind.keyword;
}
break;
case TokenType.lParen:
case TokenType.lBrace:
case TokenType.lBracket:
case TokenType.semicolon:
case TokenType.colon:
// TODO: global scope
break;
case TokenType.rParen:
case TokenType.rBrace:
case TokenType.rBracket:
default:
// TODO
break;
}
}
else if (beforeTokens[$ - 1] == TokenType.identifier)
{
Module mod = parseModule(tokenArray, request.fileName, &messageFunction);
writeln("Resolved imports: ", getImportedFiles(mod, importPaths ~ request.importPaths));
}
return response;
}
void messageFunction(string fileName, int line, int column, string message)
{
// does nothing
}
string createCamelCaseRegex(string input)
{
dstring output;
uint i;
foreach (dchar d; input)
{
if (isLower(d))
output ~= d;
else if (i > 0)
{
output ~= ".*";
output ~= d;
}
i++;
}
return to!string(output ~ ".*");
}
unittest
{
assert("ClNa".createCamelCaseRegex() == "Cl.*Na.*");
}
enum SymbolKind
{
className,
interfaceName,
enumName,
variableName,
structName,
unionName,
functionName
}
class Symbol
{
Symbol[] parts;
string name;
SymbolKind kind;
Type[string] templateParameters;
}
class Scope
{
public:
/**
* @return the innermost Scope that contains the given cursor position.
*/
const(Scope) findCurrentScope(size_t cursorPosition) const
{
if (cursorPosition < start || cursorPosition > end)
return null;
foreach (sc; children)
{
auto s = sc.findCurrentScope(cursorPosition);
if (s is null)
continue;
else
return s;
}
return this;
}
const(Symbol)[] getSymbolsInScope() const
{
return symbols ~ parent.getSymbolsInScope();
}
Symbol[] getSymbolsInScope(string name)
{
Symbol[] results;
symbols.filter!(x => x.name == name)().copy(results);
parent.getSymbolsInScope(name).copy(results);
return results;
}
private:
size_t start;
size_t end;
Symbol[] symbols;
Scope parent;
Scope[] children;
}