From 174dde2eb6ba37792fa96858af7398bef5ca9bd0 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Thu, 1 Dec 2016 11:05:54 +0100 Subject: [PATCH] scoped menus --- extensions/git/package.json | 2 +- extensions/git/src/main.ts | 2 +- .../actions/browser/menusExtensionPoint.ts | 12 ++++++++-- src/vs/platform/actions/common/actions.ts | 12 +++++++++- src/vs/workbench/api/node/mainThreadSCM.ts | 2 +- .../workbench/parts/scm/browser/scmMenus.ts | 22 ++++++++++++++----- .../workbench/parts/scm/browser/scmViewlet.ts | 21 +++++++++++++++++- src/vs/workbench/services/scm/common/scm.ts | 1 + 8 files changed, 61 insertions(+), 13 deletions(-) diff --git a/extensions/git/package.json b/extensions/git/package.json index 90987f334dc..c287ce5d5b6 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -44,7 +44,7 @@ "when": "scm.provider == git" } ], - "scm/context": [ + "scm/git/workingTree/context": [ { "command": "git.open-change", "group": "navigation", diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 4e13ec9b54d..6c0b8da3c4d 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -55,7 +55,7 @@ async function init(disposables: Disposable[]): Promise { const model = new Model(repositoryRoot, repository); const provider = new GitSCMProvider(model); - provider.onDidChange(g => console.log(g)); + provider.onDidChange(g => log(g)); const outputChannel = window.createOutputChannel('git'); outputChannel.appendLine(`Using git ${info.version} from ${info.path}`); diff --git a/src/vs/platform/actions/browser/menusExtensionPoint.ts b/src/vs/platform/actions/browser/menusExtensionPoint.ts index 5cf2484f79c..27b401b4e6c 100644 --- a/src/vs/platform/actions/browser/menusExtensionPoint.ts +++ b/src/vs/platform/actions/browser/menusExtensionPoint.ts @@ -13,7 +13,7 @@ import { IJSONSchema } from 'vs/base/common/jsonSchema'; import { forEach } from 'vs/base/common/collections'; import { IExtensionPointUser, ExtensionMessageCollector, ExtensionsRegistry } from 'vs/platform/extensions/common/extensionsRegistry'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; +import { MenuId, SCMMenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; namespace schema { @@ -26,6 +26,8 @@ namespace schema { group?: string; } + const SCMMenuRegex = /^scm\/([^/]+)\/([^/]+)(\/context)?$/; + export function parseMenuId(value: string): MenuId { switch (value) { case 'editor/title': return MenuId.EditorTitle; @@ -33,7 +35,13 @@ namespace schema { case 'explorer/context': return MenuId.ExplorerContext; case 'editor/title/context': return MenuId.EditorTitleContext; case 'scm/title': return MenuId.SCMTitle; - case 'scm/context': return MenuId.SCMContext; + } + + const match = SCMMenuRegex.exec(value); + + if (match) { + const [, providerId, resourceGroupId, isContext] = match; + return new SCMMenuId(providerId, resourceGroupId, !!isContext); } } diff --git a/src/vs/platform/actions/common/actions.ts b/src/vs/platform/actions/common/actions.ts index c1a0eadd6e0..aabe0a01f36 100644 --- a/src/vs/platform/actions/common/actions.ts +++ b/src/vs/platform/actions/common/actions.ts @@ -42,7 +42,6 @@ export class MenuId { static readonly ExplorerContext = new MenuId('4'); static readonly ProblemsPanelContext = new MenuId('5'); static readonly SCMTitle = new MenuId('scm/title'); - static readonly SCMContext = new MenuId('scm/context'); constructor(private _id: string) { @@ -53,6 +52,17 @@ export class MenuId { } } +export class SCMMenuId extends MenuId { + + get providerId(): string { return this._providerId; } + get resourceGroupId(): string { return this._resourceGroupId; } + get isContext(): boolean { return this._isContext; } + + constructor(private _providerId: string, private _resourceGroupId: string, private _isContext: boolean) { + super(`scm/${_providerId}/${_resourceGroupId}${_isContext ? '/context' : ''}`); + } +} + export const IMenuService = createDecorator('menuService'); export interface IMenuService { diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index d194b60572c..b37fd4d27d5 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -89,7 +89,7 @@ class MainThreadSCMProvider implements ISCMProvider { const resources = rawResources.map(rawResource => { const [uri] = rawResource; - return { uri: URI.parse(uri) }; + return { uri: URI.parse(uri), resourceGroupId: id }; }); return { id, label, resources }; diff --git a/src/vs/workbench/parts/scm/browser/scmMenus.ts b/src/vs/workbench/parts/scm/browser/scmMenus.ts index cf4e88c312b..ae597da67d4 100644 --- a/src/vs/workbench/parts/scm/browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/browser/scmMenus.ts @@ -10,14 +10,13 @@ import Event, { mapEvent } from 'vs/base/common/event'; import { memoize } from 'vs/base/common/decorators'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions'; +import { IMenuService, MenuId, IMenu, SCMMenuId } from 'vs/platform/actions/common/actions'; import { IAction } from 'vs/base/common/actions'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; export class SCMMenus implements IDisposable { private titleMenu: IMenu; - private contextMenu: IMenu; private disposables: IDisposable[] = []; private _titleMenuActions: { primary: IAction[]; secondary: IAction[] }; @@ -34,8 +33,7 @@ export class SCMMenus implements IDisposable { @IMenuService private menuService: IMenuService ) { this.titleMenu = menuService.createMenu(MenuId.SCMTitle, contextKeyService); - this.contextMenu = menuService.createMenu(MenuId.SCMContext, contextKeyService); - this.disposables.push(this.titleMenu, this.contextMenu); + this.disposables.push(this.titleMenu); } @memoize @@ -51,9 +49,21 @@ export class SCMMenus implements IDisposable { return this.cachedTitleMenuActions.secondary; } - get context(): IAction[] { + getResourceActions(providerId: string, resourceGroupId: string): IAction[] { + const menuId = new SCMMenuId(providerId, resourceGroupId, false); + const menu = this.menuService.createMenu(menuId, this.contextKeyService); const result = []; - fillInActions(this.contextMenu, null, result); + fillInActions(menu, null, result); + menu.dispose(); + return result; + } + + getResourceContextActions(providerId: string, resourceGroupId: string): IAction[] { + const menuId = new SCMMenuId(providerId, resourceGroupId, true); + const menu = this.menuService.createMenu(menuId, this.contextKeyService); + const result = []; + fillInActions(menu, null, result); + menu.dispose(); return result; } diff --git a/src/vs/workbench/parts/scm/browser/scmViewlet.ts b/src/vs/workbench/parts/scm/browser/scmViewlet.ts index 9ee54ebb041..25640c05325 100644 --- a/src/vs/workbench/parts/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/browser/scmViewlet.ts @@ -255,9 +255,28 @@ export class SCMViewlet extends Viewlet { } private onListContextMenu(e: IListMouseEvent): void { + const provider = this.scmService.activeProvider; + + if (!provider) { + return; + } + + const element = e.element; + let resourceGroupId: string; + + if ((element as ISCMResource).uri) { + const resource = element as ISCMResource; + resourceGroupId = resource.resourceGroupId; + } else { + const resourceGroup = element as ISCMResourceGroup; + resourceGroupId = resourceGroup.id; + } + + const actions = this.menus.getResourceContextActions(provider.id, resourceGroupId); + this.contextMenuService.showContextMenu({ getAnchor: () => ({ x: e.clientX + 1, y: e.clientY }), - getActions: () => TPromise.as(this.menus.context) + getActions: () => TPromise.as(actions) }); } diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 143b4d64dcb..6223681243e 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -19,6 +19,7 @@ export const ISCMService = createDecorator('scm'); export interface ISCMResource { readonly uri: URI; + readonly resourceGroupId: string; } export interface ISCMResourceGroup {