hokein created this revision.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay, 
ioeric, javed.absar, ilya-biryukov.

This is a quick prototype (with hacky implementation).


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D54796

Files:
  clangd/ClangdLSPServer.cpp
  clangd/ClangdLSPServer.h
  clangd/ClangdServer.cpp
  clangd/ClangdServer.h
  clangd/TUScheduler.cpp
  clangd/TUScheduler.h

Index: clangd/TUScheduler.h
===================================================================
--- clangd/TUScheduler.h
+++ clangd/TUScheduler.h
@@ -52,6 +52,27 @@
   unsigned MaxRetainedASTs = 3;
 };
 
+/// Indicates the current status of the file in ClangdServer.
+/// FIXME: should we add error code (e.g. severity)?
+struct FileStatus {
+  enum class State {
+    Unknown,
+    Preparing, // Build system is preparing for the file.
+    Wait,      // The file is waiting in the queue to be processed.
+    Building,  // The file is being built.
+    Ready,     // The file is ready.
+
+    // FIXME: others?
+  };
+
+
+  State S;
+  // A detailed message of the status, which can be shown in the status bar.
+  // This can contain details, e.g. the compile command used to build the file;
+  // whether the preamble/AST is reused.
+  std::string Message;
+};
+
 class ParsingCallbacks {
 public:
   virtual ~ParsingCallbacks() = default;
@@ -101,8 +122,9 @@
   /// Schedule an update for \p File. Adds \p File to a list of tracked files if
   /// \p File was not part of it before.
   /// FIXME(ibiryukov): remove the callback from this function.
-  void update(PathRef File, ParseInputs Inputs, WantDiagnostics WD,
-              llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
+  void update(
+      PathRef File, ParseInputs Inputs, WantDiagnostics WD,
+      llvm::unique_function<void(FileStatus, std::vector<Diag>)> OnUpdated);
 
   /// Remove \p File from the list of tracked files and schedule removal of its
   /// resources.
Index: clangd/TUScheduler.cpp
===================================================================
--- clangd/TUScheduler.cpp
+++ clangd/TUScheduler.cpp
@@ -176,7 +176,7 @@
   ~ASTWorker();
 
   void update(ParseInputs Inputs, WantDiagnostics,
-              llvm::unique_function<void(std::vector<Diag>)> OnUpdated);
+              llvm::unique_function<void(FileStatus, std::vector<Diag>)> OnUpdated);
   void runWithAST(StringRef Name,
                   unique_function<void(Expected<InputsAndAST>)> Action);
   bool blockUntilIdle(Deadline Timeout) const;
@@ -333,8 +333,9 @@
 }
 
 void ASTWorker::update(ParseInputs Inputs, WantDiagnostics WantDiags,
-                       unique_function<void(std::vector<Diag>)> OnUpdated) {
+                       unique_function<void(FileStatus, std::vector<Diag>)> OnUpdated) {
   auto Task = [=](decltype(OnUpdated) OnUpdated) mutable {
+    OnUpdated(FileStatus{FileStatus::State::Building, "Building"}, {});
     // Will be used to check if we can avoid rebuilding the AST.
     bool InputsAreTheSame =
         std::tie(FileInputs.CompileCommand, FileInputs.Contents) ==
@@ -397,6 +398,7 @@
         // current file at this point?
         log("Skipping rebuild of the AST for {0}, inputs are the same.",
             FileName);
+        OnUpdated({FileStatus::State::Ready, "Ready"}, {});
         return;
       }
     }
@@ -417,15 +419,15 @@
     // spam us with updates.
     // Note *AST can still be null if buildAST fails.
     if (*AST) {
-      OnUpdated((*AST)->getDiagnostics());
+      OnUpdated({FileStatus::State::Ready, "Ready"}, (*AST)->getDiagnostics());
       trace::Span Span("Running main AST callback");
       Callbacks.onMainAST(FileName, **AST);
       DiagsWereReported = true;
     }
     // Stash the AST in the cache for further use.
     IdleASTs.put(this, std::move(*AST));
   };
-
+  OnUpdated({FileStatus::State::Wait, "Wait"}, {});
   startTask("Update", Bind(Task, std::move(OnUpdated)), WantDiags);
 }
 
