find local usage of symbol located at cursor
(partially based on unmainted PR 202)
This commit is contained in:
parent
42c5358940
commit
1ab8a8ec08
|
@ -5,8 +5,7 @@
|
|||
*.dll
|
||||
|
||||
# *nix binaries
|
||||
bin/dcd-client
|
||||
bin/dcd-server
|
||||
bin
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
|
21
README.md
21
README.md
|
@ -213,6 +213,27 @@ in place of a file being edited.)
|
|||
/usr/include/dmd/phobos/std/conv.d f 9494
|
||||
```
|
||||
|
||||
## Find usage of symbol at cursor
|
||||
```dcd-client --localUsage -c 123```
|
||||
|
||||
The "--localUsage" or "-u" flags cause the client to instruct the server
|
||||
to return all the local usages of the symbol located at the given cursor position.
|
||||
|
||||
#### Output format
|
||||
When usages exist, if the source symbol is an identifier (a type, a variable name, etc.) and if the symbol is not ambiguous then
|
||||
the first line contains the location of the symbol (a file name or literally _stdin_), a tab then the offset to the symbol declaration,
|
||||
each following line contains a byte offset, always relative to the supplied file, to a usage of the symbol.
|
||||
|
||||
Otherwise the client outputs _00000_ so that the length of the answer is guaranteed to be at least 5 bytes.
|
||||
|
||||
#### Example output
|
||||
```
|
||||
stdin 45
|
||||
26
|
||||
45
|
||||
133
|
||||
```
|
||||
|
||||
#Server
|
||||
The server must be running for the DCD client to provide autocomplete information.
|
||||
In future versions the client may start the server if it is not running, but for
|
||||
|
|
|
@ -50,6 +50,7 @@ int main(string[] args)
|
|||
bool printVersion;
|
||||
bool listImports;
|
||||
bool getIdentifier;
|
||||
bool localUsage;
|
||||
string search;
|
||||
version(Windows)
|
||||
{
|
||||
|
@ -70,7 +71,8 @@ int main(string[] args)
|
|||
"doc|d", &doc, "query|status|q", &query, "search|s", &search,
|
||||
"version", &printVersion, "listImports", &listImports,
|
||||
"tcp", &useTCP, "socketFile", &socketFile,
|
||||
"getIdentifier", &getIdentifier);
|
||||
"getIdentifier", &getIdentifier,
|
||||
"localUsage|u", &localUsage);
|
||||
}
|
||||
catch (ConvException e)
|
||||
{
|
||||
|
@ -212,6 +214,8 @@ int main(string[] args)
|
|||
request.kind |= RequestKind.doc;
|
||||
else if (search)
|
||||
request.kind |= RequestKind.search;
|
||||
else if(localUsage)
|
||||
request.kind |= RequestKind.localUsage;
|
||||
else
|
||||
request.kind |= RequestKind.autocomplete;
|
||||
|
||||
|
@ -231,6 +235,8 @@ int main(string[] args)
|
|||
printDocResponse(response);
|
||||
else if (search !is null)
|
||||
printSearchResponse(response);
|
||||
else if (localUsage)
|
||||
printLocalUsage(response);
|
||||
else
|
||||
printCompletionResponse(response);
|
||||
|
||||
|
@ -277,6 +283,10 @@ Options:
|
|||
Searches for symbolName in both stdin / the given file name as well as
|
||||
others files cached by the server.
|
||||
|
||||
--localUsage | -u
|
||||
Searches for all the usages of the symbol at the cursor location
|
||||
in the given filename (or stdin).
|
||||
|
||||
--query | -q | --status
|
||||
Query the server statis. Returns 0 if the server is running. Returns
|
||||
1 if the server could not be contacted.
|
||||
|
@ -385,6 +395,17 @@ void printSearchResponse(const AutocompleteResponse response)
|
|||
}
|
||||
}
|
||||
|
||||
void printLocalUsage(const AutocompleteResponse response)
|
||||
{
|
||||
if (response.symbolFilePath.length)
|
||||
{
|
||||
writeln(response.symbolFilePath, '\t', response.symbolLocation);
|
||||
foreach(loc; response.locations)
|
||||
writeln(loc);
|
||||
}
|
||||
else write("00000");
|
||||
}
|
||||
|
||||
void printImportList(const AutocompleteResponse response)
|
||||
{
|
||||
import std.algorithm.iteration : each;
|
||||
|
|
|
@ -74,6 +74,8 @@ enum RequestKind : ushort
|
|||
search = 0b00000000_10000000,
|
||||
/// List import directories
|
||||
listImports = 0b00000001_00000000,
|
||||
/// local symbol usage
|
||||
localUsage = 0b00000010_00000000,
|
||||
// dfmt on
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,93 @@ import common.messages;
|
|||
|
||||
import containers.hashset;
|
||||
|
||||
/**
|
||||
* Finds usage of the symbol at the cursor position in a single document.
|
||||
* Params:
|
||||
* request = the autocompletion request
|
||||
* Returns:
|
||||
* the autocompletion response
|
||||
*/
|
||||
public AutocompleteResponse findLocalUsage(AutocompleteRequest request,
|
||||
ref ModuleCache moduleCache)
|
||||
{
|
||||
AutocompleteResponse response;
|
||||
RollbackAllocator rba;
|
||||
auto allocator = scoped!(ASTAllocator)();
|
||||
auto cache = StringCache(StringCache.defaultBucketCount);
|
||||
|
||||
// patchs the original request for the subsequent requests
|
||||
request.kind = RequestKind.symbolLocation;
|
||||
|
||||
// getSymbolsForCompletion() copy to avoid repetitive parsing
|
||||
LexerConfig config;
|
||||
config.fileName = "";
|
||||
const(Token)[] tokenArray = getTokensForParser(cast(ubyte[]) request.sourceCode,
|
||||
config, &cache);
|
||||
SymbolStuff getSymbolsAtCursor(size_t cursorPosition)
|
||||
{
|
||||
auto sortedTokens = assumeSorted(tokenArray);
|
||||
auto beforeTokens = sortedTokens.lowerBound(cursorPosition);
|
||||
ScopeSymbolPair pair = generateAutocompleteTrees(tokenArray, allocator,
|
||||
&rba, request.cursorPosition, moduleCache);
|
||||
auto expression = getExpression(beforeTokens);
|
||||
return SymbolStuff(getSymbolsByTokenChain(pair.scope_, expression,
|
||||
cursorPosition, CompletionType.location), pair.symbol, pair.scope_);
|
||||
}
|
||||
|
||||
// gets the symbol matching to cursor pos
|
||||
SymbolStuff stuff = getSymbolsAtCursor(cast(size_t)request.cursorPosition);
|
||||
scope(exit) stuff.destroy();
|
||||
|
||||
// starts searching only if no ambiguity with the symbol
|
||||
if (stuff.symbols.length == 1)
|
||||
{
|
||||
const(DSymbol*) sourceSymbol = stuff.symbols[0];
|
||||
response.symbolLocation = sourceSymbol.location;
|
||||
response.symbolFilePath = sourceSymbol.symbolFile.idup;
|
||||
|
||||
// gets the source token to avoid too much getSymbolsAtCursor()
|
||||
const(Token)* sourceToken;
|
||||
foreach(i, t; tokenArray)
|
||||
{
|
||||
if (t.type != tok!"identifier")
|
||||
continue;
|
||||
if (request.cursorPosition >= t.index &&
|
||||
request.cursorPosition < t.index + t.text.length)
|
||||
{
|
||||
sourceToken = tokenArray.ptr + i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// finds the tokens that match to the source symbol
|
||||
if (sourceToken != null) foreach (t; tokenArray)
|
||||
{
|
||||
if (t.type == tok!"identifier" && t.text == sourceToken.text)
|
||||
{
|
||||
size_t pos = cast(size_t) t.index + 1; // place cursor inside the token
|
||||
SymbolStuff candidate = getSymbolsAtCursor(pos);
|
||||
scope(exit) candidate.destroy();
|
||||
if (candidate.symbols.length == 1 &&
|
||||
candidate.symbols[0].location == sourceSymbol.location &&
|
||||
candidate.symbols[0].symbolFile == sourceSymbol.symbolFile)
|
||||
{
|
||||
response.locations ~= t.index;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("The source token is not an identifier");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
warning("No or ambiguous symbol for the identifier at cursor");
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets documentation for the symbol at the cursor
|
||||
* Params:
|
||||
|
|
|
@ -318,6 +318,19 @@ int main(string[] args)
|
|||
ubyte[] responseBytes = msgpack.pack(response);
|
||||
s.send(responseBytes);
|
||||
}
|
||||
else if (request.kind & RequestKind.localUsage)
|
||||
{
|
||||
try
|
||||
{
|
||||
AutocompleteResponse response = findLocalUsage(request, cache);
|
||||
ubyte[] responseBytes = msgpack.pack(response);
|
||||
s.send(responseBytes);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
warning("Could not find local usage", e.msg);
|
||||
}
|
||||
}
|
||||
info("Request processed in ", requestWatch.peek().to!("msecs", float), " milliseconds");
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
stdin 5
|
||||
5
|
||||
21
|
||||
27
|
||||
33
|
|
@ -0,0 +1 @@
|
|||
uint var; void foo(){var=0;var=0;var=0;}
|
|
@ -0,0 +1,5 @@
|
|||
set -e
|
||||
set -u
|
||||
|
||||
../../bin/dcd-client $1 file.d -u -c22 | sed s\""$(dirname "$(pwd)")"\"\" > actual1.txt
|
||||
diff actual1.txt expected1.txt
|
|
@ -0,0 +1,3 @@
|
|||
/imports/object.d 22
|
||||
0
|
||||
12
|
|
@ -0,0 +1 @@
|
|||
string str; string txt;
|
|
@ -0,0 +1,5 @@
|
|||
set -e
|
||||
set -u
|
||||
|
||||
../../bin/dcd-client $1 file.d -u -c1 | sed s\""$(dirname "$(pwd)")"\"\" > actual1.txt
|
||||
diff actual1.txt expected1.txt
|
|
@ -0,0 +1 @@
|
|||
00000
|
|
@ -0,0 +1 @@
|
|||
struct Foo; struct Foo;
|
|
@ -0,0 +1,5 @@
|
|||
set -e
|
||||
set -u
|
||||
|
||||
../../bin/dcd-client $1 file.d -u -c8 | sed s\""$(dirname "$(pwd)")"\"\" > actual1.txt
|
||||
diff actual1.txt expected1.txt
|
Loading…
Reference in New Issue