@theia/plugin-ext 1.34.0-next.19 → 1.34.0-next.31

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 (57) hide show
  1. package/lib/common/plugin-api-rpc.d.ts +6 -3
  2. package/lib/common/plugin-api-rpc.d.ts.map +1 -1
  3. package/lib/common/plugin-api-rpc.js.map +1 -1
  4. package/lib/main/browser/commands.js +1 -1
  5. package/lib/main/browser/commands.js.map +1 -1
  6. package/lib/main/browser/dialogs-main.d.ts.map +1 -1
  7. package/lib/main/browser/dialogs-main.js +2 -1
  8. package/lib/main/browser/dialogs-main.js.map +1 -1
  9. package/lib/main/browser/scm-main.d.ts +1 -0
  10. package/lib/main/browser/scm-main.d.ts.map +1 -1
  11. package/lib/main/browser/scm-main.js +7 -0
  12. package/lib/main/browser/scm-main.js.map +1 -1
  13. package/lib/main/browser/terminal-main.d.ts.map +1 -1
  14. package/lib/main/browser/terminal-main.js +2 -0
  15. package/lib/main/browser/terminal-main.js.map +1 -1
  16. package/lib/plugin/plugin-context.d.ts.map +1 -1
  17. package/lib/plugin/plugin-context.js +1 -0
  18. package/lib/plugin/plugin-context.js.map +1 -1
  19. package/lib/plugin/quick-open.d.ts +3 -0
  20. package/lib/plugin/quick-open.d.ts.map +1 -1
  21. package/lib/plugin/quick-open.js +7 -0
  22. package/lib/plugin/quick-open.js.map +1 -1
  23. package/lib/plugin/scm.d.ts +3 -0
  24. package/lib/plugin/scm.d.ts.map +1 -1
  25. package/lib/plugin/scm.js +7 -0
  26. package/lib/plugin/scm.js.map +1 -1
  27. package/lib/plugin/tabs.js +2 -2
  28. package/lib/plugin/tabs.js.map +1 -1
  29. package/lib/plugin/terminal-ext.d.ts +4 -0
  30. package/lib/plugin/terminal-ext.d.ts.map +1 -1
  31. package/lib/plugin/terminal-ext.js +17 -1
  32. package/lib/plugin/terminal-ext.js.map +1 -1
  33. package/lib/plugin/type-converters.d.ts +4 -0
  34. package/lib/plugin/type-converters.d.ts.map +1 -1
  35. package/lib/plugin/type-converters.js +16 -4
  36. package/lib/plugin/type-converters.js.map +1 -1
  37. package/lib/plugin/type-converters.spec.js +19 -0
  38. package/lib/plugin/type-converters.spec.js.map +1 -1
  39. package/lib/plugin/types-impl.d.ts +26 -5
  40. package/lib/plugin/types-impl.d.ts.map +1 -1
  41. package/lib/plugin/types-impl.js +44 -9
  42. package/lib/plugin/types-impl.js.map +1 -1
  43. package/package.json +25 -25
  44. package/src/common/plugin-api-rpc.ts +4 -4
  45. package/src/main/browser/commands.ts +1 -1
  46. package/src/main/browser/dialogs-main.ts +2 -1
  47. package/src/main/browser/scm-main.ts +10 -0
  48. package/src/main/browser/terminal-main.ts +2 -0
  49. package/src/main/browser/webview/pre/main.js +112 -111
  50. package/src/plugin/plugin-context.ts +2 -0
  51. package/src/plugin/quick-open.ts +10 -0
  52. package/src/plugin/scm.ts +11 -0
  53. package/src/plugin/tabs.ts +2 -2
  54. package/src/plugin/terminal-ext.ts +18 -2
  55. package/src/plugin/type-converters.spec.ts +20 -0
  56. package/src/plugin/type-converters.ts +15 -4
  57. package/src/plugin/types-impl.ts +73 -13
@@ -67,78 +67,78 @@
67
67
  };
68
68
 
