Made autocompletion work when the cursor isn't at a dot or lparen

This commit is contained in:
Hackerpilot 2013-08-18 02:15:43 +00:00
parent 357c65f62b
commit 70cdbe4428
3 changed files with 71 additions and 16 deletions

View File

@ -159,6 +159,24 @@ public:
this.end = end; this.end = end;
} }
ACSymbol[] getSymbolsInCurrentScope(size_t cursorPosition)
{
Scope s = findCurrentScope(cursorPosition);
if (s is null)
return [];
else
return s.getSymbols();
}
ACSymbol[] getSymbols()
{
ACSymbol[] rVal;
rVal ~= symbols;
if (parent !is null)
rVal ~= parent.getSymbols();
return rVal;
}
/** /**
* Finds the scope containing the cursor position, then searches for a * Finds the scope containing the cursor position, then searches for a
* symbol with the given name. * symbol with the given name.
@ -169,7 +187,7 @@ public:
if (s is null) if (s is null)
{ {
writeln("Could not find scope"); writeln("Could not find scope");
return null; return [];
} }
else else
return s.findSymbolsInScope(name); return s.findSymbolsInScope(name);

View File

@ -48,9 +48,17 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
auto tokens = request.sourceCode.byToken(config); auto tokens = request.sourceCode.byToken(config);
auto tokenArray = tokens.array(); auto tokenArray = tokens.array();
auto sortedTokens = assumeSorted(tokenArray); auto sortedTokens = assumeSorted(tokenArray);
string partial;
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition); auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == TokenType.identifier)
{
//writeln("partial completion");
partial = beforeTokens[$ - 1].value;
beforeTokens = beforeTokens[0 .. $ - 1];
goto dotCompletion;
}
if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.lParen) if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.lParen)
{ {
immutable(string)[] completions; immutable(string)[] completions;
@ -92,6 +100,7 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
} }
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.dot) else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.dot)
{ {
dotCompletion:
switch (beforeTokens[$ - 2].type) switch (beforeTokens[$ - 2].type)
{ {
case TokenType.stringLiteral: case TokenType.stringLiteral:
@ -132,9 +141,10 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
case TokenType.rBracket: case TokenType.rBracket:
case TokenType.this_: case TokenType.this_:
auto visitor = processModule(tokenArray); auto visitor = processModule(tokenArray);
auto expression = getExpression(beforeTokens[0 .. $ - 1]); auto expression = getExpression(partial == null ? beforeTokens[0 .. $ - 1]
: beforeTokens);
response.setCompletions(visitor, expression, request.cursorPosition, response.setCompletions(visitor, expression, request.cursorPosition,
CompletionType.identifiers); CompletionType.identifiers, partial);
break; break;
case TokenType.lParen: case TokenType.lParen:
case TokenType.lBrace: case TokenType.lBrace:
@ -152,10 +162,10 @@ AutocompleteResponse complete(AutocompleteRequest request, string[] importPaths)
void setCompletions(T)(ref AutocompleteResponse response, void setCompletions(T)(ref AutocompleteResponse response,
AutocompleteVisitor visitor, T tokens, size_t cursorPosition, AutocompleteVisitor visitor, T tokens, size_t cursorPosition,
CompletionType completionType) CompletionType completionType, string partial = null)
{ {
// Autocomplete module imports instead of symbols // Autocomplete module imports instead of symbols
if (tokens[0].type == TokenType.import_) if (tokens.length > 0 && tokens[0].type == TokenType.import_)
{ {
if (completionType == CompletionType.identifiers) if (completionType == CompletionType.identifiers)
setImportCompletions(tokens, response); setImportCompletions(tokens, response);
@ -163,6 +173,26 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
visitor.scope_.resolveSymbolTypes(); visitor.scope_.resolveSymbolTypes();
// Handle the simple case where we get all symbols in scope and filter it
// based on the currently entered text.
if (partial !is null && tokens.length == 0)
{
// writeln("Showing all symbols in current scope that start with ", partial);
foreach (s; visitor.scope_.getSymbolsInCurrentScope(cursorPosition)
.filter!(a => a.name.startsWith(partial)))
{
response.completionKinds ~= s.kind;
response.completions ~= s.name;
}
response.completionType = CompletionType.identifiers;
return;
}
if (tokens.length == 0)
return;
// Find the symbol corresponding to the beginning of the chain
ACSymbol[] symbols = visitor.scope_.findSymbolsInCurrentScope(cursorPosition, tokens[0].value); ACSymbol[] symbols = visitor.scope_.findSymbolsInCurrentScope(cursorPosition, tokens[0].value);
if (symbols.length == 0) if (symbols.length == 0)
{ {
@ -179,7 +209,6 @@ void setCompletions(T)(ref AutocompleteResponse response,
symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType]; symbols = symbols[0].resolvedType is null ? [] : [symbols[0].resolvedType];
if (symbols.length == 0) if (symbols.length == 0)
{ {
//writeln("Could not figure it out");
return; return;
} }
} }
@ -233,11 +262,11 @@ void setCompletions(T)(ref AutocompleteResponse response,
break loop; break loop;
break; break;
case identifier: case identifier:
writeln("looking for ", tokens[i].value, " in ", symbols[0].name); // writeln("looking for ", tokens[i].value, " in ", symbols[0].name);
symbols = symbols[0].getPartsByName(tokens[i].value); symbols = symbols[0].getPartsByName(tokens[i].value);
if (symbols.length == 0) if (symbols.length == 0)
{ {
writeln("Couldn't find it."); // writeln("Couldn't find it.");
break loop; break loop;
} }
if (symbols[0].kind == CompletionKind.variableName if (symbols[0].kind == CompletionKind.variableName
@ -317,7 +346,9 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
if (completionType == CompletionType.identifiers) if (completionType == CompletionType.identifiers)
{ {
foreach (s; symbols[0].parts.filter!(a => a.name !is null && a.name[0] != '*')) foreach (s; symbols[0].parts.filter!(a => a.name !is null
&& a.name[0] != '*'
&& (partial is null ? true : a.name.startsWith(partial))))
{ {
// writeln("Adding ", s.name, " to the completion list"); // writeln("Adding ", s.name, " to the completion list");
response.completionKinds ~= s.kind; response.completionKinds ~= s.kind;

View File

@ -57,14 +57,18 @@ local function showCompletionList(r)
completions[#completions + 1] = completion completions[#completions + 1] = completion
end end
table.sort(completions, function(a, b) return string.upper(a) < string.upper(b) end) table.sort(completions, function(a, b) return string.upper(a) < string.upper(b) end)
buffer:auto_c_show(0, table.concat(completions, " ")) local charactersEntered = buffer.current_pos - buffer:word_start_position(buffer.current_pos)
if buffer.char_at[buffer.current_pos - 1] == string.byte('.') then charactersEntered = 0 end
print(charactersEntered)
buffer:auto_c_show(charactersEntered, table.concat(completions, " "))
--buffer.auto_c_fill_ups = "(.["
buffer.auto_c_choose_single = setting buffer.auto_c_choose_single = setting
end end
local function showCurrentCallTip() local function showCurrentCallTip()
local tip = calltips[currentCalltip] local tip = calltips[currentCalltip]
buffer:call_tip_show(buffer.current_pos, buffer:call_tip_show(buffer:word_start_position(buffer.current_pos),
string.format("overload %d of %d\1\2\n%s", currentCalltip, #calltips, string.format("overload %d of %d\1\2\n%s", currentCalltip, #calltips,
calltips[currentCalltip])) calltips[currentCalltip]))
end end
@ -109,11 +113,13 @@ function M.autocomplete(ch)
local character = string.char(ch) local character = string.char(ch)
if character == "." or character == "(" then if character == "." or character == "(" then
local fileName = os.tmpname() local fileName = os.tmpname()
local tmpFile = io.open(fileName, "w") local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " > " .. fileName
tmpFile:write(buffer:get_text()) local p = io.popen(command, "w")
local command = M.PATH_TO_DCD_CLIENT .. " -c" .. buffer.current_pos .. " " .. fileName p:write(buffer:get_text())
local p = io.popen(command, "r") p:flush()
local r = p:read("*a") p:close()
local tmpFile = io.open(fileName, "r")
local r = tmpFile:read("*a")
--print(r) --print(r)
if r ~= "\n" then if r ~= "\n" then
if r:match("^identifiers.*") then if r:match("^identifiers.*") then