Skip to content

Commit cb06cf1

Browse files
committed
Report index status via $/progress
Add WorkDoneProgress to represent WorkDoneProgressBegin/WorkDoneProgressReport/WorkDoneProgressEnd.
1 parent 468258d commit cb06cf1

File tree

6 files changed

+83
-14
lines changed

6 files changed

+83
-14
lines changed

src/lsp.hh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,17 @@ struct TextDocumentDidChangeParam {
219219
std::vector<TextDocumentContentChangeEvent> contentChanges;
220220
};
221221

222+
struct WorkDoneProgress {
223+
const char *kind;
224+
std::optional<std::string> title;
225+
std::optional<std::string> message;
226+
std::optional<double> percentage;
227+
};
228+
struct WorkDoneProgressParam {
229+
const char *token;
230+
WorkDoneProgress value;
231+
};
232+
222233
struct WorkspaceFolder {
223234
DocumentUri uri;
224235
std::string name;

src/message_handler.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,8 @@ REFLECT_UNDERLYING_B(SymbolKind);
191191
REFLECT_STRUCT(TextDocumentIdentifier, uri);
192192
REFLECT_STRUCT(TextDocumentItem, uri, languageId, version, text);
193193
REFLECT_STRUCT(TextEdit, range, newText);
194+
REFLECT_STRUCT(WorkDoneProgress, kind, title, message, percentage);
195+
REFLECT_STRUCT(WorkDoneProgressParam, token, value);
194196
REFLECT_STRUCT(DiagnosticRelatedInformation, location, message);
195197
REFLECT_STRUCT(Diagnostic, range, severity, code, source, message,
196198
relatedInformation);

src/messages/ccls_info.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,14 @@ struct Out_cclsInfo {
1717
int files, funcs, types, vars;
1818
} db;
1919
struct Pipeline {
20-
int pendingIndexRequests;
20+
int64_t lastIdle, completed, enqueued;
2121
} pipeline;
2222
struct Project {
2323
int entries;
2424
} project;
2525
};
2626
REFLECT_STRUCT(Out_cclsInfo::DB, files, funcs, types, vars);
27-
REFLECT_STRUCT(Out_cclsInfo::Pipeline, pendingIndexRequests);
27+
REFLECT_STRUCT(Out_cclsInfo::Pipeline, lastIdle, completed, enqueued);
2828
REFLECT_STRUCT(Out_cclsInfo::Project, entries);
2929
REFLECT_STRUCT(Out_cclsInfo, db, pipeline, project);
3030
} // namespace
@@ -35,7 +35,9 @@ void MessageHandler::ccls_info(EmptyParam &, ReplyOnce &reply) {
3535
result.db.funcs = db->funcs.size();
3636
result.db.types = db->types.size();
3737
result.db.vars = db->vars.size();
38-
result.pipeline.pendingIndexRequests = pipeline::pending_index_requests;
38+
result.pipeline.lastIdle = pipeline::stats.last_idle;
39+
result.pipeline.completed = pipeline::stats.completed;
40+
result.pipeline.enqueued = pipeline::stats.enqueued;
3941
result.project.entries = 0;
4042
for (auto &[_, folder] : project->root2folder)
4143
result.project.entries += folder.entries.size();

src/messages/textDocument_did.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void MessageHandler::textDocument_didOpen(DidOpenTextDocumentParam &param) {
4444
// pending index request.
4545
auto [lang, header] = lookupExtension(path);
4646
if ((lang != LanguageId::Unknown && !header) ||
47-
!pipeline::pending_index_requests)
47+
pipeline::stats.completed == pipeline::stats.enqueued)
4848
pipeline::index(path, {}, IndexMode::Normal, false);
4949
if (header)
5050
project->indexRelated(path);

src/pipeline.cc

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <llvm/Support/Threading.h>
2323

2424
#include <chrono>
25+
#include <inttypes.h>
2526
#include <mutex>
2627
#include <shared_mutex>
2728
#include <thread>
@@ -38,6 +39,12 @@ struct PublishDiagnosticParam {
3839
std::vector<Diagnostic> diagnostics;
3940
};
4041
REFLECT_STRUCT(PublishDiagnosticParam, uri, diagnostics);
42+
43+
constexpr char index_progress_token[] = "index";
44+
struct WorkDoneProgressCreateParam {
45+
const char *token = index_progress_token;
46+
};
47+
REFLECT_STRUCT(WorkDoneProgressCreateParam, token);
4148
} // namespace
4249

