From 8f7589750a2ca4872c1fe65ddbb0b40fbb4795dd Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Wed, 15 Dec 2021 14:38:07 +0100 Subject: [PATCH] Support untitled with associated resource in `vscode.open` (#139194) * wip * :lipstick: * add test * comments * skip flaky test * Revert "skip flaky test" This reverts commit 94c712500eb7973330f52107755e647a4e9069e7. --- .../src/singlefolder-tests/commands.test.ts | 8 ++++++ .../browser/parts/editor/editorCommands.ts | 27 +++++++++++++++---- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts index 27efa6f4021..48abda37adb 100644 --- a/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts +++ b/extensions/vscode-api-tests/src/singlefolder-tests/commands.test.ts @@ -116,4 +116,12 @@ suite('vscode API - commands', () => { return Promise.all([a, b, c, d]); }); + + test('api-command: vscode.open with untitled supports associated resource (#138925)', async function () { + let uri = Uri.parse(workspace.workspaceFolders![0].uri.toString() + '/far-copy.js').with({ scheme: 'untitled' }); + await commands.executeCommand('vscode.open', uri).then(() => assert.ok(true), () => assert.ok(false)); + + // untitled with associated resource are dirty from the beginning + assert.ok(window.activeTextEditor?.document.isDirty); + }); }); diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 268685c05d0..67e56171157 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -7,7 +7,7 @@ import { localize } from 'vs/nls'; import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { TextCompareEditorVisibleContext, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, GroupIdentifier, TextCompareEditorActiveContext, SideBySideEditorActiveContext, isEditorInputWithOptionsAndGroup } from 'vs/workbench/common/editor'; +import { TextCompareEditorVisibleContext, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, EditorInputCapabilities, isEditorIdentifier, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, GroupIdentifier, TextCompareEditorActiveContext, SideBySideEditorActiveContext, isEditorInputWithOptionsAndGroup, IUntitledTextResourceEditorInput } from 'vs/workbench/common/editor'; import { EditorInput } from 'vs/workbench/common/editor/editorInput'; import { EditorGroupColumn, columnToEditorGroup } from 'vs/workbench/services/editor/common/editorGroupColumn'; import { ACTIVE_GROUP_TYPE, IEditorService, SIDE_GROUP, SIDE_GROUP_TYPE } from 'vs/workbench/services/editor/common/editorService'; @@ -27,12 +27,13 @@ import { MenuRegistry, MenuId, registerAction2, Action2 } from 'vs/platform/acti import { CATEGORIES } from 'vs/workbench/common/actions'; import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess'; import { IOpenerService } from 'vs/platform/opener/common/opener'; -import { EditorResolution, IEditorOptions, ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { EditorResolution, IEditorOptions, IResourceEditorInput, ITextEditorOptions } from 'vs/platform/editor/common/editor'; import { Schemas } from 'vs/base/common/network'; import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput'; import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { IEditorResolverService } from 'vs/workbench/services/editor/common/editorResolverService'; +import { IPathService } from 'vs/workbench/services/path/common/pathService'; export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors'; export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup'; @@ -494,15 +495,31 @@ function registerOpenEditorAPICommands(): void { const editorService = accessor.get(IEditorService); const editorGroupService = accessor.get(IEditorGroupsService); const openerService = accessor.get(IOpenerService); + const pathService = accessor.get(IPathService); const resource = URI.revive(resourceArg); const [columnArg, optionsArg] = columnAndOptions ?? []; - // use editor options or editor view column as a hint to use the editor service for opening - if (optionsArg || typeof columnArg === 'number') { + // use editor options or editor view column or resource scheme + // as a hint to use the editor service for opening directly + if (optionsArg || typeof columnArg === 'number' || resource.scheme === Schemas.untitled) { const [options, column] = mixinContext(context, optionsArg, columnArg); - await editorService.openEditor({ resource, options, label }, columnToEditorGroup(editorGroupService, column)); + let input: IResourceEditorInput | IUntitledTextResourceEditorInput; + if (resource.scheme === Schemas.untitled && resource.path.length > 1) { + // special case for untitled: we are getting a resource with meaningful + // path from an extension to use for the untitled editor. as such, we + // have to assume it as an associated resource to use when saving. we + // do so by setting the `forceUntitled: true` and changing the scheme + // to a file based one. the untitled editor service takes care to + // associate the path properly then. + input = { resource: resource.with({ scheme: pathService.defaultUriScheme }), forceUntitled: true, options, label }; + } else { + // use any other resource as is + input = { resource, options, label }; + } + + await editorService.openEditor(input, columnToEditorGroup(editorGroupService, column)); } // do not allow to execute commands from here