ccls/src/lsp.h

388 lines
11 KiB
C
Raw Normal View History

2017-03-05 02:16:23 +00:00
#pragma once
#include "config.h"
2018-03-22 05:01:21 +00:00
#include "method.h"
2017-03-25 20:32:44 +00:00
#include "serializer.h"
#include "utils.h"
#include <iosfwd>
2017-03-05 02:16:23 +00:00
#include <unordered_map>
#define REGISTER_IN_MESSAGE(type) \
static MessageRegistryRegister<type> type##message_handler_instance_;
2017-03-10 07:06:01 +00:00
struct MessageRegistry {
static MessageRegistry* instance_;
static MessageRegistry* instance();
2017-03-05 02:16:23 +00:00
2017-09-22 01:14:57 +00:00
using Allocator =
2018-03-22 05:01:21 +00:00
std::function<void(Reader& visitor, std::unique_ptr<InMessage>*)>;
2017-03-10 07:06:01 +00:00
std::unordered_map<std::string, Allocator> allocators;
2017-03-05 02:16:23 +00:00
2018-03-31 03:16:33 +00:00
std::optional<std::string> ReadMessageFromStdin(
2018-03-22 05:01:21 +00:00
std::unique_ptr<InMessage>* message);
2018-03-31 03:16:33 +00:00
std::optional<std::string> Parse(Reader& visitor,
2018-03-22 05:01:21 +00:00
std::unique_ptr<InMessage>* message);
};
template <typename T>
struct MessageRegistryRegister {
MessageRegistryRegister() {
T dummy;
std::string method_name = dummy.GetMethodType();
MessageRegistry::instance()->allocators[method_name] =
2018-03-22 05:01:21 +00:00
[](Reader& visitor, std::unique_ptr<InMessage>* message) {
*message = std::make_unique<T>();
// Reflect may throw and *message will be partially deserialized.
Reflect(visitor, static_cast<T&>(**message));
};
2017-03-05 02:16:23 +00:00
}
2017-03-10 07:06:01 +00:00
};
2017-03-05 02:16:23 +00:00
2017-04-16 20:43:30 +00:00
struct lsBaseOutMessage {
2017-06-09 06:20:29 +00:00
virtual ~lsBaseOutMessage();
virtual void ReflectWriter(Writer&) = 0;
// Send the message to the language client by writing it to stdout.
void Write(std::ostream& out);
2017-04-16 20:43:30 +00:00
};
2017-03-05 02:16:23 +00:00
2017-09-22 01:14:57 +00:00
template <typename TDerived>
2017-04-16 20:43:30 +00:00
struct lsOutMessage : lsBaseOutMessage {
2017-03-25 21:45:49 +00:00
// All derived types need to reflect on the |jsonrpc| member.
std::string jsonrpc = "2.0";
2017-03-24 07:59:47 +00:00
void ReflectWriter(Writer& writer) override {
Reflect(writer, static_cast<TDerived&>(*this));
2017-03-24 07:59:47 +00:00
}
};
struct lsResponseError {
enum class lsErrorCodes : int {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
serverErrorStart = -32099,
serverErrorEnd = -32000,
ServerNotInitialized = -32002,
UnknownErrorCode = -32001,
RequestCancelled = -32800,
2017-03-24 07:59:47 +00:00
};
lsErrorCodes code;
// Short description.
std::string message;
void Write(Writer& visitor);
2017-03-24 07:59:47 +00:00
};
2017-03-10 07:06:01 +00:00
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
////////////////////////////// PRIMITIVE TYPES //////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
2017-03-05 02:16:23 +00:00
2017-03-10 07:06:01 +00:00
struct lsDocumentUri {
static lsDocumentUri FromPath(const std::string& path);
2017-03-11 08:07:32 +00:00
lsDocumentUri();
bool operator==(const lsDocumentUri& other) const;
2017-03-25 23:58:11 +00:00
void SetPath(const std::string& path);
std::string GetPath() const;
2017-03-05 02:16:23 +00:00
std::string raw_uri;
2017-03-10 07:06:01 +00:00
};
2017-03-16 07:36:49 +00:00
MAKE_HASHABLE(lsDocumentUri, t.raw_uri);
2017-03-05 02:16:23 +00:00
2017-09-22 01:14:57 +00:00
template <typename TVisitor>
2017-03-10 07:06:01 +00:00
void Reflect(TVisitor& visitor, lsDocumentUri& value) {
Reflect(visitor, value.raw_uri);
}
2017-03-05 02:16:23 +00:00
2017-03-10 07:06:01 +00:00
struct lsPosition {
int line = 0;
int character = 0;
2018-04-08 00:10:54 +00:00
bool operator==(const lsPosition& o) const {
return line == o.line && character == o.character;
}
bool operator<(const lsPosition& o) const {
return line != o.line ? line < o.line : character < o.character;
}
std::string ToString() const;
2017-03-10 07:06:01 +00:00
};
2017-03-16 07:36:49 +00:00
MAKE_HASHABLE(lsPosition, t.line, t.character);
2017-03-25 23:58:11 +00:00
MAKE_REFLECT_STRUCT(lsPosition, line, character);
2017-03-05 02:16:23 +00:00
2017-03-10 07:06:01 +00:00
struct lsRange {
lsPosition start;
lsPosition end;
2018-04-08 00:10:54 +00:00
bool operator==(const lsRange& o) const {
return start == o.start && end == o.end;
}
bool operator<(const lsRange& o) const {
return !(start == o.start) ? start < o.start : end < o.end;
}
2017-03-10 07:06:01 +00:00
};
2017-03-16 07:36:49 +00:00
MAKE_HASHABLE(lsRange, t.start, t.end);
2017-03-25 23:58:11 +00:00
MAKE_REFLECT_STRUCT(lsRange, start, end);
2017-03-05 02:16:23 +00:00
2017-03-10 07:06:01 +00:00
struct lsLocation {
lsDocumentUri uri;
lsRange range;
2018-04-08 00:10:54 +00:00
bool operator==(const lsLocation& o) const {
return uri == o.uri && range == o.range;
}
bool operator<(const lsLocation& o) const {
return !(uri.raw_uri == o.uri.raw_uri) ? uri.raw_uri < o.uri.raw_uri
: range < o.range;
}
2017-03-10 07:06:01 +00:00
};
2017-03-25 23:58:11 +00:00
MAKE_HASHABLE(lsLocation, t.uri, t.range);
MAKE_REFLECT_STRUCT(lsLocation, uri, range);
2017-03-05 02:16:23 +00:00
2018-03-07 21:20:31 +00:00
enum class lsSymbolKind : uint8_t {
Unknown = 0,
File = 1,
Module = 2,
Namespace = 3,
Package = 4,
Class = 5,
Method = 6,
Property = 7,
Field = 8,
Constructor = 9,
Enum = 10,
Interface = 11,
Function = 12,
Variable = 13,
Constant = 14,
String = 15,
Number = 16,
Boolean = 17,
Array = 18,
Object = 19,
Key = 20,
Null = 21,
EnumMember = 22,
Struct = 23,
Event = 24,
Operator = 25,
// For C++, this is interpreted as "template parameter" (including
// non-type template parameters).
TypeParameter = 26,
2018-03-31 03:16:33 +00:00
// ccls extensions
2018-03-07 21:20:31 +00:00
// See also https://github.com/Microsoft/language-server-protocol/issues/344
// for new SymbolKind clang/Index/IndexSymbol.h clang::index::SymbolKind
TypeAlias = 252,
Parameter = 253,
StaticMethod = 254,
Macro = 255,
};
MAKE_REFLECT_TYPE_PROXY(lsSymbolKind);
2018-03-31 03:16:33 +00:00
// ccls extension
struct lsLocationEx : lsLocation {
2018-03-31 03:16:33 +00:00
std::optional<std::string_view> containerName;
std::optional<lsSymbolKind> parentKind;
2018-02-25 05:47:51 +00:00
// Avoid circular dependency on symbol.h
2018-03-31 03:16:33 +00:00
std::optional<uint16_t> role;
};
MAKE_REFLECT_STRUCT(lsLocationEx, uri, range, containerName, parentKind, role);
2017-09-22 01:14:57 +00:00
template <typename T>
2017-03-10 07:06:01 +00:00
struct lsCommand {
// Title of the command (ie, 'save')
std::string title;
// Actual command identifier.
std::string command;
2017-03-15 07:14:44 +00:00
// Arguments to run the command with.
// **NOTE** This must be serialized as an array. Use
// MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY.
2017-03-15 07:14:44 +00:00
T arguments;
2017-03-10 07:06:01 +00:00
};
2017-09-22 01:14:57 +00:00
template <typename TVisitor, typename T>
2017-03-15 07:14:44 +00:00
void Reflect(TVisitor& visitor, lsCommand<T>& value) {
REFLECT_MEMBER_START();
2017-03-10 07:06:01 +00:00
REFLECT_MEMBER(title);
REFLECT_MEMBER(command);
REFLECT_MEMBER(arguments);
REFLECT_MEMBER_END();
}
2017-03-05 02:16:23 +00:00
2017-09-22 01:14:57 +00:00
template <typename TData, typename TCommandArguments>
2017-03-15 07:14:44 +00:00
struct lsCodeLens {
// The range in which this code lens is valid. Should only span a single line.
lsRange range;
// The command this code lens represents.
2018-03-31 03:16:33 +00:00
std::optional<lsCommand<TCommandArguments>> command;
2017-03-15 07:14:44 +00:00
// A data entry field that is preserved on a code lens item between
// a code lens and a code lens resolve request.
TData data;
};
2017-09-22 01:14:57 +00:00
template <typename TVisitor, typename TData, typename TCommandArguments>
2017-03-15 07:14:44 +00:00
void Reflect(TVisitor& visitor, lsCodeLens<TData, TCommandArguments>& value) {
REFLECT_MEMBER_START();
2017-03-15 07:14:44 +00:00
REFLECT_MEMBER(range);
REFLECT_MEMBER(command);
REFLECT_MEMBER(data);
REFLECT_MEMBER_END();
}
2017-03-10 07:06:01 +00:00
struct lsTextDocumentIdentifier {
lsDocumentUri uri;
};
2017-03-25 23:58:11 +00:00
MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri);
2017-03-05 02:16:23 +00:00
struct lsVersionedTextDocumentIdentifier {
lsDocumentUri uri;
// The version number of this document. number | null
std::variant<std::monostate, int> version;
lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
};
MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version);
struct lsTextDocumentPositionParams {
// The text document.
lsTextDocumentIdentifier textDocument;
// The position inside the text document.
lsPosition position;
};
MAKE_REFLECT_STRUCT(lsTextDocumentPositionParams, textDocument, position);
2017-05-21 07:37:53 +00:00
struct lsTextEdit {
// The range of the text document to be manipulated. To insert
// text into a document create a range where start === end.
lsRange range;
// The string to be inserted. For delete operations use an
// empty string.
std::string newText;
bool operator==(const lsTextEdit& that);
};
MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
struct lsTextDocumentItem {
// The text document's URI.
lsDocumentUri uri;
// The text document's language identifier.
std::string languageId;
// The version number of this document (it will strictly increase after each
// change, including undo/redo).
int version;
// The content of the opened text document.
std::string text;
};
MAKE_REFLECT_STRUCT(lsTextDocumentItem, uri, languageId, version, text);
struct lsTextDocumentEdit {
// The text document to change.
lsVersionedTextDocumentIdentifier textDocument;
// The edits to be applied.
std::vector<lsTextEdit> edits;
};
MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
struct lsWorkspaceEdit {
// Holds changes to existing resources.
// changes ? : { [uri:string]: TextEdit[]; };
2017-09-22 01:14:57 +00:00
// std::unordered_map<lsDocumentUri, std::vector<lsTextEdit>> changes;
// An array of `TextDocumentEdit`s to express changes to specific a specific
// version of a text document. Whether a client supports versioned document
// edits is expressed via `WorkspaceClientCapabilites.versionedWorkspaceEdit`.
std::vector<lsTextDocumentEdit> documentChanges;
};
MAKE_REFLECT_STRUCT(lsWorkspaceEdit, documentChanges);
struct lsFormattingOptions {
// Size of a tab in spaces.
int tabSize;
// Prefer spaces over tabs.
bool insertSpaces;
};
MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces);
2017-12-01 17:50:39 +00:00
// 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.
2018-03-31 03:16:33 +00:00
// The language identifier is sematically equal to the std::optional language
2017-12-01 17:50:39 +00:00
// 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}
// ```
//
2017-12-01 17:50:39 +00:00
// Note that markdown strings will be sanitized - that means html will be
// escaped.
struct lsMarkedString1 {
std::string_view language;
std::string_view value;
};
using lsMarkedString = std::variant<std::string_view, lsMarkedString1>;
MAKE_REFLECT_STRUCT(lsMarkedString1, language, value);
2017-12-06 04:39:44 +00:00
struct lsTextDocumentContentChangeEvent {
// The range of the document that changed.
2018-03-31 03:16:33 +00:00
std::optional<lsRange> range;
2017-12-06 04:39:44 +00:00
// The length of the range that got replaced.
2018-03-31 03:16:33 +00:00
std::optional<int> rangeLength;
2017-12-06 04:39:44 +00:00
// The new text of the range/document.
std::string text;
2017-03-15 07:14:44 +00:00
};
2017-12-06 04:39:44 +00:00
MAKE_REFLECT_STRUCT(lsTextDocumentContentChangeEvent, range, rangeLength, text);
2017-03-15 07:14:44 +00:00
2017-12-06 04:39:44 +00:00
struct lsTextDocumentDidChangeParams {
lsVersionedTextDocumentIdentifier textDocument;
std::vector<lsTextDocumentContentChangeEvent> contentChanges;
2017-03-10 07:06:01 +00:00
};
2017-12-06 04:39:44 +00:00
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams,
textDocument,
contentChanges);
2017-03-06 08:48:51 +00:00
2017-03-25 21:45:49 +00:00
// Show a message to the user.
2017-09-22 01:14:57 +00:00
enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 };
2018-01-30 00:35:01 +00:00
MAKE_REFLECT_TYPE_PROXY(lsMessageType)
2017-03-25 21:45:49 +00:00
struct Out_ShowLogMessageParams {
2017-03-10 07:06:01 +00:00
lsMessageType type = lsMessageType::Error;
std::string message;
};
2017-03-25 23:58:11 +00:00
MAKE_REFLECT_STRUCT(Out_ShowLogMessageParams, type, message);
2017-03-25 21:45:49 +00:00
struct Out_ShowLogMessage : public lsOutMessage<Out_ShowLogMessage> {
2017-09-22 01:14:57 +00:00
enum class DisplayType { Show, Log };
2017-03-25 21:45:49 +00:00
DisplayType display_type = DisplayType::Show;
2017-03-25 23:58:11 +00:00
std::string method();
2017-03-25 21:45:49 +00:00
Out_ShowLogMessageParams params;
2017-03-10 07:06:01 +00:00
};
2017-09-22 01:14:57 +00:00
template <typename TVisitor>
2017-03-25 21:45:49 +00:00
void Reflect(TVisitor& visitor, Out_ShowLogMessage& value) {
REFLECT_MEMBER_START();
2017-03-25 21:45:49 +00:00
REFLECT_MEMBER(jsonrpc);
2017-05-21 07:43:10 +00:00
std::string method = value.method();
REFLECT_MEMBER2("method", method);
2017-03-25 21:45:49 +00:00
REFLECT_MEMBER(params);
REFLECT_MEMBER_END();
}
struct Out_LocationList : public lsOutMessage<Out_LocationList> {
lsRequestId id;
std::vector<lsLocationEx> result;
};
2017-05-21 07:43:10 +00:00
MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);