Report document links on includes

This commit is contained in:
Jacob Dufault 2017-05-20 21:30:59 -07:00
parent 41e1dff4c9
commit 7a79532fff
7 changed files with 124 additions and 1 deletions

View File

@ -28,7 +28,7 @@ be productive with cquery. Here's a list of implemented features:
* diagnostics * diagnostics
* code actions (clang FixIts) * code actions (clang FixIts)
* darken/fade code disabled by preprocessor * darken/fade code disabled by preprocessor
* goto definition on include to jump to file * goto definition, document links on include to jump to file
# Setup - build cquery, install extension, setup project # Setup - build cquery, install extension, setup project

View File

@ -914,6 +914,7 @@ void RegisterMessageTypes() {
MessageRegistry::instance()->Register<Ipc_TextDocumentHover>(); MessageRegistry::instance()->Register<Ipc_TextDocumentHover>();
MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>(); MessageRegistry::instance()->Register<Ipc_TextDocumentReferences>();
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>(); MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentSymbol>();
MessageRegistry::instance()->Register<Ipc_TextDocumentDocumentLink>();
MessageRegistry::instance()->Register<Ipc_TextDocumentCodeAction>(); MessageRegistry::instance()->Register<Ipc_TextDocumentCodeAction>();
MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>(); MessageRegistry::instance()->Register<Ipc_TextDocumentCodeLens>();
MessageRegistry::instance()->Register<Ipc_CodeLensResolve>(); MessageRegistry::instance()->Register<Ipc_CodeLensResolve>();
@ -1539,6 +1540,9 @@ bool QueryDbMainLoop(
response.result.capabilities.documentSymbolProvider = true; response.result.capabilities.documentSymbolProvider = true;
response.result.capabilities.workspaceSymbolProvider = true; response.result.capabilities.workspaceSymbolProvider = true;
response.result.capabilities.documentLinkProvider = lsDocumentLinkOptions();
response.result.capabilities.documentLinkProvider->resolveProvider = false;
ipc->SendOutMessageToClient(IpcId::Initialize, response); ipc->SendOutMessageToClient(IpcId::Initialize, response);
break; break;
} }
@ -2097,6 +2101,68 @@ bool QueryDbMainLoop(
break; break;
} }
case IpcId::TextDocumentDocumentLink: {
auto msg = static_cast<Ipc_TextDocumentDocumentLink*>(message.get());
Out_TextDocumentDocumentLink response;
response.id = msg->id;
if (config->showDocumentLinksOnIncludes) {
QueryFile* file = FindFile(db, msg->params.textDocument.uri.GetPath());
if (!file) {
std::cerr << "Unable to find file " << msg->params.textDocument.uri.GetPath() << std::endl;
break;
}
WorkingFile* working_file = working_files->GetFileByFilename(msg->params.textDocument.uri.GetPath());
if (!working_file) {
std::cerr << "Unable to find working file " << msg->params.textDocument.uri.GetPath() << std::endl;
break;
}
for (const IndexInclude& include : file->def.includes) {
optional<int> buffer_line;
optional<std::string> buffer_line_content = working_file->GetBufferLineContentFromIndexLine(include.line, &buffer_line);
if (!buffer_line || !buffer_line_content)
continue;
// Find starting and ending quote.
int start = 0;
while (start < buffer_line_content->size()) {
char c = (*buffer_line_content)[start];
++start;
if (c == '"' || c == '<')
break;
}
if (start == buffer_line_content->size())
continue;
int end = buffer_line_content->size();
while (end > 0) {
char c = (*buffer_line_content)[end];
if (c == '"' || c == '>')
break;
--end;
}
if (start >= end)
break;
lsDocumentLink link;
link.target = lsDocumentUri::FromPath(include.resolved_path);
// Subtract 1 from line because querydb stores 1-based lines but
// vscode expects 0-based lines.
link.range.start.line = *buffer_line - 1;
link.range.start.character = start;
link.range.end.line = *buffer_line - 1;
link.range.end.character = end;
response.result.push_back(link);
}
}
response.Write(std::cerr);
ipc->SendOutMessageToClient(IpcId::TextDocumentDocumentLink, response);
break;
}
case IpcId::TextDocumentCodeAction: { case IpcId::TextDocumentCodeAction: {
// NOTE: This code snippet will generate some FixIts for testing: // NOTE: This code snippet will generate some FixIts for testing:
// //
@ -2495,6 +2561,7 @@ void LanguageServerStdinLoop(IndexerConfig* config, std::unordered_map<IpcId, Ti
case IpcId::TextDocumentHover: case IpcId::TextDocumentHover:
case IpcId::TextDocumentReferences: case IpcId::TextDocumentReferences:
case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
case IpcId::TextDocumentDocumentLink:
case IpcId::TextDocumentCodeAction: case IpcId::TextDocumentCodeAction:
case IpcId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:
case IpcId::WorkspaceSymbol: case IpcId::WorkspaceSymbol:

View File

@ -38,6 +38,8 @@ const char* IpcIdToString(IpcId id) {
return "textDocument/references"; return "textDocument/references";
case IpcId::TextDocumentDocumentSymbol: case IpcId::TextDocumentDocumentSymbol:
return "textDocument/documentSymbol"; return "textDocument/documentSymbol";
case IpcId::TextDocumentDocumentLink:
return "textDocument/documentLink";
case IpcId::TextDocumentCodeAction: case IpcId::TextDocumentCodeAction:
return "textDocument/codeAction"; return "textDocument/codeAction";
case IpcId::TextDocumentCodeLens: case IpcId::TextDocumentCodeLens:

View File

@ -24,6 +24,7 @@ enum class IpcId : int {
TextDocumentHover, TextDocumentHover,
TextDocumentReferences, TextDocumentReferences,
TextDocumentDocumentSymbol, TextDocumentDocumentSymbol,
TextDocumentDocumentLink,
TextDocumentCodeAction, TextDocumentCodeAction,
TextDocumentCodeLens, TextDocumentCodeLens,
CodeLensResolve, CodeLensResolve,

View File

@ -74,6 +74,9 @@ struct IndexerConfig {
// If false, the index will not be loaded from a previous run. // If false, the index will not be loaded from a previous run.
bool enableCacheRead = true; bool enableCacheRead = true;
// If true, document links are reported for #include directives.
bool showDocumentLinksOnIncludes = true;
// Enables code lens on parameter and function variables. // Enables code lens on parameter and function variables.
bool codeLensOnLocalVariables = true; bool codeLensOnLocalVariables = true;
@ -89,6 +92,8 @@ MAKE_REFLECT_STRUCT(IndexerConfig,
indexerCount, indexerCount,
enableIndexing, enableCacheWrite, enableCacheRead, enableIndexing, enableCacheWrite, enableCacheRead,
showDocumentLinksOnIncludes,
codeLensOnLocalVariables, codeLensOnLocalVariables,
clientVersion); clientVersion);
@ -1492,6 +1497,36 @@ struct Out_TextDocumentDocumentSymbol : public lsOutMessage<Out_TextDocumentDocu
}; };
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result); MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentSymbol, jsonrpc, id, result);
// List links a document
struct Ipc_TextDocumentDocumentLink : public IpcMessage<Ipc_TextDocumentDocumentLink> {
const static IpcId kIpcId = IpcId::TextDocumentDocumentLink;
struct DocumentLinkParams {
// The document to provide document links for.
lsTextDocumentIdentifier textDocument;
};
lsRequestId id;
DocumentLinkParams params;
};
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink::DocumentLinkParams, textDocument);
MAKE_REFLECT_STRUCT(Ipc_TextDocumentDocumentLink, id, params);
// A document link is a range in a text document that links to an internal or external resource, like another
// text document or a web site.
struct lsDocumentLink {
// The range this link applies to.
lsRange range;
// The uri this link points to. If missing a resolve request is sent later.
optional<lsDocumentUri> target;
};
MAKE_REFLECT_STRUCT(lsDocumentLink, range, target);
struct Out_TextDocumentDocumentLink : public lsOutMessage<Out_TextDocumentDocumentLink> {
lsRequestId id;
NonElidedVector<lsDocumentLink> result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentDocumentLink, jsonrpc, id, result);
// List code lens in a document. // List code lens in a document.
struct lsDocumentCodeLensParams { struct lsDocumentCodeLensParams {
lsTextDocumentIdentifier textDocument; lsTextDocumentIdentifier textDocument;

View File

@ -164,6 +164,22 @@ optional<int> WorkingFile::GetIndexLineFromBufferLine(int buffer_line) const {
return closest_index_line; return closest_index_line;
} }
optional<std::string> WorkingFile::GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const {
optional<int> buffer_line = GetBufferLineFromIndexLine(indexed_line);
if (out_buffer_line)
*out_buffer_line = buffer_line;
if (!buffer_line)
return nullopt;
if (*buffer_line < 1 || *buffer_line >= all_buffer_lines.size()) {
std::cerr << "GetBufferLineContentFromIndexLine buffer line lookup not in all_buffer_lines" << std::endl;
return nullopt;
}
return all_buffer_lines[*buffer_line - 1];
}
std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* active_parameter, lsPosition* completion_position) const { std::string WorkingFile::FindClosestCallNameInBuffer(lsPosition position, int* active_parameter, lsPosition* completion_position) const {
*active_parameter = 0; *active_parameter = 0;

View File

@ -44,6 +44,8 @@ struct WorkingFile {
// accepts and returns 1-based lines. // accepts and returns 1-based lines.
optional<int> GetIndexLineFromBufferLine(int buffer_line) const; optional<int> GetIndexLineFromBufferLine(int buffer_line) const;
optional<std::string> GetBufferLineContentFromIndexLine(int indexed_line, optional<int>* out_buffer_line) const;
// Finds the closest 'callable' name prior to position. This is used for // Finds the closest 'callable' name prior to position. This is used for
// signature help to filter code completion results. // signature help to filter code completion results.
// //