Fix issue with fully qualified symbols, improve allocation code, improve partial symbol completion
This commit is contained in:
parent
a8e90377d5
commit
e6610fd7bc
|
@ -48,7 +48,7 @@ import stupidlog;
|
|||
* Returns:
|
||||
* the autocompletion response
|
||||
*/
|
||||
AutocompleteResponse getDoc(const AutocompleteRequest request)
|
||||
public AutocompleteResponse getDoc(const AutocompleteRequest request)
|
||||
{
|
||||
// Log.trace("Getting doc comments");
|
||||
AutocompleteResponse response;
|
||||
|
@ -58,16 +58,8 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
|
|||
allocator, &cache);
|
||||
if (symbols.length == 0)
|
||||
Log.error("Could not find symbol");
|
||||
else foreach (symbol; symbols)
|
||||
{
|
||||
if (symbol.doc is null)
|
||||
{
|
||||
// Log.trace("Doc comment for ", symbol.name, " was null");
|
||||
continue;
|
||||
}
|
||||
// Log.trace("Adding doc comment for ", symbol.name, ": ", symbol.doc);
|
||||
else foreach (symbol; symbols.filter!(a => a.doc !is null))
|
||||
response.docComments ~= formatComment(symbol.doc);
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -78,9 +70,8 @@ AutocompleteResponse getDoc(const AutocompleteRequest request)
|
|||
* Returns:
|
||||
* the autocompletion response
|
||||
*/
|
||||
AutocompleteResponse findDeclaration(const AutocompleteRequest request)
|
||||
public AutocompleteResponse findDeclaration(const AutocompleteRequest request)
|
||||
{
|
||||
// Log.trace("Finding declaration");
|
||||
AutocompleteResponse response;
|
||||
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
|
||||
auto cache = StringCache(StringCache.defaultBucketCount);
|
||||
|
@ -90,11 +81,9 @@ AutocompleteResponse findDeclaration(const AutocompleteRequest request)
|
|||
{
|
||||
response.symbolLocation = symbols[0].location;
|
||||
response.symbolFilePath = symbols[0].symbolFile.idup;
|
||||
// Log.trace(symbols[0].name, " declared in ",
|
||||
// response.symbolFilePath, " at ", response.symbolLocation);
|
||||
}
|
||||
else
|
||||
Log.error("Could not find symbol");
|
||||
Log.error("Could not find symbol declaration");
|
||||
return response;
|
||||
}
|
||||
|
||||
|
@ -105,41 +94,70 @@ AutocompleteResponse findDeclaration(const AutocompleteRequest request)
|
|||
* Returns:
|
||||
* the autocompletion response
|
||||
*/
|
||||
AutocompleteResponse complete(const AutocompleteRequest request)
|
||||
public AutocompleteResponse complete(const AutocompleteRequest request)
|
||||
{
|
||||
// Log.info("Got a completion request");
|
||||
|
||||
const(Token)[] tokenArray;
|
||||
auto cache = StringCache(StringCache.defaultBucketCount);
|
||||
auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
|
||||
request.cursorPosition, &cache, tokenArray);
|
||||
string partial;
|
||||
IdType tokenType;
|
||||
|
||||
if (beforeTokens.length >= 2 && (beforeTokens[$ - 1] == tok!"("
|
||||
|| beforeTokens[$ - 1] == tok!"["))
|
||||
{
|
||||
return parenCompletion(beforeTokens, tokenArray, request.cursorPosition);
|
||||
}
|
||||
|
||||
if (beforeTokens.length >= 2 && isSelectiveImport(beforeTokens))
|
||||
else if (beforeTokens.length >= 2 && isSelectiveImport(beforeTokens))
|
||||
{
|
||||
return selectiveImportCompletion(beforeTokens);
|
||||
}
|
||||
else
|
||||
{
|
||||
return dotCompletion(beforeTokens, tokenArray, request.cursorPosition);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
private:
|
||||
|
||||
/**
|
||||
* Handles dot completion for identifiers and types.
|
||||
* Params:
|
||||
* beforeTokens = the tokens before the cursor
|
||||
* tokenArray = all tokens in the file
|
||||
* cursorPosition = the cursor position in bytes
|
||||
* Returns:
|
||||
* the autocompletion response
|
||||
*/
|
||||
AutocompleteResponse dotCompletion(T)(T beforeTokens,
|
||||
const(Token)[] tokenArray, size_t cursorPosition)
|
||||
{
|
||||
AutocompleteResponse response;
|
||||
|
||||
// Partial symbol name appearing after the dot character and before the
|
||||
// cursor.
|
||||
string partial;
|
||||
|
||||
// Type of the token before the dot, or identifier if the cursor was at
|
||||
// an identifier.
|
||||
IdType significantTokenType;
|
||||
|
||||
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
|
||||
{
|
||||
partial = beforeTokens[$ - 1].text;
|
||||
tokenType = beforeTokens[$ - 1].type;
|
||||
// Set partial to the slice of the identifier between the beginning
|
||||
// of the identifier and the cursor. This improves the completion
|
||||
// responses when the cursor is in the middle of an identifier instead
|
||||
// of at the end
|
||||
auto t = beforeTokens[$ - 1];
|
||||
partial = t.text[0 .. cursorPosition - t.index];
|
||||
|
||||
significantTokenType = tok!"identifier";
|
||||
beforeTokens = beforeTokens[0 .. $ - 1];
|
||||
}
|
||||
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!".")
|
||||
tokenType = beforeTokens[$ - 2].type;
|
||||
significantTokenType = beforeTokens[$ - 2].type;
|
||||
else
|
||||
return response;
|
||||
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
|
||||
switch (tokenType)
|
||||
|
||||
switch (significantTokenType)
|
||||
{
|
||||
case tok!"stringLiteral":
|
||||
case tok!"wstringLiteral":
|
||||
|
@ -178,12 +196,11 @@ AutocompleteResponse complete(const AutocompleteRequest request)
|
|||
case tok!")":
|
||||
case tok!"]":
|
||||
case tok!"this":
|
||||
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray,
|
||||
"stdin", allocator, semanticAllocator);
|
||||
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray, allocator);
|
||||
scope(exit) typeid(Scope).destroy(completionScope);
|
||||
response.setCompletions(completionScope, getExpression(beforeTokens),
|
||||
request.cursorPosition, CompletionType.identifiers, false, partial);
|
||||
cursorPosition, CompletionType.identifiers, false, partial);
|
||||
break;
|
||||
case tok!"(":
|
||||
case tok!"{":
|
||||
|
@ -208,7 +225,7 @@ auto getTokensBeforeCursor(const(ubyte[]) sourceCode, size_t cursorPosition,
|
|||
StringCache* cache, out const(Token)[] tokenArray)
|
||||
{
|
||||
LexerConfig config;
|
||||
config.fileName = "stdin";
|
||||
config.fileName = "";
|
||||
tokenArray = getTokensForParser(cast(ubyte[]) sourceCode, config, cache);
|
||||
auto sortedTokens = assumeSorted(tokenArray);
|
||||
return sortedTokens.lowerBound(cast(size_t) cursorPosition);
|
||||
|
@ -228,9 +245,7 @@ ACSymbol*[] getSymbolsForCompletion(const AutocompleteRequest request,
|
|||
const(Token)[] tokenArray;
|
||||
auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
|
||||
request.cursorPosition, cache, tokenArray);
|
||||
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray,
|
||||
"stdin", allocator, semanticAllocator);
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray, allocator);
|
||||
scope(exit) typeid(Scope).destroy(completionScope);
|
||||
auto expression = getExpression(beforeTokens);
|
||||
return getSymbolsByTokenChain(completionScope, expression,
|
||||
|
@ -251,7 +266,6 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
|
|||
{
|
||||
AutocompleteResponse response;
|
||||
immutable(string)[] completions;
|
||||
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
|
||||
switch (beforeTokens[$ - 2].type)
|
||||
{
|
||||
case tok!"__traits":
|
||||
|
@ -279,9 +293,8 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
|
|||
case tok!"identifier":
|
||||
case tok!")":
|
||||
case tok!"]":
|
||||
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray,
|
||||
"stdin", allocator, semanticAllocator);
|
||||
auto allocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 16)))();
|
||||
Scope* completionScope = generateAutocompleteTrees(tokenArray, allocator);
|
||||
scope(exit) typeid(Scope).destroy(completionScope);
|
||||
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
|
||||
response.setCompletions(completionScope, expression,
|
||||
|
@ -299,11 +312,11 @@ bool isSelectiveImport(T)(T tokens)
|
|||
size_t i = tokens.length - 1;
|
||||
if (!(tokens[i] == tok!":" || tokens[i] == tok!","))
|
||||
return false;
|
||||
bool r = false;
|
||||
bool foundColon = false;
|
||||
loop: while (true) switch (tokens[i].type)
|
||||
{
|
||||
case tok!":":
|
||||
r = true;
|
||||
foundColon = true;
|
||||
goto case;
|
||||
case tok!"identifier":
|
||||
case tok!"=":
|
||||
|
@ -315,7 +328,7 @@ bool isSelectiveImport(T)(T tokens)
|
|||
i--;
|
||||
break;
|
||||
case tok!"import":
|
||||
return r;
|
||||
return foundColon;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -392,28 +405,24 @@ body
|
|||
auto symbols = ModuleCache.getSymbolsInModule(ModuleCache.resolveImportLoctation(path));
|
||||
import containers.hashset;
|
||||
HashSet!string h;
|
||||
|
||||
void addSymbolToResponses(ACSymbol* sy)
|
||||
{
|
||||
auto a = ACSymbol(sy.name);
|
||||
if (!builtinSymbols.contains(&a) && sy.name !is null && !h.contains(sy.name))
|
||||
{
|
||||
response.completionKinds ~= sy.kind;
|
||||
response.completions ~= sy.name;
|
||||
h.insert(sy.name);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (s; symbols.parts[])
|
||||
{
|
||||
if (s.kind == CompletionKind.importSymbol) foreach (sy; s.type.parts[])
|
||||
{
|
||||
auto a = ACSymbol(sy.name);
|
||||
if (!builtinSymbols.contains(&a) && sy.name !is null && !h.contains(sy.name))
|
||||
{
|
||||
response.completionKinds ~= sy.kind;
|
||||
response.completions ~= sy.name;
|
||||
h.insert(sy.name);
|
||||
}
|
||||
}
|
||||
addSymbolToResponses(sy);
|
||||
else
|
||||
{
|
||||
auto a = ACSymbol(s.name);
|
||||
if (!builtinSymbols.contains(&a) && s.name !is null && !h.contains(s.name))
|
||||
{
|
||||
response.completionKinds ~= s.kind;
|
||||
response.completions ~= s.name;
|
||||
h.insert(s.name);
|
||||
}
|
||||
}
|
||||
addSymbolToResponses(s);
|
||||
}
|
||||
response.completionType = CompletionType.identifiers;
|
||||
return response;
|
||||
|
@ -426,8 +435,6 @@ ACSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
|
|||
T tokens, size_t cursorPosition, CompletionType completionType)
|
||||
{
|
||||
import std.d.lexer;
|
||||
// Log.trace("Getting symbols from token chain",
|
||||
// tokens.map!stringToken);
|
||||
// Find the symbol corresponding to the beginning of the chain
|
||||
ACSymbol*[] symbols;
|
||||
if (tokens.length == 0)
|
||||
|
@ -435,7 +442,6 @@ ACSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
|
|||
if (tokens[0] == tok!"." && tokens.length > 1)
|
||||
{
|
||||
tokens = tokens[1 .. $];
|
||||
// Log.trace("Looking for ", stringToken(tokens[0]), " at global scope");
|
||||
symbols = completionScope.getSymbolsAtGlobalScope(stringToken(tokens[0]));
|
||||
}
|
||||
else
|
||||
|
@ -447,11 +453,6 @@ ACSymbol*[] getSymbolsByTokenChain(T)(Scope* completionScope,
|
|||
" from position ", cursorPosition);
|
||||
return [];
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// Log.trace("Found ", symbols[0].name, " at ", symbols[0].location,
|
||||
// " with type ", symbols[0].type is null ? "null" : symbols[0].type.name);
|
||||
// }
|
||||
|
||||
if (shouldSwapWithType(completionType, symbols[0].kind, 0, tokens.length - 1))
|
||||
{
|
||||
|
|
|
@ -29,12 +29,13 @@ import std.d.lexer;
|
|||
import std.d.parser;
|
||||
import std.typecons;
|
||||
|
||||
Scope* generateAutocompleteTrees(const(Token)[] tokens, string symbolFile,
|
||||
CAllocator symbolAllocator, CAllocator semanticAllocator)
|
||||
/**
|
||||
* Used by autocompletion.
|
||||
*/
|
||||
Scope* generateAutocompleteTrees(const(Token)[] tokens, CAllocator symbolAllocator)
|
||||
{
|
||||
Module m = parseModule(tokens, "editor buffer", semanticAllocator, &doesNothing);
|
||||
auto first = scoped!FirstPass(m, symbolFile, symbolAllocator,
|
||||
semanticAllocator);
|
||||
Module m = parseModule(tokens, "stdin", symbolAllocator, &doesNothing);
|
||||
auto first = scoped!FirstPass(m, "stdin", symbolAllocator, symbolAllocator);
|
||||
first.run();
|
||||
|
||||
SecondPass second = SecondPass(first);
|
||||
|
@ -46,13 +47,22 @@ Scope* generateAutocompleteTrees(const(Token)[] tokens, string symbolFile,
|
|||
return third.moduleScope;
|
||||
}
|
||||
|
||||
Module parseModuleSimple(const(Token)[] tokens, string fileName, CAllocator p)
|
||||
/**
|
||||
* Used by import symbol caching.
|
||||
*
|
||||
* Params:
|
||||
* tokens = the tokens that compose the file
|
||||
* fileName = the name of the file being parsed
|
||||
* parseAllocator = the allocator to use for the AST
|
||||
* Returns: the parsed module
|
||||
*/
|
||||
Module parseModuleSimple(const(Token)[] tokens, string fileName, CAllocator parseAllocator)
|
||||
{
|
||||
auto parser = scoped!SimpleParser();
|
||||
parser.fileName = fileName;
|
||||
parser.tokens = tokens;
|
||||
parser.messageFunction = &doesNothing;
|
||||
parser.allocator = p;
|
||||
parser.allocator = parseAllocator;
|
||||
return parser.parseModule();
|
||||
}
|
||||
|
||||
|
|
|
@ -163,6 +163,7 @@ private:
|
|||
IMPORT_SYMBOL_NAME, CompletionKind.importSymbol, symbol));
|
||||
else
|
||||
currentScope.symbols.insert(symbol.parts[]);
|
||||
currentScope.symbols.insert(moduleSymbol);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue