@adecore/editor-react 0.39.0 → 0.40.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 (154) hide show
  1. package/dist/CallHierarchyPanel.js +30 -55
  2. package/dist/CodeAuthorsCard.js +0 -1
  3. package/dist/CompletionPopup.js +150 -181
  4. package/dist/DiffView.d.ts +1 -1
  5. package/dist/DiffView.js +2 -29
  6. package/dist/PickPopup.js +54 -80
  7. package/dist/SplitDiffView.js +27 -57
  8. package/dist/SymbolPicker.js +2 -8
  9. package/dist/code-actions-model.js +2 -9
  10. package/dist/code-actions.js +10 -11
  11. package/dist/code-vision.js +2 -1
  12. package/dist/completion-model.js +2 -2
  13. package/dist/completion.js +13 -34
  14. package/dist/definition-link.d.ts +1 -0
  15. package/dist/definition-link.js +22 -18
  16. package/dist/diagnostics-model.d.ts +1 -0
  17. package/dist/diagnostics-model.js +3 -1
  18. package/dist/diagnostics.js +1 -2
  19. package/dist/diff-syntax.d.ts +1 -0
  20. package/dist/diff-syntax.js +31 -0
  21. package/dist/doc-comment-model.d.ts +1 -0
  22. package/dist/doc-comment-model.js +1 -1
  23. package/dist/folding.js +2 -3
  24. package/dist/format-on-type.js +6 -10
  25. package/dist/hover-content.d.ts +0 -2
  26. package/dist/hover-content.js +1 -9
  27. package/dist/inlay-hints.d.ts +0 -1
  28. package/dist/inlay-hints.js +11 -41
  29. package/dist/navigation.js +4 -14
  30. package/dist/peek.js +2 -12
  31. package/dist/popup-focus.d.ts +3 -1
  32. package/dist/popup-focus.js +33 -0
  33. package/dist/recent-choices.d.ts +0 -1
  34. package/dist/recent-choices.js +0 -4
  35. package/dist/rendered-docs.d.ts +1 -0
  36. package/dist/rendered-docs.js +15 -28
  37. package/dist/snippet-field-transforms.d.ts +5 -0
  38. package/dist/snippet-field-transforms.js +27 -16
  39. package/dist/snippet-session.js +8 -20
  40. package/dist/symbol-links.js +3 -10
  41. package/dist/symbol-picker-model.d.ts +1 -0
  42. package/dist/symbol-picker-model.js +7 -0
  43. package/dist/unique.d.ts +10 -0
  44. package/dist/unique.js +15 -0
  45. package/package.json +9 -9
  46. package/src/AnchoredPopup.tsx +2 -0
  47. package/src/BaselineStatus.tsx +1 -0
  48. package/src/CallHierarchyPanel.tsx +16 -6
  49. package/src/ChangeReview.tsx +7 -0
  50. package/src/CodeAuthorsCard.tsx +2 -5
  51. package/src/CompletionPopup.tsx +21 -15
  52. package/src/DiffView.tsx +53 -30
  53. package/src/EditorContextMenu.tsx +7 -0
  54. package/src/EditorView.tsx +28 -0
  55. package/src/FindReplace.tsx +8 -0
  56. package/src/HoverCard.tsx +8 -0
  57. package/src/HoverSections.tsx +11 -0
  58. package/src/LanguagePopups.tsx +1 -0
  59. package/src/PanelResizeHandle.tsx +8 -0
  60. package/src/PathText.tsx +1 -0
  61. package/src/PeekPanel.tsx +13 -0
  62. package/src/PickPopup.tsx +7 -6
  63. package/src/RenameCard.tsx +13 -0
  64. package/src/RenderedDocs.tsx +11 -0
  65. package/src/SplitDiffView.tsx +91 -56
  66. package/src/SymbolPicker.tsx +10 -18
  67. package/src/call-hierarchy-model.ts +10 -0
  68. package/src/call-hierarchy.ts +82 -0
  69. package/src/code-actions-model.ts +21 -9
  70. package/src/code-actions.ts +83 -7
  71. package/src/code-authors.ts +20 -0
  72. package/src/code-vision-model.ts +37 -0
  73. package/src/code-vision.ts +47 -3
  74. package/src/completion-call.ts +19 -0
  75. package/src/completion-model.ts +58 -2
  76. package/src/completion.ts +156 -30
  77. package/src/conflict-model.ts +4 -0
  78. package/src/context-menu-rows.ts +1 -0
  79. package/src/context-menu.ts +7 -0
  80. package/src/definition-link.ts +42 -18
  81. package/src/diagnostics-model.ts +19 -1
  82. package/src/diagnostics.ts +31 -2
  83. package/src/diff-expansion.ts +9 -0
  84. package/src/diff-overlays.tsx +8 -0
  85. package/src/diff-syntax.ts +54 -0
  86. package/src/diff-wordmarks.ts +8 -0
  87. package/src/doc-comment-model.ts +51 -1
  88. package/src/editor-language.ts +11 -0
  89. package/src/find-query.ts +7 -0
  90. package/src/folding.ts +10 -3
  91. package/src/format-on-type.ts +23 -10
  92. package/src/highlight-layers.ts +3 -0
  93. package/src/highlights.ts +18 -0
  94. package/src/history.ts +11 -0
  95. package/src/holder.ts +3 -0
  96. package/src/hover-content.ts +34 -17
  97. package/src/hover.ts +57 -0
  98. package/src/index.ts +4 -0
  99. package/src/inlay-hints.ts +86 -47
  100. package/src/key-priority.ts +2 -0
  101. package/src/line-edits.ts +8 -0
  102. package/src/models.ts +6 -0
  103. package/src/navigation-history.ts +5 -0
  104. package/src/navigation.ts +28 -13
  105. package/src/panel-size.ts +7 -0
  106. package/src/patch-decorations.ts +39 -0
  107. package/src/patch-layout.ts +47 -0
  108. package/src/peek-model.ts +21 -0
  109. package/src/peek.ts +49 -13
  110. package/src/pick.ts +35 -0
  111. package/src/popup-focus.ts +11 -1
  112. package/src/popup-placement.ts +5 -0
  113. package/src/popups.ts +2 -6
  114. package/src/project-language.ts +33 -0
  115. package/src/project-problems.ts +11 -0
  116. package/src/proposal-model.ts +40 -0
  117. package/src/recent-choices.ts +3 -5
  118. package/src/refresher.ts +3 -0
  119. package/src/rename-model.ts +28 -0
  120. package/src/rename.ts +56 -0
  121. package/src/rendered-docs.ts +89 -19
  122. package/src/review-group.ts +4 -0
  123. package/src/row-host.ts +12 -0
  124. package/src/selection-ranges.ts +6 -0
  125. package/src/semantic-delta.ts +7 -0
  126. package/src/semantic-model.ts +11 -0
  127. package/src/semantic-tokens.ts +37 -0
  128. package/src/shortcut-keys.ts +3 -0
  129. package/src/signature-model.ts +7 -0
  130. package/src/signature.ts +27 -0
  131. package/src/snippet-field-transforms.ts +48 -13
  132. package/src/snippet-indent.ts +10 -0
  133. package/src/snippet-range-order.ts +5 -0
  134. package/src/snippet-session.ts +173 -31
  135. package/src/snippet-transform-client.ts +14 -0
  136. package/src/snippet-transform-format.ts +98 -0
  137. package/src/snippet-transform-protocol.ts +5 -0
  138. package/src/snippet-transform-queue.ts +53 -0
  139. package/src/snippet-transform-worker.ts +14 -0
  140. package/src/snippet-variables.ts +9 -0
  141. package/src/snippet.ts +107 -0
  142. package/src/split-alignment.ts +10 -0
  143. package/src/split-scroll.ts +8 -0
  144. package/src/symbol-links.ts +9 -12
  145. package/src/symbol-picker-model.ts +25 -0
  146. package/src/symbol-picker.ts +9 -0
  147. package/src/symbols.ts +21 -0
  148. package/src/testing.ts +7 -0
  149. package/src/timers.ts +5 -0
  150. package/src/unique.ts +23 -0
  151. package/src/use-problem-counts.ts +4 -0
  152. package/src/view-state.ts +9 -0
  153. package/src/word-diff.ts +5 -0
  154. package/src/workspace-edit.ts +84 -0
