Changes according to suggestions

This commit is contained in:
davu 2023-05-10 23:30:05 +02:00 committed by Jan Jurzitza
parent 4d3bc1142d
commit 9484c44b49
7 changed files with 129 additions and 56 deletions

View File

@ -28,6 +28,7 @@ import std.path;
import std.range : assumeSorted; import std.range : assumeSorted;
import std.string; import std.string;
import std.typecons; import std.typecons;
import std.exception : enforce;
import dcd.server.autocomplete.util; import dcd.server.autocomplete.util;
@ -47,7 +48,7 @@ import dsymbol.utils;
import dcd.common.constants; import dcd.common.constants;
import dcd.common.messages; import dcd.common.messages;
enum CallTipHint { enum CalltipHint {
none, // asserts false if passed into setCompletion with CompletionType.calltips none, // asserts false if passed into setCompletion with CompletionType.calltips
regularArguments, regularArguments,
templateArguments, templateArguments,
@ -135,34 +136,33 @@ public AutocompleteResponse complete(const AutocompleteRequest request,
} }
} }
if (beforeTokens.length >= 2) auto calltipHint = getCalltipHint(beforeTokens);
{
if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"[" final switch (calltipHint) with (CalltipHint) {
|| beforeTokens[$ - 1] == tok!",") case regularArguments:
{
immutable size_t end = goBackToOpenParen(beforeTokens); immutable size_t end = goBackToOpenParen(beforeTokens);
if (end != size_t.max) { if (end != size_t.max)
return callTipCompletion(beforeTokens[0 .. end], tokenArray, return calltipCompletion(beforeTokens[0 .. end], tokenArray,
request.cursorPosition, moduleCache); request.cursorPosition, moduleCache, calltipHint);
break;
case templateArguments, indexOperator:
return calltipCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache, calltipHint);
case none:
// could be import or dot completion
if (beforeTokens.length < 2){
break;
} }
}
else if (beforeTokens[$ - 1] == tok!"!"){ // Bang completion
return callTipCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache);
}
else
{
ImportKind kind = determineImportKind(beforeTokens); ImportKind kind = determineImportKind(beforeTokens);
if (kind == ImportKind.neither) if (kind == ImportKind.neither)
{ {
if (beforeTokens.isUdaExpression) if (beforeTokens.isUdaExpression)
beforeTokens = beforeTokens[$-1 .. $]; beforeTokens = beforeTokens[$ - 1 .. $];
return dotCompletion(beforeTokens, tokenArray, request.cursorPosition, return dotCompletion(beforeTokens, tokenArray, request.cursorPosition,
moduleCache); moduleCache);
} }
else
return importCompletion(beforeTokens, kind, moduleCache); return importCompletion(beforeTokens, kind, moduleCache);
} }
}
return dotCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache); return dotCompletion(beforeTokens, tokenArray, request.cursorPosition, moduleCache);
} }
@ -229,7 +229,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache); ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache);
scope(exit) pair.destroy(); scope(exit) pair.destroy();
response.setCompletions(pair.scope_, getExpression(beforeTokens), response.setCompletions(pair.scope_, getExpression(beforeTokens),
cursorPosition, CompletionType.identifiers, CompletionToken.none, partial); cursorPosition, CompletionType.identifiers, CalltipHint.none, partial);
if (!pair.ufcsSymbols.empty) { if (!pair.ufcsSymbols.empty) {
response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array; response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array;
// Setting CompletionType in case of none symbols are found via setCompletions, but we have UFCS symbols. // Setting CompletionType in case of none symbols are found via setCompletions, but we have UFCS symbols.
@ -248,7 +248,7 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, 1, moduleCache); ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, 1, moduleCache);
scope(exit) pair.destroy(); scope(exit) pair.destroy();
response.setCompletions(pair.scope_, getExpression(beforeTokens), response.setCompletions(pair.scope_, getExpression(beforeTokens),
1, CompletionType.identifiers, CompletionToken.none, partial); 1, CompletionType.identifiers, CalltipHint.none, partial);
break; break;
default: default:
break; break;
@ -265,12 +265,15 @@ AutocompleteResponse dotCompletion(T)(T beforeTokens, const(Token)[] tokenArray,
* Returns: * Returns:
* the autocompletion response * the autocompletion response
*/ */
AutocompleteResponse callTipCompletion(T)(T beforeTokens, deprecated("Use `calltipCompletion` instead") alias parenCompletion = calltipCompletion;
const(Token)[] tokenArray, size_t cursorPosition, ref ModuleCache moduleCache) AutocompleteResponse calltipCompletion(T)(T beforeTokens,
const(Token)[] tokenArray, size_t cursorPosition, ref ModuleCache moduleCache, CalltipHint calltipHint = CalltipHint.none)
{ {
AutocompleteResponse response; AutocompleteResponse response;
immutable(ConstantCompletion)[] completions; immutable(ConstantCompletion)[] completions;
switch (beforeTokens[$ - 2].type) auto significantTokenId = getSignificantTokenId(beforeTokens);
switch (significantTokenId)
{ {
case tok!"__traits": case tok!"__traits":
completions = traits; completions = traits;
@ -318,9 +321,11 @@ AutocompleteResponse callTipCompletion(T)(T beforeTokens,
RollbackAllocator rba; RollbackAllocator rba;
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache); ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, &rba, cursorPosition, moduleCache);
scope(exit) pair.destroy(); scope(exit) pair.destroy();
auto expression = getExpression(beforeTokens[0 .. $ - 1]); // We remove by 2 when the calltip hint is !( else remove by 1.
auto endOffset = beforeTokens.isBangParenCalltipHint ? 2 : 1;
auto expression = getExpression(beforeTokens[0 .. $ - endOffset]);
response.setCompletions(pair.scope_, expression, response.setCompletions(pair.scope_, expression,
cursorPosition, CompletionType.calltips, getCompletionToken(beforeTokens)); cursorPosition, CompletionType.calltips, calltipHint);
if (!pair.ufcsSymbols.empty) { if (!pair.ufcsSymbols.empty) {
response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array; response.completions ~= pair.ufcsSymbols.map!(s => makeSymbolCompletionInfo(s, CompletionKind.ufcsName)).array;
// Setting CompletionType in case of none symbols are found via setCompletions, but we have UFCS symbols. // Setting CompletionType in case of none symbols are found via setCompletions, but we have UFCS symbols.
@ -333,16 +338,54 @@ AutocompleteResponse callTipCompletion(T)(T beforeTokens,
return response; return response;
} }
CompletionToken getCompletionToken(T)(T beforeTokens) { IdType getSignificantTokenId(T)(T beforeTokens){
if(beforeTokens[$ - 1] == tok!"["){ auto significantTokenId = beforeTokens[$ - 2].type;
return CompletionToken.bracket; if (beforeTokens.isBangParenCalltipHint) {
if(beforeTokens[$ - 3] == tok!"identifier"){
return beforeTokens[$ - 3].type;
}
}
return significantTokenId;
}
/**
* Hinting what the user expects for calltip completion
* Params:
* beforeTokens = tokens before the cursor
* Returns: calltipHint based of beforeTokens
*/
CalltipHint getCalltipHint(T)(T beforeTokens) {
if (beforeTokens.length < 2){
return CalltipHint.none;
}
if (beforeTokens[$ - 1] == tok!"(" || beforeTokens[$ - 1] == tok!"["
|| beforeTokens[$ - 1] == tok!",")
{
return CalltipHint.regularArguments;
}
if(beforeTokens[$ - 2] == tok!"identifier" && beforeTokens[$ - 1] == tok!"["){
return CalltipHint.indexOperator;
} }
if(beforeTokens[$ - 1] == tok!"!"){ if(beforeTokens.isSingleBangCalltipHint || beforeTokens.isBangParenCalltipHint){
return CompletionToken.bang; return CalltipHint.templateArguments;
} }
return CompletionToken.none; return CalltipHint.none;
}
// Check if we are doing a single "!" calltip hint
private bool isSingleBangCalltipHint(T)(T beforeTokens) {
return beforeTokens.length >= 2
&& beforeTokens[$ - 2] == tok!"identifier"
&& beforeTokens[$ - 1] == tok!"!";
}
// Check if we are doing a "!(" calltip hint
private bool isBangParenCalltipHint(T)(T beforeTokens){
return beforeTokens.length >= 3
&& beforeTokens[$ - 3] == tok!"identifier"
&& beforeTokens[$ - 2] == tok!"!"
&& beforeTokens[$ - 1] == tok!"(";
} }
/** /**
@ -528,7 +571,7 @@ void setImportCompletions(T)(T tokens, ref AutocompleteResponse response,
*/ */
void setCompletions(T)(ref AutocompleteResponse response, void setCompletions(T)(ref AutocompleteResponse response,
Scope* completionScope, T tokens, size_t cursorPosition, Scope* completionScope, T tokens, size_t cursorPosition,
CompletionType completionType, CompletionToken completionToken = CompletionToken.none, string partial = null) CompletionType completionType, CalltipHint callTipHint = CalltipHint.none, string partial = null)
{ {
static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r, string p, static void addSymToResponse(const(DSymbol)* s, ref AutocompleteResponse r, string p,
Scope* completionScope, size_t[] circularGuard = []) Scope* completionScope, size_t[] circularGuard = [])
@ -590,8 +633,8 @@ void setCompletions(T)(ref AutocompleteResponse response,
DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens, DSymbol*[] symbols = getSymbolsByTokenChain(completionScope, tokens,
cursorPosition, completionType); cursorPosition, completionType);
// If bang completion we check if symbol is also templated // If calltipHint is templateArguments we ensure that the symbol is also templated
if (completionToken == CompletionToken.bang && symbols.length >= 1 && symbols[0].qualifier != SymbolQualifier.templated){ if (callTipHint == CalltipHint.templateArguments && symbols.length >= 1 && symbols[0].qualifier != SymbolQualifier.templated){
return; return;
} }
@ -615,6 +658,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
else if (completionType == CompletionType.calltips) else if (completionType == CompletionType.calltips)
{ {
enforce(callTipHint != CalltipHint.none, "Make sure to have a properly defined calltipHint!");
//trace("Showing call tips for ", symbols[0].name, " of kind ", symbols[0].kind); //trace("Showing call tips for ", symbols[0].name, " of kind ", symbols[0].kind);
if (symbols[0].kind != CompletionKind.functionName if (symbols[0].kind != CompletionKind.functionName
&& symbols[0].callTip is null) && symbols[0].callTip is null)
@ -635,7 +679,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
symbols = [dumb]; symbols = [dumb];
goto setCallTips; goto setCallTips;
} }
if (completionToken == CompletionToken.bracket) if (callTipHint == CalltipHint.indexOperator)
{ {
auto index = dumb.getPartsByName(internString("opIndex")); auto index = dumb.getPartsByName(internString("opIndex"));
if (index.length > 0) if (index.length > 0)
@ -652,9 +696,15 @@ void setCompletions(T)(ref AutocompleteResponse response,
} }
} }
} }
if (symbols[0].kind == CompletionKind.structName if ((symbols[0].kind == CompletionKind.structName || symbols[0].kind == CompletionKind.className))
|| symbols[0].kind == CompletionKind.className)
{ {
if (callTipHint == CalltipHint.templateArguments) {
response.completionType = CompletionType.calltips;
response.completions = [generateStructConstructorCalltip(symbols[0], callTipHint)];
return;
}
//Else we do calltip for regular arguments
auto constructor = symbols[0].getPartsByName(CONSTRUCTOR_SYMBOL_NAME); auto constructor = symbols[0].getPartsByName(CONSTRUCTOR_SYMBOL_NAME);
if (constructor.length == 0) if (constructor.length == 0)
{ {
@ -662,7 +712,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
if (symbols[0].kind == CompletionKind.structName) if (symbols[0].kind == CompletionKind.structName)
{ {
response.completionType = CompletionType.calltips; response.completionType = CompletionType.calltips;
response.completions = [generateStructConstructorCalltip(symbols[0])]; response.completions = [generateStructConstructorCalltip(symbols[0], callTipHint)];
return; return;
} }
} }
@ -672,6 +722,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
goto setCallTips; goto setCallTips;
} }
} }
} }
setCallTips: setCallTips:
response.completionType = CompletionType.calltips; response.completionType = CompletionType.calltips;
@ -702,23 +753,27 @@ bool mightBeRelevantInCompletionScope(const DSymbol* symbol, Scope* scope_)
} }
AutocompleteResponse.Completion generateStructConstructorCalltip(const DSymbol* symbol) AutocompleteResponse.Completion generateStructConstructorCalltip(const DSymbol* symbol, CalltipHint calltipHint = CalltipHint.regularArguments)
in in
{ {
if (calltipHint == CalltipHint.regularArguments)
{
assert(symbol.kind == CompletionKind.structName); assert(symbol.kind == CompletionKind.structName);
}
} }
do do
{ {
string generatedStructConstructorCalltip = "this("; string generatedStructConstructorCalltip = calltipHint == CalltipHint.regularArguments ? "this(" : symbol.name ~ "(";
const(DSymbol)*[] fields = symbol.opSlice().filter!( auto completionKindFilter = calltipHint == CalltipHint.regularArguments ? CompletionKind.variableName : CompletionKind.typeTmpParam;
a => a.kind == CompletionKind.variableName).map!(a => cast(const(DSymbol)*) a).array(); const(DSymbol)*[] fields =
symbol.opSlice().filter!(a => a.kind == completionKindFilter).map!(a => cast(const(DSymbol)*) a).array();
fields.sort!((a, b) => a.location < b.location); fields.sort!((a, b) => a.location < b.location);
foreach (i, field; fields) foreach (i, field; fields)
{ {
if (field.kind != CompletionKind.variableName) if (field.kind != completionKindFilter)
continue; continue;
i++; i++;
if (field.type !is null) if (field.type !is null && calltipHint == CalltipHint.regularArguments)
{ {
generatedStructConstructorCalltip ~= field.type.name; generatedStructConstructorCalltip ~= field.type.name;
generatedStructConstructorCalltip ~= " "; generatedStructConstructorCalltip ~= " ";
@ -729,7 +784,7 @@ do
} }
generatedStructConstructorCalltip ~= ")"; generatedStructConstructorCalltip ~= ")";
auto completion = makeSymbolCompletionInfo(symbol, char.init); auto completion = makeSymbolCompletionInfo(symbol, char.init);
completion.identifier = "this"; completion.identifier = calltipHint == CalltipHint.regularArguments ? "this" : symbol.name;
completion.definition = generatedStructConstructorCalltip; completion.definition = generatedStructConstructorCalltip;
completion.typeOf = symbol.name; completion.typeOf = symbol.name;
return completion; return completion;

View File

@ -1,2 +1,2 @@
calltips calltips
this(T data) Wrapper(T)

View File

@ -1,2 +1,2 @@
calltips calltips
this(T foo, X bar) Something(T, X)

View File

@ -0,0 +1,2 @@
calltips
void doSomething(T)(T someElement)

View File

@ -0,0 +1,2 @@
calltips
void doSomething(T)(T someElement)

View File

@ -21,3 +21,11 @@ void instantiateTemp2() {
void instantiateTemp3() { void instantiateTemp3() {
doSomething! doSomething!
} }
void instantiateTemp4() {
doSomething!(
}
void instantiateTemp5() {
doSomething!("something",
}

View File

@ -9,3 +9,9 @@ diff actual2.txt expected2.txt --strip-trailing-cr
../../bin/dcd-client $1 file.d -c239 > actual3.txt ../../bin/dcd-client $1 file.d -c239 > actual3.txt
diff actual3.txt expected3.txt --strip-trailing-cr diff actual3.txt expected3.txt --strip-trailing-cr
../../bin/dcd-client $1 file.d -c283 > actual4.txt
diff actual4.txt expected4.txt --strip-trailing-cr
../../bin/dcd-client $1 file.d -c339 > actual5.txt
diff actual5.txt expected5.txt --strip-trailing-cr