ccls/src/messages/text_document_signature_help.cc

173 lines
6.2 KiB
C++
Raw Normal View History

2017-12-29 16:29:47 +00:00
#include "clang_complete.h"
#include "code_complete_cache.h"
2017-12-06 03:32:33 +00:00
#include "message_handler.h"
2017-12-29 16:29:47 +00:00
#include "queue_manager.h"
2017-12-06 03:32:33 +00:00
#include "timer.h"
#include <stdint.h>
namespace {
2017-12-06 04:39:44 +00:00
struct Ipc_TextDocumentSignatureHelp
: public RequestMessage<Ipc_TextDocumentSignatureHelp> {
2017-12-06 04:39:44 +00:00
const static IpcId kIpcId = IpcId::TextDocumentSignatureHelp;
lsTextDocumentPositionParams params;
};
MAKE_REFLECT_STRUCT(Ipc_TextDocumentSignatureHelp, id, params);
REGISTER_IPC_MESSAGE(Ipc_TextDocumentSignatureHelp);
// Represents a parameter of a callable-signature. A parameter can
// have a label and a doc-comment.
struct lsParameterInformation {
// The label of this parameter. Will be shown in
// the UI.
std::string label;
// The human-readable doc-comment of this parameter. Will be shown
// in the UI but can be omitted.
optional<std::string> documentation;
};
MAKE_REFLECT_STRUCT(lsParameterInformation, label, documentation);
// Represents the signature of something callable. A signature
// can have a label, like a function-name, a doc-comment, and
// a set of parameters.
struct lsSignatureInformation {
// The label of this signature. Will be shown in
// the UI.
std::string label;
// The human-readable doc-comment of this signature. Will be shown
// in the UI but can be omitted.
optional<std::string> documentation;
// The parameters of this signature.
std::vector<lsParameterInformation> parameters;
};
MAKE_REFLECT_STRUCT(lsSignatureInformation, label, documentation, parameters);
// Signature help represents the signature of something
// callable. There can be multiple signature but only one
// active and only one active parameter.
struct lsSignatureHelp {
// One or more signatures.
2017-12-12 05:20:29 +00:00
std::vector<lsSignatureInformation> signatures;
2017-12-06 04:39:44 +00:00
// The active signature. If omitted or the value lies outside the
// range of `signatures` the value defaults to zero or is ignored if
// `signatures.length === 0`. Whenever possible implementors should
// make an active decision about the active signature and shouldn't
// rely on a default value.
// In future version of the protocol this property might become
// mandantory to better express this.
optional<int> activeSignature;
// The active parameter of the active signature. If omitted or the value
// lies outside the range of `signatures[activeSignature].parameters`
// defaults to 0 if the active signature has parameters. If
// the active signature has no parameters it is ignored.
// In future version of the protocol this property might become
// mandantory to better express the active parameter if the
// active signature does have any.
optional<int> activeParameter;
};
MAKE_REFLECT_STRUCT(lsSignatureHelp,
signatures,
activeSignature,
activeParameter);
struct Out_TextDocumentSignatureHelp
: public lsOutMessage<Out_TextDocumentSignatureHelp> {
lsRequestId id;
lsSignatureHelp result;
};
MAKE_REFLECT_STRUCT(Out_TextDocumentSignatureHelp, jsonrpc, id, result);
2017-12-06 03:32:33 +00:00
struct TextDocumentSignatureHelpHandler : MessageHandler {
IpcId GetId() const override { return IpcId::TextDocumentSignatureHelp; }
void Run(std::unique_ptr<BaseIpcMessage> message) override {
auto request = message->As<Ipc_TextDocumentSignatureHelp>();
lsTextDocumentPositionParams& params = request->params;
WorkingFile* file =
working_files->GetFileByFilename(params.textDocument.uri.GetPath());
std::string search;
int active_param = 0;
if (file) {
lsPosition completion_position;
search = file->FindClosestCallNameInBuffer(params.position, &active_param,
&completion_position);
params.position = completion_position;
}
if (search.empty())
return;
ClangCompleteManager::OnComplete callback = std::bind(
[this](BaseIpcMessage* message, std::string search, int active_param,
2017-12-12 05:20:29 +00:00
const std::vector<lsCompletionItem>& results,
2017-12-06 03:32:33 +00:00
bool is_cached_result) {
auto msg = message->As<Ipc_TextDocumentSignatureHelp>();
Out_TextDocumentSignatureHelp out;
out.id = msg->id;
for (auto& result : results) {
if (result.label != search)
continue;
lsSignatureInformation signature;
signature.label = result.detail;
for (auto& parameter : result.parameters_) {
lsParameterInformation ls_param;
ls_param.label = parameter;
signature.parameters.push_back(ls_param);
}
out.result.signatures.push_back(signature);
}
// Prefer the signature with least parameter count but still larger
// than active_param.
2017-12-06 03:32:33 +00:00
out.result.activeSignature = 0;
if (out.result.signatures.size()) {
size_t num_parameters = SIZE_MAX;
for (size_t i = 0; i < out.result.signatures.size(); ++i) {
size_t t = out.result.signatures[i].parameters.size();
if (active_param < t && t < num_parameters) {
out.result.activeSignature = int(i);
num_parameters = t;
}
2017-12-06 03:32:33 +00:00
}
}
// Set signature to what we parsed from the working file.
out.result.activeParameter = active_param;
Timer timer;
2017-12-24 00:25:18 +00:00
QueueManager::WriteStdout(IpcId::TextDocumentSignatureHelp, out);
2017-12-06 03:32:33 +00:00
if (!is_cached_result) {
signature_cache->WithLock([&]() {
signature_cache->cached_path_ =
msg->params.textDocument.uri.GetPath();
signature_cache->cached_completion_position_ =
msg->params.position;
signature_cache->cached_results_ = results;
});
}
delete message;
},
message.release(), search, active_param, std::placeholders::_1,
std::placeholders::_2);
if (signature_cache->IsCacheValid(params)) {
signature_cache->WithLock([&]() {
callback(signature_cache->cached_results_, true /*is_cached_result*/);
});
} else {
clang_complete->CodeComplete(params, std::move(callback));
2017-12-06 03:32:33 +00:00
}
}
};
REGISTER_MESSAGE_HANDLER(TextDocumentSignatureHelpHandler);
2017-12-30 07:15:46 +00:00
} // namespace