scoped menus

This commit is contained in:
Joao Moreno
2016-12-01 11:05:54 +01:00
parent e0e2be3384
commit 174dde2eb6
8 changed files with 61 additions and 13 deletions

View File

@@ -44,7 +44,7 @@
"when": "scm.provider == git"
}
],
"scm/context": [
"scm/git/workingTree/context": [
{
"command": "git.open-change",
"group": "navigation",

View File

@@ -55,7 +55,7 @@ async function init(disposables: Disposable[]): Promise<void> {
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}`);

View File

@@ -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);
}
}

View File

@@ -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<IMenuService>('menuService');
export interface IMenuService {

View File

@@ -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 };

View File

@@ -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;
}

View File

@@ -255,9 +255,28 @@ export class SCMViewlet extends Viewlet {
}
private onListContextMenu(e: IListMouseEvent<ISCMResourceGroup | ISCMResource>): 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)
});
}

View File

@@ -19,6 +19,7 @@ export const ISCMService = createDecorator<ISCMService>('scm');
export interface ISCMResource {
readonly uri: URI;
readonly resourceGroupId: string;
}
export interface ISCMResourceGroup {