File: LanguageServerProtocol.h

package info (click to toggle)
codelite 17.0.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 136,204 kB
  • sloc: cpp: 491,547; ansic: 280,393; php: 10,259; sh: 8,930; lisp: 7,664; vhdl: 6,518; python: 6,020; lex: 4,920; yacc: 3,123; perl: 2,385; javascript: 1,715; cs: 1,193; xml: 1,110; makefile: 804; cobol: 741; sql: 709; ruby: 620; f90: 566; ada: 534; asm: 464; fortran: 350; objc: 289; tcl: 258; java: 157; erlang: 61; pascal: 51; ml: 49; awk: 44; haskell: 36
file content (301 lines) | stat: -rw-r--r-- 9,728 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
#ifndef LANGUAG_ESERVER_PROTOCOL_H
#define LANGUAG_ESERVER_PROTOCOL_H

#include "LSP/DocumentSymbolsRequest.hpp"
#include "LSP/IPathConverter.hpp"
#include "LSP/MessageWithParams.h"
#include "LSPNetwork.h"
#include "ServiceProvider.h"
#include "SocketAPI/clSocketClientAsync.h"
#include "asyncprocess.h"
#include "cl_command_event.h"
#include "codelite_events.h"
#include "codelite_exports.h"
#include "fileextmanager.h"
#include "macros.h"

#include <functional>
#include <map>
#include <queue>
#include <string>
#include <unordered_map>
#include <wx/arrstr.h>
#include <wx/filename.h>
#include <wx/sharedptr.h>
#include <wxStringHash.h>

typedef std::function<void()> LSPOnConnectedCallback_t;

class IEditor;
class WXDLLIMPEXP_SDK LSPRequestMessageQueue
{
    std::queue<LSP::MessageWithParams::Ptr_t> m_Queue;
    std::unordered_map<int, LSP::MessageWithParams::Ptr_t> m_pendingReplyMessages;
    bool m_waitingReponse = false;

public:
    LSPRequestMessageQueue() {}
    virtual ~LSPRequestMessageQueue() {}

    LSP::MessageWithParams::Ptr_t TakePendingReplyMessage(int msgid);
    void Push(LSP::MessageWithParams::Ptr_t message);
    void Pop();
    LSP::MessageWithParams::Ptr_t Get();
    void Clear();
    bool IsEmpty() const { return m_Queue.empty(); }
    void SetWaitingReponse(bool waitingReponse) { this->m_waitingReponse = waitingReponse; }
    bool IsWaitingReponse() const { return m_waitingReponse; }
};

class WXDLLIMPEXP_SDK LanguageServerProtocol : public ServiceProvider
{
    enum eState {
        kUnInitialized,
        kInitialized,
    };

    wxString m_name;
    wxEvtHandler* m_owner = nullptr;
    LSPNetwork::Ptr_t m_network;
    wxString m_initOptions;
    wxStringMap_t m_filesSent;
    wxStringSet_t m_languages;
    wxString m_outputBuffer;
    wxString m_rootFolder;
    clEnvList_t m_env;
    LSPStartupInfo m_startupInfo;
    // initialization
    eState m_state = kUnInitialized;
    int m_initializeRequestID = wxNOT_FOUND;

    // Parsing queue
    LSPRequestMessageQueue m_Queue;
    wxStringSet_t m_providers;
    bool m_disaplayDiagnostics = true;
    int m_lastCompletionRequestId = wxNOT_FOUND;
    wxArrayString m_semanticTokensTypes;
    LSPOnConnectedCallback_t m_onServerStartedCallback = nullptr;

public:
    typedef wxSharedPtr<LanguageServerProtocol> Ptr_t;
    static FileExtManager::FileType workspace_file_type;

protected:
    void OnNetConnected(clCommandEvent& event);
    void OnNetError(clCommandEvent& event);
    void OnNetDataReady(clCommandEvent& event);

    void OnFileLoaded(clCommandEvent& event);
    void OnFileClosed(clCommandEvent& event);
    void OnFileSaved(clCommandEvent& event);
    void OnWorkspaceLoaded(clWorkspaceEvent& e);
    void OnWorkspaceClosed(clWorkspaceEvent& e);
    void OnEditorChanged(wxCommandEvent& event);
    void OnCodeComplete(clCodeCompletionEvent& event);
    void OnFindSymbolDecl(clCodeCompletionEvent& event);
    void OnFindSymbolImpl(clCodeCompletionEvent& event);
    void OnFindSymbol(clCodeCompletionEvent& event);
    void OnFunctionCallTip(clCodeCompletionEvent& event);
    void OnTypeInfoToolTip(clCodeCompletionEvent& event);
    void OnQuickOutline(clCodeCompletionEvent& event);
    void OnSemanticHighlights(clCodeCompletionEvent& event);
    void OnWorkspaceSymbols(clCodeCompletionEvent& event);
    void OnFindHeaderFile(clCodeCompletionEvent& event);
    void OnQuickJump(clCodeCompletionEvent& event);

