Skip to content

Commit

Permalink
[clangd] Represent Hover result using FormattedString
Browse files Browse the repository at this point in the history
Reviewers: sammccall, kadircet

Reviewed By: kadircet

Subscribers: MaskRay, jkorous, arphaman, kadircet, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D61601

llvm-svn: 361940
  • Loading branch information
ilya-biryukov committed May 29, 2019
1 parent d2042d3 commit f9169d0
Show file tree
Hide file tree
Showing 11 changed files with 319 additions and 95 deletions.
32 changes: 22 additions & 10 deletions clang-tools-extra/clangd/ClangdLSPServer.cpp
Expand Up @@ -8,6 +8,7 @@

#include "ClangdLSPServer.h"
#include "Diagnostics.h"
#include "FormattedString.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "Trace.h"
Expand Down Expand Up @@ -358,6 +359,7 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params,
SupportsHierarchicalDocumentSymbol =
Params.capabilities.HierarchicalDocumentSymbol;
SupportFileStatus = Params.initializationOptions.FileStatus;
HoverContentFormat = Params.capabilities.HoverContentFormat;
llvm::json::Object Result{
{{"capabilities",
llvm::json::Object{
Expand Down Expand Up @@ -843,17 +845,27 @@ void ClangdLSPServer::onHover(const TextDocumentPositionParams &Params,
Callback<llvm::Optional<Hover>> Reply) {
Server->findHover(Params.textDocument.uri.file(), Params.position,
Bind(
[](decltype(Reply) Reply,
llvm::Expected<llvm::Optional<HoverInfo>> HIorErr) {
if (!HIorErr)
return Reply(HIorErr.takeError());
const auto &HI = HIorErr.get();
if (!HI)
[this](decltype(Reply) Reply,
llvm::Expected<llvm::Optional<HoverInfo>> H) {
if (!H)
return Reply(H.takeError());
if (!*H)
return Reply(llvm::None);
Hover H;
H.range = HI->SymRange;
H.contents = HI->render();
return Reply(H);

Hover R;
R.contents.kind = HoverContentFormat;
R.range = (*H)->SymRange;
switch (HoverContentFormat) {
case MarkupKind::PlainText:
R.contents.value =
(*H)->present().renderAsPlainText();
return Reply(std::move(R));
case MarkupKind::Markdown:
R.contents.value =
(*H)->present().renderAsMarkdown();
return Reply(std::move(R));
};
llvm_unreachable("unhandled MarkupKind");
},
std::move(Reply)));
}
Expand Down
5 changes: 4 additions & 1 deletion clang-tools-extra/clangd/ClangdLSPServer.h
Expand Up @@ -154,7 +154,10 @@ class ClangdLSPServer : private DiagnosticsConsumer {
bool SupportsHierarchicalDocumentSymbol = false;
/// Whether the client supports showing file status.
bool SupportFileStatus = false;
// Store of the current versions of the open documents.
/// Which kind of markup should we use in textDocument/hover responses.
MarkupKind HoverContentFormat = MarkupKind::PlainText;

/// Store of the current versions of the open documents.
DraftStore DraftMgr;

// The CDB is created by the "initialize" LSP method.
Expand Down
4 changes: 3 additions & 1 deletion clang-tools-extra/clangd/ClangdServer.cpp
Expand Up @@ -10,11 +10,13 @@
#include "ClangdUnit.h"
#include "CodeComplete.h"
#include "FindSymbols.h"
#include "FormattedString.h"
#include "Headers.h"
#include "Protocol.h"
#include "SourceCode.h"
#include "TUScheduler.h"
#include "Trace.h"
#include "XRefs.h"
#include "index/CanonicalIncludes.h"
#include "index/FileIndex.h"
#include "index/Merge.h"
Expand Down Expand Up @@ -462,7 +464,7 @@ void ClangdServer::findDocumentHighlights(

void ClangdServer::findHover(PathRef File, Position Pos,
Callback<llvm::Optional<HoverInfo>> CB) {
auto Action = [Pos](Callback<llvm::Optional<HoverInfo>> CB, Path File,
auto Action = [Pos](decltype(CB) CB, Path File,
llvm::Expected<InputsAndAST> InpAST) {
if (!InpAST)
return CB(InpAST.takeError());
Expand Down
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/ClangdServer.h
Expand Up @@ -14,6 +14,7 @@
#include "ClangdUnit.h"
#include "CodeComplete.h"
#include "FSProvider.h"
#include "FormattedString.h"
#include "Function.h"
#include "GlobalCompilationDatabase.h"
#include "Protocol.h"
Expand Down
23 changes: 23 additions & 0 deletions clang-tools-extra/clangd/FormattedString.cpp
Expand Up @@ -9,6 +9,7 @@
#include "clang/Basic/CharInfo.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormatVariadic.h"
#include <cstddef>
#include <string>

Expand Down Expand Up @@ -169,5 +170,27 @@ std::string FormattedString::renderAsPlainText() const {
R.pop_back();
return R;
}

std::string FormattedString::renderForTests() const {
std::string R;
for (const auto &C : Chunks) {
switch (C.Kind) {
case ChunkKind::PlainText:
R += "text[" + C.Contents + "]";
break;
case ChunkKind::InlineCodeBlock:
R += "code[" + C.Contents + "]";
break;
case ChunkKind::CodeBlock:
if (!R.empty())
R += "\n";
R += llvm::formatv("codeblock({0}) [\n{1}\n]\n", C.Language, C.Contents);
break;
}
}
while (!R.empty() && isWhitespace(R.back()))
R.pop_back();
return R;
}
} // namespace clangd
} // namespace clang
1 change: 1 addition & 0 deletions clang-tools-extra/clangd/FormattedString.h
Expand Up @@ -35,6 +35,7 @@ class FormattedString {

std::string renderAsMarkdown() const;
std::string renderAsPlainText() const;
std::string renderForTests() const;

private:
enum class ChunkKind {
Expand Down
32 changes: 32 additions & 0 deletions clang-tools-extra/clangd/Protocol.cpp
Expand Up @@ -303,6 +303,17 @@ bool fromJSON(const llvm::json::Value &Params, ClientCapabilities &R) {
DocumentSymbol->getBoolean("hierarchicalDocumentSymbolSupport"))
R.HierarchicalDocumentSymbol = *HierarchicalSupport;
}
if (auto *Hover = TextDocument->getObject("hover")) {
if (auto *ContentFormat = Hover->getArray("contentFormat")) {
for (const auto &Format : *ContentFormat) {
MarkupKind K = MarkupKind::PlainText;
if (fromJSON(Format, K)) {
R.HoverContentFormat = K;
break;
}
}
}
}
}
if (auto *Workspace = O->getObject("workspace")) {
if (auto *Symbol = Workspace->getObject("symbol")) {
Expand Down Expand Up @@ -684,6 +695,27 @@ static llvm::StringRef toTextKind(MarkupKind Kind) {
llvm_unreachable("Invalid MarkupKind");
}

bool fromJSON(const llvm::json::Value &V, MarkupKind &K) {
auto Str = V.getAsString();
if (!Str) {
elog("Failed to parse markup kind: expected a string");
return false;
}
if (*Str == "plaintext")
K = MarkupKind::PlainText;
else if (*Str == "markdown")
K = MarkupKind::Markdown;
else {
elog("Unknown markup kind: {0}", *Str);
return false;
}
return true;
}

llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind K) {
return OS << toTextKind(K);
}

llvm::json::Value toJSON(const MarkupContent &MC) {
if (MC.value.empty())
return nullptr;
Expand Down
17 changes: 12 additions & 5 deletions clang-tools-extra/clangd/Protocol.h
Expand Up @@ -353,6 +353,15 @@ llvm::json::Value toJSON(const OffsetEncoding &);
bool fromJSON(const llvm::json::Value &, OffsetEncoding &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &, OffsetEncoding);

// Describes the content type that a client supports in various result literals
// like `Hover`, `ParameterInfo` or `CompletionItem`.
enum class MarkupKind {
PlainText,
Markdown,
};
bool fromJSON(const llvm::json::Value &, MarkupKind &);
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, MarkupKind);

// This struct doesn't mirror LSP!
// The protocol defines deeply nested structures for client capabilities.
// Instead of mapping them all, this just parses out the bits we care about.
Expand Down Expand Up @@ -391,6 +400,9 @@ struct ClientCapabilities {

/// Supported encodings for LSP character offsets. (clangd extension).
llvm::Optional<std::vector<OffsetEncoding>> offsetEncoding;

/// The content format that should be used for Hover requests.
MarkupKind HoverContentFormat = MarkupKind::PlainText;
};
bool fromJSON(const llvm::json::Value &, ClientCapabilities &);

Expand Down Expand Up @@ -861,11 +873,6 @@ struct CompletionParams : TextDocumentPositionParams {
};
bool fromJSON(const llvm::json::Value &, CompletionParams &);

enum class MarkupKind {
PlainText,
Markdown,
};

struct MarkupContent {
MarkupKind kind = MarkupKind::PlainText;
std::string value;
Expand Down
25 changes: 10 additions & 15 deletions clang-tools-extra/clangd/XRefs.cpp
Expand Up @@ -9,6 +9,7 @@
#include "AST.h"
#include "CodeCompletionStrings.h"
#include "FindSymbols.h"
#include "FormattedString.h"
#include "Logger.h"
#include "Protocol.h"
#include "SourceCode.h"
Expand Down Expand Up @@ -1155,32 +1156,26 @@ getTypeHierarchy(ParsedAST &AST, Position Pos, int ResolveLevels,
return Result;
}

MarkupContent HoverInfo::render() const {
MarkupContent Content;
Content.kind = MarkupKind::PlainText;
std::vector<std::string> Output;

FormattedString HoverInfo::present() const {
FormattedString Output;
if (NamespaceScope) {
llvm::raw_string_ostream Out(Content.value);
Out << "Declared in ";
Output.appendText("Declared in");
// Drop trailing "::".
if (!LocalScope.empty())
Out << *NamespaceScope << llvm::StringRef(LocalScope).drop_back(2);
Output.appendInlineCode(llvm::StringRef(LocalScope).drop_back(2));
else if (NamespaceScope->empty())
Out << "global namespace";
Output.appendInlineCode("global namespace");
else
Out << llvm::StringRef(*NamespaceScope).drop_back(2);
Out << "\n\n";
Output.appendInlineCode(llvm::StringRef(*NamespaceScope).drop_back(2));
}

if (!Definition.empty()) {
Output.push_back(Definition);
Output.appendCodeBlock(Definition);
} else {
// Builtin types
Output.push_back(Name);
Output.appendCodeBlock(Name);
}
Content.value += llvm::join(Output, " ");
return Content;
return Output;
}

llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
Expand Down
5 changes: 3 additions & 2 deletions clang-tools-extra/clangd/XRefs.h
Expand Up @@ -14,6 +14,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_XREFS_H

#include "ClangdUnit.h"
#include "FormattedString.h"
#include "Protocol.h"
#include "index/Index.h"
#include "index/SymbolLocation.h"
Expand Down Expand Up @@ -103,8 +104,8 @@ struct HoverInfo {
/// Set for all templates(function, class, variable).
llvm::Optional<std::vector<Param>> TemplateParameters;

/// Lower to LSP struct.
MarkupContent render() const;
/// Produce a user-readable information.
FormattedString present() const;
};
llvm::raw_ostream &operator<<(llvm::raw_ostream &, const HoverInfo::Param &);
inline bool operator==(const HoverInfo::Param &LHS,
Expand Down

0 comments on commit f9169d0

Please sign in to comment.