diff --git a/extensions/git/package.json b/extensions/git/package.json index fb84e21d6ed..7fd88a4d57c 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -38,22 +38,38 @@ { "command": "git.stage", "title": "Stage", - "category": "Git" + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } }, { "command": "git.stage-all", "title": "Stage All", - "category": "Git" + "category": "Git", + "icon": { + "light": "resources/icons/light/stage.svg", + "dark": "resources/icons/dark/stage.svg" + } }, { "command": "git.unstage", "title": "Unstage", - "category": "Git" + "category": "Git", + "icon": { + "light": "resources/icons/light/unstage.svg", + "dark": "resources/icons/dark/unstage.svg" + } }, { "command": "git.unstage-all", "title": "Unstage All", - "category": "Git" + "category": "Git", + "icon": { + "light": "resources/icons/light/unstage.svg", + "dark": "resources/icons/dark/unstage.svg" + } } ], "menus": { @@ -63,24 +79,48 @@ "group": "navigation" } ], + "scm/git/index/group": [ + { + "command": "git.unstage-all", + "group": "navigation" + } + ], "scm/git/index/group/context": [ { "command": "git.unstage-all", "group": "navigation" } ], + "scm/git/index/resource": [ + { + "command": "git.unstage", + "group": "navigation" + } + ], "scm/git/index/resource/context": [ { "command": "git.unstage", "group": "navigation" } ], + "scm/git/workingTree/group": [ + { + "command": "git.stage-all", + "group": "navigation" + } + ], "scm/git/workingTree/group/context": [ { "command": "git.stage-all", "group": "navigation" } ], + "scm/git/workingTree/resource": [ + { + "command": "git.stage", + "group": "navigation" + } + ], "scm/git/workingTree/resource/context": [ { "command": "git.stage", diff --git a/extensions/git/resources/icons/dark/stage.svg b/extensions/git/resources/icons/dark/stage.svg new file mode 100644 index 00000000000..3475c1e1963 --- /dev/null +++ b/extensions/git/resources/icons/dark/stage.svg @@ -0,0 +1 @@ +Layer 1 \ No newline at end of file diff --git a/extensions/git/resources/icons/dark/unstage.svg b/extensions/git/resources/icons/dark/unstage.svg new file mode 100644 index 00000000000..2de46fcf5b5 --- /dev/null +++ b/extensions/git/resources/icons/dark/unstage.svg @@ -0,0 +1 @@ +Layer 1 \ No newline at end of file diff --git a/extensions/git/resources/icons/light/stage.svg b/extensions/git/resources/icons/light/stage.svg new file mode 100644 index 00000000000..bdecdb0e45b --- /dev/null +++ b/extensions/git/resources/icons/light/stage.svg @@ -0,0 +1 @@ +Layer 1 \ No newline at end of file diff --git a/extensions/git/resources/icons/light/unstage.svg b/extensions/git/resources/icons/light/unstage.svg new file mode 100644 index 00000000000..f5d128b2df8 --- /dev/null +++ b/extensions/git/resources/icons/light/unstage.svg @@ -0,0 +1 @@ +Layer 1 \ No newline at end of file diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 96a8a9aba2b..c4cf4bded6b 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -5,7 +5,7 @@ 'use strict'; -import { commands, Disposable } from 'vscode'; +import { commands, Disposable, SCMResourceGroup, SCMResource } from 'vscode'; import { Model } from './model'; import { log } from './util'; @@ -20,9 +20,29 @@ function openChange(...args: any[]): void { console.log('openChange', args); } +function stage(resource: SCMResource): void { + log('stage', resource); +} + +function stageAll(resourceGroup: SCMResourceGroup): void { + log('stage-all', resourceGroup); +} + +function unstage(resource: SCMResource): void { + log('unstage', resource); +} + +function unstageAll(resourceGroup: SCMResourceGroup): void { + log('unstage-all', resourceGroup); +} + export function registerCommands(model: Model): Disposable { const disposables = [ commands.registerCommand('git.refresh', refresh(model)), + commands.registerCommand('git.stage', stage), + commands.registerCommand('git.stage-all', stageAll), + commands.registerCommand('git.unstage', unstage), + commands.registerCommand('git.unstage-all', unstageAll), commands.registerCommand('git.open-change', openChange) ]; diff --git a/src/vs/workbench/parts/scm/browser/media/scmViewlet.css b/src/vs/workbench/parts/scm/browser/media/scmViewlet.css index 62bf3a862a2..398f2149b3b 100644 --- a/src/vs/workbench/parts/scm/browser/media/scmViewlet.css +++ b/src/vs/workbench/parts/scm/browser/media/scmViewlet.css @@ -29,12 +29,41 @@ font-size: 11px; font-weight: bold; text-transform: uppercase; + overflow: hidden; + text-overflow: ellipsis; } -.scm-viewlet .monaco-list-row > .resource-group > .count-badge { +.scm-viewlet .monaco-list-row > .resource-group:hover > .count { + display: none; +} + +.scm-viewlet .monaco-list-row > .resource-group:not(:hover) > .actions { + display: none; +} + +.scm-viewlet .monaco-list-row > .resource { + display: flex; +} + +.scm-viewlet .monaco-list-row > .resource > .name { flex: 1; - font-size: 11px; - font-weight: bold; - text-transform: uppercase; - cursor: default; + overflow: hidden; +} + +.scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label { + width: 100%; + overflow: hidden; + text-overflow: ellipsis; +} + +.scm-viewlet .monaco-list-row > .resource > .actions .action-label, +.scm-viewlet .monaco-list-row > .resource-group > .actions .action-label { + width: 16px; + height: 100%; + background-position: 50% 50%; + background-repeat: no-repeat; +} + +.scm-viewlet .monaco-list-row > .resource:not(:hover) > .actions { + display: none; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/browser/scmMenus.ts b/src/vs/workbench/parts/scm/browser/scmMenus.ts index 2214fda7c95..540eabce68f 100644 --- a/src/vs/workbench/parts/scm/browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/browser/scmMenus.ts @@ -63,23 +63,39 @@ export class SCMMenus implements IDisposable { return this.titleSecondaryActions; } - getResourceGroupActions(providerId: string, resourceGroupId: string): IAction[] { - const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.ResourceGroup, false); + getResourceGroupActions(resourceGroupId: string): IAction[] { + if (!this.scmService.activeProvider) { + return []; + } + + const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.ResourceGroup, false); return this.getActions(menuId); } - getResourceGroupContextActions(providerId: string, resourceGroupId: string): IAction[] { - const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.ResourceGroup, true); + getResourceGroupContextActions(resourceGroupId: string): IAction[] { + if (!this.scmService.activeProvider) { + return []; + } + + const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.ResourceGroup, true); return this.getActions(menuId); } - getResourceActions(providerId: string, resourceGroupId: string): IAction[] { - const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.Resource, false); + getResourceActions(resourceGroupId: string): IAction[] { + if (!this.scmService.activeProvider) { + return []; + } + + const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.Resource, false); return this.getActions(menuId); } - getResourceContextActions(providerId: string, resourceGroupId: string): IAction[] { - const menuId = new SCMMenuId(providerId, resourceGroupId, SCMMenuType.Resource, true); + getResourceContextActions(resourceGroupId: string): IAction[] { + if (!this.scmService.activeProvider) { + return []; + } + + const menuId = new SCMMenuId(this.scmService.activeProvider.id, resourceGroupId, SCMMenuType.Resource, true); return this.getActions(menuId); } diff --git a/src/vs/workbench/parts/scm/browser/scmViewlet.ts b/src/vs/workbench/parts/scm/browser/scmViewlet.ts index cc7216ca98e..bb02b070d7e 100644 --- a/src/vs/workbench/parts/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/browser/scmViewlet.ts @@ -34,6 +34,7 @@ import { IMenuService } from 'vs/platform/actions/common/actions'; import { IAction, IActionItem } from 'vs/base/common/actions'; import { createActionItem } from 'vs/platform/actions/browser/menuItemActionItem'; import { SCMMenus } from './scmMenus'; +import { ActionBar, IActionItemProvider } from 'vs/base/browser/ui/actionbar/actionbar'; interface SearchInputEvent extends Event { target: HTMLInputElement; @@ -43,6 +44,7 @@ interface SearchInputEvent extends Event { interface ResourceGroupTemplate { name: HTMLElement; count: CountBadge; + actionBar: ActionBar; } class ResourceGroupRenderer implements IRenderer { @@ -50,18 +52,27 @@ class ResourceGroupRenderer implements IRenderer { @@ -79,19 +91,27 @@ class ResourceRenderer implements IRenderer { get templateId(): string { return ResourceRenderer.TEMPLATE_ID; } constructor( + private scmMenus: SCMMenus, + private actionItemProvider: IActionItemProvider, @IInstantiationService private instantiationService: IInstantiationService ) { } renderTemplate(container: HTMLElement): ResourceTemplate { - const fileLabel = this.instantiationService.createInstance(FileLabel, container, void 0); + const element = append(container, $('.resource')); + const name = append(element, $('.name')); + const fileLabel = this.instantiationService.createInstance(FileLabel, name, void 0); + const actionsContainer = append(element, $('.actions')); + const actionBar = new ActionBar(actionsContainer, { actionItemProvider: this.actionItemProvider }); - return { fileLabel }; + return { fileLabel, actionBar }; } renderElement(resource: ISCMResource, index: number, template: ResourceTemplate): void { template.fileLabel.setFile(resource.uri); + template.actionBar.clear(); + template.actionBar.push(this.scmMenus.getResourceActions(resource.resourceGroupId)); } disposeTemplate(template: ResourceTemplate): void { @@ -176,9 +196,11 @@ export class SCMViewlet extends Viewlet { this.listContainer = append(root, $('.scm-status.show-file-icons')); const delegate = new Delegate(); + const actionItemProvider = action => this.getActionItem(action); + this.list = new List(this.listContainer, delegate, [ - new ResourceGroupRenderer(), - this.instantiationService.createInstance(ResourceRenderer) + new ResourceGroupRenderer(this.menus, actionItemProvider), + this.instantiationService.createInstance(ResourceRenderer, this.menus, actionItemProvider) ]); chain(this.list.onSelectionChange) @@ -254,21 +276,15 @@ export class SCMViewlet extends Viewlet { } private onListContextMenu(e: IListMouseEvent): void { - const provider = this.scmService.activeProvider; - - if (!provider) { - return; - } - const element = e.element; let actions: IAction[]; if ((element as ISCMResource).uri) { const resource = element as ISCMResource; - actions = this.menus.getResourceContextActions(provider.id, resource.resourceGroupId); + actions = this.menus.getResourceContextActions(resource.resourceGroupId); } else { const resourceGroup = element as ISCMResourceGroup; - actions = this.menus.getResourceGroupContextActions(provider.id, resourceGroup.id); + actions = this.menus.getResourceGroupContextActions(resourceGroup.id); } this.contextMenuService.showContextMenu({