lspclientserver.h 7.49 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*  SPDX-License-Identifier: MIT

    Copyright (C) 2019 Mark Nauwelaerts <mark.nauwelaerts@gmail.com>

    Permission is hereby granted, free of charge, to any person obtaining
    a copy of this software and associated documentation files (the
    "Software"), to deal in the Software without restriction, including
    without limitation the rights to use, copy, modify, merge, publish,
    distribute, sublicense, and/or sell copies of the Software, and to
    permit persons to whom the Software is furnished to do so, subject to
    the following conditions:

    The above copyright notice and this permission notice shall be included
    in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
24 25 26 27

#ifndef LSPCLIENTSERVER_H
#define LSPCLIENTSERVER_H

28 29
#include "lspclientprotocol.h"

30 31 32 33
#include <QObject>
#include <QString>
#include <QUrl>
#include <QList>
34
#include <QVector>
35
#include <QPointer>
36
#include <QJsonValue>
37 38 39

#include <functional>

40
namespace utils {
41

42 43 44
// template helper
// function bind helpers
template<typename R, typename T, typename Tp, typename... Args>
45
inline std::function<R(Args...)> mem_fun(R (T::*pm)(Args...), Tp object)
46
{
47
    return [object, pm](Args... args) { return (object->*pm)(std::forward<Args>(args)...); };
48 49 50
}

template<typename R, typename T, typename Tp, typename... Args>
51
inline std::function<R(Args...)> mem_fun(R (T::*pm)(Args...) const, Tp object)
52
{
53
    return [object, pm](Args... args) { return (object->*pm)(std::forward<Args>(args)...); };
54 55
}

56
// prevent argument deduction
57 58 59 60
template<typename T>
struct identity {
    typedef T type;
};
61 62 63

} // namespace utils

64 65
static const int TIMEOUT_SHUTDOWN = 200;

66 67 68 69
template<typename T>
using ReplyHandler = std::function<void(const T &)>;

using DocumentSymbolsReplyHandler = ReplyHandler<QList<LSPSymbolInformation>>;
70
using DocumentDefinitionReplyHandler = ReplyHandler<QList<LSPLocation>>;
71
using DocumentHighlightReplyHandler = ReplyHandler<QList<LSPDocumentHighlight>>;
Mark Nauwelaerts's avatar
Mark Nauwelaerts committed
72
using DocumentHoverReplyHandler = ReplyHandler<LSPHover>;
73
using DocumentCompletionReplyHandler = ReplyHandler<QList<LSPCompletionItem>>;
74
using SignatureHelpReplyHandler = ReplyHandler<LSPSignatureHelp>;
75
using FormattingReplyHandler = ReplyHandler<QList<LSPTextEdit>>;
76
using CodeActionReplyHandler = ReplyHandler<QList<LSPCodeAction>>;
77
using WorkspaceEditReplyHandler = ReplyHandler<LSPWorkspaceEdit>;
78
using ApplyEditReplyHandler = ReplyHandler<LSPApplyWorkspaceEditResponse>;
79 80 81 82 83 84

class LSPClientServer : public QObject
{
    Q_OBJECT

public:
85
    enum class State { None, Started, Running, Shutdown };
86 87 88 89 90 91 92

    class LSPClientServerPrivate;
    class RequestHandle
    {
        friend class LSPClientServerPrivate;
        QPointer<LSPClientServer> m_server;
        int m_id = -1;
93

94
    public:
95
        RequestHandle &cancel()
96 97 98 99 100 101 102
        {
            if (m_server)
                m_server->cancel(m_id);
            return *this;
        }
    };

103 104
    LSPClientServer(const QStringList &server, const QUrl &root,
                    const QJsonValue &init = QJsonValue());
105 106 107 108 109 110 111 112 113 114
    ~LSPClientServer();

    // server management
    // request start
    bool start();
    // request shutdown/stop
    // if to_xxx >= 0 -> send signal if not exit'ed after timeout
    void stop(int to_term_ms, int to_kill_ms);
    int cancel(int id);

115
    // properties
116
    const QStringList &cmdline() const;
117
    State state() const;
118
    Q_SIGNAL void stateChanged(LSPClientServer *server);
119

120
    const LSPServerCapabilities &capabilities() const;
121

122
    // language
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
    RequestHandle documentSymbols(const QUrl &document, const QObject *context,
                                  const DocumentSymbolsReplyHandler &h);
    RequestHandle documentDefinition(const QUrl &document, const LSPPosition &pos,
                                     const QObject *context,
                                     const DocumentDefinitionReplyHandler &h);
    RequestHandle documentDeclaration(const QUrl &document, const LSPPosition &pos,
                                      const QObject *context,
                                      const DocumentDefinitionReplyHandler &h);
    RequestHandle documentHighlight(const QUrl &document, const LSPPosition &pos,
                                    const QObject *context, const DocumentHighlightReplyHandler &h);
    RequestHandle documentHover(const QUrl &document, const LSPPosition &pos,
                                const QObject *context, const DocumentHoverReplyHandler &h);
    RequestHandle documentReferences(const QUrl &document, const LSPPosition &pos, bool decl,
                                     const QObject *context,
                                     const DocumentDefinitionReplyHandler &h);
    RequestHandle documentCompletion(const QUrl &document, const LSPPosition &pos,
                                     const QObject *context,
                                     const DocumentCompletionReplyHandler &h);
    RequestHandle signatureHelp(const QUrl &document, const LSPPosition &pos,
                                const QObject *context, const SignatureHelpReplyHandler &h);

    RequestHandle documentFormatting(const QUrl &document, const LSPFormattingOptions &options,
                                     const QObject *context, const FormattingReplyHandler &h);
    RequestHandle documentRangeFormatting(const QUrl &document, const LSPRange &range,
                                          const LSPFormattingOptions &options,
                                          const QObject *context, const FormattingReplyHandler &h);
    RequestHandle documentOnTypeFormatting(const QUrl &document, const LSPPosition &pos,
                                           QChar lastChar, const LSPFormattingOptions &options,
                                           const QObject *context, const FormattingReplyHandler &h);
    RequestHandle documentRename(const QUrl &document, const LSPPosition &pos,
                                 const QString newName, const QObject *context,
                                 const WorkspaceEditReplyHandler &h);

    RequestHandle documentCodeAction(const QUrl &document, const LSPRange &range,
                                     const QList<QString> &kinds, QList<LSPDiagnostic> diagnostics,
                                     const QObject *context, const CodeActionReplyHandler &h);
    void executeCommand(const QString &command, const QJsonValue &args);
160

161
    // sync
162
    void didOpen(const QUrl &document, int version, const QString &langId, const QString &text);
163
    // only 1 of text or changes should be non-empty and is considered
164 165 166 167
    void didChange(const QUrl &document, int version, const QString &text,
                   const QList<LSPTextDocumentContentChangeEvent> &changes = {});
    void didSave(const QUrl &document, const QString &text);
    void didClose(const QUrl &document);
168

169 170
    // notifcation = signal
Q_SIGNALS:
171
    void publishDiagnostics(const LSPPublishDiagnosticsParams &);
172

173
    // request = signal
174 175
    void applyEdit(const LSPApplyWorkspaceEditParams &req, const ApplyEditReplyHandler &h,
                   bool &handled);
176

177 178
private:
    // pimpl data holder
179
    LSPClientServerPrivate *const d;
180 181 182
};

#endif