@adecore/editor 0.22.1 → 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.
Files changed (94) hide show
  1. package/dist/attribution.d.ts +9 -8
  2. package/dist/attribution.js +44 -9
  3. package/dist/bidi.d.ts +44 -0
  4. package/dist/bidi.js +26 -0
  5. package/dist/column-selection.js +2 -1
  6. package/dist/controller.d.ts +6 -1
  7. package/dist/controller.js +93 -3
  8. package/dist/editor.css +81 -1
  9. package/dist/engine.js +184 -41
  10. package/dist/fake.d.ts +43 -5
  11. package/dist/fake.js +117 -13
  12. package/dist/find-search.d.ts +26 -0
  13. package/dist/find-search.js +130 -0
  14. package/dist/find.d.ts +50 -2
  15. package/dist/find.js +575 -25
  16. package/dist/geometry-stops.d.ts +6 -0
  17. package/dist/geometry-stops.js +47 -0
  18. package/dist/grammar-preparation.d.ts +29 -0
  19. package/dist/grammar-preparation.js +147 -0
  20. package/dist/index.d.ts +3 -1
  21. package/dist/index.js +2 -0
  22. package/dist/keymap-table.d.ts +10 -1
  23. package/dist/keymap-table.js +37 -1
  24. package/dist/keymap.d.ts +1 -0
  25. package/dist/keymap.js +4 -1
  26. package/dist/layout-changes.d.ts +6 -0
  27. package/dist/layout-changes.js +27 -0
  28. package/dist/layout.d.ts +45 -2
  29. package/dist/layout.js +202 -58
  30. package/dist/offsets.d.ts +1 -0
  31. package/dist/offsets.js +23 -0
  32. package/dist/outline.js +5 -4
  33. package/dist/paint.d.ts +11 -3
  34. package/dist/paint.js +180 -34
  35. package/dist/search-client.d.ts +27 -0
  36. package/dist/search-client.js +210 -0
  37. package/dist/search-protocol.d.ts +103 -0
  38. package/dist/search-protocol.js +3 -0
  39. package/dist/search-worker.d.ts +11 -0
  40. package/dist/search-worker.js +137 -0
  41. package/dist/semantic.d.ts +2 -1
  42. package/dist/semantic.js +6 -1
  43. package/dist/shiki-document.d.ts +8 -0
  44. package/dist/shiki-document.js +93 -0
  45. package/dist/shiki-worker.d.ts +65 -0
  46. package/dist/shiki-worker.js +265 -0
  47. package/dist/shiki.d.ts +1 -0
  48. package/dist/shiki.js +96 -33
  49. package/dist/testing.d.ts +1 -0
  50. package/dist/tokens.d.ts +2 -0
  51. package/dist/tokens.js +37 -7
  52. package/dist/touch.d.ts +27 -0
  53. package/dist/touch.js +100 -0
  54. package/dist/types.d.ts +84 -2
  55. package/dist/uniform-geometry.d.ts +7 -0
  56. package/dist/uniform-geometry.js +49 -0
  57. package/dist/view.d.ts +68 -17
  58. package/dist/view.js +424 -97
  59. package/dist/worker-client.d.ts +37 -0
  60. package/dist/worker-client.js +195 -0
  61. package/package.json +17 -2
  62. package/src/attribution.ts +50 -14
  63. package/src/bidi.ts +32 -0
  64. package/src/column-selection.ts +2 -1
  65. package/src/controller.ts +97 -3
  66. package/src/editor.css +81 -1
  67. package/src/engine.ts +216 -42
  68. package/src/fake.ts +152 -14
  69. package/src/find-search.ts +165 -0
  70. package/src/find.ts +622 -21
  71. package/src/geometry-stops.ts +51 -0
  72. package/src/grammar-preparation.ts +158 -0
  73. package/src/index.ts +10 -0
  74. package/src/keymap-table.ts +44 -2
  75. package/src/keymap.ts +5 -1
  76. package/src/layout-changes.ts +33 -0
  77. package/src/layout.ts +262 -63
  78. package/src/offsets.ts +24 -0
  79. package/src/outline.ts +5 -4
  80. package/src/paint.ts +202 -36
  81. package/src/search-client.ts +306 -0
  82. package/src/search-protocol.ts +100 -0
  83. package/src/search-worker.ts +171 -0
  84. package/src/semantic.ts +8 -2
  85. package/src/shiki-document.ts +143 -0
  86. package/src/shiki-worker.ts +344 -0
  87. package/src/shiki.ts +103 -33
  88. package/src/testing.ts +2 -0
  89. package/src/tokens.ts +36 -7
  90. package/src/touch.ts +134 -0
  91. package/src/types.ts +174 -8
  92. package/src/uniform-geometry.ts +57 -0
  93. package/src/view.ts +500 -102
  94. 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
- return this.model.applyEdits(edits.map((edit) => ({ from: this.offsetAt(edit.range.start), to: this.offsetAt(edit.range.end), text: edit.text })), { source: 'command' });
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) => ({ id: `hint-${index}`, at: this.offsetAt(hint.position), text: hint.label })));
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 mark = find.currentMark;
296
- const query = find.activeQuery;
297
- if (mark === null || query === null || this.blockedByReadOnly()) {
355
+ const match = find.currentMatch;
356
+ if (this.blockedByReadOnly()) {
298
357
  return false;
299
358
  }
300
- try {
301
- const options = { caseSensitive: query.caseSensitive, wholeWord: query.wholeWord, regex: query.regex, from: mark.from, to: mark.to, maxResults: 1 };
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 = mark.from + replacementText(this.model.getText(), match, replacement, false, replaceOptions.preserveCase).length;
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 query = this.view.find.activeQuery;
323
- if (query === null || this.blockedByReadOnly()) {
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
- return this.model.replaceAll(query.text, replacement, {
328
- caseSensitive: query.caseSensitive,
329
- wholeWord: query.wholeWord,
330
- regex: query.regex,
331
- preserveCase: options.preserveCase,
332
- ...this.view.find.scope
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
- let matches;
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
- matches = this.model.find(query.text, { caseSensitive: query.caseSensitive, wholeWord: query.wholeWord, regex: query.regex });
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
- readonly scrollTop: number | null;
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
- setChangeMarks(marks: readonly EditorChangeMark[]): void;
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;