    wxString GetEditorFilePath(IEditor* editor) const;
    bool CheckCapability(const LSP::ResponseMessage& res, const wxString& capabilityName,
                         const wxString& lspRequestName);

protected:
    void DoClear();
    bool ShouldHandleFile(IEditor* editor) const;
    wxString GetLogPrefix() const;
    void ProcessQueue();
    static wxString GetLanguageId(IEditor* editor);
    static wxString GetLanguageId(FileExtManager::FileType file_type);
    void UpdateFileSent(const wxString& filename, const wxString& fileContent);
    bool IsFileChangedSinceLastParse(const wxString& filename, const wxString& fileContent) const;
    void HandleResponseError(LSP::ResponseMessage& response, LSP::MessageWithParams::Ptr_t msg_ptr);
    void HandleResponse(LSP::ResponseMessage& response, LSP::MessageWithParams::Ptr_t msg_ptr);
    IEditor* GetEditor(const clCodeCompletionEvent& event) const;

protected:
    /**
     * @brief notify about file open
     */
    void SendOpenRequest(IEditor* editor, const wxString& fileContent, const wxString& languageId);

    /**
     * @brief report a file-close notification
     */
    void SendCloseRequest(const wxString& filename);

    /**
     * @brief ask the server for semantic tokens
     */
    void SendSemanticTokensRequest(IEditor* editor);

    /**
     * @brief query the LSP for a list of workspace symbols that matches a query string
     */
    void SendWorkspaceSymbolsRequest(const wxString& query_string);

    /**
     * @brief report a file-changed notification
     */
    void SendChangeRequest(IEditor* editor, const wxString& fileContent, bool force_reparse = false);

    /**
     * @brief report a file-save notification
     */
    void SendSaveRequest(IEditor* editor, const wxString& fileContent);

    /**
     * @brief request for a code completion at a given doc/position
     */
    void SendCodeCompleteRequest(IEditor* editor, size_t line, size_t column);

    bool DoStart();

    /**
     * @brief add message to the outgoing queue
     */
    void QueueMessage(LSP::MessageWithParams::Ptr_t request);

public:
    LanguageServerProtocol(const wxString& name, eNetworkType netType, wxEvtHandler* owner);
    virtual ~LanguageServerProtocol();

    /**
     * @brief set a callnack to be executed once the LSP is up and running
     * but before the `initialize` request has been sent
     */
    void SetStartedCallback(LSPOnConnectedCallback_t&& cb);

    /**
     * @brief return the semantic token at a given index
     */
    const wxString& GetSemanticToken(size_t index) const;

    LanguageServerProtocol& SetDisaplayDiagnostics(bool disaplayDiagnostics)
    {
        this->m_disaplayDiagnostics = disaplayDiagnostics;
        return *this;
    }
    bool IsDisaplayDiagnostics() const { return m_disaplayDiagnostics; }

    LanguageServerProtocol& SetName(const wxString& name)
    {
        this->m_name = name;
        return *this;
    }

    const wxStringSet_t& GetProviders() const { return m_providers; }
    const wxString& GetName() const { return m_name; }
    bool IsInitialized() const { return (m_state == kInitialized); }

    /**
     * @brief return list of all supported languages by LSP. The list contains the abbreviation entry and a description
     */
    static std::set<wxString> GetSupportedLanguages();
    bool CanHandle(IEditor* editor) const;
    bool CanHandle(FileExtManager::FileType file_type) const;

    /**
     * @brief return true if this server supports `lang`
     */
    bool IsLanguageSupported(const wxString& lang) const;

    /**
     * @brief start LSP server and connect to it (e.g. clangd)
     * @param LSPStartupInfo which contains the command to execute, working directory and other process related stuff
     * @param env environment vriables for this LSP
     * @param initOptions initialization options to pass to the LSP
     * @param rootFolder the LSP root folder (to be passed during the 'initialize' request)
     * @param languages supported languages by this LSP
     */
    bool Start(const LSPStartupInfo& startupInfo, const clEnvList_t& env, const wxString& initOptions,
               const wxString& rootFolder, const wxArrayString& languages);

    /**
     * @brief same as above, but reuse the current parameters
     */
    bool Start();

    /**
     * @brief is the LSP running?
     */
    bool IsRunning() const;

    /**
     * @brief stop the language server
     */
    void Stop();

    /**
     * @brief find the definition of the item at the caret position
     */
    void FindDefinition(IEditor* editor);
    /**
     * @brief find the implementatin of a symbol at the caret position
     */
    void FindImplementation(IEditor* editor);
    /**
     * @brief find the definition of the item at the caret position
     * @param for_add_missing_header the context of the `FindDeclaration` is `Add include header` request
     */
    void FindDeclaration(IEditor* editor, bool for_add_missing_header);

    /**
     * @brief perform code completion for a given editor
     */
    void CodeComplete(IEditor* editor);

    /**
     * @brief ask for function call help
     */
    void FunctionHelp(IEditor* editor);

    /**
     * @brief ask for available hovertip
     */
    void HoverTip(IEditor* editor);

    /**
     * @brief manually load file into the server
     */
    void OpenEditor(IEditor* editor);

    /**
     * @brief tell the server to close editor
     */
    void CloseEditor(IEditor* editor);

    /**
     * @brief find references of a symbol
     */
    void FindReferences(IEditor* editor);

    /**
     * @brief rename a symbol
     */
    void RenameSymbol(IEditor* editor);

    /**
     * @brief get list of symbols for the current editor
     * @param editor the current editor
     * @param context_flags request context. See LSP::DocumentSymbolsRequest::eDocumentSymbolsContext (bit or'd)
     */
    void DocumentSymbols(IEditor* editor, size_t context_flags);

    // helpers
    bool IsCapabilitySupported(const wxString& name) const;
    bool IsDocumentSymbolsSupported() const;
    bool IsSemanticTokensSupported() const;
    bool IsDeclarationSupported() const;
    bool IsReferencesSupported() const;
    bool IsRenameSupported() const;
};

#endif // CLLANGUAGESERVER_H