Doc updates

This commit is contained in:
Hackerpilot 2014-01-14 01:50:50 +00:00
parent 48bd1bf9d5
commit 3de79c81da
2 changed files with 149 additions and 141 deletions

View File

@ -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```

View File

@ -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);