@adecore/editor-react 0.42.0 → 0.44.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 (150) hide show
  1. package/dist/CallHierarchyPanel.js +177 -181
  2. package/dist/EditorContextMenu.js +118 -105
  3. package/dist/LanguagePopups.js +7 -0
  4. package/dist/PickPopup.js +245 -104
  5. package/dist/WrapCard.d.ts +8 -0
  6. package/dist/WrapCard.js +172 -0
  7. package/dist/call-hierarchy-model.d.ts +4 -2
  8. package/dist/call-hierarchy-model.js +20 -0
  9. package/dist/call-hierarchy.d.ts +3 -0
  10. package/dist/call-hierarchy.js +54 -22
  11. package/dist/clipboard-history.d.ts +31 -0
  12. package/dist/clipboard-history.js +70 -0
  13. package/dist/code-actions.d.ts +3 -1
  14. package/dist/code-actions.js +50 -10
  15. package/dist/code-vision.js +2 -3
  16. package/dist/completion.d.ts +28 -0
  17. package/dist/completion.js +83 -27
  18. package/dist/context-menu-rows.d.ts +1 -1
  19. package/dist/context-menu-rows.js +4 -0
  20. package/dist/definition-link.js +15 -5
  21. package/dist/document-colors.d.ts +24 -0
  22. package/dist/document-colors.js +194 -0
  23. package/dist/document-links.d.ts +22 -0
  24. package/dist/document-links.js +133 -0
  25. package/dist/document-query.d.ts +15 -0
  26. package/dist/document-query.js +54 -0
  27. package/dist/edit-locations.d.ts +20 -0
  28. package/dist/edit-locations.js +136 -0
  29. package/dist/editor-language.d.ts +23 -1
  30. package/dist/editor-language.js +83 -2
  31. package/dist/emmet.d.ts +13 -0
  32. package/dist/emmet.js +62 -0
  33. package/dist/folding.js +2 -3
  34. package/dist/format-on-type.js +3 -5
  35. package/dist/highlights.js +2 -3
  36. package/dist/history.d.ts +7 -0
  37. package/dist/history.js +79 -1
  38. package/dist/host-types.d.ts +10 -0
  39. package/dist/index.d.ts +13 -2
  40. package/dist/index.js +10 -0
  41. package/dist/inlay-hints.js +2 -2
  42. package/dist/inline-completion.d.ts +39 -0
  43. package/dist/inline-completion.js +221 -0
  44. package/dist/key-priority.d.ts +9 -5
  45. package/dist/key-priority.js +11 -6
  46. package/dist/linked-editing.d.ts +26 -0
  47. package/dist/linked-editing.js +215 -0
  48. package/dist/live-templates.d.ts +16 -0
  49. package/dist/live-templates.js +289 -0
  50. package/dist/locales/en.json +61 -2
  51. package/dist/locales/nl.json +61 -2
  52. package/dist/markup-context.d.ts +55 -0
  53. package/dist/markup-context.js +408 -0
  54. package/dist/markup.d.ts +39 -0
  55. package/dist/markup.js +465 -0
  56. package/dist/navigation.js +4 -6
  57. package/dist/paste-history.d.ts +7 -0
  58. package/dist/paste-history.js +104 -0
  59. package/dist/peek.js +3 -4
  60. package/dist/pick.d.ts +21 -2
  61. package/dist/pick.js +152 -19
  62. package/dist/popups.d.ts +10 -0
  63. package/dist/popups.js +2 -1
  64. package/dist/postfix.d.ts +21 -0
  65. package/dist/postfix.js +212 -0
  66. package/dist/project-language.d.ts +20 -1
  67. package/dist/project-language.js +132 -18
  68. package/dist/rename.js +8 -11
  69. package/dist/rendered-docs.js +1 -2
  70. package/dist/selection-ranges.js +2 -3
  71. package/dist/shortcut-keys.d.ts +24 -0
  72. package/dist/signature.js +3 -6
  73. package/dist/snippet-insert.d.ts +10 -0
  74. package/dist/snippet-insert.js +217 -0
  75. package/dist/snippet-session.d.ts +2 -2
  76. package/dist/snippet-session.js +3 -3
  77. package/dist/snippet.d.ts +7 -1
  78. package/dist/snippet.js +65 -8
  79. package/dist/surround-constructs.d.ts +10 -0
  80. package/dist/surround-constructs.js +100 -0
  81. package/dist/surround.d.ts +18 -0
  82. package/dist/surround.js +399 -0
  83. package/dist/symbol-picker.js +4 -6
  84. package/dist/symbols.js +22 -3
  85. package/dist/template-builtins.d.ts +3 -0
  86. package/dist/template-builtins.js +46 -0
  87. package/dist/template-context.d.ts +12 -0
  88. package/dist/template-context.js +56 -0
  89. package/dist/templates.d.ts +59 -0
  90. package/dist/templates.js +103 -0
  91. package/dist/testing.d.ts +23 -1
  92. package/dist/testing.js +114 -0
  93. package/package.json +7 -6
  94. package/src/CallHierarchyPanel.tsx +26 -11
  95. package/src/EditorContextMenu.tsx +7 -0
  96. package/src/LanguagePopups.tsx +4 -0
  97. package/src/PickPopup.tsx +47 -5
  98. package/src/WrapCard.tsx +64 -0
  99. package/src/call-hierarchy-model.ts +25 -3
  100. package/src/call-hierarchy.ts +62 -20
  101. package/src/clipboard-history.ts +102 -0
  102. package/src/code-actions.ts +48 -11
  103. package/src/code-vision.ts +3 -3
  104. package/src/completion.ts +123 -25
  105. package/src/context-menu-rows.ts +3 -2
  106. package/src/definition-link.ts +17 -5
  107. package/src/document-colors.ts +189 -0
  108. package/src/document-links.ts +129 -0
  109. package/src/document-query.ts +71 -0
  110. package/src/edit-locations.ts +162 -0
  111. package/src/editor-language.ts +86 -3
  112. package/src/emmet-module.d.ts +44 -0
  113. package/src/emmet.ts +73 -0
  114. package/src/folding.ts +3 -3
  115. package/src/format-on-type.ts +5 -5
  116. package/src/highlights.ts +3 -3
  117. package/src/history.ts +81 -1
  118. package/src/host-types.ts +17 -0
  119. package/src/index.ts +28 -3
  120. package/src/inlay-hints.ts +2 -2
  121. package/src/inline-completion.ts +221 -0
  122. package/src/key-priority.ts +11 -6
  123. package/src/linked-editing.ts +199 -0
  124. package/src/live-templates.ts +315 -0
  125. package/src/locales/en.json +61 -2
  126. package/src/locales/nl.json +61 -2
  127. package/src/markup-context.ts +387 -0
  128. package/src/markup.ts +377 -0
  129. package/src/navigation.ts +6 -6
  130. package/src/paste-history.ts +111 -0
  131. package/src/peek.ts +4 -4
  132. package/src/pick.ts +218 -20
  133. package/src/popups.ts +21 -1
  134. package/src/postfix.ts +224 -0
  135. package/src/project-language.ts +139 -19
  136. package/src/rename.ts +11 -11
  137. package/src/rendered-docs.ts +2 -2
  138. package/src/selection-ranges.ts +3 -3
  139. package/src/signature.ts +6 -6
  140. package/src/snippet-insert.ts +258 -0
  141. package/src/snippet-session.ts +9 -4
  142. package/src/snippet.ts +82 -7
  143. package/src/surround-constructs.ts +85 -0
  144. package/src/surround.ts +430 -0
  145. package/src/symbol-picker.ts +6 -6
  146. package/src/symbols.ts +30 -4
  147. package/src/template-builtins.ts +94 -0
  148. package/src/template-context.ts +65 -0
  149. package/src/templates.ts +197 -0
  150. package/src/testing.ts +126 -1
