Skip to content

Commit

Permalink
Support scmResourceState in when clauses
Browse files Browse the repository at this point in the history
fixes #86180

* Adds `contextValue?: string` to the SourceControlResourceState
* Allows when clause in scm/resourceState/context menus to use scmResourceState
  • Loading branch information
mjcrouch committed Feb 19, 2020
1 parent 69e0508 commit 11f523c
Show file tree
Hide file tree
Showing 7 changed files with 68 additions and 18 deletions.
26 changes: 26 additions & 0 deletions src/vs/vscode.proposed.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1734,4 +1734,30 @@ declare module 'vscode' {
}

//#endregion

//#region Support `scmResourceState` in `when` clauses #86180 https://github.com/microsoft/vscode/issues/86180

export interface SourceControlResourceState {
/**
* Context value of the resource state. This can be used to contribute resource specific actions.
* For example, if a resource is given a context value as `diffable`. When contributing actions to `scm/resourceState/context`
* using `menus` extension point, you can specify context value for key `scmResourceState` in `when` expressions, like `scmResourceState == diffable`.
* ```
* "contributes": {
* "menus": {
* "scm/resourceState/context": [
* {
* "command": "extension.diff",
* "when": "scmResourceState == diffable"
* }
* ]
* }
* }
* ```
* This will show action `extension.diff` only for resources with `contextValue` is `diffable`.
*/
readonly contextValue?: string;
}

//#endregion
}
8 changes: 5 additions & 3 deletions src/vs/workbench/api/browser/mainThreadSCM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ class MainThreadSCMResource implements ISCMResource {
private readonly handle: number,
public sourceUri: URI,
public resourceGroup: ISCMResourceGroup,
public decorations: ISCMResourceDecorations
public decorations: ISCMResourceDecorations,
public contextValue: string
) { }

open(): Promise<void> {
Expand Down Expand Up @@ -198,7 +199,7 @@ class MainThreadSCMProvider implements ISCMProvider {

for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded] = rawResource;
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
Expand All @@ -216,7 +217,8 @@ class MainThreadSCMProvider implements ISCMProvider {
handle,
URI.revive(sourceUri),
group,
decorations
decorations,
contextValue
);
});

Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -715,7 +715,8 @@ export type SCMRawResource = [
UriComponents[] /*icons: light, dark*/,
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/
boolean /*faded*/,
string /*context value*/
];

export type SCMRawResourceSplice = [
Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHostSCM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,8 +306,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const tooltip = (r.decorations && r.decorations.tooltip) || '';
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
const faded = r.decorations && !!r.decorations.faded;
const contextValue = r.contextValue || '';

const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource;
const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] as SCMRawResource;

