Nebiroth updated this revision to Diff 108997.
Nebiroth added a comment.
Implemention of Code Hover as described in LSP definition.
Removed unintentional changes to formatting.
Removed file id field in Location struct.
https://reviews.llvm.org/D35894
Files:
clangd/ClangdLSPServer.cpp
clangd/ClangdServer.cpp
clangd/ClangdServer.h
clangd/ClangdUnit.h
clangd/Protocol.cpp
clangd/Protocol.h
clangd/ProtocolHandlers.cpp
clangd/ProtocolHandlers.h
clangd/clients/clangd-vscode/src/extension.ts
test/clangd/hover.test
Index: test/clangd/hover.test
===================================================================
--- /dev/null
+++ test/clangd/hover.test
@@ -0,0 +1,26 @@
+# RUN: clangd -run-synchronously < %s | FileCheck %s
+# It is absolutely vital that this file has CRLF line endings.
+#
+Content-Length: 125
+
+{"jsonrpc":"2.0","id":0,"method":"initialize","params":{"processId":123,"rootPath":"clangd","capabilities":{},"trace":"off"}}
+
+Content-Length: 172
+
+{"jsonrpc":"2.0","method":"textDocument/didOpen","params":{"textDocument":{"uri":"file:///main.cpp","languageId":"cpp","version":1,"text":"int main() {\nint a;\na;\n}\n"}}}
+
+Content-Length: 143
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":0,"character":5}}}
+# Go to local variable
+# CHECK: {"jsonrpc":"2.0","id":1,"result":{"contents": {"language": "C++", "value": "int main() {\nint a;\na;\n}"}, "range": {"start": {"line": 0, "character": 0}, "end": {"line": 3, "character": 1}}}}
+
+Content-Length: 143
+
+{"jsonrpc":"2.0","id":1,"method":"textDocument/hover","params":{"textDocument":{"uri":"file:///main.cpp"},"position":{"line":1,"character":5}}}
+# Go to local variable
+# CHECK: {"jsonrpc":"2.0","id":1,"result":{"contents": {"language": "C++", "value": "int a"}, "range": {"start": {"line": 1, "character": 0}, "end": {"line": 1, "character": 5}}}}
+
+Content-Length: 44
+
+{"jsonrpc":"2.0","id":3,"method":"shutdown"}
Index: clangd/clients/clangd-vscode/src/extension.ts
===================================================================
--- clangd/clients/clangd-vscode/src/extension.ts
+++ clangd/clients/clangd-vscode/src/extension.ts
@@ -1,5 +1,6 @@
import * as vscode from 'vscode';
import * as vscodelc from 'vscode-languageclient';
+import * as vscodejsonrpc from 'vscode-jsonrpc';
/**
* Method to get workspace configuration option
Index: clangd/ProtocolHandlers.h
===================================================================
--- clangd/ProtocolHandlers.h
+++ clangd/ProtocolHandlers.h
@@ -48,6 +48,8 @@
JSONOutput &Out) = 0;
virtual void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) = 0;
+ virtual void onCodeHover(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) = 0;
};
void regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher, JSONOutput &Out,
Index: clangd/ProtocolHandlers.cpp
===================================================================
--- clangd/ProtocolHandlers.cpp
+++ clangd/ProtocolHandlers.cpp
@@ -204,6 +204,24 @@
ProtocolCallbacks &Callbacks;
};
+struct CodeHoverHandler : Handler {
+ CodeHoverHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto TDPP = TextDocumentPositionParams::parse(Params);
+ if (!TDPP) {
+ Output.log("Failed to decode TextDocumentPositionParams!\n");
+ return;
+ }
+
+ Callbacks.onCodeHover(*TDPP, ID, Output);
+ }
+
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
} // namespace
void clangd::regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher,
@@ -239,4 +257,7 @@
llvm::make_unique<CompletionHandler>(Out, Callbacks));
Dispatcher.registerHandler("textDocument/definition",
llvm::make_unique<GotoDefinitionHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/hover",
+ llvm::make_unique<CodeHoverHandler>(Out, Callbacks));
}
Index: clangd/Protocol.h
===================================================================
--- clangd/Protocol.h
+++ clangd/Protocol.h
@@ -23,6 +23,7 @@
#include "llvm/ADT/Optional.h"
#include "llvm/Support/YAMLParser.h"
+#include "clang/Basic/SourceLocation.h"
#include <string>
#include <vector>
@@ -304,7 +305,59 @@
parse(llvm::yaml::MappingNode *Params);
};
-/// The kind of a completion entry.
+struct MarkedString {
+ /**
+ * MarkedString can be used to render human readable text. It is either a
+ * markdown string
+ * or a code-block that provides a language and a code snippet. The language
+ * identifier
+ * is sematically equal to the optional language identifier in fenced code
+ * blocks in GitHub
+ * issues. See
+ * https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
+ *
+ * The pair of a language and a value is an equivalent to markdown:
+ * ```${language}
+ * ${value}
+ * ```
+ *
+ * Note that markdown strings will be sanitized - that means html will be
+ * escaped.
+ */
+
+ MarkedString(std::string markdown)
+ : markdownString(markdown), codeBlockLanguage(""), codeBlockValue("") {}
+
+ MarkedString(std::string blockLanguage, std::string blockValue)
+ : markdownString(""), codeBlockLanguage(blockLanguage),
+ codeBlockValue(blockValue) {}
+
+ std::string markdownString;
+ std::string codeBlockLanguage;
+ std::string codeBlockValue;
+
+ static std::string unparse(const MarkedString &MS);
+};
+
+struct Hover {
+
+ Hover(MarkedString ms, Range r) : contents(ms), range(r) {}
+
+ /**
+ * The hover's content
+ */
+ MarkedString contents;
+
+ /**
+ * An optional range is a range inside a text document
+ * that is used to visualize a hover, e.g. by changing the background color.
+ */
+ Range range;
+
+ static std::string unparse(const Hover &H);
+};
+
+/// The kind of a completion entry.std::string*
enum class CompletionItemKind {
Missing = 0,
Text = 1,
Index: clangd/Protocol.cpp
===================================================================
--- clangd/Protocol.cpp
+++ clangd/Protocol.cpp
@@ -746,3 +746,26 @@
Result.back() = '}';
return Result;
}
+
+std::string Hover::unparse(const Hover &H) {
+ std::string Result;
+ llvm::raw_string_ostream(Result) << llvm::format(
+ R"({"contents": %s, "range": %s})", MarkedString::unparse(H.contents).c_str(),
+ Range::unparse(H.range).c_str());
+ return Result;
+}
+
+std::string MarkedString::unparse(const MarkedString &MS) {
+ std::string Result;
+ if (MS.markdownString != "")
+ {
+ llvm::raw_string_ostream(Result) << llvm::format(R"({"markdown": "%s"})", MS.markdownString.c_str());
+ }
+ else
+ {
+
+ llvm::raw_string_ostream(Result) << llvm::format(R"({"language": "%s", "value": "%s"})", (llvm::yaml::escape(MS.codeBlockLanguage)).c_str(), (llvm::yaml::escape(MS.codeBlockValue)).c_str());
+ }
+
+ return Result;
+}
Index: clangd/ClangdUnit.h
===================================================================
--- clangd/ClangdUnit.h
+++ clangd/ClangdUnit.h
@@ -69,6 +69,24 @@
/// unserialized Decls, so use with care.
void dumpAST(llvm::raw_ostream &OS) const;
+ Hover getHover(Location L){
+
+ MarkedString MS = MarkedString("", "");
+ Range R;
+ const FileEntry *FE = Unit->getFileManager().getFile(L.uri.file);
+ FileID id = Unit->getSourceManager().translateFile(FE);
+ StringRef ref = Unit->getSourceManager().getBufferData(id);
+ start = Unit->getSourceManager().getFileOffset(Unit->getSourceManager().translateFileLineCol(FE, L.range.start.line + 1, L.range.start.character + 1));
+ end = Unit->getSourceManager().getFileOffset(Unit->getSourceManager().translateFileLineCol(FE, L.range.end.line + 1, L.range.end.character + 1));
+ ref = ref.slice(start, end);
+ MS = MarkedString("C++", ref);
+ R = L.range;
+ Hover H(MS, R);
+ return H;
+ }
+ unsigned start;
+ unsigned end;
+
private:
Path FileName;
std::unique_ptr<ASTUnit> Unit;
Index: clangd/ClangdServer.h
===================================================================
--- clangd/ClangdServer.h
+++ clangd/ClangdServer.h
@@ -182,6 +182,8 @@
/// Get definition of symbol at a specified \p Line and \p Column in \p File.
Tagged<std::vector<Location>> findDefinitions(PathRef File, Position Pos);
+ Tagged<Hover> findHover(PathRef File, Position Pos);
+
/// Run formatting for \p Rng inside \p File.
std::vector<tooling::Replacement> formatRange(PathRef File, Range Rng);
/// Run formatting for the whole \p File.
Index: clangd/ClangdServer.cpp
===================================================================
--- clangd/ClangdServer.cpp
+++ clangd/ClangdServer.cpp
@@ -8,6 +8,7 @@
//===-------------------------------------------------------------------===//
#include "ClangdServer.h"
+#include "Protocol.h"
#include "clang/Format/Format.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
@@ -286,3 +287,28 @@
});
return make_tagged(std::move(Result), TaggedFS.Tag);
}
+
+Tagged<Hover> ClangdServer::findHover(PathRef File, Position Pos) {
+ auto FileContents = DraftMgr.getDraft(File);
+ assert(FileContents.Draft &&
+ "findHover is called for non-added document");
+
+
+ MarkedString MS = MarkedString("", "");
+ Range R;
+ Hover FinalHover(MS, R);
+ auto TaggedFS = FSProvider.getTaggedFileSystem(File);
+ Units.runOnUnit(File, *FileContents.Draft, ResourceDir, CDB, PCHs,
+ TaggedFS.Value, [&](ClangdUnit &Unit) {
+ std::vector<Location> Result = Unit.findDefinitions(Pos);
+ if (!Result.empty()) {
+ Location FoundLocation = Result[0];
+ FinalHover = Unit.getHover(FoundLocation);
+ }
+ });
+
+
+ return make_tagged(std::move(FinalHover), TaggedFS.Tag);
+}
+
+
Index: clangd/ClangdLSPServer.cpp
===================================================================
--- clangd/ClangdLSPServer.cpp
+++ clangd/ClangdLSPServer.cpp
@@ -71,6 +71,8 @@
JSONOutput &Out) override;
void onGoToDefinition(TextDocumentPositionParams Params, StringRef ID,
JSONOutput &Out) override;
+ void onCodeHover(TextDocumentPositionParams Params, StringRef ID,
+ JSONOutput &Out) override;
private:
ClangdLSPServer &LangServer;
@@ -87,7 +89,8 @@
"documentOnTypeFormattingProvider": {"firstTriggerCharacter":"}","moreTriggerCharacter":[]},
"codeActionProvider": true,
"completionProvider": {"resolveProvider": false, "triggerCharacters": [".",">"]},
- "definitionProvider": true
+ "definitionProvider": true,
+ "hoverProvider": true
}}})");
}
@@ -216,6 +219,18 @@
R"(,"result":[)" + Locations + R"(]})");
}
+void ClangdLSPServer::LSPProtocolCallbacks::onCodeHover(
+ TextDocumentPositionParams Params, StringRef ID, JSONOutput &Out) {
+
+ Hover H = LangServer.Server.findHover(
+ Params.textDocument.uri.file,
+ Position{Params.position.line, Params.position.character}) .Value;
+
+ Out.writeMessage(
+ R"({"jsonrpc":"2.0","id":)" + ID.str() +
+ R"(,"result":)" + Hover::unparse(H) + R"(})");
+}
+
ClangdLSPServer::ClangdLSPServer(JSONOutput &Out, bool RunSynchronously)
: Out(Out), DiagConsumer(*this),
Server(CDB, DiagConsumer, FSProvider, RunSynchronously) {}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits