mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
Report index status via $/progress
Add WorkDoneProgress to represent WorkDoneProgressBegin/WorkDoneProgressReport/WorkDoneProgressEnd.
This commit is contained in:
parent
468258d641
commit
5108cfafcb
11
src/lsp.hh
11
src/lsp.hh
@ -219,6 +219,17 @@ struct TextDocumentDidChangeParam {
|
|||||||
std::vector<TextDocumentContentChangeEvent> contentChanges;
|
std::vector<TextDocumentContentChangeEvent> contentChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WorkDoneProgress {
|
||||||
|
const char *kind;
|
||||||
|
std::optional<std::string> title;
|
||||||
|
std::optional<std::string> message;
|
||||||
|
std::optional<double> percentage;
|
||||||
|
};
|
||||||
|
struct WorkDoneProgressParam {
|
||||||
|
const char *token;
|
||||||
|
WorkDoneProgress value;
|
||||||
|
};
|
||||||
|
|
||||||
struct WorkspaceFolder {
|
struct WorkspaceFolder {
|
||||||
DocumentUri uri;
|
DocumentUri uri;
|
||||||
std::string name;
|
std::string name;
|
||||||
|
@ -191,6 +191,8 @@ REFLECT_UNDERLYING_B(SymbolKind);
|
|||||||
REFLECT_STRUCT(TextDocumentIdentifier, uri);
|
REFLECT_STRUCT(TextDocumentIdentifier, uri);
|
||||||
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
|
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
|
||||||
REFLECT_STRUCT(TextEdit, range, newText);
|
REFLECT_STRUCT(TextEdit, range, newText);
|
||||||
|
REFLECT_STRUCT(WorkDoneProgress, kind, title, message, percentage);
|
||||||
|
REFLECT_STRUCT(WorkDoneProgressParam, token, value);
|
||||||
REFLECT_STRUCT(DiagnosticRelatedInformation, location, message);
|
REFLECT_STRUCT(DiagnosticRelatedInformation, location, message);
|
||||||
REFLECT_STRUCT(Diagnostic, range, severity, code, source, message,
|
REFLECT_STRUCT(Diagnostic, range, severity, code, source, message,
|
||||||
relatedInformation);
|
relatedInformation);
|
||||||
|
@ -17,14 +17,14 @@ struct Out_cclsInfo {
|
|||||||
int files, funcs, types, vars;
|
int files, funcs, types, vars;
|
||||||
} db;
|
} db;
|
||||||
struct Pipeline {
|
struct Pipeline {
|
||||||
int pendingIndexRequests;
|
int64_t lastIdle, completed, enqueued;
|
||||||
} pipeline;
|
} pipeline;
|
||||||
struct Project {
|
struct Project {
|
||||||
int entries;
|
int entries;
|
||||||
} project;
|
} project;
|
||||||
};
|
};
|
||||||
REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars);
|
REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars);
|
||||||
REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests);
|
REFLECT_STRUCT(Out_cclsInfo::Pipeline, lastIdle, completed, enqueued);
|
||||||
REFLECT_STRUCT(Out_cclsInfo::Project, entries);
|
REFLECT_STRUCT(Out_cclsInfo::Project, entries);
|
||||||
REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project);
|
REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project);
|
||||||
} // namespace
|
} // namespace
|
||||||
@ -35,7 +35,9 @@ void MessageHandler::ccls_info(EmptyParam &, ReplyOnce &reply) {
|
|||||||
result.db.funcs = db->funcs.size();
|
result.db.funcs = db->funcs.size();
|
||||||
result.db.types = db->types.size();
|
result.db.types = db->types.size();
|
||||||
result.db.vars = db->vars.size();
|
result.db.vars = db->vars.size();
|
||||||
result.pipeline.pendingIndexRequests = pipeline::pending_index_requests;
|
result.pipeline.lastIdle = pipeline::stats.last_idle;
|
||||||
|
result.pipeline.completed = pipeline::stats.completed;
|
||||||
|
result.pipeline.enqueued = pipeline::stats.enqueued;
|
||||||
result.project.entries = 0;
|
result.project.entries = 0;
|
||||||
for (auto &[_, folder] : project->root2folder)
|
for (auto &[_, folder] : project->root2folder)
|
||||||
result.project.entries += folder.entries.size();
|
result.project.entries += folder.entries.size();
|
||||||
|
@ -44,7 +44,7 @@ void MessageHandler::textDocument_didOpen(DidOpenTextDocumentParam ¶m) {
|
|||||||
// pending index request.
|
// pending index request.
|
||||||
auto [lang, header] = lookupExtension(path);
|
auto [lang, header] = lookupExtension(path);
|
||||||
if ((lang != LanguageId::Unknown && !header) ||
|
if ((lang != LanguageId::Unknown && !header) ||
|
||||||
!pipeline::pending_index_requests)
|
pipeline::stats.completed == pipeline::stats.enqueued)
|
||||||
pipeline::index(path, {}, IndexMode::Normal, false);
|
pipeline::index(path, {}, IndexMode::Normal, false);
|
||||||
if (header)
|
if (header)
|
||||||
project->indexRelated(path);
|
project->indexRelated(path);
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <llvm/Support/Threading.h>
|
#include <llvm/Support/Threading.h>
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <shared_mutex>
|
#include <shared_mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
@ -38,6 +39,12 @@ struct PublishDiagnosticParam {
|
|||||||
std::vector<Diagnostic> diagnostics;
|
std::vector<Diagnostic> diagnostics;
|
||||||
};
|
};
|
||||||
REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics);
|
REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics);
|
||||||
|
|
||||||
|
constexpr char index_progress_token[] = "index";
|
||||||
|
struct WorkDoneProgressCreateParam {
|
||||||
|
const char *token = index_progress_token;
|
||||||
|
};
|
||||||
|
REFLECT_STRUCT(WorkDoneProgressCreateParam, token);
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void VFS::clear() {
|
void VFS::clear() {
|
||||||
@ -67,7 +74,8 @@ void standaloneInitialize(MessageHandler &, const std::string &root);
|
|||||||
namespace pipeline {
|
namespace pipeline {
|
||||||
|
|
||||||
std::atomic<bool> g_quit;
|
std::atomic<bool> g_quit;
|
||||||
std::atomic<int64_t> loaded_ts{0}, pending_index_requests{0}, request_id{0};
|
std::atomic<int64_t> loaded_ts{0}, request_id{0};
|
||||||
|
IndexStats stats;
|
||||||
int64_t tick = 0;
|
int64_t tick = 0;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@ -195,9 +203,6 @@ bool indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
|
|||||||
return false;
|
return false;
|
||||||
auto &request = *opt_request;
|
auto &request = *opt_request;
|
||||||
bool loud = request.mode != IndexMode::OnChange;
|
bool loud = request.mode != IndexMode::OnChange;
|
||||||
struct RAII {
|
|
||||||
~RAII() { pending_index_requests--; }
|
|
||||||
} raii;
|
|
||||||
|
|
||||||
// Dummy one to trigger refresh semantic highlight.
|
// Dummy one to trigger refresh semantic highlight.
|
||||||
if (request.path.empty()) {
|
if (request.path.empty()) {
|
||||||
@ -207,6 +212,9 @@ bool indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct RAII {
|
||||||
|
~RAII() { stats.completed++; }
|
||||||
|
} raii;
|
||||||
if (!matcher.matches(request.path)) {
|
if (!matcher.matches(request.path)) {
|
||||||
LOG_IF_S(INFO, loud) << "skip " << request.path;
|
LOG_IF_S(INFO, loud) << "skip " << request.path;
|
||||||
return false;
|
return false;
|
||||||
@ -643,7 +651,9 @@ void mainLoop() {
|
|||||||
handler.manager = &manager;
|
handler.manager = &manager;
|
||||||
handler.include_complete = &include_complete;
|
handler.include_complete = &include_complete;
|
||||||
|
|
||||||
|
bool work_done_created = false, in_progress = false;
|
||||||
bool has_indexed = false;
|
bool has_indexed = false;
|
||||||
|
int64_t last_completed = 0;
|
||||||
std::deque<InMessage> backlog;
|
std::deque<InMessage> backlog;
|
||||||
StringMap<std::deque<InMessage *>> path2backlog;
|
StringMap<std::deque<InMessage *>> path2backlog;
|
||||||
while (true) {
|
while (true) {
|
||||||
@ -693,6 +703,45 @@ void mainLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int64_t completed = stats.completed.load(std::memory_order_relaxed);
|
||||||
|
if (completed != last_completed) {
|
||||||
|
if (!work_done_created) {
|
||||||
|
WorkDoneProgressCreateParam param;
|
||||||
|
request("window/workDoneProgress/create", param);
|
||||||
|
work_done_created = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t enqueued = stats.enqueued.load(std::memory_order_relaxed);
|
||||||
|
if (completed != enqueued) {
|
||||||
|
if (!in_progress) {
|
||||||
|
WorkDoneProgressParam param;
|
||||||
|
param.token = index_progress_token;
|
||||||
|
param.value.kind = "begin";
|
||||||
|
param.value.title = "indexing";
|
||||||
|
notify("$/progress", param);
|
||||||
|
in_progress = true;
|
||||||
|
}
|
||||||
|
int64_t last_idle = stats.last_idle.load(std::memory_order_relaxed);
|
||||||
|
WorkDoneProgressParam param;
|
||||||
|
param.token = index_progress_token;
|
||||||
|
param.value.kind = "report";
|
||||||
|
param.value.message =
|
||||||
|
(Twine(completed - last_idle) + "/" + Twine(enqueued - last_idle))
|
||||||
|
.str();
|
||||||
|
param.value.percentage =
|
||||||
|
100.0 * (completed - last_idle) / (enqueued - last_idle);
|
||||||
|
notify("$/progress", param);
|
||||||
|
} else if (in_progress) {
|
||||||
|
stats.last_idle.store(enqueued, std::memory_order_relaxed);
|
||||||
|
WorkDoneProgressParam param;
|
||||||
|
param.token = index_progress_token;
|
||||||
|
param.value.kind = "end";
|
||||||
|
notify("$/progress", param);
|
||||||
|
in_progress = false;
|
||||||
|
}
|
||||||
|
last_completed = completed;
|
||||||
|
}
|
||||||
|
|
||||||
if (did_work) {
|
if (did_work) {
|
||||||
has_indexed |= indexed;
|
has_indexed |= indexed;
|
||||||
if (g_quit.load(std::memory_order_relaxed))
|
if (g_quit.load(std::memory_order_relaxed))
|
||||||
@ -736,16 +785,16 @@ void standalone(const std::string &root) {
|
|||||||
int entries = 0;
|
int entries = 0;
|
||||||
for (auto &[_, folder] : project.root2folder)
|
for (auto &[_, folder] : project.root2folder)
|
||||||
entries += folder.entries.size();
|
entries += folder.entries.size();
|
||||||
printf("entries: %5d\n", entries);
|
printf("entries: %4d\n", entries);
|
||||||
}
|
}
|
||||||
while (1) {
|
while (1) {
|
||||||
(void)on_indexed->dequeueAll();
|
(void)on_indexed->dequeueAll();
|
||||||
int pending = pending_index_requests;
|
int64_t enqueued = stats.enqueued, completed = stats.completed;
|
||||||
if (tty) {
|
if (tty) {
|
||||||
printf("\rpending: %5d", pending);
|
printf("\rcompleted: %4" PRId64 "/%" PRId64, completed, enqueued);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
if (!pending)
|
if (completed == enqueued)
|
||||||
break;
|
break;
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||||
}
|
}
|
||||||
@ -756,7 +805,8 @@ void standalone(const std::string &root) {
|
|||||||
|
|
||||||
void index(const std::string &path, const std::vector<const char *> &args,
|
void index(const std::string &path, const std::vector<const char *> &args,
|
||||||
IndexMode mode, bool must_exist, RequestId id) {
|
IndexMode mode, bool must_exist, RequestId id) {
|
||||||
pending_index_requests++;
|
if (!path.empty())
|
||||||
|
stats.enqueued++;
|
||||||
index_request->pushBack({path, args, mode, must_exist, std::move(id)},
|
index_request->pushBack({path, args, mode, must_exist, std::move(id)},
|
||||||
mode != IndexMode::Background);
|
mode != IndexMode::Background);
|
||||||
}
|
}
|
||||||
|
@ -39,9 +39,14 @@ enum class IndexMode {
|
|||||||
Normal,
|
Normal,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct IndexStats {
|
||||||
|
std::atomic<int64_t> last_idle, completed, enqueued;
|
||||||
|
};
|
||||||
|
|
||||||
namespace pipeline {
|
namespace pipeline {
|
||||||
extern std::atomic<bool> g_quit;
|
extern std::atomic<bool> g_quit;
|
||||||
extern std::atomic<int64_t> loaded_ts, pending_index_requests;
|
extern std::atomic<int64_t> loaded_ts;
|
||||||
|
extern IndexStats stats;
|
||||||
extern int64_t tick;
|
extern int64_t tick;
|
||||||
|
|
||||||
void threadEnter();
|
void threadEnter();
|
||||||
|
Loading…
Reference in New Issue
Block a user