return { rawResource, handle };
});
Expand Down
37 changes: 26 additions & 11 deletions src/vs/workbench/contrib/scm/browser/menus.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ interface ISCMResourceGroupMenuEntry {

interface ISCMMenus {
readonly resourceGroupMenu: IMenu;
readonly resourceMenu: IMenu;
readonly resourceFolderMenu: IMenu;
}

interface ISCMResourceMenu extends IDisposable {
readonly menu: IMenu;
}

export function getSCMResourceContextKey(resource: ISCMResourceGroup | ISCMResource): string {
return isSCMResource(resource) ? resource.resourceGroup.id : resource.id;
}
Expand Down Expand Up @@ -111,13 +114,20 @@ export class SCMMenus implements IDisposable {
return this.getActions(MenuId.SCMResourceContext, resource).secondary;
}

getResourceInlineActions(resource: ISCMResource): IAction[] {
return this.getActions(MenuId.SCMResourceContext, resource).primary;
}

getResourceFolderContextActions(group: ISCMResourceGroup): IAction[] {
return this.getActions(MenuId.SCMResourceFolderContext, group).secondary;
}

private getActions(menuId: MenuId, resource: ISCMResourceGroup | ISCMResource): { primary: IAction[]; secondary: IAction[]; } {
const contextKeyService = this.contextKeyService.createScoped();
contextKeyService.createKey('scmResourceGroup', getSCMResourceContextKey(resource));
if (isSCMResource(resource)) {
contextKeyService.createKey('scmResourceState', resource.contextValue);
}

const menu = this.menuService.createMenu(menuId, contextKeyService);
const primary: IAction[] = [];
Expand All @@ -131,20 +141,26 @@ export class SCMMenus implements IDisposable {
return result;
}

getResourceGroupMenu(group: ISCMResourceGroup): IMenu {
if (!this.resourceGroupMenus.has(group)) {
throw new Error('SCM Resource Group menu not found');
}
createResourceMenu(group: ISCMResourceGroup, resource: ISCMResource): ISCMResourceMenu {
const contextKeyService = this.contextKeyService.createScoped();
contextKeyService.createKey('scmProvider', group.provider.contextValue);
contextKeyService.createKey('scmResourceGroup', getSCMResourceContextKey(resource));
contextKeyService.createKey('scmResourceState', resource.contextValue);

return this.resourceGroupMenus.get(group)!.resourceGroupMenu;
const menu = this.menuService.createMenu(MenuId.SCMResourceContext, contextKeyService);

const disposable = combinedDisposable(menu, contextKeyService);
const dispose = () => disposable.dispose();

return { menu, dispose };
}

getResourceMenu(group: ISCMResourceGroup): IMenu {
getResourceGroupMenu(group: ISCMResourceGroup): IMenu {
if (!this.resourceGroupMenus.has(group)) {
throw new Error('SCM Resource Group menu not found');
}

return this.resourceGroupMenus.get(group)!.resourceMenu;
return this.resourceGroupMenus.get(group)!.resourceGroupMenu;
}

getResourceFolderMenu(group: ISCMResourceGroup): IMenu {
Expand All @@ -162,11 +178,10 @@ export class SCMMenus implements IDisposable {
contextKeyService.createKey('scmResourceGroup', getSCMResourceContextKey(group));

const resourceGroupMenu = this.menuService.createMenu(MenuId.SCMResourceGroupContext, contextKeyService);
const resourceMenu = this.menuService.createMenu(MenuId.SCMResourceContext, contextKeyService);
const resourceFolderMenu = this.menuService.createMenu(MenuId.SCMResourceFolderContext, contextKeyService);
const disposable = combinedDisposable(contextKeyService, resourceGroupMenu, resourceMenu, resourceFolderMenu);
const disposable = combinedDisposable(contextKeyService, resourceGroupMenu, resourceFolderMenu);

this.resourceGroupMenus.set(group, { resourceGroupMenu, resourceMenu, resourceFolderMenu });
this.resourceGroupMenus.set(group, { resourceGroupMenu, resourceFolderMenu });
return { group, disposable };
});

Expand Down
8 changes: 6 additions & 2 deletions src/vs/workbench/contrib/scm/browser/repositoryPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,9 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso

if (ResourceTree.isResourceNode(resourceOrFolder)) {
if (resourceOrFolder.element) {
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resourceOrFolder.element.resourceGroup), template.actionBar));
const menu = this.menus.createResourceMenu(resourceOrFolder.element.resourceGroup, resourceOrFolder.element);
elementDisposables.add(menu);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menu.menu, template.actionBar));
toggleClass(template.name, 'strike-through', resourceOrFolder.element.decorations.strikeThrough);
toggleClass(template.element, 'faded', resourceOrFolder.element.decorations.faded);
} else {
Expand All @@ -229,7 +231,9 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
removeClass(template.element, 'faded');
}
} else {
elementDisposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resourceOrFolder.resourceGroup), template.actionBar));
const menu = this.menus.createResourceMenu(resourceOrFolder.resourceGroup, resourceOrFolder);
elementDisposables.add(menu);
elementDisposables.add(connectPrimaryMenuToInlineActionBar(menu.menu, template.actionBar));
toggleClass(template.name, 'strike-through', resourceOrFolder.decorations.strikeThrough);
toggleClass(template.element, 'faded', resourceOrFolder.decorations.faded);
}
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/contrib/scm/common/scm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export interface ISCMResource {
readonly resourceGroup: ISCMResourceGroup;
readonly sourceUri: URI;
readonly decorations: ISCMResourceDecorations;
readonly contextValue: string
open(): Promise<void>;
}

Expand Down

0 comments on commit 11f523c

Please sign in to comment.