@adecore/editor-react 0.43.0 → 0.44.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.
Files changed (63) hide show
  1. package/dist/PickPopup.js +94 -73
  2. package/dist/completion.d.ts +28 -0
  3. package/dist/completion.js +76 -15
  4. package/dist/editor-language.d.ts +4 -0
  5. package/dist/editor-language.js +6 -0
  6. package/dist/host-types.d.ts +4 -0
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.js +2 -0
  9. package/dist/key-priority.d.ts +1 -0
  10. package/dist/key-priority.js +2 -0
  11. package/dist/live-templates.d.ts +16 -0
  12. package/dist/live-templates.js +289 -0
  13. package/dist/locales/en.json +30 -0
  14. package/dist/locales/nl.json +30 -0
  15. package/dist/markup-context.d.ts +18 -0
  16. package/dist/markup-context.js +122 -5
  17. package/dist/markup.d.ts +3 -0
  18. package/dist/markup.js +16 -4
  19. package/dist/pick.d.ts +1 -0
  20. package/dist/pick.js +11 -1
  21. package/dist/popups.d.ts +1 -0
  22. package/dist/postfix.d.ts +21 -0
  23. package/dist/postfix.js +212 -0
  24. package/dist/project-language.d.ts +2 -0
  25. package/dist/project-language.js +3 -0
  26. package/dist/shortcut-keys.d.ts +5 -0
  27. package/dist/snippet-insert.d.ts +10 -0
  28. package/dist/snippet-insert.js +217 -0
  29. package/dist/snippet.d.ts +7 -1
  30. package/dist/snippet.js +65 -8
  31. package/dist/surround-constructs.d.ts +10 -0
  32. package/dist/surround-constructs.js +100 -0
  33. package/dist/surround.d.ts +18 -0
  34. package/dist/surround.js +399 -0
  35. package/dist/template-builtins.d.ts +3 -0
  36. package/dist/template-builtins.js +46 -0
  37. package/dist/template-context.d.ts +12 -0
  38. package/dist/template-context.js +56 -0
  39. package/dist/templates.d.ts +59 -0
  40. package/dist/templates.js +103 -0
  41. package/package.json +6 -6
  42. package/src/PickPopup.tsx +7 -0
  43. package/src/completion.ts +111 -13
  44. package/src/editor-language.ts +6 -0
  45. package/src/host-types.ts +7 -0
  46. package/src/index.ts +16 -0
  47. package/src/key-priority.ts +2 -0
  48. package/src/live-templates.ts +315 -0
  49. package/src/locales/en.json +30 -0
  50. package/src/locales/nl.json +30 -0
  51. package/src/markup-context.ts +131 -6
  52. package/src/markup.ts +15 -5
  53. package/src/pick.ts +17 -1
  54. package/src/popups.ts +2 -0
  55. package/src/postfix.ts +224 -0
  56. package/src/project-language.ts +3 -0
  57. package/src/snippet-insert.ts +258 -0
  58. package/src/snippet.ts +82 -7
  59. package/src/surround-constructs.ts +85 -0
  60. package/src/surround.ts +430 -0
  61. package/src/template-builtins.ts +94 -0
  62. package/src/template-context.ts +65 -0
  63. package/src/templates.ts +197 -0
package/dist/PickPopup.js CHANGED
@@ -199,7 +199,7 @@ function _temp(line, index) {
199
199
  }, index);
200
200
  }
