Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/modules/gdscript/language_server/godot_lsp.h
21100 views
1
/**************************************************************************/
2
/* godot_lsp.h */
3
/**************************************************************************/
4
/* This file is part of: */
5
/* GODOT ENGINE */
6
/* https://godotengine.org */
7
/**************************************************************************/
8
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10
/* */
11
/* Permission is hereby granted, free of charge, to any person obtaining */
12
/* a copy of this software and associated documentation files (the */
13
/* "Software"), to deal in the Software without restriction, including */
14
/* without limitation the rights to use, copy, modify, merge, publish, */
15
/* distribute, sublicense, and/or sell copies of the Software, and to */
16
/* permit persons to whom the Software is furnished to do so, subject to */
17
/* the following conditions: */
18
/* */
19
/* The above copyright notice and this permission notice shall be */
20
/* included in all copies or substantial portions of the Software. */
21
/* */
22
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29
/**************************************************************************/
30
31
#pragma once
32
33
#include "core/doc_data.h"
34
#include "core/object/class_db.h"
35
#include "core/templates/list.h"
36
37
// Enable additional LSP related logging.
38
//#define DEBUG_LSP
39
40
#ifdef DEBUG_LSP
41
#define LOG_LSP(...) print_line("[ LSP -", __FILE__, ":", __LINE__, "-", __func__, "] -", ##__VA_ARGS__)
42
#else
43
#define LOG_LSP(...)
44
#endif
45
46
namespace LSP {
47
48
typedef String DocumentUri;
49
50
/** Format BBCode documentation from DocData to markdown */
51
static String marked_documentation(const String &p_bbcode);
52
53
/**
54
* Text documents are identified using a URI. On the protocol level, URIs are passed as strings.
55
*/
56
struct TextDocumentIdentifier {
57
/**
58
* The text document's URI.
59
*/
60
DocumentUri uri;
61
62
_FORCE_INLINE_ void load(const Dictionary &p_params) {
63
uri = p_params["uri"];
64
}
65
66
_FORCE_INLINE_ Dictionary to_json() const {
67
Dictionary dict;
68
dict["uri"] = uri;
69
return dict;
70
}
71
};
72
73
/**
74
* Position in a text document expressed as zero-based line and zero-based character offset.
75
* A position is between two characters like an ‘insert’ cursor in a editor.
76
* Special values like for example -1 to denote the end of a line are not supported.
77
*/
78
struct Position {
79
/**
80
* Line position in a document (zero-based).
81
*/
82
int line = 0;
83
84
/**
85
* Character offset on a line in a document (zero-based). Assuming that the line is
86
* represented as a string, the `character` value represents the gap between the
87
* `character` and `character + 1`.
88
*
89
* If the character value is greater than the line length it defaults back to the
90
* line length.
91
*/
92
int character = 0;
93
94
_FORCE_INLINE_ bool operator==(const Position &p_other) const {
95
return line == p_other.line && character == p_other.character;
96
}
97
98
String to_string() const {
99
return vformat("(%d,%d)", line, character);
100
}
101
102
_FORCE_INLINE_ void load(const Dictionary &p_params) {
103
line = p_params["line"];
104
character = p_params["character"];
105
}
106
107
_FORCE_INLINE_ Dictionary to_json() const {
108
Dictionary dict;
109
dict["line"] = line;
110
dict["character"] = character;
111
return dict;
112
}
113
};
114
115
/**
116
* A range in a text document expressed as (zero-based) start and end positions.
117
* A range is comparable to a selection in an editor. Therefore the end position is exclusive.
118
* If you want to specify a range that contains a line including the line ending character(s) then use an end position denoting the start of the next line.
119
*/
120
struct Range {
121
/**
122
* The range's start position.
123
*/
124
Position start;
125
126
/**
127
* The range's end position.
128
*/
129
Position end;
130
131
_FORCE_INLINE_ bool operator==(const Range &p_other) const {
132
return start == p_other.start && end == p_other.end;
133
}
134
135
bool contains(const Position &p_pos) const {
136
// Inside line range.
137
if (start.line <= p_pos.line && p_pos.line <= end.line) {
138
// If on start line: must come after start char.
139
bool start_ok = p_pos.line == start.line ? start.character <= p_pos.character : true;
140
// If on end line: must come before end char.
141
bool end_ok = p_pos.line == end.line ? p_pos.character <= end.character : true;
142
return start_ok && end_ok;
143
} else {
144
return false;
145
}
146
}
147
148
String to_string() const {
149
return vformat("[%s:%s]", start.to_string(), end.to_string());
150
}
151
152
_FORCE_INLINE_ void load(const Dictionary &p_params) {
153
start.load(p_params["start"]);
154
end.load(p_params["end"]);
155
}
156
157
_FORCE_INLINE_ Dictionary to_json() const {
158
Dictionary dict;
159
dict["start"] = start.to_json();
160
dict["end"] = end.to_json();
161
return dict;
162
}
163
};
164
165
/**
166
* Represents a location inside a resource, such as a line inside a text file.
167
*/
168
struct Location {
169
DocumentUri uri;
170
Range range;
171
172
_FORCE_INLINE_ void load(const Dictionary &p_params) {
173
uri = p_params["uri"];
174
range.load(p_params["range"]);
175
}
176
177
_FORCE_INLINE_ Dictionary to_json() const {
178
Dictionary dict;
179
dict["uri"] = uri;
180
dict["range"] = range.to_json();
181
return dict;
182
}
183
};
184
185
/**
186
* Represents a link between a source and a target location.
187
*/
188
struct LocationLink {
189
/**
190
* Span of the origin of this link.
191
*
192
* Used as the underlined span for mouse interaction. Defaults to the word range at
193
* the mouse position.
194
*/
195
Range *originSelectionRange = nullptr;
196
197
/**
198
* The target resource identifier of this link.
199
*/
200
String targetUri;
201
202
/**
203
* The full target range of this link. If the target for example is a symbol then target range is the
204
* range enclosing this symbol not including leading/trailing whitespace but everything else
205
* like comments. This information is typically used to highlight the range in the editor.
206
*/
207
Range targetRange;
208
209
/**
210
* The range that should be selected and revealed when this link is being followed, e.g the name of a function.
211
* Must be contained by the `targetRange`. See also `DocumentSymbol#range`
212
*/
213
Range targetSelectionRange;
214
};
215
216
/**
217
* A parameter literal used in requests to pass a text document and a position inside that document.
218
*/
219
struct TextDocumentPositionParams {
220
/**
221
* The text document.
222
*/
223
TextDocumentIdentifier textDocument;
224
225
/**
226
* The position inside the text document.
227
*/
228
Position position;
229
230
_FORCE_INLINE_ void load(const Dictionary &p_params) {
231
textDocument.load(p_params["textDocument"]);
232
position.load(p_params["position"]);
233
}
234
235
_FORCE_INLINE_ Dictionary to_json() const {
236
Dictionary dict;
237
dict["textDocument"] = textDocument.to_json();
238
dict["position"] = position.to_json();
239
return dict;
240
}
241
};
242
243
struct ReferenceContext {
244
/**
245
* Include the declaration of the current symbol.
246
*/
247
bool includeDeclaration = false;
248
};
249
250
struct ShowMessageParams {
251
/**
252
* The message type. See {@link MessageType}.
253
*/
254
int type;
255
256
/**
257
* The actual message.
258
*/
259
String message;
260
261
_FORCE_INLINE_ Dictionary to_json() const {
262
Dictionary dict;
263
dict["type"] = type;
264
dict["message"] = message;
265
return dict;
266
}
267
};
268
269
struct ReferenceParams : TextDocumentPositionParams {
270
ReferenceContext context;
271
};
272
273
struct DocumentLinkParams {
274
/**
275
* The document to provide document links for.
276
*/
277
TextDocumentIdentifier textDocument;
278
279
_FORCE_INLINE_ void load(const Dictionary &p_params) {
280
textDocument.load(p_params["textDocument"]);
281
}
282
};
283
284
/**
285
* A document link is a range in a text document that links to an internal or external resource, like another
286
* text document or a web site.
287
*/
288
struct DocumentLink {
289
/**
290
* The range this link applies to.
291
*/
292
Range range;
293
294
/**
295
* The uri this link points to. If missing a resolve request is sent later.
296
*/
297
DocumentUri target;
298
299
Dictionary to_json() const {
300
Dictionary dict;
301
dict["range"] = range.to_json();
302
dict["target"] = target;
303
return dict;
304
}
305
};
306
307
/**
308
* A textual edit applicable to a text document.
309
*/
310
struct TextEdit {
311
/**
312
* The range of the text document to be manipulated. To insert
313
* text into a document create a range where start === end.
314
*/
315
Range range;
316
317
/**
318
* The string to be inserted. For delete operations use an
319
* empty string.
320
*/
321
String newText;
322
};
323
324
/**
325
* The edits to be applied.
326
*/
327
struct WorkspaceEdit {
328
/**
329
* Holds changes to existing resources.
330
*/
331
HashMap<String, Vector<TextEdit>> changes;
332
333
_FORCE_INLINE_ void add_edit(const String &uri, const TextEdit &edit) {
334
if (changes.has(uri)) {
335
changes[uri].push_back(edit);
336
} else {
337
Vector<TextEdit> edits;
338
edits.push_back(edit);
339
changes[uri] = edits;
340
}
341
}
342
343
_FORCE_INLINE_ Dictionary to_json() const {
344
Dictionary dict;
345
346
Dictionary out_changes;
347
for (const KeyValue<String, Vector<TextEdit>> &E : changes) {
348
Array edits;
349
for (int i = 0; i < E.value.size(); ++i) {
350
Dictionary text_edit;
351
text_edit["range"] = E.value[i].range.to_json();
352
text_edit["newText"] = E.value[i].newText;
353
edits.push_back(text_edit);
354
}
355
out_changes[E.key] = edits;
356
}
357
dict["changes"] = out_changes;
358
359
return dict;
360
}
361
362
_FORCE_INLINE_ void add_change(const String &uri, const int &line, const int &start_character, const int &end_character, const String &new_text) {
363
TextEdit new_edit;
364
new_edit.newText = new_text;
365
new_edit.range.start.line = line;
366
new_edit.range.start.character = start_character;
367
new_edit.range.end.line = line;
368
new_edit.range.end.character = end_character;
369
370
if (HashMap<String, Vector<TextEdit>>::Iterator E = changes.find(uri)) {
371
E->value.push_back(new_edit);
372
} else {
373
Vector<TextEdit> edit_list;
374
edit_list.push_back(new_edit);
375
changes.insert(uri, edit_list);
376
}
377
}
378
};
379
380
/**
381
* Represents a reference to a command.
382
* Provides a title which will be used to represent a command in the UI.
383
* Commands are identified by a string identifier.
384
* The recommended way to handle commands is to implement their execution on the server side if the client and server provides the corresponding capabilities.
385
* Alternatively the tool extension code could handle the command. The protocol currently doesn’t specify a set of well-known commands.
386
*/
387
struct Command {
388
/**
389
* Title of the command, like `save`.
390
*/
391
String title;
392
/**
393
* The identifier of the actual command handler.
394
*/
395
String command;
396
/**
397
* Arguments that the command handler should be
398
* invoked with.
399
*/
400
Array arguments;
401
402
Dictionary to_json() const {
403
Dictionary dict;
404
dict["title"] = title;
405
dict["command"] = command;
406
if (arguments.size()) {
407
dict["arguments"] = arguments;
408
}
409
return dict;
410
}
411
};
412
413
// Use namespace instead of enumeration to follow the LSP specifications.
414
// `LSP::EnumName::EnumValue` is OK but `LSP::EnumValue` is not.
415
416
namespace TextDocumentSyncKind {
417
/**
418
* Documents should not be synced at all.
419
*/
420
static const int None = 0;
421
422
/**
423
* Documents are synced by always sending the full content
424
* of the document.
425
*/
426
static const int Full = 1;
427
428
/**
429
* Documents are synced by sending the full content on open.
430
* After that only incremental updates to the document are
431
* send.
432
*/
433
static const int Incremental = 2;
434
}; // namespace TextDocumentSyncKind
435
436
namespace MessageType {
437
/**
438
* An error message.
439
*/
440
static const int Error = 1;
441
/**
442
* A warning message.
443
*/
444
static const int Warning = 2;
445
/**
446
* An information message.
447
*/
448
static const int Info = 3;
449
/**
450
* A log message.
451
*/
452
static const int Log = 4;
453
}; // namespace MessageType
454
455
/**
456
* Completion options.
457
*/
458
struct CompletionOptions {
459
/**
460
* The server provides support to resolve additional
461
* information for a completion item.
462
*/
463
bool resolveProvider = true;
464
465
/**
466
* The characters that trigger completion automatically.
467
*/
468
Vector<String> triggerCharacters;
469
470
CompletionOptions() {
471
triggerCharacters.push_back(".");
472
triggerCharacters.push_back("$");
473
triggerCharacters.push_back("'");
474
triggerCharacters.push_back("\"");
475
}
476
477
Dictionary to_json() const {
478
Dictionary dict;
479
dict["resolveProvider"] = resolveProvider;
480
dict["triggerCharacters"] = triggerCharacters;
481
return dict;
482
}
483
};
484
485
/**
486
* Signature help options.
487
*/
488
struct SignatureHelpOptions {
489
/**
490
* The characters that trigger signature help
491
* automatically.
492
*/
493
Vector<String> triggerCharacters;
494
495
Dictionary to_json() {
496
Dictionary dict;
497
dict["triggerCharacters"] = triggerCharacters;
498
return dict;
499
}
500
};
501
502
/**
503
* Code Lens options.
504
*/
505
struct CodeLensOptions {
506
/**
507
* Code lens has a resolve provider as well.
508
*/
509
bool resolveProvider = false;
510
511
Dictionary to_json() {
512
Dictionary dict;
513
dict["resolveProvider"] = resolveProvider;
514
return dict;
515
}
516
};
517
518
/**
519
* Rename options
520
*/
521
struct RenameOptions {
522
/**
523
* Renames should be checked and tested before being executed.
524
*/
525
bool prepareProvider = true;
526
527
Dictionary to_json() {
528
Dictionary dict;
529
dict["prepareProvider"] = prepareProvider;
530
return dict;
531
}
532
};
533
534
/**
535
* Document link options.
536
*/
537
struct DocumentLinkOptions {
538
/**
539
* Document links have a resolve provider as well.
540
*/
541
bool resolveProvider = false;
542
543
Dictionary to_json() {
544
Dictionary dict;
545
dict["resolveProvider"] = resolveProvider;
546
return dict;
547
}
548
};
549
550
/**
551
* Execute command options.
552
*/
553
struct ExecuteCommandOptions {
554
/**
555
* The commands to be executed on the server
556
*/
557
Vector<String> commands;
558
559
Dictionary to_json() {
560
Dictionary dict;
561
dict["commands"] = commands;
562
return dict;
563
}
564
};
565
566
/**
567
* Save options.
568
*/
569
struct SaveOptions {
570
/**
571
* The client is supposed to include the content on save.
572
*/
573
bool includeText = true;
574
575
Dictionary to_json() {
576
Dictionary dict;
577
dict["includeText"] = includeText;
578
return dict;
579
}
580
};
581
582
/**
583
* Color provider options.
584
*/
585
struct ColorProviderOptions {
586
Dictionary to_json() {
587
return Dictionary();
588
}
589
};
590
591
/**
592
* Folding range provider options.
593
*/
594
struct FoldingRangeProviderOptions {
595
Dictionary to_json() {
596
return Dictionary();
597
}
598
};
599
600
struct TextDocumentSyncOptions {
601
/**
602
* Open and close notifications are sent to the server. If omitted open close notification should not
603
* be sent.
604
*/
605
bool openClose = true;
606
607
/**
608
* Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full
609
* and TextDocumentSyncKind.Incremental. If omitted it defaults to TextDocumentSyncKind.None.
610
*/
611
int change = TextDocumentSyncKind::Full;
612
613
/**
614
* If present will save notifications are sent to the server. If omitted the notification should not be
615
* sent.
616
*/
617
bool willSave = false;
618
619
/**
620
* If present will save wait until requests are sent to the server. If omitted the request should not be
621
* sent.
622
*/
623
bool willSaveWaitUntil = true;
624
625
/**
626
* If present save notifications are sent to the server. If omitted the notification should not be
627
* sent.
628
*/
629
SaveOptions save;
630
631
Dictionary to_json() {
632
Dictionary dict;
633
dict["willSaveWaitUntil"] = willSaveWaitUntil;
634
dict["willSave"] = willSave;
635
dict["openClose"] = openClose;
636
dict["change"] = change;
637
dict["save"] = save.to_json();
638
return dict;
639
}
640
};
641
642
/**
643
* Static registration options to be returned in the initialize request.
644
*/
645
struct StaticRegistrationOptions {
646
/**
647
* The id used to register the request. The id can be used to deregister
648
* the request again. See also Registration#id.
649
*/
650
String id;
651
};
652
653
/**
654
* Format document on type options.
655
*/
656
struct DocumentOnTypeFormattingOptions {
657
/**
658
* A character on which formatting should be triggered, like `}`.
659
*/
660
String firstTriggerCharacter;
661
662
/**
663
* More trigger characters.
664
*/
665
Vector<String> moreTriggerCharacter;
666
667
Dictionary to_json() {
668
Dictionary dict;
669
dict["firstTriggerCharacter"] = firstTriggerCharacter;
670
dict["moreTriggerCharacter"] = moreTriggerCharacter;
671
return dict;
672
}
673
};
674
675
enum class LanguageId {
676
GDSCRIPT,
677
OTHER,
678
};
679
680
struct TextDocumentItem {
681
/**
682
* The text document's URI.
683
*/
684
DocumentUri uri;
685
686
/**
687
* The text document's language identifier.
688
*/
689
LanguageId languageId;
690
691
/**
692
* The version number of this document (it will increase after each
693
* change, including undo/redo).
694
*/
695
int version = 0;
696
697
/**
698
* The content of the opened text document.
699
*/
700
String text;
701
702
void load(const Dictionary &p_dict) {
703
uri = p_dict["uri"];
704
version = p_dict["version"];
705
text = p_dict["text"];
706
707
// Clients should use "gdscript" as language id, but we can't enforce it.
708
// We normalize some known ids to make them easier to work with:
709
// Rider < 2026.1: "gd"
710
// Kate: "godot"
711
String rawLanguageId = p_dict["languageId"];
712
if (rawLanguageId == "gdscript" || rawLanguageId == "gd" || rawLanguageId == "godot") {
713
languageId = LanguageId::GDSCRIPT;
714
} else {
715
languageId = LanguageId::OTHER;
716
}
717
}
718
};
719
720
/**
721
* An event describing a change to a text document.
722
*/
723
struct TextDocumentContentChangeEvent {
724
/**
725
* The new text of the range/document.
726
*/
727
String text;
728
729
void load(const Dictionary &p_params) {
730
text = p_params["text"];
731
}
732
};
733
734
// Use namespace instead of enumeration to follow the LSP specifications
735
namespace DiagnosticSeverity {
736
/**
737
* Reports an error.
738
*/
739
static const int Error = 1;
740
/**
741
* Reports a warning.
742
*/
743
static const int Warning = 2;
744
/**
745
* Reports an information.
746
*/
747
static const int Information = 3;
748
/**
749
* Reports a hint.
750
*/
751
static const int Hint = 4;
752
}; // namespace DiagnosticSeverity
753
754
/**
755
* Represents a related message and source code location for a diagnostic. This should be
756
* used to point to code locations that cause or related to a diagnostics, e.g when duplicating
757
* a symbol in a scope.
758
*/
759
struct DiagnosticRelatedInformation {
760
/**
761
* The location of this related diagnostic information.
762
*/
763
Location location;
764
765
/**
766
* The message of this related diagnostic information.
767
*/
768
String message;
769
770
Dictionary to_json() const {
771
Dictionary dict;
772
dict["location"] = location.to_json();
773
dict["message"] = message;
774
return dict;
775
}
776
};
777
778
/**
779
* Represents a diagnostic, such as a compiler error or warning.
780
* Diagnostic objects are only valid in the scope of a resource.
781
*/
782
struct Diagnostic {
783
/**
784
* The range at which the message applies.
785
*/
786
Range range;
787
788
/**
789
* The diagnostic's severity. Can be omitted. If omitted it is up to the
790
* client to interpret diagnostics as error, warning, info or hint.
791
*/
792
int severity = 0;
793
794
/**
795
* The diagnostic's code, which might appear in the user interface.
796
*/
797
int code = 0;
798
799
/**
800
* A human-readable string describing the source of this
801
* diagnostic, e.g. 'typescript' or 'super lint'.
802
*/
803
String source;
804
805
/**
806
* The diagnostic's message.
807
*/
808
String message;
809
810
/**
811
* An array of related diagnostic information, e.g. when symbol-names within
812
* a scope collide all definitions can be marked via this property.
813
*/
814
Vector<DiagnosticRelatedInformation> relatedInformation;
815
816
Dictionary to_json() const {
817
Dictionary dict;
818
dict["range"] = range.to_json();
819
dict["code"] = code;
820
dict["severity"] = severity;
821
dict["message"] = message;
822
dict["source"] = source;
823
if (!relatedInformation.is_empty()) {
824
Array arr;
825
arr.resize(relatedInformation.size());
826
for (int i = 0; i < relatedInformation.size(); i++) {
827
arr[i] = relatedInformation[i].to_json();
828
}
829
dict["relatedInformation"] = arr;
830
}
831
return dict;
832
}
833
};
834
835
// Use namespace instead of enumeration to follow the LSP specifications
836
/**
837
* Describes the content type that a client supports in various
838
* result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
839
*
840
* Please note that `MarkupKinds` must not start with a `$`. This kinds
841
* are reserved for internal usage.
842
*/
843
namespace MarkupKind {
844
static const String PlainText = "plaintext";
845
static const String Markdown = "markdown";
846
}; // namespace MarkupKind
847
848
/**
849
* A `MarkupContent` literal represents a string value which content is interpreted base on its
850
* kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds.
851
*
852
* If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues.
853
* See https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting
854
*
855
* Here is an example how such a string can be constructed using JavaScript / TypeScript:
856
* ```typescript
857
* let markdown: MarkdownContent = {
858
* kind: MarkupKind.Markdown,
859
* value: [
860
* '# Header',
861
* 'Some text',
862
* '```typescript',
863
* 'someCode();',
864
* '```'
865
* ].join('\n')
866
* };
867
* ```
868
*
869
* *Please Note* that clients might sanitize the return markdown. A client could decide to
870
* remove HTML from the markdown to avoid script execution.
871
*/
872
struct MarkupContent {
873
/**
874
* The type of the Markup.
875
*/
876
String kind;
877
878
/**
879
* The content itself.
880
*/
881
String value;
882
883
MarkupContent() {
884
kind = MarkupKind::Markdown;
885
}
886
887
MarkupContent(const String &p_value) {
888
value = p_value;
889
kind = MarkupKind::Markdown;
890
}
891
892
Dictionary to_json() const {
893
Dictionary dict;
894
dict["kind"] = kind;
895
dict["value"] = value;
896
return dict;
897
}
898
};
899
900
// Use namespace instead of enumeration to follow the LSP specifications
901
// `LSP::EnumName::EnumValue` is OK but `LSP::EnumValue` is not.
902
// And here C++ compilers are unhappy with our enumeration name like `Color`, `File`, `RefCounted` etc.
903
/**
904
* The kind of a completion entry.
905
*/
906
namespace CompletionItemKind {
907
static const int Text = 1;
908
static const int Method = 2;
909
static const int Function = 3;
910
static const int Constructor = 4;
911
static const int Field = 5;
912
static const int Variable = 6;
913
static const int Class = 7;
914
static const int Interface = 8;
915
static const int Module = 9;
916
static const int Property = 10;
917
static const int Unit = 11;
918
static const int Value = 12;
919
static const int Enum = 13;
920
static const int Keyword = 14;
921
static const int Snippet = 15;
922
static const int Color = 16;
923
static const int File = 17;
924
static const int RefCounted = 18;
925
static const int Folder = 19;
926
static const int EnumMember = 20;
927
static const int Constant = 21;
928
static const int Struct = 22;
929
static const int Event = 23;
930
static const int Operator = 24;
931
static const int TypeParameter = 25;
932
}; // namespace CompletionItemKind
933
934
// Use namespace instead of enumeration to follow the LSP specifications.
935
/**
936
* Defines whether the insert text in a completion item should be interpreted as
937
* plain text or a snippet.
938
*/
939
namespace InsertTextFormat {
940
/**
941
* The primary text to be inserted is treated as a plain string.
942
*/
943
static const int PlainText = 1;
944
945
/**
946
* The primary text to be inserted is treated as a snippet.
947
*
948
* A snippet can define tab stops and placeholders with `$1`, `$2`
949
* and `${3:foo}`. `$0` defines the final tab stop, it defaults to
950
* the end of the snippet. Placeholders with equal identifiers are linked,
951
* that is typing in one will update others too.
952
*/
953
static const int Snippet = 2;
954
}; // namespace InsertTextFormat
955
956
struct CompletionItem {
957
/**
958
* The label of this completion item. By default
959
* also the text that is inserted when selecting
960
* this completion.
961
*/
962
String label;
963
964
/**
965
* The kind of this completion item. Based of the kind
966
* an icon is chosen by the editor. The standardized set
967
* of available values is defined in `CompletionItemKind`.
968
*/
969
int kind = 0;
970
971
/**
972
* A human-readable string with additional information
973
* about this item, like type or symbol information.
974
*/
975
String detail;
976
977
/**
978
* A human-readable string that represents a doc-comment.
979
*/
980
MarkupContent documentation;
981
982
/**
983
* Indicates if this item is deprecated.
984
*/
985
bool deprecated = false;
986
987
/**
988
* Select this item when showing.
989
*
990
* *Note* that only one completion item can be selected and that the
991
* tool / client decides which item that is. The rule is that the *first*
992
* item of those that match best is selected.
993
*/
994
bool preselect = false;
995
996
/**
997
* A string that should be used when comparing this item
998
* with other items. When omitted the label is used
999
* as the filter text for this item.
1000
*/
1001
String sortText;
1002
1003
/**
1004
* A string that should be used when filtering a set of
1005
* completion items. When omitted the label is used as the
1006
* filter text for this item.
1007
*/
1008
String filterText;
1009
1010
/**
1011
* A string that should be inserted into a document when selecting
1012
* this completion. When omitted the label is used as the insert text
1013
* for this item.
1014
*
1015
* The `insertText` is subject to interpretation by the client side.
1016
* Some tools might not take the string literally. For example
1017
* VS Code when code complete is requested in this example
1018
* `con<cursor position>` and a completion item with an `insertText` of
1019
* `console` is provided it will only insert `sole`. Therefore it is
1020
* recommended to use `textEdit` instead since it avoids additional client
1021
* side interpretation.
1022
*/
1023
String insertText;
1024
1025
/**
1026
* The format of the insert text. The format applies to both the `insertText` property
1027
* and the `newText` property of a provided `textEdit`.
1028
*/
1029
int insertTextFormat = 0;
1030
1031
/**
1032
* An edit which is applied to a document when selecting this completion. When an edit is provided the value of
1033
* `insertText` is ignored.
1034
*
1035
* *Note:* The range of the edit must be a single line range and it must contain the position at which completion
1036
* has been requested.
1037
*/
1038
TextEdit textEdit;
1039
1040
/**
1041
* An optional array of additional text edits that are applied when
1042
* selecting this completion. Edits must not overlap (including the same insert position)
1043
* with the main edit nor with themselves.
1044
*
1045
* Additional text edits should be used to change text unrelated to the current cursor position
1046
* (for example adding an import statement at the top of the file if the completion item will
1047
* insert an unqualified type).
1048
*/
1049
Vector<TextEdit> additionalTextEdits;
1050
1051
/**
1052
* An optional set of characters that when pressed while this completion is active will accept it first and
1053
* then type that character. *Note* that all commit characters should have `length=1` and that superfluous
1054
* characters will be ignored.
1055
*/
1056
Vector<String> commitCharacters;
1057
1058
/**
1059
* An optional command that is executed *after* inserting this completion. *Note* that
1060
* additional modifications to the current document should be described with the
1061
* additionalTextEdits-property.
1062
*/
1063
Command command;
1064
1065
/**
1066
* A data entry field that is preserved on a completion item between
1067
* a completion and a completion resolve request.
1068
*/
1069
Variant data;
1070
1071
_FORCE_INLINE_ Dictionary to_json(bool resolved = false) const {
1072
Dictionary dict;
1073
dict["label"] = label;
1074
dict["kind"] = kind;
1075
dict["data"] = data;
1076
if (!insertText.is_empty()) {
1077
dict["insertText"] = insertText;
1078
}
1079
if (resolved) {
1080
dict["detail"] = detail;
1081
dict["documentation"] = documentation.to_json();
1082
dict["deprecated"] = deprecated;
1083
dict["preselect"] = preselect;
1084
if (!sortText.is_empty()) {
1085
dict["sortText"] = sortText;
1086
}
1087
if (!filterText.is_empty()) {
1088
dict["filterText"] = filterText;
1089
}
1090
if (commitCharacters.size()) {
1091
dict["commitCharacters"] = commitCharacters;
1092
}
1093
if (!command.command.is_empty()) {
1094
dict["command"] = command.to_json();
1095
}
1096
}
1097
return dict;
1098
}
1099
1100
void load(const Dictionary &p_dict) {
1101
if (p_dict.has("label")) {
1102
label = p_dict["label"];
1103
}
1104
if (p_dict.has("kind")) {
1105
kind = p_dict["kind"];
1106
}
1107
if (p_dict.has("detail")) {
1108
detail = p_dict["detail"];
1109
}
1110
if (p_dict.has("documentation")) {
1111
Variant doc = p_dict["documentation"];
1112
if (doc.is_string()) {
1113
documentation.value = doc;
1114
} else if (doc.get_type() == Variant::DICTIONARY) {
1115
Dictionary v = doc;
1116
documentation.value = v["value"];
1117
}
1118
}
1119
if (p_dict.has("deprecated")) {
1120
deprecated = p_dict["deprecated"];
1121
}
1122
if (p_dict.has("preselect")) {
1123
preselect = p_dict["preselect"];
1124
}
1125
if (p_dict.has("sortText")) {
1126
sortText = p_dict["sortText"];
1127
}
1128
if (p_dict.has("filterText")) {
1129
filterText = p_dict["filterText"];
1130
}
1131
if (p_dict.has("insertText")) {
1132
insertText = p_dict["insertText"];
1133
}
1134
if (p_dict.has("data")) {
1135
data = p_dict["data"];
1136
}
1137
}
1138
};
1139
1140
/**
1141
* Represents a collection of [completion items](#CompletionItem) to be presented
1142
* in the editor.
1143
*/
1144
struct CompletionList {
1145
/**
1146
* This list it not complete. Further typing should result in recomputing
1147
* this list.
1148
*/
1149
bool isIncomplete = false;
1150
1151
/**
1152
* The completion items.
1153
*/
1154
Vector<CompletionItem> items;
1155
};
1156
1157
// Use namespace instead of enumeration to follow the LSP specifications
1158
// `LSP::EnumName::EnumValue` is OK but `LSP::EnumValue` is not
1159
// And here C++ compilers are unhappy with our enumeration name like `String`, `Array`, `Object` etc
1160
/**
1161
* A symbol kind.
1162
*/
1163
namespace SymbolKind {
1164
static const int File = 1;
1165
static const int Module = 2;
1166
static const int Namespace = 3;
1167
static const int Package = 4;
1168
static const int Class = 5;
1169
static const int Method = 6;
1170
static const int Property = 7;
1171
static const int Field = 8;
1172
static const int Constructor = 9;
1173
static const int Enum = 10;
1174
static const int Interface = 11;
1175
static const int Function = 12;
1176
static const int Variable = 13;
1177
static const int Constant = 14;
1178
static const int String = 15;
1179
static const int Number = 16;
1180
static const int Boolean = 17;
1181
static const int Array = 18;
1182
static const int Object = 19;
1183
static const int Key = 20;
1184
static const int Null = 21;
1185
static const int EnumMember = 22;
1186
static const int Struct = 23;
1187
static const int Event = 24;
1188
static const int Operator = 25;
1189
static const int TypeParameter = 26;
1190
}; // namespace SymbolKind
1191
1192
/**
1193
* Represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document symbols can be
1194
* hierarchical and they have two ranges: one that encloses its definition and one that points to its most interesting range,
1195
* e.g. the range of an identifier.
1196
*/
1197
struct DocumentSymbol {
1198
/**
1199
* The name of this symbol. Will be displayed in the user interface and therefore must not be
1200
* an empty string or a string only consisting of white spaces.
1201
*/
1202
String name;
1203
1204
/**
1205
* More detail for this symbol, e.g the signature of a function.
1206
*/
1207
String detail;
1208
1209
/**
1210
* Documentation for this symbol.
1211
*/
1212
String documentation;
1213
1214
/**
1215
* Class name for the native symbols.
1216
*/
1217
String native_class;
1218
1219
/**
1220
* The kind of this symbol.
1221
*/
1222
int kind = SymbolKind::File;
1223
1224
/**
1225
* Indicates if this symbol is deprecated.
1226
*/
1227
bool deprecated = false;
1228
1229
/**
1230
* If `true`: Symbol is local to script and cannot be accessed somewhere else.
1231
*
1232
* For example: local variable inside a `func`.
1233
*/
1234
bool local = false;
1235
1236
/**
1237
* The range enclosing this symbol not including leading/trailing whitespace but everything else
1238
* like comments. This information is typically used to determine if the clients cursor is
1239
* inside the symbol to reveal in the symbol in the UI.
1240
*/
1241
Range range;
1242
1243
/**
1244
* The range that should be selected and revealed when this symbol is being picked, e.g the name of a function.
1245
* Must be contained by the `range`.
1246
*/
1247
Range selectionRange;
1248
1249
DocumentUri uri;
1250
String script_path;
1251
1252
/**
1253
* Children of this symbol, e.g. properties of a class.
1254
*/
1255
Vector<DocumentSymbol> children;
1256
1257
Dictionary to_json(bool with_doc = false) const {
1258
Dictionary dict;
1259
dict["name"] = name;
1260
dict["detail"] = detail;
1261
dict["kind"] = kind;
1262
dict["deprecated"] = deprecated;
1263
dict["range"] = range.to_json();
1264
dict["selectionRange"] = selectionRange.to_json();
1265
if (with_doc) {
1266
dict["documentation"] = documentation;
1267
dict["native_class"] = native_class;
1268
}
1269
if (!children.is_empty()) {
1270
Array arr;
1271
for (int i = 0; i < children.size(); i++) {
1272
if (children[i].local) {
1273
continue;
1274
}
1275
arr.push_back(children[i].to_json(with_doc));
1276
}
1277
if (!children.is_empty()) {
1278
dict["children"] = arr;
1279
}
1280
}
1281
return dict;
1282
}
1283
1284
_FORCE_INLINE_ MarkupContent render() const {
1285
MarkupContent markdown;
1286
if (detail.length()) {
1287
markdown.value = "\t" + detail + "\n\n";
1288
}
1289
if (documentation.length()) {
1290
markdown.value += marked_documentation(documentation) + "\n\n";
1291
}
1292
if (script_path.length()) {
1293
markdown.value += "Defined in [" + script_path + "](" + uri + ")";
1294
}
1295
return markdown;
1296
}
1297
1298
_FORCE_INLINE_ CompletionItem make_completion_item(bool resolved = false) const {
1299
LSP::CompletionItem item;
1300
item.label = name;
1301
1302
if (resolved) {
1303
item.documentation = render();
1304
}
1305
1306
switch (kind) {
1307
case LSP::SymbolKind::Enum:
1308
item.kind = LSP::CompletionItemKind::Enum;
1309
break;
1310
case LSP::SymbolKind::Class:
1311
item.kind = LSP::CompletionItemKind::Class;
1312
break;
1313
case LSP::SymbolKind::Property:
1314
item.kind = LSP::CompletionItemKind::Property;
1315
break;
1316
case LSP::SymbolKind::Method:
1317
case LSP::SymbolKind::Function:
1318
item.kind = LSP::CompletionItemKind::Method;
1319
break;
1320
case LSP::SymbolKind::Event:
1321
item.kind = LSP::CompletionItemKind::Event;
1322
break;
1323
case LSP::SymbolKind::Constant:
1324
item.kind = LSP::CompletionItemKind::Constant;
1325
break;
1326
case LSP::SymbolKind::Variable:
1327
item.kind = LSP::CompletionItemKind::Variable;
1328
break;
1329
case LSP::SymbolKind::File:
1330
item.kind = LSP::CompletionItemKind::File;
1331
break;
1332
default:
1333
item.kind = LSP::CompletionItemKind::Text;
1334
break;
1335
}
1336
1337
return item;
1338
}
1339
};
1340
1341
struct ApplyWorkspaceEditParams {
1342
WorkspaceEdit edit;
1343
1344
Dictionary to_json() {
1345
Dictionary dict;
1346
1347
dict["edit"] = edit.to_json();
1348
1349
return dict;
1350
}
1351
};
1352
1353
struct NativeSymbolInspectParams {
1354
String native_class;
1355
String symbol_name;
1356
1357
void load(const Dictionary &p_params) {
1358
native_class = p_params["native_class"];
1359
symbol_name = p_params["symbol_name"];
1360
}
1361
};
1362
1363
/**
1364
* Enum of known range kinds
1365
*/
1366
namespace FoldingRangeKind {
1367
/**
1368
* Folding range for a comment
1369
*/
1370
static const String Comment = "comment";
1371
/**
1372
* Folding range for a imports or includes
1373
*/
1374
static const String Imports = "imports";
1375
/**
1376
* Folding range for a region (e.g. `#region`)
1377
*/
1378
static const String Region = "region";
1379
} // namespace FoldingRangeKind
1380
1381
/**
1382
* Represents a folding range.
1383
*/
1384
struct FoldingRange {
1385
/**
1386
* The zero-based line number from where the folded range starts.
1387
*/
1388
int startLine = 0;
1389
1390
/**
1391
* The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line.
1392
*/
1393
int startCharacter = 0;
1394
1395
/**
1396
* The zero-based line number where the folded range ends.
1397
*/
1398
int endLine = 0;
1399
1400
/**
1401
* The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line.
1402
*/
1403
int endCharacter = 0;
1404
1405
/**
1406
* Describes the kind of the folding range such as `comment' or 'region'. The kind
1407
* is used to categorize folding ranges and used by commands like 'Fold all comments'. See
1408
* [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds.
1409
*/
1410
String kind = FoldingRangeKind::Region;
1411
1412
_FORCE_INLINE_ Dictionary to_json() const {
1413
Dictionary dict;
1414
dict["startLine"] = startLine;
1415
dict["startCharacter"] = startCharacter;
1416
dict["endLine"] = endLine;
1417
dict["endCharacter"] = endCharacter;
1418
return dict;
1419
}
1420
};
1421
1422
// Use namespace instead of enumeration to follow the LSP specifications
1423
/**
1424
* How a completion was triggered
1425
*/
1426
namespace CompletionTriggerKind {
1427
/**
1428
* Completion was triggered by typing an identifier (24x7 code
1429
* complete), manual invocation (e.g Ctrl+Space) or via API.
1430
*/
1431
static const int Invoked = 1;
1432
1433
/**
1434
* Completion was triggered by a trigger character specified by
1435
* the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
1436
*/
1437
static const int TriggerCharacter = 2;
1438
1439
/**
1440
* Completion was re-triggered as the current completion list is incomplete.
1441
*/
1442
static const int TriggerForIncompleteCompletions = 3;
1443
} // namespace CompletionTriggerKind
1444
1445
/**
1446
* Contains additional information about the context in which a completion request is triggered.
1447
*/
1448
struct CompletionContext {
1449
/**
1450
* How the completion was triggered.
1451
*/
1452
int triggerKind = CompletionTriggerKind::Invoked;
1453
1454
/**
1455
* The trigger character (a single character) that has trigger code complete.
1456
* Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter`
1457
*/
1458
String triggerCharacter;
1459
1460
void load(const Dictionary &p_params) {
1461
triggerKind = int(p_params["triggerKind"]);
1462
triggerCharacter = p_params.get("triggerCharacter", "");
1463
}
1464
};
1465
1466
struct CompletionParams : public TextDocumentPositionParams {
1467
/**
1468
* The completion context. This is only available if the client specifies
1469
* to send this using `ClientCapabilities.textDocument.completion.contextSupport === true`
1470
*/
1471
CompletionContext context;
1472
1473
void load(const Dictionary &p_params) {
1474
TextDocumentPositionParams::load(p_params);
1475
1476
if (p_params.has("context")) {
1477
context.load(p_params["context"]);
1478
}
1479
}
1480
1481
Dictionary to_json() {
1482
Dictionary ctx;
1483
ctx["triggerCharacter"] = context.triggerCharacter;
1484
ctx["triggerKind"] = context.triggerKind;
1485
1486
Dictionary dict;
1487
dict = TextDocumentPositionParams::to_json();
1488
dict["context"] = ctx;
1489
return dict;
1490
}
1491
};
1492
1493
/**
1494
* The result of a hover request.
1495
*/
1496
struct Hover {
1497
/**
1498
* The hover's content
1499
*/
1500
MarkupContent contents;
1501
1502
/**
1503
* An optional range is a range inside a text document
1504
* that is used to visualize a hover, e.g. by changing the background color.
1505
*/
1506
Range range;
1507
1508
_FORCE_INLINE_ Dictionary to_json() const {
1509
Dictionary dict;
1510
dict["range"] = range.to_json();
1511
dict["contents"] = contents.to_json();
1512
return dict;
1513
}
1514
};
1515
1516
/**
1517
* Represents a parameter of a callable-signature. A parameter can
1518
* have a label and a doc-comment.
1519
*/
1520
struct ParameterInformation {
1521
/**
1522
* The label of this parameter information.
1523
*
1524
* Either a string or an inclusive start and exclusive end offsets within its containing
1525
* signature label. (see SignatureInformation.label). The offsets are based on a UTF-16
1526
* string representation as `Position` and `Range` does.
1527
*
1528
* *Note*: a label of type string should be a substring of its containing signature label.
1529
* Its intended use case is to highlight the parameter label part in the `SignatureInformation.label`.
1530
*/
1531
String label;
1532
1533
/**
1534
* The human-readable doc-comment of this parameter. Will be shown
1535
* in the UI but can be omitted.
1536
*/
1537
MarkupContent documentation;
1538
1539
Dictionary to_json() const {
1540
Dictionary dict;
1541
dict["label"] = label;
1542
dict["documentation"] = documentation.to_json();
1543
return dict;
1544
}
1545
};
1546
1547
/**
1548
* Represents the signature of something callable. A signature
1549
* can have a label, like a function-name, a doc-comment, and
1550
* a set of parameters.
1551
*/
1552
struct SignatureInformation {
1553
/**
1554
* The label of this signature. Will be shown in
1555
* the UI.
1556
*/
1557
String label;
1558
1559
/**
1560
* The human-readable doc-comment of this signature. Will be shown
1561
* in the UI but can be omitted.
1562
*/
1563
MarkupContent documentation;
1564
1565
/**
1566
* The parameters of this signature.
1567
*/
1568
Vector<ParameterInformation> parameters;
1569
1570
Dictionary to_json() const {
1571
Dictionary dict;
1572
dict["label"] = label;
1573
dict["documentation"] = documentation.to_json();
1574
Array args;
1575
for (int i = 0; i < parameters.size(); i++) {
1576
args.push_back(parameters[i].to_json());
1577
}
1578
dict["parameters"] = args;
1579
return dict;
1580
}
1581
};
1582
1583
/**
1584
* Signature help represents the signature of something
1585
* callable. There can be multiple signature but only one
1586
* active and only one active parameter.
1587
*/
1588
struct SignatureHelp {
1589
/**
1590
* One or more signatures.
1591
*/
1592
Vector<SignatureInformation> signatures;
1593
1594
/**
1595
* The active signature. If omitted or the value lies outside the
1596
* range of `signatures` the value defaults to zero or is ignored if
1597
* `signatures.length === 0`. Whenever possible implementers should
1598
* make an active decision about the active signature and shouldn't
1599
* rely on a default value.
1600
* In future version of the protocol this property might become
1601
* mandatory to better express this.
1602
*/
1603
int activeSignature = 0;
1604
1605
/**
1606
* The active parameter of the active signature. If omitted or the value
1607
* lies outside the range of `signatures[activeSignature].parameters`
1608
* defaults to 0 if the active signature has parameters. If
1609
* the active signature has no parameters it is ignored.
1610
* In future version of the protocol this property might become
1611
* mandatory to better express the active parameter if the
1612
* active signature does have any.
1613
*/
1614
int activeParameter = 0;
1615
1616
Dictionary to_json() const {
1617
Dictionary dict;
1618
Array sigs;
1619
for (int i = 0; i < signatures.size(); i++) {
1620
sigs.push_back(signatures[i].to_json());
1621
}
1622
dict["signatures"] = sigs;
1623
dict["activeSignature"] = activeSignature;
1624
dict["activeParameter"] = activeParameter;
1625
return dict;
1626
}
1627
};
1628
1629
/**
1630
* A pattern to describe in which file operation requests or notifications
1631
* the server is interested in.
1632
*/
1633
struct FileOperationPattern {
1634
/**
1635
* The glob pattern to match.
1636
*/
1637
String glob = "**/*.gd";
1638
1639
/**
1640
* Whether to match `file`s or `folder`s with this pattern.
1641
*
1642
* Matches both if undefined.
1643
*/
1644
String matches = "file";
1645
1646
Dictionary to_json() const {
1647
Dictionary dict;
1648
1649
dict["glob"] = glob;
1650
dict["matches"] = matches;
1651
1652
return dict;
1653
}
1654
};
1655
1656
/**
1657
* A filter to describe in which file operation requests or notifications
1658
* the server is interested in.
1659
*/
1660
struct FileOperationFilter {
1661
/**
1662
* The actual file operation pattern.
1663
*/
1664
FileOperationPattern pattern;
1665
1666
Dictionary to_json() const {
1667
Dictionary dict;
1668
1669
dict["pattern"] = pattern.to_json();
1670
1671
return dict;
1672
}
1673
};
1674
1675
/**
1676
* The options to register for file operations.
1677
*/
1678
struct FileOperationRegistrationOptions {
1679
/**
1680
* The actual filters.
1681
*/
1682
Vector<FileOperationFilter> filters;
1683
1684
FileOperationRegistrationOptions() {
1685
filters.push_back(FileOperationFilter());
1686
}
1687
1688
Dictionary to_json() const {
1689
Dictionary dict;
1690
1691
Array filts;
1692
for (int i = 0; i < filters.size(); i++) {
1693
filts.push_back(filters[i].to_json());
1694
}
1695
dict["filters"] = filts;
1696
1697
return dict;
1698
}
1699
};
1700
1701
/**
1702
* The server is interested in file notifications/requests.
1703
*/
1704
struct FileOperations {
1705
/**
1706
* The server is interested in receiving didDeleteFiles file notifications.
1707
*/
1708
FileOperationRegistrationOptions didDelete;
1709
1710
Dictionary to_json() const {
1711
Dictionary dict;
1712
1713
dict["didDelete"] = didDelete.to_json();
1714
1715
return dict;
1716
}
1717
};
1718
1719
/**
1720
* Workspace specific server capabilities
1721
*/
1722
struct Workspace {
1723
Dictionary to_json() const {
1724
Dictionary dict;
1725
return dict;
1726
}
1727
};
1728
1729
struct ServerCapabilities {
1730
/**
1731
* Defines how text documents are synced. Is either a detailed structure defining each notification or
1732
* for backwards compatibility the TextDocumentSyncKind number. If omitted it defaults to `TextDocumentSyncKind.None`.
1733
*/
1734
TextDocumentSyncOptions textDocumentSync;
1735
1736
/**
1737
* The server provides hover support.
1738
*/
1739
bool hoverProvider = true;
1740
1741
/**
1742
* The server provides completion support.
1743
*/
1744
CompletionOptions completionProvider;
1745
1746
/**
1747
* The server provides signature help support.
1748
*/
1749
SignatureHelpOptions signatureHelpProvider;
1750
1751
/**
1752
* The server provides goto definition support.
1753
*/
1754
bool definitionProvider = true;
1755
1756
/**
1757
* The server provides Goto Type Definition support.
1758
*
1759
* Since 3.6.0
1760
*/
1761
bool typeDefinitionProvider = false;
1762
1763
/**
1764
* The server provides Goto Implementation support.
1765
*
1766
* Since 3.6.0
1767
*/
1768
bool implementationProvider = false;
1769
1770
/**
1771
* The server provides find references support.
1772
*/
1773
bool referencesProvider = true;
1774
1775
/**
1776
* The server provides document highlight support.
1777
*/
1778
bool documentHighlightProvider = true;
1779
1780
/**
1781
* The server provides document symbol support.
1782
*/
1783
bool documentSymbolProvider = true;
1784
1785
/**
1786
* The server provides workspace symbol support.
1787
*/
1788
bool workspaceSymbolProvider = false;
1789
1790
/**
1791
* The server supports workspace folder.
1792
*/
1793
Workspace workspace;
1794
1795
/**
1796
* The server provides code actions. The `CodeActionOptions` return type is only
1797
* valid if the client signals code action literal support via the property
1798
* `textDocument.codeAction.codeActionLiteralSupport`.
1799
*/
1800
bool codeActionProvider = false;
1801
1802
/**
1803
* The server provides code lens.
1804
*/
1805
CodeLensOptions codeLensProvider;
1806
1807
/**
1808
* The server provides document formatting.
1809
*/
1810
bool documentFormattingProvider = false;
1811
1812
/**
1813
* The server provides document range formatting.
1814
*/
1815
bool documentRangeFormattingProvider = false;
1816
1817
/**
1818
* The server provides document formatting on typing.
1819
*/
1820
DocumentOnTypeFormattingOptions documentOnTypeFormattingProvider;
1821
1822
/**
1823
* The server provides rename support. RenameOptions may only be
1824
* specified if the client states that it supports
1825
* `prepareSupport` in its initial `initialize` request.
1826
*/
1827
RenameOptions renameProvider;
1828
1829
/**
1830
* The server provides document link support.
1831
*/
1832
DocumentLinkOptions documentLinkProvider;
1833
1834
/**
1835
* The server provides color provider support.
1836
*
1837
* Since 3.6.0
1838
*/
1839
ColorProviderOptions colorProvider;
1840
1841
/**
1842
* The server provides folding provider support.
1843
*
1844
* Since 3.10.0
1845
*/
1846
FoldingRangeProviderOptions foldingRangeProvider;
1847
1848
/**
1849
* The server provides go to declaration support.
1850
*
1851
* Since 3.14.0
1852
*/
1853
bool declarationProvider = true;
1854
1855
/**
1856
* The server provides execute command support.
1857
*/
1858
ExecuteCommandOptions executeCommandProvider;
1859
1860
_FORCE_INLINE_ Dictionary to_json() {
1861
Dictionary dict;
1862
dict["textDocumentSync"] = textDocumentSync.to_json();
1863
dict["completionProvider"] = completionProvider.to_json();
1864
signatureHelpProvider.triggerCharacters.push_back(",");
1865
signatureHelpProvider.triggerCharacters.push_back("(");
1866
dict["signatureHelpProvider"] = signatureHelpProvider.to_json();
1867
//dict["codeLensProvider"] = codeLensProvider.to_json();
1868
dict["documentOnTypeFormattingProvider"] = documentOnTypeFormattingProvider.to_json();
1869
dict["renameProvider"] = renameProvider.to_json();
1870
dict["documentLinkProvider"] = documentLinkProvider.to_json();
1871
dict["colorProvider"] = false; // colorProvider.to_json();
1872
dict["foldingRangeProvider"] = false; //foldingRangeProvider.to_json();
1873
dict["executeCommandProvider"] = executeCommandProvider.to_json();
1874
dict["hoverProvider"] = hoverProvider;
1875
dict["definitionProvider"] = definitionProvider;
1876
dict["typeDefinitionProvider"] = typeDefinitionProvider;
1877
dict["implementationProvider"] = implementationProvider;
1878
dict["referencesProvider"] = referencesProvider;
1879
dict["documentHighlightProvider"] = documentHighlightProvider;
1880
dict["documentSymbolProvider"] = documentSymbolProvider;
1881
dict["workspaceSymbolProvider"] = workspaceSymbolProvider;
1882
dict["workspace"] = workspace.to_json();
1883
dict["codeActionProvider"] = codeActionProvider;
1884
dict["documentFormattingProvider"] = documentFormattingProvider;
1885
dict["documentRangeFormattingProvider"] = documentRangeFormattingProvider;
1886
dict["declarationProvider"] = declarationProvider;
1887
return dict;
1888
}
1889
};
1890
1891
struct InitializeResult {
1892
/**
1893
* The capabilities the language server provides.
1894
*/
1895
ServerCapabilities capabilities;
1896
1897
_FORCE_INLINE_ Dictionary to_json() {
1898
Dictionary dict;
1899
dict["capabilities"] = capabilities.to_json();
1900
return dict;
1901
}
1902
};
1903
1904
struct GodotNativeClassInfo {
1905
String name;
1906
const DocData::ClassDoc *class_doc = nullptr;
1907
const ClassDB::ClassInfo *class_info = nullptr;
1908
1909
Dictionary to_json() const {
1910
Dictionary dict;
1911
dict["name"] = name;
1912
dict["inherits"] = class_doc->inherits;
1913
return dict;
1914
}
1915
};
1916
1917
/** Features not included in the standard lsp specifications */
1918
struct GodotCapabilities {
1919
/**
1920
* Native class list
1921
*/
1922
List<GodotNativeClassInfo> native_classes;
1923
1924
Dictionary to_json() const {
1925
Dictionary dict;
1926
Array classes;
1927
for (const GodotNativeClassInfo &native_class : native_classes) {
1928
classes.push_back(native_class.to_json());
1929
}
1930
dict["native_classes"] = classes;
1931
return dict;
1932
}
1933
};
1934
1935
/** Format BBCode documentation from DocData to markdown */
1936
static String marked_documentation(const String &p_bbcode) {
1937
String markdown = p_bbcode.strip_edges();
1938
1939
Vector<String> lines = markdown.split("\n");
1940
bool in_codeblock_tag = false;
1941
// This is for handling the special [codeblocks] syntax used by the built-in class reference.
1942
bool in_codeblocks_tag = false;
1943
bool in_codeblocks_gdscript_tag = false;
1944
1945
markdown = "";
1946
for (int i = 0; i < lines.size(); i++) {
1947
String line = lines[i];
1948
1949
// For [codeblocks] tags we locate a child [gdscript] tag and turn that
1950
// into a GDScript code listing. Other languages and the surrounding tag
1951
// are skipped.
1952
if (line.contains("[codeblocks]")) {
1953
in_codeblocks_tag = true;
1954
continue;
1955
}
1956
if (in_codeblocks_tag && line.contains("[/codeblocks]")) {
1957
in_codeblocks_tag = false;
1958
continue;
1959
}
1960
if (in_codeblocks_tag) {
1961
if (line.contains("[gdscript]")) {
1962
in_codeblocks_gdscript_tag = true;
1963
line = "```gdscript";
1964
} else if (in_codeblocks_gdscript_tag && line.contains("[/gdscript]")) {
1965
line = "```";
1966
in_codeblocks_gdscript_tag = false;
1967
} else if (!in_codeblocks_gdscript_tag) {
1968
continue;
1969
}
1970
}
1971
1972
// We need to account for both [codeblock] and [codeblock lang=...].
1973
String codeblock_lang = "gdscript";
1974
int block_start = line.find("[codeblock");
1975
if (block_start != -1) {
1976
int bracket_pos = line.find_char(']', block_start);
1977
if (bracket_pos != -1) {
1978
int lang_start = line.find("lang=", block_start);
1979
if (lang_start != -1 && lang_start < bracket_pos) {
1980
constexpr int LANG_PARAM_LENGTH = 5; // Length of "lang=".
1981
int lang_value_start = lang_start + LANG_PARAM_LENGTH;
1982
int lang_end = bracket_pos;
1983
if (lang_value_start < lang_end) {
1984
codeblock_lang = line.substr(lang_value_start, lang_end - lang_value_start);
1985
}
1986
}
1987
in_codeblock_tag = true;
1988
line = "```" + codeblock_lang;
1989
}
1990
}
1991
1992
if (in_codeblock_tag && line.contains("[/codeblock]")) {
1993
line = "```";
1994
in_codeblock_tag = false;
1995
}
1996
1997
if (!in_codeblock_tag) {
1998
line = line.strip_edges();
1999
line = line.replace("[br]", "\n\n");
2000
2001
line = line.replace("[code]", "`");
2002
line = line.replace("[/code]", "`");
2003
line = line.replace("[i]", "*");
2004
line = line.replace("[/i]", "*");
2005
line = line.replace("[b]", "**");
2006
line = line.replace("[/b]", "**");
2007
line = line.replace("[u]", "__");
2008
line = line.replace("[/u]", "__");
2009
line = line.replace("[s]", "~~");
2010
line = line.replace("[/s]", "~~");
2011
line = line.replace("[kbd]", "`");
2012
line = line.replace("[/kbd]", "`");
2013
line = line.replace("[center]", "");
2014
line = line.replace("[/center]", "");
2015
line = line.replace("[/font]", "");
2016
line = line.replace("[/color]", "");
2017
line = line.replace("[/img]", "");
2018
2019
// Convert remaining simple bracketed class names to backticks and literal brackets.
2020
// This handles cases like [Node2D], [Sprite2D], etc. and [lb] and [rb].
2021
int pos = 0;
2022
while ((pos = line.find_char('[', pos)) != -1) {
2023
// Replace the special cases for [lb] and [rb] first and walk
2024
// past them to avoid conflicts with class names.
2025
const bool is_within_bounds = pos + 4 <= line.length();
2026
if (is_within_bounds && line.substr(pos, 4) == "[lb]") {
2027
line = line.substr(0, pos) + "\\[" + line.substr(pos + 4);
2028
// We advance past the newly inserted `\\` and `[` characters (2 chars) so the
2029
// next `line.find()` does not stop at the same position.
2030
pos += 2;
2031
continue;
2032
} else if (is_within_bounds && line.substr(pos, 4) == "[rb]") {
2033
line = line.substr(0, pos) + "\\]" + line.substr(pos + 4);
2034
pos += 2;
2035
continue;
2036
}
2037
2038
// Replace class names in brackets.
2039
int end_pos = line.find_char(']', pos);
2040
if (end_pos == -1) {
2041
break;
2042
}
2043
2044
String content = line.substr(pos + 1, end_pos - pos - 1);
2045
// We only convert if it looks like a simple class name (no spaces, no special chars).
2046
// GDScript supports unicode characters as identifiers so we only exclude markers of other BBCode tags to avoid conflicts.
2047
bool is_class_name = (!content.is_empty() && content != "url" && !content.contains_char(' ') && !content.contains_char('=') && !content.contains_char('/'));
2048
if (is_class_name) {
2049
line = line.substr(0, pos) + "`" + content + "`" + line.substr(end_pos + 1);
2050
pos += content.length() + 2;
2051
} else {
2052
pos = end_pos + 1;
2053
}
2054
}
2055
2056
constexpr int URL_OPEN_TAG_LENGTH = 5; // Length of "[url=".
2057
constexpr int URL_CLOSE_TAG_LENGTH = 6; // Length of "[/url]".
2058
2059
// This is for the case [url=$url]$text[/url].
2060
pos = 0;
2061
while ((pos = line.find("[url=", pos)) != -1) {
2062
int url_end = line.find_char(']', pos);
2063
int close_start = line.find("[/url]", url_end);
2064
if (url_end == -1 || close_start == -1) {
2065
break;
2066
}
2067
2068
String url = line.substr(pos + URL_OPEN_TAG_LENGTH, url_end - pos - URL_OPEN_TAG_LENGTH);
2069
String text = line.substr(url_end + 1, close_start - url_end - 1);
2070
String replacement = "[" + text + "](" + url + ")";
2071
line = line.substr(0, pos) + replacement + line.substr(close_start + URL_CLOSE_TAG_LENGTH);
2072
pos += replacement.length();
2073
}
2074
2075
// This is for the case [url]$url[/url].
2076
pos = 0;
2077
while ((pos = line.find("[url]", pos)) != -1) {
2078
int close_pos = line.find("[/url]", pos);
2079
if (close_pos == -1) {
2080
break;
2081
}
2082
2083
String url = line.substr(pos + URL_OPEN_TAG_LENGTH, close_pos - pos - URL_OPEN_TAG_LENGTH);
2084
String replacement = "[" + url + "](" + url + ")";
2085
line = line.substr(0, pos) + replacement + line.substr(close_pos + URL_CLOSE_TAG_LENGTH);
2086
pos += replacement.length();
2087
}
2088
2089
// Replace the various link types with inline code ([class MyNode] to `MyNode`).
2090
// Uses a while loop because there can occasionally be multiple links of the same type in a single line.
2091
const Vector<String> link_start_patterns = {
2092
"[class ", "[method ", "[member ", "[signal ", "[enum ", "[constant ",
2093
"[annotation ", "[constructor ", "[operator ", "[theme_item ", "[param "
2094
};
2095
for (const String &pattern : link_start_patterns) {
2096
int pattern_pos = 0;
2097
while ((pattern_pos = line.find(pattern, pattern_pos)) != -1) {
2098
int end_pos = line.find_char(']', pattern_pos);
2099
if (end_pos == -1) {
2100
break;
2101
}
2102
2103
String content = line.substr(pattern_pos + pattern.length(), end_pos - pattern_pos - pattern.length());
2104
String replacement = "`" + content + "`";
2105
line = line.substr(0, pattern_pos) + replacement + line.substr(end_pos + 1);
2106
pattern_pos += replacement.length();
2107
}
2108
}
2109
2110
// Remove tags with attributes like [color=red], as they don't have a direct Markdown
2111
// equivalent supported by external tools.
2112
const String attribute_tags[] = {
2113
"color", "font", "img"
2114
};
2115
for (const String &tag_name : attribute_tags) {
2116
int tag_pos = 0;
2117
while ((tag_pos = line.find("[" + tag_name + "=", tag_pos)) != -1) {
2118
int end_pos = line.find_char(']', tag_pos);
2119
if (end_pos == -1) {
2120
break;
2121
}
2122
2123
line = line.substr(0, tag_pos) + line.substr(end_pos + 1);
2124
}
2125
}
2126
}
2127
2128
if (i < lines.size() - 1) {
2129
line += "\n";
2130
}
2131
markdown += line;
2132
}
2133
return markdown;
2134
}
2135
2136
/**
2137
* A document highlight is a range inside a text document which deserves
2138
* special attention. Usually a document highlight is visualized by changing
2139
* the background color of its range.
2140
*/
2141
struct DocumentHighlight {
2142
/**
2143
* The range this highlight applies to.
2144
*/
2145
Range range;
2146
2147
_FORCE_INLINE_ Dictionary to_json() const {
2148
Dictionary dict;
2149
dict["range"] = range.to_json();
2150
return dict;
2151
}
2152
2153
_FORCE_INLINE_ void load(const Dictionary &p_params) {
2154
range.load(p_params["range"]);
2155
}
2156
};
2157
} // namespace LSP
2158
2159