@adecore/editor 0.22.1 → 0.23.1
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 +189 -41
- package/dist/fake.d.ts +45 -5
- package/dist/fake.js +121 -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 +86 -2
- package/dist/uniform-geometry.d.ts +7 -0
- package/dist/uniform-geometry.js +49 -0
- package/dist/view.d.ts +69 -17
- package/dist/view.js +427 -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 +222 -42
- package/src/fake.ts +157 -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 +178 -8
- package/src/uniform-geometry.ts +57 -0
- package/src/view.ts +505 -102
- package/src/worker-client.ts +212 -0
package/dist/fake.js
CHANGED
|
@@ -76,7 +76,7 @@ export class FakeEditor {
|
|
|
76
76
|
this.replaceText(text);
|
|
77
77
|
}
|
|
78
78
|
/* The text becomes `text`, and listeners of the text hear the one stretch that differs, as the real editor reports it. */
|
|
79
|
-
replaceText(text, source = 'external') {
|
|
79
|
+
replaceText(text, source = 'external', selections) {
|
|
80
80
|
const span = changedSpan(this.text, text);
|
|
81
81
|
const before = this.text;
|
|
82
82
|
this.text = text;
|
|
@@ -85,7 +85,12 @@ export class FakeEditor {
|
|
|
85
85
|
}
|
|
86
86
|
// As in the real editor the caret lands behind what was typed, and listeners of the caret hear it before those of the text.
|
|
87
87
|
if (source !== 'external') {
|
|
88
|
-
|
|
88
|
+
if (selections === undefined) {
|
|
89
|
+
this.moveCaret(positionIn(text, span.start + span.text.length));
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
this.setSelections(selections);
|
|
93
|
+
}
|
|
89
94
|
}
|
|
90
95
|
this.followTracked(span.start, span.end, span.text.length);
|
|
91
96
|
this.ghost = null;
|
|
@@ -180,6 +185,9 @@ export class FakeEditor {
|
|
|
180
185
|
this.replaceOptions.push(options);
|
|
181
186
|
return this.readOnly ? 0 : this.findState.count;
|
|
182
187
|
}
|
|
188
|
+
async replaceAllAsync(replacement, options = {}) {
|
|
189
|
+
return this.replaceAll(replacement, options);
|
|
190
|
+
}
|
|
183
191
|
setReplacePreview(replacement) {
|
|
184
192
|
this.replacePreview = replacement;
|
|
185
193
|
}
|
|
@@ -210,10 +218,18 @@ export class FakeEditor {
|
|
|
210
218
|
/* What the host handed it last; null while it reads the structure itself. */
|
|
211
219
|
blocks = null;
|
|
212
220
|
scopes = new Set();
|
|
213
|
-
/*
|
|
214
|
-
changeMarks
|
|
215
|
-
|
|
216
|
-
|
|
221
|
+
/* The marks of every layer, in the order the layers last became non-empty. */
|
|
222
|
+
get changeMarks() {
|
|
223
|
+
return [...this.changeLayers.values()].flat();
|
|
224
|
+
}
|
|
225
|
+
changeLayers = new Map();
|
|
226
|
+
setChangeMarks(marks, layer = '') {
|
|
227
|
+
if (marks.length === 0) {
|
|
228
|
+
this.changeLayers.delete(layer);
|
|
229
|
+
}
|
|
230
|
+
else {
|
|
231
|
+
this.changeLayers.set(layer, marks);
|
|
232
|
+
}
|
|
217
233
|
}
|
|
218
234
|
/* The tinted lines the host set last. */
|
|
219
235
|
lineHighlights = [];
|
|
@@ -222,6 +238,32 @@ export class FakeEditor {
|
|
|
222
238
|
}
|
|
223
239
|
/* What the host drew as code outside the document: the text and how, and into which element. */
|
|
224
240
|
codeBlocks = [];
|
|
241
|
+
lineNumbers = null;
|
|
242
|
+
lineTokens = null;
|
|
243
|
+
setLineNumbers(labels) {
|
|
244
|
+
this.lineNumbers = labels;
|
|
245
|
+
}
|
|
246
|
+
lineLabels = null;
|
|
247
|
+
setLineLabels(labels) {
|
|
248
|
+
this.lineLabels = labels;
|
|
249
|
+
}
|
|
250
|
+
/* What the input points at, as the last call left it. */
|
|
251
|
+
inputPopup = null;
|
|
252
|
+
setInputPopup(popup) {
|
|
253
|
+
this.inputPopup = popup;
|
|
254
|
+
}
|
|
255
|
+
/* Every sentence said, oldest first. */
|
|
256
|
+
announcements = [];
|
|
257
|
+
announce(message) {
|
|
258
|
+
this.announcements.push(message);
|
|
259
|
+
}
|
|
260
|
+
messages = {};
|
|
261
|
+
setMessages(messages) {
|
|
262
|
+
this.messages = { ...this.messages, ...messages };
|
|
263
|
+
}
|
|
264
|
+
setLineTokens(tokens) {
|
|
265
|
+
this.lineTokens = tokens;
|
|
266
|
+
}
|
|
225
267
|
renderCode(container, text, options = {}) {
|
|
226
268
|
this.codeBlocks.push({ container, text, options });
|
|
227
269
|
}
|
|
@@ -265,11 +307,20 @@ export class FakeEditor {
|
|
|
265
307
|
const before = this.drawnWidgets.get(owner) ?? new Set();
|
|
266
308
|
for (const widget of widgets) {
|
|
267
309
|
if (!before.has(widget.id)) {
|
|
268
|
-
widget.render({});
|
|
310
|
+
widget.render(this.element.ownerDocument?.createElement('div') ?? {});
|
|
269
311
|
}
|
|
270
312
|
}
|
|
271
313
|
this.drawnWidgets.set(owner, new Set(widgets.map((widget) => widget.id)));
|
|
272
314
|
}
|
|
315
|
+
replacementsByOwner = new Map();
|
|
316
|
+
setReplacements(replacements, owner = 'default') {
|
|
317
|
+
if (replacements.length === 0) {
|
|
318
|
+
this.replacementsByOwner.delete(owner);
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
this.replacementsByOwner.set(owner, replacements);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
273
324
|
lineActionsByOwner = new Map();
|
|
274
325
|
setLineActions(actions, owner = 'default') {
|
|
275
326
|
if (actions.length === 0) {
|
|
@@ -329,11 +380,15 @@ export class FakeEditor {
|
|
|
329
380
|
}
|
|
330
381
|
smartKeys;
|
|
331
382
|
guides = true;
|
|
383
|
+
stickyScroll = true;
|
|
332
384
|
whitespace = false;
|
|
333
385
|
rightMargin = null;
|
|
334
386
|
setGuides(guides) {
|
|
335
387
|
this.guides = guides;
|
|
336
388
|
}
|
|
389
|
+
setStickyScroll(sticky) {
|
|
390
|
+
this.stickyScroll = sticky;
|
|
391
|
+
}
|
|
337
392
|
setWhitespace(whitespace) {
|
|
338
393
|
this.whitespace = whitespace;
|
|
339
394
|
}
|
|
@@ -367,6 +422,7 @@ export class FakeEditor {
|
|
|
367
422
|
charSize = { width: 8, height: 20 };
|
|
368
423
|
carets = new Set();
|
|
369
424
|
hovers = new Set();
|
|
425
|
+
lineHeights = new Set();
|
|
370
426
|
views = new Set();
|
|
371
427
|
keys = new Set();
|
|
372
428
|
setMarkers(markers) {
|
|
@@ -377,6 +433,28 @@ export class FakeEditor {
|
|
|
377
433
|
setInlayHints(hints) {
|
|
378
434
|
this.inlayHints = hints;
|
|
379
435
|
}
|
|
436
|
+
inlayHovers = new Set();
|
|
437
|
+
inlayHandlers = new Set();
|
|
438
|
+
/* The hint, or part of one, the last `setInlayLink` drew as a link. */
|
|
439
|
+
inlayLink = null;
|
|
440
|
+
onInlayHover(listener) {
|
|
441
|
+
return subscribe(this.inlayHovers, listener);
|
|
442
|
+
}
|
|
443
|
+
/* The pointer resting on a hint or a part of one, or leaving them. */
|
|
444
|
+
hoverInlay(id, part = null) {
|
|
445
|
+
emit(this.inlayHovers, id === null ? null : { id, part, rect: { left: 0, top: 0, right: 40, bottom: 20 } });
|
|
446
|
+
}
|
|
447
|
+
onInlayClick(handler) {
|
|
448
|
+
return subscribe(this.inlayHandlers, handler);
|
|
449
|
+
}
|
|
450
|
+
/* A press on a hint as the editor sees it first; true when a handler took it. */
|
|
451
|
+
clickInlay(click) {
|
|
452
|
+
const full = { part: null, mod: false, alt: false, shift: false, clicks: 1, touch: false, ...click };
|
|
453
|
+
return [...this.inlayHandlers].some((handler) => handler(full));
|
|
454
|
+
}
|
|
455
|
+
setInlayLink(target) {
|
|
456
|
+
this.inlayLink = target;
|
|
457
|
+
}
|
|
380
458
|
/* The suggestion after the caret now, which any change of the text takes away as the real editor does. */
|
|
381
459
|
ghost = null;
|
|
382
460
|
setGhostText(ghost) {
|
|
@@ -408,6 +486,26 @@ export class FakeEditor {
|
|
|
408
486
|
}
|
|
409
487
|
/* The selection a person made; without one the caret. */
|
|
410
488
|
selection = null;
|
|
489
|
+
/* A test supplies the measured height; this fake has no layout. */
|
|
490
|
+
contentHeight = 0;
|
|
491
|
+
setScrollTop(top) {
|
|
492
|
+
if (Number.isFinite(top) && this.getScrollTop() !== Math.max(0, top)) {
|
|
493
|
+
this.scrollTop = Math.max(0, top);
|
|
494
|
+
emit(this.views);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
getLineHeight(line) {
|
|
498
|
+
return Number.isInteger(line) && line >= 0 && line < this.text.split('\n').length ? this.charSize.height : 0;
|
|
499
|
+
}
|
|
500
|
+
getBaseLineHeight() {
|
|
501
|
+
return this.charSize.height;
|
|
502
|
+
}
|
|
503
|
+
onLineHeights(listener) {
|
|
504
|
+
return subscribe(this.lineHeights, listener);
|
|
505
|
+
}
|
|
506
|
+
getContentHeight() {
|
|
507
|
+
return this.contentHeight;
|
|
508
|
+
}
|
|
411
509
|
getSelection() {
|
|
412
510
|
return this.selection ?? { start: this.caret, end: this.caret };
|
|
413
511
|
}
|
|
@@ -512,7 +610,8 @@ export class FakeEditor {
|
|
|
512
610
|
const full = { ctrlKey: false, metaKey: false, altKey: false, shiftKey: false, preventDefault: () => undefined, ...event };
|
|
513
611
|
return [...this.keys].some((handler) => handler(full));
|
|
514
612
|
}
|
|
515
|
-
|
|
613
|
+
/* The fake keeps no undo history, so `mergeUndo` changes nothing here. It keeps no selection direction either, so a test of `mapSelections` keeping a backward selection needs the real editor. */
|
|
614
|
+
applyEdits(edits, options = {}) {
|
|
516
615
|
if (this.readOnly || edits.length === 0) {
|
|
517
616
|
return false;
|
|
518
617
|
}
|
|
@@ -539,11 +638,14 @@ export class FakeEditor {
|
|
|
539
638
|
return offset + delta;
|
|
540
639
|
};
|
|
541
640
|
const moved = others.map((range) => ({ anchor: follow(range.anchor), head: follow(range.head) }));
|
|
542
|
-
this.
|
|
543
|
-
this.
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
641
|
+
const mapped = options.mapSelections && this.getSelections().map((range) => options.mapSelections(range));
|
|
642
|
+
this.replaceText(text, 'command', mapped);
|
|
643
|
+
if (mapped === undefined) {
|
|
644
|
+
this.otherSelections = moved.map((range) => ({
|
|
645
|
+
start: positionIn(text, Math.min(range.anchor, range.head)),
|
|
646
|
+
end: positionIn(text, Math.max(range.anchor, range.head))
|
|
647
|
+
}));
|
|
648
|
+
}
|
|
547
649
|
emit(this.changes);
|
|
548
650
|
return true;
|
|
549
651
|
}
|
|
@@ -557,6 +659,9 @@ export class FakeEditor {
|
|
|
557
659
|
this.readOnly = readOnly;
|
|
558
660
|
this.readOnlyReason = reason;
|
|
559
661
|
}
|
|
662
|
+
isReadOnly() {
|
|
663
|
+
return this.readOnly;
|
|
664
|
+
}
|
|
560
665
|
/* The commands run, in order; the fake has no commands of its own to carry out. */
|
|
561
666
|
commands = [];
|
|
562
667
|
runCommand(command) {
|
|
@@ -572,8 +677,11 @@ export class FakeEditor {
|
|
|
572
677
|
this.textChanges.clear();
|
|
573
678
|
this.carets.clear();
|
|
574
679
|
this.hovers.clear();
|
|
680
|
+
this.inlayHovers.clear();
|
|
681
|
+
this.inlayHandlers.clear();
|
|
575
682
|
this.attributionHovers.clear();
|
|
576
683
|
this.views.clear();
|
|
684
|
+
this.lineHeights.clear();
|
|
577
685
|
this.keys.clear();
|
|
578
686
|
this.saves.clear();
|
|
579
687
|
this.blurs.clear();
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type EditorSearchClient } from './search-client.ts';
|
|
2
|
+
export interface FindSearchOptions {
|
|
3
|
+
readonly createClient: () => EditorSearchClient | null;
|
|
4
|
+
readonly schedule?: (callback: () => void, delay: number) => () => void;
|
|
5
|
+
readonly now?: () => number;
|
|
6
|
+
}
|
|
7
|
+
type SearchKind = 'live' | 'preview' | 'command';
|
|
8
|
+
export declare function scheduleFind(callback: () => void, delay: number): () => void;
|
|
9
|
+
export declare class FindSearchQueue {
|
|
10
|
+
private client;
|
|
11
|
+
private active;
|
|
12
|
+
private pending;
|
|
13
|
+
private cancelTimer;
|
|
14
|
+
private started;
|
|
15
|
+
private disposed;
|
|
16
|
+
private epoch;
|
|
17
|
+
private readonly options;
|
|
18
|
+
constructor(options: FindSearchOptions);
|
|
19
|
+
get busy(): boolean;
|
|
20
|
+
request<Result>(run: (client: EditorSearchClient, isCurrent: () => boolean) => Promise<Result>, kind?: SearchKind, valid?: () => boolean): Promise<Result>;
|
|
21
|
+
private now;
|
|
22
|
+
private pump;
|
|
23
|
+
release(): void;
|
|
24
|
+
dispose(): void;
|
|
25
|
+
}
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { EditorSearchError } from './search-client.js';
|
|
2
|
+
export function scheduleFind(callback, delay) {
|
|
3
|
+
const timer = setTimeout(callback, delay);
|
|
4
|
+
return () => clearTimeout(timer);
|
|
5
|
+
}
|
|
6
|
+
function superseded() {
|
|
7
|
+
return new EditorSearchError('superseded', 'The find operation is no longer current.');
|
|
8
|
+
}
|
|
9
|
+
/* Commands finish atomically; short background requests reuse the worker before newer work starts. */
|
|
10
|
+
export class FindSearchQueue {
|
|
11
|
+
client;
|
|
12
|
+
active;
|
|
13
|
+
pending = [];
|
|
14
|
+
cancelTimer;
|
|
15
|
+
started = 0;
|
|
16
|
+
disposed = false;
|
|
17
|
+
epoch = 0;
|
|
18
|
+
options;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
}
|
|
22
|
+
get busy() {
|
|
23
|
+
return this.active !== undefined || this.pending.length > 0;
|
|
24
|
+
}
|
|
25
|
+
request(run, kind = 'live', valid) {
|
|
26
|
+
if (this.disposed) {
|
|
27
|
+
return Promise.reject(new EditorSearchError('disposed', 'The find session was disposed.'));
|
|
28
|
+
}
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
this.pending = this.pending.filter((job) => {
|
|
31
|
+
if (job.kind !== 'command' && (job.kind === kind || (kind !== 'preview' && job.kind === 'preview'))) {
|
|
32
|
+
job.cancelled = true;
|
|
33
|
+
job.reject(superseded());
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
return true;
|
|
37
|
+
});
|
|
38
|
+
this.pending.push({ kind, valid, run, resolve: (value) => resolve(value), reject, cancelled: false });
|
|
39
|
+
this.pending.sort((left, right) => priority(left.kind) - priority(right.kind));
|
|
40
|
+
if (this.active === undefined) {
|
|
41
|
+
this.pump();
|
|
42
|
+
}
|
|
43
|
+
else if ((kind !== 'preview' || this.active.valid?.() === false) &&
|
|
44
|
+
(this.active.kind !== 'command' || this.active.valid?.() === false) &&
|
|
45
|
+
this.cancelTimer === undefined) {
|
|
46
|
+
this.cancelTimer = (this.options.schedule ?? scheduleFind)(() => {
|
|
47
|
+
this.cancelTimer = undefined;
|
|
48
|
+
if (this.pending.length > 0 && this.active !== undefined && (this.active.kind !== 'command' || this.active.valid?.() === false)) {
|
|
49
|
+
this.active.cancelled = true;
|
|
50
|
+
this.active.reject(superseded());
|
|
51
|
+
this.client?.cancel();
|
|
52
|
+
}
|
|
53
|
+
}, Math.max(0, 200 - (this.now() - this.started)));
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
now() {
|
|
58
|
+
return this.options.now?.() ?? performance.now();
|
|
59
|
+
}
|
|
60
|
+
pump() {
|
|
61
|
+
if (this.disposed || this.active !== undefined) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const job = this.pending.shift();
|
|
65
|
+
if (job === undefined) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
this.active = job;
|
|
69
|
+
this.started = this.now();
|
|
70
|
+
const epoch = this.epoch;
|
|
71
|
+
const alive = () => !this.disposed && epoch === this.epoch && !job.cancelled;
|
|
72
|
+
const isCurrent = () => alive() && job.valid?.() !== false;
|
|
73
|
+
void Promise.resolve()
|
|
74
|
+
.then(() => {
|
|
75
|
+
if (!isCurrent()) {
|
|
76
|
+
throw superseded();
|
|
77
|
+
}
|
|
78
|
+
this.client ??= this.options.createClient();
|
|
79
|
+
if (this.client === null) {
|
|
80
|
+
throw new EditorSearchError('unavailable', 'Regex search needs a search worker.');
|
|
81
|
+
}
|
|
82
|
+
const client = this.client;
|
|
83
|
+
const guarded = {
|
|
84
|
+
search: (...args) => (isCurrent() ? client.search(...args) : Promise.reject(superseded())),
|
|
85
|
+
match: (...args) => (isCurrent() ? client.match(...args) : Promise.reject(superseded())),
|
|
86
|
+
next: (...args) => (isCurrent() ? client.next(...args) : Promise.reject(superseded())),
|
|
87
|
+
replacements: (...args) => (isCurrent() ? client.replacements(...args) : Promise.reject(superseded())),
|
|
88
|
+
cancel: () => client.cancel(),
|
|
89
|
+
release: () => client.release(),
|
|
90
|
+
dispose: () => client.dispose()
|
|
91
|
+
};
|
|
92
|
+
return job.run(guarded, isCurrent);
|
|
93
|
+
})
|
|
94
|
+
.then((value) => {
|
|
95
|
+
if (alive()) {
|
|
96
|
+
job.resolve(value);
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
job.reject(superseded());
|
|
100
|
+
}
|
|
101
|
+
}, job.reject)
|
|
102
|
+
.finally(() => {
|
|
103
|
+
this.active = undefined;
|
|
104
|
+
this.cancelTimer?.();
|
|
105
|
+
this.cancelTimer = undefined;
|
|
106
|
+
this.pump();
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
release() {
|
|
110
|
+
this.epoch++;
|
|
111
|
+
this.active?.reject(superseded());
|
|
112
|
+
for (const job of this.pending) {
|
|
113
|
+
job.cancelled = true;
|
|
114
|
+
job.reject(superseded());
|
|
115
|
+
}
|
|
116
|
+
this.pending = [];
|
|
117
|
+
this.cancelTimer?.();
|
|
118
|
+
this.cancelTimer = undefined;
|
|
119
|
+
this.client?.release();
|
|
120
|
+
}
|
|
121
|
+
dispose() {
|
|
122
|
+
this.disposed = true;
|
|
123
|
+
this.release();
|
|
124
|
+
this.client?.dispose();
|
|
125
|
+
this.client = undefined;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
function priority(kind) {
|
|
129
|
+
return kind === 'command' ? 0 : kind === 'live' ? 1 : 2;
|
|
130
|
+
}
|
package/dist/find.d.ts
CHANGED
|
@@ -1,18 +1,45 @@
|
|
|
1
|
-
import type { DocumentChange, DocumentModel } from '@adecore/editor-core';
|
|
1
|
+
import type { DocumentChange, DocumentModel, FindMatch } from '@adecore/editor-core';
|
|
2
|
+
import { type FindSearchOptions } from './find-search.ts';
|
|
2
3
|
import type { EditorFindQuery, EditorFindState } from './types.ts';
|
|
3
4
|
export interface FindMark {
|
|
4
5
|
from: number;
|
|
5
6
|
to: number;
|
|
6
7
|
}
|
|
7
8
|
export declare const FIND_LIMIT = 10000;
|
|
9
|
+
export interface FindControllerOptions extends FindSearchOptions {
|
|
10
|
+
readonly changed: (reveal?: boolean) => void;
|
|
11
|
+
}
|
|
8
12
|
export declare class FindController {
|
|
9
13
|
private query;
|
|
10
14
|
private marks;
|
|
15
|
+
private cache?;
|
|
11
16
|
private index;
|
|
17
|
+
private outside;
|
|
18
|
+
private seeking;
|
|
19
|
+
private replacing;
|
|
20
|
+
private replaceEpoch;
|
|
21
|
+
private replaced;
|
|
22
|
+
private replaceFailed;
|
|
12
23
|
private bounds;
|
|
13
24
|
pendingAnchor: number | undefined;
|
|
14
25
|
private readonly model;
|
|
15
|
-
|
|
26
|
+
private readonly options;
|
|
27
|
+
private readonly search;
|
|
28
|
+
private regexCache;
|
|
29
|
+
private snapshotMemo;
|
|
30
|
+
private retained;
|
|
31
|
+
private epoch;
|
|
32
|
+
private searching;
|
|
33
|
+
private failed;
|
|
34
|
+
private captureFailed;
|
|
35
|
+
private pendingStep;
|
|
36
|
+
private cancelSearch;
|
|
37
|
+
private cancelMatch;
|
|
38
|
+
private preview;
|
|
39
|
+
private disposed;
|
|
40
|
+
private revision;
|
|
41
|
+
private cursorRequests;
|
|
42
|
+
constructor(model: DocumentModel, options?: FindControllerOptions);
|
|
16
43
|
get activeQuery(): EditorFindQuery | null;
|
|
17
44
|
get active(): boolean;
|
|
18
45
|
get matches(): readonly FindMark[];
|
|
@@ -23,8 +50,29 @@ export declare class FindController {
|
|
|
23
50
|
to: number;
|
|
24
51
|
} | null;
|
|
25
52
|
get currentMark(): FindMark | null;
|
|
53
|
+
matchesBetween(from: number, to: number): readonly FindMark[];
|
|
54
|
+
get currentMatch(): FindMatch | null;
|
|
55
|
+
get completeMatches(): readonly FindMatch[] | null;
|
|
56
|
+
private get cachedMatches();
|
|
57
|
+
private cacheKey;
|
|
26
58
|
set(query: EditorFindQuery | null): void;
|
|
27
59
|
mapBounds(changes: readonly DocumentChange[]): void;
|
|
28
60
|
refresh(): void;
|
|
29
61
|
step(direction: 1 | -1): void;
|
|
62
|
+
private get freshRegex();
|
|
63
|
+
private resetRegex;
|
|
64
|
+
private refreshRegex;
|
|
65
|
+
private startRegex;
|
|
66
|
+
private snapshot;
|
|
67
|
+
setPreview(active: boolean): void;
|
|
68
|
+
private preparePreview;
|
|
69
|
+
ensureMatch(command?: boolean): Promise<FindMatch | null>;
|
|
70
|
+
private chooseCurrent;
|
|
71
|
+
private seek;
|
|
72
|
+
nextFromCursor(query: EditorFindQuery, offset: number, direction: 1 | -1): Promise<FindMark | null>;
|
|
73
|
+
reportReplaceFailed(failure: NonNullable<EditorFindState['replaceFailed']>): void;
|
|
74
|
+
reportReplaced(count: number): void;
|
|
75
|
+
replaceOne(replacement: string, preserveCase: boolean, canApply: () => boolean): Promise<boolean>;
|
|
76
|
+
replaceAll(replacement: string, preserveCase: boolean, canApply: () => boolean): Promise<number>;
|
|
77
|
+
dispose(): void;
|
|
30
78
|
}
|