Merge pull request #385 from BBasile/reboot-localusage
find local usage of symbol located at cursor
This commit is contained in:
commit
1fd445a80b
|
@ -5,8 +5,7 @@
|
|||
*.dll
|
||||
|
||||
# *nix binaries
|
||||
bin/dcd-client
|
||||
bin/dcd-server
|
||||
bin/
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
|
24
README.md
24
README.md
|
@ -213,6 +213,30 @@ in place of a file being edited.)
|
|||
/usr/include/dmd/phobos/std/conv.d f 9494
|
||||
```
|
||||
|
||||
## Find the use of the symbol at the cursor
|
||||
```dcd-client --localUse -c 123```
|
||||
|
||||
The "--localUse" or "-u" flags cause the client to instruct the server
|
||||
to return all the uses, within the same module, of the symbol located at the given cursor position.
|
||||
|
||||
#### Output format
|
||||
When uses 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.
|
||||
Following the first line is a list of all known uses of the symbol in the current file.
|
||||
The list is composed of lines each containing a single number that indicates the byte offset
|
||||
from the start of the file to the i-th use.
|
||||
|
||||
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 localUse;
|
||||
string search;
|
||||
version(Windows)
|
||||
{
|
||||
|
@ -70,7 +71,9 @@ 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", &localUse, // TODO:remove this line in Nov. 2017
|
||||
"localUse|u", &localUse);
|
||||
}
|
||||
catch (ConvException e)
|
||||
{
|
||||
|
@ -212,6 +215,8 @@ int main(string[] args)
|
|||
request.kind |= RequestKind.doc;
|
||||
else if (search)
|
||||
request.kind |= RequestKind.search;
|
||||
else if(localUse)
|
||||
request.kind |= RequestKind.localUse;
|
||||
else
|
||||
request.kind |= RequestKind.autocomplete;
|
||||
|
||||
|
@ -231,6 +236,8 @@ int main(string[] args)
|
|||
printDocResponse(response);
|
||||
else if (search !is null)
|
||||
printSearchResponse(response);
|
||||
else if (localUse)
|
||||
printLocalUse(response);
|
||||
else
|
||||
printCompletionResponse(response);
|
||||
|
||||
|
@ -277,6 +284,10 @@ Options:
|
|||
Searches for symbolName in both stdin / the given file name as well as
|
||||
others files cached by the server.
|
||||
|
||||
--localUse | -u
|
||||
Searches for all the uses 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 +396,17 @@ void printSearchResponse(const AutocompleteResponse response)
|
|||
}
|
||||
}
|
||||
|
||||
void printLocalUse(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
|
||||
localUse = 0b00000010_00000000,
|
||||
// dfmt on
|
||||
}
|
||||
|
||||
|
|
|
@ -50,6 +50,93 @@ import common.messages;
|
|||
|
||||
import containers.hashset;
|
||||
|
||||
/**
|
||||
* Finds the uses of the symbol at the cursor position within a single document.
|
||||
* Params:
|
||||
* request = the autocompletion request.
|
||||
* Returns:
|
||||
* the autocompletion response.
|
||||
*/
|
||||
public AutocompleteResponse findLocalUse(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.localUse)
|
||||
{
|
||||
try
|
||||
{
|
||||
AutocompleteResponse response = findLocalUse(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