69
69
  const defaultCssRules = `
70
- body {
71
- background-color: var(--vscode-editor-background);
72
- color: var(--vscode-editor-foreground);
73
- font-family: var(--vscode-font-family);
74
- font-weight: var(--vscode-font-weight);
75
- font-size: var(--vscode-font-size);
76
- margin: 0;
77
- padding: 0 20px;
78
- }
79
-
80
- img {
81
- max-width: 100%;
82
- max-height: 100%;
83
- }
84
-
85
- a {
86
- color: var(--vscode-textLink-foreground);
87
- }
88
-
89
- a:hover {
90
- color: var(--vscode-textLink-activeForeground);
91
- }
92
-
93
- a:focus,
94
- input:focus,
95
- select:focus,
96
- textarea:focus {
97
- outline: 1px solid -webkit-focus-ring-color;
98
- outline-offset: -1px;
99
- }
100
-
101
- code {
102
- color: var(--vscode-textPreformat-foreground);
103
- }
104
-
105
- blockquote {
106
- background: var(--vscode-textBlockQuote-background);
107
- border-color: var(--vscode-textBlockQuote-border);
108
- }
109
-
110
- kbd {
111
- color: var(--vscode-editor-foreground);
112
- border-radius: 3px;
113
- vertical-align: middle;
114
- padding: 1px 3px;
115
-
116
- background-color: hsla(0,0%,50%,.17);
117
- border: 1px solid rgba(71,71,71,.4);
118
- border-bottom-color: rgba(88,88,88,.4);
119
- box-shadow: inset 0 -1px 0 rgba(88,88,88,.4);
120
- }
121
- .vscode-light kbd {
122
- background-color: hsla(0,0%,87%,.5);
123
- border: 1px solid hsla(0,0%,80%,.7);
124
- border-bottom-color: hsla(0,0%,73%,.7);
125
- box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7);
126
- }
127
-
128
- ::-webkit-scrollbar {
129
- width: 10px;
130
- height: 10px;
131
- }
132
-
133
- ::-webkit-scrollbar-thumb {
134
- background-color: var(--vscode-scrollbarSlider-background);
135
- }
136
- ::-webkit-scrollbar-thumb:hover {
137
- background-color: var(--vscode-scrollbarSlider-hoverBackground);
138
- }
139
- ::-webkit-scrollbar-thumb:active {
140
- background-color: var(--vscode-scrollbarSlider-activeBackground);
141
- }`;
70
+ body {
71
+ background-color: var(--vscode-editor-background);
72
+ color: var(--vscode-editor-foreground);
73
+ font-family: var(--vscode-font-family);
74
+ font-weight: var(--vscode-font-weight);
75
+ font-size: var(--vscode-font-size);
76
+ margin: 0;
77
+ padding: 0 20px;
78
+ }
79
+
80
+ img {
81
+ max-width: 100%;
82
+ max-height: 100%;
83
+ }
84
+
85
+ a {
86
+ color: var(--vscode-textLink-foreground);
87
+ }
88
+
89
+ a:hover {
90
+ color: var(--vscode-textLink-activeForeground);
91
+ }
92
+
93
+ a:focus,
94
+ input:focus,
95
+ select:focus,
96
+ textarea:focus {
97
+ outline: 1px solid -webkit-focus-ring-color;
98
+ outline-offset: -1px;
99
+ }
100
+
101
+ code {
102
+ color: var(--vscode-textPreformat-foreground);
103
+ }
104
+
105
+ blockquote {
106
+ background: var(--vscode-textBlockQuote-background);
107
+ border-color: var(--vscode-textBlockQuote-border);
108
+ }
109
+
110
+ kbd {
111
+ color: var(--vscode-editor-foreground);
112
+ border-radius: 3px;
113
+ vertical-align: middle;
114
+ padding: 1px 3px;
115
+
116
+ background-color: hsla(0,0%,50%,.17);
117
+ border: 1px solid rgba(71,71,71,.4);
118
+ border-bottom-color: rgba(88,88,88,.4);
119
+ box-shadow: inset 0 -1px 0 rgba(88,88,88,.4);
120
+ }
121
+ .vscode-light kbd {
122
+ background-color: hsla(0,0%,87%,.5);
123
+ border: 1px solid hsla(0,0%,80%,.7);
124
+ border-bottom-color: hsla(0,0%,73%,.7);
125
+ box-shadow: inset 0 -1px 0 hsla(0,0%,73%,.7);
126
+ }
127
+
128
+ ::-webkit-scrollbar {
129
+ width: 10px;
130
+ height: 10px;
131
+ }
132
+
133
+ ::-webkit-scrollbar-thumb {
134
+ background-color: var(--vscode-scrollbarSlider-background);
135
+ }
136
+ ::-webkit-scrollbar-thumb:hover {
137
+ background-color: var(--vscode-scrollbarSlider-hoverBackground);
138
+ }
139
+ ::-webkit-scrollbar-thumb:active {
140
+ background-color: var(--vscode-scrollbarSlider-activeBackground);
141
+ }`;
142
142
 
143
143
  /**
144
144
  * @param {*} [state]
@@ -146,38 +146,38 @@
146
146
  */
147
147
  function getVsCodeApiScript(state) {
148
148
  return `
