Doc updates
This commit is contained in:
parent
48bd1bf9d5
commit
3de79c81da
18
README.md
18
README.md
|
@ -20,6 +20,7 @@ back to the client.
|
||||||
* Public imports
|
* Public imports
|
||||||
* Finding the declaration location of a symbol at the cursor
|
* Finding the declaration location of a symbol at the cursor
|
||||||
* *import* statement completions
|
* *import* statement completions
|
||||||
|
* Display of documentation comments in function call tips
|
||||||
* Not working:
|
* Not working:
|
||||||
* Automatic starting of the server by the client
|
* Automatic starting of the server by the client
|
||||||
* UFCS
|
* UFCS
|
||||||
|
@ -30,8 +31,8 @@ back to the client.
|
||||||
* That one feature that you *REALLY* needed
|
* That one feature that you *REALLY* needed
|
||||||
|
|
||||||
#Setup
|
#Setup
|
||||||
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack library and the parser from DScanner.
|
1. Run ```git submodule update --init``` after cloning this repository to grab the MessagePack and Datapacked libraries and the parser from DScanner.
|
||||||
1. run the ```build.sh``` script to build the client and server.
|
1. run the ```build.sh``` script to build the client and server. (Or build.bat on Windows)
|
||||||
1. Configure your text editor to call the dcd-client program. See the *editors* folder for directions on configuring your specific editor.
|
1. Configure your text editor to call the dcd-client program. See the *editors* folder for directions on configuring your specific editor.
|
||||||
1. Start the dcd-server program before editing code.
|
1. Start the dcd-server program before editing code.
|
||||||
|
|
||||||
|
@ -87,15 +88,22 @@ tab character, followed by a completion kind
|
||||||
calltip v
|
calltip v
|
||||||
getPartByName f
|
getPartByName f
|
||||||
|
|
||||||
####Parenthesis completion
|
####Note
|
||||||
|
DCD's output will start with "identifiers" when completing at a left paren
|
||||||
|
character if the keywords *pragma*, *scope*, *__traits*, *extern*, or *version*
|
||||||
|
were just before the paren.
|
||||||
|
|
||||||
|
###Parenthesis completion
|
||||||
When the first line of output is "calltips", the editor should display a function
|
When the first line of output is "calltips", the editor should display a function
|
||||||
call tip.
|
call tip.
|
||||||
#####Output format
|
#####Output format
|
||||||
A line containing the string "calltips", followed by zero or more lines, each
|
A line containing the string "calltips", followed by zero or more lines, each
|
||||||
containing a call tip for an overload of the given function.
|
containing a call tip for an overload of the given function as well as its
|
||||||
|
DDoc comment, if available. Be sure to escape the \n sequences to newlines
|
||||||
|
when implementing an editor plugin.
|
||||||
#####Example output
|
#####Example output
|
||||||
calltips
|
calltips
|
||||||
ACSymbol findSymbolInCurrentScope(size_t cursorPosition, string name)
|
Some DDoc comment\nspread over two lines\n\nACSymbol findSymbolInCurrentScope(size_t cursorPosition, string name)
|
||||||
|
|
||||||
##Clear server's autocomplete cache
|
##Clear server's autocomplete cache
|
||||||
```dcd-client --clearCache```
|
```dcd-client --clearCache```
|
||||||
|
|
272
autocomplete.d
272
autocomplete.d
|
@ -71,7 +71,7 @@ AutocompleteResponse findDeclaration(const AutocompleteRequest request)
|
||||||
{
|
{
|
||||||
response.symbolLocation = symbols[0].location;
|
response.symbolLocation = symbols[0].location;
|
||||||
response.symbolFilePath = symbols[0].symbolFile;
|
response.symbolFilePath = symbols[0].symbolFile;
|
||||||
Log.info(beforeTokens[$ - 1].value, " declared in ",
|
Log.info(beforeTokens[$ - 1].text, " declared in ",
|
||||||
response.symbolFilePath, " at ", response.symbolLocation);
|
response.symbolFilePath, " at ", response.symbolLocation);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -88,10 +88,10 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
Log.trace("Getting symbols from token chain", tokens);
|
Log.trace("Getting symbols from token chain", tokens);
|
||||||
// Find the symbol corresponding to the beginning of the chain
|
// Find the symbol corresponding to the beginning of the chain
|
||||||
const(ACSymbol)*[] symbols = completionScope.getSymbolsByNameAndCursor(
|
const(ACSymbol)*[] symbols = completionScope.getSymbolsByNameAndCursor(
|
||||||
tokens[0].value, cursorPosition);
|
tokens[0].text, cursorPosition);
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
{
|
{
|
||||||
Log.error("Could not find declaration of ", tokens[0].value,
|
Log.error("Could not find declaration of ", tokens[0].text,
|
||||||
" from position ", cursorPosition);
|
" from position ", cursorPosition);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -114,8 +114,8 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
|
|
||||||
loop: for (size_t i = 1; i < tokens.length; i++)
|
loop: for (size_t i = 1; i < tokens.length; i++)
|
||||||
{
|
{
|
||||||
TokenType open;
|
IdType open;
|
||||||
TokenType close;
|
IdType close;
|
||||||
void skip()
|
void skip()
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
|
@ -130,37 +130,37 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
with (TokenType) switch (tokens[i].type)
|
switch (tokens[i].type)
|
||||||
{
|
{
|
||||||
case int_:
|
case tok!"int":
|
||||||
case uint_:
|
case tok!"uint":
|
||||||
case long_:
|
case tok!"long":
|
||||||
case ulong_:
|
case tok!"ulong":
|
||||||
case char_:
|
case tok!"char":
|
||||||
case wchar_:
|
case tok!"wchar":
|
||||||
case dchar_:
|
case tok!"dchar":
|
||||||
case bool_:
|
case tok!"bool":
|
||||||
case byte_:
|
case tok!"byte":
|
||||||
case ubyte_:
|
case tok!"ubyte":
|
||||||
case short_:
|
case tok!"short":
|
||||||
case ushort_:
|
case tok!"ushort":
|
||||||
case cent_:
|
case tok!"cent":
|
||||||
case ucent_:
|
case tok!"ucent":
|
||||||
case float_:
|
case tok!"float":
|
||||||
case ifloat_:
|
case tok!"ifloat":
|
||||||
case cfloat_:
|
case tok!"cfloat":
|
||||||
case idouble_:
|
case tok!"idouble":
|
||||||
case cdouble_:
|
case tok!"cdouble":
|
||||||
case double_:
|
case tok!"double":
|
||||||
case real_:
|
case tok!"real":
|
||||||
case ireal_:
|
case tok!"ireal":
|
||||||
case creal_:
|
case tok!"creal":
|
||||||
case this_:
|
case tok!"this":
|
||||||
symbols = symbols[0].getPartsByName(getTokenValue(tokens[i].type));
|
symbols = symbols[0].getPartsByName(str(tokens[i].type));
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
break loop;
|
break loop;
|
||||||
break;
|
break;
|
||||||
case identifier:
|
case tok!"identifier":
|
||||||
// Use function return type instead of the function itself
|
// Use function return type instead of the function itself
|
||||||
if (symbols[0].qualifier == SymbolQualifier.func
|
if (symbols[0].qualifier == SymbolQualifier.func
|
||||||
|| symbols[0].kind == CompletionKind.functionName)
|
|| symbols[0].kind == CompletionKind.functionName)
|
||||||
|
@ -170,8 +170,8 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
break loop;
|
break loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.trace("looking for ", tokens[i].value, " in ", symbols[0].name);
|
Log.trace("looking for ", tokens[i].text, " in ", symbols[0].name);
|
||||||
symbols = symbols[0].getPartsByName(tokens[i].value);
|
symbols = symbols[0].getPartsByName(tokens[i].text);
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
{
|
{
|
||||||
Log.trace("Couldn't find it.");
|
Log.trace("Couldn't find it.");
|
||||||
|
@ -197,14 +197,14 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
if (symbols.length == 0)
|
if (symbols.length == 0)
|
||||||
break loop;
|
break loop;
|
||||||
break;
|
break;
|
||||||
case lParen:
|
case tok!"(":
|
||||||
open = TokenType.lParen;
|
open = tok!"(";
|
||||||
close = TokenType.rParen;
|
close = tok!")";
|
||||||
skip();
|
skip();
|
||||||
break;
|
break;
|
||||||
case lBracket:
|
case tok!"[":
|
||||||
open = TokenType.lBracket;
|
open = tok!"[";
|
||||||
close = TokenType.rBracket;
|
close = tok!"]";
|
||||||
if (symbols[0].qualifier == SymbolQualifier.array)
|
if (symbols[0].qualifier == SymbolQualifier.array)
|
||||||
{
|
{
|
||||||
auto h = i;
|
auto h = i;
|
||||||
|
@ -240,7 +240,7 @@ const(ACSymbol)*[] getSymbolsByTokenChain(T)(const(Scope)* completionScope,
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case dot:
|
case tok!".":
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break loop;
|
break loop;
|
||||||
|
@ -269,33 +269,33 @@ AutocompleteResponse complete(const AutocompleteRequest request)
|
||||||
|
|
||||||
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
|
auto beforeTokens = sortedTokens.lowerBound(cast(size_t) request.cursorPosition);
|
||||||
|
|
||||||
TokenType tokenType;
|
IdType tokenType;
|
||||||
|
|
||||||
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == TokenType.identifier)
|
if (beforeTokens.length >= 1 && beforeTokens[$ - 1] == tok!"identifier")
|
||||||
{
|
{
|
||||||
partial = beforeTokens[$ - 1].value;
|
partial = beforeTokens[$ - 1].text;
|
||||||
tokenType = beforeTokens[$ - 1].type;
|
tokenType = beforeTokens[$ - 1].type;
|
||||||
beforeTokens = beforeTokens[0 .. $ - 1];
|
beforeTokens = beforeTokens[0 .. $ - 1];
|
||||||
goto dotCompletion;
|
goto dotCompletion;
|
||||||
}
|
}
|
||||||
if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.lParen)
|
if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!"(")
|
||||||
{
|
{
|
||||||
immutable(string)[] completions;
|
immutable(string)[] completions;
|
||||||
switch (beforeTokens[$ - 2].type)
|
switch (beforeTokens[$ - 2].type)
|
||||||
{
|
{
|
||||||
case TokenType.traits:
|
case tok!"__traits":
|
||||||
completions = traits;
|
completions = traits;
|
||||||
goto fillResponse;
|
goto fillResponse;
|
||||||
case TokenType.scope_:
|
case tok!"scope":
|
||||||
completions = scopes;
|
completions = scopes;
|
||||||
goto fillResponse;
|
goto fillResponse;
|
||||||
case TokenType.version_:
|
case tok!"version":
|
||||||
completions = versions;
|
completions = versions;
|
||||||
goto fillResponse;
|
goto fillResponse;
|
||||||
case TokenType.extern_:
|
case tok!"extern":
|
||||||
completions = linkages;
|
completions = linkages;
|
||||||
goto fillResponse;
|
goto fillResponse;
|
||||||
case TokenType.pragma_:
|
case tok!"pragma":
|
||||||
completions = pragmas;
|
completions = pragmas;
|
||||||
fillResponse:
|
fillResponse:
|
||||||
response.completionType = CompletionType.identifiers;
|
response.completionType = CompletionType.identifiers;
|
||||||
|
@ -305,9 +305,9 @@ AutocompleteResponse complete(const AutocompleteRequest request)
|
||||||
response.completionKinds ~= CompletionKind.keyword;
|
response.completionKinds ~= CompletionKind.keyword;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case TokenType.identifier:
|
case tok!"identifier":
|
||||||
case TokenType.rParen:
|
case tok!")":
|
||||||
case TokenType.rBracket:
|
case tok!"]":
|
||||||
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
|
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
|
||||||
"stdin");
|
"stdin");
|
||||||
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
|
auto expression = getExpression(beforeTokens[0 .. $ - 1]);
|
||||||
|
@ -318,15 +318,15 @@ AutocompleteResponse complete(const AutocompleteRequest request)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == TokenType.dot)
|
else if (beforeTokens.length >= 2 && beforeTokens[$ - 1] == tok!".")
|
||||||
{
|
{
|
||||||
tokenType = beforeTokens[$ - 2].type;
|
tokenType = beforeTokens[$ - 2].type;
|
||||||
dotCompletion:
|
dotCompletion:
|
||||||
switch (tokenType)
|
switch (tokenType)
|
||||||
{
|
{
|
||||||
case TokenType.stringLiteral:
|
case tok!"stringLiteral":
|
||||||
case TokenType.wstringLiteral:
|
case tok!"wstringLiteral":
|
||||||
case TokenType.dstringLiteral:
|
case tok!"dstringLiteral":
|
||||||
foreach (symbol; arraySymbols)
|
foreach (symbol; arraySymbols)
|
||||||
{
|
{
|
||||||
response.completionKinds ~= symbol.kind;
|
response.completionKinds ~= symbol.kind;
|
||||||
|
@ -334,44 +334,44 @@ dotCompletion:
|
||||||
}
|
}
|
||||||
response.completionType = CompletionType.identifiers;
|
response.completionType = CompletionType.identifiers;
|
||||||
break;
|
break;
|
||||||
case TokenType.int_:
|
case tok!"int":
|
||||||
case TokenType.uint_:
|
case tok!"uint":
|
||||||
case TokenType.long_:
|
case tok!"long":
|
||||||
case TokenType.ulong_:
|
case tok!"ulong":
|
||||||
case TokenType.char_:
|
case tok!"char":
|
||||||
case TokenType.wchar_:
|
case tok!"wchar":
|
||||||
case TokenType.dchar_:
|
case tok!"dchar":
|
||||||
case TokenType.bool_:
|
case tok!"bool":
|
||||||
case TokenType.byte_:
|
case tok!"byte":
|
||||||
case TokenType.ubyte_:
|
case tok!"ubyte":
|
||||||
case TokenType.short_:
|
case tok!"short":
|
||||||
case TokenType.ushort_:
|
case tok!"ushort":
|
||||||
case TokenType.cent_:
|
case tok!"cent":
|
||||||
case TokenType.ucent_:
|
case tok!"ucent":
|
||||||
case TokenType.float_:
|
case tok!"float":
|
||||||
case TokenType.ifloat_:
|
case tok!"ifloat":
|
||||||
case TokenType.cfloat_:
|
case tok!"cfloat":
|
||||||
case TokenType.idouble_:
|
case tok!"idouble":
|
||||||
case TokenType.cdouble_:
|
case tok!"cdouble":
|
||||||
case TokenType.double_:
|
case tok!"double":
|
||||||
case TokenType.real_:
|
case tok!"real":
|
||||||
case TokenType.ireal_:
|
case tok!"ireal":
|
||||||
case TokenType.creal_:
|
case tok!"creal":
|
||||||
case TokenType.identifier:
|
case tok!"identifier":
|
||||||
case TokenType.rParen:
|
case tok!")":
|
||||||
case TokenType.rBracket:
|
case tok!"]":
|
||||||
case TokenType.this_:
|
case tok!"this":
|
||||||
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
|
const(Scope)* completionScope = generateAutocompleteTrees(tokenArray,
|
||||||
"stdin");
|
"stdin");
|
||||||
auto expression = getExpression(beforeTokens);
|
auto expression = getExpression(beforeTokens);
|
||||||
response.setCompletions(completionScope, expression,
|
response.setCompletions(completionScope, expression,
|
||||||
request.cursorPosition, CompletionType.identifiers, partial);
|
request.cursorPosition, CompletionType.identifiers, partial);
|
||||||
break;
|
break;
|
||||||
case TokenType.lParen:
|
case tok!"(":
|
||||||
case TokenType.lBrace:
|
case tok!"{":
|
||||||
case TokenType.lBracket:
|
case tok!"[":
|
||||||
case TokenType.semicolon:
|
case tok!";":
|
||||||
case TokenType.colon:
|
case tok!":":
|
||||||
// TODO: global scope
|
// TODO: global scope
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -386,7 +386,7 @@ void setCompletions(T)(ref AutocompleteResponse response,
|
||||||
CompletionType completionType, string partial = null)
|
CompletionType completionType, string partial = null)
|
||||||
{
|
{
|
||||||
// Autocomplete module imports instead of symbols
|
// Autocomplete module imports instead of symbols
|
||||||
if (tokens.length > 0 && tokens[0].type == TokenType.import_)
|
if (tokens.length > 0 && tokens[0].type == tok!"import")
|
||||||
{
|
{
|
||||||
if (completionType == CompletionType.identifiers)
|
if (completionType == CompletionType.identifiers)
|
||||||
setImportCompletions(tokens, response);
|
setImportCompletions(tokens, response);
|
||||||
|
@ -475,59 +475,59 @@ T getExpression(T)(T beforeTokens)
|
||||||
if (beforeTokens.length == 0)
|
if (beforeTokens.length == 0)
|
||||||
return beforeTokens[0 .. 0];
|
return beforeTokens[0 .. 0];
|
||||||
size_t i = beforeTokens.length - 1;
|
size_t i = beforeTokens.length - 1;
|
||||||
TokenType open;
|
IdType open;
|
||||||
TokenType close;
|
IdType close;
|
||||||
bool hasSpecialPrefix = false;
|
bool hasSpecialPrefix = false;
|
||||||
expressionLoop: while (true)
|
expressionLoop: while (true)
|
||||||
{
|
{
|
||||||
with (TokenType) switch (beforeTokens[i].type)
|
switch (beforeTokens[i].type)
|
||||||
{
|
{
|
||||||
case TokenType.import_:
|
case tok!"import":
|
||||||
break expressionLoop;
|
break expressionLoop;
|
||||||
case TokenType.int_:
|
case tok!"int":
|
||||||
case TokenType.uint_:
|
case tok!"uint":
|
||||||
case TokenType.long_:
|
case tok!"long":
|
||||||
case TokenType.ulong_:
|
case tok!"ulong":
|
||||||
case TokenType.char_:
|
case tok!"char":
|
||||||
case TokenType.wchar_:
|
case tok!"wchar":
|
||||||
case TokenType.dchar_:
|
case tok!"dchar":
|
||||||
case TokenType.bool_:
|
case tok!"bool":
|
||||||
case TokenType.byte_:
|
case tok!"byte":
|
||||||
case TokenType.ubyte_:
|
case tok!"ubyte":
|
||||||
case TokenType.short_:
|
case tok!"short":
|
||||||
case TokenType.ushort_:
|
case tok!"ushort":
|
||||||
case TokenType.cent_:
|
case tok!"cent":
|
||||||
case TokenType.ucent_:
|
case tok!"ucent":
|
||||||
case TokenType.float_:
|
case tok!"float":
|
||||||
case TokenType.ifloat_:
|
case tok!"ifloat":
|
||||||
case TokenType.cfloat_:
|
case tok!"cfloat":
|
||||||
case TokenType.idouble_:
|
case tok!"idouble":
|
||||||
case TokenType.cdouble_:
|
case tok!"cdouble":
|
||||||
case TokenType.double_:
|
case tok!"double":
|
||||||
case TokenType.real_:
|
case tok!"real":
|
||||||
case TokenType.ireal_:
|
case tok!"ireal":
|
||||||
case TokenType.creal_:
|
case tok!"creal":
|
||||||
case this_:
|
case tok!"this":
|
||||||
case identifier:
|
case tok!"identifier":
|
||||||
if (hasSpecialPrefix)
|
if (hasSpecialPrefix)
|
||||||
{
|
{
|
||||||
i++;
|
i++;
|
||||||
break expressionLoop;
|
break expressionLoop;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case dot:
|
case tok!".":
|
||||||
break;
|
break;
|
||||||
case star:
|
case tok!"*":
|
||||||
case amp:
|
case tok!"&":
|
||||||
hasSpecialPrefix = true;
|
hasSpecialPrefix = true;
|
||||||
break;
|
break;
|
||||||
case rParen:
|
case tok!")":
|
||||||
open = rParen;
|
open = tok!")";
|
||||||
close = lParen;
|
close = tok!"(";
|
||||||
goto skip;
|
goto skip;
|
||||||
case rBracket:
|
case tok!"]":
|
||||||
open = rBracket;
|
open = tok!"]";
|
||||||
close = lBracket;
|
close = tok!"[";
|
||||||
skip:
|
skip:
|
||||||
auto bookmark = i;
|
auto bookmark = i;
|
||||||
int depth = 1;
|
int depth = 1;
|
||||||
|
@ -546,13 +546,13 @@ T getExpression(T)(T beforeTokens)
|
||||||
// if it's a loop keyword, pretend we never skipped the parens.
|
// if it's a loop keyword, pretend we never skipped the parens.
|
||||||
if (i > 0) switch (beforeTokens[i - 1].type)
|
if (i > 0) switch (beforeTokens[i - 1].type)
|
||||||
{
|
{
|
||||||
case TokenType.scope_:
|
case tok!"scope":
|
||||||
case TokenType.if_:
|
case tok!"if":
|
||||||
case TokenType.while_:
|
case tok!"while":
|
||||||
case TokenType.for_:
|
case tok!"for":
|
||||||
case TokenType.foreach_:
|
case tok!"foreach":
|
||||||
case TokenType.foreach_reverse_:
|
case tok!"foreach_reverse":
|
||||||
case TokenType.do_:
|
case tok!"do":
|
||||||
i = bookmark + 1;
|
i = bookmark + 1;
|
||||||
break expressionLoop;
|
break expressionLoop;
|
||||||
default:
|
default:
|
||||||
|
@ -576,7 +576,7 @@ T getExpression(T)(T beforeTokens)
|
||||||
void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
|
void setImportCompletions(T)(T tokens, ref AutocompleteResponse response)
|
||||||
{
|
{
|
||||||
response.completionType = CompletionType.identifiers;
|
response.completionType = CompletionType.identifiers;
|
||||||
auto moduleParts = tokens.filter!(a => a.type == TokenType.identifier).map!("a.value").array();
|
auto moduleParts = tokens.filter!(a => a.type == tok!"identifier").map!("a.text").array();
|
||||||
if (moduleParts.length == 0)
|
if (moduleParts.length == 0)
|
||||||
return;
|
return;
|
||||||
string path = buildPath(moduleParts);
|
string path = buildPath(moduleParts);
|
||||||
|
|
Loading…
Reference in New Issue