From 1ed110b6be47c2cb9ba1f162c2cfc20fed4c990a Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Thu, 20 Apr 2023 18:00:12 +0200 Subject: [PATCH] Return resulting `URI` from commands that save the active editor (fix #178713) (#179091) * Return resulting `URI` from commands that save the active editor (fix #178713) * :lipstick: * address feedback * change to real proposed API * cleanup --- extensions/vscode-api-tests/package.json | 1 + .../src/singlefolder-tests/workspace.test.ts | 43 ++++++++++++++++++- .../api/browser/mainThreadWorkspace.ts | 32 +++++++++++++- .../workbench/api/common/extHost.api.impl.ts | 8 ++++ .../workbench/api/common/extHost.protocol.ts | 2 + .../workbench/api/common/extHostWorkspace.ts | 12 ++++++ .../test/browser/editSessions.test.ts | 2 +- .../contrib/files/browser/fileCommands.ts | 17 ++++---- .../services/editor/browser/editorService.ts | 11 +++-- .../services/editor/common/editorService.ts | 21 ++++++--- .../editor/test/browser/editorService.test.ts | 16 ++++--- .../common/extensionsApiProposals.ts | 1 + .../workingCopyBackupTracker.ts | 2 +- .../test/browser/workbenchTestServices.ts | 6 +-- .../vscode.proposed.saveEditor.d.ts | 30 +++++++++++++ 15 files changed, 173 insertions(+), 31 deletions(-) create mode 100644 src/vscode-dts/vscode.proposed.saveEditor.d.ts diff --git a/extensions/vscode-api-tests/package.json b/extensions/vscode-api-tests/package.json index 94ba38957a5..16655a6202c 100644 --- a/extensions/vscode-api-tests/package.json +++ b/extensions/vscode-api-tests/package.json @@ -25,6 +25,7 @@ "portsAttributes", "quickPickSortByLabel", "resolvers", + "saveEditor", "scmActionButton", "scmSelectedProvider", "scmTextDocument", diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts index ce245f31116..6e0c8e59404 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.test.ts @@ -1171,7 +1171,6 @@ suite('vscode API - workspace', () => { assert.deepStrictEqual(edt.selections, [new vscode.Selection(0, 0, 0, 3)]); }); - test('Support creating binary files in a WorkspaceEdit', async function (): Promise { const fileUri = vscode.Uri.parse(`${testFs.scheme}:/${rndName()}`); @@ -1187,4 +1186,46 @@ suite('vscode API - workspace', () => { assert.deepStrictEqual(actual, data); }); + + test('saveAll', async () => { + await testSave(true); + }); + + test('save', async () => { + await testSave(false); + }); + + async function testSave(saveAll: boolean) { + const file = await createRandomFile(); + const disposables: vscode.Disposable[] = []; + + await revertAllDirty(); // needed for a clean state for `onDidSaveTextDocument` (#102365) + + const onDidSaveTextDocument = new Set(); + + disposables.push(vscode.workspace.onDidSaveTextDocument(e => { + onDidSaveTextDocument.add(e); + })); + + const doc = await vscode.workspace.openTextDocument(file); + await vscode.window.showTextDocument(doc); + + if (saveAll) { + const edit = new vscode.WorkspaceEdit(); + edit.insert(doc.uri, new vscode.Position(0, 0), 'Hello World'); + + await vscode.workspace.applyEdit(edit); + assert.ok(doc.isDirty); + + await vscode.workspace.saveAll(false); // requires dirty documents + } else { + const res = await vscode.workspace.save(doc.uri); // enforces to save even when not dirty + assert.ok(res?.toString() === doc.uri.toString()); + } + + assert.ok(onDidSaveTextDocument); + assert.ok(Array.from(onDidSaveTextDocument).find(e => e.uri.toString() === file.toString()), 'did Save: ' + file.toString()); + disposeAll(disposables); + return deleteFile(file); + } }); diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index 48931201010..55cecb6cd4f 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -21,11 +21,13 @@ import { IWorkspace, IWorkspaceContextService, WorkbenchState, isUntitledWorkspa import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers'; import { checkGlobFileExists } from 'vs/workbench/services/extensions/common/workspaceContains'; import { ITextQueryBuilderOptions, QueryBuilder } from 'vs/workbench/services/search/common/queryBuilder'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService'; import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { ExtHostContext, ExtHostWorkspaceShape, ITextSearchComplete, IWorkspaceData, MainContext, MainThreadWorkspaceShape } from '../common/extHost.protocol'; import { IEditSessionIdentityService } from 'vs/platform/workspace/common/editSessions'; +import { EditorResourceAccessor, SaveReason, SideBySideEditor } from 'vs/workbench/common/editor'; +import { coalesce, firstOrDefault } from 'vs/base/common/arrays'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -201,8 +203,34 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- save & edit resources --- + async $save(uriComponents: UriComponents): Promise { + const uri = URI.revive(uriComponents); + + const editors = [...this._editorService.findEditors(uri, { supportSideBySide: SideBySideEditor.PRIMARY })]; + const result = await this._editorService.save(editors, { reason: SaveReason.EXPLICIT, force: true /* force save even when non-dirty */ }); + + return firstOrDefault(this.saveResultToUris(result)); + } + + async $saveAs(uriComponents: UriComponents): Promise { + const uri = URI.revive(uriComponents); + + const editors = [...this._editorService.findEditors(uri, { supportSideBySide: SideBySideEditor.PRIMARY })]; + const result = await this._editorService.save(editors, { reason: SaveReason.EXPLICIT, saveAs: true }); + + return firstOrDefault(this.saveResultToUris(result)); + } + + private saveResultToUris(result: ISaveEditorsResult): URI[] { + if (!result.success) { + return []; + } + + return coalesce(result.editors.map(editor => EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.PRIMARY }))); + } + $saveAll(includeUntitled?: boolean): Promise { - return this._editorService.saveAll({ includeUntitled }); + return this._editorService.saveAll({ includeUntitled }).then(res => res.success); } $resolveProxy(url: string): Promise { diff --git a/src/vs/workbench/api/common/extHost.api.impl.ts b/src/vs/workbench/api/common/extHost.api.impl.ts index 8e66edb74ca..ce3dcc74026 100644 --- a/src/vs/workbench/api/common/extHost.api.impl.ts +++ b/src/vs/workbench/api/common/extHost.api.impl.ts @@ -893,6 +893,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I return extHostWorkspace.findTextInFiles(query, options || {}, callback, extension.identifier, token); }, + save: (uri) => { + checkProposedApiEnabled(extension, 'saveEditor'); + return extHostWorkspace.save(uri); + }, + saveAs: (uri) => { + checkProposedApiEnabled(extension, 'saveEditor'); + return extHostWorkspace.saveAs(uri); + }, saveAll: (includeUntitled?) => { return extHostWorkspace.saveAll(includeUntitled); }, diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index db6380db3a8..cab1774b57f 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -1169,6 +1169,8 @@ export interface MainThreadWorkspaceShape extends IDisposable { $startFileSearch(includePattern: string | null, includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise; $startTextSearch(query: search.IPatternInfo, folder: UriComponents | null, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise; $checkExists(folders: readonly UriComponents[], includes: string[], token: CancellationToken): Promise; + $save(uri: UriComponents): Promise; + $saveAs(uri: UriComponents): Promise; $saveAll(includeUntitled?: boolean): Promise; $updateWorkspaceFolders(extensionName: string, index: number, deleteCount: number, workspaceFoldersToAdd: { uri: UriComponents; name?: string }[]): Promise; $resolveProxy(url: string): Promise; diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index c0516ab8604..88069f0fb2d 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -557,6 +557,18 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac this._activeSearchCallbacks[requestId]?.(result); } + async save(uri: URI): Promise { + const result = await this._proxy.$save(uri); + + return URI.revive(result); + } + + async saveAs(uri: URI): Promise { + const result = await this._proxy.$saveAs(uri); + + return URI.revive(result); + } + saveAll(includeUntitled?: boolean): Promise { return this._proxy.$saveAll(includeUntitled); } diff --git a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts index 0898688d094..15efba18fcf 100644 --- a/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts +++ b/src/vs/workbench/contrib/editSessions/test/browser/editSessions.test.ts @@ -130,7 +130,7 @@ suite('Edit session sync', () => { override registerTextModelContentProvider = () => ({ dispose: () => { } }); }); instantiationService.stub(IEditorService, new class extends mock() { - override saveAll = async (_options: ISaveAllEditorsOptions) => true; + override saveAll = async (_options: ISaveAllEditorsOptions) => { return { success: true, editors: [] }; }; }); instantiationService.stub(IEditSessionIdentityService, new class extends mock() { override async getEditSessionIdentifier() { diff --git a/src/vs/workbench/contrib/files/browser/fileCommands.ts b/src/vs/workbench/contrib/files/browser/fileCommands.ts index c6dedeb0e43..0c38f6f266b 100644 --- a/src/vs/workbench/contrib/files/browser/fileCommands.ts +++ b/src/vs/workbench/contrib/files/browser/fileCommands.ts @@ -309,7 +309,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: undefined, primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyP), id: 'workbench.action.files.copyPathOfActiveFile', - handler: async (accessor) => { + handler: async accessor => { const editorService = accessor.get(IEditorService); const activeInput = editorService.activeEditor; const resource = EditorResourceAccessor.getOriginalUri(activeInput, { supportSideBySide: SideBySideEditor.PRIMARY }); @@ -491,7 +491,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KeyS }, win: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyS) }, id: SAVE_ALL_COMMAND_ID, - handler: (accessor) => { + handler: accessor => { return saveDirtyEditorsOfGroups(accessor, accessor.get(IEditorGroupsService).getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE), { reason: SaveReason.EXPLICIT }); } }); @@ -516,10 +516,11 @@ CommandsRegistry.registerCommand({ CommandsRegistry.registerCommand({ id: SAVE_FILES_COMMAND_ID, - handler: accessor => { + handler: async accessor => { const editorService = accessor.get(IEditorService); - return editorService.saveAll({ includeUntitled: false, reason: SaveReason.EXPLICIT }); + const res = await editorService.saveAll({ includeUntitled: false, reason: SaveReason.EXPLICIT }); + return res.success; } }); @@ -580,7 +581,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext.negate()), primary: KeyCode.LeftArrow, id: PREVIOUS_COMPRESSED_FOLDER, - handler: (accessor) => { + handler: accessor => { const paneCompositeService = accessor.get(IPaneCompositePartService); const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); @@ -599,7 +600,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerCompressedFocusContext, ExplorerCompressedLastFocusContext.negate()), primary: KeyCode.RightArrow, id: NEXT_COMPRESSED_FOLDER, - handler: (accessor) => { + handler: accessor => { const paneCompositeService = accessor.get(IPaneCompositePartService); const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); @@ -618,7 +619,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerCompressedFocusContext, ExplorerCompressedFirstFocusContext.negate()), primary: KeyCode.Home, id: FIRST_COMPRESSED_FOLDER, - handler: (accessor) => { + handler: accessor => { const paneCompositeService = accessor.get(IPaneCompositePartService); const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); @@ -637,7 +638,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ when: ContextKeyExpr.and(FilesExplorerFocusCondition, ExplorerCompressedFocusContext, ExplorerCompressedLastFocusContext.negate()), primary: KeyCode.End, id: LAST_COMPRESSED_FOLDER, - handler: (accessor) => { + handler: accessor => { const paneCompositeService = accessor.get(IPaneCompositePartService); const viewlet = paneCompositeService.getActivePaneComposite(ViewContainerLocation.Sidebar); diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index 6253b7d7431..4f4d475b589 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -15,7 +15,7 @@ import { URI } from 'vs/base/common/uri'; import { joinPath } from 'vs/base/common/resources'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, IEditorReplacement, isEditorReplacement, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IUntypedEditorReplacement, IEditorService, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorsOptions, PreferredGroup, isPreferredGroup, IEditorsChangeEvent } from 'vs/workbench/services/editor/common/editorService'; +import { IUntypedEditorReplacement, IEditorService, ISaveEditorsOptions, ISaveAllEditorsOptions, IRevertAllEditorsOptions, IBaseSaveRevertAllEditorOptions, IOpenEditorsOptions, PreferredGroup, isPreferredGroup, IEditorsChangeEvent, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService'; import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Disposable, IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; import { coalesce, distinct } from 'vs/base/common/arrays'; @@ -894,7 +894,7 @@ export class EditorService extends Disposable implements EditorServiceImpl { //#region save/revert - async save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { + async save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { // Convert to array if (!Array.isArray(editors)) { @@ -973,10 +973,13 @@ export class EditorService extends Disposable implements EditorServiceImpl { } } - return saveResults.every(result => !!result); + return { + success: saveResults.every(result => !!result), + editors: coalesce(saveResults) + }; } - saveAll(options?: ISaveAllEditorsOptions): Promise { + saveAll(options?: ISaveAllEditorsOptions): Promise { return this.save(this.getAllDirtyEditors(options), options); } diff --git a/src/vs/workbench/services/editor/common/editorService.ts b/src/vs/workbench/services/editor/common/editorService.ts index 73b2331c6ff..243f682eb18 100644 --- a/src/vs/workbench/services/editor/common/editorService.ts +++ b/src/vs/workbench/services/editor/common/editorService.ts @@ -43,6 +43,19 @@ export interface ISaveEditorsOptions extends ISaveOptions { readonly saveAs?: boolean; } +export interface ISaveEditorsResult { + + /** + * Whether the save operation was successful. + */ + readonly success: boolean; + + /** + * Resulting editors after the save operation. + */ + readonly editors: Array; +} + export interface IUntypedEditorReplacement { /** @@ -293,17 +306,13 @@ export interface IEditorService { /** * Save the provided list of editors. - * - * @returns `true` if all editors saved and `false` otherwise. */ - save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise; + save(editors: IEditorIdentifier | IEditorIdentifier[], options?: ISaveEditorsOptions): Promise; /** * Save all editors. - * - * @returns `true` if all editors saved and `false` otherwise. */ - saveAll(options?: ISaveAllEditorsOptions): Promise; + saveAll(options?: ISaveAllEditorsOptions): Promise; /** * Reverts the provided list of editors. diff --git a/src/vs/workbench/services/editor/test/browser/editorService.test.ts b/src/vs/workbench/services/editor/test/browser/editorService.test.ts index fb23ed1feee..91854520e43 100644 --- a/src/vs/workbench/services/editor/test/browser/editorService.test.ts +++ b/src/vs/workbench/services/editor/test/browser/editorService.test.ts @@ -2068,7 +2068,9 @@ suite('EditorService', () => { await service.openEditor(input2, { pinned: true }); await service.openEditor(sameInput1, { pinned: true }, SIDE_GROUP); - await service.save({ groupId: rootGroup.id, editor: input1 }); + const res1 = await service.save({ groupId: rootGroup.id, editor: input1 }); + assert.strictEqual(res1.success, true); + assert.strictEqual(res1.editors[0], input1); assert.strictEqual(input1.gotSaved, true); input1.gotSaved = false; @@ -2079,7 +2081,9 @@ suite('EditorService', () => { input2.dirty = true; sameInput1.dirty = true; - await service.save({ groupId: rootGroup.id, editor: input1 }, { saveAs: true }); + const res2 = await service.save({ groupId: rootGroup.id, editor: input1 }, { saveAs: true }); + assert.strictEqual(res2.success, true); + assert.strictEqual(res2.editors[0], input1); assert.strictEqual(input1.gotSavedAs, true); input1.gotSaved = false; @@ -2102,8 +2106,9 @@ suite('EditorService', () => { input2.dirty = true; sameInput1.dirty = true; - const saveRes = await service.saveAll(); - assert.strictEqual(saveRes, true); + const res3 = await service.saveAll(); + assert.strictEqual(res3.success, true); + assert.strictEqual(res3.editors.length, 2); assert.strictEqual(input1.gotSaved, true); assert.strictEqual(input2.gotSaved, true); @@ -2161,7 +2166,8 @@ suite('EditorService', () => { sameInput1.dirty = true; const saveRes = await service.saveAll({ excludeSticky: true }); - assert.strictEqual(saveRes, true); + assert.strictEqual(saveRes.success, true); + assert.strictEqual(saveRes.editors.length, 2); assert.strictEqual(input1.gotSaved, false); assert.strictEqual(input2.gotSaved, true); assert.strictEqual(sameInput1.gotSaved, true); diff --git a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts index 8085ebef643..8739a178f4e 100644 --- a/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts +++ b/src/vs/workbench/services/extensions/common/extensionsApiProposals.ts @@ -62,6 +62,7 @@ export const allApiProposals = Object.freeze({ quickPickItemTooltip: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickItemTooltip.d.ts', quickPickSortByLabel: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.quickPickSortByLabel.d.ts', resolvers: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.resolvers.d.ts', + saveEditor: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.saveEditor.d.ts', scmActionButton: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmActionButton.d.ts', scmSelectedProvider: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmSelectedProvider.d.ts', scmTextDocument: 'https://raw.githubusercontent.com/microsoft/vscode/main/src/vscode-dts/vscode.proposed.scmTextDocument.d.ts', diff --git a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts index 6994989e01d..7fcce30fdba 100644 --- a/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts +++ b/src/vs/workbench/services/workingCopy/electron-sandbox/workingCopyBackupTracker.ts @@ -319,7 +319,7 @@ export class NativeWorkingCopyBackupTracker extends WorkingCopyBackupTracker imp let result: boolean | undefined = undefined; if (typeof arg1 === 'boolean' || dirtyWorkingCopies.length === this.workingCopyService.dirtyCount) { - result = await this.editorService.saveAll({ includeUntitled: typeof arg1 === 'boolean' ? arg1 : true, ...saveOptions }); + result = (await this.editorService.saveAll({ includeUntitled: typeof arg1 === 'boolean' ? arg1 : true, ...saveOptions })).success; } // If we still have dirty working copies, save those directly diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index efcae100a18..38646a14f85 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -53,7 +53,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IDecorationsService, IResourceDecorationChangeEvent, IDecoration, IDecorationData, IDecorationsProvider } from 'vs/workbench/services/decorations/common/decorations'; import { IDisposable, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupsArrangement, GroupDirection, IAddGroupOptions, IMergeGroupOptions, IEditorReplacement, IFindGroupScope, EditorGroupLayout, ICloseEditorOptions, GroupOrientation, ICloseAllEditorsOptions, ICloseEditorsFilter } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, PreferredGroup, IEditorsChangeEvent } from 'vs/workbench/services/editor/common/editorService'; +import { IEditorService, ISaveEditorsOptions, IRevertAllEditorsOptions, PreferredGroup, IEditorsChangeEvent, ISaveEditorsResult } from 'vs/workbench/services/editor/common/editorService'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IEditorPaneRegistry, EditorPaneDescriptor } from 'vs/workbench/browser/editor'; import { Dimension, IDimension } from 'vs/base/browser/dom'; @@ -997,8 +997,8 @@ export class TestEditorService implements EditorServiceImpl { isOpened(_editor: IResourceEditorInputIdentifier): boolean { return false; } isVisible(_editor: EditorInput): boolean { return false; } replaceEditors(_editors: any, _group: any) { return Promise.resolve(undefined); } - save(editors: IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } - saveAll(options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } + save(editors: IEditorIdentifier[], options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } + saveAll(options?: ISaveEditorsOptions): Promise { throw new Error('Method not implemented.'); } revert(editors: IEditorIdentifier[], options?: IRevertOptions): Promise { throw new Error('Method not implemented.'); } revertAll(options?: IRevertAllEditorsOptions): Promise { throw new Error('Method not implemented.'); } } diff --git a/src/vscode-dts/vscode.proposed.saveEditor.d.ts b/src/vscode-dts/vscode.proposed.saveEditor.d.ts new file mode 100644 index 00000000000..9b113aad70c --- /dev/null +++ b/src/vscode-dts/vscode.proposed.saveEditor.d.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +// https://github.com/microsoft/vscode/issues/178713 + +declare module 'vscode' { + + export namespace workspace { + + /** + * Saves the editor identified by the given resource and returns the resulting resource or `undefined` + * if save was not successful. + * + * @param uri the associated uri for the editor to save. + * @return A thenable that resolves when the save operation has finished. + */ + export function save(uri: Uri): Thenable; + + /** + * Saves the editor identified by the given resource to a new file name as provided by the user and + * returns the resulting resource or `undefined` if save was not successful or cancelled. + * + * @param uri the associated uri for the editor to save as. + * @return A thenable that resolves when the save-as operation has finished. + */ + export function saveAs(uri: Uri): Thenable; + } +}