149
- const acquireVsCodeApi = (function() {
150
- const originalPostMessage = window.parent.postMessage.bind(window.parent);
151
- const targetOrigin = '*';
152
- let acquired = false;
153
-
154
- let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined};
155
-
156
- return () => {
157
- if (acquired) {
158
- throw new Error('An instance of the VS Code API has already been acquired');
159
- }
160
- acquired = true;
161
- return Object.freeze({
162
- postMessage: function(msg) {
163
- return originalPostMessage({ command: 'onmessage', data: msg }, targetOrigin);
164
- },
165
- setState: function(newState) {
166
- state = newState;
167
- originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, targetOrigin);
168
- return newState;
169
- },
170
- getState: function() {
171
- return state;
172
- }
173
- });
174
- };
175
- })();
176
- const acquireTheiaApi = acquireVsCodeApi;
177
- delete window.parent;
178
- delete window.top;
179
- delete window.frameElement;
180
- `;
149
+ const acquireVsCodeApi = (function() {
150
+ const originalPostMessage = window.parent.postMessage.bind(window.parent);
151
+ const targetOrigin = '*';
152
+ let acquired = false;
153
+
154
+ let state = ${state ? `JSON.parse(${JSON.stringify(state)})` : undefined};
155
+
156
+ return () => {
157
+ if (acquired) {
158
+ throw new Error('An instance of the VS Code API has already been acquired');
159
+ }
160
+ acquired = true;
161
+ return Object.freeze({
162
+ postMessage: function(msg) {
163
+ return originalPostMessage({ command: 'onmessage', data: msg }, targetOrigin);
164
+ },
165
+ setState: function(newState) {
166
+ state = newState;
167
+ originalPostMessage({ command: 'do-update-state', data: JSON.stringify(newState) }, targetOrigin);
168
+ return newState;
169
+ },
170
+ getState: function() {
171
+ return state;
172
+ }
173
+ });
174
+ };
175
+ })();
176
+ const acquireTheiaApi = acquireVsCodeApi;
177
+ delete window.parent;
178
+ delete window.top;
179
+ delete window.frameElement;
180
+ `;
181
181
  }
182
182
 
