Skip to content

Commit

Permalink
Add a new request to get inlay hints (#764)
Browse files Browse the repository at this point in the history
Co-authored-by: ryuukk <[email protected]>
  • Loading branch information
WebFreak001 and ryuukk authored Dec 4, 2023
1 parent 6d63592 commit b79982d
Show file tree
Hide file tree
Showing 9 changed files with 179 additions and 2 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,19 @@ Otherwise the client outputs _00000_ so that the length of the answer is guarant
45
133

## Inlay Hints

Build a list of extra annoations for your IDE to display.
You must submit the content of the current file displayed in your editor.

dcd-client --inlayHints

This is a W.I.P., currently it only provide annoatations about aliases for your variables,
more is planned.

#### Example output

l ->MyAlias->MyType 42

# Server

Expand Down
4 changes: 3 additions & 1 deletion common/src/dcd/common/messages.d
Original file line number Diff line number Diff line change
Expand Up @@ -78,10 +78,12 @@ enum RequestKind : ushort
localUse = 0b00000010_00000000,
/// Remove import directory from server
removeImport = 0b00000100_00000000,
/// Get inlay hints
inlayHints = 0b00001000_00000000,

/// These request kinds require source code and won't be executed if there
/// is no source sent
requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse,
requiresSourceCode = autocomplete | doc | symbolLocation | search | localUse | inlayHints,
// dfmt on
}

Expand Down
27 changes: 26 additions & 1 deletion src/dcd/client/client.d
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ int runClient(string[] args)
bool clearCache;
bool symbolLocation;
bool doc;
bool inlayHints;
bool query;
bool printVersion;
bool listImports;
Expand All @@ -86,6 +87,7 @@ int runClient(string[] args)
"R", &removedImportPaths, "port|p", &port, "help|h", &help,
"shutdown", &shutdown, "clearCache", &clearCache,
"symbolLocation|l", &symbolLocation, "doc|d", &doc,
"inlayHints", &inlayHints,
"query|status|q", &query, "search|s", &search,
"version", &printVersion, "listImports", &listImports,
"tcp", &useTCP, "socketFile", &socketFile,
Expand Down Expand Up @@ -181,7 +183,7 @@ int runClient(string[] args)
printImportList(response);
return 0;
}
else if (search == null && cursorPos == size_t.max)
else if (search == null && !inlayHints && cursorPos == size_t.max)
{
// cursor position is a required argument
printHelp(args[0]);
Expand Down Expand Up @@ -234,6 +236,8 @@ int runClient(string[] args)
request.kind |= RequestKind.search;
else if(localUse)
request.kind |= RequestKind.localUse;
else if (inlayHints)
request.kind |= RequestKind.inlayHints;
else
request.kind |= RequestKind.autocomplete;

Expand All @@ -255,6 +259,8 @@ int runClient(string[] args)
printSearchResponse(response);
else if (localUse)
printLocalUse(response);
else if (inlayHints)
printInlayHintsResponse(response);
else
printCompletionResponse(response, fullOutput);

Expand Down Expand Up @@ -295,6 +301,10 @@ Options:
Gets documentation comments associated with the symbol at the cursor
location.
--inlayHints
For all supported variable usages, show value types. Currently shows
alias definitions.
--search | -s symbolName
Searches for symbolName in both stdin / the given file name as well as
others files cached by the server.
Expand Down Expand Up @@ -384,6 +394,21 @@ void printLocationResponse(ref const AutocompleteResponse response)
writeln(makeTabSeparated(response.symbolFilePath, response.symbolLocation.to!string));
}

void printInlayHintsResponse(ref const AutocompleteResponse response)
{
auto app = appender!(string[])();
foreach (ref completion; response.completions)
{
app.put(makeTabSeparated(
completion.kind == char.init ? "" : "" ~ completion.kind,
completion.identifier,
completion.symbolLocation.to!string
));
}
foreach (line; app.data)
writeln(line);
}

