@adecore/editor 0.22.0 → 0.23.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/attribution.d.ts +9 -8
- package/dist/attribution.js +44 -9
- package/dist/bidi.d.ts +44 -0
- package/dist/bidi.js +26 -0
- package/dist/column-selection.js +2 -1
- package/dist/controller.d.ts +6 -1
- package/dist/controller.js +93 -3
- package/dist/editor.css +81 -1
- package/dist/engine.js +184 -41
- package/dist/fake.d.ts +43 -5
- package/dist/fake.js +117 -13
- package/dist/find-search.d.ts +26 -0
- package/dist/find-search.js +130 -0
- package/dist/find.d.ts +50 -2
- package/dist/find.js +575 -25
- package/dist/geometry-stops.d.ts +6 -0
- package/dist/geometry-stops.js +47 -0
- package/dist/grammar-preparation.d.ts +29 -0
- package/dist/grammar-preparation.js +147 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/keymap-table.d.ts +10 -1
- package/dist/keymap-table.js +37 -1
- package/dist/keymap.d.ts +1 -0
- package/dist/keymap.js +4 -1
- package/dist/layout-changes.d.ts +6 -0
- package/dist/layout-changes.js +27 -0
- package/dist/layout.d.ts +45 -2
- package/dist/layout.js +202 -58
- package/dist/offsets.d.ts +1 -0
- package/dist/offsets.js +23 -0
- package/dist/outline.js +5 -4
- package/dist/paint.d.ts +11 -3
- package/dist/paint.js +180 -34
- package/dist/search-client.d.ts +27 -0
- package/dist/search-client.js +210 -0
- package/dist/search-protocol.d.ts +103 -0
- package/dist/search-protocol.js +3 -0
- package/dist/search-worker.d.ts +11 -0
- package/dist/search-worker.js +137 -0
- package/dist/semantic.d.ts +2 -1
- package/dist/semantic.js +6 -1
- package/dist/shiki-document.d.ts +8 -0
- package/dist/shiki-document.js +93 -0
- package/dist/shiki-worker.d.ts +65 -0
- package/dist/shiki-worker.js +265 -0
- package/dist/shiki.d.ts +1 -0
- package/dist/shiki.js +96 -33
- package/dist/testing.d.ts +1 -0
- package/dist/tokens.d.ts +2 -0
- package/dist/tokens.js +37 -7
- package/dist/touch.d.ts +27 -0
- package/dist/touch.js +100 -0
- package/dist/types.d.ts +84 -2
- package/dist/uniform-geometry.d.ts +7 -0
- package/dist/uniform-geometry.js +49 -0
- package/dist/view.d.ts +68 -17
- package/dist/view.js +424 -97
- package/dist/worker-client.d.ts +37 -0
- package/dist/worker-client.js +195 -0
- package/package.json +17 -2
- package/src/attribution.ts +50 -14
- package/src/bidi.ts +32 -0
- package/src/column-selection.ts +2 -1
- package/src/controller.ts +97 -3
- package/src/editor.css +81 -1
- package/src/engine.ts +216 -42
- package/src/fake.ts +152 -14
- package/src/find-search.ts +165 -0
- package/src/find.ts +622 -21
- package/src/geometry-stops.ts +51 -0
- package/src/grammar-preparation.ts +158 -0
- package/src/index.ts +10 -0
- package/src/keymap-table.ts +44 -2
- package/src/keymap.ts +5 -1
- package/src/layout-changes.ts +33 -0
- package/src/layout.ts +262 -63
- package/src/offsets.ts +24 -0
- package/src/outline.ts +5 -4
- package/src/paint.ts +202 -36
- package/src/search-client.ts +306 -0
- package/src/search-protocol.ts +100 -0
- package/src/search-worker.ts +171 -0
- package/src/semantic.ts +8 -2
- package/src/shiki-document.ts +143 -0
- package/src/shiki-worker.ts +344 -0
- package/src/shiki.ts +103 -33
- package/src/testing.ts +2 -0
- package/src/tokens.ts +36 -7
- package/src/touch.ts +134 -0
- package/src/types.ts +174 -8
- package/src/uniform-geometry.ts +57 -0
- package/src/view.ts +500 -102
- package/src/worker-client.ts +212 -0
package/dist/engine.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { changedSpans, DocumentModel, replacementText } from '@adecore/editor-core';
|
|
2
|
+
import { MAX_REPLACEMENT_CHARACTERS } from './search-protocol.js';
|
|
3
|
+
import { GrammarPreparation } from './grammar-preparation.js';
|
|
2
4
|
import { InputController } from './controller.js';
|
|
3
5
|
import { resolveSmartKeys } from './smart-keys.js';
|
|
4
6
|
import { emit, subscribe } from './listeners.js';
|
|
@@ -7,11 +9,14 @@ import { EditorView } from './view.js';
|
|
|
7
9
|
const DEFAULT_TAB_SIZE = 4;
|
|
8
10
|
const DEFAULT_LABEL = 'Code editor';
|
|
9
11
|
const DEFAULT_WIDGET_OWNER = 'default';
|
|
12
|
+
/* The space a hint's padding keeps clear; a whole pixel count so the pill stays on the pixel grid. */
|
|
13
|
+
const INLAY_GAP = 4;
|
|
10
14
|
class SmartEditor {
|
|
11
15
|
model;
|
|
12
16
|
settings;
|
|
13
17
|
view;
|
|
14
18
|
controller;
|
|
19
|
+
grammarPreparation;
|
|
15
20
|
changes = new Set();
|
|
16
21
|
textChanges = new Set();
|
|
17
22
|
carets = new Set();
|
|
@@ -34,6 +39,7 @@ class SmartEditor {
|
|
|
34
39
|
this.language = options.language;
|
|
35
40
|
this.theme = options.theme;
|
|
36
41
|
this.settings = {
|
|
42
|
+
searchWorker: engine.searchWorker,
|
|
37
43
|
language: options.language,
|
|
38
44
|
tabSize: options.indentation?.tabSize ?? DEFAULT_TAB_SIZE,
|
|
39
45
|
insertSpaces: options.indentation?.insertSpaces ?? true,
|
|
@@ -46,11 +52,13 @@ class SmartEditor {
|
|
|
46
52
|
guides: options.guides !== false,
|
|
47
53
|
whitespace: options.whitespace === true,
|
|
48
54
|
rightMargin: options.rightMargin ?? null,
|
|
49
|
-
foldOutline: options.foldOutline ?? 'hover'
|
|
55
|
+
foldOutline: options.foldOutline ?? 'hover',
|
|
56
|
+
folding: options.folding !== false
|
|
50
57
|
};
|
|
51
58
|
this.view = new EditorView(element, this.model, this.settings);
|
|
59
|
+
this.grammarPreparation = new GrammarPreparation(this.model, () => this.view.grammarChanged());
|
|
52
60
|
this.controller = new InputController(this.view, {
|
|
53
|
-
handBack: engine.handBack ?? [],
|
|
61
|
+
handBack: [...(engine.handBack ?? []), ...(options.handBack ?? [])],
|
|
54
62
|
keymap: engine.keymap,
|
|
55
63
|
apple: engine.apple ?? false,
|
|
56
64
|
save: () => emit(this.saves),
|
|
@@ -62,8 +70,9 @@ class SmartEditor {
|
|
|
62
70
|
this.caretMoved(snapshot.selections.at(-1).head);
|
|
63
71
|
if (snapshot.revision !== this.revision) {
|
|
64
72
|
this.revision = snapshot.revision;
|
|
73
|
+
this.grammarPreparation.edited(snapshot.changes ?? []);
|
|
65
74
|
if (snapshot.contentEdits !== undefined && snapshot.contentEdits.length > 0) {
|
|
66
|
-
this.announceTextChange(snapshot.contentEdits, snapshot.source ?? 'external');
|
|
75
|
+
this.announceTextChange(snapshot.contentEdits, snapshot.source ?? 'external', snapshot.typed === true);
|
|
67
76
|
}
|
|
68
77
|
if (!this.settingText) {
|
|
69
78
|
emit(this.changes);
|
|
@@ -96,6 +105,7 @@ class SmartEditor {
|
|
|
96
105
|
}
|
|
97
106
|
loadTokenizer() {
|
|
98
107
|
const request = ++this.tokenizerRequest;
|
|
108
|
+
this.grammarPreparation.begin();
|
|
99
109
|
void this.engine
|
|
100
110
|
.scopeColors?.(this.theme)
|
|
101
111
|
.catch(() => null)
|
|
@@ -110,6 +120,7 @@ class SmartEditor {
|
|
|
110
120
|
.then((tokenizer) => {
|
|
111
121
|
if (!this.disposed && request === this.tokenizerRequest) {
|
|
112
122
|
this.view.setTokenizer(tokenizer);
|
|
123
|
+
this.grammarPreparation.ready(tokenizer);
|
|
113
124
|
}
|
|
114
125
|
});
|
|
115
126
|
}
|
|
@@ -136,9 +147,10 @@ class SmartEditor {
|
|
|
136
147
|
onTextChange(listener) {
|
|
137
148
|
return subscribe(this.textChanges, listener);
|
|
138
149
|
}
|
|
139
|
-
announceTextChange(edits, source) {
|
|
150
|
+
announceTextChange(edits, source, typed) {
|
|
140
151
|
const change = {
|
|
141
152
|
source,
|
|
153
|
+
...(typed ? { typed } : {}),
|
|
142
154
|
changes: edits.map((edit) => ({
|
|
143
155
|
range: { start: { line: edit.start.line, character: edit.start.column }, end: { line: edit.end.line, character: edit.end.column } },
|
|
144
156
|
text: edit.text
|
|
@@ -160,6 +172,21 @@ class SmartEditor {
|
|
|
160
172
|
getScrollTop() {
|
|
161
173
|
return this.view.scrollPlace.y;
|
|
162
174
|
}
|
|
175
|
+
setScrollTop(top) {
|
|
176
|
+
this.view.setScrollTop(top);
|
|
177
|
+
}
|
|
178
|
+
getLineHeight(line) {
|
|
179
|
+
return this.view.getLineHeight(line);
|
|
180
|
+
}
|
|
181
|
+
getBaseLineHeight() {
|
|
182
|
+
return this.view.layout.metrics.lineHeight;
|
|
183
|
+
}
|
|
184
|
+
onLineHeights(listener) {
|
|
185
|
+
return this.view.onLineHeights(listener);
|
|
186
|
+
}
|
|
187
|
+
getContentHeight() {
|
|
188
|
+
return this.view.contentHeight;
|
|
189
|
+
}
|
|
163
190
|
getSelection() {
|
|
164
191
|
return this.rangeOf(this.model.getPrimary());
|
|
165
192
|
}
|
|
@@ -218,12 +245,29 @@ class SmartEditor {
|
|
|
218
245
|
setSelectionRanges(provider) {
|
|
219
246
|
this.controller.setSelectionRanges(provider);
|
|
220
247
|
}
|
|
221
|
-
applyEdits(edits) {
|
|
248
|
+
applyEdits(edits, options = {}) {
|
|
222
249
|
if (this.settings.readOnly || edits.length === 0) {
|
|
223
250
|
return false;
|
|
224
251
|
}
|
|
225
252
|
try {
|
|
226
|
-
|
|
253
|
+
const { mapSelections } = options;
|
|
254
|
+
return this.model.applyEdits(edits.map((edit) => ({ from: this.offsetAt(edit.range.start), to: this.offsetAt(edit.range.end), text: edit.text })), {
|
|
255
|
+
source: 'command',
|
|
256
|
+
joinPrevious: options.mergeUndo === true,
|
|
257
|
+
selectionPositions: mapSelections &&
|
|
258
|
+
this.model.getSelections().map((selection) => {
|
|
259
|
+
const { start, end } = mapSelections(this.rangeOf(selection));
|
|
260
|
+
const from = { line: start.line, column: start.character };
|
|
261
|
+
const to = { line: end.line, column: end.character };
|
|
262
|
+
if (selection.head < selection.anchor) {
|
|
263
|
+
return { anchor: to, head: from };
|
|
264
|
+
}
|
|
265
|
+
return {
|
|
266
|
+
anchor: from,
|
|
267
|
+
head: selection.head === selection.anchor && start.line === end.line && start.character === end.character ? from : to
|
|
268
|
+
};
|
|
269
|
+
})
|
|
270
|
+
});
|
|
227
271
|
}
|
|
228
272
|
catch {
|
|
229
273
|
return false;
|
|
@@ -240,7 +284,23 @@ class SmartEditor {
|
|
|
240
284
|
})));
|
|
241
285
|
}
|
|
242
286
|
setInlayHints(hints) {
|
|
243
|
-
this.view.setInlays(hints.map((hint, index) => ({
|
|
287
|
+
this.view.setInlays(hints.map((hint, index) => ({
|
|
288
|
+
id: hint.id ?? `hint-${index}`,
|
|
289
|
+
at: this.offsetAt(hint.position),
|
|
290
|
+
text: hint.label,
|
|
291
|
+
...(hint.parts === undefined ? {} : { parts: hint.parts }),
|
|
292
|
+
...(hint.paddingLeft ? { gapLeft: INLAY_GAP } : {}),
|
|
293
|
+
...(hint.paddingRight ? { gapRight: INLAY_GAP } : {})
|
|
294
|
+
})));
|
|
295
|
+
}
|
|
296
|
+
onInlayHover(listener) {
|
|
297
|
+
return this.view.onInlayHover(listener);
|
|
298
|
+
}
|
|
299
|
+
onInlayClick(handler) {
|
|
300
|
+
return this.controller.onInlayClick(handler);
|
|
301
|
+
}
|
|
302
|
+
setInlayLink(target) {
|
|
303
|
+
this.view.setInlayLink(target);
|
|
244
304
|
}
|
|
245
305
|
setGhostText(ghost) {
|
|
246
306
|
this.view.setGhost(ghost === null ? null : { at: this.offsetAt(ghost.position), text: ghost.text, accessory: ghost.accessory });
|
|
@@ -250,7 +310,7 @@ class SmartEditor {
|
|
|
250
310
|
? null
|
|
251
311
|
: tokens.map((token) => {
|
|
252
312
|
const from = this.offsetAt({ line: token.line, character: token.character });
|
|
253
|
-
return { from, to: from + token.length, scopes: token.scopes };
|
|
313
|
+
return { from, to: from + token.length, scopes: token.scopes, within: token.within };
|
|
254
314
|
}));
|
|
255
315
|
}
|
|
256
316
|
setHighlights(highlights) {
|
|
@@ -292,19 +352,23 @@ class SmartEditor {
|
|
|
292
352
|
}
|
|
293
353
|
replace(replacement, replaceOptions = {}) {
|
|
294
354
|
const { find } = this.view;
|
|
295
|
-
const
|
|
296
|
-
|
|
297
|
-
if (mark === null || query === null || this.blockedByReadOnly()) {
|
|
355
|
+
const match = find.currentMatch;
|
|
356
|
+
if (this.blockedByReadOnly()) {
|
|
298
357
|
return false;
|
|
299
358
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
const match = this.model.find(query.text, options)[0];
|
|
303
|
-
if (match === undefined) {
|
|
359
|
+
if (find.activeQuery?.regex === true) {
|
|
360
|
+
if (find.currentMark === null) {
|
|
304
361
|
return false;
|
|
305
362
|
}
|
|
363
|
+
void find.replaceOne(replacement, replaceOptions.preserveCase === true, () => !this.disposed && !this.settings.readOnly);
|
|
364
|
+
return true;
|
|
365
|
+
}
|
|
366
|
+
if (match === null) {
|
|
367
|
+
return false;
|
|
368
|
+
}
|
|
369
|
+
try {
|
|
306
370
|
// The next match is looked for after what was written, or a replacement that holds the query would find itself again.
|
|
307
|
-
find.pendingAnchor =
|
|
371
|
+
find.pendingAnchor = match.to;
|
|
308
372
|
if (!this.model.replace(match, replacement, { preserveCase: replaceOptions.preserveCase })) {
|
|
309
373
|
find.pendingAnchor = undefined;
|
|
310
374
|
return false;
|
|
@@ -319,23 +383,48 @@ class SmartEditor {
|
|
|
319
383
|
return true;
|
|
320
384
|
}
|
|
321
385
|
replaceAll(replacement, options = {}) {
|
|
322
|
-
const
|
|
323
|
-
|
|
386
|
+
const { find } = this.view;
|
|
387
|
+
const query = find.activeQuery;
|
|
388
|
+
if (query === null || find.state.noSelection === true || this.blockedByReadOnly()) {
|
|
324
389
|
return 0;
|
|
325
390
|
}
|
|
326
391
|
try {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
392
|
+
const matches = find.completeMatches;
|
|
393
|
+
if (matches !== null) {
|
|
394
|
+
let characters = 0;
|
|
395
|
+
for (const match of matches) {
|
|
396
|
+
characters += replacementText('', match, replacement, false, options.preserveCase, MAX_REPLACEMENT_CHARACTERS).length;
|
|
397
|
+
if (characters > MAX_REPLACEMENT_CHARACTERS) {
|
|
398
|
+
find.reportReplaceFailed('limit');
|
|
399
|
+
return 0;
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
const count = this.model.replaceMatches(matches, replacement, { preserveCase: options.preserveCase });
|
|
403
|
+
find.reportReplaced(count);
|
|
404
|
+
return count;
|
|
405
|
+
}
|
|
406
|
+
void this.replaceAllAsync(replacement, options);
|
|
407
|
+
return 0;
|
|
334
408
|
}
|
|
335
|
-
catch {
|
|
409
|
+
catch (error) {
|
|
410
|
+
find.reportReplaceFailed(error instanceof RangeError ? 'limit' : 'error');
|
|
336
411
|
return 0;
|
|
337
412
|
}
|
|
338
413
|
}
|
|
414
|
+
async replaceAllAsync(replacement, options = {}) {
|
|
415
|
+
const { find } = this.view;
|
|
416
|
+
if (this.disposed || this.blockedByReadOnly() || find.activeQuery === null || find.state.noSelection) {
|
|
417
|
+
return 0;
|
|
418
|
+
}
|
|
419
|
+
if (find.state.limited) {
|
|
420
|
+
find.reportReplaceFailed('limit');
|
|
421
|
+
return 0;
|
|
422
|
+
}
|
|
423
|
+
if (find.completeMatches !== null) {
|
|
424
|
+
return this.replaceAll(replacement, options);
|
|
425
|
+
}
|
|
426
|
+
return find.replaceAll(replacement, options.preserveCase === true, () => !this.disposed && !this.settings.readOnly);
|
|
427
|
+
}
|
|
339
428
|
setReplacePreview(replacement, options = {}) {
|
|
340
429
|
this.view.setReplacePreview(replacement, options.preserveCase === true);
|
|
341
430
|
}
|
|
@@ -359,24 +448,38 @@ class SmartEditor {
|
|
|
359
448
|
if (query.text === '') {
|
|
360
449
|
return false;
|
|
361
450
|
}
|
|
362
|
-
|
|
451
|
+
const { anchor, head } = this.model.getPrimary();
|
|
452
|
+
const offset = direction === 1 ? Math.max(anchor, head) : Math.min(anchor, head);
|
|
453
|
+
const reveal = (target) => {
|
|
454
|
+
if (target === null || this.disposed) {
|
|
455
|
+
return false;
|
|
456
|
+
}
|
|
457
|
+
this.view.ensureVisible(target.from);
|
|
458
|
+
this.model.setSelections([direction === 1 ? { anchor: target.from, head: target.to } : { anchor: target.to, head: target.from }]);
|
|
459
|
+
this.view.revealCaret(target.from > head ? 'centerDown' : 'centerUp');
|
|
460
|
+
return true;
|
|
461
|
+
};
|
|
462
|
+
if (query.regex) {
|
|
463
|
+
const revision = this.model.getRevision();
|
|
464
|
+
void this.view.find.nextFromCursor(query, offset, direction).then((target) => {
|
|
465
|
+
const current = this.model.getPrimary();
|
|
466
|
+
if (this.model.getRevision() === revision && current.anchor === anchor && current.head === head) {
|
|
467
|
+
reveal(target);
|
|
468
|
+
}
|
|
469
|
+
});
|
|
470
|
+
return true;
|
|
471
|
+
}
|
|
363
472
|
try {
|
|
364
|
-
|
|
473
|
+
return reveal(this.model.findNext(query.text, offset, {
|
|
474
|
+
caseSensitive: query.caseSensitive,
|
|
475
|
+
wholeWord: query.wholeWord,
|
|
476
|
+
backwards: direction === -1,
|
|
477
|
+
wrap: true
|
|
478
|
+
}));
|
|
365
479
|
}
|
|
366
480
|
catch {
|
|
367
481
|
return false;
|
|
368
482
|
}
|
|
369
|
-
if (matches.length === 0) {
|
|
370
|
-
return false;
|
|
371
|
-
}
|
|
372
|
-
const { anchor, head } = this.model.getPrimary();
|
|
373
|
-
const from = Math.min(anchor, head);
|
|
374
|
-
const to = Math.max(anchor, head);
|
|
375
|
-
const target = direction === 1 ? (matches.find((match) => match.from >= to) ?? matches[0]) : (matches.findLast((match) => match.to <= from) ?? matches.at(-1));
|
|
376
|
-
this.view.ensureVisible(target.from);
|
|
377
|
-
this.model.setSelections([direction === 1 ? { anchor: target.from, head: target.to } : { anchor: target.to, head: target.from }]);
|
|
378
|
-
this.view.revealCaret(target.from > head ? 'centerDown' : 'centerUp');
|
|
379
|
-
return true;
|
|
380
483
|
}
|
|
381
484
|
blockedByReadOnly() {
|
|
382
485
|
if (!this.settings.readOnly) {
|
|
@@ -406,8 +509,8 @@ class SmartEditor {
|
|
|
406
509
|
}
|
|
407
510
|
this.view.applySettings();
|
|
408
511
|
}
|
|
409
|
-
setChangeMarks(marks) {
|
|
410
|
-
this.view.setChangeMarks(marks);
|
|
512
|
+
setChangeMarks(marks, layer) {
|
|
513
|
+
this.view.setChangeMarks(marks, layer);
|
|
411
514
|
}
|
|
412
515
|
setAttributionMarks(marks) {
|
|
413
516
|
this.view.setAttributionMarks(marks);
|
|
@@ -415,6 +518,26 @@ class SmartEditor {
|
|
|
415
518
|
setLineHighlights(highlights) {
|
|
416
519
|
this.view.setLineHighlights(highlights);
|
|
417
520
|
}
|
|
521
|
+
setLineLabels(labels) {
|
|
522
|
+
this.view.setLineLabels(labels);
|
|
523
|
+
}
|
|
524
|
+
setInputPopup(popup) {
|
|
525
|
+
this.view.setInputPopup(popup);
|
|
526
|
+
}
|
|
527
|
+
announce(message) {
|
|
528
|
+
this.view.announce(message);
|
|
529
|
+
}
|
|
530
|
+
setMessages(messages) {
|
|
531
|
+
this.settings.messages = { ...this.settings.messages, ...messages };
|
|
532
|
+
this.view.repaint();
|
|
533
|
+
}
|
|
534
|
+
setLineNumbers(labels) {
|
|
535
|
+
this.view.setLineNumbers(labels);
|
|
536
|
+
}
|
|
537
|
+
setLineTokens(tokens) {
|
|
538
|
+
this.grammarPreparation.pause(tokens !== null);
|
|
539
|
+
this.view.setLineTokens(tokens);
|
|
540
|
+
}
|
|
418
541
|
renderCode(container, text, options = {}) {
|
|
419
542
|
this.view.renderCode(container, text, options);
|
|
420
543
|
}
|
|
@@ -430,12 +553,28 @@ class SmartEditor {
|
|
|
430
553
|
at: this.offsetAt({ line: widget.line, character: 0 }),
|
|
431
554
|
placement: widget.placement ?? 'below',
|
|
432
555
|
height: widget.height,
|
|
556
|
+
fixed: widget.fixed,
|
|
433
557
|
render: (container) => {
|
|
434
558
|
container.classList.add('se-widget');
|
|
435
559
|
widget.render(container);
|
|
436
560
|
}
|
|
437
561
|
})));
|
|
438
562
|
}
|
|
563
|
+
setReplacements(replacements, owner = DEFAULT_WIDGET_OWNER) {
|
|
564
|
+
this.view.setReplacements(owner, replacements.map((replacement) => ({
|
|
565
|
+
id: `replacement:${owner}:${replacement.id}`,
|
|
566
|
+
from: this.offsetAt({ line: replacement.startLine, character: 0 }),
|
|
567
|
+
to: this.model.getLine(Math.max(0, Math.min(replacement.endLine, this.model.getLineCount() - 1))).end,
|
|
568
|
+
height: replacement.height,
|
|
569
|
+
label: replacement.label,
|
|
570
|
+
enterable: replacement.enterable,
|
|
571
|
+
onReveal: replacement.onReveal === undefined ? undefined : () => replacement.onReveal(),
|
|
572
|
+
render: (container) => {
|
|
573
|
+
container.classList.add('se-widget-replacement');
|
|
574
|
+
replacement.render(container);
|
|
575
|
+
}
|
|
576
|
+
})));
|
|
577
|
+
}
|
|
439
578
|
setLineActions(actions, owner = DEFAULT_WIDGET_OWNER) {
|
|
440
579
|
this.view.setLineActions(owner, actions.map((action) => ({
|
|
441
580
|
id: action.id,
|
|
@@ -568,6 +707,9 @@ class SmartEditor {
|
|
|
568
707
|
this.settings.readOnlyReason = reason;
|
|
569
708
|
this.view.applySettings();
|
|
570
709
|
}
|
|
710
|
+
isReadOnly() {
|
|
711
|
+
return this.settings.readOnly;
|
|
712
|
+
}
|
|
571
713
|
runCommand(command) {
|
|
572
714
|
return this.controller.command(command);
|
|
573
715
|
}
|
|
@@ -582,6 +724,7 @@ class SmartEditor {
|
|
|
582
724
|
return;
|
|
583
725
|
}
|
|
584
726
|
this.disposed = true;
|
|
727
|
+
this.grammarPreparation.dispose();
|
|
585
728
|
this.changes.clear();
|
|
586
729
|
this.textChanges.clear();
|
|
587
730
|
this.carets.clear();
|
package/dist/fake.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorLineHighlight, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayHint, EditorKeyHandler, EditorMarker, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWidget } from './types.ts';
|
|
1
|
+
import type { Editor, EditorAttributionHover, EditorAttributionMark, EditorBlock, EditorCodeBlockOptions, EditorLineAction, EditorReplacement, EditorLineHighlight, LineToken, EditorChangeMark, EditorCodeVision, EditorClick, EditorClickHandler, EditorContextMenu, EditorContentChange, EditorEngine, EditorFindQuery, EditorFindState, EditorReplaceOptions, EditorGutterAction, EditorGutterMarker, EditorHighlight, EditorHover, EditorIndentation, EditorGhostText, EditorInlayClick, EditorInlayClickHandler, EditorInlayHint, EditorInlayTarget, EditorKeyHandler, EditorInputPopup, EditorMarker, EditorMessages, EditorOptions, EditorPosition, EditorRemoteCursor, EditorRange, EditorReveal, EditorRect, EditorRunCommand, EditorSelectionRanges, EditorFoldHints, EditorFoldOutline, EditorFolds, EditorSemanticToken, EditorSmartKeys, EditorApplyEditsOptions, EditorTextChange, EditorTrackedRange, EditorTheme, EditorWidget } from './types.ts';
|
|
2
2
|
import { type Listener } from './listeners.ts';
|
|
3
3
|
export declare class FakeEditor implements Editor {
|
|
4
4
|
readonly element: HTMLElement;
|
|
5
5
|
readonly language: string | undefined;
|
|
6
6
|
readonly path: string | undefined;
|
|
7
7
|
readonly column: number | null;
|
|
8
|
-
|
|
8
|
+
scrollTop: number | null;
|
|
9
9
|
wrap: boolean;
|
|
10
10
|
theme: EditorTheme;
|
|
11
11
|
readOnly: boolean;
|
|
@@ -54,6 +54,7 @@ export declare class FakeEditor implements Editor {
|
|
|
54
54
|
replacementsOfAll: string[];
|
|
55
55
|
replace(replacement: string, options?: EditorReplaceOptions): boolean;
|
|
56
56
|
replaceAll(replacement: string, options?: EditorReplaceOptions): number;
|
|
57
|
+
replaceAllAsync(replacement: string, options?: EditorReplaceOptions): Promise<number>;
|
|
57
58
|
setReplacePreview(replacement: string | null): void;
|
|
58
59
|
selectFindMatches(): number;
|
|
59
60
|
findFromCursor(query: EditorFindQuery, direction: 1 | -1): boolean;
|
|
@@ -63,8 +64,9 @@ export declare class FakeEditor implements Editor {
|
|
|
63
64
|
setWrap(wrap: boolean): void;
|
|
64
65
|
blocks: readonly EditorBlock[] | null;
|
|
65
66
|
private readonly scopes;
|
|
66
|
-
changeMarks: readonly EditorChangeMark[];
|
|
67
|
-
|
|
67
|
+
get changeMarks(): readonly EditorChangeMark[];
|
|
68
|
+
private readonly changeLayers;
|
|
69
|
+
setChangeMarks(marks: readonly EditorChangeMark[], layer?: string): void;
|
|
68
70
|
lineHighlights: readonly EditorLineHighlight[];
|
|
69
71
|
setLineHighlights(highlights: readonly EditorLineHighlight[]): void;
|
|
70
72
|
codeBlocks: {
|
|
@@ -72,6 +74,18 @@ export declare class FakeEditor implements Editor {
|
|
|
72
74
|
text: string;
|
|
73
75
|
options: EditorCodeBlockOptions;
|
|
74
76
|
}[];
|
|
77
|
+
lineNumbers: ((line: number) => string | null) | null;
|
|
78
|
+
lineTokens: ((line: number) => readonly LineToken[] | null | undefined) | null;
|
|
79
|
+
setLineNumbers(labels: ((line: number) => string | null) | null): void;
|
|
80
|
+
lineLabels: ((line: number) => string | null) | null;
|
|
81
|
+
setLineLabels(labels: ((line: number) => string | null) | null): void;
|
|
82
|
+
inputPopup: EditorInputPopup | null;
|
|
83
|
+
setInputPopup(popup: EditorInputPopup | null): void;
|
|
84
|
+
announcements: string[];
|
|
85
|
+
announce(message: string): void;
|
|
86
|
+
messages: Partial<EditorMessages>;
|
|
87
|
+
setMessages(messages: Partial<EditorMessages>): void;
|
|
88
|
+
setLineTokens(tokens: ((line: number) => readonly LineToken[] | null | undefined) | null): void;
|
|
75
89
|
renderCode(container: HTMLElement, text: string, options?: EditorCodeBlockOptions): void;
|
|
76
90
|
remoteCursors: readonly EditorRemoteCursor[];
|
|
77
91
|
setRemoteCursors(cursors: readonly EditorRemoteCursor[]): void;
|
|
@@ -84,6 +98,8 @@ export declare class FakeEditor implements Editor {
|
|
|
84
98
|
get widgets(): readonly EditorWidget[];
|
|
85
99
|
private readonly drawnWidgets;
|
|
86
100
|
setWidgets(widgets: readonly EditorWidget[], owner?: string): void;
|
|
101
|
+
readonly replacementsByOwner: Map<string, readonly EditorReplacement[]>;
|
|
102
|
+
setReplacements(replacements: readonly EditorReplacement[], owner?: string): void;
|
|
87
103
|
readonly lineActionsByOwner: Map<string, readonly EditorLineAction[]>;
|
|
88
104
|
setLineActions(actions: readonly EditorLineAction[], owner?: string): void;
|
|
89
105
|
codeVision: readonly EditorCodeVision[];
|
|
@@ -129,11 +145,26 @@ export declare class FakeEditor implements Editor {
|
|
|
129
145
|
};
|
|
130
146
|
private readonly carets;
|
|
131
147
|
private readonly hovers;
|
|
148
|
+
private readonly lineHeights;
|
|
132
149
|
private readonly views;
|
|
133
150
|
private readonly keys;
|
|
134
151
|
setMarkers(markers: readonly EditorMarker[]): void;
|
|
135
152
|
inlayHints: readonly EditorInlayHint[];
|
|
136
153
|
setInlayHints(hints: readonly EditorInlayHint[]): void;
|
|
154
|
+
private readonly inlayHovers;
|
|
155
|
+
private readonly inlayHandlers;
|
|
156
|
+
inlayLink: {
|
|
157
|
+
readonly id: string;
|
|
158
|
+
readonly part: number | null;
|
|
159
|
+
} | null;
|
|
160
|
+
onInlayHover(listener: (target: EditorInlayTarget | null) => void): () => void;
|
|
161
|
+
hoverInlay(id: string | null, part?: number | null): void;
|
|
162
|
+
onInlayClick(handler: EditorInlayClickHandler): () => void;
|
|
163
|
+
clickInlay(click: Partial<EditorInlayClick> & Pick<EditorInlayClick, 'id'>): boolean;
|
|
164
|
+
setInlayLink(target: {
|
|
165
|
+
readonly id: string;
|
|
166
|
+
readonly part: number | null;
|
|
167
|
+
} | null): void;
|
|
137
168
|
ghost: EditorGhostText | null;
|
|
138
169
|
setGhostText(ghost: EditorGhostText | null): void;
|
|
139
170
|
semanticTokens: readonly EditorSemanticToken[] | null;
|
|
@@ -146,6 +177,12 @@ export declare class FakeEditor implements Editor {
|
|
|
146
177
|
getFolds(): EditorFolds;
|
|
147
178
|
getScrollTop(): number;
|
|
148
179
|
selection: EditorRange | null;
|
|
180
|
+
contentHeight: number;
|
|
181
|
+
setScrollTop(top: number): void;
|
|
182
|
+
getLineHeight(line: number): number;
|
|
183
|
+
getBaseLineHeight(): number;
|
|
184
|
+
onLineHeights(listener: Listener): () => void;
|
|
185
|
+
getContentHeight(): number;
|
|
149
186
|
getSelection(): EditorRange;
|
|
150
187
|
private otherSelections;
|
|
151
188
|
get otherCarets(): EditorPosition[];
|
|
@@ -174,10 +211,11 @@ export declare class FakeEditor implements Editor {
|
|
|
174
211
|
click(click: EditorClick): boolean;
|
|
175
212
|
openContextMenu(menu: EditorContextMenu): void;
|
|
176
213
|
press(event: Pick<KeyboardEvent, 'key'> & Partial<KeyboardEvent>): boolean;
|
|
177
|
-
applyEdits(edits: readonly EditorContentChange[]): boolean;
|
|
214
|
+
applyEdits(edits: readonly EditorContentChange[], options?: EditorApplyEditsOptions): boolean;
|
|
178
215
|
setTheme(theme: EditorTheme): void;
|
|
179
216
|
refreshFont(): void;
|
|
180
217
|
setReadOnly(readOnly: boolean, reason?: string): void;
|
|
218
|
+
isReadOnly(): boolean;
|
|
181
219
|
readonly commands: EditorRunCommand[];
|
|
182
220
|
runCommand(command: EditorRunCommand): boolean;
|
|
183
221
|
focus(): void;
|