183
183
  /**
@@ -381,20 +381,21 @@
381
381
 
382
382
  applyStyles(newDocument, newDocument.body);
383
383
 
384
+ const sameOrigin = '\'self\''; // see: https://content-security-policy.com/self/
384
385
  // Check for CSP
385
386
  const csp = newDocument.querySelector('meta[http-equiv="Content-Security-Policy"]');
386
- if (!csp) {
387
- host.postMessage('no-csp-found');
388
- } else {
389
- // Rewrite vscode-resource in csp
390
- if (data.endpoint) {
387
+ if (csp !== null) {
388
+ const cspContent = csp.getAttribute('content');
389
+ if (cspContent !== null) {
390
+ // Rewrite vscode-resource in csp
391
391
  try {
392
- const endpointUrl = new URL(data.endpoint);
393
- csp.setAttribute('content', csp.getAttribute('content').replace(/(?:vscode|theia)-resource:(?=(\s|;|$))/g, endpointUrl.origin));
392
+ csp.setAttribute('content', cspContent.replace(/(vscode-webview-resource|vscode-resource):(?=(\s|;|$))/g, sameOrigin));
394
393
  } catch (e) {
395
394
  console.error('Could not rewrite csp');
396
395
  }
397
396
  }
397
+ } else {
398
+ host.postMessage('no-csp-found');
398
399
  }
399
400
 
400
401
  // set DOCTYPE for newDocument explicitly as DOMParser.parseFromString strips it off
@@ -61,6 +61,7 @@ import {
61
61
  CompletionItemKind,
62
62
  CompletionList,
63
63
  TextEdit,
64
+ SnippetTextEdit,
64
65
  CompletionTriggerKind,
65
66
  Diagnostic,
66
67
  DiagnosticRelatedInformation,
@@ -1170,6 +1171,7 @@ export function createAPIFactory(
1170
1171
  Diagnostic,
1171
1172
  CompletionTriggerKind,
1172
1173
  TextEdit,
1174
+ SnippetTextEdit,
1173
1175
  ProgressLocation,
1174
1176
  ProgressOptions,
1175
1177
  Progress,
@@ -543,6 +543,7 @@ export class InputBoxExt extends QuickInputExt implements theia.InputBox {
543
543
 
544
544
  private _password: boolean;
545
545
  private _prompt: string | undefined;
546
+ private _valueSelection: readonly [number, number] | undefined;
546
547
  private _validationMessage: string | undefined;
547
548
 
548
549
  constructor(
@@ -576,6 +577,15 @@ export class InputBoxExt extends QuickInputExt implements theia.InputBox {
576
577
  this.update({ prompt });
577
578
  }
578
579
 
580
+ get valueSelection(): readonly [number, number] | undefined {
581
+ return this._valueSelection;
582
+ }
583
+
584
+ set valueSelection(valueSelection: readonly [number, number] | undefined) {
585
+ this._valueSelection = valueSelection;
586
+ this.update({ valueSelection });
587
+ }
588
+
579
589
  get validationMessage(): string | undefined {
580
590
  return this._validationMessage;
581
591
  }
package/src/plugin/scm.ts CHANGED
@@ -322,6 +322,17 @@ export class ScmInputBoxImpl implements theia.SourceControlInputBox {
322
322
  this._visible = visible;
323
323
  }
324
324
 
325
+ private _enabled: boolean;
326
+
327
+ get enabled(): boolean {
328
+ return this._enabled;
329
+ }
330
+
331
+ set enabled(enabled: boolean) {
332
+ this.proxy.$setInputBoxEnabled(this.sourceControlHandle, enabled);
333
+ this._enabled = enabled;
334
+ }
335
+
325
336
  private _validateInput: ValidateInput | undefined;
326
337
 
327
338
  get validateInput(): ValidateInput | undefined {
@@ -406,7 +406,7 @@ export class TabsExtImpl implements TabsExt {
406
406
  return this.proxy.$closeTab(extHostTabIds, preserveFocus);
407
407
  }
408
408
 
409
- private async _closeGroups(groups: theia.TabGroup[], preserverFoucs?: boolean): Promise<boolean> {
409
+ private async _closeGroups(groups: theia.TabGroup[], preserveFocus?: boolean): Promise<boolean> {
410
410
  const extHostGroupIds: number[] = [];
411
411
  for (const group of groups) {
412
412
  const extHostGroup = this._findExtHostTabGroupFromApi(group);
@@ -415,7 +415,7 @@ export class TabsExtImpl implements TabsExt {
415
415
  }
416
416
  extHostGroupIds.push(extHostGroup.groupId);
417
417
  }
418
- return this.proxy.$closeGroup(extHostGroupIds, preserverFoucs);
418
+ return this.proxy.$closeGroup(extHostGroupIds, preserveFocus);
419
419
  }
420
420
  }
421
421
 
@@ -20,9 +20,25 @@ import { RPCProtocol } from '../common/rpc-protocol';
20
20
  import { Event, Emitter } from '@theia/core/lib/common/event';
21
21
  import { Deferred } from '@theia/core/lib/common/promise-util';
22
22
  import * as theia from '@theia/plugin';
23
- import { Disposable, EnvironmentVariableMutatorType } from './types-impl';
23
+ import { Disposable, EnvironmentVariableMutatorType, ThemeIcon } from './types-impl';
24
24
  import { SerializableEnvironmentVariableCollection } from '@theia/terminal/lib/common/base-terminal-protocol';
25
25
  import { ProvidedTerminalLink } from '../common/plugin-api-rpc-model';
26
+ import { ThemeIcon as MonacoThemeIcon } from '@theia/monaco-editor-core/esm/vs/platform/theme/common/themeService';
27
+
28
+ export function getIconUris(iconPath: theia.TerminalOptions['iconPath']): { id: string } | undefined {
29
+ if (ThemeIcon.is(iconPath)) {
30
+ return { id: iconPath.id };
31
+ }
32
+ return undefined;
33
+ }
34
+
35
+ export function getIconClass(options: theia.TerminalOptions | theia.ExtensionTerminalOptions): string | undefined {
36
+ const iconClass = getIconUris(options.iconPath);
37
+ if (iconClass) {
38
+ return MonacoThemeIcon.asClassName(iconClass);
39
+ }
40
+ return undefined;
41
+ }
26
42
 
27
43
  /**
28
44
  * Provides high level terminal plugin api to use in the Theia plugins.
@@ -65,7 +81,7 @@ export class TerminalServiceExtImpl implements TerminalServiceExt {
65
81
  nameOrOptions: TerminalOptions | PseudoTerminalOptions | ExtensionTerminalOptions | (string | undefined),
66
82
  shellPath?: string, shellArgs?: string[] | string
67
83
  ): Terminal {
68
- let options: TerminalOptions;
84
+ let options: TerminalOptions | ExtensionTerminalOptions;
69
85
  let pseudoTerminal: theia.Pseudoterminal | undefined = undefined;
70
86
  const id = `plugin-terminal-${UUID.uuid4()}`;
71
87
  if (typeof nameOrOptions === 'object') {
@@ -453,4 +453,24 @@ describe('Type converters:', () => {
453
453
  assert.deepStrictEqual(result, showOptions);
454
454
  });
455
455
  });
456
+
457
+ describe('#convertCode', () => {
458
+ it('should convert a "code" of type "string"', () => {
459
+ assert.strictEqual(Converter.convertCode('string'), 'string');
460
+ });
461
+ it('should convert a "code" of type "number"', () => {
462
+ assert.strictEqual(Converter.convertCode(4), '4');
463
+ });
464
+ it('should convert an undefined "code"', () => {
465
+ assert.strictEqual(Converter.convertCode(undefined), undefined);
466
+ });
467
+ it('should convert a "code" of type "{ value: number, target: Uri }"', () => {
468
+ const uri = types.URI.parse('foo://example.com:8042/over/there?name=ferret#nose');
469
+ assert.strictEqual(Converter.convertCode({ value: 4, target: uri }), '4');
470
+ });
471
+ it('should convert a "code" of type "{ value: number, target: Uri }"', () => {
472
+ const uri = types.URI.parse('foo://example.com:8042/over/there?name=ferret#nose');
473
+ assert.strictEqual(Converter.convertCode({ value: 'string', target: uri }), 'string');
474
+ });
475
+ });
456
476
  });
@@ -316,6 +316,14 @@ export function fromTextEdit(edit: theia.TextEdit): model.TextEdit {
316
316
  };
317
317
  }
318
318
 
319
+ function fromSnippetTextEdit(edit: theia.SnippetTextEdit): model.TextEdit & { insertAsSnippet?: boolean } {
320
+ return {
321
+ text: edit.snippet.value,
322
+ range: fromRange(edit.range),
323
+ insertAsSnippet: true
324
+ };
325
+ }
326
+
319
327
  export function convertDiagnosticToMarkerData(diagnostic: theia.Diagnostic): model.MarkerData {
320
328
  return {
321
329
  code: convertCode(diagnostic.code),
@@ -331,12 +339,15 @@ export function convertDiagnosticToMarkerData(diagnostic: theia.Diagnostic): mod
331
339
  };
332
340
  }
333
341
 
334
- function convertCode(code: string | number | undefined): string | undefined {
342
+ export function convertCode(code: string | number | { value: string | number; target: theia.Uri } | undefined): string | undefined {
335
343
  if (typeof code === 'number') {
336
344
  return String(code);
337
- } else {
338
- return code;
339
345
  }
346
+ if (typeof code === 'string' || typeof code === 'undefined') {
347
+ return code;
348
+ } else {
349
+ return String(code.value);
350
+ };
340
351
  }
341
352
 
342
353
  function convertSeverity(severity: types.DiagnosticSeverity): types.MarkerSeverity {
@@ -567,7 +578,7 @@ export function fromWorkspaceEdit(value: theia.WorkspaceEdit, documents?: any):
567
578
  const workspaceTextEditDto: WorkspaceTextEditDto = {
568
579
  resource: uri,
569
580
  modelVersionId: doc?.version,
570
- textEdit: uriOrEdits.map(fromTextEdit)[0],
581
+ textEdit: uriOrEdits.map(edit => (edit instanceof types.TextEdit) ? fromTextEdit(edit) : fromSnippetTextEdit(edit))[0],
571
582
  metadata: entry[2] as types.WorkspaceEditMetadata
572
583
  };
573
584
  result.edits.push(workspaceTextEditDto);
@@ -1279,6 +1279,30 @@ export class NotebookRange implements theia.NotebookRange {
1279
1279
 
1280
1280
  }
1281
1281
 
1282
+ export class SnippetTextEdit implements theia.SnippetTextEdit {
1283
+ range: Range;
1284
+ snippet: SnippetString;
1285
+
1286
+ static isSnippetTextEdit(thing: unknown): thing is SnippetTextEdit {
1287
+ return thing instanceof SnippetTextEdit || isObject<SnippetTextEdit>(thing)
1288
+ && Range.isRange((<SnippetTextEdit>thing).range)
1289
+ && SnippetString.isSnippetString((<SnippetTextEdit>thing).snippet);
1290
+ }
1291
+
1292
+ static replace(range: Range, snippet: SnippetString): SnippetTextEdit {
1293
+ return new SnippetTextEdit(range, snippet);
1294
+ }
1295
+
1296
+ static insert(position: Position, snippet: SnippetString): SnippetTextEdit {
1297
+ return SnippetTextEdit.replace(new Range(position, position), snippet);
1298
+ }
1299
+
1300
+ constructor(range: Range, snippet: SnippetString) {
1301
+ this.range = range;
1302
+ this.snippet = snippet;
1303
+ }
1304
+ }
1305
+
1282
1306
  @es5ClassCompat
1283
1307
  export class NotebookEdit implements theia.NotebookEdit {
1284
1308
  range: theia.NotebookRange;
@@ -1623,11 +1647,17 @@ export interface WorkspaceEditMetadata {
1623
1647
  } | {
1624
1648
  light: URI;
1625
1649
  dark: URI;
1626
- };
1650
+ } | ThemeIcon;
1651
+ }
1652
+
1653
+ export const enum FileEditType {
1654
+ File = 1,
1655
+ Text = 2,
1656
+ Snippet = 6,
1627
1657
  }
1628
1658
 
1629
1659
  export interface FileOperation {
1630
- _type: 1;
1660
+ _type: FileEditType.File;
1631
1661
  from: URI | undefined;
1632
1662
  to: URI | undefined;
1633
1663
  options?: FileOperationOptions;
@@ -1635,16 +1665,26 @@ export interface FileOperation {
1635
1665
  }
1636
1666
 
1637
1667
  export interface FileTextEdit {
1638
- _type: 2;
1668
+ _type: FileEditType.Text;
1639
1669
  uri: URI;
1640
1670
  edit: TextEdit;
1641
1671
  metadata?: WorkspaceEditMetadata;
1642
1672
  }
1643
1673
 
1674
+ export interface FileSnippetTextEdit {
1675
+ readonly _type: FileEditType.Snippet;
1676
+ readonly uri: URI;
1677
+ readonly range: Range;
1678
+ readonly edit: SnippetTextEdit;
1679
+ readonly metadata?: theia.WorkspaceEditEntryMetadata;
1680
+ }
1681
+
1682
+ type WorkspaceEditEntry = FileOperation | FileTextEdit | FileSnippetTextEdit | undefined;
1683
+
1644
1684
  @es5ClassCompat
1645
1685
  export class WorkspaceEdit implements theia.WorkspaceEdit {
1646
1686
 
1647
- private _edits = new Array<FileOperation | FileTextEdit | undefined>();
1687
+ private _edits = new Array<WorkspaceEditEntry>();
1648
1688
 
1649
1689
  renameFile(from: theia.Uri, to: theia.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void {
1650
1690
  this._edits.push({ _type: 1, from, to, options, metadata });
@@ -1679,21 +1719,41 @@ export class WorkspaceEdit implements theia.WorkspaceEdit {
1679
1719
  return false;
1680
1720
  }
1681
1721
 
1682
- set(uri: URI, edits: TextEdit[]): void {
1722
+ set(uri: URI, edits: ReadonlyArray<TextEdit | SnippetTextEdit>): void;
1723
+ set(uri: URI, edits: ReadonlyArray<[TextEdit | SnippetTextEdit, theia.WorkspaceEditEntryMetadata]>): void;
1724
+
1725
+ set(uri: URI, edits: ReadonlyArray<TextEdit | SnippetTextEdit | [TextEdit | SnippetTextEdit, theia.WorkspaceEditEntryMetadata]>): void {
1683
1726
  if (!edits) {
1684
1727
  // remove all text edits for `uri`
1685
1728
  for (let i = 0; i < this._edits.length; i++) {
1686
1729
  const element = this._edits[i];
1687
- if (element && element._type === 2 && element.uri.toString() === uri.toString()) {
1730
+ if (element &&
1731
+ (element._type === FileEditType.Text || element._type === FileEditType.Snippet) &&
1732
+ element.uri.toString() === uri.toString()) {
1688
1733
  this._edits[i] = undefined;
1689
1734
  }
1690
1735
  }
1691
1736
  this._edits = this._edits.filter(e => !!e);
1692
1737
  } else {
1693
1738
  // append edit to the end
1694
- for (const edit of edits) {
1695
- if (edit) {
1696
- this._edits.push({ _type: 2, uri, edit });
1739
+ for (const editOrTuple of edits) {
1740
+ if (!editOrTuple) {
1741
+ continue;
1742
+ }
1743
+
1744
+ let edit: TextEdit | SnippetTextEdit;
1745
+ let metadata: theia.WorkspaceEditEntryMetadata | undefined;
1746
+ if (Array.isArray(editOrTuple)) {
1747
+ edit = editOrTuple[0];
1748
+ metadata = editOrTuple[1];
1749
+ } else {
1750
+ edit = editOrTuple;
1751
+ }
1752
+
1753
+ if (SnippetTextEdit.isSnippetTextEdit(edit)) {
1754
+ this._edits.push({ _type: FileEditType.Snippet, uri, range: edit.range, edit, metadata });
1755
+ } else {
1756
+ this._edits.push({ _type: FileEditType.Text, uri, edit });
1697
1757
  }
1698
1758
  }
1699
1759
  }
@@ -1715,7 +1775,7 @@ export class WorkspaceEdit implements theia.WorkspaceEdit {
1715
1775
  entries(): [URI, TextEdit[]][] {
1716
1776
  const textEdits = new Map<string, [URI, TextEdit[]]>();
1717
1777
  for (const candidate of this._edits) {
1718
- if (candidate && candidate._type === 2) {
1778
+ if (candidate && candidate._type === FileEditType.Text) {
1719
1779
  let textEdit = textEdits.get(candidate.uri.toString());
1720
1780
  if (!textEdit) {
1721
1781
  textEdit = [candidate.uri, []];
@@ -1729,13 +1789,13 @@ export class WorkspaceEdit implements theia.WorkspaceEdit {
1729
1789
  return result;
1730
1790
  }
1731
1791
 
1732
- _allEntries(): ([URI, TextEdit[], WorkspaceEditMetadata] | [URI, URI, FileOperationOptions, WorkspaceEditMetadata])[] {
1733
- const res: ([URI, TextEdit[], WorkspaceEditMetadata] | [URI, URI, FileOperationOptions, WorkspaceEditMetadata])[] = [];
1792
+ _allEntries(): ([URI, Array<TextEdit | SnippetTextEdit>, theia.WorkspaceEditEntryMetadata] | [URI, URI, FileOperationOptions, WorkspaceEditMetadata])[] {
1793
+ const res: ([URI, Array<TextEdit | SnippetTextEdit>, theia.WorkspaceEditEntryMetadata] | [URI, URI, FileOperationOptions, WorkspaceEditMetadata])[] = [];
1734
1794
  for (const edit of this._edits) {
1735
1795
  if (!edit) {
1736
1796
  continue;
1737
1797
  }
1738
- if (edit._type === 1) {
1798
+ if (edit._type === FileEditType.File) {
1739
1799
  res.push([edit.from!, edit.to!, edit.options!, edit.metadata!]);
1740
1800
  } else {
1741
1801
  res.push([edit.uri, [edit.edit], edit.metadata!]);