@@ -697,7 +699,7 @@
 
 void TUScheduler::update(PathRef File, ParseInputs Inputs,
                          WantDiagnostics WantDiags,
-                         unique_function<void(std::vector<Diag>)> OnUpdated) {
+                         unique_function<void(FileStatus, std::vector<Diag>)> OnUpdated) {
   std::unique_ptr<FileData> &FD = Files[File];
   if (!FD) {
     // Create a new worker to process the AST-related tasks.
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -43,6 +43,9 @@
   /// Called by ClangdServer when \p Diagnostics for \p File are ready.
   virtual void onDiagnosticsReady(PathRef File,
                                   std::vector<Diag> Diagnostics) = 0;
+
+  /// Called by ClangdServer when the status of file is updated.
+  virtual void onFileUpdated(PathRef File, FileStatus Status) = 0;
 };
 
 /// Manages a collection of source files and derived data (ASTs, indexes),
@@ -229,6 +232,7 @@
   typedef uint64_t DocVersion;
 
   void consumeDiagnostics(PathRef File, DocVersion Version,
+                          FileStatus FS,
                           std::vector<Diag> Diags);
 
   tooling::CompileCommand getCompileCommand(PathRef File);
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -135,14 +135,19 @@
 void ClangdServer::addDocument(PathRef File, StringRef Contents,
                                WantDiagnostics WantDiags) {
   DocVersion Version = ++InternalVersion[File];
+  // FIXME: notify clients if we are using fallback compilation command.
+  FileStatus FS{FileStatus::State::Preparing,
+                "Getting compilation command..."};
+  consumeDiagnostics(File, Version, FS, {});
   ParseInputs Inputs = {getCompileCommand(File), FSProvider.getFileSystem(),
                         Contents.str()};
 
   Path FileStr = File.str();
-  WorkScheduler.update(File, std::move(Inputs), WantDiags,
-                       [this, FileStr, Version](std::vector<Diag> Diags) {
-                         consumeDiagnostics(FileStr, Version, std::move(Diags));
-                       });
+  WorkScheduler.update(
+      File, std::move(Inputs), WantDiags,
+      [this, FileStr, Version](FileStatus FS, std::vector<Diag> Diags) {
+        consumeDiagnostics(FileStr, Version, FS, std::move(Diags));
+      });
 }
 
 void ClangdServer::removeDocument(PathRef File) {
@@ -445,8 +450,9 @@
   WorkScheduler.runWithAST("Hover", File, Bind(Action, std::move(CB)));
 }
 
+// FIXME: this is a **hacky** way to emit FileStatus to client, revisit it.
 void ClangdServer::consumeDiagnostics(PathRef File, DocVersion Version,
-                                      std::vector<Diag> Diags) {
+                                      FileStatus FS, std::vector<Diag> Diags) {
   // We need to serialize access to resulting diagnostics to avoid calling
   // `onDiagnosticsReady` in the wrong order.
   std::lock_guard<std::mutex> DiagsLock(DiagnosticsMutex);
@@ -460,7 +466,10 @@
     return;
   LastReportedDiagsVersion = Version;
 
-  DiagConsumer.onDiagnosticsReady(File, std::move(Diags));
+  if (FS.S == FileStatus::State::Ready)
+    DiagConsumer.onDiagnosticsReady(File, std::move(Diags));
+
+  DiagConsumer.onFileUpdated(File, FS);
 }
 
 tooling::CompileCommand ClangdServer::getCompileCommand(PathRef File) {
Index: clangd/ClangdLSPServer.h
===================================================================
--- clangd/ClangdLSPServer.h
+++ clangd/ClangdLSPServer.h
@@ -52,6 +52,7 @@
 private:
   // Implement DiagnosticsConsumer.
   void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
+  void onFileUpdated(PathRef File, FileStatus FS) override;
 
   // LSP methods. Notifications have signature void(const Params&).
   // Calls have signature void(const Params&, Callback<Response>).
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -781,6 +781,15 @@
          });
 }
 
+ void ClangdLSPServer::onFileUpdated(PathRef File, FileStatus FS) {
+  URIForFile URI(File);
+  notify("window/showMessage",
+         json::Object {
+           {"uri", URI},
+           {"message", FS.Message},
+         });
+ }
+
 void ClangdLSPServer::reparseOpenedFiles() {
   for (const Path &FilePath : DraftMgr.getActiveFiles())
     Server->addDocument(FilePath, *DraftMgr.getDraft(FilePath),
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to