Skip to content

Commit bf9130e

Browse files
committed
scm repository title menu
1 parent 99f3c36 commit bf9130e

4 files changed

Lines changed: 76 additions & 28 deletions

File tree

src/vs/workbench/contrib/scm/browser/media/scm.css

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -58,32 +58,35 @@
5858
font-size: 0.9em;
5959
}
6060

61-
.scm-viewlet .scm-provider > .monaco-action-bar {
61+
.scm-viewlet .scm-provider > .status {
6262
flex: 1;
63+
display: flex;
64+
padding-right: 10px;
65+
justify-content: flex-end;
66+
overflow: hidden;
6367
}
6468

65-
.scm-viewlet .scm-provider > .monaco-action-bar .action-item {
69+
.scm-viewlet .scm-provider > .status > .monaco-action-bar .action-item {
6670
margin-left: 4px;
67-
overflow: hidden;
6871
text-overflow: ellipsis;
6972
display: flex;
7073
align-items: center;
7174
min-width: 14px;
7275
}
7376

74-
.scm-viewlet .scm-provider > .monaco-action-bar .action-label {
77+
.scm-viewlet .scm-provider > .status > .monaco-action-bar .action-label {
7578
text-overflow: ellipsis;
7679
overflow: hidden;
7780
min-width: 14px; /* minimum size of icons */
7881
}
7982

80-
.scm-viewlet .scm-provider > .monaco-action-bar .action-label .codicon {
83+
.scm-viewlet .scm-provider > .status > .monaco-action-bar .action-label .codicon {
8184
font-size: 14px;
8285
vertical-align: sub;
8386
display: inline-flex;
8487
}
8588

86-
.scm-viewlet .scm-provider > .monaco-action-bar .action-item:last-of-type {
89+
.scm-viewlet .scm-provider > .status > .monaco-action-bar .action-item:last-of-type {
8790
padding-right: 0;
8891
}
8992

src/vs/workbench/contrib/scm/browser/menus.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ export function getSCMResourceContextKey(resource: ISCMResourceGroup | ISCMResou
3939
export class SCMRepositoryMenus implements IDisposable {
4040

4141
private contextKeyService: IContextKeyService;
42-
private titleMenu: IMenu;
42+
readonly titleMenu: IMenu;
4343

4444
private titleActionDisposable: IDisposable = Disposable.None;
4545
private titleActions: IAction[] = [];

src/vs/workbench/contrib/scm/browser/scmViewPane.ts

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser
2525
import { SCMMenus } from './menus';
2626
import { ActionBar, IActionViewItemProvider, Separator, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
2727
import { IThemeService, LIGHT, registerThemingParticipant, IFileIconTheme } from 'vs/platform/theme/common/themeService';
28-
import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar, isSCMRepository, isSCMInput } from './util';
28+
import { isSCMResource, isSCMResourceGroup, connectPrimaryMenuToInlineActionBar, isSCMRepository, isSCMInput, connectPrimaryMenuToInlineToolbarBar } from './util';
2929
import { attachBadgeStyler } from 'vs/platform/theme/common/styler';
3030
import { WorkbenchCompressibleObjectTree, IOpenEvent } from 'vs/platform/list/browser/listService';
3131
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
@@ -77,6 +77,7 @@ import { KeyCode } from 'vs/base/common/keyCodes';
7777
import { DEFAULT_FONT_FAMILY } from 'vs/workbench/browser/style';
7878
import { Command } from 'vs/editor/common/modes';
7979
import { renderCodicons } from 'vs/base/common/codicons';
80+
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
8081

8182
type TreeElement = ISCMRepository | ISCMInput | ISCMResourceGroup | IResourceNode<ISCMResource, ISCMResourceGroup> | ISCMResource;
8283

@@ -152,7 +153,8 @@ interface RepositoryTemplate {
152153
readonly description: HTMLElement;
153154
readonly countContainer: HTMLElement;
154155
readonly count: CountBadge;
155-
readonly actionBar: ActionBar;
156+
readonly statusActionBar: ActionBar;
157+
readonly toolBar: ToolBar;
156158
disposable: IDisposable;
157159
readonly templateDisposable: IDisposable;
158160
}
@@ -163,7 +165,10 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
163165
get templateId(): string { return RepositoryRenderer.TEMPLATE_ID; }
164166

165167
constructor(
168+
private actionViewItemProvider: IActionViewItemProvider,
169+
private menus: SCMMenus,
166170
@ICommandService private commandService: ICommandService,
171+
@IContextMenuService private contextMenuService: IContextMenuService,
167172
@IThemeService private themeService: IThemeService
168173
) { }
169174

@@ -176,14 +181,17 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
176181
const label = append(provider, $('.label'));
177182
const name = append(label, $('span.name'));
178183
const description = append(label, $('span.description'));
179-
const actionBar = new ActionBar(provider, { actionViewItemProvider: a => new StatusBarActionViewItem(a as StatusBarAction) });
184+
const status = append(provider, $('.status'));
185+
const statusActionBar = new ActionBar(status, { actionViewItemProvider: a => new StatusBarActionViewItem(a as StatusBarAction) });
186+
const actions = append(provider, $('.actions'));
187+
const toolBar = new ToolBar(actions, this.contextMenuService, { actionViewItemProvider: this.actionViewItemProvider });
180188
const countContainer = append(provider, $('.count'));
181189
const count = new CountBadge(countContainer);
182190
const badgeStyler = attachBadgeStyler(count, this.themeService);
183191
const disposable = Disposable.None;
184-
const templateDisposable = combinedDisposable(actionBar, badgeStyler);
192+
const templateDisposable = combinedDisposable(statusActionBar, toolBar, badgeStyler);
185193

186-
return { name, description, countContainer, count, actionBar, disposable, templateDisposable };
194+
return { name, description, countContainer, count, statusActionBar, toolBar, disposable, templateDisposable };
187195
}
188196

189197
renderElement(node: ITreeNode<ISCMRepository, FuzzyScore>, index: number, templateData: RepositoryTemplate, height: number | undefined): void {
@@ -209,17 +217,20 @@ class RepositoryRenderer implements ICompressibleTreeRenderer<ISCMRepository, Fu
209217

210218
const commands = repository.provider.statusBarCommands || [];
211219
actions.splice(0, actions.length, ...commands.map(c => new StatusBarAction(c, this.commandService)));
212-
templateData.actionBar.clear();
213-
templateData.actionBar.push(actions);
220+
templateData.statusActionBar.clear();
221+
templateData.statusActionBar.push(actions);
214222

215223
const count = repository.provider.count || 0;
216224
toggleClass(templateData.countContainer, 'hidden', count === 0);
217225
templateData.count.setCount(count);
218226
};
219-
220227
disposables.add(repository.provider.onDidChange(update, null));
221228
update();
222229

230+
const menus = this.menus.getRepositoryMenus(repository.provider);
231+
disposables.add(connectPrimaryMenuToInlineToolbarBar(menus.titleMenu, templateData.toolBar));
232+
templateData.toolBar.context = repository.provider;
233+
223234
templateData.disposable = disposables;
224235
}
225236

@@ -334,8 +345,8 @@ class ResourceGroupRenderer implements ICompressibleTreeRenderer<ISCMResourceGro
334345

335346
constructor(
336347
private actionViewItemProvider: IActionViewItemProvider,
337-
private themeService: IThemeService,
338-
private menus: SCMMenus
348+
private menus: SCMMenus,
349+
@IThemeService private themeService: IThemeService,
339350
) { }
340351

341352
renderTemplate(container: HTMLElement): ResourceGroupTemplate {
@@ -424,8 +435,8 @@ class ResourceRenderer implements ICompressibleTreeRenderer<ISCMResource | IReso
424435
private labels: ResourceLabels,
425436
private actionViewItemProvider: IActionViewItemProvider,
426437
private actionRunner: ActionRunner,
427-
private themeService: IThemeService,
428-
private menus: SCMMenus
438+
private menus: SCMMenus,
439+
@IThemeService private themeService: IThemeService
429440
) { }
430441

431442
renderTemplate(container: HTMLElement): ResourceTemplate {
@@ -1452,12 +1463,11 @@ export class SCMViewPane extends ViewPane {
14521463
this._register(actionRunner);
14531464
this._register(actionRunner.onDidBeforeRun(() => this.tree.domFocus()));
14541465

1455-
const inputRenderer = new InputRenderer(this.layoutCache, (input, height) => this.tree.updateElementHeight(input, height), this.instantiationService);
14561466
const renderers = [
1457-
new RepositoryRenderer(this.commandService, this.themeService),
1458-
inputRenderer,
1459-
new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus),
1460-
new ResourceRenderer(() => this.viewModel, this.listLabels, actionViewItemProvider, actionRunner, this.themeService, this.menus)
1467+
this.instantiationService.createInstance(RepositoryRenderer, actionViewItemProvider, this.menus),
1468+
this.instantiationService.createInstance(InputRenderer, this.layoutCache, (input, height) => this.tree.updateElementHeight(input, height)),
1469+
this.instantiationService.createInstance(ResourceGroupRenderer, actionViewItemProvider, this.menus),
1470+
this.instantiationService.createInstance(ResourceRenderer, () => this.viewModel, this.listLabels, actionViewItemProvider, actionRunner, this.menus)
14611471
];
14621472

14631473
const filter = new SCMTreeFilter();

src/vs/workbench/contrib/scm/browser/util.ts

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { IDisposable, Disposable, combinedDisposable, toDisposable } from 'vs/ba
1010
import { IAction } from 'vs/base/common/actions';
1111
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
1212
import { equals } from 'vs/base/common/arrays';
13+
import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
1314

1415
export function isSCMRepository(element: any): element is ISCMRepository {
1516
return !!(element as ISCMRepository).provider && typeof (element as ISCMRepository).setSelected === 'function';
@@ -27,6 +28,8 @@ export function isSCMResource(element: any): element is ISCMResource {
2728
return !!(element as ISCMResource).sourceUri && isSCMResourceGroup((element as ISCMResource).resourceGroup);
2829
}
2930

31+
const compareActions = (a: IAction, b: IAction) => a.id === b.id;
32+
3033
export function connectPrimaryMenuToInlineActionBar(menu: IMenu, actionBar: ActionBar): IDisposable {
3134
let cachedDisposable: IDisposable = Disposable.None;
3235
let cachedPrimary: IAction[] = [];
@@ -37,7 +40,7 @@ export function connectPrimaryMenuToInlineActionBar(menu: IMenu, actionBar: Acti
3740

3841
const disposable = createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, { primary, secondary }, g => /^inline/.test(g));
3942

40-
if (equals(cachedPrimary, primary, (a, b) => a.id === b.id)) {
43+
if (equals(cachedPrimary, primary, compareActions)) {
4144
disposable.dispose();
4245
return;
4346
}
@@ -51,7 +54,39 @@ export function connectPrimaryMenuToInlineActionBar(menu: IMenu, actionBar: Acti
5154

5255
updateActions();
5356

54-
return combinedDisposable(menu.onDidChange(updateActions), toDisposable(() => {
55-
cachedDisposable.dispose();
56-
}));
57+
return combinedDisposable(
58+
menu.onDidChange(updateActions),
59+
toDisposable(() => cachedDisposable.dispose())
60+
);
61+
}
62+
63+
export function connectPrimaryMenuToInlineToolbarBar(menu: IMenu, toolBar: ToolBar): IDisposable {
64+
let cachedDisposable: IDisposable = Disposable.None;
65+
let cachedPrimary: IAction[] = [];
66+
let cachedSecondary: IAction[] = [];
67+
68+
const updateActions = () => {
69+
const primary: IAction[] = [];
70+
const secondary: IAction[] = [];
71+
72+
const disposable = createAndFillInActionBarActions(menu, { shouldForwardArgs: true }, { primary, secondary });
73+
74+
if (equals(cachedPrimary, primary, compareActions) && equals(cachedSecondary, secondary, compareActions)) {
75+
disposable.dispose();
76+
return;
77+
}
78+
79+
cachedDisposable = disposable;
80+
cachedPrimary = primary;
81+
cachedSecondary = secondary;
82+
83+
toolBar.setActions(primary, secondary);
84+
};
85+
86+
updateActions();
87+
88+
return combinedDisposable(
89+
menu.onDidChange(updateActions),
90+
toDisposable(() => cachedDisposable.dispose())
91+
);
5792
}

0 commit comments

Comments
 (0)