mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-28 02:21:57 +00:00
Delay requests if the document has not not indexed (#176)
This fixes a plethora of "not indexed" errors when the document has not been indexed. * Message handler throws NotIndexed if not overdue * The message is put into backlog and tagged with backlog_path * path2backlog[path] tracks backlog associated with document `path` * The backlog is cleared when the index is merged * backlog[0] is forced to run if it becomes overdue
This commit is contained in:
parent
e8cacf1efa
commit
9a529bd691
@ -242,6 +242,12 @@ struct Config {
|
|||||||
std::vector<std::string> whitelist;
|
std::vector<std::string> whitelist;
|
||||||
} index;
|
} index;
|
||||||
|
|
||||||
|
struct Request {
|
||||||
|
// If the document of a request has not been indexed, wait up to this many
|
||||||
|
// milleseconds before reporting error.
|
||||||
|
int64_t timeout = 5000;
|
||||||
|
} request;
|
||||||
|
|
||||||
struct Session {
|
struct Session {
|
||||||
int maxNum = 10;
|
int maxNum = 10;
|
||||||
} session;
|
} session;
|
||||||
@ -278,12 +284,14 @@ REFLECT_STRUCT(Config::Index, blacklist, comments, initialBlacklist,
|
|||||||
initialWhitelist, multiVersion, multiVersionBlacklist,
|
initialWhitelist, multiVersion, multiVersionBlacklist,
|
||||||
multiVersionWhitelist, onChange, threads, trackDependency,
|
multiVersionWhitelist, onChange, threads, trackDependency,
|
||||||
whitelist);
|
whitelist);
|
||||||
|
REFLECT_STRUCT(Config::Request, timeout);
|
||||||
REFLECT_STRUCT(Config::Session, maxNum);
|
REFLECT_STRUCT(Config::Session, maxNum);
|
||||||
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
REFLECT_STRUCT(Config::WorkspaceSymbol, caseSensitivity, maxNum, sort);
|
||||||
REFLECT_STRUCT(Config::Xref, maxNum);
|
REFLECT_STRUCT(Config::Xref, maxNum);
|
||||||
REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
|
REFLECT_STRUCT(Config, compilationDatabaseCommand, compilationDatabaseDirectory,
|
||||||
cacheDirectory, cacheFormat, clang, client, codeLens, completion,
|
cacheDirectory, cacheFormat, clang, client, codeLens, completion,
|
||||||
diagnostics, highlight, index, session, workspaceSymbol, xref);
|
diagnostics, highlight, index, request, session, workspaceSymbol,
|
||||||
|
xref);
|
||||||
|
|
||||||
extern Config *g_config;
|
extern Config *g_config;
|
||||||
|
|
||||||
|
@ -21,8 +21,8 @@ limitations under the License.
|
|||||||
|
|
||||||
#include <rapidjson/fwd.h>
|
#include <rapidjson/fwd.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
struct RequestId {
|
struct RequestId {
|
||||||
@ -43,6 +43,8 @@ struct InMessage {
|
|||||||
std::string method;
|
std::string method;
|
||||||
std::unique_ptr<char[]> message;
|
std::unique_ptr<char[]> message;
|
||||||
std::unique_ptr<rapidjson::Document> document;
|
std::unique_ptr<rapidjson::Document> document;
|
||||||
|
std::chrono::steady_clock::time_point deadline;
|
||||||
|
std::string backlog_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class ErrorCode {
|
enum class ErrorCode {
|
||||||
|
@ -109,11 +109,8 @@ struct ScanLineEvent {
|
|||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void ReplyOnce::NotReady(bool file) {
|
void ReplyOnce::NotOpened(std::string_view path) {
|
||||||
if (file)
|
Error(ErrorCode::InvalidRequest, std::string(path) + " is not opened");
|
||||||
Error(ErrorCode::InvalidRequest, "not opened");
|
|
||||||
else
|
|
||||||
Error(ErrorCode::InternalError, "not indexed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
|
void ReplyOnce::ReplyLocationLink(std::vector<LocationLink> &result) {
|
||||||
@ -215,13 +212,11 @@ MessageHandler::MessageHandler() {
|
|||||||
|
|
||||||
void MessageHandler::Run(InMessage &msg) {
|
void MessageHandler::Run(InMessage &msg) {
|
||||||
rapidjson::Document &doc = *msg.document;
|
rapidjson::Document &doc = *msg.document;
|
||||||
rapidjson::Value param;
|
rapidjson::Value null;
|
||||||
auto it = doc.FindMember("params");
|
auto it = doc.FindMember("params");
|
||||||
if (it != doc.MemberEnd())
|
JsonReader reader(it != doc.MemberEnd() ? &it->value : &null);
|
||||||
param = it->value;
|
|
||||||
JsonReader reader(¶m);
|
|
||||||
if (msg.id.Valid()) {
|
if (msg.id.Valid()) {
|
||||||
ReplyOnce reply{msg.id};
|
ReplyOnce reply{*this, msg.id};
|
||||||
auto it = method2request.find(msg.method);
|
auto it = method2request.find(msg.method);
|
||||||
if (it != method2request.end()) {
|
if (it != method2request.end()) {
|
||||||
try {
|
try {
|
||||||
@ -230,6 +225,8 @@ void MessageHandler::Run(InMessage &msg) {
|
|||||||
reply.Error(ErrorCode::InvalidParams,
|
reply.Error(ErrorCode::InvalidParams,
|
||||||
"invalid params of " + msg.method + ": expected " +
|
"invalid params of " + msg.method + ": expected " +
|
||||||
ex.what() + " for " + reader.GetPath());
|
ex.what() + " for " + reader.GetPath());
|
||||||
|
} catch (NotIndexed &) {
|
||||||
|
throw;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
reply.Error(ErrorCode::InternalError, "failed to process " + msg.method);
|
reply.Error(ErrorCode::InternalError, "failed to process " + msg.method);
|
||||||
}
|
}
|
||||||
@ -249,7 +246,8 @@ void MessageHandler::Run(InMessage &msg) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QueryFile *MessageHandler::FindFile(const std::string &path, int *out_file_id) {
|
QueryFile *MessageHandler::FindFile(const std::string &path,
|
||||||
|
int *out_file_id) {
|
||||||
QueryFile *ret = nullptr;
|
QueryFile *ret = nullptr;
|
||||||
auto it = db->name2file_id.find(LowerPathIfInsensitive(path));
|
auto it = db->name2file_id.find(LowerPathIfInsensitive(path));
|
||||||
if (it != db->name2file_id.end()) {
|
if (it != db->name2file_id.end()) {
|
||||||
@ -266,6 +264,24 @@ QueryFile *MessageHandler::FindFile(const std::string &path, int *out_file_id) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<QueryFile *, WorkingFile *>
|
||||||
|
MessageHandler::FindOrFail(const std::string &path, ReplyOnce &reply,
|
||||||
|
int *out_file_id) {
|
||||||
|
WorkingFile *wf = wfiles->GetFile(path);
|
||||||
|
if (!wf) {
|
||||||
|
reply.NotOpened(path);
|
||||||
|
return {nullptr, nullptr};
|
||||||
|
}
|
||||||
|
QueryFile *file = FindFile(path, out_file_id);
|
||||||
|
if (!file) {
|
||||||
|
if (!overdue)
|
||||||
|
throw NotIndexed{path};
|
||||||
|
reply.Error(ErrorCode::InvalidRequest, "not indexed");
|
||||||
|
return {nullptr, nullptr};
|
||||||
|
}
|
||||||
|
return {file, wf};
|
||||||
|
}
|
||||||
|
|
||||||
void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
|
void EmitSkippedRanges(WorkingFile *wfile, QueryFile &file) {
|
||||||
CclsSetSkippedRanges params;
|
CclsSetSkippedRanges params;
|
||||||
params.uri = DocumentUri::FromPath(wfile->filename);
|
params.uri = DocumentUri::FromPath(wfile->filename);
|
||||||
|
@ -199,7 +199,13 @@ REFLECT_STRUCT(Diagnostic, range, severity, code, source, message);
|
|||||||
REFLECT_STRUCT(ShowMessageParam, type, message);
|
REFLECT_STRUCT(ShowMessageParam, type, message);
|
||||||
REFLECT_UNDERLYING_B(LanguageId);
|
REFLECT_UNDERLYING_B(LanguageId);
|
||||||
|
|
||||||
|
struct NotIndexed {
|
||||||
|
std::string path;
|
||||||
|
};
|
||||||
|
struct MessageHandler;
|
||||||
|
|
||||||
struct ReplyOnce {
|
struct ReplyOnce {
|
||||||
|
MessageHandler &handler;
|
||||||
RequestId id;
|
RequestId id;
|
||||||
template <typename Res> void operator()(Res &&result) const {
|
template <typename Res> void operator()(Res &&result) const {
|
||||||
if (id.Valid())
|
if (id.Valid())
|
||||||
@ -210,7 +216,7 @@ struct ReplyOnce {
|
|||||||
if (id.Valid())
|
if (id.Valid())
|
||||||
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
|
pipeline::ReplyError(id, [&](JsonWriter &w) { Reflect(w, err); });
|
||||||
}
|
}
|
||||||
void NotReady(bool file);
|
void NotOpened(std::string_view path);
|
||||||
void ReplyLocationLink(std::vector<LocationLink> &result);
|
void ReplyLocationLink(std::vector<LocationLink> &result);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,10 +231,14 @@ struct MessageHandler {
|
|||||||
llvm::StringMap<std::function<void(JsonReader &)>> method2notification;
|
llvm::StringMap<std::function<void(JsonReader &)>> method2notification;
|
||||||
llvm::StringMap<std::function<void(JsonReader &, ReplyOnce &)>>
|
llvm::StringMap<std::function<void(JsonReader &, ReplyOnce &)>>
|
||||||
method2request;
|
method2request;
|
||||||
|
bool overdue = false;
|
||||||
|
|
||||||
MessageHandler();
|
MessageHandler();
|
||||||
void Run(InMessage &msg);
|
void Run(InMessage &msg);
|
||||||
QueryFile *FindFile(const std::string &path, int *out_file_id = nullptr);
|
QueryFile *FindFile(const std::string &path, int *out_file_id = nullptr);
|
||||||
|
std::pair<QueryFile *, WorkingFile *> FindOrFail(const std::string &path,
|
||||||
|
ReplyOnce &reply,
|
||||||
|
int *out_file_id = nullptr);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Bind(const char *method, void (MessageHandler::*handler)(JsonReader &));
|
void Bind(const char *method, void (MessageHandler::*handler)(JsonReader &));
|
||||||
|
@ -200,8 +200,7 @@ void MessageHandler::ccls_call(JsonReader &reader, ReplyOnce &reply) {
|
|||||||
Expand(this, &*result, param.callee, param.callType, param.qualified,
|
Expand(this, &*result, param.callee, param.callType, param.qualified,
|
||||||
param.levels);
|
param.levels);
|
||||||
} else {
|
} else {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf)
|
if (!wf)
|
||||||
return;
|
return;
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
||||||
|
@ -146,10 +146,10 @@ void Inheritance(MessageHandler *m, Param ¶m, ReplyOnce &reply) {
|
|||||||
Expand(m, &*result, param.derived, param.qualified, param.levels)))
|
Expand(m, &*result, param.derived, param.qualified, param.levels)))
|
||||||
result.reset();
|
result.reset();
|
||||||
} else {
|
} else {
|
||||||
QueryFile *file = m->FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = m->FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
if (!file)
|
if (!wf) {
|
||||||
return;
|
return;
|
||||||
WorkingFile *wf = m->wfiles->GetFile(file->def->path);
|
}
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position))
|
||||||
if (sym.kind == Kind::Func || sym.kind == Kind::Type) {
|
if (sym.kind == Kind::Func || sym.kind == Kind::Type) {
|
||||||
result = BuildInitial(m, sym, param.derived, param.qualified,
|
result = BuildInitial(m, sym, param.derived, param.qualified,
|
||||||
|
@ -281,12 +281,9 @@ void MessageHandler::ccls_member(JsonReader &reader, ReplyOnce &reply) {
|
|||||||
param.levels, param.kind)))
|
param.levels, param.kind)))
|
||||||
result.reset();
|
result.reset();
|
||||||
} else {
|
} else {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
||||||
switch (sym.kind) {
|
switch (sym.kind) {
|
||||||
case Kind::Func:
|
case Kind::Func:
|
||||||
|
@ -41,10 +41,8 @@ Maybe<Range> FindParent(QueryFile *file, Pos pos) {
|
|||||||
void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
|
void MessageHandler::ccls_navigate(JsonReader &reader, ReplyOnce &reply) {
|
||||||
Param param;
|
Param param;
|
||||||
Reflect(reader, param);
|
Reflect(reader, param);
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Position ls_pos = param.position;
|
Position ls_pos = param.position;
|
||||||
|
@ -31,10 +31,8 @@ REFLECT_STRUCT(Param, textDocument, position, kind);
|
|||||||
void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
|
void MessageHandler::ccls_vars(JsonReader &reader, ReplyOnce &reply) {
|
||||||
Param param;
|
Param param;
|
||||||
Reflect(reader, param);
|
Reflect(reader, param);
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -388,7 +388,7 @@ void MessageHandler::initialize(JsonReader &reader, ReplyOnce &reply) {
|
|||||||
void StandaloneInitialize(MessageHandler &handler, const std::string &root) {
|
void StandaloneInitialize(MessageHandler &handler, const std::string &root) {
|
||||||
InitializeParam param;
|
InitializeParam param;
|
||||||
param.rootUri = DocumentUri::FromPath(root);
|
param.rootUri = DocumentUri::FromPath(root);
|
||||||
ReplyOnce reply;
|
ReplyOnce reply{handler};
|
||||||
Initialize(&handler, param, reply);
|
Initialize(&handler, param, reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,11 +35,9 @@ REFLECT_STRUCT(CodeAction, title, kind, edit);
|
|||||||
}
|
}
|
||||||
void MessageHandler::textDocument_codeAction(CodeActionParam ¶m,
|
void MessageHandler::textDocument_codeAction(CodeActionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
WorkingFile *wf = wfiles->GetFile(param.textDocument.uri.GetPath());
|
WorkingFile *wf = FindOrFail(param.textDocument.uri.GetPath(), reply).second;
|
||||||
if (!wf) {
|
if (!wf)
|
||||||
reply.NotReady(true);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
std::vector<CodeAction> result;
|
std::vector<CodeAction> result;
|
||||||
std::vector<Diagnostic> diagnostics;
|
std::vector<Diagnostic> diagnostics;
|
||||||
wfiles->WithLock([&]() { diagnostics = wf->diagnostics; });
|
wfiles->WithLock([&]() { diagnostics = wf->diagnostics; });
|
||||||
@ -96,16 +94,13 @@ struct CommonCodeLensParams {
|
|||||||
|
|
||||||
void MessageHandler::textDocument_codeLens(TextDocumentParam ¶m,
|
void MessageHandler::textDocument_codeLens(TextDocumentParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<CodeLens> result;
|
std::vector<CodeLens> result;
|
||||||
auto Add = [&](const char *singular, Cmd_xref show, Range range, int num,
|
auto Add = [&, wf = wf](const char *singular, Cmd_xref show, Range range,
|
||||||
bool force_display = false) {
|
int num, bool force_display = false) {
|
||||||
if (!num && !force_display)
|
if (!num && !force_display)
|
||||||
return;
|
return;
|
||||||
std::optional<lsRange> ls_range = GetLsRange(wf, range);
|
std::optional<lsRange> ls_range = GetLsRange(wf, range);
|
||||||
|
@ -459,7 +459,7 @@ void MessageHandler::textDocument_completion(CompletionParam ¶m,
|
|||||||
std::string path = param.textDocument.uri.GetPath();
|
std::string path = param.textDocument.uri.GetPath();
|
||||||
WorkingFile *wf = wfiles->GetFile(path);
|
WorkingFile *wf = wfiles->GetFile(path);
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(true);
|
reply.NotOpened(path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,12 +48,9 @@ std::vector<DeclRef> GetNonDefDeclarationTargets(DB *db, SymbolRef sym) {
|
|||||||
void MessageHandler::textDocument_declaration(TextDocumentPositionParam ¶m,
|
void MessageHandler::textDocument_declaration(TextDocumentPositionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
int file_id;
|
int file_id;
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<LocationLink> result;
|
std::vector<LocationLink> result;
|
||||||
Position &ls_pos = param.position;
|
Position &ls_pos = param.position;
|
||||||
@ -69,12 +66,9 @@ void MessageHandler::textDocument_declaration(TextDocumentPositionParam ¶m,
|
|||||||
void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
int file_id;
|
int file_id;
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<LocationLink> result;
|
std::vector<LocationLink> result;
|
||||||
Maybe<DeclRef> on_def;
|
Maybe<DeclRef> on_def;
|
||||||
@ -190,12 +184,9 @@ void MessageHandler::textDocument_definition(TextDocumentPositionParam ¶m,
|
|||||||
|
|
||||||
void MessageHandler::textDocument_typeDefinition(
|
void MessageHandler::textDocument_typeDefinition(
|
||||||
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!file)
|
||||||
if (!file) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<LocationLink> result;
|
std::vector<LocationLink> result;
|
||||||
auto Add = [&](const QueryType &type) {
|
auto Add = [&](const QueryType &type) {
|
||||||
|
@ -44,12 +44,9 @@ REFLECT_STRUCT(DocumentHighlight, range, kind, role);
|
|||||||
void MessageHandler::textDocument_documentHighlight(
|
void MessageHandler::textDocument_documentHighlight(
|
||||||
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
||||||
int file_id;
|
int file_id;
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<DocumentHighlight> result;
|
std::vector<DocumentHighlight> result;
|
||||||
std::vector<SymbolRef> syms =
|
std::vector<SymbolRef> syms =
|
||||||
@ -90,10 +87,8 @@ REFLECT_STRUCT(DocumentLink, range, target);
|
|||||||
|
|
||||||
void MessageHandler::textDocument_documentLink(TextDocumentParam ¶m,
|
void MessageHandler::textDocument_documentLink(TextDocumentParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,10 +160,8 @@ void MessageHandler::textDocument_documentSymbol(JsonReader &reader,
|
|||||||
Reflect(reader, param);
|
Reflect(reader, param);
|
||||||
|
|
||||||
int file_id;
|
int file_id;
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath(), &file_id);
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply, &file_id);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,12 +31,9 @@ REFLECT_STRUCT(FoldingRange, startLine, startCharacter, endLine, endCharacter,
|
|||||||
|
|
||||||
void MessageHandler::textDocument_foldingRange(TextDocumentParam ¶m,
|
void MessageHandler::textDocument_foldingRange(TextDocumentParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
std::vector<FoldingRange> result;
|
std::vector<FoldingRange> result;
|
||||||
std::optional<lsRange> ls_range;
|
std::optional<lsRange> ls_range;
|
||||||
|
|
||||||
|
@ -80,21 +80,16 @@ void Format(ReplyOnce &reply, WorkingFile *wfile, tooling::Range range) {
|
|||||||
|
|
||||||
void MessageHandler::textDocument_formatting(DocumentFormattingParam ¶m,
|
void MessageHandler::textDocument_formatting(DocumentFormattingParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
Format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
|
Format(reply, wf, {0, (unsigned)wf->buffer_content.size()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageHandler::textDocument_onTypeFormatting(
|
void MessageHandler::textDocument_onTypeFormatting(
|
||||||
DocumentOnTypeFormattingParam ¶m, ReplyOnce &reply) {
|
DocumentOnTypeFormattingParam ¶m, ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string_view code = wf->buffer_content;
|
std::string_view code = wf->buffer_content;
|
||||||
@ -107,10 +102,8 @@ void MessageHandler::textDocument_onTypeFormatting(
|
|||||||
|
|
||||||
void MessageHandler::textDocument_rangeFormatting(
|
void MessageHandler::textDocument_rangeFormatting(
|
||||||
DocumentRangeFormattingParam ¶m, ReplyOnce &reply) {
|
DocumentRangeFormattingParam ¶m, ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
std::string_view code = wf->buffer_content;
|
std::string_view code = wf->buffer_content;
|
||||||
|
@ -93,12 +93,9 @@ GetHover(DB *db, LanguageId lang, SymbolRef sym, int file_id) {
|
|||||||
|
|
||||||
void MessageHandler::textDocument_hover(TextDocumentPositionParam ¶m,
|
void MessageHandler::textDocument_hover(TextDocumentPositionParam ¶m,
|
||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
Hover result;
|
Hover result;
|
||||||
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
for (SymbolRef sym : FindSymbolsAtLocation(wf, file, param.position)) {
|
||||||
|
@ -45,12 +45,9 @@ void MessageHandler::textDocument_references(JsonReader &reader,
|
|||||||
ReplyOnce &reply) {
|
ReplyOnce &reply) {
|
||||||
ReferenceParam param;
|
ReferenceParam param;
|
||||||
Reflect(reader, param);
|
Reflect(reader, param);
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
if (!wf)
|
||||||
if (!wf) {
|
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
for (auto &folder : param.folders)
|
for (auto &folder : param.folders)
|
||||||
EnsureEndsInSlash(folder);
|
EnsureEndsInSlash(folder);
|
||||||
|
@ -56,10 +56,8 @@ WorkspaceEdit BuildWorkspaceEdit(DB *db, WorkingFiles *wfiles, SymbolRef sym,
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void MessageHandler::textDocument_rename(RenameParam ¶m, ReplyOnce &reply) {
|
void MessageHandler::textDocument_rename(RenameParam ¶m, ReplyOnce &reply) {
|
||||||
QueryFile *file = FindFile(param.textDocument.uri.GetPath());
|
auto [file, wf] = FindOrFail(param.textDocument.uri.GetPath(), reply);
|
||||||
WorkingFile *wf = file ? wfiles->GetFile(file->def->path) : nullptr;
|
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(file);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,12 +152,11 @@ public:
|
|||||||
void MessageHandler::textDocument_signatureHelp(
|
void MessageHandler::textDocument_signatureHelp(
|
||||||
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
TextDocumentPositionParam ¶m, ReplyOnce &reply) {
|
||||||
static CompleteConsumerCache<SignatureHelp> cache;
|
static CompleteConsumerCache<SignatureHelp> cache;
|
||||||
|
|
||||||
std::string path = param.textDocument.uri.GetPath();
|
|
||||||
Position begin_pos = param.position;
|
Position begin_pos = param.position;
|
||||||
|
std::string path = param.textDocument.uri.GetPath();
|
||||||
WorkingFile *wf = wfiles->GetFile(path);
|
WorkingFile *wf = wfiles->GetFile(path);
|
||||||
if (!wf) {
|
if (!wf) {
|
||||||
reply.NotReady(true);
|
reply.NotOpened(path);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
@ -32,7 +32,6 @@ limitations under the License.
|
|||||||
#include <llvm/Support/Path.h>
|
#include <llvm/Support/Path.h>
|
||||||
#include <llvm/Support/Process.h>
|
#include <llvm/Support/Process.h>
|
||||||
#include <llvm/Support/Threading.h>
|
#include <llvm/Support/Threading.h>
|
||||||
using namespace llvm;
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -41,6 +40,8 @@ using namespace llvm;
|
|||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
using namespace llvm;
|
||||||
|
namespace chrono = std::chrono;
|
||||||
|
|
||||||
namespace ccls {
|
namespace ccls {
|
||||||
namespace {
|
namespace {
|
||||||
@ -527,8 +528,11 @@ void LaunchStdin() {
|
|||||||
if (method.empty())
|
if (method.empty())
|
||||||
continue;
|
continue;
|
||||||
bool should_exit = method == "exit";
|
bool should_exit = method == "exit";
|
||||||
|
// g_config is not available before "initialize". Use 0 in that case.
|
||||||
on_request->PushBack(
|
on_request->PushBack(
|
||||||
{id, std::move(method), std::move(message), std::move(document)});
|
{id, std::move(method), std::move(message), std::move(document),
|
||||||
|
chrono::steady_clock::now() +
|
||||||
|
chrono::milliseconds(g_config ? g_config->request.timeout : 0)});
|
||||||
|
|
||||||
if (should_exit)
|
if (should_exit)
|
||||||
break;
|
break;
|
||||||
@ -590,11 +594,34 @@ void MainLoop() {
|
|||||||
handler.include_complete = &include_complete;
|
handler.include_complete = &include_complete;
|
||||||
|
|
||||||
bool has_indexed = false;
|
bool has_indexed = false;
|
||||||
|
std::deque<InMessage> backlog;
|
||||||
|
StringMap<std::deque<InMessage *>> path2backlog;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
if (backlog.size()) {
|
||||||
|
auto now = chrono::steady_clock::now();
|
||||||
|
handler.overdue = true;
|
||||||
|
while (backlog.size()) {
|
||||||
|
if (backlog[0].backlog_path.size()) {
|
||||||
|
if (now < backlog[0].deadline)
|
||||||
|
break;
|
||||||
|
handler.Run(backlog[0]);
|
||||||
|
path2backlog[backlog[0].backlog_path].pop_front();
|
||||||
|
}
|
||||||
|
backlog.pop_front();
|
||||||
|
}
|
||||||
|
handler.overdue = false;
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<InMessage> messages = on_request->DequeueAll();
|
std::vector<InMessage> messages = on_request->DequeueAll();
|
||||||
bool did_work = messages.size();
|
bool did_work = messages.size();
|
||||||
for (InMessage &message : messages)
|
for (InMessage &message : messages)
|
||||||
handler.Run(message);
|
try {
|
||||||
|
handler.Run(message);
|
||||||
|
} catch (NotIndexed &ex) {
|
||||||
|
backlog.push_back(std::move(message));
|
||||||
|
backlog.back().backlog_path = ex.path;
|
||||||
|
path2backlog[ex.path].push_back(&backlog.back());
|
||||||
|
}
|
||||||
|
|
||||||
bool indexed = false;
|
bool indexed = false;
|
||||||
for (int i = 20; i--;) {
|
for (int i = 20; i--;) {
|
||||||
@ -604,6 +631,16 @@ void MainLoop() {
|
|||||||
did_work = true;
|
did_work = true;
|
||||||
indexed = true;
|
indexed = true;
|
||||||
Main_OnIndexed(&db, &wfiles, &*update);
|
Main_OnIndexed(&db, &wfiles, &*update);
|
||||||
|
if (update->files_def_update) {
|
||||||
|
auto it = path2backlog.find(update->files_def_update->first.path);
|
||||||
|
if (it != path2backlog.end()) {
|
||||||
|
for (auto &message : it->second) {
|
||||||
|
handler.Run(*message);
|
||||||
|
message->backlog_path.clear();
|
||||||
|
}
|
||||||
|
path2backlog.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (did_work) {
|
if (did_work) {
|
||||||
@ -615,7 +652,10 @@ void MainLoop() {
|
|||||||
FreeUnusedMemory();
|
FreeUnusedMemory();
|
||||||
has_indexed = false;
|
has_indexed = false;
|
||||||
}
|
}
|
||||||
main_waiter->Wait(quit, on_indexed, on_request);
|
if (backlog.empty())
|
||||||
|
main_waiter->Wait(quit, on_indexed, on_request);
|
||||||
|
else
|
||||||
|
main_waiter->WaitUntil(backlog[0].deadline, on_indexed, on_request);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ limitations under the License.
|
|||||||
#include "utils.hh"
|
#include "utils.hh"
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@ -76,6 +77,14 @@ struct MultiQueueWaiter {
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename... BaseThreadQueue>
|
||||||
|
void WaitUntil(std::chrono::steady_clock::time_point t,
|
||||||
|
BaseThreadQueue... queues) {
|
||||||
|
MultiQueueLock<BaseThreadQueue...> l(queues...);
|
||||||
|
if (!HasState({queues...}))
|
||||||
|
cv.wait_until(l, t);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
// A threadsafe-queue. http://stackoverflow.com/a/16075550
|
||||||
|
Loading…
Reference in New Issue
Block a user