mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-16 16:56:35 +00:00
[clangd] Expose FileStatus to LSP.
Summary: Add an LSP extension "textDocument/clangd.fileStatus" to emit file-status information. Reviewers: ilya-biryukov Subscribers: javed.absar, ioeric, MaskRay, jkorous, arphaman, kadircet, cfe-commits Differential Revision: https://reviews.llvm.org/D55363 llvm-svn: 349768
This commit is contained in:
parent
92e5e36004
commit
b618849e31
@ -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),
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
13
clang-tools-extra/test/clangd/filestatus.test
Normal file
13
clang-tools-extra/test/clangd/filestatus.test
Normal file
@ -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"}
|
Loading…
x
Reference in New Issue
Block a user