2018-08-21 05:27:52 +00:00
|
|
|
/* Copyright 2017-2018 ccls Authors
|
|
|
|
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
you may not use this file except in compliance with the License.
|
|
|
|
You may obtain a copy of the License at
|
|
|
|
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
See the License for the specific language governing permissions and
|
|
|
|
limitations under the License.
|
|
|
|
==============================================================================*/
|
|
|
|
|
2017-03-05 02:16:23 +00:00
|
|
|
#pragma once
|
|
|
|
|
2017-05-21 19:51:15 +00:00
|
|
|
#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"
|
|
|
|
|
2018-02-22 21:50:46 +00:00
|
|
|
#include <iosfwd>
|
2017-03-05 02:16:23 +00:00
|
|
|
#include <unordered_map>
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
#define REGISTER_IN_MESSAGE(type) \
|
2017-12-06 04:05:01 +00:00
|
|
|
static MessageRegistryRegister<type> type##message_handler_instance_;
|
|
|
|
|
2017-03-10 07:06:01 +00:00
|
|
|
struct MessageRegistry {
|
2018-08-09 17:08:14 +00:00
|
|
|
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-08-09 17:08:14 +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-08-09 17:08:14 +00:00
|
|
|
std::optional<std::string>
|
|
|
|
ReadMessageFromStdin(std::unique_ptr<InMessage> *message);
|
|
|
|
std::optional<std::string> Parse(Reader &visitor,
|
|
|
|
std::unique_ptr<InMessage> *message);
|
2017-12-06 04:05:01 +00:00
|
|
|
};
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
template <typename T> struct MessageRegistryRegister {
|
2017-12-06 04:05:01 +00:00
|
|
|
MessageRegistryRegister() {
|
2018-03-22 04:05:25 +00:00
|
|
|
T dummy;
|
|
|
|
std::string method_name = dummy.GetMethodType();
|
2018-01-19 22:31:49 +00:00
|
|
|
MessageRegistry::instance()->allocators[method_name] =
|
2018-08-09 17:08:14 +00:00
|
|
|
[](Reader &visitor, std::unique_ptr<InMessage> *message) {
|
2018-03-10 23:40:27 +00:00
|
|
|
*message = std::make_unique<T>();
|
2018-01-19 22:31:49 +00:00
|
|
|
// Reflect may throw and *message will be partially deserialized.
|
2018-08-09 17:08:14 +00:00
|
|
|
Reflect(visitor, static_cast<T &>(**message));
|
2018-01-19 22:31:49 +00:00
|
|
|
};
|
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();
|
2018-08-09 17:08:14 +00:00
|
|
|
virtual void ReflectWriter(Writer &) = 0;
|
2018-02-22 21:50:46 +00:00
|
|
|
|
|
|
|
// Send the message to the language client by writing it to stdout.
|
2018-08-09 17:08:14 +00:00
|
|
|
void Write(std::ostream &out);
|
2017-04-16 20:43:30 +00:00
|
|
|
};
|
2017-03-05 02:16:23 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
template <typename TDerived> 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
|
|
|
|
2018-08-09 17:08:14 +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,
|
2018-03-02 02:06:48 +00:00
|
|
|
UnknownErrorCode = -32001,
|
|
|
|
RequestCancelled = -32800,
|
2017-03-24 07:59:47 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
lsErrorCodes code;
|
|
|
|
// Short description.
|
|
|
|
std::string message;
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
void Write(Writer &visitor);
|
2017-03-24 07:59:47 +00:00
|
|
|
};
|
|
|
|
|
2018-09-29 08:10:56 +00:00
|
|
|
constexpr std::string_view ccls_xref("ccls.xref");
|
|
|
|
|
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 {
|
2018-08-09 17:08:14 +00:00
|
|
|
static lsDocumentUri FromPath(const std::string &path);
|
2017-03-11 08:07:32 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator==(const lsDocumentUri &other) const;
|
2017-03-25 23:58:11 +00:00
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
void SetPath(const std::string &path);
|
2017-03-26 21:40:34 +00:00
|
|
|
std::string GetPath() const;
|
2017-03-05 02:16:23 +00:00
|
|
|
|
2017-03-25 22:13:19 +00:00
|
|
|
std::string raw_uri;
|
2017-03-10 07:06:01 +00:00
|
|
|
};
|
2017-03-05 02:16:23 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename TVisitor>
|
2018-08-09 17:08:14 +00:00
|
|
|
void Reflect(TVisitor &visitor, lsDocumentUri &value) {
|
2017-03-10 07:06:01 +00:00
|
|
|
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-08-09 17:08:14 +00:00
|
|
|
bool operator==(const lsPosition &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
return line == o.line && character == o.character;
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator<(const lsPosition &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
return line != o.line ? line < o.line : character < o.character;
|
|
|
|
}
|
|
|
|
std::string ToString() const;
|
2017-03-10 07:06:01 +00:00
|
|
|
};
|
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 {
|
2017-03-25 22:13:19 +00:00
|
|
|
lsPosition start;
|
|
|
|
lsPosition end;
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator==(const lsRange &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
return start == o.start && end == o.end;
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator<(const lsRange &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
return !(start == o.start) ? start < o.start : end < o.end;
|
|
|
|
}
|
2017-03-10 07:06:01 +00:00
|
|
|
};
|
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 {
|
2017-03-25 22:13:19 +00:00
|
|
|
lsDocumentUri uri;
|
|
|
|
lsRange range;
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator==(const lsLocation &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
return uri == o.uri && range == o.range;
|
|
|
|
}
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator<(const lsLocation &o) const {
|
2018-04-08 00:10:54 +00:00
|
|
|
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_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-07 03:07:54 +00:00
|
|
|
|
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
|
|
|
|
2017-03-26 06:47:59 +00:00
|
|
|
struct lsVersionedTextDocumentIdentifier {
|
|
|
|
lsDocumentUri uri;
|
2018-01-10 07:57:33 +00:00
|
|
|
// The version number of this document. number | null
|
2018-04-16 19:36:02 +00:00
|
|
|
std::optional<int> version;
|
2017-09-22 02:25:33 +00:00
|
|
|
|
|
|
|
lsTextDocumentIdentifier AsTextDocumentIdentifier() const;
|
2017-03-26 06:47:59 +00:00
|
|
|
};
|
|
|
|
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;
|
|
|
|
|
2018-08-09 17:08:14 +00:00
|
|
|
bool operator==(const lsTextEdit &that);
|
2017-05-21 07:37:53 +00:00
|
|
|
};
|
|
|
|
MAKE_REFLECT_STRUCT(lsTextEdit, range, newText);
|
|
|
|
|
2017-03-26 06:47:59 +00:00
|
|
|
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);
|
|
|
|
|
2017-04-14 08:21:03 +00:00
|
|
|
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;
|
2017-04-14 08:21:03 +00:00
|
|
|
|
|
|
|
// 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);
|
|
|
|
|
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
|
2017-11-30 03:47:29 +00:00
|
|
|
//
|
|
|
|
// 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.
|
2018-04-16 19:36:02 +00:00
|
|
|
struct lsMarkedString {
|
|
|
|
std::optional<std::string> language;
|
|
|
|
std::string value;
|
2017-11-30 03:47:29 +00:00
|
|
|
};
|
2018-08-09 17:08:14 +00:00
|
|
|
void Reflect(Writer &visitor, lsMarkedString &value);
|
2017-11-30 03:47:29 +00:00
|
|
|
|
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
|
|
|
};
|
2018-08-09 17:08:14 +00:00
|
|
|
MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, textDocument,
|
2017-12-06 04:39:44 +00:00
|
|
|
contentChanges);
|
2017-03-06 08:48:51 +00:00
|
|
|
|
2018-10-08 05:02:28 +00:00
|
|
|
struct lsWorkspaceFolder {
|
|
|
|
lsDocumentUri uri;
|
|
|
|
std::string name;
|
|
|
|
};
|
|
|
|
MAKE_REFLECT_STRUCT(lsWorkspaceFolder, uri, name);
|
|
|
|
|
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)
|
2018-04-08 17:32:08 +00:00
|
|
|
|
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);
|
2018-04-08 17:32:08 +00:00
|
|
|
|
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
|
|
|
|
2017-03-25 22:13:19 +00:00
|
|
|
std::string method();
|
2017-03-25 21:45:49 +00:00
|
|
|
Out_ShowLogMessageParams params;
|
2017-03-10 07:06:01 +00:00
|
|
|
};
|
2018-04-08 17:32:08 +00:00
|
|
|
|
2017-09-22 01:14:57 +00:00
|
|
|
template <typename TVisitor>
|
2018-08-09 17:08:14 +00:00
|
|
|
void Reflect(TVisitor &visitor, Out_ShowLogMessage &value) {
|
2018-01-08 04:10:16 +00:00
|
|
|
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();
|
2017-04-21 04:50:31 +00:00
|
|
|
}
|
|
|
|
|
2017-05-07 06:56:04 +00:00
|
|
|
struct Out_LocationList : public lsOutMessage<Out_LocationList> {
|
|
|
|
lsRequestId id;
|
2018-10-04 23:13:30 +00:00
|
|
|
std::vector<lsLocation> result;
|
2017-05-07 06:56:04 +00:00
|
|
|
};
|
2017-05-21 07:43:10 +00:00
|
|
|
MAKE_REFLECT_STRUCT(Out_LocationList, jsonrpc, id, result);
|
2018-10-14 06:22:29 +00:00
|
|
|
|
|
|
|
// Used to identify the language at a file level. The ordering is important, as
|
|
|
|
// a file previously identified as `C`, will be changed to `Cpp` if it
|
|
|
|
// encounters a c++ declaration.
|
|
|
|
enum class LanguageId { Unknown = -1, C = 0, Cpp = 1, ObjC = 2, ObjCpp = 3 };
|
|
|
|
MAKE_REFLECT_TYPE_PROXY(LanguageId);
|