void printCompletionResponse(ref const AutocompleteResponse response, bool extended)
{
if (response.completions.length > 0)
Expand Down
108 changes: 108 additions & 0 deletions src/dcd/server/autocomplete/inlayhints.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

module dcd.server.autocomplete.inlayhints;

import std.stdio;
import std.algorithm;
import std.array;
import std.experimental.allocator;
import std.experimental.logger;
import std.typecons;

import dcd.server.autocomplete.util;

import dparse.lexer;
import dparse.rollback_allocator;

import dsymbol.modulecache;
import dsymbol.symbol;
import dsymbol.scope_;
import dsymbol.conversion;
import dsymbol.string_interning;

import dcd.common.messages;

import containers.hashset;

public AutocompleteResponse getInlayHints(const AutocompleteRequest request,
ref ModuleCache moduleCache)
{
// trace("Getting inlay hints comments");
AutocompleteResponse response;

LexerConfig config;
config.fileName = "";
auto cache = StringCache(request.sourceCode.length.optimalBucketCount);
auto tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode, config, &cache);
RollbackAllocator rba;
auto pair = generateAutocompleteTrees(tokenArray, &rba, -1, moduleCache);
scope(exit) pair.destroy();

void check(DSymbol* it, ref HashSet!size_t visited)
{
if (visited.contains(cast(size_t) it))
return;
if (it.symbolFile != "stdin") return;
visited.insert(cast(size_t) it);

//writeln("sym: ", it.name," ", it.location, " kind: ", it.kind," qualifier: ", it.qualifier);
//if (auto type = it.type)
//{
// writeln(" ", type.name, " kind: ", type.kind, " qualifier", type.qualifier);
// if (auto ttype = type.type)
// writeln(" ", ttype.name, " kind: ", ttype.kind, " qualifier", ttype.qualifier);
//}


// aliases
// struct Data {}
// alias Alias1 = Data;
// Alias1 var; becomes: Alias1 [-> Data] var;
if (it.kind == CompletionKind.variableName && it.type && it.type.kind == CompletionKind.aliasName)
{
AutocompleteResponse.Completion c;
c.symbolLocation = it.location - 1;
c.kind = CompletionKind.aliasName;

DSymbol* type = it.type;

while (type)
{
if (type.kind == CompletionKind.aliasName && type.type)
c.identifier ~= "->" ~ type.type.name;
if (type.type && type.type.kind != CompletionKind.aliasName) break;
type = type.type;
}

response.completions ~= c;
}

foreach(part; it.opSlice())
check(part, visited);
}

HashSet!size_t visited;
foreach (symbol; pair.scope_.symbols)
{
check(symbol, visited);
foreach(part; symbol.opSlice())
check(part, visited);
}
return response;
}
1 change: 1 addition & 0 deletions src/dcd/server/autocomplete/package.d
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ import dcd.server.autocomplete.complete;
import dcd.server.autocomplete.doc;
import dcd.server.autocomplete.localuse;
import dcd.server.autocomplete.symbols;
import dcd.server.autocomplete.inlayhints;
5 changes: 5 additions & 0 deletions src/dcd/server/main.d
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,11 @@ int runServer(string[] args)
s.trySendResponse(symbolSearch(request, cache), "Could not perform symbol search");
else if (request.kind & RequestKind.localUse)
s.trySendResponse(findLocalUse(request, cache), "Couldnot find local usage");
else if (request.kind & RequestKind.inlayHints)
{
info("Getting inlay hints");
s.trySendResponse(getInlayHints(request, cache), "Could not get inlay hints");
}
else if (needResponse)
s.trySendResponse(AutocompleteResponse.ack, "Could not send ack");
}
Expand Down
1 change: 1 addition & 0 deletions tests/tc_inlay_hints/expected.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
l ->Point 208
17 changes: 17 additions & 0 deletions tests/tc_inlay_hints/file.d
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// when extending the inlayHints capabilities, don't forget to update the --help
// text inside client.d

import point;
import point : P = Point;

void foo(int x, int y) {}
void foo(Point point) {}
void bar(P point, int z = 1) {}

void main()
{
P p;
foo(1, 2);
foo(p);
bar(p, 3);
}
5 changes: 5 additions & 0 deletions tests/tc_inlay_hints/run.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
set -e
set -u

../../bin/dcd-client $1 --inlayHints file.d > actual.txt
diff actual.txt expected.txt --strip-trailing-cr

0 comments on commit b79982d

Please sign in to comment.