File indexing completed on 2024-04-28 05:49:00
0001 /* 0002 SPDX-FileCopyrightText: 2019 Mark Nauwelaerts <mark.nauwelaerts@gmail.com> 0003 0004 SPDX-License-Identifier: MIT 0005 */ 0006 0007 #pragma once 0008 0009 #include "lspclientprotocol.h" 0010 0011 #include <QJsonValue> 0012 #include <QList> 0013 #include <QObject> 0014 #include <QPointer> 0015 #include <QString> 0016 #include <QUrl> 0017 0018 #include <functional> 0019 #include <optional> 0020 0021 namespace utils 0022 { 0023 // template helper 0024 // function bind helpers 0025 template<typename R, typename T, typename Tp, typename... Args> 0026 inline std::function<R(Args...)> mem_fun(R (T::*pm)(Args...), Tp object) 0027 { 0028 return [object, pm](Args... args) { 0029 return (object->*pm)(std::forward<Args>(args)...); 0030 }; 0031 } 0032 0033 template<typename R, typename T, typename Tp, typename... Args> 0034 inline std::function<R(Args...)> mem_fun(R (T::*pm)(Args...) const, Tp object) 0035 { 0036 return [object, pm](Args... args) { 0037 return (object->*pm)(std::forward<Args>(args)...); 0038 }; 0039 } 0040 0041 // prevent argument deduction 0042 template<typename T> 0043 struct identity { 0044 typedef T type; 0045 }; 0046 0047 } // namespace utils 0048 0049 static const int TIMEOUT_SHUTDOWN = 200; 0050 0051 template<typename T> 0052 using ReplyHandler = std::function<void(const T &)>; 0053 0054 using ErrorReplyHandler = ReplyHandler<LSPResponseError>; 0055 using DocumentSymbolsReplyHandler = ReplyHandler<std::list<LSPSymbolInformation>>; 0056 using DocumentDefinitionReplyHandler = ReplyHandler<QList<LSPLocation>>; 0057 using DocumentHighlightReplyHandler = ReplyHandler<QList<LSPDocumentHighlight>>; 0058 using DocumentHoverReplyHandler = ReplyHandler<LSPHover>; 0059 using DocumentCompletionReplyHandler = ReplyHandler<QList<LSPCompletionItem>>; 0060 using DocumentCompletionResolveReplyHandler = ReplyHandler<LSPCompletionItem>; 0061 using SignatureHelpReplyHandler = ReplyHandler<LSPSignatureHelp>; 0062 using FormattingReplyHandler = ReplyHandler<QList<LSPTextEdit>>; 0063 using CodeActionReplyHandler = ReplyHandler<QList<LSPCodeAction>>; 0064 using WorkspaceEditReplyHandler = ReplyHandler<LSPWorkspaceEdit>; 0065 using ApplyEditReplyHandler = ReplyHandler<LSPApplyWorkspaceEditResponse>; 0066 using WorkspaceFoldersReplyHandler = ReplyHandler<QList<LSPWorkspaceFolder>>; 0067 using SwitchSourceHeaderHandler = ReplyHandler<QString>; 0068 using MemoryUsageHandler = ReplyHandler<QString>; 0069 using ExpandMacroHandler = ReplyHandler<LSPExpandedMacro>; 0070 using SemanticTokensDeltaReplyHandler = ReplyHandler<LSPSemanticTokensDelta>; 0071 using WorkspaceSymbolsReplyHandler = ReplyHandler<std::vector<LSPSymbolInformation>>; 0072 using SelectionRangeReplyHandler = ReplyHandler<QList<std::shared_ptr<LSPSelectionRange>>>; 0073 using InlayHintsReplyHandler = ReplyHandler<QList<LSPInlayHint>>; 0074 0075 class LSPClientPlugin; 0076 0077 struct LSPClientCapabilities { 0078 bool snippetSupport = false; 0079 }; 0080 0081 class LSPClientServer : public QObject 0082 { 0083 Q_OBJECT 0084 0085 public: 0086 enum class State { None, Started, Running, Shutdown }; 0087 0088 class LSPClientServerPrivate; 0089 class RequestHandle 0090 { 0091 friend class LSPClientServerPrivate; 0092 QPointer<LSPClientServer> m_server; 0093 int m_id = -1; 0094 0095 public: 0096 RequestHandle &cancel() 0097 { 0098 if (m_server) { 0099 m_server->cancel(m_id); 0100 } 0101 return *this; 0102 } 0103 }; 0104 0105 using FoldersType = std::optional<QList<LSPWorkspaceFolder>>; 0106 0107 // optionally adjust server provided/suggest trigger characters 0108 struct TriggerCharactersOverride { 0109 QList<QChar> exclude; 0110 QList<QChar> include; 0111 }; 0112 0113 // collect additional tweaks into a helper struct to avoid ever growing parameter list 0114 // (which then also needs to be duplicated in a few places) 0115 struct ExtraServerConfig { 0116 FoldersType folders; 0117 LSPClientCapabilities caps; 0118 TriggerCharactersOverride completion; 0119 TriggerCharactersOverride signature; 0120 }; 0121 0122 LSPClientServer(const QStringList &server, 0123 const QUrl &root, 0124 const QString &langId = QString(), 0125 const QJsonValue &init = QJsonValue(), 0126 const ExtraServerConfig = {}); 0127 ~LSPClientServer() override; 0128 0129 // server management 0130 // request start 0131 bool start(bool forwardStdError); 0132 // request shutdown/stop 0133 // if to_xxx >= 0 -> send signal if not exit'ed after timeout 0134 void stop(int to_term_ms, int to_kill_ms); 0135 int cancel(int id); 0136 0137 // properties 0138 const QStringList &cmdline() const; 0139 const QUrl &root() const; 0140 const QString &langId() const; 0141 State state() const; 0142 Q_SIGNAL void stateChanged(LSPClientServer *server); 0143 0144 const LSPServerCapabilities &capabilities() const; 0145 0146 // language 0147 RequestHandle documentSymbols(const QUrl &document, const QObject *context, const DocumentSymbolsReplyHandler &h, const ErrorReplyHandler &eh = nullptr); 0148 RequestHandle documentDefinition(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentDefinitionReplyHandler &h); 0149 RequestHandle documentDeclaration(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentDefinitionReplyHandler &h); 0150 RequestHandle documentTypeDefinition(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentDefinitionReplyHandler &h); 0151 RequestHandle documentImplementation(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentDefinitionReplyHandler &h); 0152 RequestHandle documentHighlight(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentHighlightReplyHandler &h); 0153 RequestHandle documentHover(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentHoverReplyHandler &h); 0154 RequestHandle documentReferences(const QUrl &document, const LSPPosition &pos, bool decl, const QObject *context, const DocumentDefinitionReplyHandler &h); 0155 RequestHandle documentCompletion(const QUrl &document, const LSPPosition &pos, const QObject *context, const DocumentCompletionReplyHandler &h); 0156 RequestHandle documentCompletionResolve(const LSPCompletionItem &c, const QObject *context, const DocumentCompletionResolveReplyHandler &h); 0157 RequestHandle signatureHelp(const QUrl &document, const LSPPosition &pos, const QObject *context, const SignatureHelpReplyHandler &h); 0158 RequestHandle selectionRange(const QUrl &document, const QList<LSPPosition> &positions, const QObject *context, const SelectionRangeReplyHandler &h); 0159 // clangd specific 0160 RequestHandle clangdSwitchSourceHeader(const QUrl &document, const QObject *context, const SwitchSourceHeaderHandler &h); 0161 RequestHandle clangdMemoryUsage(const QObject *context, const MemoryUsageHandler &h); 0162 0163 RequestHandle documentFormatting(const QUrl &document, const LSPFormattingOptions &options, const QObject *context, const FormattingReplyHandler &h); 0164 RequestHandle documentRangeFormatting(const QUrl &document, 0165 const LSPRange &range, 0166 const LSPFormattingOptions &options, 0167 const QObject *context, 0168 const FormattingReplyHandler &h); 0169 RequestHandle documentOnTypeFormatting(const QUrl &document, 0170 const LSPPosition &pos, 0171 QChar lastChar, 0172 const LSPFormattingOptions &options, 0173 const QObject *context, 0174 const FormattingReplyHandler &h); 0175 RequestHandle 0176 documentRename(const QUrl &document, const LSPPosition &pos, const QString &newName, const QObject *context, const WorkspaceEditReplyHandler &h); 0177 0178 RequestHandle documentCodeAction(const QUrl &document, 0179 const LSPRange &range, 0180 const QList<QString> &kinds, 0181 QList<LSPDiagnostic> diagnostics, 0182 const QObject *context, 0183 const CodeActionReplyHandler &h); 0184 0185 RequestHandle documentSemanticTokensFull(const QUrl &document, const QString requestId, const QObject *context, const SemanticTokensDeltaReplyHandler &h); 0186 0187 RequestHandle 0188 documentSemanticTokensFullDelta(const QUrl &document, const QString requestId, const QObject *context, const SemanticTokensDeltaReplyHandler &h); 0189 0190 RequestHandle documentSemanticTokensRange(const QUrl &document, const LSPRange &range, const QObject *context, const SemanticTokensDeltaReplyHandler &h); 0191 0192 RequestHandle documentInlayHint(const QUrl &document, const LSPRange &range, const QObject *context, const InlayHintsReplyHandler &h); 0193 0194 void executeCommand(const LSPCommand &command); 0195 0196 // rust-analyzer specific 0197 RequestHandle rustAnalyzerExpandMacro(const QObject *context, const QUrl &document, const LSPPosition &pos, const ExpandMacroHandler &h); 0198 0199 // sync 0200 void didOpen(const QUrl &document, int version, const QString &langId, const QString &text); 0201 // only 1 of text or changes should be non-empty and is considered 0202 void didChange(const QUrl &document, int version, const QString &text, const QList<LSPTextDocumentContentChangeEvent> &changes = {}); 0203 void didSave(const QUrl &document, const QString &text); 0204 void didClose(const QUrl &document); 0205 0206 // workspace 0207 void didChangeConfiguration(const QJsonValue &settings); 0208 void didChangeWorkspaceFolders(const QList<LSPWorkspaceFolder> &added, const QList<LSPWorkspaceFolder> &removed); 0209 void workspaceSymbol(const QString &symbol, const QObject *context, const WorkspaceSymbolsReplyHandler &h); 0210 0211 // notification = signal 0212 Q_SIGNALS: 0213 void showMessage(const LSPShowMessageParams &); 0214 void logMessage(const LSPLogMessageParams &); 0215 void publishDiagnostics(const LSPPublishDiagnosticsParams &); 0216 void workDoneProgress(const LSPWorkDoneProgressParams &); 0217 0218 // request = signal 0219 void applyEdit(const LSPApplyWorkspaceEditParams &req, const ApplyEditReplyHandler &h, bool &handled); 0220 void workspaceFolders(const WorkspaceFoldersReplyHandler &h, bool &handled); 0221 void showMessageRequest(const LSPShowMessageParams &message, 0222 const QList<LSPMessageRequestAction> &actions, 0223 const std::function<void()> chooseNothing, 0224 bool &handled); 0225 0226 private: 0227 // pimpl data holder 0228 LSPClientServerPrivate *const d; 0229 };