Skip to content

Commit

Permalink
debt - use new EditorContent menu for "Open Workspace" (#158741) (#…
Browse files Browse the repository at this point in the history
…159844)

* debt - use new `EditorContent` menu for "Open Workspace" (#158741)

* Update src/vs/workbench/contrib/workspaces/browser/workspaces.contribution.ts

Co-authored-by: John Murray <johnm@georgejames.com>

Co-authored-by: John Murray <johnm@georgejames.com>
  • Loading branch information
bpasero and gjsjohnmurray committed Sep 2, 2022
1 parent 9b99454 commit 0edaded
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 111 deletions.
2 changes: 1 addition & 1 deletion src/vs/platform/workspace/common/workspace.ts
Expand Up @@ -406,7 +406,7 @@ export function toWorkspaceFolder(resource: URI): WorkspaceFolder {
}

export const WORKSPACE_EXTENSION = 'code-workspace';
const WORKSPACE_SUFFIX = `.${WORKSPACE_EXTENSION}`;
export const WORKSPACE_SUFFIX = `.${WORKSPACE_EXTENSION}`;
export const WORKSPACE_FILTER = [{ name: localize('codeWorkspace', "Code Workspace"), extensions: [WORKSPACE_EXTENSION] }];
export const UNTITLED_WORKSPACE_NAME = 'workspace.json';

Expand Down
101 changes: 1 addition & 100 deletions src/vs/workbench/browser/codeeditor.ts
Expand Up @@ -12,13 +12,9 @@ import { $, append, clearNode } from 'vs/base/browser/dom';
import { attachStylerCallback } from 'vs/platform/theme/common/styler';
import { buttonBackground, buttonForeground, editorBackground, editorForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { hasWorkspaceFileExtension, isTemporaryWorkspace, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { Disposable, DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { isEqual } from 'vs/base/common/resources';
import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IRange } from 'vs/editor/common/core/range';
Expand Down Expand Up @@ -253,98 +249,3 @@ export class FloatingClickMenu extends Disposable implements IEditorContribution
renderMenuAsFloatingClickBtn();
}
}

export class OpenWorkspaceButtonContribution extends Disposable implements IEditorContribution {

static get(editor: ICodeEditor): OpenWorkspaceButtonContribution | null {
return editor.getContribution<OpenWorkspaceButtonContribution>(OpenWorkspaceButtonContribution.ID);
}

public static readonly ID = 'editor.contrib.openWorkspaceButton';

private openWorkspaceButton: FloatingClickWidget | undefined;

constructor(
private editor: ICodeEditor,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IHostService private readonly hostService: IHostService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IFileService private readonly fileService: IFileService
) {
super();

this.update();
this.registerListeners();
}

private registerListeners(): void {
this._register(this.editor.onDidChangeModel(e => this.update()));
}

private update(): void {
if (!this.shouldShowButton(this.editor)) {
this.disposeOpenWorkspaceWidgetRenderer();
return;
}

this.createOpenWorkspaceWidgetRenderer();
}

private shouldShowButton(editor: ICodeEditor): boolean {
const model = editor.getModel();
if (!model) {
return false; // we need a model
}

if (!hasWorkspaceFileExtension(model.uri)) {
return false; // we need a workspace file
}

if (!this.fileService.hasProvider(model.uri)) {
return false; // needs to be backed by a file service
}

if (isTemporaryWorkspace(this.contextService.getWorkspace())) {
return false; // unsupported in temporary workspaces
}

if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
const workspaceConfiguration = this.contextService.getWorkspace().configuration;
if (workspaceConfiguration && isEqual(workspaceConfiguration, model.uri)) {
return false; // already inside workspace
}
}

if (editor.getOption(EditorOption.inDiffEditor)) {
// in diff editor
return false;
}

return true;
}

private createOpenWorkspaceWidgetRenderer(): void {
if (!this.openWorkspaceButton) {
this.openWorkspaceButton = this.instantiationService.createInstance(FloatingClickWidget, this.editor, localize('openWorkspace', "Open Workspace"), null);
this._register(this.openWorkspaceButton.onClick(() => {
const model = this.editor.getModel();
if (model) {
this.hostService.openWindow([{ workspaceUri: model.uri }]);
}
}));

this.openWorkspaceButton.render();
}
}

private disposeOpenWorkspaceWidgetRenderer(): void {
dispose(this.openWorkspaceButton);
this.openWorkspaceButton = undefined;
}

override dispose(): void {
this.disposeOpenWorkspaceWidgetRenderer();

super.dispose();
}
}
13 changes: 8 additions & 5 deletions src/vs/workbench/browser/contextkeys.ts
Expand Up @@ -7,14 +7,14 @@ import { Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext, IsMacContext, IsLinuxContext, IsWindowsContext, IsWebContext, IsMacNativeContext, IsDevelopmentContext, IsIOSContext, ProductQualityContext } from 'vs/platform/contextkey/common/contextkeys';
import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext } from 'vs/workbench/common/contextkeys';
import { SplitEditorsVertically, InEditorZenModeContext, ActiveEditorCanRevertContext, ActiveEditorGroupLockedContext, ActiveEditorCanSplitInGroupContext, SideBySideEditorActiveContext, AuxiliaryBarVisibleContext, SideBarVisibleContext, PanelAlignmentContext, PanelMaximizedContext, PanelVisibleContext, ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, EditorTabsVisibleContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext, ActiveEditorReadonlyContext, EditorAreaVisibleContext, ActiveEditorAvailableEditorIdsContext, DirtyWorkingCopiesContext, EmptyWorkspaceSupportContext, EnterMultiRootWorkspaceSupportContext, HasWebFileSystemAccess, IsFullscreenContext, OpenFolderWorkspaceSupportContext, RemoteNameContext, VirtualWorkspaceContext, WorkbenchStateContext, WorkspaceFolderCountContext, PanelPositionContext, TemporaryWorkspaceContext } from 'vs/workbench/common/contextkeys';
import { TEXT_DIFF_EDITOR_ID, EditorInputCapabilities, SIDE_BY_SIDE_EDITOR_ID, DEFAULT_EDITOR_ASSOCIATION } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { WorkbenchState, IWorkspaceContextService, isTemporaryWorkspace } from 'vs/platform/workspace/common/workspace';
import { IWorkbenchLayoutService, Parts, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { getRemoteName } from 'vs/platform/remote/common/remoteHosts';
import { getVirtualWorkspaceScheme } from 'vs/platform/workspace/common/virtualWorkspace';
Expand Down Expand Up @@ -59,6 +59,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
private emptyWorkspaceSupportContext: IContextKey<boolean>;

private virtualWorkspaceContext: IContextKey<string>;
private temporaryWorkspaceContext: IContextKey<boolean>;

private inZenModeContext: IContextKey<boolean>;
private isFullscreenContext: IContextKey<boolean>;
Expand Down Expand Up @@ -99,7 +100,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.remoteAuthority) || '');

