diff options
Diffstat (limited to 'src/shared/lsp/lsptypes.h')
-rw-r--r-- | src/shared/lsp/lsptypes.h | 680 |
1 files changed, 680 insertions, 0 deletions
diff --git a/src/shared/lsp/lsptypes.h b/src/shared/lsp/lsptypes.h new file mode 100644 index 000000000..52e7b95a9 --- /dev/null +++ b/src/shared/lsp/lsptypes.h @@ -0,0 +1,680 @@ +// Copyright (C) 2018 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0 + +#pragma once + +#include "jsonkeys.h" +#include "jsonobject.h" +#include "lsputils.h" +#include "filepath.h" +#include "link.h" + +#include <QJsonObject> +#include <QUrl> +#include <QList> + +#include <optional> +#include <variant> + +namespace lsp { + +class LANGUAGESERVERPROTOCOL_EXPORT DocumentUri : public QUrl +{ +public: + DocumentUri() = default; + using PathMapper = std::function<Utils::FilePath(const Utils::FilePath &)>; + Utils::FilePath toFilePath(const PathMapper &mapToHostPath) const; + + static DocumentUri fromProtocol(const QString &uri); + static DocumentUri fromFilePath(const Utils::FilePath &file, const PathMapper &mapToServerPath); + + operator QJsonValue() const { return QJsonValue(toString()); } + +private: + DocumentUri(const QString &other); + DocumentUri(const Utils::FilePath &other, const PathMapper &mapToServerPath); + + friend class LanguageClientValue<QString>; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT Position : public JsonObject +{ +public: + Position() = default; + Position(int line, int character); + using JsonObject::JsonObject; + + // Line position in a document (zero-based). + int line() const { return typedValue<int>(lineKey); } + void setLine(int line) { insert(lineKey, line); } + + /* + * Character offset on a line in a document (zero-based). Assuming that the line is + * represented as a string, the `character` value represents the gap between the + * `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back to the + * line length. + */ + int character() const { return typedValue<int>(characterKey); } + void setCharacter(int character) { insert(characterKey, character); } + + bool isValid() const override + { return contains(lineKey) && contains(characterKey); } +}; + +inline bool operator<(const Position &first, const Position &second) +{ + return first.line() < second.line() + || (first.line() == second.line() && first.character() < second.character()); +} + +inline bool operator>(const Position &first, const Position &second) +{ + return second < first; +} + +inline bool operator>=(const Position &first, const Position &second) +{ + return !(first < second); +} + +inline bool operator<=(const Position &first, const Position &second) +{ + return !(first > second); +} + +class LANGUAGESERVERPROTOCOL_EXPORT Range : public JsonObject +{ +public: + Range() = default; + Range(const Position &start, const Position &end); + using JsonObject::JsonObject; + + // The range's start position. + Position start() const { return typedValue<Position>(startKey); } + void setStart(const Position &start) { insert(startKey, start); } + + // The range's end position. + Position end() const { return typedValue<Position>(endKey); } + void setEnd(const Position &end) { insert(endKey, end); } + + bool isEmpty() const { return start() == end(); } + bool contains(const Position &pos) const { return start() <= pos && pos <= end(); } + bool contains(const Range &other) const; + bool overlaps(const Range &range) const; + bool isLeftOf(const Range &other) const + { return isEmpty() || other.isEmpty() ? end() < other.start() : end() <= other.start(); } + + bool isValid() const override + { return JsonObject::contains(startKey) && JsonObject::contains(endKey); } +}; + +inline bool operator==(const Range &r1, const Range &r2) +{ + return r1.contains(r2) && r2.contains(r1); +} +inline bool operator!=(const Range &r1, const Range &r2) { return !(r1 == r2); } + +class LANGUAGESERVERPROTOCOL_EXPORT Location : public JsonObject +{ +public: + using JsonObject::JsonObject; + + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + Range range() const { return typedValue<Range>(rangeKey); } + void setRange(const Range &range) { insert(rangeKey, range); } + + Utils::Link toLink(const DocumentUri::PathMapper &mapToHostPath) const; + + bool isValid() const override { return contains(uriKey) && contains(rangeKey); } +}; + +enum class DiagnosticSeverity +{ + Error = 1, + Warning = 2, + Information = 3, + Hint = 4 + +}; + +class LANGUAGESERVERPROTOCOL_EXPORT Diagnostic : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // The range at which the message applies. + Range range() const { return typedValue<Range>(rangeKey); } + void setRange(const Range &range) { insert(rangeKey, range); } + + // The diagnostic's severity. Can be omitted. If omitted it is up to the + // client to interpret diagnostics as error, warning, info or hint. + std::optional<DiagnosticSeverity> severity() const; + void setSeverity(const DiagnosticSeverity &severity) + { insert(severityKey, static_cast<int>(severity)); } + void clearSeverity() { remove(severityKey); } + + // The diagnostic's code, which might appear in the user interface. + using Code = std::variant<int, QString>; + std::optional<Code> code() const; + void setCode(const Code &code); + void clearCode() { remove(codeKey); } + + // A human-readable string describing the source of this + // diagnostic, e.g. 'typescript' or 'super lint'. + std::optional<QString> source() const + { return optionalValue<QString>(sourceKey); } + void setSource(const QString &source) { insert(sourceKey, source); } + void clearSource() { remove(sourceKey); } + + // The diagnostic's message. + QString message() const + { return typedValue<QString>(messageKey); } + void setMessage(const QString &message) { insert(messageKey, message); } + + bool isValid() const override { return contains(rangeKey) && contains(messageKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT Command : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // Title of the command, like `save`. + QString title() const { return typedValue<QString>(titleKey); } + void setTitle(const QString &title) { insert(titleKey, title); } + void clearTitle() { remove(titleKey); } + + // The identifier of the actual command handler. + QString command() const { return typedValue<QString>(commandKey); } + void setCommand(const QString &command) { insert(commandKey, command); } + void clearCommand() { remove(commandKey); } + + // Arguments that the command handler should be invoked with. + std::optional<QJsonArray> arguments() const { return typedValue<QJsonArray>(argumentsKey); } + void setArguments(const QJsonArray &arguments) { insert(argumentsKey, arguments); } + void clearArguments() { remove(argumentsKey); } + + bool isValid() const override { return contains(titleKey) && contains(commandKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT TextEdit : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // The range of the text document to be manipulated. To insert + // text into a document create a range where start === end. + Range range() const { return typedValue<Range>(rangeKey); } + void setRange(const Range &range) { insert(rangeKey, range); } + + // The string to be inserted. For delete operations use an empty string. + QString newText() const { return typedValue<QString>(newTextKey); } + void setNewText(const QString &text) { insert(newTextKey, text); } + + bool isValid() const override + { return contains(rangeKey) && contains(newTextKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentIdentifier : public JsonObject +{ +public: + TextDocumentIdentifier() : TextDocumentIdentifier(DocumentUri()) {} + explicit TextDocumentIdentifier(const DocumentUri &uri) { setUri(uri); } + using JsonObject::JsonObject; + + // The text document's URI. + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + bool isValid() const override { return contains(uriKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT VersionedTextDocumentIdentifier : public TextDocumentIdentifier +{ +public: + using TextDocumentIdentifier::TextDocumentIdentifier; + + /* + * The version number of this document. If a versioned text document identifier + * is sent from the server to the client and the file is not open in the editor + * (the server has not received an open notification before) the server can send + * `null` to indicate that the version is known and the content on disk is the + * truth (as speced with document content ownership) + */ + LanguageClientValue<int> version() const { return clientValue<int>(versionKey); } + void setVersion(LanguageClientValue<int> version) { insert(versionKey, version); } + + bool isValid() const override + { + return TextDocumentIdentifier::isValid() && contains(versionKey); + } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentEdit : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // The text document to change. + VersionedTextDocumentIdentifier textDocument() const + { return typedValue<VersionedTextDocumentIdentifier>(textDocumentKey); } + void setTextDocument(const VersionedTextDocumentIdentifier &textDocument) + { insert(textDocumentKey, textDocument); } + + // The edits to be applied. + QList<TextEdit> edits() const { return array<TextEdit>(editsKey); } + void setEdits(const QList<TextEdit> edits) { insertArray(editsKey, edits); } + + bool isValid() const override { return contains(textDocumentKey) && contains(editsKey); } +}; + +class CreateFileOptions : public JsonObject +{ +public: + using JsonObject::JsonObject; + + std::optional<bool> overwrite() const { return optionalValue<bool>(overwriteKey); } + void setOverwrite(bool overwrite) { insert(overwriteKey, overwrite); } + void clearOverwrite() { remove(overwriteKey); } + + std::optional<bool> ignoreIfExists() const { return optionalValue<bool>(ignoreIfExistsKey); } + void setIgnoreIfExists(bool ignoreIfExists) { insert(ignoreIfExistsKey, ignoreIfExists); } + void clearIgnoreIfExists() { remove(ignoreIfExistsKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT CreateFileOperation : public JsonObject +{ +public: + using JsonObject::JsonObject; + CreateFileOperation(); + + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + std::optional<CreateFileOptions> options() const + { return optionalValue<CreateFileOptions>(optionsKey); } + void setOptions(const CreateFileOptions &options) { insert(optionsKey, options); } + void clearOptions() { remove(optionsKey); } + + QString message(const DocumentUri::PathMapper &mapToHostPath) const; + + bool isValid() const override; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT RenameFileOperation : public JsonObject +{ +public: + using JsonObject::JsonObject; + RenameFileOperation(); + + DocumentUri oldUri() const { return DocumentUri::fromProtocol(typedValue<QString>(oldUriKey)); } + void setOldUri(const DocumentUri &oldUri) { insert(oldUriKey, oldUri); } + + DocumentUri newUri() const { return DocumentUri::fromProtocol(typedValue<QString>(newUriKey)); } + void setNewUri(const DocumentUri &newUri) { insert(newUriKey, newUri); } + + std::optional<CreateFileOptions> options() const + { return optionalValue<CreateFileOptions>(optionsKey); } + void setOptions(const CreateFileOptions &options) { insert(optionsKey, options); } + void clearOptions() { remove(optionsKey); } + + QString message(const DocumentUri::PathMapper &mapToHostPath) const; + + bool isValid() const override; +}; + +class DeleteFileOptions : public JsonObject +{ +public: + using JsonObject::JsonObject; + + std::optional<bool> recursive() const { return optionalValue<bool>(recursiveKey); } + void setRecursive(bool recursive) { insert(recursiveKey, recursive); } + void clearRecursive() { remove(recursiveKey); } + + std::optional<bool> ignoreIfNotExists() const { return optionalValue<bool>(ignoreIfNotExistsKey); } + void setIgnoreIfNotExists(bool ignoreIfNotExists) { insert(ignoreIfNotExistsKey, ignoreIfNotExists); } + void clearIgnoreIfNotExists() { remove(ignoreIfNotExistsKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT DeleteFileOperation : public JsonObject +{ +public: + using JsonObject::JsonObject; + DeleteFileOperation(); + + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + std::optional<DeleteFileOptions> options() const + { return optionalValue<DeleteFileOptions>(optionsKey); } + void setOptions(const DeleteFileOptions &options) { insert(optionsKey, options); } + void clearOptions() { remove(optionsKey); } + + QString message(const DocumentUri::PathMapper &mapToHostPath) const; + + bool isValid() const override; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT DocumentChange + : public std::variant<TextDocumentEdit, CreateFileOperation, RenameFileOperation, DeleteFileOperation> +{ +public: + using variant::variant; + DocumentChange(const QJsonValue &value); + + bool isValid() const; + + operator const QJsonValue() const; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT WorkspaceEdit : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // Holds changes to existing resources. + using Changes = QMap<DocumentUri, QList<TextEdit>>; + std::optional<Changes> changes() const; + void setChanges(const Changes &changes); + + /* + * Depending on the client capability + * `workspace.workspaceEdit.resourceOperations` document changes are either + * an array of `TextDocumentEdit`s to express changes to n different text + * documents where each text document edit addresses a specific version of + * a text document. Or it can contain above `TextDocumentEdit`s mixed with + * create, rename and delete file / folder operations. + * + * Whether a client supports versioned document edits is expressed via + * `workspace.workspaceEdit.documentChanges` client capability. + * + * If a client neither supports `documentChanges` nor + * `workspace.workspaceEdit.resourceOperations` then only plain `TextEdit`s + * using the `changes` property are supported. + */ + std::optional<QList<DocumentChange>> documentChanges() const + { return optionalArray<DocumentChange>(documentChangesKey); } + void setDocumentChanges(const QList<DocumentChange> &changes) + { insertArray(documentChangesKey, changes); } +}; + +LANGUAGESERVERPROTOCOL_EXPORT QMap<QString, QString> languageIds(); + +class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentItem : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // The text document's URI. + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + // The text document's language identifier. + QString languageId() const { return typedValue<QString>(languageIdKey); } + void setLanguageId(const QString &id) { insert(languageIdKey, id); } + + // The version number of this document (it will increase after each change, including undo/redo + int version() const { return typedValue<int>(versionKey); } + void setVersion(int version) { insert(versionKey, version); } + + // The content of the opened text document. + QString text() const { return typedValue<QString>(textKey); } + void setText(const QString &text) { insert(textKey, text); } + + bool isValid() const override; + +}; + +class LANGUAGESERVERPROTOCOL_EXPORT TextDocumentPositionParams : public JsonObject +{ +public: + TextDocumentPositionParams(); + TextDocumentPositionParams(const TextDocumentIdentifier &document, const Position &position); + using JsonObject::JsonObject; + + // The text document. + TextDocumentIdentifier textDocument() const + { return typedValue<TextDocumentIdentifier>(textDocumentKey); } + void setTextDocument(const TextDocumentIdentifier &id) { insert(textDocumentKey, id); } + + // The position inside the text document. + Position position() const { return typedValue<Position>(positionKey); } + void setPosition(const Position &position) { insert(positionKey, position); } + + bool isValid() const override { return contains(textDocumentKey) && contains(positionKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT DocumentFilter : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // A language id, like `typescript`. + std::optional<QString> language() const { return optionalValue<QString>(languageKey); } + void setLanguage(const QString &language) { insert(languageKey, language); } + void clearLanguage() { remove(languageKey); } + + // A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + std::optional<QString> scheme() const { return optionalValue<QString>(schemeKey); } + void setScheme(const QString &scheme) { insert(schemeKey, scheme); } + void clearScheme() { remove(schemeKey); } + + /** + * A glob pattern, like `*.{ts,js}`. + * + * Glob patterns can have the following syntax: + * - `*` to match one or more characters in a path segment + * - `?` to match on one character in a path segment + * - `**` to match any number of path segments, including none + * - `{}` to group sub patterns into an OR expression. (e.g. `*.{ts,js}` + * matches all TypeScript and JavaScript files) + * - `[]` to declare a range of characters to match in a path segment + * (e.g., `example.[0-9]` to match on `example.0`, `example.1`, …) + * - `[!...]` to negate a range of characters to match in a path segment + * (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + * not `example.0`) + */ + std::optional<QString> pattern() const { return optionalValue<QString>(patternKey); } + void setPattern(const QString &pattern) { insert(patternKey, pattern); } + void clearPattern() { remove(patternKey); } + + bool applies(const Utils::FilePath &fileName) const; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT MarkupKind +{ +public: + enum Value { plaintext, markdown }; + MarkupKind() = default; + MarkupKind(const Value value) + : m_value(value) + {} + explicit MarkupKind(const QJsonValue &value); + + operator QJsonValue() const; + Value value() const { return m_value; } + + bool operator==(const Value &value) const { return m_value == value; } + + bool isValid() const { return true; } +private: + Value m_value = plaintext; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT MarkupContent : public JsonObject +{ +public: + using JsonObject::JsonObject; + + // The type of the Markup + MarkupKind kind() const { return MarkupKind(value(kindKey)); } + void setKind(MarkupKind kind) { insert(kindKey, kind); } + Qt::TextFormat textFormat() const + { return kind() == MarkupKind::markdown ? Qt::MarkdownText : Qt::PlainText; } + + // The content itself + QString content() const { return typedValue<QString>(contentKey); } + void setContent(const QString &content) { insert(contentKey, content); } + + bool isValid() const override + { return contains(kindKey) && contains(contentKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT MarkupOrString : public std::variant<QString, MarkupContent> +{ +public: + MarkupOrString() = default; + explicit MarkupOrString(const std::variant<QString, MarkupContent> &val); + explicit MarkupOrString(const QString &val); + explicit MarkupOrString(const MarkupContent &val); + MarkupOrString(const QJsonValue &val); + + bool isValid() const { return true; } + + QJsonValue toJson() const; +}; + +class LANGUAGESERVERPROTOCOL_EXPORT WorkSpaceFolder : public JsonObject +{ +public: + WorkSpaceFolder() = default; + WorkSpaceFolder(const DocumentUri &uri, const QString &name); + using JsonObject::JsonObject; + + // The associated URI for this workspace folder. + DocumentUri uri() const { return DocumentUri::fromProtocol(typedValue<QString>(uriKey)); } + void setUri(const DocumentUri &uri) { insert(uriKey, uri); } + + // The name of the workspace folder. Defaults to the uri's basename. + QString name() const { return typedValue<QString>(nameKey); } + void setName(const QString &name) { insert(nameKey, name); } + + bool isValid() const override + { return contains(uriKey) && contains(nameKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT SymbolInformation : public JsonObject +{ +public: + using JsonObject::JsonObject; + + QString name() const { return typedValue<QString>(nameKey); } + void setName(const QString &name) { insert(nameKey, name); } + + int kind() const { return typedValue<int>(kindKey); } + void setKind(int kind) { insert(kindKey, kind); } + + std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); } + void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } + void clearDeprecated() { remove(deprecatedKey); } + + Location location() const { return typedValue<Location>(locationKey); } + void setLocation(const Location &location) { insert(locationKey, location); } + + std::optional<QString> containerName() const + { return optionalValue<QString>(containerNameKey); } + void setContainerName(const QString &containerName) { insert(containerNameKey, containerName); } + void clearContainerName() { remove(containerNameKey); } + + bool isValid() const override + { return contains(nameKey) && contains(kindKey) && contains(locationKey); } +}; + +class LANGUAGESERVERPROTOCOL_EXPORT DocumentSymbol : public JsonObject +{ +public: + using JsonObject::JsonObject; + + QString name() const { return typedValue<QString>(nameKey); } + void setName(const QString &name) { insert(nameKey, name); } + + std::optional<QString> detail() const { return optionalValue<QString>(detailKey); } + void setDetail(const QString &detail) { insert(detailKey, detail); } + void clearDetail() { remove(detailKey); } + + int kind() const { return typedValue<int>(kindKey); } + void setKind(int kind) { insert(kindKey, kind); } + + std::optional<bool> deprecated() const { return optionalValue<bool>(deprecatedKey); } + void setDeprecated(bool deprecated) { insert(deprecatedKey, deprecated); } + void clearDeprecated() { remove(deprecatedKey); } + + Range range() const { return typedValue<Range>(rangeKey); } + void setRange(Range range) { insert(rangeKey, range); } + + Range selectionRange() const { return typedValue<Range>(selectionRangeKey); } + void setSelectionRange(Range selectionRange) { insert(selectionRangeKey, selectionRange); } + + std::optional<QList<DocumentSymbol>> children() const + { return optionalArray<DocumentSymbol>(childrenKey); } + void setChildren(QList<DocumentSymbol> children) { insertArray(childrenKey, children); } + void clearChildren() { remove(childrenKey); } +}; + +enum class SymbolKind { + File = 1, + FirstSymbolKind = File, + 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, + TypeParameter = 26, + LastSymbolKind = TypeParameter, +}; + +namespace CompletionItemKind { +enum Kind { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25 +}; +} // namespace CompletionItemKind + +} // namespace LanguageClient |