summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.cpp15
-rw-r--r--clang-tools-extra/clangd/ClangdLSPServer.h6
-rw-r--r--clang-tools-extra/clangd/Protocol.cpp7
-rw-r--r--clang-tools-extra/clangd/Protocol.h15
-rw-r--r--clang-tools-extra/clangd/TUScheduler.cpp34
-rw-r--r--clang-tools-extra/clangd/TUScheduler.h2
-rw-r--r--clang-tools-extra/test/clangd/filestatus.test13
7 files changed, 89 insertions, 3 deletions
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index a9d1795d248..012302d132f 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -294,7 +294,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
SupportsCodeAction = Params.capabilities.CodeActionStructure;
SupportsHierarchicalDocumentSymbol =
Params.capabilities.HierarchicalDocumentSymbol;
-
+ SupportFileStatus = Params.initializationOptions.FileStatus;
Reply(json::Object{
{{"capabilities",
json::Object{
@@ -802,6 +802,19 @@ void ClangdLSPServer::onDiagnosticsReady(PathRef File,
});
}
+void ClangdLSPServer::onFileUpdated(PathRef File, const TUStatus &Status) {
+ if (!SupportFileStatus)
+ return;
+ // FIXME: we don't emit "BuildingFile" and `RunningAction`, as these
+ // two statuses are running faster in practice, which leads the UI constantly
+ // changing, and doesn't provide much value. We may want to emit status at a
+ // reasonable time interval (e.g. 0.5s).
+ if (Status.Action.S == TUAction::BuildingFile ||
+ Status.Action.S == TUAction::RunningAction)
+ return;
+ notify("textDocument/clangd.fileStatus", Status.render(File));
+}
+
void ClangdLSPServer::reparseOpenedFiles() {
for (const Path &FilePath : DraftMgr.getActiveFiles())
Server->addDocument(FilePath, *DraftMgr.getDraft(FilePath),
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h
index 8f8b951b654..9063ea2188b 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -52,6 +52,7 @@ public:
private:
// Implement DiagnosticsConsumer.
void onDiagnosticsReady(PathRef File, std::vector<Diag> Diagnostics) override;
+ void onFileUpdated(PathRef File, const TUStatus &Status) override;
// LSP methods. Notifications have signature void(const Params&).
// Calls have signature void(const Params&, Callback<Response>).
@@ -132,11 +133,12 @@ private:
SymbolKindBitset SupportedSymbolKinds;
/// The supported completion item kinds of the client.
CompletionItemKindBitset SupportedCompletionItemKinds;
- // Whether the client supports CodeAction response objects.
+ /// Whether the client supports CodeAction response objects.
bool SupportsCodeAction = false;
/// From capabilities of textDocument/documentSymbol.
bool SupportsHierarchicalDocumentSymbol = false;
-
+ /// Whether the client supports showing file status.
+ bool SupportFileStatus = false;
// Store of the current versions of the open documents.
DraftStore DraftMgr;
diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp
index 550789548cd..3c1fc7f0050 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -716,6 +716,12 @@ json::Value toJSON(const DocumentHighlight &DH) {
};
}
+llvm::json::Value toJSON(const FileStatus &FStatus) {
+ return json::Object{
+ {"uri", FStatus.uri}, {"state", FStatus.state},
+ };
+}
+
raw_ostream &operator<<(raw_ostream &O, const DocumentHighlight &V) {
O << V.range;
if (V.kind == DocumentHighlightKind::Read)
@@ -752,6 +758,7 @@ bool fromJSON(const json::Value &Params, InitializationOptions &Opts) {
fromJSON(Params, Opts.ConfigSettings);
O.map("compilationDatabasePath", Opts.compilationDatabasePath);
O.map("fallbackFlags", Opts.fallbackFlags);
+ O.map("clangdFileStatus", Opts.FileStatus);
return true;
}
diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h
index 76dcf52a87e..94838a8575a 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -397,6 +397,9 @@ struct InitializationOptions {
// the compilation database doesn't describe an opened file.
// The command used will be approximately `clang $FILE $fallbackFlags`.
std::vector<std::string> fallbackFlags;
+
+ /// Clients supports show file status for textDocument/clangd.fileStatus.
+ bool FileStatus = false;
};
bool fromJSON(const llvm::json::Value &, InitializationOptions &);
@@ -973,6 +976,18 @@ struct ReferenceParams : public TextDocumentPositionParams {
};
bool fromJSON(const llvm::json::Value &, ReferenceParams &);
+/// Clangd extension: indicates the current state of the file in clangd,
+/// sent from server via the `textDocument/clangd.fileStatus` notification.
+struct FileStatus {
+ /// The text document's URI.
+ URIForFile uri;
+ /// The human-readable string presents the current state of the file, can be
+ /// shown in the UI (e.g. status bar).
+ std::string state;
+ // FIXME: add detail messages.
+};
+llvm::json::Value toJSON(const FileStatus &FStatus);
+
} // namespace clangd
} // namespace clang
diff --git a/clang-tools-extra/clangd/TUScheduler.cpp b/clang-tools-extra/clangd/TUScheduler.cpp
index 764bc26a4dc..a6260f95676 100644
--- a/clang-tools-extra/clangd/TUScheduler.cpp
+++ b/clang-tools-extra/clangd/TUScheduler.cpp
@@ -729,6 +729,33 @@ bool ASTWorker::blockUntilIdle(Deadline Timeout) const {
return wait(Lock, RequestsCV, Timeout, [&] { return Requests.empty(); });
}
+// Render a TUAction to a user-facing string representation.
+// TUAction represents clangd-internal states, we don't intend to expose them
+// to users (say C++ programmers) directly to avoid confusion, we use terms that
+// are familiar by C++ programmers.
+std::string renderTUAction(const TUAction &Action) {
+ std::string Result;
+ raw_string_ostream OS(Result);
+ switch (Action.S) {
+ case TUAction::Queued:
+ OS << "file is queued";
+ break;
+ case TUAction::RunningAction:
+ OS << "running " << Action.Name;
+ break;
+ case TUAction::BuildingPreamble:
+ OS << "parsing includes";
+ break;
+ case TUAction::BuildingFile:
+ OS << "parsing main file";
+ break;
+ case TUAction::Idle:
+ OS << "idle";
+ break;
+ }
+ return OS.str();
+}
+
} // namespace
unsigned getDefaultAsyncThreadsCount() {
@@ -741,6 +768,13 @@ unsigned getDefaultAsyncThreadsCount() {
return HardwareConcurrency;
}
+FileStatus TUStatus::render(PathRef File) const {
+ FileStatus FStatus;
+ FStatus.uri = URIForFile::canonicalize(File, /*TUPath=*/File);
+ FStatus.state = renderTUAction(Action);
+ return FStatus;
+}
+
struct TUScheduler::FileData {
/// Latest inputs, passed to TUScheduler::update().
std::string Contents;
diff --git a/clang-tools-extra/clangd/TUScheduler.h b/clang-tools-extra/clangd/TUScheduler.h
index cf04c1f992a..33b394ca3e6 100644
--- a/clang-tools-extra/clangd/TUScheduler.h
+++ b/clang-tools-extra/clangd/TUScheduler.h
@@ -77,6 +77,8 @@ struct TUStatus {
/// Indicates whether we reused the prebuilt AST.
bool ReuseAST = false;
};
+ /// Serialize this to an LSP file status item.
+ FileStatus render(PathRef File) const;
TUAction Action;
BuildDetails Details;
diff --git a/clang-tools-extra/test/clangd/filestatus.test b/clang-tools-extra/test/clangd/filestatus.test
new file mode 100644
index 00000000000..c485939b5c5
--- /dev/null
+++ b/clang-tools-extra/test/clangd/filestatus.test
@@ -0,0 +1,13 @@
+# RUN: clangd -lit-test < %s | FileCheck -strict-whitespace %s
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"initializationOptions":{"clangdFileStatus": true},"trace":"off"}}
+---
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"test:///main.cpp","languageId":"cpp","version":1,"text":"int x; int y = x;"}}}
+# CHECK: "method": "textDocument/clangd.fileStatus",
+# CHECK-NEXT: "params": {
+# CHECK-NEXT: "state": "parsing includes",
+# CHECK-NEXT: "uri": "{{.*}}/main.cpp"
+# CHECK-NEXT: }
+---
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
+---
+{"jsonrpc":"2.0","method":"exit"}
OpenPOWER on IntegriCloud