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};
4041REFLECT_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
4350void VFS::clear () {
@@ -67,7 +74,8 @@ void standaloneInitialize(MessageHandler &, const std::string &root);
6774namespace pipeline {
6875
6976std::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;
7179int64_t tick = 0 ;
7280
7381namespace {
@@ -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 (" \r pending : %5d " , pending );
793+ printf (" \r completed : %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
757805void 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}
0 commit comments