4350
void VFS::clear() {
@@ -67,7 +74,8 @@ void standaloneInitialize(MessageHandler &, const std::string &root);
6774
namespace pipeline {
6875

6976
std::atomic<bool> g_quit;
70-
std::atomic<int64_t> loaded_ts{0}, pending_index_requests{0}, request_id{0};
77+
std::atomic<int64_t> loaded_ts{0}, request_id{0};
78+
IndexStats stats;
7179
int64_t tick = 0;
7280

7381
namespace {
@@ -195,9 +203,6 @@ bool indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
195203
return false;
196204
auto &request = *opt_request;
197205
bool loud = request.mode != IndexMode::OnChange;
198-
struct RAII {
199-
~RAII() { pending_index_requests--; }
200-
} raii;
201206

202207
// Dummy one to trigger refresh semantic highlight.
203208
if (request.path.empty()) {
@@ -207,6 +212,9 @@ bool indexer_Parse(SemaManager *completion, WorkingFiles *wfiles,
207212
return false;
208213
}
209214

215+
struct RAII {
216+
~RAII() { stats.completed++; }
217+
} raii;
210218
if (!matcher.matches(request.path)) {
211219
LOG_IF_S(INFO, loud) << "skip " << request.path;
212220
return false;
@@ -643,7 +651,9 @@ void mainLoop() {
643651
handler.manager = &manager;
644652
handler.include_complete = &include_complete;
645653

654+
bool work_done_created = false, in_progress = false;
646655
bool has_indexed = false;
656+
int64_t last_completed = 0;
647657
std::deque<InMessage> backlog;
648658
StringMap<std::deque<InMessage *>> path2backlog;
649659
while (true) {
@@ -693,6 +703,44 @@ void mainLoop() {
693703
}
694704
}
695705

706+
int64_t completed = stats.completed.load(std::memory_order_relaxed);
707+
if (completed != last_completed) {
708+
if (!work_done_created) {
709+
WorkDoneProgressCreateParam param;
710+
request("window/workDoneProgress/create", param);
711+
work_done_created = true;
712+
}
713+
714+
int64_t enqueued = stats.enqueued.load(std::memory_order_relaxed);
715+
if (completed != enqueued) {
716+
if (!in_progress) {
717+
WorkDoneProgressParam param;
718+
param.token = index_progress_token;
719+
param.value.kind = "begin";
720+
param.value.title = "indexing";
721+
notify("$/progress", param);
722+
in_progress = true;
723+
}
724+
int64_t last_idle = stats.last_idle.load(std::memory_order_relaxed);
725+
WorkDoneProgressParam param;
726+
param.token = index_progress_token;
727+
param.value.kind = "report";
728+
param.value.message =
729+
(Twine(completed - last_idle) + "/" + Twine(enqueued - last_idle))
730+
.str();
731+
param.value.percentage =
732+
100.0 * (completed - last_idle) / (enqueued - last_idle);
733+
notify("$/progress", param);
734+
} else if (in_progress) {
735+
stats.last_idle.store(enqueued, std::memory_order_relaxed);
736+
WorkDoneProgressParam param;
737+
param.token = index_progress_token;
738+
param.value.kind = "end";
739+
notify("$/progress", param);
740+
in_progress = false;
741+
}
742+
}
743+
696744
if (did_work) {
697745
has_indexed |= indexed;
698746
if (g_quit.load(std::memory_order_relaxed))
@@ -736,16 +784,16 @@ void standalone(const std::string &root) {
736784
int entries = 0;
737785
for (auto &[_, folder] : project.root2folder)
738786
entries += folder.entries.size();
739-
printf("entries: %5d\n", entries);
787+
printf("entries: %4d\n", entries);
740788
}
741789
while (1) {
742790
(void)on_indexed->dequeueAll();
743-
int pending = pending_index_requests;
791+
int64_t enqueued = stats.enqueued, completed = stats.completed;
744792
if (tty) {
745-
printf("\rpending: %5d", pending);
793+
printf("\rcompleted: %4" PRId64 "/%" PRId64, completed, enqueued);
746794
fflush(stdout);
747795
}
748-
if (!pending)
796+
if (completed == enqueued)
749797
break;
750798
std::this_thread::sleep_for(std::chrono::milliseconds(100));
751799
}
@@ -756,7 +804,8 @@ void standalone(const std::string &root) {
756804

757805
void index(const std::string &path, const std::vector<const char *> &args,
758806
IndexMode mode, bool must_exist, RequestId id) {
759-
pending_index_requests++;
807+
if (!path.empty())
808+
stats.enqueued++;
760809
index_request->pushBack({path, args, mode, must_exist, std::move(id)},
761810
mode != IndexMode::Background);
762811
}

src/pipeline.hh

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,14 @@ enum class IndexMode {
3939
Normal,
4040
};
4141

42+
struct IndexStats {
43+
std::atomic<int64_t> last_idle, completed, enqueued;
44+
};
45+
4246
namespace pipeline {
4347
extern std::atomic<bool> g_quit;
44-
extern std::atomic<int64_t> loaded_ts, pending_index_requests;
48+
extern std::atomic<int64_t> loaded_ts;
49+
extern IndexStats stats;
4550
extern int64_t tick;
4651

4752
void threadEnter();

0 commit comments

Comments
 (0)