From fa10f7dc23f8b93c0f9ef3fb5477871a20aaa974 Mon Sep 17 00:00:00 2001 From: Yong He Date: Wed, 1 Jun 2022 17:36:44 -0700 Subject: Add language server daemon. (#2251) * Add language server daemon. * Fix. Co-authored-by: Yong He Co-authored-by: jsmall-nvidia Co-authored-by: Theresa Foley <10618364+tangent-vector@users.noreply.github.com> --- tools/slangd/language-server.cpp | 184 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 tools/slangd/language-server.cpp (limited to 'tools/slangd/language-server.cpp') diff --git a/tools/slangd/language-server.cpp b/tools/slangd/language-server.cpp new file mode 100644 index 000000000..7cb744ecd --- /dev/null +++ b/tools/slangd/language-server.cpp @@ -0,0 +1,184 @@ +// language-server.cpp + +// This file implements the language server for Slang, conforming to the Language Server Protocol. +// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/ + + +#include +#include +#include +#include + +#include "../../source/core/slang-secure-crt.h" +#include "../../slang-com-helper.h" + +#include "language-server-protocol.h" +#include "language-server.h" + +namespace Slang +{ +using namespace LanguageServerProtocol; + +SlangResult LanguageServer::init(const InitializeParams& args) +{ + SLANG_RETURN_ON_FAIL(m_connection->initWithStdStreams()); + m_workspaceFolders = args.workspaceFolders; + return SLANG_OK; +} + +slang::IGlobalSession* LanguageServer::getOrCreateGlobalSession() +{ + if (!m_session) + { + // Just create the global session in the regular way if there isn't one set + if (SLANG_FAILED(slang_createGlobalSession(SLANG_API_VERSION, m_session.writeRef()))) + { + return nullptr; + } + } + + return m_session; +} + +SlangResult LanguageServer::_executeSingle() +{ + // If we don't have a message, we can quit for now + if (!m_connection->hasMessage()) + { + return SLANG_OK; + } + + const JSONRPCMessageType msgType = m_connection->getMessageType(); + + switch (msgType) + { + case JSONRPCMessageType::Call: + { + JSONRPCCall call; + SLANG_RETURN_ON_FAIL(m_connection->getRPCOrSendError(&call)); + + // Do different things + if (call.method == ExitParams::methodName) + { + m_quit = true; + return SLANG_OK; + } + else if (call.method == ShutdownParams::methodName) + { + m_connection->sendResult(NullResponse::get(), call.id); + return SLANG_OK; + } + else if (call.method == InitializeParams::methodName) + { + InitializeParams args = {}; + SLANG_RETURN_ON_FAIL( + m_connection->toNativeArgsOrSendError(call.params, &args, call.id)); + + init(args); + + InitializeResult result = {}; + result.serverInfo.name = "SlangLanguageServer"; + result.serverInfo.version = "1.0"; + result.capabilities.positionEncoding = "utf-8"; + result.capabilities.textDocumentSync.openClose = true; + result.capabilities.textDocumentSync.change = (int)TextDocumentSyncKind::Full; + m_connection->sendResult(&result, call.id); + return SLANG_OK; + } + else if (call.method == DidOpenTextDocumentParams::methodName) + { + DidOpenTextDocumentParams args; + SLANG_RETURN_ON_FAIL( + m_connection->toNativeArgsOrSendError(call.params, &args, call.id)); + return didOpenTextDocument(args); + } + else if (call.method == DidCloseTextDocumentParams::methodName) + { + DidCloseTextDocumentParams args; + SLANG_RETURN_ON_FAIL( + m_connection->toNativeArgsOrSendError(call.params, &args, call.id)); + return didCloseTextDocument(args); + } + else if (call.method == DidChangeTextDocumentParams::methodName) + { + DidChangeTextDocumentParams args; + SLANG_RETURN_ON_FAIL( + m_connection->toNativeArgsOrSendError(call.params, &args, call.id)); + return didChangeTextDocument(args); + } + else if (call.method == "initialized") + { + return SLANG_OK; + } + else + { + return m_connection->sendError(JSONRPC::ErrorCode::MethodNotFound, call.id); + } + } + default: + { + return m_connection->sendError( + JSONRPC::ErrorCode::InvalidRequest, m_connection->getCurrentMessageId()); + } + } + + return SLANG_OK; +} + +SlangResult LanguageServer::didOpenTextDocument(const DidOpenTextDocumentParams& args) +{ + return SLANG_OK; +} +SlangResult LanguageServer::didCloseTextDocument(const DidCloseTextDocumentParams& args) +{ + return SLANG_OK; +} +SlangResult LanguageServer::didChangeTextDocument(const DidChangeTextDocumentParams& args) +{ + return SLANG_OK; +} + +void LanguageServer::update() +{ + +} + +SlangResult LanguageServer::execute() +{ + m_connection = new JSONRPCConnection(); + m_connection->initWithStdStreams(); + while (m_connection->isActive() && !m_quit) + { + // Consume all messages first. + while (m_connection->tryReadMessage() == SLANG_OK) + { + const SlangResult res = _executeSingle(); + } + + // Now we can use this time to reparse user's code, report diagnostics, etc. + update(); + } + + return SLANG_OK; +} + +} // namespace LanguageServer + +int main(int argc, const char* const* argv) +{ + bool isDebug = false; + for (auto i = 1; i < argc; i++) + { + if (Slang::UnownedStringSlice(argv[i]) == "--debug") + { + isDebug = true; + } + } + if (isDebug) + { + std::this_thread::sleep_for(std::chrono::seconds(10)); + } + Slang::LanguageServer server; + SLANG_RETURN_ON_FAIL(server.execute()); + return 0; +} -- cgit v1.2.3