@adecore/editor-react 0.31.11 → 0.32.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AnchoredPopup.js +73 -19
- package/dist/AttributionCard.js +162 -4
- package/dist/BaselineStatus.js +62 -8
- package/dist/CallHierarchyPanel.js +977 -60
- package/dist/ChangeReview.js +76 -25
- package/dist/CodeAuthorsCard.js +314 -14
- package/dist/CompletionPopup.js +490 -83
- package/dist/DiffView.js +548 -181
- package/dist/EditorContextMenu.js +352 -34
- package/dist/EditorView.js +276 -99
- package/dist/FindReplace.js +525 -67
- package/dist/HoverCard.js +378 -38
- package/dist/HoverSections.js +367 -56
- package/dist/LanguagePopups.js +95 -34
- package/dist/Markdown.js +41 -6
- package/dist/PanelResizeHandle.js +199 -66
- package/dist/PathText.js +49 -7
- package/dist/PeekPanel.js +675 -72
- package/dist/PickPopup.js +304 -34
- package/dist/RenameCard.js +679 -85
- package/dist/RenderedDocs.js +329 -58
- package/dist/SignatureCard.js +91 -7
- package/dist/SplitDiffView.js +344 -254
- package/dist/SymbolPicker.js +440 -85
- package/dist/call-hierarchy-model.js +102 -68
- package/dist/call-hierarchy.js +458 -359
- package/dist/code-actions-model.js +88 -76
- package/dist/code-actions.js +372 -283
- package/dist/code-authors.js +64 -55
- package/dist/code-vision-model.js +134 -127
- package/dist/code-vision.js +224 -206
- package/dist/completion-call.js +94 -67
- package/dist/completion-model.js +334 -244
- package/dist/completion.js +840 -649
- package/dist/conflict-model.js +35 -29
- package/dist/context-menu-rows.js +42 -17
- package/dist/context-menu.js +64 -46
- package/dist/definition-link.js +88 -85
- package/dist/diagnostics-model.js +74 -55
- package/dist/diagnostics.js +121 -100
- package/dist/diff-expansion.js +38 -35
- package/dist/diff-overlays.js +144 -22
- package/dist/diff-syntax.js +65 -42
- package/dist/diff-wordmarks.js +26 -23
- package/dist/doc-comment-model.js +265 -216
- package/dist/editor-language.js +177 -152
- package/dist/error-message.js +2 -2
- package/dist/find-query.js +49 -36
- package/dist/folding.js +81 -62
- package/dist/format-on-type.js +86 -67
- package/dist/highlight-layers.js +19 -20
- package/dist/highlights.js +105 -83
- package/dist/history.js +44 -38
- package/dist/holder.js +18 -18
- package/dist/host-types.js +1 -1
- package/dist/hover-content.js +167 -129
- package/dist/hover.js +285 -245
- package/dist/index.js +10 -10
- package/dist/inlay-hints.js +369 -324
- package/dist/key-priority.js +34 -31
- package/dist/language-ids.js +45 -42
- package/dist/line-edits.js +74 -28
- package/dist/line-text.js +18 -3
- package/dist/locales/en.json +38 -38
- package/dist/locales/nl.json +41 -41
- package/dist/models.js +1 -1
- package/dist/navigation-history.js +40 -41
- package/dist/navigation.js +141 -123
- package/dist/panel-size.js +8 -8
- package/dist/patch-decorations.js +236 -160
- package/dist/patch-layout.js +331 -262
- package/dist/paths.js +3 -3
- package/dist/peek-model.js +86 -69
- package/dist/peek.js +254 -192
- package/dist/pick.js +164 -157
- package/dist/popup-focus.js +5 -5
- package/dist/popup-placement.js +36 -21
- package/dist/popups.js +13 -13
- package/dist/project-language.js +228 -211
- package/dist/project-problems.js +81 -69
- package/dist/proposal-model.js +163 -126
- package/dist/recent-choices.js +25 -25
- package/dist/refresher.js +44 -49
- package/dist/rename-model.js +113 -113
- package/dist/rename.js +321 -233
- package/dist/rendered-docs.d.ts +4 -2
- package/dist/rendered-docs.js +384 -318
- package/dist/rendering-context.js +5 -3
- package/dist/rendering.js +22 -4
- package/dist/review-group.js +42 -39
- package/dist/row-host.d.ts +4 -2
- package/dist/row-host.js +90 -78
- package/dist/selection-ranges.js +21 -17
- package/dist/semantic-delta.js +22 -19
- package/dist/semantic-model.js +86 -73
- package/dist/semantic-tokens.js +201 -162
- package/dist/shortcut-keys.js +16 -10
- package/dist/signature-model.js +34 -28
- package/dist/signature.js +177 -129
- package/dist/snippet-field-transforms.js +118 -106
- package/dist/snippet-indent.js +48 -43
- package/dist/snippet-range-order.js +11 -11
- package/dist/snippet-session.js +703 -667
- package/dist/snippet-transform-client.js +59 -59
- package/dist/snippet-transform-format.js +285 -263
- package/dist/snippet-transform-protocol.js +1 -1
- package/dist/snippet-transform-queue.js +163 -153
- package/dist/snippet-transform-worker.js +42 -35
- package/dist/snippet-variable-names.js +1 -36
- package/dist/snippet-variables.js +53 -63
- package/dist/snippet.js +477 -405
- package/dist/split-alignment.js +47 -35
- package/dist/split-scroll.js +42 -40
- package/dist/symbol-links.js +33 -25
- package/dist/symbol-picker-model.js +126 -116
- package/dist/symbol-picker.js +98 -59
- package/dist/symbols.js +117 -88
- package/dist/testing.js +248 -165
- package/dist/timers.js +35 -30
- package/dist/use-panel-body.js +49 -8
- package/dist/use-problem-counts.js +29 -15
- package/dist/view-state.js +54 -33
- package/dist/word-diff.js +18 -18
- package/dist/workspace-edit.js +300 -249
- package/package.json +6 -6
- package/src/CallHierarchyPanel.tsx +2 -2
- package/src/DiffView.tsx +3 -3
- package/src/FindReplace.tsx +2 -2
- package/src/LanguagePopups.tsx +2 -0
- package/src/PeekPanel.tsx +3 -3
- package/src/RenderedDocs.tsx +9 -10
- package/src/SymbolPicker.tsx +2 -2
- package/src/diff-overlays.tsx +6 -4
- package/src/locales/en.json +38 -38
- package/src/locales/nl.json +41 -41
- package/src/rendered-docs.ts +14 -3
- package/src/row-host.ts +14 -3
package/dist/editor-language.js
CHANGED
|
@@ -32,159 +32,184 @@ import { SymbolsFeature } from './symbols.js';
|
|
|
32
32
|
* the editor and lets go of it again. Every language feature of the editor hangs off this object.
|
|
33
33
|
*/
|
|
34
34
|
export class EditorLanguage {
|
|
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
|
-
|
|
35
|
+
editor;
|
|
36
|
+
apple;
|
|
37
|
+
keymap;
|
|
38
|
+
shortcuts;
|
|
39
|
+
project;
|
|
40
|
+
document;
|
|
41
|
+
languageId;
|
|
42
|
+
/* What the features of this editor have open over it: the hover card, the suggestions, the signature. */
|
|
43
|
+
popups = createPopupStore();
|
|
44
|
+
diagnostics;
|
|
45
|
+
hover;
|
|
46
|
+
inlayHints;
|
|
47
|
+
completion;
|
|
48
|
+
signature;
|
|
49
|
+
snippets;
|
|
50
|
+
highlights;
|
|
51
|
+
pick;
|
|
52
|
+
codeActions;
|
|
53
|
+
rename;
|
|
54
|
+
navigation;
|
|
55
|
+
peek;
|
|
56
|
+
callHierarchy;
|
|
57
|
+
symbolPicker;
|
|
58
|
+
contextMenu;
|
|
59
|
+
history;
|
|
60
|
+
definitionLink;
|
|
61
|
+
symbols;
|
|
62
|
+
codeVision;
|
|
63
|
+
formatOnType;
|
|
64
|
+
renderedDocs;
|
|
65
|
+
disposers = [];
|
|
66
|
+
keys = new KeyDispatcher();
|
|
67
|
+
disposed = false;
|
|
68
|
+
constructor(project, editor, uri, languageId, timers = realTimers, options = {}) {
|
|
69
|
+
this.editor = editor;
|
|
70
|
+
this.apple = project.host.apple ?? false;
|
|
71
|
+
this.keymap = project.host.keymap ?? KEYMAP;
|
|
72
|
+
this.shortcuts = shortcutsOf(this.keymap, this.apple);
|
|
73
|
+
this.project = project;
|
|
74
|
+
this.languageId = languageId;
|
|
75
|
+
this.document = project.acquire(uri, languageId, editor);
|
|
76
|
+
this.onDispose(editor.onKeyDown(event => this.keys.dispatch(event)));
|
|
77
|
+
this.pick = new PickFeature(this, timers);
|
|
78
|
+
this.diagnostics = new DiagnosticsFeature(this);
|
|
79
|
+
this.hover = new HoverFeature(this, timers);
|
|
80
|
+
this.completion = new CompletionFeature(this, timers);
|
|
81
|
+
this.snippets = new SnippetFeature(this, timers);
|
|
82
|
+
this.signature = new SignatureFeature(this, timers);
|
|
83
|
+
this.highlights = new HighlightsFeature(this, timers);
|
|
84
|
+
this.symbols = new SymbolsFeature(this, timers);
|
|
85
|
+
new SelectionRangesFeature(this);
|
|
86
|
+
new SemanticTokensFeature(this, timers, options.semanticTokens);
|
|
87
|
+
this.inlayHints = new InlayHintsFeature(this, timers);
|
|
88
|
+
this.codeActions = new CodeActionsFeature(this, timers);
|
|
89
|
+
this.rename = new RenameFeature(this);
|
|
90
|
+
this.navigation = new NavigationFeature(this);
|
|
91
|
+
this.peek = new PeekFeature(this, timers);
|
|
92
|
+
this.callHierarchy = new CallHierarchyFeature(this, timers);
|
|
93
|
+
this.symbolPicker = new SymbolPickerFeature(this);
|
|
94
|
+
this.contextMenu = new ContextMenuFeature(this);
|
|
95
|
+
this.history = new HistoryFeature(this);
|
|
96
|
+
this.definitionLink = new DefinitionLinkFeature(this);
|
|
97
|
+
this.codeVision = new CodeVisionFeature(this, listener => this.symbols.onResult(listener), timers);
|
|
98
|
+
this.formatOnType = new FormatOnTypeFeature(this);
|
|
99
|
+
this.renderedDocs = new RenderedDocsFeature(this, timers);
|
|
100
|
+
new FoldingFeature(this, listener => this.symbols.onResult(listener), timers);
|
|
101
|
+
this.placeOpenedCaret(editor.getCaret());
|
|
102
|
+
this.onDispose(editor.onCaret(position => this.placeOpenedCaret(position)));
|
|
103
|
+
}
|
|
104
|
+
get uri() {
|
|
105
|
+
return this.document.uri;
|
|
106
|
+
}
|
|
107
|
+
get isDisposed() {
|
|
108
|
+
return this.disposed;
|
|
109
|
+
}
|
|
110
|
+
/* Where the caret is, as a place the history can come back to. */
|
|
111
|
+
get place() {
|
|
112
|
+
return {
|
|
113
|
+
uri: this.uri,
|
|
114
|
+
position: this.editor.getCaret()
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
/* Takes the caret to a place the servers named, in this file or in another one that opens beside it, and remembers where it was. */
|
|
118
|
+
goTo(location) {
|
|
119
|
+
this.project.history.record(this.place);
|
|
120
|
+
this.visit({
|
|
121
|
+
uri: location.uri,
|
|
122
|
+
position: location.range.start
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
/* Takes the caret to a position of this file and remembers where it was. */
|
|
126
|
+
jump(position) {
|
|
127
|
+
this.goTo({
|
|
128
|
+
uri: this.uri,
|
|
129
|
+
range: {
|
|
130
|
+
start: position,
|
|
131
|
+
end: position
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/* Goes to a place without touching the history, which is how Back and Forward move. */
|
|
136
|
+
visit(place) {
|
|
137
|
+
if (place.uri === this.uri) {
|
|
138
|
+
this.editor.setCaret(place.position, 'center');
|
|
139
|
+
this.editor.focus();
|
|
140
|
+
} else {
|
|
141
|
+
this.project.openPlace(place);
|
|
103
142
|
}
|
|
104
|
-
|
|
105
|
-
|
|
143
|
+
}
|
|
144
|
+
/* Lists places under a position to choose from; choosing one goes there. */
|
|
145
|
+
locations(places, anchor, title) {
|
|
146
|
+
const rows = places.map((place, index) => ({
|
|
147
|
+
id: String(index),
|
|
148
|
+
...locationRow(place, this.project.pathOfLocation(place.uri))
|
|
149
|
+
}));
|
|
150
|
+
this.pick.open({
|
|
151
|
+
anchor,
|
|
152
|
+
title,
|
|
153
|
+
groups: [{
|
|
154
|
+
title: null,
|
|
155
|
+
rows
|
|
156
|
+
}],
|
|
157
|
+
accept: id => this.goTo(places[Number(id)])
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
/*
|
|
161
|
+
* Runs `listener` once the document is open and again whenever the service says what it can ask for
|
|
162
|
+
* this document changed. A service that is ready before the document opens never says so, so the
|
|
163
|
+
* opening counts as the first change.
|
|
164
|
+
*/
|
|
165
|
+
onProvidersChanged(listener) {
|
|
166
|
+
let listening = true;
|
|
167
|
+
void this.document.ready.then(() => {
|
|
168
|
+
if (listening && !this.disposed) {
|
|
169
|
+
listener();
|
|
170
|
+
}
|
|
171
|
+
}, () => undefined);
|
|
172
|
+
const providers = this.project.service.onProvidersChanged(uri => {
|
|
173
|
+
if (uri === this.uri) {
|
|
174
|
+
listener();
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
return () => {
|
|
178
|
+
listening = false;
|
|
179
|
+
providers.dispose();
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
/*
|
|
183
|
+
* Lets `handler` see the editor's keys before every handler of a lower `priority`, the first to take a key
|
|
184
|
+
* winning. `KEY_PRIORITY` holds the features'; the default, 0, comes after all of them.
|
|
185
|
+
*/
|
|
186
|
+
onKey(handler, priority = 0) {
|
|
187
|
+
return this.keys.add(handler, priority);
|
|
188
|
+
}
|
|
189
|
+
/* Runs `dispose` when the editor lets go of its document. */
|
|
190
|
+
onDispose(dispose) {
|
|
191
|
+
this.disposers.push(dispose);
|
|
192
|
+
}
|
|
193
|
+
dispose() {
|
|
194
|
+
if (this.disposed) {
|
|
195
|
+
return;
|
|
106
196
|
}
|
|
107
|
-
|
|
108
|
-
|
|
197
|
+
this.disposed = true;
|
|
198
|
+
for (const dispose of this.disposers.splice(0).reverse()) {
|
|
199
|
+
dispose();
|
|
109
200
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
201
|
+
this.document.release();
|
|
202
|
+
}
|
|
203
|
+
/* A file opened from another one lands on the line; this puts the caret on the column the jump meant. */
|
|
204
|
+
placeOpenedCaret(position) {
|
|
205
|
+
const column = this.project.takeCaret(this.uri, position.line);
|
|
206
|
+
if (column !== null && column.character !== position.character) {
|
|
207
|
+
this.editor.setCaret(column);
|
|
208
|
+
return;
|
|
113
209
|
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
jump(position) {
|
|
121
|
-
this.goTo({ uri: this.uri, range: { start: position, end: position } });
|
|
122
|
-
}
|
|
123
|
-
/* Goes to a place without touching the history, which is how Back and Forward move. */
|
|
124
|
-
visit(place) {
|
|
125
|
-
if (place.uri === this.uri) {
|
|
126
|
-
this.editor.setCaret(place.position, 'center');
|
|
127
|
-
this.editor.focus();
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
this.project.openPlace(place);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
/* Lists places under a position to choose from; choosing one goes there. */
|
|
134
|
-
locations(places, anchor, title) {
|
|
135
|
-
const rows = places.map((place, index) => ({ id: String(index), ...locationRow(place, this.project.pathOfLocation(place.uri)) }));
|
|
136
|
-
this.pick.open({ anchor, title, groups: [{ title: null, rows }], accept: (id) => this.goTo(places[Number(id)]) });
|
|
137
|
-
}
|
|
138
|
-
/*
|
|
139
|
-
* Runs `listener` once the document is open and again whenever the service says what it can ask for
|
|
140
|
-
* this document changed. A service that is ready before the document opens never says so, so the
|
|
141
|
-
* opening counts as the first change.
|
|
142
|
-
*/
|
|
143
|
-
onProvidersChanged(listener) {
|
|
144
|
-
let listening = true;
|
|
145
|
-
void this.document.ready.then(() => {
|
|
146
|
-
if (listening && !this.disposed) {
|
|
147
|
-
listener();
|
|
148
|
-
}
|
|
149
|
-
}, () => undefined);
|
|
150
|
-
const providers = this.project.service.onProvidersChanged((uri) => {
|
|
151
|
-
if (uri === this.uri) {
|
|
152
|
-
listener();
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
return () => {
|
|
156
|
-
listening = false;
|
|
157
|
-
providers.dispose();
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
/*
|
|
161
|
-
* Lets `handler` see the editor's keys before every handler of a lower `priority`, the first to take a key
|
|
162
|
-
* winning. `KEY_PRIORITY` holds the features'; the default, 0, comes after all of them.
|
|
163
|
-
*/
|
|
164
|
-
onKey(handler, priority = 0) {
|
|
165
|
-
return this.keys.add(handler, priority);
|
|
166
|
-
}
|
|
167
|
-
/* Runs `dispose` when the editor lets go of its document. */
|
|
168
|
-
onDispose(dispose) {
|
|
169
|
-
this.disposers.push(dispose);
|
|
170
|
-
}
|
|
171
|
-
dispose() {
|
|
172
|
-
if (this.disposed) {
|
|
173
|
-
return;
|
|
174
|
-
}
|
|
175
|
-
this.disposed = true;
|
|
176
|
-
for (const dispose of this.disposers.splice(0).reverse()) {
|
|
177
|
-
dispose();
|
|
178
|
-
}
|
|
179
|
-
this.document.release();
|
|
180
|
-
}
|
|
181
|
-
/* A file opened from another one lands on the line; this puts the caret on the column the jump meant. */
|
|
182
|
-
placeOpenedCaret(position) {
|
|
183
|
-
const column = this.project.takeCaret(this.uri, position.line);
|
|
184
|
-
if (column !== null && column.character !== position.character) {
|
|
185
|
-
this.editor.setCaret(column);
|
|
186
|
-
return;
|
|
187
|
-
}
|
|
188
|
-
this.project.noteCaret({ uri: this.uri, position });
|
|
189
|
-
}
|
|
190
|
-
}
|
|
210
|
+
this.project.noteCaret({
|
|
211
|
+
uri: this.uri,
|
|
212
|
+
position
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
package/dist/error-message.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export function messageOf(error) {
|
|
2
|
-
|
|
3
|
-
}
|
|
2
|
+
return error instanceof Error ? error.message : String(error);
|
|
3
|
+
}
|
package/dist/find-query.js
CHANGED
|
@@ -1,51 +1,64 @@
|
|
|
1
|
-
export const EMPTY_FIND_QUERY = {
|
|
1
|
+
export const EMPTY_FIND_QUERY = {
|
|
2
|
+
text: '',
|
|
3
|
+
caseSensitive: false,
|
|
4
|
+
wholeWord: false,
|
|
5
|
+
regex: false
|
|
6
|
+
};
|
|
2
7
|
/* Past this a count stops meaning anything to a reader, and marking every one would stall the page. */
|
|
3
8
|
export const MATCH_LIMIT = 10000;
|
|
4
9
|
// A letter or digit in any script, so a whole word in Dutch ends at the same place as one in English.
|
|
5
10
|
const WORD_CHAR = '[\\p{L}\\p{N}_]';
|
|
6
11
|
function escapeRegExp(text) {
|
|
7
|
-
|
|
12
|
+
return text.replace(/[.*+?^${}()|[\]\\/]/g, '\\$&');
|
|
8
13
|
}
|
|
9
14
|
/* `u` in both modes, since a whole word needs Unicode classes; a pattern that only parses without it counts as invalid. */
|
|
10
15
|
export function compileFind(query) {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
if (query.text === '') {
|
|
17
|
+
return {
|
|
18
|
+
kind: 'empty'
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const body = query.regex ? query.text : escapeRegExp(query.text);
|
|
22
|
+
const source = query.wholeWord ? `(?<!${WORD_CHAR})(?:${body})(?!${WORD_CHAR})` : body;
|
|
23
|
+
// Multiline, so `^` and `$` in a pattern mean a line, the way an editor's find reads them.
|
|
24
|
+
const flags = `gmu${query.caseSensitive ? '' : 'i'}`;
|
|
25
|
+
try {
|
|
26
|
+
return {
|
|
27
|
+
kind: 'pattern',
|
|
28
|
+
pattern: new RegExp(source, flags)
|
|
29
|
+
};
|
|
30
|
+
} catch {
|
|
31
|
+
return {
|
|
32
|
+
kind: 'invalid'
|
|
33
|
+
};
|
|
34
|
+
}
|
|
24
35
|
}
|
|
25
36
|
/* Every match in a text, in order. An empty match (`a*` between two letters) is nothing to show, so it is stepped over. */
|
|
26
37
|
export function matchesIn(text, pattern, limit = MATCH_LIMIT) {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
const matches = [];
|
|
39
|
+
const global = new RegExp(pattern.source, pattern.flags.includes('g') ? pattern.flags : `${pattern.flags}g`);
|
|
40
|
+
let found = global.exec(text);
|
|
41
|
+
while (found !== null && matches.length < limit) {
|
|
42
|
+
if (found[0] === '') {
|
|
43
|
+
// A `u` pattern moves a lastIndex inside a surrogate pair back to its start, so one step would never leave it.
|
|
44
|
+
global.lastIndex = found.index + ((text.codePointAt(found.index) ?? 0) > 0xffff ? 2 : 1);
|
|
45
|
+
} else {
|
|
46
|
+
matches.push({
|
|
47
|
+
start: found.index,
|
|
48
|
+
end: found.index + found[0].length
|
|
49
|
+
});
|
|
39
50
|
}
|
|
40
|
-
|
|
51
|
+
found = global.exec(text);
|
|
52
|
+
}
|
|
53
|
+
return matches;
|
|
41
54
|
}
|
|
42
55
|
/* The step from one match to the next or the one before, round at either end. */
|
|
43
56
|
export function stepIndex(current, count, direction) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
}
|
|
57
|
+
if (count === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
if (current === null) {
|
|
61
|
+
return direction === 1 ? 0 : count - 1;
|
|
62
|
+
}
|
|
63
|
+
return (current + direction + count) % count;
|
|
64
|
+
}
|
package/dist/folding.js
CHANGED
|
@@ -5,36 +5,46 @@ const METHOD = 'textDocument/foldingRange';
|
|
|
5
5
|
const PAUSE_MS = 500;
|
|
6
6
|
/* The kind of body a symbol has, by LSP symbol kind; a namespace, a property of a type or an enum member has none worth folding. */
|
|
7
7
|
const BODIES = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
8
|
+
5: 'class',
|
|
9
|
+
6: 'method',
|
|
10
|
+
7: 'value',
|
|
11
|
+
8: 'value',
|
|
12
|
+
9: 'method',
|
|
13
|
+
10: 'class',
|
|
14
|
+
11: 'class',
|
|
15
|
+
12: 'function',
|
|
16
|
+
13: 'value',
|
|
17
|
+
14: 'value',
|
|
18
|
+
23: 'class'
|
|
19
19
|
};
|
|
20
20
|
/* The symbols that have a body of more than one line, as what the editor folds them by. */
|
|
21
21
|
export function foldSymbolsOf(result) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
22
|
+
return symbolSpansOf(result).flatMap(({
|
|
23
|
+
kind,
|
|
24
|
+
range
|
|
25
|
+
}) => {
|
|
26
|
+
const body = BODIES[kind];
|
|
27
|
+
return body !== undefined && range.end.line > range.start.line ? [{
|
|
28
|
+
range,
|
|
29
|
+
body
|
|
30
|
+
}] : [];
|
|
31
|
+
});
|
|
26
32
|
}
|
|
27
33
|
/* The ranges a server folds that span more than one line, with where a range starts and ends within its lines when it says. */
|
|
28
34
|
export function foldRangesOf(ranges) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
})
|
|
35
|
+
return (ranges ?? []).filter(range => range.endLine > range.startLine).map(range => ({
|
|
36
|
+
startLine: range.startLine,
|
|
37
|
+
endLine: range.endLine,
|
|
38
|
+
...(range.kind === undefined ? {} : {
|
|
39
|
+
kind: range.kind
|
|
40
|
+
}),
|
|
41
|
+
...(range.startCharacter === undefined ? {} : {
|
|
42
|
+
startCharacter: range.startCharacter
|
|
43
|
+
}),
|
|
44
|
+
...(range.endCharacter === undefined ? {} : {
|
|
45
|
+
endCharacter: range.endCharacter
|
|
46
|
+
})
|
|
47
|
+
}));
|
|
38
48
|
}
|
|
39
49
|
/*
|
|
40
50
|
* What the servers know about folding: the bodies of the symbols (read from the symbols the document already
|
|
@@ -42,41 +52,50 @@ export function foldRangesOf(ranges) {
|
|
|
42
52
|
* editor folds what the settings choose by them when the file opens, and keeps them with their text after.
|
|
43
53
|
*/
|
|
44
54
|
export class FoldingFeature {
|
|
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
|
-
}
|
|
55
|
+
symbols = [];
|
|
56
|
+
ranges = [];
|
|
57
|
+
refresher;
|
|
58
|
+
language;
|
|
59
|
+
constructor(language, onSymbols, timers = realTimers) {
|
|
60
|
+
this.language = language;
|
|
61
|
+
const {
|
|
62
|
+
editor,
|
|
63
|
+
project,
|
|
64
|
+
uri
|
|
65
|
+
} = language;
|
|
66
|
+
this.refresher = new Refresher(async signal => {
|
|
67
|
+
if (!project.service.supports(METHOD, uri)) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const ranges = await project.service.foldingRanges(uri, {
|
|
71
|
+
signal
|
|
72
|
+
});
|
|
73
|
+
if (!signal.aborted) {
|
|
74
|
+
this.ranges = foldRangesOf(ranges);
|
|
75
|
+
this.publish();
|
|
76
|
+
}
|
|
77
|
+
}, PAUSE_MS, timers);
|
|
78
|
+
const symbols = onSymbols(result => {
|
|
79
|
+
this.symbols = foldSymbolsOf(result);
|
|
80
|
+
this.publish();
|
|
81
|
+
});
|
|
82
|
+
const edits = editor.onTextChange(() => this.refresher.later());
|
|
83
|
+
const providers = language.onProvidersChanged(() => {
|
|
84
|
+
this.refresher.now();
|
|
85
|
+
});
|
|
86
|
+
language.onDispose(() => {
|
|
87
|
+
symbols();
|
|
88
|
+
edits();
|
|
89
|
+
providers();
|
|
90
|
+
this.refresher.dispose();
|
|
91
|
+
editor.setFoldHints(null);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
publish() {
|
|
95
|
+
const hints = {
|
|
96
|
+
symbols: this.symbols,
|
|
97
|
+
ranges: this.ranges
|
|
98
|
+
};
|
|
99
|
+
this.language.editor.setFoldHints(hints);
|
|
100
|
+
}
|
|
101
|
+
}
|