From 63142fc2cbb200c8ca8690ba680e4c4d054d749b Mon Sep 17 00:00:00 2001 From: Johannes Rieken Date: Mon, 20 Jan 2020 15:31:50 +0100 Subject: [PATCH] add API proposal for workspace edit metadata, #77728 --- src/vs/vscode.proposed.d.ts | 22 ++++++++ .../api/common/extHostTypeConverters.ts | 32 ++++++++---- src/vs/workbench/api/common/extHostTypes.ts | 51 ++++++++++--------- .../electron-browser/api/extHostTypes.test.ts | 44 +++++++--------- 4 files changed, 91 insertions(+), 58 deletions(-) diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 939d77562e3..bb3bbf0472e 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -1550,4 +1550,26 @@ declare module 'vscode' { //#endregion + + //#region https://github.com/microsoft/vscode/issues/77728 + + export interface WorkspaceEditMetadata { + needsConfirmation: boolean; + label: string; + description?: string; + iconPath?: Uri | { light: Uri; dark: Uri } | ThemeIcon; + } + + export interface WorkspaceEdit { + + insert(uri: Uri, position: Position, newText: string, metadata?: WorkspaceEditMetadata): void; + delete(uri: Uri, range: Range, metadata?: WorkspaceEditMetadata): void; + replace(uri: Uri, range: Range, newText: string, metadata?: WorkspaceEditMetadata): void; + + createFile(uri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + deleteFile(uri: Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + renameFile(oldUri: Uri, newUri: Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean }, metadata?: WorkspaceEditMetadata): void; + } + + //#endregion } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 2e2b44dfff7..dc1e02f3af8 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -483,15 +483,29 @@ export namespace WorkspaceEdit { const result: extHostProtocol.IWorkspaceEditDto = { edits: [] }; - for (const entry of (value as types.WorkspaceEdit)._allEntries()) { - const [uri, uriOrEdits] = entry; - if (URI.isUri(uriOrEdits) || uriOrEdits === undefined) { - // resource edits - result.edits.push({ oldUri: uri, newUri: uriOrEdits, options: entry[2] }); - } else { - // text edits - const doc = documents && uri ? documents.getDocument(uri) : undefined; - result.edits.push({ resource: uri, modelVersionId: doc && doc.version, edit: TextEdit.from(uriOrEdits) }); + + if (value instanceof types.WorkspaceEdit) { + for (let entry of value.allEntries()) { + + if (entry._type === 1) { + // file operation + result.edits.push({ + oldUri: entry.from, + newUri: entry.to, + options: entry.options, + metadata: entry.metadata + }); + + } else { + // text edits + const doc = documents?.getDocument(entry.uri); + result.edits.push({ + resource: entry.uri, + edit: TextEdit.from(entry.edit), + modelVersionId: doc?.version, + metadata: entry.metadata + }); + } } } return result; diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index b93bf29bef5..7b996ed7b20 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -564,7 +564,6 @@ export class TextEdit { } } - export interface IFileOperationOptions { overwrite?: boolean; ignoreIfExists?: boolean; @@ -577,12 +576,14 @@ export interface IFileOperation { from?: URI; to?: URI; options?: IFileOperationOptions; + metadata?: vscode.WorkspaceEditMetadata; } export interface IFileTextEdit { _type: 2; uri: URI; edit: TextEdit; + metadata?: vscode.WorkspaceEditMetadata; } @es5ClassCompat @@ -590,28 +591,28 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { private _edits = new Array(); - renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }): void { - this._edits.push({ _type: 1, from, to, options }); + renameFile(from: vscode.Uri, to: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void { + this._edits.push({ _type: 1, from, to, options, metadata }); } - createFile(uri: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }): void { - this._edits.push({ _type: 1, from: undefined, to: uri, options }); + createFile(uri: vscode.Uri, options?: { overwrite?: boolean, ignoreIfExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void { + this._edits.push({ _type: 1, from: undefined, to: uri, options, metadata }); } - deleteFile(uri: vscode.Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean; }): void { - this._edits.push({ _type: 1, from: uri, to: undefined, options }); + deleteFile(uri: vscode.Uri, options?: { recursive?: boolean, ignoreIfNotExists?: boolean; }, metadata?: vscode.WorkspaceEditMetadata): void { + this._edits.push({ _type: 1, from: uri, to: undefined, options, metadata }); } - replace(uri: URI, range: Range, newText: string): void { - this._edits.push({ _type: 2, uri, edit: new TextEdit(range, newText) }); + replace(uri: URI, range: Range, newText: string, metadata?: vscode.WorkspaceEditMetadata): void { + this._edits.push({ _type: 2, uri, edit: new TextEdit(range, newText), metadata }); } - insert(resource: URI, position: Position, newText: string): void { - this.replace(resource, new Range(position, position), newText); + insert(resource: URI, position: Position, newText: string, metadata?: vscode.WorkspaceEditMetadata): void { + this.replace(resource, new Range(position, position), newText, metadata); } - delete(resource: URI, range: Range): void { - this.replace(resource, range, ''); + delete(resource: URI, range: Range, metadata?: vscode.WorkspaceEditMetadata): void { + this.replace(resource, range, '', metadata); } has(uri: URI): boolean { @@ -663,18 +664,22 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit { return values(textEdits); } - _allEntries(): ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] { - const res: ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] = []; - for (let edit of this._edits) { - if (edit._type === 1) { - res.push([edit.from, edit.to, edit.options]); - } else { - res.push([edit.uri, edit.edit]); - } - } - return res; + allEntries(): ReadonlyArray { + return this._edits; } + // _allEntries(): ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] { + // const res: ([URI, TextEdit] | [URI?, URI?, IFileOperationOptions?])[] = []; + // for (let edit of this._edits) { + // if (edit._type === 1) { + // res.push([edit.from, edit.to, edit.options]); + // } else { + // res.push([edit.uri, edit.edit]); + // } + // } + // return res; + // } + get size(): number { return this.entries().length; } diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index d940701e611..25bf62c4691 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import * as types from 'vs/workbench/api/common/extHostTypes'; import { isWindows } from 'vs/base/common/platform'; -import { isObject } from 'vs/base/common/types'; +import { assertType } from 'vs/base/common/types'; function assertToJSON(a: any, expected: any) { const raw = JSON.stringify(a); @@ -384,33 +384,22 @@ suite('ExtHostTypes', function () { edit.replace(URI.parse('foo:a'), new types.Range(2, 1, 2, 1), 'bar'); edit.replace(URI.parse('foo:b'), new types.Range(3, 1, 3, 1), 'bazz'); - const all = edit._allEntries(); + const all = edit.allEntries(); assert.equal(all.length, 4); - function isFileChange(thing: [URI, types.TextEdit] | [URI?, URI?, { overwrite?: boolean }?]): thing is [URI?, URI?, { overwrite?: boolean }?] { - const [f, s] = thing; - return URI.isUri(f) && URI.isUri(s); - } - - function isTextChange(thing: [URI, types.TextEdit] | [URI?, URI?, { overwrite?: boolean }?]): thing is [URI, types.TextEdit] { - const [f, s] = thing; - return URI.isUri(f) && isObject(s); - } - const [first, second, third, fourth] = all; - assert.equal(first[0]!.toString(), 'foo:a'); - assert.ok(!isFileChange(first)); - assert.ok(isTextChange(first)); + assertType(first._type === 2); + assert.equal(first.uri.toString(), 'foo:a'); - assert.equal(second[0]!.toString(), 'foo:a'); - assert.ok(isFileChange(second)); + assertType(second._type === 1); + assert.equal(second.from!.toString(), 'foo:a'); + assert.equal(second.to!.toString(), 'foo:b'); - assert.equal(third[0]!.toString(), 'foo:a'); - assert.ok(isTextChange(third)); + assertType(third._type === 2); + assert.equal(third.uri.toString(), 'foo:a'); - assert.equal(fourth[0]!.toString(), 'foo:b'); - assert.ok(!isFileChange(fourth)); - assert.ok(isTextChange(fourth)); + assertType(fourth._type === 2); + assert.equal(fourth.uri.toString(), 'foo:b'); }); test('WorkspaceEdit - two edits for one resource', function () { @@ -419,10 +408,13 @@ suite('ExtHostTypes', function () { edit.insert(uri, new types.Position(0, 0), 'Hello'); edit.insert(uri, new types.Position(0, 0), 'Foo'); - assert.equal(edit._allEntries().length, 2); - let [first, second] = edit._allEntries(); - assert.equal((first as [URI, types.TextEdit])[1].newText, 'Hello'); - assert.equal((second as [URI, types.TextEdit])[1].newText, 'Foo'); + assert.equal(edit.allEntries().length, 2); + let [first, second] = edit.allEntries(); + + assertType(first._type === 2); + assertType(second._type === 2); + assert.equal(first.edit.newText, 'Hello'); + assert.equal(second.edit.newText, 'Foo'); }); test('DocumentLink', () => {