201
201
  export function PickPopup(t0) {
202
- const $ = _c(34);
202
+ const $ = _c(37);
203
203
  const {
204
204
  language,
205
205
  view,
@@ -279,27 +279,36 @@ export function PickPopup(t0) {
279
279
  t4 = $[10];
280
280
  }
281
281
  const activeId = t4;
282
- useInputPopup(language, listId, activeId);
283
282
  let t5;
284
- if ($[11] === Symbol.for("react.memo_cache_sentinel")) {
285
- t5 = {
286
- visibility: "hidden"
287
- };
288
- $[11] = t5;
283
+ if ($[11] !== view.groups) {
284
+ t5 = view.groups.some(_temp5);
285
+ $[11] = view.groups;
286
+ $[12] = t5;
289
287
  } else {
290
- t5 = $[11];
288
+ t5 = $[12];
291
289
  }
290
+ const mnemonics = t5;
291
+ useInputPopup(language, listId, activeId);
292
292
  let t6;
293
- if ($[12] !== language) {
294
- t6 = keepFocusOutOfList(() => language.editor.focus());
295
- $[12] = language;
293
+ if ($[13] === Symbol.for("react.memo_cache_sentinel")) {
294
+ t6 = {
295
+ visibility: "hidden"
296
+ };
296
297
  $[13] = t6;
297
298
  } else {
298
299
  t6 = $[13];
299
300
  }
300
301
  let t7;
301
- if ($[14] !== view.query || $[15] !== view.title) {
302
- t7 = (view.title !== null || view.query !== null) && /*#__PURE__*/_jsxs("div", {
302
+ if ($[14] !== language) {
303
+ t7 = keepFocusOutOfList(() => language.editor.focus());
304
+ $[14] = language;
305
+ $[15] = t7;
306
+ } else {
307
+ t7 = $[15];
308
+ }
309
+ let t8;
310
+ if ($[16] !== view.query || $[17] !== view.title) {
311
+ t8 = (view.title !== null || view.query !== null) && /*#__PURE__*/_jsxs("div", {
303
312
  className: "flex items-baseline gap-2 border-b border-border px-3 py-1.5 text-xs text-text-muted",
304
313
  children: [/*#__PURE__*/_jsx("span", {
305
314
  className: "min-w-0 truncate",
@@ -309,103 +318,115 @@ export function PickPopup(t0) {
309
318
  children: view.query
310
319
  })]
311
320
  });
312
- $[14] = view.query;
313
- $[15] = view.title;
314
- $[16] = t7;
321
+ $[16] = view.query;
322
+ $[17] = view.title;
323
+ $[18] = t8;
315
324
  } else {
316
- t7 = $[16];
325
+ t8 = $[18];
317
326
  }
318
- let t8;
319
- if ($[17] !== language || $[18] !== optionIds || $[19] !== view.active || $[20] !== view.chosen || $[21] !== view.groups || $[22] !== view.query) {
320
- t8 = view.groups.map((group_0, groupIndex) => /*#__PURE__*/_jsxs("div", {
327
+ let t9;
328
+ if ($[19] !== language || $[20] !== mnemonics || $[21] !== optionIds || $[22] !== view.active || $[23] !== view.chosen || $[24] !== view.groups || $[25] !== view.query) {
329
+ t9 = view.groups.map((group_1, groupIndex) => /*#__PURE__*/_jsxs("div", {
321
330
  role: "group",
322
331
  className: "flex flex-col",
323
- children: [group_0.title !== null && /*#__PURE__*/_jsx("div", {
332
+ children: [group_1.title !== null && /*#__PURE__*/_jsx("div", {
324
333
  className: "px-2 pt-1.5 pb-0.5 text-xs font-medium text-text-faint",
325
- children: group_0.title
326
- }), group_0.rows.map(row_0 => /*#__PURE__*/_jsxs("button", {
327
- id: optionIds.get(row_0.id),
328
- ref: row_0.id === view.active ? activeRow : undefined,
334
+ children: group_1.title
335
+ }), group_1.rows.map(row_1 => /*#__PURE__*/_jsxs("button", {
336
+ id: optionIds.get(row_1.id),
337
+ ref: row_1.id === view.active ? activeRow : undefined,
329
338
  type: "button",
330
339
  role: "option",
331
340
  tabIndex: -1,
332
- "aria-selected": row_0.id === view.active || view.chosen.includes(row_0.id),
333
- "data-active": row_0.id === view.active,
334
- "data-chosen": view.chosen.includes(row_0.id),
341
+ "aria-selected": row_1.id === view.active || view.chosen.includes(row_1.id),
342
+ "aria-keyshortcuts": row_1.mnemonic,
343
+ "data-active": row_1.id === view.active,
344
+ "data-chosen": view.chosen.includes(row_1.id),
335
345
  className: "flex h-7 w-full items-center gap-2 rounded-md px-2 text-left text-xs cursor-row data-[chosen=true]:bg-accent/15",
336
- onClick: event_0 => language.pick.choose(row_0.id, {
346
+ onClick: event_0 => language.pick.choose(row_1.id, {
337
347
  toggle: event_0.metaKey || event_0.ctrlKey,
338
348
  range: event_0.shiftKey
339
349
  }),
340
- children: [/*#__PURE__*/_jsx("span", {
341
- className: row_0.path ? "shrink-0" : "min-w-0 truncate",
350
+ children: [mnemonics && /*#__PURE__*/_jsx("span", {
351
+ "aria-hidden": "true",
352
+ className: "w-3 shrink-0 text-center font-mono text-text-faint",
353
+ children: row_1.mnemonic
354
+ }), /*#__PURE__*/_jsx("span", {
355
+ className: row_1.path ? "shrink-0" : "min-w-0 truncate",
342
356
  children: /*#__PURE__*/_jsx(MatchedLabel, {
343
- label: row_0.label,
357
+ label: row_1.label,
344
358
  query: view.query
345
359
  })
346
- }), row_0.path ? /*#__PURE__*/_jsx(PathText, {
347
- path: row_0.detail,
360
+ }), row_1.path ? /*#__PURE__*/_jsx(PathText, {
361
+ path: row_1.detail,
348
362
  className: "ml-auto font-mono text-text-faint"
349
363
  }) : /*#__PURE__*/_jsx("span", {
350
364
  className: "ml-auto shrink-0 font-mono text-text-faint",
351
- children: row_0.id === view.active && row_0.detail === "" ? "\u21B5" : row_0.detail
365
+ children: row_1.id === view.active && row_1.detail === "" ? "\u21B5" : row_1.detail
352
366
  })]
353
- }, row_0.id))]
354
- }, group_0.title ?? groupIndex));
355
- $[17] = language;
356
- $[18] = optionIds;
357
- $[19] = view.active;
358
- $[20] = view.chosen;
359
- $[21] = view.groups;
360
- $[22] = view.query;
361
- $[23] = t8;
367
+ }, row_1.id))]
368
+ }, group_1.title ?? groupIndex));
369
+ $[19] = language;
370
+ $[20] = mnemonics;
371
+ $[21] = optionIds;
372
+ $[22] = view.active;
373
+ $[23] = view.chosen;
374
+ $[24] = view.groups;
375
+ $[25] = view.query;
376
+ $[26] = t9;
362
377
  } else {
363
- t8 = $[23];
378
+ t9 = $[26];
364
379
  }
365
- let t9;
366
- if ($[24] !== listId || $[25] !== t8) {
367
- t9 = /*#__PURE__*/_jsx("div", {
380
+ let t10;
381
+ if ($[27] !== listId || $[28] !== t9) {
382
+ t10 = /*#__PURE__*/_jsx("div", {
368
383
  id: listId,
369
384
  role: "listbox",
370
385
  className: "min-h-0 flex-1 overflow-y-auto p-1",
371
- children: t8
386
+ children: t9
372
387
  });
373
- $[24] = listId;
374
- $[25] = t8;
375
- $[26] = t9;
388
+ $[27] = listId;
389
+ $[28] = t9;
390
+ $[29] = t10;
376
391
  } else {
377
- t9 = $[26];
392
+ t10 = $[29];
378
393
  }
379
- let t10;
380
- if ($[27] !== view.preview) {
381
- t10 = view.preview !== null && /*#__PURE__*/_jsx(PreviewLines, {
394
+ let t11;
395
+ if ($[30] !== view.preview) {
396
+ t11 = view.preview !== null && /*#__PURE__*/_jsx(PreviewLines, {
382
397
  preview: view.preview
383
398
  });
384
- $[27] = view.preview;
385
- $[28] = t10;
399
+ $[30] = view.preview;
400
+ $[31] = t11;
386
401
  } else {
387
- t10 = $[28];
402
+ t11 = $[31];
388
403
  }
389
- let t11;
390
- if ($[29] !== t10 || $[30] !== t6 || $[31] !== t7 || $[32] !== t9) {
391
- t11 = createPortal(/*#__PURE__*/_jsxs("div", {
404
+ let t12;
405
+ if ($[32] !== t10 || $[33] !== t11 || $[34] !== t7 || $[35] !== t8) {
406
+ t12 = createPortal(/*#__PURE__*/_jsxs("div", {
392
407
  ref: card,
393
408
  className: CARD,
394
- style: t5,
395
- onPointerDown: _temp4,
396
- ...t6,
397
- children: [t7, t9, t10]
409
+ style: t6,
410
+ onPointerDown: _temp6,
411
+ ...t7,
412
+ children: [t8, t10, t11]
398
413
  }), document.body);
399
- $[29] = t10;
400
- $[30] = t6;
401
- $[31] = t7;
402
- $[32] = t9;
414
+ $[32] = t10;
403
415
  $[33] = t11;
416
+ $[34] = t7;
417
+ $[35] = t8;
418
+ $[36] = t12;
404
419
  } else {
405
- t11 = $[33];
420
+ t12 = $[36];
406
421
  }
407
- return t11;
422
+ return t12;
408
423
  }
409
- function _temp4(event) {
424
+ function _temp6(event) {
410
425
  return event.preventDefault();
426
+ }
427
+ function _temp5(group_0) {
428
+ return group_0.rows.some(_temp4);
429
+ }
430
+ function _temp4(row_0) {
431
+ return row_0.mnemonic !== undefined;
411
432
  }
@@ -1,5 +1,26 @@
1
+ import { type CompletionItem } from '@adecore/lsp';
2
+ import type { EditorPosition } from '@adecore/editor';
1
3
  import type { EditorLanguage } from './editor-language.ts';
2
4
  import { type Timers } from './timers.ts';
5
+ /** A row a source of the editor offers beside the language server's. */
6
+ export interface LocalCompletionItem {
7
+ /** The label, kind, detail, documentation, filter text and sort text of the row; its edit range is the typed prefix on the caret's line, ending at the caret. */
8
+ readonly item: CompletionItem;
9
+ /** Runs instead of the insertion: the source inserts the row itself. */
10
+ accept(): void;
11
+ }
12
+ /** What a source is asked for when the list is requested. */
13
+ export interface CompletionRequest {
14
+ readonly position: EditorPosition;
15
+ /** Whether the person asked for the list with the keyboard. */
16
+ readonly explicit: boolean;
17
+ readonly triggerCharacter?: string;
18
+ }
19
+ /** Rows that come from the editor itself, such as templates, merged into the list of the language server. */
20
+ export interface CompletionSource {
21
+ /** Synchronous and cheap; asked on every request of the list. */
22
+ items(request: CompletionRequest): readonly LocalCompletionItem[];
23
+ }
3
24
  export declare class CompletionFeature {
4
25
  private readonly language;
5
26
  private readonly timers;
@@ -24,9 +45,16 @@ export declare class CompletionFeature {
24
45
  private acceptSequence;
25
46
  private disposed;
26
47
  private readonly resolved;
48
+ private readonly sources;
49
+ private locals;
50
+ private shown;
27
51
  constructor(language: EditorLanguage, timers?: Timers);
28
52
  get isOpen(): boolean;
29
53
  invoke(): void;
54
+ /** Adds rows to every list, also in a document without a language server. Returns the function that takes the source away again. */
55
+ addSource(source: CompletionSource): () => void;
56
+ /** Opens the list with only these rows, the typed prefix starting at `start`, as Insert Live Template does. */
57
+ showItems(items: readonly LocalCompletionItem[], start: EditorPosition): void;
30
58
  move(delta: number): void;
31
59
  accept(replace: boolean, index?: number, commit?: string): Promise<void>;
32
60
  private insert;
@@ -101,6 +101,11 @@ export class CompletionFeature {
101
101
  acceptSequence = 0;
102
102
  disposed = false;
103
103
  resolved = new Map();
104
+ sources = new Set();
105
+ /* The rows of the list that a source inserts itself. */
106
+ locals = new Map();
107
+ /* Whether the list holds the rows `showItems` gave it and no request refreshes it. */
108
+ shown = false;
104
109
  constructor(language, timers = realTimers) {
105
110
  this.language = language;
106
111
  this.timers = timers;
@@ -132,6 +137,27 @@ export class CompletionFeature {
132
137
  triggerKind: 1
133
138
  }, 0);
134
139
  }
140
+ /** Adds rows to every list, also in a document without a language server. Returns the function that takes the source away again. */
141
+ addSource(source) {
142
+ this.sources.add(source);
143
+ return () => {
144
+ this.sources.delete(source);
145
+ };
146
+ }
147
+ /** Opens the list with only these rows, the typed prefix starting at `start`, as Insert Live Template does. */
148
+ showItems(items, start) {
149
+ this.language.pick.close();
150
+ this.close();
151
+ this.shown = true;
152
+ this.locals = new Map(items.map(local => [local.item, local]));
153
+ this.pool = items.map(local => local.item);
154
+ this.incomplete = false;
155
+ this.start = start;
156
+ this.active = 0;
157
+ this.touched = false;
158
+ this.server = '';
159
+ this.refilter();
160
+ }
135
161
  move(delta) {
136
162
  if (this.ranked.length === 0) {
137
163
  return;
@@ -165,6 +191,13 @@ export class CompletionFeature {
165
191
  if (entry === undefined) {
166
192
  return;
167
193
  }
194
+ const local = this.locals.get(entry.item);
195
+ if (local !== undefined) {
196
+ recentChoicesOf(this.language.languageId).record(entry.item);
197
+ this.close();
198
+ local.accept();
199
+ return;
200
+ }
168
201
  const {
169
202
  editor,
170
203
  project,
@@ -562,6 +595,8 @@ export class CompletionFeature {
562
595
  this.activeKey = null;
563
596
  this.start = null;
564
597
  this.resolved.clear();
598
+ this.locals = new Map();
599
+ this.shown = false;
565
600
  if (this.language.popups.getState().completion !== null) {
566
601
  this.language.popups.setState({
567
602
  completion: null
@@ -621,6 +656,15 @@ export class CompletionFeature {
621
656
  }
622
657
  edited(change) {
623
658
  this.textRevision++;
659
+ // The rows were given, so typing only filters them.
660
+ if (this.shown && this.isOpen) {
661
+ if (change.source === 'input' && change.changes.length === 1 && Array.from(change.changes[0].text).every(isIdentifierCharacter)) {
662
+ this.refilter();
663
+ } else {
664
+ this.close();
665
+ }
666
+ return;
667
+ }
624
668
  if (change.source !== 'input' || change.changes.length !== 1) {
625
669
  this.close();
626
670
  return;
@@ -678,7 +722,7 @@ export class CompletionFeature {
678
722
  const {
679
723
  uri
680
724
  } = this.language;
681
- if (!this.language.service.supports(METHOD, uri)) {
725
+ if (!this.language.service.supports(METHOD, uri) && this.sources.size === 0) {
682
726
  return;
683
727
  }
684
728
  this.timers.clear(this.requestTimer);
@@ -695,26 +739,43 @@ export class CompletionFeature {
695
739
  this.controller?.abort();
696
740
  const controller = new AbortController();
697
741
  this.controller = controller;
698
- let normalized;
699
- try {
700
- const result = await this.language.service.completion(uri, position, context, {
701
- signal: controller.signal
702
- });
703
- if (request !== this.request || this.controller !== controller || controller.signal.aborted) {
704
- return;
705
- }
706
- normalized = itemsOf(result);
707
- } catch {
708
- if (request === this.request && this.controller === controller && !controller.signal.aborted) {
709
- this.close();
742
+ let normalized = {
743
+ items: [],
744
+ incomplete: false
745
+ };
746
+ let failed = false;
747
+ if (this.language.service.supports(METHOD, uri)) {
748
+ try {
749
+ const result = await this.language.service.completion(uri, position, context, {
750
+ signal: controller.signal
751
+ });
752
+ if (request !== this.request || this.controller !== controller || controller.signal.aborted) {
753
+ return;
754
+ }
755
+ normalized = itemsOf(result);
756
+ } catch {
757
+ if (request !== this.request || this.controller !== controller || controller.signal.aborted) {
758
+ return;
759
+ }
760
+ failed = true;
710
761
  }
762
+ }
763
+ const locals = [...this.sources].flatMap(source => source.items({
764
+ position,
765
+ explicit: this.explicit && !refresh,
766
+ triggerCharacter: context.triggerCharacter
767
+ }));
768
+ // A failed request still leaves the rows of the sources.
769
+ if (failed && locals.length === 0) {
770
+ this.close();
711
771
  return;
712
772
  }
713
773
  const {
714
774
  items,
715
775
  incomplete
716
776
  } = normalized;
717
- this.pool = items;
777
+ this.pool = [...items, ...locals.map(local => local.item)];
778
+ this.locals = new Map(locals.map(local => [local.item, local]));
718
779
  this.incomplete = incomplete;
719
780
  this.resolved.clear();
720
781
  this.server = project.host.serverNames?.(uri)[0] ?? '';
@@ -806,7 +867,7 @@ export class CompletionFeature {
806
867
  this.timers.clear(this.resolveTimer);
807
868
  this.resolving?.abort();
808
869
  const entry = this.ranked[this.active];
809
- if (entry === undefined || this.resolved.has(entry.item) || this.language.service.providerOptions('completionItem/resolve', uri) === undefined) {
870
+ if (entry === undefined || this.locals.has(entry.item) || this.resolved.has(entry.item) || this.language.service.providerOptions('completionItem/resolve', uri) === undefined) {
810
871
  return;
811
872
  }
812
873
  const request = this.request;
@@ -30,7 +30,9 @@ import { InlayHintsFeature } from './inlay-hints.ts';
30
30
  import { type SemanticTokensOptions } from './semantic-tokens.ts';
31
31
  import { SignatureFeature } from './signature.ts';
32
32
  import { SnippetFeature } from './snippet-session.ts';
33
+ import { SurroundFeature } from './surround.ts';
33
34
  import { SymbolsFeature } from './symbols.ts';
35
+ import { TemplatesFeature } from './live-templates.ts';
34
36
  import type { Place } from './navigation-history.ts';
35
37
  import type { LanguageDocumentHandle, ProjectLanguage } from './project-language.ts';
36
38
  export interface EditorLanguageOptions {
@@ -54,6 +56,8 @@ export declare class EditorLanguage {
54
56
  readonly signature: SignatureFeature;
55
57
  readonly snippets: SnippetFeature;
56
58
  readonly markup: MarkupFeature;
59
+ readonly templates: TemplatesFeature;
60
+ readonly surround: SurroundFeature;
57
61
  readonly highlights: HighlightsFeature;
58
62
  readonly pick: PickFeature;
59
63
  readonly codeActions: CodeActionsFeature;
@@ -32,7 +32,9 @@ import { SelectionRangesFeature } from './selection-ranges.js';
32
32
  import { SemanticTokensFeature } from './semantic-tokens.js';
33
33
  import { SignatureFeature } from './signature.js';
34
34
  import { SnippetFeature } from './snippet-session.js';
35
+ import { SurroundFeature } from './surround.js';
35
36
  import { SymbolsFeature } from './symbols.js';
37
+ import { TemplatesFeature } from './live-templates.js';
36
38
  /* How long the edits servers want before a save are waited for. */
37
39
  const SAVE_PARTICIPANT_MS = 1_000;
38
40
  /*
@@ -58,6 +60,8 @@ export class EditorLanguage {
58
60
  signature;
59
61
  snippets;
60
62
  markup;
63
+ templates;
64
+ surround;
61
65
  highlights;
62
66
  pick;
63
67
  codeActions;
@@ -101,6 +105,8 @@ export class EditorLanguage {
101
105
  this.completion = new CompletionFeature(this, timers);
102
106
  this.snippets = new SnippetFeature(this, timers);
103
107
  this.markup = new MarkupFeature(this);
108
+ this.templates = new TemplatesFeature(this);
109
+ this.surround = new SurroundFeature(this);
104
110
  this.signature = new SignatureFeature(this, timers);
105
111
  this.highlights = new HighlightsFeature(this, timers);
106
112
  this.symbols = new SymbolsFeature(this, timers);
@@ -6,6 +6,7 @@ import type { ClipboardHistory } from './clipboard-history.ts';
6
6
  import type { ProjectFiles } from './workspace-edit.ts';
7
7
  import type { Place } from './navigation-history.ts';
8
8
  import type { ProblemSource } from './project-problems.ts';
9
+ import type { LiveTemplateDraft, TemplateRegistry } from './templates.ts';
9
10
  import type { ServerMessage } from '@adecore/lsp';
10
11
  export interface DiskText {
11
12
  text: string;
@@ -58,6 +59,9 @@ export interface LanguageHost {
58
59
  readonly apple?: boolean;
59
60
  readonly keymap?: Keymap;
60
61
  readonly clipboard?: ClipboardHistory;
62
+ readonly templates?: TemplateRegistry;
63
+ saveAsLiveTemplate?(draft: LiveTemplateDraft): void;
64
+ openTemplateSettings?(): void;
61
65
  readonly editHistoryLimit?: number;
62
66
  readonly panelBodyHeight?: number;
63
67
  onPanelResize?(height: number): void;
package/dist/index.d.ts CHANGED
@@ -34,6 +34,7 @@ export type { BlameSource, CodeVisionSettings } from './code-vision.ts';
34
34
  export type { HoverSettings } from './hover.ts';
35
35
  export type { PopupState, PopupStore, HoverInfo, HoverView, CompletionView, CompletionDocs, CompletionRow, SignatureView, RenameView, RenameFileView, PeekView, CallHierarchyView, PickView, PickGroup, PickRow, PickPreview, SymbolsView, MenuView, AuthorsView, WrapView } from './popups.ts';
36
36
  export { type MarkupFeature } from './markup.ts';
37
+ export { type SurroundFeature } from './surround.ts';
37
38
  export type { MarkupSettings } from './markup.ts';
38
39
  export { RowHost, LineActionHost } from './row-host.ts';
39
40
  export type { HostedRow, HostedAction } from './row-host.ts';
@@ -43,6 +44,7 @@ export type { Place } from './navigation-history.ts';
43
44
  export { EditLocations, type EditPlace } from './edit-locations.ts';
44
45
  export { ClipboardHistory, type ClipboardEntry, type ClipboardHistoryOptions } from './clipboard-history.ts';
45
46
  export { type PasteHistoryFeature } from './paste-history.ts';
47
+ export { TemplateRegistry, checkTemplate, BUILT_IN_LIVE_TEMPLATES, BUILT_IN_POSTFIX_TEMPLATES, type TemplatesFeature, type LiveTemplate, type PostfixTemplate, type LiveTemplateDraft, type TemplateLanguage, type TemplatePlace, type TemplateSettings, type TemplateRegistryOptions, type TemplateUpdate } from './templates.ts';
46
48
  export { openingPlace, viewStates, followViewStates, viewStateKey, forgetMovesFrom } from './view-state.ts';
47
49
  export type { ViewState, RevealLineRequest } from './view-state.ts';
48
50
  export { lspLanguageIdOf, shikiLanguageOf, shikiLanguageOfPath } from './language-ids.ts';
package/dist/index.js CHANGED
@@ -20,12 +20,14 @@ export { ProjectProblems, serviceProblems, countsOf } from './project-problems.j
20
20
  export { applyWorkspaceEdit, supportedResourceOperations } from './workspace-edit.js';
21
21
  export { useProblemCounts } from './use-problem-counts.js';
22
22
  export {} from './markup.js';
23
+ export {} from './surround.js';
23
24
  export { RowHost, LineActionHost } from './row-host.js';
24
25
  export { highlightLayers } from './highlight-layers.js';
25
26
  export {} from './navigation-history.js';
26
27
  export { EditLocations } from './edit-locations.js';
27
28
  export { ClipboardHistory } from './clipboard-history.js';
28
29
  export {} from './paste-history.js';
30
+ export { TemplateRegistry, checkTemplate, BUILT_IN_LIVE_TEMPLATES, BUILT_IN_POSTFIX_TEMPLATES } from './templates.js';
29
31
  export { openingPlace, viewStates, followViewStates, viewStateKey, forgetMovesFrom } from './view-state.js';
30
32
  export { lspLanguageIdOf, shikiLanguageOf, shikiLanguageOfPath } from './language-ids.js';
31
33
  export { AttributionCard } from "./AttributionCard.js";
@@ -5,6 +5,7 @@ export declare const KEY_PRIORITY: {
5
5
  readonly hover: 1400;
6
6
  readonly completion: 1300;
7
7
  readonly snippets: 1200;
8
+ readonly templates: 1150;
8
9
  readonly markup: 1100;
9
10
  readonly signature: 1000;
10
11
  readonly highlights: 900;
@@ -8,6 +8,8 @@ export const KEY_PRIORITY = {
8
8
  hover: 1400,
9
9
  completion: 1300,
10
10
  snippets: 1200,
11
+ // Between snippets and markup, so the spacing of a hundred bends here: Tab has to reach the templates after a running snippet and before Emmet.
12
+ templates: 1150,
11
13
  markup: 1100,
12
14
  signature: 1000,
13
15
  highlights: 900,
@@ -0,0 +1,16 @@
1
+ import type { EditorLanguage } from './editor-language.ts';
2
+ export declare class TemplatesFeature {
3
+ private readonly language;
4
+ private readonly postfix;
5
+ constructor(language: EditorLanguage);
6
+ expand(): boolean;
7
+ insert(): void;
8
+ saveSelection(): boolean;
9
+ private customKey;
10
+ private matchAtCarets;
11
+ private matchAt;
12
+ private expandAtCarets;
13
+ private run;
14
+ private rows;
15
+ private row;
16
+ }