this.virtualWorkspaceContext = VirtualWorkspaceContext.bindTo(this.contextKeyService);
this.updateVirtualWorkspaceContextKey();
this.temporaryWorkspaceContext = TemporaryWorkspaceContext.bindTo(this.contextKeyService);
this.updateWorkspaceContextKeys();

// Capabilities
HasWebFileSystemAccess.bindTo(this.contextKeyService).set(WebFileSystemAccess.supported(window));
Expand Down Expand Up @@ -225,7 +227,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateWorkbenchStateContextKey()));
this._register(this.contextService.onDidChangeWorkspaceFolders(() => {
this.updateWorkspaceFolderCountContextKey();
this.updateVirtualWorkspaceContextKey();
this.updateWorkspaceContextKeys();
}));

this._register(this.configurationService.onDidChangeConfiguration(e => {
Expand Down Expand Up @@ -363,7 +365,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.sideBarVisibleContext.set(this.layoutService.isVisible(Parts.SIDEBAR_PART));
}

private updateVirtualWorkspaceContextKey(): void {
private updateWorkspaceContextKeys(): void {
this.virtualWorkspaceContext.set(getVirtualWorkspaceScheme(this.contextService.getWorkspace()) || '');
this.temporaryWorkspaceContext.set(isTemporaryWorkspace(this.contextService.getWorkspace()));
}
}
3 changes: 1 addition & 2 deletions src/vs/workbench/browser/parts/editor/editor.contribution.ts
Expand Up @@ -54,7 +54,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
import { ContextKeyExpr, ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { isMacintosh } from 'vs/base/common/platform';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { FloatingClickMenu, OpenWorkspaceButtonContribution } from 'vs/workbench/browser/codeeditor';
import { FloatingClickMenu } from 'vs/workbench/browser/codeeditor';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { EditorAutoSave } from 'vs/workbench/browser/parts/editor/editorAutoSave';
Expand Down Expand Up @@ -128,7 +128,6 @@ Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).regi
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DynamicEditorConfigurations, 'DynamicEditorConfigurations', LifecyclePhase.Ready);

registerEditorContribution(FloatingClickMenu.ID, FloatingClickMenu);
registerEditorContribution(OpenWorkspaceButtonContribution.ID, OpenWorkspaceButtonContribution);

//#endregion

Expand Down
4 changes: 3 additions & 1 deletion src/vs/workbench/common/contextkeys.ts
Expand Up @@ -24,7 +24,9 @@ export const EmptyWorkspaceSupportContext = new RawContextKey<boolean>('emptyWor
export const DirtyWorkingCopiesContext = new RawContextKey<boolean>('dirtyWorkingCopies', false, localize('dirtyWorkingCopies', "Whether there are any working copies with unsaved changes"));

export const RemoteNameContext = new RawContextKey<string>('remoteName', '', localize('remoteName', "The name of the remote the window is connected to or an empty string if not connected to any remote"));
export const VirtualWorkspaceContext = new RawContextKey<string>('virtualWorkspace', '', localize('virtualWorkspace', "The scheme of the current workspace if is from a virtual file system or an empty string."));

export const VirtualWorkspaceContext = new RawContextKey<string>('virtualWorkspace', '', localize('virtualWorkspace', "The scheme of the current workspace is from a virtual file system or an empty string."));
export const TemporaryWorkspaceContext = new RawContextKey<boolean>('temporaryWorkspace', false, localize('temporaryWorkspace', "The scheme of the current workspace is from a temporary file system."));

export const IsFullscreenContext = new RawContextKey<boolean>('isFullscreen', false, localize('isFullscreen', "Whether the window is in fullscreen mode"));

Expand Down
Expand Up @@ -7,16 +7,21 @@ import { localize } from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { hasWorkspaceFileExtension, IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { hasWorkspaceFileExtension, IWorkspaceContextService, WorkbenchState, WORKSPACE_SUFFIX } from 'vs/platform/workspace/common/workspace';
import { Disposable } from 'vs/base/common/lifecycle';
import { IFileService } from 'vs/platform/files/common/files';
import { INeverShowAgainOptions, INotificationService, NeverShowAgainScope, Severity } from 'vs/platform/notification/common/notification';
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
import { isEqual, joinPath } from 'vs/base/common/resources';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IQuickInputService, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { isVirtualWorkspace } from 'vs/platform/workspace/common/virtualWorkspace';
import { Action2, MenuId, registerAction2 } from 'vs/platform/actions/common/actions';
import { ServicesAccessor } from 'vs/editor/browser/editorExtensions';
import { ActiveEditorContext, ResourceContextKey, TemporaryWorkspaceContext } from 'vs/workbench/common/contextkeys';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { TEXT_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files';

/**
* A workbench contribution that will look for `.code-workspace` files in the root of the
Expand Down Expand Up @@ -90,3 +95,40 @@ export class WorkspacesFinderContribution extends Disposable implements IWorkben
}

Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(WorkspacesFinderContribution, 'WorkspacesFinderContribution', LifecyclePhase.Eventually);

// Render "Open Workspace" button in *.code-workspace files

registerAction2(class extends Action2 {
constructor() {
super({
id: 'workbench.action.openWorkspaceFromEditor',
title: { original: 'Open Workspace', value: localize('openWorkspace', "Open Workspace") },
f1: false,
menu: {
id: MenuId.EditorContent,
when: ContextKeyExpr.and(
ResourceContextKey.Extension.isEqualTo(WORKSPACE_SUFFIX),
ActiveEditorContext.isEqualTo(TEXT_FILE_EDITOR_ID),
TemporaryWorkspaceContext.toNegated()
)
}
});
}

async run(accessor: ServicesAccessor, uri: URI): Promise<void> {
const hostService = accessor.get(IHostService);
const contextService = accessor.get(IWorkspaceContextService);
const notificationService = accessor.get(INotificationService);

if (contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
const workspaceConfiguration = contextService.getWorkspace().configuration;
if (workspaceConfiguration && isEqual(workspaceConfiguration, uri)) {
notificationService.info(localize('alreadyOpen', "This workspace is already open."));

return; // workspace already opened
}
}

return hostService.openWindow([{ workspaceUri: uri }]);
}
});

0 comments on commit 0edaded

Please sign in to comment.