aboutsummaryrefslogtreecommitdiff
path: root/clangd/ProtocolHandlers.cpp
diff options
context:
space:
mode:
authorIlya Biryukov <ibiryukov@google.com>2017-05-16 14:40:30 +0000
committerIlya Biryukov <ibiryukov@google.com>2017-05-16 14:40:30 +0000
commit53c6ae9211549cdf523407b4826a3c6429eec83d (patch)
tree9a3ebcda7bd9ff09fb15e8340be6894bec7ff011 /clangd/ProtocolHandlers.cpp
parent18140c41ccaf948359c9ee26f1ef6e8ec7167946 (diff)
[clangd] Refactor ProtocolHandlers to decouple them from ClangdLSPServer
Summary: A refactoring to decouple ProtocolHandlers and Language Server input parsing loop from the ClangdLSPServer. The input parsing was extracted from `main` to a function(runLanguageServerLoop). ProtocolHandlers now provide an interface to handle various LSP methods, this interface is used by ClangdLSPServer. Methods for code formatting were moved from ProtocolHandlers to ClangdServer. ClangdLSPServer now provides a cleaner interface that only runs Language Server input loop. Reviewers: bkramer, krasimir Reviewed By: krasimir Subscribers: cfe-commits, klimek Tags: #clang-tools-extra Differential Revision: https://reviews.llvm.org/D33201 git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/trunk@303173 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clangd/ProtocolHandlers.cpp')
-rw-r--r--clangd/ProtocolHandlers.cpp339
1 files changed, 175 insertions, 164 deletions
diff --git a/clangd/ProtocolHandlers.cpp b/clangd/ProtocolHandlers.cpp
index 66edee3d..264ef33e 100644
--- a/clangd/ProtocolHandlers.cpp
+++ b/clangd/ProtocolHandlers.cpp
@@ -8,204 +8,215 @@
//===----------------------------------------------------------------------===//
#include "ProtocolHandlers.h"
+#include "ClangdLSPServer.h"
#include "ClangdServer.h"
#include "DraftStore.h"
-#include "clang/Format/Format.h"
-#include "ClangdLSPServer.h"
using namespace clang;
using namespace clangd;
-void TextDocumentDidOpenHandler::handleNotification(
- llvm::yaml::MappingNode *Params) {
- auto DOTDP = DidOpenTextDocumentParams::parse(Params);
- if (!DOTDP) {
- Output.log("Failed to decode DidOpenTextDocumentParams!\n");
- return;
- }
- AST.openDocument(DOTDP->textDocument.uri.file, DOTDP->textDocument.text);
-}
+namespace {
-void TextDocumentDidCloseHandler::handleNotification(
- llvm::yaml::MappingNode *Params) {
- auto DCTDP = DidCloseTextDocumentParams::parse(Params);
- if (!DCTDP) {
- Output.log("Failed to decode DidCloseTextDocumentParams!\n");
- return;
+struct InitializeHandler : Handler {
+ InitializeHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ Callbacks.onInitialize(ID, Output);
}
- AST.closeDocument(DCTDP->textDocument.uri.file);
-}
+private:
+ ProtocolCallbacks &Callbacks;
+};
-void TextDocumentDidChangeHandler::handleNotification(
- llvm::yaml::MappingNode *Params) {
- auto DCTDP = DidChangeTextDocumentParams::parse(Params);
- if (!DCTDP || DCTDP->contentChanges.size() != 1) {
- Output.log("Failed to decode DidChangeTextDocumentParams!\n");
- return;
+struct ShutdownHandler : Handler {
+ ShutdownHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ Callbacks.onShutdown(Output);
}
- // We only support full syncing right now.
- AST.openDocument(DCTDP->textDocument.uri.file, DCTDP->contentChanges[0].text);
-}
-/// Turn a [line, column] pair into an offset in Code.
-static size_t positionToOffset(StringRef Code, Position P) {
- size_t Offset = 0;
- for (int I = 0; I != P.line; ++I) {
- // FIXME: \r\n
- // FIXME: UTF-8
- size_t F = Code.find('\n', Offset);
- if (F == StringRef::npos)
- return 0; // FIXME: Is this reasonable?
- Offset = F + 1;
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+struct TextDocumentDidOpenHandler : Handler {
+ TextDocumentDidOpenHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleNotification(llvm::yaml::MappingNode *Params) override {
+ auto DOTDP = DidOpenTextDocumentParams::parse(Params);
+ if (!DOTDP) {
+ Output.log("Failed to decode DidOpenTextDocumentParams!\n");
+ return;
+ }
+ Callbacks.onDocumentDidOpen(*DOTDP, Output);
}
- return (Offset == 0 ? 0 : (Offset - 1)) + P.character;
-}
-/// Turn an offset in Code into a [line, column] pair.
-static Position offsetToPosition(StringRef Code, size_t Offset) {
- StringRef JustBefore = Code.substr(0, Offset);
- // FIXME: \r\n
- // FIXME: UTF-8
- int Lines = JustBefore.count('\n');
- int Cols = JustBefore.size() - JustBefore.rfind('\n') - 1;
- return {Lines, Cols};
-}
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+struct TextDocumentDidChangeHandler : Handler {
+ TextDocumentDidChangeHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleNotification(llvm::yaml::MappingNode *Params) override {
+ auto DCTDP = DidChangeTextDocumentParams::parse(Params);
+ if (!DCTDP || DCTDP->contentChanges.size() != 1) {
+ Output.log("Failed to decode DidChangeTextDocumentParams!\n");
+ return;
+ }
-template <typename T>
-static std::string replacementsToEdits(StringRef Code, const T &Replacements) {
- // Turn the replacements into the format specified by the Language Server
- // Protocol. Fuse them into one big JSON array.
- std::string Edits;
- for (auto &R : Replacements) {
- Range ReplacementRange = {
- offsetToPosition(Code, R.getOffset()),
- offsetToPosition(Code, R.getOffset() + R.getLength())};
- TextEdit TE = {ReplacementRange, R.getReplacementText()};
- Edits += TextEdit::unparse(TE);
- Edits += ',';
+ Callbacks.onDocumentDidChange(*DCTDP, Output);
}
- if (!Edits.empty())
- Edits.pop_back();
- return Edits;
-}
+private:
+ ProtocolCallbacks &Callbacks;
+};
-static std::string formatCode(StringRef Code, StringRef Filename,
- ArrayRef<tooling::Range> Ranges, StringRef ID) {
- // Call clang-format.
- // FIXME: Don't ignore style.
- format::FormatStyle Style = format::getLLVMStyle();
- tooling::Replacements Replacements =
- format::reformat(Style, Code, Ranges, Filename);
-
- std::string Edits = replacementsToEdits(Code, Replacements);
- return R"({"jsonrpc":"2.0","id":)" + ID.str() +
- R"(,"result":[)" + Edits + R"(]})";
-}
+struct TextDocumentDidCloseHandler : Handler {
+ TextDocumentDidCloseHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleNotification(llvm::yaml::MappingNode *Params) override {
+ auto DCTDP = DidCloseTextDocumentParams::parse(Params);
+ if (!DCTDP) {
+ Output.log("Failed to decode DidCloseTextDocumentParams!\n");
+ return;
+ }
-void TextDocumentRangeFormattingHandler::handleMethod(
- llvm::yaml::MappingNode *Params, StringRef ID) {
- auto DRFP = DocumentRangeFormattingParams::parse(Params);
- if (!DRFP) {
- Output.log("Failed to decode DocumentRangeFormattingParams!\n");
- return;
+ Callbacks.onDocumentDidClose(*DCTDP, Output);
}
- std::string Code = AST.getDocument(DRFP->textDocument.uri.file);
+private:
+ ProtocolCallbacks &Callbacks;
+};
- size_t Begin = positionToOffset(Code, DRFP->range.start);
- size_t Len = positionToOffset(Code, DRFP->range.end) - Begin;
+struct TextDocumentOnTypeFormattingHandler : Handler {
+ TextDocumentOnTypeFormattingHandler(JSONOutput &Output,
+ ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
- writeMessage(formatCode(Code, DRFP->textDocument.uri.file,
- {clang::tooling::Range(Begin, Len)}, ID));
-}
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto DOTFP = DocumentOnTypeFormattingParams::parse(Params);
+ if (!DOTFP) {
+ Output.log("Failed to decode DocumentOnTypeFormattingParams!\n");
+ return;
+ }
-void TextDocumentOnTypeFormattingHandler::handleMethod(
- llvm::yaml::MappingNode *Params, StringRef ID) {
- auto DOTFP = DocumentOnTypeFormattingParams::parse(Params);
- if (!DOTFP) {
- Output.log("Failed to decode DocumentOnTypeFormattingParams!\n");
- return;
+ Callbacks.onDocumentOnTypeFormatting(*DOTFP, ID, Output);
}
- // Look for the previous opening brace from the character position and format
- // starting from there.
- std::string Code = AST.getDocument(DOTFP->textDocument.uri.file);
- size_t CursorPos = positionToOffset(Code, DOTFP->position);
- size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos);
- if (PreviousLBracePos == StringRef::npos)
- PreviousLBracePos = CursorPos;
- size_t Len = 1 + CursorPos - PreviousLBracePos;
-
- writeMessage(formatCode(Code, DOTFP->textDocument.uri.file,
- {clang::tooling::Range(PreviousLBracePos, Len)}, ID));
-}
+private:
+ ProtocolCallbacks &Callbacks;
+};
-void TextDocumentFormattingHandler::handleMethod(
- llvm::yaml::MappingNode *Params, StringRef ID) {
- auto DFP = DocumentFormattingParams::parse(Params);
- if (!DFP) {
- Output.log("Failed to decode DocumentFormattingParams!\n");
- return;
- }
+struct TextDocumentRangeFormattingHandler : Handler {
+ TextDocumentRangeFormattingHandler(JSONOutput &Output,
+ ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
- // Format everything.
- std::string Code = AST.getDocument(DFP->textDocument.uri.file);
- writeMessage(formatCode(Code, DFP->textDocument.uri.file,
- {clang::tooling::Range(0, Code.size())}, ID));
-}
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto DRFP = DocumentRangeFormattingParams::parse(Params);
+ if (!DRFP) {
+ Output.log("Failed to decode DocumentRangeFormattingParams!\n");
+ return;
+ }
-void CodeActionHandler::handleMethod(llvm::yaml::MappingNode *Params,
- StringRef ID) {
- auto CAP = CodeActionParams::parse(Params);
- if (!CAP) {
- Output.log("Failed to decode CodeActionParams!\n");
- return;
+ Callbacks.onDocumentRangeFormatting(*DRFP, ID, Output);
}
- // We provide a code action for each diagnostic at the requested location
- // which has FixIts available.
- std::string Code = AST.getDocument(CAP->textDocument.uri.file);
- std::string Commands;
- for (Diagnostic &D : CAP->context.diagnostics) {
- std::vector<clang::tooling::Replacement> Fixes = AST.getFixIts(CAP->textDocument.uri.file, D);
- std::string Edits = replacementsToEdits(Code, Fixes);
-
- if (!Edits.empty())
- Commands +=
- R"({"title":"Apply FixIt ')" + llvm::yaml::escape(D.message) +
- R"('", "command": "clangd.applyFix", "arguments": [")" +
- llvm::yaml::escape(CAP->textDocument.uri.uri) +
- R"(", [)" + Edits +
- R"(]]},)";
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+struct TextDocumentFormattingHandler : Handler {
+ TextDocumentFormattingHandler(JSONOutput &Output,
+ ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
+
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto DFP = DocumentFormattingParams::parse(Params);
+ if (!DFP) {
+ Output.log("Failed to decode DocumentFormattingParams!\n");
+ return;
+ }
+
+ Callbacks.onDocumentFormatting(*DFP, ID, Output);
}
- if (!Commands.empty())
- Commands.pop_back();
- writeMessage(
- R"({"jsonrpc":"2.0","id":)" + ID.str() +
- R"(, "result": [)" + Commands +
- R"(]})");
-}
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+struct CodeActionHandler : Handler {
+ CodeActionHandler(JSONOutput &Output, ProtocolCallbacks &Callbacks)
+ : Handler(Output), Callbacks(Callbacks) {}
-void CompletionHandler::handleMethod(llvm::yaml::MappingNode *Params,
- StringRef ID) {
- auto TDPP = TextDocumentPositionParams::parse(Params);
- if (!TDPP) {
- Output.log("Failed to decode TextDocumentPositionParams!\n");
- return;
+ void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID) override {
+ auto CAP = CodeActionParams::parse(Params);
+ if (!CAP) {
+ Output.log("Failed to decode CodeActionParams!\n");
+ return;
+ }
+
+ Callbacks.onCodeAction(*CAP, ID, Output);
}
- auto Items = AST.codeComplete(TDPP->textDocument.uri.file, Position{TDPP->position.line,
- TDPP->position.character});
- std::string Completions;
- for (const auto &Item : Items) {
- Completions += CompletionItem::unparse(Item);
- Completions += ",";
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+struct CompletionHandler : Handler {
+ CompletionHandler(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.onCompletion(*TDPP, ID, Output);
}
- if (!Completions.empty())
- Completions.pop_back();
- writeMessage(
- R"({"jsonrpc":"2.0","id":)" + ID.str() +
- R"(,"result":[)" + Completions + R"(]})");
+
+private:
+ ProtocolCallbacks &Callbacks;
+};
+
+} // namespace
+
+void clangd::regiterCallbackHandlers(JSONRPCDispatcher &Dispatcher,
+ JSONOutput &Out,
+ ProtocolCallbacks &Callbacks) {
+ Dispatcher.registerHandler(
+ "initialize", llvm::make_unique<InitializeHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "shutdown", llvm::make_unique<ShutdownHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/didOpen",
+ llvm::make_unique<TextDocumentDidOpenHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/didClose",
+ llvm::make_unique<TextDocumentDidCloseHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/didChange",
+ llvm::make_unique<TextDocumentDidChangeHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/rangeFormatting",
+ llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/onTypeFormatting",
+ llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/formatting",
+ llvm::make_unique<TextDocumentFormattingHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/codeAction",
+ llvm::make_unique<CodeActionHandler>(Out, Callbacks));
+ Dispatcher.registerHandler(
+ "textDocument/completion",
+ llvm::make_unique<CompletionHandler>(Out, Callbacks));
}