@@ -1,6 +1,6 @@
1
1
  import { type Timers } from './timers.ts';
2
2
  import { type SnippetTransformJob } from './snippet-transform-protocol.ts';
3
- import type { EditorContentChange, EditorPosition, EditorRange } from '@adecore/editor';
3
+ import type { EditorApplyEditsOptions, EditorContentChange, EditorPosition, EditorRange } from '@adecore/editor';
4
4
  import type { EditorLanguage } from './editor-language.ts';
5
5
  import type { SnippetField, SnippetStop } from './snippet.ts';
6
6
  export declare function positionInInsertion(start: EditorPosition, text: string, offset: number): EditorPosition;
@@ -34,7 +34,7 @@ export declare class SnippetFeature {
34
34
  beginInstances(insertions: readonly SnippetInsertion[], options?: {
35
35
  nested?: boolean;
36
36
  }): void;
37
- applyEdits(changes: readonly EditorContentChange[], token: number, extras?: readonly EditorContentChange[]): boolean;
37
+ applyEdits(changes: readonly EditorContentChange[], token: number, extras?: readonly EditorContentChange[], options?: EditorApplyEditsOptions): boolean;
38
38
  end(): void;
39
39
  private closeChoices;
40
40
  private pop;
@@ -251,17 +251,17 @@ export class SnippetFeature {
251
251
  this.visit(0);
252
252
  }
253
253
  /* Imports can touch a hull's edge; their affinity must differ from edits inside its active field. */
254
- applyEdits(changes, token, extras = []) {
254
+ applyEdits(changes, token, extras = [], options) {
255
255
  const frame = this.frames.at(-1);
256
256
  const fits = frame !== undefined && changes.every(edit => extras.includes(edit) ? frame.instances.every(instance => comparePositions(edit.range.end, instance.hull.start) <= 0 || comparePositions(edit.range.start, instance.hull.end) >= 0) : frame.instances.some(instance => instance.selected.some(range => rangeHolds(range, edit.range.start) && rangeHolds(range, edit.range.end))));
257
257
  if (token !== this.generation || !fits) {
258
258
  this.end();
259
- return this.language.editor.applyEdits(changes);
259
+ return this.language.editor.applyEdits(changes, options);
260
260
  }
261
261
  this.applying = true;
262
262
  this.extras = extras;
263
263
  try {
264
- return this.language.editor.applyEdits(changes);
264
+ return this.language.editor.applyEdits(changes, options);
265
265
  } finally {
266
266
  this.applying = false;
267
267
  this.extras = [];
package/dist/snippet.d.ts CHANGED
@@ -28,11 +28,17 @@ export interface ParsedSnippet {
28
28
  })[];
29
29
  }
30
30
  export type SnippetVariableResolver = (name: string) => string | undefined;
31
+ export interface SnippetRenderOptions {
32
+ readonly indentVariables?: boolean;
33
+ }
31
34
  export interface SnippetTemplate {
32
35
  readonly source: string;
33
- render(resolve?: SnippetVariableResolver, variableTransforms?: readonly string[]): ParsedSnippet;
36
+ render(resolve?: SnippetVariableResolver, variableTransforms?: readonly string[], options?: SnippetRenderOptions): ParsedSnippet;
34
37
  }
35
38
  export declare const MAX_SNIPPET_TEXT = 100000;
36
39
  export declare function compileSnippet(source: string): SnippetTemplate;
37
40
  export declare function parseSnippet(snippet: string, resolve?: SnippetVariableResolver): ParsedSnippet;
38
41
  export declare function tabOrder(parsed: ParsedSnippet): SnippetStop[];
42
+ export declare function snippetVariables(source: string): ReadonlySet<string>;
43
+ export declare function checkSnippet(source: string): string | null;
44
+ export declare function escapeSnippetText(text: string): string;
package/dist/snippet.js CHANGED
@@ -168,6 +168,11 @@ class SnippetParser {
168
168
  return values;
169
169
  }
170
170
  }
171
+ /* The lines of a value after its first, behind the whitespace the last line of `before` starts with; blank lines stay blank. */
172
+ function indentLines(value, before) {
173
+ const prefix = /^[\t ]*/.exec(before.slice(before.lastIndexOf('\n') + 1))[0];
174
+ return prefix === '' ? value : value.replace(/(\r\n|\r|\n)(?=[^\r\n])/g, `$1${prefix}`);
175
+ }
171
176
  function renderSnippet(nodes, variableTransforms) {
172
177
  const definitions = new Map();
173
178
  const collect = nodes => {
@@ -216,7 +221,8 @@ function renderSnippet(nodes, variableTransforms) {
216
221
  const order = occurrence++;
217
222
  if (node.kind === 'text') {
218
223
  const start = text.length;
219
- const value = node.transform === undefined || variableTransforms === undefined ? node.text : variableTransforms[transforms.length];
224
+ const given = node.transform === undefined || variableTransforms === undefined ? node.text : variableTransforms[transforms.length];
225
+ const value = node.indent === true && typeof given === 'string' ? indentLines(given, text) : given;
220
226
  if (typeof value !== 'string') {
221
227
  throw new RangeError('The variable transform count does not match the snippet.');
222
228
  }
@@ -352,7 +358,7 @@ function variableIndices(nodes) {
352
358
  return [name, highest];
353
359
  }));
354
360
  }
355
- function resolveVariables(nodes, indices, resolve) {
361
+ function resolveVariables(nodes, indices, resolve, indentVariables = false) {
356
362
  const unknown = new Map();
357
363
  const values = new Map();
358
364
  const valueOf = name => {
@@ -408,10 +414,16 @@ function resolveVariables(nodes, indices, resolve) {
408
414
  transform: node.transform
409
415
  }];
410
416
  }
411
- return value !== undefined && value !== '' ? [{
412
- kind: 'text',
413
- text: value
414
- }] : normalize(node.body ?? [], visiting, depth + 1);
417
+ if (value !== undefined && value !== '') {
418
+ return [{
419
+ kind: 'text',
420
+ text: value,
421
+ ...(indentVariables ? {
422
+ indent: true
423
+ } : {})
424
+ }];
425
+ }
426
+ return normalize(node.body ?? [], visiting, depth + 1);
415
427
  }
416
428
  if (node.kind === 'field') {
417
429
  return [{
@@ -464,7 +476,7 @@ export function compileSnippet(source) {
464
476
  }
465
477
  return {
466
478
  source,
467
- render: (resolve, variableTransforms) => {
479
+ render: (resolve, variableTransforms, options) => {
468
480
  if (nodes === null) {
469
481
  return {
470
482
  text: source,
@@ -473,7 +485,7 @@ export function compileSnippet(source) {
473
485
  };
474
486
  }
475
487
  try {
476
- return renderSnippet(resolveVariables(nodes, indices, resolve), variableTransforms);
488
+ return renderSnippet(resolveVariables(nodes, indices, resolve, options?.indentVariables === true), variableTransforms);
477
489
  } catch (error) {
478
490
  if (!(error instanceof SnippetLimitError)) {
479
491
  throw error;
@@ -518,4 +530,49 @@ export function tabOrder(parsed) {
518
530
  start: parsed.text.length,
519
531
  end: parsed.text.length
520
532
  }];
533
+ }
534
+ /* The names of the variables a snippet uses, the editable ones that are no built-in too. A source that does not parse names none. */
535
+ export function snippetVariables(source) {
536
+ const names = new Set();
537
+ const scan = nodes => {
538
+ for (const node of nodes) {
539
+ if (node.kind === 'variable') {
540
+ names.add(node.name);
541
+ }
542
+ if (node.kind !== 'text' && node.body !== undefined) {
543
+ scan(node.body);
544
+ }
545
+ }
546
+ };
547
+ if (source.length > MAX_SNIPPET_TEXT) {
548
+ return names;
549
+ }
550
+ try {
551
+ scan(new SnippetParser(source).parse());
552
+ } catch {
553
+ return new Set();
554
+ }
555
+ return names;
556
+ }
557
+ /* Why a snippet cannot be used, in English for a host to show, or null: it does not parse, or it is over the limits an insertion keeps. */
558
+ export function checkSnippet(source) {
559
+ if (source.length > MAX_SNIPPET_TEXT) {
560
+ return `The text is longer than ${MAX_SNIPPET_TEXT} characters.`;
561
+ }
562
+ try {
563
+ new SnippetParser(source).parse();
564
+ } catch (error) {
565
+ if (error instanceof MalformedSnippetError) {
566
+ return 'A transform in the text is not valid.';
567
+ }
568
+ if (error instanceof SnippetLimitError) {
569
+ return 'The text has too many parts or is nested too deeply.';
570
+ }
571
+ throw error;
572
+ }
573
+ return compileSnippet(source).render().limited === true ? 'The text expands to more than a snippet can hold.' : null;
574
+ }
575
+ /* Escapes `\`, `$` and `}`, so the text reads back as itself in a snippet. */
576
+ export function escapeSnippetText(text) {
577
+ return text.replace(/[\\$}]/g, '\\$&');
521
578
  }
@@ -0,0 +1,10 @@
1
+ import type { CommentSyntax } from '@adecore/editor';
2
+ import type { TemplateLanguage } from './templates.ts';
3
+ export interface Construct {
4
+ readonly id: string;
5
+ readonly label: string;
6
+ readonly body: string;
7
+ }
8
+ export declare function statementConstructs(families: readonly TemplateLanguage[]): readonly Construct[];
9
+ export declare function expressionConstructs(families: readonly TemplateLanguage[]): readonly Construct[];
10
+ export declare function regionConstructs(syntax: CommentSyntax): readonly Construct[];
@@ -0,0 +1,100 @@
1
+ import { escapeSnippetText } from './snippet.js';
2
+ const SELECTED = '$TM_SELECTED_TEXT';
3
+ function block(head, tail = '') {
4
+ return `${head} {\n\t${SELECTED}\n}${tail}`;
5
+ }
6
+ const JS_STATEMENTS = [{
7
+ id: 'if',
8
+ label: 'if',
9
+ body: block('if ($1)')
10
+ }, {
11
+ id: 'ifElse',
12
+ label: 'if / else',
13
+ body: block('if ($1)', ' else {\n\t$2\n}')
14
+ }, {
15
+ id: 'while',
16
+ label: 'while',
17
+ body: block('while ($1)')
18
+ }, {
19
+ id: 'doWhile',
20
+ label: 'do / while',
21
+ body: `do {\n\t${SELECTED}\n} while ($1);`
22
+ }, {
23
+ id: 'for',
24
+ label: 'for',
25
+ body: block('for (let ${1:i} = 0; $1 < $2; $1++)')
26
+ }, {
27
+ id: 'tryCatch',
28
+ label: 'try / catch',
29
+ body: block('try', ' catch (${1:e}) {\n\t$0\n}')
30
+ }, {
31
+ id: 'tryFinally',
32
+ label: 'try / finally',
33
+ body: block('try', ' finally {\n\t$0\n}')
34
+ }, {
35
+ id: 'tryCatchFinally',
36
+ label: 'try / catch / finally',
37
+ body: block('try', ' catch (${1:e}) {\n\t$2\n} finally {\n\t$0\n}')
38
+ }, {
39
+ id: 'braces',
40
+ label: '{ }',
41
+ body: `{\n\t${SELECTED}\n}`
42
+ }, {
43
+ id: 'function',
44
+ label: 'function',
45
+ body: block('function ${1:name}()')
46
+ }];
47
+ const PHP_STATEMENTS = [JS_STATEMENTS[0], JS_STATEMENTS[1], JS_STATEMENTS[2], JS_STATEMENTS[3], {
48
+ id: 'for',
49
+ label: 'for',
50
+ body: block('for (\\$${1:i} = 0; \\$$1 < $2; \\$$1++)')
51
+ }, {
52
+ id: 'foreach',
53
+ label: 'foreach',
54
+ body: block('foreach (\\$${1:array} as \\$${2:value})')
55
+ }, {
56
+ id: 'tryCatch',
57
+ label: 'try / catch',
58
+ body: block('try', ' catch (${1:\\\\Exception} \\$${2:e}) {\n\t$0\n}')
59
+ }, JS_STATEMENTS[6], JS_STATEMENTS[7], JS_STATEMENTS[9]];
60
+ const EXPRESSIONS = [{
61
+ id: 'parentheses',
62
+ label: '(expr)',
63
+ body: `(${SELECTED})`
64
+ }, {
65
+ id: 'not',
66
+ label: '!(expr)',
67
+ body: `!(${SELECTED})`
68
+ }];
69
+ /* The statement surrounders of the first of the families that has any; JavaScript and TypeScript share theirs. */
70
+ export function statementConstructs(families) {
71
+ if (families.includes('javascript')) {
72
+ return JS_STATEMENTS;
73
+ }
74
+ return families.includes('php') ? PHP_STATEMENTS : [];
75
+ }
76
+ /* The surrounders of one expression, which JavaScript, TypeScript and PHP share. */
77
+ export function expressionConstructs(families) {
78
+ return families.includes('javascript') || families.includes('php') ? EXPRESSIONS : [];
79
+ }
80
+ /*
81
+ * The two comment pairs that fold a region, written with the language's own comments: the line comment, or the block
82
+ * pair where there is none. There is no space after the marker, so the output reads `//region Description`.
83
+ */
84
+ export function regionConstructs(syntax) {
85
+ const marker = syntax.line ?? syntax.block?.open;
86
+ if (marker === undefined) {
87
+ return [];
88
+ }
89
+ const start = escapeSnippetText(marker);
90
+ const end = syntax.line === null ? escapeSnippetText(syntax.block?.close ?? '') : '';
91
+ return [{
92
+ id: 'region',
93
+ label: 'region...endregion',
94
+ body: `${start}region \${1:Description}${end}\n${SELECTED}\n${start}endregion${end}`
95
+ }, {
96
+ id: 'editorFold',
97
+ label: '<editor-fold...>',
98
+ body: `${start}<editor-fold desc="\${1:Description}">${end}\n${SELECTED}\n${start}</editor-fold>${end}`
99
+ }];
100
+ }
@@ -0,0 +1,18 @@
1
+ import type { EditorLanguage } from './editor-language.ts';
2
+ export declare class SurroundFeature {
3
+ private readonly language;
4
+ constructor(language: EditorLanguage);
5
+ open(): boolean;
6
+ openTemplates(): boolean;
7
+ unwrap(): boolean;
8
+ private show;
9
+ private refuse;
10
+ private subjectOf;
11
+ private groupsOf;
12
+ private insert;
13
+ private indentUnit;
14
+ private previewOf;
15
+ private unwrapRows;
16
+ private applyUnwrap;
17
+ private unwrapPreview;
18
+ }