diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 49b565156ac7e..7fbdec2f64284 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -8764,6 +8764,10 @@ declare module 'vscode' { /** * The [command](#Command) that should be executed when the tree item is selected. + * + * Please use `vscode.open` or `vscode.diff` as command IDs when the tree item is opening + * something in the editor. Using these commands ensures that the resulting editor will + * appear consistent with how other built-in trees open editors. */ command?: Command; diff --git a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts index 4af72559d2889..bcf31a1a7a8d4 100644 --- a/src/vs/workbench/api/browser/mainThreadCustomEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadCustomEditors.ts @@ -23,8 +23,7 @@ import { IUndoRedoService, UndoRedoElementType } from 'vs/platform/undoRedo/comm import { MainThreadWebviewPanels } from 'vs/workbench/api/browser/mainThreadWebviewPanels'; import { MainThreadWebviews, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor'; -import { IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor'; +import { editorGroupToViewColumn, IRevertOptions, ISaveOptions } from 'vs/workbench/common/editor'; import { CustomEditorInput } from 'vs/workbench/contrib/customEditor/browser/customEditorInput'; import { CustomDocumentBackupData } from 'vs/workbench/contrib/customEditor/browser/customEditorInputFactory'; import { ICustomEditorModel, ICustomEditorService } from 'vs/workbench/contrib/customEditor/common/customEditor'; diff --git a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts index c92a58c2709f7..ed55ed547b129 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts @@ -19,9 +19,8 @@ import { MainThreadDocuments } from 'vs/workbench/api/browser/mainThreadDocument import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor'; import { MainThreadTextEditors } from 'vs/workbench/api/browser/mainThreadEditors'; import { ExtHostContext, ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IExtHostContext, IModelAddedData, ITextEditorAddData, MainContext } from 'vs/workbench/api/common/extHost.protocol'; -import { EditorViewColumn, editorGroupToViewColumn } from 'vs/workbench/api/common/shared/editor'; import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor'; -import { IEditorPane } from 'vs/workbench/common/editor'; +import { editorGroupToViewColumn, EditorGroupColumn, IEditorPane } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -443,7 +442,7 @@ export class MainThreadDocumentsAndEditors { }; } - private _findEditorPosition(editor: MainThreadTextEditor): EditorViewColumn | undefined { + private _findEditorPosition(editor: MainThreadTextEditor): EditorGroupColumn | undefined { for (const editorPane of this._editorService.visibleEditorPanes) { if (editor.matches(editorPane)) { return editorGroupToViewColumn(this._editorGroupService, editorPane.group); diff --git a/src/vs/workbench/api/browser/mainThreadEditors.ts b/src/vs/workbench/api/browser/mainThreadEditors.ts index 441f6c68c707b..1723f63286645 100644 --- a/src/vs/workbench/api/browser/mainThreadEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadEditors.ts @@ -16,16 +16,12 @@ import { ISingleEditOperation } from 'vs/editor/common/model'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ITextEditorOptions, IResourceEditorInput, EditorActivation } from 'vs/platform/editor/common/editor'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IOpenerService } from 'vs/platform/opener/common/opener'; import { MainThreadDocumentsAndEditors } from 'vs/workbench/api/browser/mainThreadDocumentsAndEditors'; import { MainThreadTextEditor } from 'vs/workbench/api/browser/mainThreadEditor'; import { ExtHostContext, ExtHostEditorsShape, IApplyEditsOptions, IExtHostContext, ITextDocumentShowOptions, ITextEditorConfigurationUpdate, ITextEditorPositionData, IUndoStopOptions, MainThreadTextEditorsShape, TextEditorRevealType, IWorkspaceEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol'; -import { EditorViewColumn, editorGroupToViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; +import { editorGroupToViewColumn, EditorGroupColumn, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkingCopyService } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { revive } from 'vs/base/common/marshalling'; @@ -161,7 +157,7 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { return this._documentsAndEditors.findTextEditorIdFor(editor); } - async $tryShowEditor(id: string, position?: EditorViewColumn): Promise { + async $tryShowEditor(id: string, position?: EditorGroupColumn): Promise { const mainThreadEditor = this._documentsAndEditors.getEditor(id); if (mainThreadEditor) { const model = mainThreadEditor.getModel(); @@ -297,60 +293,6 @@ export class MainThreadTextEditors implements MainThreadTextEditorsShape { // --- commands -CommandsRegistry.registerCommand('_workbench.open', async function (accessor: ServicesAccessor, args: [URI, ITextEditorOptions | undefined, EditorViewColumn | undefined, string | undefined]) { - const editorService = accessor.get(IEditorService); - const editorGroupService = accessor.get(IEditorGroupsService); - const openerService = accessor.get(IOpenerService); - - let [resource, options, position, label] = args; - resource = URI.revive(resource); - - if (options || typeof position === 'number') { - // use editor options or editor view column as a hint to use the editor service for opening - await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, position)); - return; - } - - if (resource && resource.scheme === 'command') { - // do not allow to execute commands from here - return; - - } - // finally, delegate to opener service - await openerService.open(resource); -}); - -CommandsRegistry.registerCommand('_workbench.openWith', (accessor: ServicesAccessor, args: [URI, string, ITextEditorOptions | undefined, EditorViewColumn | undefined]) => { - const editorService = accessor.get(IEditorService); - const editorGroupsService = accessor.get(IEditorGroupsService); - const configurationService = accessor.get(IConfigurationService); - const quickInputService = accessor.get(IQuickInputService); - - const [resource, id, options, position] = args; - - const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, position)) ?? editorGroupsService.activeGroup; - const textOptions: ITextEditorOptions = options ? { ...options, override: false } : { override: false }; - - const input = editorService.createEditorInput({ resource }); - return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService); -}); - - -CommandsRegistry.registerCommand('_workbench.diff', async function (accessor: ServicesAccessor, args: [URI, URI, string, string, ITextEditorOptions | undefined, EditorViewColumn | undefined]) { - const editorService = accessor.get(IEditorService); - const editorGroupService = accessor.get(IEditorGroupsService); - - let [leftResource, rightResource, label, description, options, position] = args; - - if (!options || typeof options !== 'object') { - options = { - preserveFocus: false - }; - } - - await editorService.openEditor({ leftResource: URI.revive(leftResource), rightResource: URI.revive(rightResource), label, description, options }, viewColumnToEditorGroup(editorGroupService, position)); -}); - CommandsRegistry.registerCommand('_workbench.revertAllDirty', async function (accessor: ServicesAccessor) { const environmentService = accessor.get(IEnvironmentService); if (!environmentService.extensionTestsLocationURI) { diff --git a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts index 561e3c219eb59..6428e6f488cc9 100644 --- a/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts +++ b/src/vs/workbench/api/browser/mainThreadWebviewPanels.ts @@ -9,8 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { MainThreadWebviews, reviveWebviewExtension, reviveWebviewOptions } from 'vs/workbench/api/browser/mainThreadWebviews'; import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol'; -import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; -import { IEditorInput } from 'vs/workbench/common/editor'; +import { editorGroupToViewColumn, EditorGroupColumn, IEditorInput, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import { WebviewIcons } from 'vs/workbench/contrib/webview/browser/webview'; import { WebviewInput } from 'vs/workbench/contrib/webviewPanel/browser/webviewEditorInput'; @@ -150,7 +149,7 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc handle: extHostProtocol.WebviewHandle, viewType: string, title: string, - showOptions: { viewColumn?: EditorViewColumn, preserveFocus?: boolean; }, + showOptions: { viewColumn?: EditorGroupColumn, preserveFocus?: boolean; }, options: WebviewInputOptions ): void { const mainThreadShowOptions: ICreateWebViewShowOptions = Object.create(null); diff --git a/src/vs/workbench/api/common/apiCommands.ts b/src/vs/workbench/api/common/apiCommands.ts index eaf1c90ec2d2d..1da3eef641646 100644 --- a/src/vs/workbench/api/common/apiCommands.ts +++ b/src/vs/workbench/api/common/apiCommands.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { CommandsRegistry, ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; +import { EditorGroupColumn } from 'vs/workbench/common/editor'; import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { IOpenWindowOptions, IWindowOpenable, IOpenEmptyWindowOptions } from 'vs/platform/windows/common/windows'; @@ -114,7 +114,7 @@ export class OpenAPICommand { public static readonly ID = 'vscode.open'; public static execute(executor: ICommandsExecutor, resource: URI, columnOrOptions?: vscode.ViewColumn | typeConverters.TextEditorOpenOptions, label?: string): Promise { let options: ITextEditorOptions | undefined; - let position: EditorViewColumn | undefined; + let position: EditorGroupColumn | undefined; if (columnOrOptions) { if (typeof columnOrOptions === 'number') { @@ -139,7 +139,7 @@ export class OpenWithAPICommand { public static readonly ID = 'vscode.openWith'; public static execute(executor: ICommandsExecutor, resource: URI, viewType: string, columnOrOptions?: vscode.ViewColumn | typeConverters.TextEditorOpenOptions): Promise { let options: ITextEditorOptions | undefined; - let position: EditorViewColumn | undefined; + let position: EditorGroupColumn | undefined; if (typeof columnOrOptions === 'number') { position = typeConverters.ViewColumn.from(columnOrOptions); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 2d70cd338f803..638e9f29ca6a5 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -36,7 +36,6 @@ import * as statusbar from 'vs/workbench/services/statusbar/common/statusbar'; import { ClassifiedEvent, GDPRClassification, StrictPropertyCheck } from 'vs/platform/telemetry/common/gdprTypings'; import { ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import * as tasks from 'vs/workbench/api/common/shared/tasks'; import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; import { IAdapterDescriptor, IConfig, IDebugSessionReplMode } from 'vs/workbench/contrib/debug/common/debug'; @@ -45,7 +44,7 @@ import { ITerminalDimensions, IShellLaunchConfig, ITerminalLaunchError } from 'v import { ActivationKind, ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as search from 'vs/workbench/services/search/common/search'; -import { SaveReason } from 'vs/workbench/common/editor'; +import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor'; import { ExtensionActivationReason } from 'vs/workbench/api/common/extHostExtensionActivator'; import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService'; import { TunnelOptions } from 'vs/platform/remote/common/tunnel'; @@ -263,7 +262,7 @@ export interface IApplyEditsOptions extends IUndoStopOptions { } export interface ITextDocumentShowOptions { - position?: EditorViewColumn; + position?: EditorGroupColumn; preserveFocus?: boolean; pinned?: boolean; selection?: IRange; @@ -277,7 +276,7 @@ export interface MainThreadTextEditorsShape extends IDisposable { $tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise; $registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void; $removeTextEditorDecorationType(key: string): void; - $tryShowEditor(id: string, position: EditorViewColumn): Promise; + $tryShowEditor(id: string, position: EditorGroupColumn): Promise; $tryHideEditor(id: string): Promise; $trySetOptions(id: string, options: ITextEditorConfigurationUpdate): Promise; $trySetDecorations(id: string, key: string, ranges: editorCommon.IDecorationOptions[]): Promise; @@ -597,7 +596,7 @@ export interface ExtHostEditorInsetsShape { export type WebviewHandle = string; export interface WebviewPanelShowOptions { - readonly viewColumn?: EditorViewColumn; + readonly viewColumn?: EditorGroupColumn; readonly preserveFocus?: boolean; } @@ -661,7 +660,7 @@ export interface WebviewPanelViewStateData { [handle: string]: { readonly active: boolean; readonly visible: boolean; - readonly position: EditorViewColumn; + readonly position: EditorGroupColumn; }; } @@ -673,11 +672,11 @@ export interface ExtHostWebviewsShape { export interface ExtHostWebviewPanelsShape { $onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void; $onDidDisposeWebviewPanel(handle: WebviewHandle): Promise; - $deserializeWebviewPanel(newWebviewHandle: WebviewHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; + $deserializeWebviewPanel(newWebviewHandle: WebviewHandle, viewType: string, title: string, state: any, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise; } export interface ExtHostCustomEditorsShape { - $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise; + $resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewHandle, viewType: string, title: string, position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise; $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>; $disposeCustomDocument(resource: UriComponents, viewType: string): Promise; @@ -1006,10 +1005,10 @@ export interface ITextEditorAddData { options: IResolvedTextEditorConfiguration; selections: ISelection[]; visibleRanges: IRange[]; - editorPosition: EditorViewColumn | undefined; + editorPosition: EditorGroupColumn | undefined; } export interface ITextEditorPositionData { - [id: string]: EditorViewColumn; + [id: string]: EditorGroupColumn; } export interface IEditorPropertiesChangeData { options: IResolvedTextEditorConfiguration | null; diff --git a/src/vs/workbench/api/common/extHostCustomEditors.ts b/src/vs/workbench/api/common/extHostCustomEditors.ts index f3b3cbd84383e..becd0887e19d4 100644 --- a/src/vs/workbench/api/common/extHostCustomEditors.ts +++ b/src/vs/workbench/api/common/extHostCustomEditors.ts @@ -15,7 +15,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths'; import { ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview'; import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; +import { EditorGroupColumn } from 'vs/workbench/common/editor'; import type * as vscode from 'vscode'; import { Cache } from './cache'; import * as extHostProtocol from './extHost.protocol'; @@ -252,7 +252,7 @@ export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditor handle: extHostProtocol.WebviewHandle, viewType: string, title: string, - position: EditorViewColumn, + position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken, ): Promise { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index ee870895848c5..f68ee495a271e 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -7,13 +7,12 @@ import * as modes from 'vs/editor/common/modes'; import * as types from './extHostTypes'; import * as search from 'vs/workbench/contrib/search/common/search'; import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import { IDecorationOptions, IThemeDecorationRenderOptions, IDecorationRenderOptions, IContentDecorationRenderOptions } from 'vs/editor/common/editorCommon'; import { EndOfLineSequence, TrackedRangeStickiness } from 'vs/editor/common/model'; import type * as vscode from 'vscode'; import { URI, UriComponents } from 'vs/base/common/uri'; import { ProgressLocation as MainProgressLocation } from 'vs/platform/progress/common/progress'; -import { SaveReason } from 'vs/workbench/common/editor'; +import { EditorGroupColumn, SaveReason } from 'vs/workbench/common/editor'; import { IPosition } from 'vs/editor/common/core/position'; import * as editorRange from 'vs/editor/common/core/range'; import { ISelection } from 'vs/editor/common/core/selection'; @@ -220,7 +219,7 @@ export namespace DiagnosticSeverity { } export namespace ViewColumn { - export function from(column?: vscode.ViewColumn): EditorViewColumn { + export function from(column?: vscode.ViewColumn): EditorGroupColumn { if (typeof column === 'number' && column >= types.ViewColumn.One) { return column - 1; // adjust zero index (ViewColumn.ONE => 0) } @@ -232,12 +231,12 @@ export namespace ViewColumn { return ACTIVE_GROUP; // default is always the active group } - export function to(position: EditorViewColumn): vscode.ViewColumn { + export function to(position: EditorGroupColumn): vscode.ViewColumn { if (typeof position === 'number' && position >= 0) { return position + 1; // adjust to index (ViewColumn.ONE => 1) } - throw new Error(`invalid 'EditorViewColumn'`); + throw new Error(`invalid 'EditorGroupColumn'`); } } diff --git a/src/vs/workbench/api/common/extHostWebviewPanels.ts b/src/vs/workbench/api/common/extHostWebviewPanels.ts index d29fdc631fab8..797702b887f76 100644 --- a/src/vs/workbench/api/common/extHostWebviewPanels.ts +++ b/src/vs/workbench/api/common/extHostWebviewPanels.ts @@ -12,7 +12,7 @@ import { IExtensionDescription } from 'vs/platform/extensions/common/extensions' import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { convertWebviewOptions, ExtHostWebview, ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview'; import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; +import { EditorGroupColumn } from 'vs/workbench/common/editor'; import type * as vscode from 'vscode'; import * as extHostProtocol from './extHost.protocol'; import * as extHostTypes from './extHostTypes'; @@ -273,7 +273,7 @@ export class ExtHostWebviewPanels implements extHostProtocol.ExtHostWebviewPanel viewType: string, title: string, state: any, - position: EditorViewColumn, + position: EditorGroupColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions ): Promise { const entry = this._serializers.get(viewType); diff --git a/src/vs/workbench/api/common/shared/editor.ts b/src/vs/workbench/api/common/shared/editor.ts deleted file mode 100644 index 247c9b17880e9..0000000000000 --- a/src/vs/workbench/api/common/shared/editor.ts +++ /dev/null @@ -1,39 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IEditorGroupsService, IEditorGroup, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { GroupIdentifier } from 'vs/workbench/common/editor'; -import { ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; - -export type EditorViewColumn = number; - -export function viewColumnToEditorGroup(editorGroupService: IEditorGroupsService, position?: EditorViewColumn): GroupIdentifier { - if (typeof position !== 'number' || position === ACTIVE_GROUP) { - return ACTIVE_GROUP; // prefer active group when position is undefined or passed in as such - } - - const groups = editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE); - - let candidate = groups[position]; - if (candidate) { - return candidate.id; // found direct match - } - - let firstGroup = groups[0]; - if (groups.length === 1 && firstGroup.count === 0) { - return firstGroup.id; // first editor should always open in first group independent from position provided - } - - return SIDE_GROUP; // open to the side if group not found or we are instructed to -} - -export function editorGroupToViewColumn(editorGroupService: IEditorGroupsService, editorGroup: IEditorGroup | GroupIdentifier): EditorViewColumn { - const group = (typeof editorGroup === 'number') ? editorGroupService.getGroup(editorGroup) : editorGroup; - if (!group) { - throw new Error('Invalid group provided'); - } - - return editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE).indexOf(group); -} \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/editor/editorCommands.ts b/src/vs/workbench/browser/parts/editor/editorCommands.ts index 8eb81049a38ff..4eff9ef8b1407 100644 --- a/src/vs/workbench/browser/parts/editor/editorCommands.ts +++ b/src/vs/workbench/browser/parts/editor/editorCommands.ts @@ -7,14 +7,14 @@ import * as nls from 'vs/nls'; import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder } from 'vs/workbench/common/editor'; -import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, viewColumnToEditorGroup, EditorGroupColumn } from 'vs/workbench/common/editor'; +import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes'; -import { URI } from 'vs/base/common/uri'; +import { URI, UriComponents } from 'vs/base/common/uri'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; -import { IListService } from 'vs/platform/list/browser/listService'; +import { IListService, IOpenEvent } from 'vs/platform/list/browser/listService'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { distinct, coalesce } from 'vs/base/common/arrays'; import { IEditorGroupsService, IEditorGroup, GroupDirection, GroupLocation, GroupsOrder, preferredSideBySideGroupDirection, EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -25,6 +25,8 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import { ITextEditorOptions } from 'vs/platform/editor/common/editor'; +import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith'; export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors'; export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup'; @@ -64,6 +66,10 @@ export const FOCUS_BELOW_GROUP_WITHOUT_WRAP_COMMAND_ID = 'workbench.action.focus export const OPEN_EDITOR_AT_INDEX_COMMAND_ID = 'workbench.action.openEditorAtIndex'; +export const API_OPEN_EDITOR_COMMAND_ID = '_workbench.open'; +export const API_OPEN_DIFF_EDITOR_COMMAND_ID = '_workbench.diff'; +export const API_OPEN_WITH_EDITOR_COMMAND_ID = '_workbench.openWith'; + export interface ActiveEditorMoveArguments { to: 'first' | 'last' | 'left' | 'right' | 'up' | 'down' | 'center' | 'position' | 'previous' | 'next'; by: 'tab' | 'group'; @@ -388,6 +394,84 @@ function registerDiffEditorCommands(): void { }); } +function registerOpenEditorAPICommands(): void { + + function mixinContext(context: IOpenEvent | undefined, options: ITextEditorOptions | undefined, column: EditorGroupColumn | undefined): [ITextEditorOptions | undefined, EditorGroupColumn | undefined] { + if (!context) { + return [options, column]; + } + + return [ + { ...(options ?? Object.create(null)), ...context.editorOptions }, + context.sideBySide ? SIDE_GROUP : column + ]; + } + + CommandsRegistry.registerCommand(API_OPEN_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, payload: [UriComponents, ITextEditorOptions | undefined, EditorGroupColumn | undefined, string | undefined], context?: IOpenEvent) { + const editorService = accessor.get(IEditorService); + const editorGroupService = accessor.get(IEditorGroupsService); + const openerService = accessor.get(IOpenerService); + + const [resourceArg, optionsArg, columnArg, label] = payload; + const resource = URI.revive(resourceArg); + + // use editor options or editor view column as a hint to use the editor service for opening + if (optionsArg || typeof columnArg === 'number') { + const [options, column] = mixinContext(context, optionsArg, columnArg); + + await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, column)); + } + + // do not allow to execute commands from here + else if (resource.scheme === 'command') { + return; + } + + // finally, delegate to opener service + else { + await openerService.open(resource, { openToSide: context?.sideBySide, editorOptions: context?.editorOptions }); + } + }); + + CommandsRegistry.registerCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, payload: [UriComponents, UriComponents, string, string, ITextEditorOptions | undefined, EditorGroupColumn | undefined], context?: IOpenEvent) { + const editorService = accessor.get(IEditorService); + const editorGroupService = accessor.get(IEditorGroupsService); + + let [leftResource, rightResource, label, description, optionsArg, columnArg] = payload; + + if (!optionsArg || typeof optionsArg !== 'object') { + optionsArg = { + preserveFocus: false + }; + } + + const [options, column] = mixinContext(context, optionsArg, columnArg); + + await editorService.openEditor({ + leftResource: URI.revive(leftResource), + rightResource: URI.revive(rightResource), + label, + description, + options + }, viewColumnToEditorGroup(editorGroupService, column)); + }); + + CommandsRegistry.registerCommand(API_OPEN_WITH_EDITOR_COMMAND_ID, (accessor: ServicesAccessor, payload: [UriComponents, string, ITextEditorOptions | undefined, EditorGroupColumn | undefined]) => { + const editorService = accessor.get(IEditorService); + const editorGroupsService = accessor.get(IEditorGroupsService); + const configurationService = accessor.get(IConfigurationService); + const quickInputService = accessor.get(IQuickInputService); + + const [resource, id, optionsArg, columnArg] = payload; + + const group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup; + const textOptions: ITextEditorOptions = optionsArg ? { ...optionsArg, override: false } : { override: false }; + + const input = editorService.createEditorInput({ resource: URI.revive(resource) }); + return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService); + }); +} + function registerOpenEditorAtIndexCommands(): void { const openEditorAtIndex: ICommandHandler = (accessor: ServicesAccessor, editorIndex: number): void => { const editorService = accessor.get(IEditorService); @@ -966,6 +1050,7 @@ export function setup(): void { registerActiveEditorMoveCommand(); registerEditorGroupsLayoutCommand(); registerDiffEditorCommands(); + registerOpenEditorAPICommands(); registerOpenEditorAtIndexCommands(); registerCloseEditorCommands(); registerOtherEditorCommands(); diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index f567d044e2e71..39778e10d7a0f 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -14,13 +14,13 @@ import { IInstantiationService, IConstructorSignature0, ServicesAccessor, Brande import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { Registry } from 'vs/platform/registry/common/platform'; import { ITextModel } from 'vs/editor/common/model'; -import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; +import { GroupsOrder, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ICompositeControl, IComposite } from 'vs/workbench/common/composite'; import { ActionRunner, IAction } from 'vs/base/common/actions'; import { IFileService } from 'vs/platform/files/common/files'; import { IPathData } from 'vs/platform/windows/common/windows'; import { coalesce, firstOrDefault } from 'vs/base/common/arrays'; -import { IResourceEditorInputType } from 'vs/workbench/services/editor/common/editorService'; +import { ACTIVE_GROUP, IResourceEditorInputType, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { IRange } from 'vs/editor/common/core/range'; import { IExtUri } from 'vs/base/common/resources'; @@ -1572,3 +1572,44 @@ export function computeEditorAriaLabel(input: IEditorInput, index: number | unde return ariaLabel; } + + +//#region Editor Group Column + +/** + * A way to address editor groups through a column based system + * where `0` is the first column. Will fallback to `SIDE_GROUP` + * in case the column does not exist yet. + */ +export type EditorGroupColumn = number; + +export function viewColumnToEditorGroup(editorGroupService: IEditorGroupsService, viewColumn?: EditorGroupColumn): GroupIdentifier { + if (typeof viewColumn !== 'number' || viewColumn === ACTIVE_GROUP) { + return ACTIVE_GROUP; // prefer active group when position is undefined or passed in as such + } + + const groups = editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE); + + let candidateGroup = groups[viewColumn]; + if (candidateGroup) { + return candidateGroup.id; // found direct match + } + + let firstGroup = groups[0]; + if (groups.length === 1 && firstGroup.count === 0) { + return firstGroup.id; // first editor should always open in first group independent from position provided + } + + return SIDE_GROUP; // open to the side if group not found or we are instructed to +} + +export function editorGroupToViewColumn(editorGroupService: IEditorGroupsService, editorGroup: IEditorGroup | GroupIdentifier): EditorGroupColumn { + const group = (typeof editorGroup === 'number') ? editorGroupService.getGroup(editorGroup) : editorGroup; + if (!group) { + throw new Error('Invalid group provided'); + } + + return editorGroupService.getGroups(GroupsOrder.GRID_APPEARANCE).indexOf(group); +} + +//#endregion diff --git a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts index f91e70ba6129f..970b76a7ba828 100644 --- a/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts +++ b/src/vs/workbench/contrib/notebook/browser/diff/notebookDiffActions.ts @@ -7,8 +7,7 @@ import { IBulkEditService, ResourceTextEdit } from 'vs/editor/browser/services/b import { localize } from 'vs/nls'; import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions'; import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; -import { ActiveEditorContext } from 'vs/workbench/common/editor'; +import { ActiveEditorContext, viewColumnToEditorGroup } from 'vs/workbench/common/editor'; import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel'; import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor'; import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput'; diff --git a/src/vs/workbench/contrib/views/browser/treeView.ts b/src/vs/workbench/contrib/views/browser/treeView.ts index 1f03a2b9bbca1..71a99598f5b61 100644 --- a/src/vs/workbench/contrib/views/browser/treeView.ts +++ b/src/vs/workbench/contrib/views/browser/treeView.ts @@ -45,6 +45,7 @@ import { IHoverDelegate, IHoverDelegateOptions } from 'vs/base/browser/ui/iconLa import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IIconLabelMarkdownString } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { renderMarkdownAsPlaintext } from 'vs/base/browser/markdownRenderer'; +import { API_OPEN_DIFF_EDITOR_COMMAND_ID, API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands'; class Root implements ITreeItem { label = { label: 'root' }; @@ -462,8 +463,16 @@ export class TreeView extends Disposable implements ITreeView { return; } const selection = this.tree!.getSelection(); - if ((selection.length === 1) && selection[0].command) { - this.commandService.executeCommand(selection[0].command.id, ...(selection[0].command.arguments || [])); + const command = selection.length === 1 ? selection[0].command : undefined; + if (command) { + let args = command.arguments || []; + if (command.id === API_OPEN_EDITOR_COMMAND_ID || command.id === API_OPEN_DIFF_EDITOR_COMMAND_ID) { + // Some commands owned by us should receive the + // `IOpenEvent` as context to open properly + args = [...args, e]; + } + + this.commandService.executeCommand(command.id, ...args); } })); diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 851734c7d2e55..c54ec57ee84df 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -21,16 +21,6 @@ export const enum GroupDirection { RIGHT } -export function preferredSideBySideGroupDirection(configurationService: IConfigurationService): GroupDirection.DOWN | GroupDirection.RIGHT { - const openSideBySideDirection = configurationService.getValue<'right' | 'down'>('workbench.editor.openSideBySideDirection'); - - if (openSideBySideDirection === 'down') { - return GroupDirection.DOWN; - } - - return GroupDirection.RIGHT; -} - export const enum GroupOrientation { HORIZONTAL, VERTICAL @@ -595,3 +585,18 @@ export interface IEditorGroup { */ focus(): void; } + + +//#region Editor Group Helpers + +export function preferredSideBySideGroupDirection(configurationService: IConfigurationService): GroupDirection.DOWN | GroupDirection.RIGHT { + const openSideBySideDirection = configurationService.getValue<'right' | 'down'>('workbench.editor.openSideBySideDirection'); + + if (openSideBySideDirection === 'down') { + return GroupDirection.DOWN; + } + + return GroupDirection.RIGHT; +} + +//#endregion diff --git a/src/vs/workbench/test/browser/api/extHostWebview.test.ts b/src/vs/workbench/test/browser/api/extHostWebview.test.ts index 577b61c1747ca..32854e82cad37 100644 --- a/src/vs/workbench/test/browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/browser/api/extHostWebview.test.ts @@ -14,7 +14,7 @@ import { NullApiDeprecationService } from 'vs/workbench/api/common/extHostApiDep import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels'; -import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; +import { EditorGroupColumn } from 'vs/workbench/common/editor'; import type * as vscode from 'vscode'; import { SingleProxyRPCProtocol } from './testRPCProtocol'; @@ -53,7 +53,7 @@ suite('ExtHostWebview', () => { const serializerARegistration = extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerA); - await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {}); + await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorGroupColumn, {}); assert.strictEqual(lastInvokedDeserializer, serializerA); assert.throws( @@ -64,7 +64,7 @@ suite('ExtHostWebview', () => { extHostWebviewPanels.registerWebviewPanelSerializer(extension, viewType, serializerB); - await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorViewColumn, {}); + await extHostWebviewPanels.$deserializeWebviewPanel('x', viewType, 'title', {}, 0 as EditorGroupColumn, {}); assert.strictEqual(lastInvokedDeserializer, serializerB); });