Basic autocomplete for enums in current file works
This commit is contained in:
parent
a7eb6c363d
commit
267dbab208
|
@ -0,0 +1,92 @@
|
||||||
|
/**
|
||||||
|
* 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 actypes;
|
||||||
|
|
||||||
|
import stdx.d.ast;
|
||||||
|
import std.algorithm;
|
||||||
|
import std.stdio;
|
||||||
|
import messages;
|
||||||
|
|
||||||
|
class ACSymbol
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ACSymbol[] parts;
|
||||||
|
string name;
|
||||||
|
CompletionKind kind;
|
||||||
|
Type[string] templateParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Scope
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
this(size_t start, size_t end)
|
||||||
|
{
|
||||||
|
this.start = start;
|
||||||
|
this.end = end;
|
||||||
|
}
|
||||||
|
|
||||||
|
const(ACSymbol) findSymbolInCurrentScope(size_t cursorPosition, string name) const
|
||||||
|
{
|
||||||
|
auto s = findCurrentScope(cursorPosition);
|
||||||
|
if (s is null)
|
||||||
|
{
|
||||||
|
writeln("Could not find scope");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return s.findSymbolInScope(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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(ACSymbol) findSymbolInScope(string name) const
|
||||||
|
{
|
||||||
|
foreach (symbol; symbols)
|
||||||
|
{
|
||||||
|
if (symbol.name == name)
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
if (parent !is null)
|
||||||
|
return parent.findSymbolInScope(name);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t start;
|
||||||
|
size_t end;
|
||||||
|
ACSymbol[] symbols;
|
||||||
|
Scope parent;
|
||||||
|
Scope[] children;
|
||||||
|
}
|
|
@ -0,0 +1,147 @@
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
|
||||||
|
import std.file;
|
||||||
|
import stdx.d.parser;
|
||||||
|
import stdx.d.ast;
|
||||||
|
import stdx.d.lexer;
|
||||||
|
import std.stdio;
|
||||||
|
|
||||||
|
import actypes;
|
||||||
|
import messages;
|
||||||
|
|
||||||
|
class AutoCompleteVisitor : ASTVisitor
|
||||||
|
{
|
||||||
|
alias ASTVisitor.visit visit;
|
||||||
|
|
||||||
|
override void visit(EnumDeclaration enumDec)
|
||||||
|
{
|
||||||
|
auto symbol = new ACSymbol;
|
||||||
|
symbol.name = enumDec.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;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(EnumMember member)
|
||||||
|
{
|
||||||
|
auto s = new ACSymbol;
|
||||||
|
s.kind = CompletionKind.enumMember;
|
||||||
|
s.name = member.name.value;
|
||||||
|
writeln("Added enum member ", s.name);
|
||||||
|
if (parentSymbol !is null)
|
||||||
|
parentSymbol.parts ~= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(ImportDeclaration dec)
|
||||||
|
{
|
||||||
|
foreach (singleImport; dec.singleImports)
|
||||||
|
{
|
||||||
|
imports ~= flattenIdentifierChain(singleImport.identifierChain);
|
||||||
|
}
|
||||||
|
if (dec.importBindings !is null)
|
||||||
|
{
|
||||||
|
imports ~= flattenIdentifierChain(dec.importBindings.singleImport.identifierChain);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(BlockStatement blockStatement)
|
||||||
|
{
|
||||||
|
auto s = scope_;
|
||||||
|
scope_ = new Scope(blockStatement.startLocation,
|
||||||
|
blockStatement.endLocation);
|
||||||
|
blockStatement.accept(this);
|
||||||
|
s.children ~= scope_;
|
||||||
|
scope_ = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
override void visit(Module mod)
|
||||||
|
{
|
||||||
|
scope_ = new Scope(0, size_t.max);
|
||||||
|
mod.accept(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string flattenIdentifierChain(IdentifierChain chain)
|
||||||
|
{
|
||||||
|
string rVal;
|
||||||
|
bool first = true;
|
||||||
|
foreach (identifier; chain.identifiers)
|
||||||
|
{
|
||||||
|
if (!first)
|
||||||
|
rVal ~= "/";
|
||||||
|
rVal ~= identifier.value;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
rVal ~= ".d";
|
||||||
|
return rVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ACSymbol[] symbols;
|
||||||
|
ACSymbol parentSymbol;
|
||||||
|
Scope scope_;
|
||||||
|
string[] imports;
|
||||||
|
}
|
||||||
|
|
||||||
|
void doesNothing(string, int, int, string) {}
|
||||||
|
|
||||||
|
AutoCompleteVisitor processModule(const(Token)[] tokens)
|
||||||
|
{
|
||||||
|
Module mod = parseModule(tokens, "", &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;
|
||||||
|
}
|
166
autocomplete.d
166
autocomplete.d
|
@ -23,17 +23,19 @@ module autocomplete;
|
||||||
import std.algorithm;
|
import std.algorithm;
|
||||||
import std.array;
|
import std.array;
|
||||||
import std.conv;
|
import std.conv;
|
||||||
import std.d.ast;
|
import stdx.d.ast;
|
||||||
import std.d.lexer;
|
import stdx.d.lexer;
|
||||||
import std.d.parser;
|
import stdx.d.parser;
|
||||||
import std.range;
|
import std.range;
|
||||||
import std.stdio;
|
import std.stdio;
|
||||||
import std.uni;
|
import std.uni;
|
||||||
|
|
||||||
import messages;
|
import messages;
|
||||||
import importutils;
|
import acvisitor;
|
||||||
|
import actypes;
|
||||||
import constants;
|
import constants;
|
||||||
|
|
||||||
|
|
||||||
AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
{
|
{
|
||||||
writeln("Got a completion request");
|
writeln("Got a completion request");
|
||||||
|
@ -47,49 +49,37 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
|
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
|
||||||
if (beforeTokens[$ - 1] == TokenType.lParen && beforeTokens.length >= 2)
|
if (beforeTokens[$ - 1] == TokenType.lParen && beforeTokens.length >= 2)
|
||||||
{
|
{
|
||||||
|
immutable(string)[] completions;
|
||||||
switch (beforeTokens[$ - 2].type)
|
switch (beforeTokens[$ - 2].type)
|
||||||
{
|
{
|
||||||
case TokenType.traits:
|
case TokenType.traits:
|
||||||
response.completionType = CompletionType.identifiers;
|
completions = traits;
|
||||||
for (size_t i = 0; i < traits.length; i++)
|
goto fillResponse;
|
||||||
{
|
|
||||||
response.completions ~= traits[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.scope_:
|
case TokenType.scope_:
|
||||||
response.completionType = CompletionType.identifiers;
|
completions = scopes;
|
||||||
for (size_t i = 0; i < scopes.length; i++)
|
goto fillResponse;
|
||||||
{
|
|
||||||
response.completions ~= scopes[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.version_:
|
case TokenType.version_:
|
||||||
response.completionType = CompletionType.identifiers;
|
completions = versions;
|
||||||
for (size_t i = 0; i < versions.length; i++)
|
goto fillResponse;
|
||||||
{
|
|
||||||
response.completions ~= versions[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.extern_:
|
case TokenType.extern_:
|
||||||
response.completionType = CompletionType.identifiers;
|
completions = linkages;
|
||||||
for (size_t i = 0; i < linkages.length; i++)
|
goto fillResponse;
|
||||||
{
|
|
||||||
response.completions ~= linkages[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case TokenType.pragma_:
|
case TokenType.pragma_:
|
||||||
|
completions = pragmas;
|
||||||
|
fillResponse:
|
||||||
response.completionType = CompletionType.identifiers;
|
response.completionType = CompletionType.identifiers;
|
||||||
for (size_t i = 0; i < pragmas.length; i++)
|
for (size_t i = 0; i < completions.length; i++)
|
||||||
{
|
{
|
||||||
response.completions ~= pragmas[i];
|
response.completions ~= completions[i];
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
response.completionKinds ~= CompletionKind.keyword;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TokenType.identifier:
|
case TokenType.identifier:
|
||||||
|
case TokenType.rParen:
|
||||||
|
case TokenType.rBracket:
|
||||||
|
auto expression = getExpression(beforeTokens[0..$]);
|
||||||
|
writeln("Expression: ", expression.map!"a.value"());
|
||||||
|
response.completionType = CompletionType.calltips;
|
||||||
// TODO
|
// TODO
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -150,14 +140,9 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
case TokenType.identifier:
|
case TokenType.identifier:
|
||||||
case TokenType.rParen:
|
case TokenType.rParen:
|
||||||
case TokenType.rBracket:
|
case TokenType.rBracket:
|
||||||
|
auto visitor = processModule(tokenArray);
|
||||||
auto expression = getExpression(beforeTokens[0..$]);
|
auto expression = getExpression(beforeTokens[0..$]);
|
||||||
writeln("Expression: ", expression.map!"a.value"());
|
response.setCompletions(visitor, expression, request.cursorPosition);
|
||||||
response.completionType = CompletionType.identifiers;
|
|
||||||
for (size_t i = 0; i < allProperties.length; i++)
|
|
||||||
{
|
|
||||||
response.completions ~= allProperties[i];
|
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case TokenType.lParen:
|
case TokenType.lParen:
|
||||||
case TokenType.lBrace:
|
case TokenType.lBrace:
|
||||||
|
@ -171,14 +156,25 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (beforeTokens[$ - 1] == TokenType.identifier)
|
return response;
|
||||||
{
|
|
||||||
Module mod = parseModule(tokenArray, request.fileName, &messageFunction);
|
|
||||||
|
|
||||||
writeln("Resolved imports: ", getImportedFiles(mod, importPaths ~ request.importPaths));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return response;
|
void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
|
ref const 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);
|
||||||
|
if (symbol is null)
|
||||||
|
return;
|
||||||
|
foreach (s; symbol.parts)
|
||||||
|
{
|
||||||
|
writeln("Adding ", s.name, " to the completion list");
|
||||||
|
response.completionKinds ~= s.kind;
|
||||||
|
response.completions ~= s.name;
|
||||||
|
}
|
||||||
|
response.completionType = CompletionType.identifiers;
|
||||||
}
|
}
|
||||||
|
|
||||||
T getExpression(T)(T beforeTokens)
|
T getExpression(T)(T beforeTokens)
|
||||||
|
@ -239,11 +235,6 @@ T getExpression(T)(T beforeTokens)
|
||||||
return beforeTokens[i .. $ - 1];
|
return beforeTokens[i .. $ - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
void messageFunction(string fileName, int line, int column, string message)
|
|
||||||
{
|
|
||||||
// does nothing
|
|
||||||
}
|
|
||||||
|
|
||||||
string createCamelCaseRegex(string input)
|
string createCamelCaseRegex(string input)
|
||||||
{
|
{
|
||||||
dstring output;
|
dstring output;
|
||||||
|
@ -266,74 +257,3 @@ unittest
|
||||||
{
|
{
|
||||||
assert("ClNa".createCamelCaseRegex() == "Cl.*Na.*");
|
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:
|
|
||||||
|
|
||||||
Symbol[] findSymbolsInCurrentScope(size_t cursorPosition, string name)
|
|
||||||
{
|
|
||||||
auto s = findCurrentScope(cursorPosition);
|
|
||||||
if (s is null)
|
|
||||||
return [];
|
|
||||||
else
|
|
||||||
return s.getSymbolsInScope(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the innermost Scope that contains the given cursor position.
|
|
||||||
*/
|
|
||||||
Scope findCurrentScope(size_t cursorPosition)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
Symbol[] getSymbolsInScope()
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
2
build.sh
2
build.sh
|
@ -1,2 +1,2 @@
|
||||||
dmd client.d messages.d msgpack-d/src/msgpack.d -Imsgpack-d/src -ofdcd-client
|
dmd client.d messages.d msgpack-d/src/msgpack.d -Imsgpack-d/src -ofdcd-client
|
||||||
dmd server.d messages.d constants.d importutils.d autocomplete.d ../dscanner/std/d/ast.d ../dscanner/std/d/parser.d ../dscanner/std/d/lexer.d ../dscanner/std/d/entities.d msgpack-d/src/msgpack.d -Imsgpack-d/src -I../dscanner/ -ofdcd-server
|
dmd server.d actypes.d messages.d constants.d acvisitor.d autocomplete.d ../dscanner/stdx/d/ast.d ../dscanner/stdx/d/parser.d ../dscanner/stdx/d/lexer.d ../dscanner/stdx/d/entities.d msgpack-d/src/msgpack.d -Imsgpack-d/src -I../dscanner/ -ofdcd-server
|
||||||
|
|
4
client.d
4
client.d
|
@ -28,7 +28,7 @@ import messages;
|
||||||
|
|
||||||
int main(string[] args)
|
int main(string[] args)
|
||||||
{
|
{
|
||||||
int cursorPos = -1;
|
size_t cursorPos = size_t.max;
|
||||||
string[] importPaths;
|
string[] importPaths;
|
||||||
ushort port = 9166;
|
ushort port = 9166;
|
||||||
bool help;
|
bool help;
|
||||||
|
@ -50,7 +50,7 @@ int main(string[] args)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cursor position is a required argument
|
// cursor position is a required argument
|
||||||
if (cursorPos == -1)
|
if (cursorPos == size_t.max)
|
||||||
{
|
{
|
||||||
printHelp(args[0]);
|
printHelp(args[0]);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -1,89 +0,0 @@
|
||||||
/**
|
|
||||||
* 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 importutils;
|
|
||||||
|
|
||||||
import std.file;
|
|
||||||
import std.d.parser;
|
|
||||||
import std.d.ast;
|
|
||||||
import std.stdio;
|
|
||||||
|
|
||||||
class ImportCollector : ASTVisitor
|
|
||||||
{
|
|
||||||
alias ASTVisitor.visit visit;
|
|
||||||
|
|
||||||
override void visit(ImportDeclaration dec)
|
|
||||||
{
|
|
||||||
foreach (singleImport; dec.singleImports)
|
|
||||||
{
|
|
||||||
imports ~= flattenIdentifierChain(singleImport.identifierChain);
|
|
||||||
}
|
|
||||||
if (dec.importBindings !is null)
|
|
||||||
{
|
|
||||||
imports ~= flattenIdentifierChain(dec.importBindings.singleImport.identifierChain);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string flattenIdentifierChain(IdentifierChain chain)
|
|
||||||
{
|
|
||||||
string rVal;
|
|
||||||
bool first = true;
|
|
||||||
foreach (identifier; chain.identifiers)
|
|
||||||
{
|
|
||||||
if (!first)
|
|
||||||
rVal ~= "/";
|
|
||||||
rVal ~= identifier.value;
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
rVal ~= ".d";
|
|
||||||
return rVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] imports;
|
|
||||||
}
|
|
||||||
|
|
||||||
string[] getImportedFiles(Module mod, string[] importPaths)
|
|
||||||
{
|
|
||||||
auto collector = new ImportCollector;
|
|
||||||
collector.visit(mod);
|
|
||||||
string[] importedFiles;
|
|
||||||
foreach (imp; collector.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;
|
|
||||||
}
|
|
|
@ -47,6 +47,9 @@ enum CompletionKind : char
|
||||||
/// enum name
|
/// enum name
|
||||||
enumName = 'g',
|
enumName = 'g',
|
||||||
|
|
||||||
|
/// enum member
|
||||||
|
enumMember = 'e',
|
||||||
|
|
||||||
/// package name
|
/// package name
|
||||||
packageName = 'P',
|
packageName = 'P',
|
||||||
|
|
||||||
|
@ -94,7 +97,7 @@ struct AutocompleteRequest
|
||||||
/**
|
/**
|
||||||
* The cursor position
|
* The cursor position
|
||||||
*/
|
*/
|
||||||
int cursorPosition;
|
size_t cursorPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
7
server.d
7
server.d
|
@ -48,7 +48,11 @@ int main(string[] args)
|
||||||
socket.blocking = true;
|
socket.blocking = true;
|
||||||
socket.bind(new InternetAddress("127.0.0.1", port));
|
socket.bind(new InternetAddress("127.0.0.1", port));
|
||||||
socket.listen(0);
|
socket.listen(0);
|
||||||
scope (exit) socket.close();
|
scope (exit)
|
||||||
|
{
|
||||||
|
socket.shutdown(SocketShutdown.BOTH);
|
||||||
|
socket.close();
|
||||||
|
}
|
||||||
ubyte[1024 * 1024 * 4] buffer = void; // 4 megabytes should be enough for anybody...
|
ubyte[1024 * 1024 * 4] buffer = void; // 4 megabytes should be enough for anybody...
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
@ -78,7 +82,6 @@ int main(string[] args)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
AutocompleteRequest request;
|
AutocompleteRequest request;
|
||||||
writeln("Unpacking ", bytesReceived, "/", buffer.length, " bytes into a request");
|
|
||||||
msgpack.unpack(buffer[8 .. bytesReceived], request);
|
msgpack.unpack(buffer[8 .. bytesReceived], request);
|
||||||
AutocompleteResponse response = complete(request, importPaths);
|
AutocompleteResponse response = complete(request, importPaths);
|
||||||
ubyte[] responseBytes = msgpack.pack(response);
|
ubyte[] responseBytes = msgpack.pack(response);
|
||||||
|
|
Loading…
Reference in New Issue