@@ -71,20 +71,25 @@ function refused(failureReason: string): ApplyWorkspaceEditResult {
71
71
  /* The text edits of an edit per document, as the entries a document has in it, whatever else the edit does. */
72
72
  export function textEntriesOf(edit: WorkspaceEdit): Map<string, TextEdit[][]> {
73
73
  const entries = new Map<string, TextEdit[][]>();
74
+
74
75
  const add = (uri: string, edits: TextEdit[]): void => {
75
76
  entries.set(uri, [...(entries.get(uri) ?? []), edits]);
76
77
  };
78
+
77
79
  if (edit.documentChanges === undefined) {
78
80
  for (const [uri, edits] of Object.entries(edit.changes ?? {})) {
79
81
  add(uri, edits);
80
82
  }
83
+
81
84
  return entries;
82
85
  }
86
+
83
87
  for (const change of edit.documentChanges) {
84
88
  if ('textDocument' in change) {
85
89
  add(change.textDocument.uri, change.edits);
86
90
  }
87
91
  }
92
+
88
93
  return entries;
89
94
  }
90
95
 
@@ -101,12 +106,15 @@ export function renamesOf(edit: WorkspaceEdit): RenameFile[] {
101
106
  /* Every file an edit makes, moves or deletes, in the order it says. */
102
107
  export function resourceOperationsOf(edit: WorkspaceEdit): ResourceOperationView[] {
103
108
  const operations: ResourceOperationView[] = [];
109
+
104
110
  for (const change of edit.documentChanges ?? []) {
105
111
  if ('textDocument' in change) {
106
112
  continue;
107
113
  }
114
+
108
115
  operations.push(change.kind === 'rename' ? { kind: 'rename', uri: change.oldUri, newUri: change.newUri } : { kind: change.kind, uri: change.uri });
109
116
  }
117
+
110
118
  return operations;
111
119
  }
112
120
 
@@ -125,15 +133,19 @@ interface Reads {
125
133
  /* The resource operations a project has a way to carry out; pass it as the session's `resourceOperations` so servers only ask for what can be done. */
126
134
  export function supportedResourceOperations(files: ProjectFiles | null | undefined): ResourceOperationKind[] {
127
135
  const operations: ResourceOperationKind[] = [];
136
+
128
137
  if (files?.create !== undefined) {
129
138
  operations.push('create');
130
139
  }
140
+
131
141
  if (files?.rename !== undefined) {
132
142
  operations.push('rename');
133
143
  }
144
+
134
145
  if (files?.delete !== undefined) {
135
146
  operations.push('delete');
136
147
  }
148
+
137
149
  return operations;
138
150
  }
139
151
 
@@ -144,8 +156,10 @@ function within(uri: string, folder: string): boolean {
144
156
  /* Where a deleted URI stood before the renames that ran ahead of it, and what was moved into it: the places unsaved work can be. */
145
157
  function placesOf(uri: string, renames: readonly RenameFile[]): string[] {
146
158
  const found = new Set([uri]);
159
+
147
160
  for (let i = renames.length - 1; i >= 0; i--) {
148
161
  const { oldUri, newUri } = renames[i]!;
162
+
149
163
  for (const place of [...found]) {
150
164
  if (place === newUri || within(place, newUri)) {
151
165
  found.add(oldUri + place.slice(newUri.length));
@@ -154,22 +168,28 @@ function placesOf(uri: string, renames: readonly RenameFile[]): string[] {
154
168
  }
155
169
  }
156
170
  }
171
+
157
172
  return [...found];
158
173
  }
159
174
 
160
175
  /* Whether deleting or replacing loses work nobody saved at any of the places. Without `isUnsaved` that is an editor on, or under, a place. A `recursive` one may be a folder. */
161
176
  function losesWork(recursive: boolean, places: readonly string[], host: WorkspaceEditHost): boolean {
162
177
  const files = host.files!;
178
+
163
179
  if (files.isUnsaved !== undefined) {
164
180
  return places.some((place) => {
165
181
  const path = fileUriToPath(place);
182
+
166
183
  return path !== null && files.isUnsaved!(path);
167
184
  });
168
185
  }
186
+
169
187
  if (host.openUris === undefined && recursive) {
170
188
  return true;
171
189
  }
190
+
172
191
  const open = host.openUris?.() ?? [];
192
+
173
193
  return places.some((place) => host.editorOf(place) !== undefined || open.some((uri) => uri === place || within(uri, place)));
174
194
  }
175
195
 
@@ -186,62 +206,81 @@ function overwriteProblem(
186
206
  reads: Reads
187
207
  ): string | null {
188
208
  const path = fileUriToPath(target)!;
209
+
189
210
  if (host.files?.supportsOverwrite !== true) {
190
211
  return `${path} already exists`;
191
212
  }
213
+
192
214
  // A target no text was read from may be a folder, with unsaved work anywhere under it.
193
215
  const isText = step.kind === 'create' || reads.open.has(target) || reads.disks.has(target);
216
+
194
217
  if (losesWork(!isText, places, host)) {
195
218
  return `${path} has changes that are not saved`;
196
219
  }
220
+
197
221
  const editor = host.editorOf(target);
222
+
198
223
  return editor !== undefined && step.kind === 'create' && readOnlyAt(host, target, editor) ? `${path} is read only` : null;
199
224
  }
200
225
 
201
226
  /* Checks a plan against what only the host can see: paths, overwrites, unsaved work and the editors it touches. Null when it fits. */
202
227
  function problemWith(steps: readonly WorkspaceEditStep[], host: WorkspaceEditHost, reads: Reads): string | null {
203
228
  const renames: RenameFile[] = [];
229
+
204
230
  for (const step of steps) {
205
231
  if (step.kind === 'edits') {
206
232
  if (step.open && readOnlyAt(host, step.readUri, host.editorOf(step.readUri))) {
207
233
  return `${step.uri} is read only`;
208
234
  }
235
+
209
236
  continue;
210
237
  }
238
+
211
239
  const uris = step.kind === 'rename' ? [step.oldUri, step.newUri] : [step.uri];
212
240
  const paths = uris.map((uri) => fileUriToPath(uri));
241
+
213
242
  if (paths.includes(null)) {
214
243
  return `${uris[0]} cannot be changed from here`;
215
244
  }
245
+
216
246
  if ((step.kind === 'create' || step.kind === 'rename') && step.overwrite) {
217
247
  const target = step.kind === 'create' ? step.uri : step.newUri;
218
248
  const refusal = overwriteProblem(step, target, placesOf(target, renames), host, reads);
249
+
219
250
  if (refusal !== null) {
220
251
  return refusal;
221
252
  }
222
253
  }
254
+
223
255
  if (step.kind === 'rename') {
224
256
  renames.push({ kind: 'rename', oldUri: step.oldUri, newUri: step.newUri });
225
257
  }
258
+
226
259
  if (step.kind === 'delete' && losesWork(step.recursive, placesOf(step.uri, renames), host)) {
227
260
  return `${paths[0]} has changes that are not saved`;
228
261
  }
229
262
  }
263
+
230
264
  for (const [uri, planned] of reads.open) {
231
265
  const editor = host.editorOf(uri);
266
+
232
267
  if (editor === undefined || editor.getText() !== planned.text) {
233
268
  return `${uri} changed while the edit was being prepared`;
234
269
  }
270
+
235
271
  const version = host.versionOf?.(uri) ?? null;
272
+
236
273
  if (planned.version !== null && version !== planned.version) {
237
274
  return `${uri} changed while the edit was being prepared`;
238
275
  }
239
276
  }
277
+
240
278
  for (const uri of reads.disks.keys()) {
241
279
  if (host.editorOf(uri) !== undefined) {
242
280
  return `${uri} was opened while the edit was being prepared`;
243
281
  }
244
282
  }
283
+
245
284
  return null;
246
285
  }
247
286
 
@@ -266,23 +305,30 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
266
305
  const reads: Reads = { open: new Map(), disks: new Map() };
267
306
  const files = host.files;
268
307
  let steps: readonly WorkspaceEditStep[];
308
+
269
309
  try {
270
310
  ({ steps } = await planWorkspaceOperations(edit, {
271
311
  operations: supportedResourceOperations(files),
272
312
  read: async (uri) => {
273
313
  const editor = host.editorOf(uri);
314
+
274
315
  if (editor !== undefined) {
275
316
  const text = editor.getText();
276
317
  const version = host.versionOf?.(uri) ?? null;
277
318
  reads.open.set(uri, { text, version });
319
+
278
320
  return { text, version, open: true };
279
321
  }
322
+
280
323
  const path = fileUriToPath(uri);
281
324
  const disk = path === null || files === null ? null : await files.read(path);
325
+
282
326
  if (disk === null) {
283
327
  return null;
284
328
  }
329
+
285
330
  reads.disks.set(uri, disk);
331
+
286
332
  return { text: disk.text, version: null, open: false };
287
333
  },
288
334
  ...(files?.exists === undefined
@@ -290,6 +336,7 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
290
336
  : {
291
337
  exists: async (uri: string) => {
292
338
  const path = fileUriToPath(uri);
339
+
293
340
  return path !== null && (await files.exists!(path));
294
341
  }
295
342
  }),
@@ -298,6 +345,7 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
298
345
  : {
299
346
  isFolder: async (uri: string) => {
300
347
  const path = fileUriToPath(uri);
348
+
301
349
  return path === null || (await files.isFolder!(path));
302
350
  }
303
351
  })
@@ -305,21 +353,28 @@ export async function applyWorkspaceEdit(edit: WorkspaceEdit, host: WorkspaceEdi
305
353
  } catch (error) {
306
354
  return refused(messageOf(error));
307
355
  }
356
+
308
357
  const problem = problemWith(steps, host, reads);
358
+
309
359
  if (problem !== null) {
310
360
  return refused(problem);
311
361
  }
362
+
312
363
  const running: Running = { ahead: [], reads, saving: steps.some((step) => step.kind === 'rename'), staged: [], touched: new Set() };
364
+
313
365
  for (const [index, step] of steps.entries()) {
314
366
  running.ahead = steps.slice(index + 1);
315
367
  const reason = await run(step, host, running);
368
+
316
369
  if (reason !== null) {
317
370
  return refused(reason);
318
371
  }
319
372
  }
373
+
320
374
  if (running.staged.length > 0) {
321
375
  files?.stage(running.staged);
322
376
  }
377
+
323
378
  return { applied: true };
324
379
  }
325
380
 
@@ -340,56 +395,74 @@ function driftOf(step: PlannedTextStep, host: WorkspaceEditHost, uri: string, ed
340
395
  if (editor.getText() !== step.before) {
341
396
  return `${step.uri} changed while the edit was being applied`;
342
397
  }
398
+
343
399
  const version = uri === step.readUri && !touched.has(editor) ? host.versionOf?.(uri) : undefined;
400
+
344
401
  if (version !== undefined && step.version !== null && version !== step.version) {
345
402
  return `${step.uri} changed while the edit was being applied`;
346
403
  }
404
+
347
405
  return readOnlyAt(host, uri, editor) ? `${step.uri} is read only` : null;
348
406
  }
349
407
 
350
408
  /* Does one step; the reason it could not, or null. */
351
409
  async function run(step: WorkspaceEditStep, host: WorkspaceEditHost, running: Running): Promise<string | null> {
352
410
  const files = host.files!;
411
+
353
412
  if (step.kind === 'create') {
354
413
  return step.overwrite ? overwriteFile(step, host) : files.create!(fileUriToPath(step.uri)!, step.text);
355
414
  }
415
+
356
416
  if (step.kind === 'rename') {
357
417
  const [from, to] = [fileUriToPath(step.oldUri)!, fileUriToPath(step.newUri)!];
418
+
358
419
  if (!step.overwrite) {
359
420
  return files.rename(from, to);
360
421
  }
422
+
361
423
  // The steps before this one ran, so the unsaved work at the target is looked for once more.
362
424
  return losesWork(!running.reads.disks.has(step.newUri) && !running.reads.open.has(step.newUri), [step.newUri], host)
363
425
  ? `${to} has changes that are not saved`
364
426
  : files.rename(from, to, { overwrite: true });
365
427
  }
428
+
366
429
  if (step.kind === 'delete') {
367
430
  const path = fileUriToPath(step.uri)!;
431
+
368
432
  if (losesWork(step.recursive, [step.uri], host)) {
369
433
  return `${path} has changes that are not saved`;
370
434
  }
435
+
371
436
  return files.delete!(path, { recursive: step.recursive });
372
437
  }
438
+
373
439
  if (step.after === step.before) {
374
440
  return null;
375
441
  }
442
+
376
443
  if (step.open) {
377
444
  const uri = host.editorOf(step.uri) === undefined ? step.readUri : step.uri;
445
+
378
446
  return editOpen(step, host, running, uri, host.editorOf(uri));
379
447
  }
448
+
380
449
  return runDraft(step, host, running);
381
450
  }
382
451
 
383
452
  /* Empties a file that is there and gives it its text; the editor that still holds it is set to the same text. */
384
453
  async function overwriteFile(step: PlannedCreateStep, host: WorkspaceEditHost): Promise<string | null> {
385
454
  const path = fileUriToPath(step.uri)!;
455
+
386
456
  if (losesWork(false, [step.uri], host)) {
387
457
  return `${path} has changes that are not saved`;
388
458
  }
459
+
389
460
  const reason = await host.files!.create!(path, step.text, { overwrite: true });
461
+
390
462
  if (reason === null) {
391
463
  host.editorOf(step.uri)?.setText(step.text);
392
464
  }
465
+
393
466
  return reason;
394
467
  }
395
468
 
@@ -397,11 +470,15 @@ function editOpen(step: PlannedTextStep, host: WorkspaceEditHost, running: Runni
397
470
  if (editor === undefined) {
398
471
  return `${step.uri} is not open any more`;
399
472
  }
473
+
400
474
  const drift = driftOf(step, host, uri, editor, running.touched);
475
+
401
476
  if (drift !== null) {
402
477
  return drift;
403
478
  }
479
+
404
480
  running.touched.add(editor);
481
+
405
482
  // The edits stay apart, so the caret and what is drawn over the text stay where they were between them.
406
483
  return editor.applyEdits(step.edits.map(contentChangeOf)) ? null : `${step.uri} is read only`;
407
484
  }
@@ -414,18 +491,25 @@ function deletedAhead(uri: string, ahead: readonly WorkspaceEditStep[]): boolean
414
491
  async function runDraft(step: PlannedTextStep, host: WorkspaceEditHost, running: Running): Promise<string | null> {
415
492
  const { reads, saving, staged, ahead } = running;
416
493
  const uri = [step.uri, step.readUri].find((candidate) => host.editorOf(candidate) !== undefined);
494
+
417
495
  if (uri !== undefined) {
418
496
  return editOpen(step, host, running, uri, host.editorOf(uri));
419
497
  }
498
+
420
499
  const path = fileUriToPath(step.uri);
421
500
  const disk = reads.disks.get(step.readUri);
501
+
422
502
  if (path === null || disk === undefined || deletedAhead(step.uri, ahead)) {
423
503
  return null;
424
504
  }
505
+
425
506
  const file = { path, disk, text: step.after };
507
+
426
508
  if (!saving) {
427
509
  staged.push(file);
510
+
428
511
  return null;
429
512
  }
513
+
430
514
  return host.files!.save([file]);
431
515
  }