Skip to content

Commit 5c37aff

Browse files
committed
scm menus
1 parent 4bd4261 commit 5c37aff

3 files changed

Lines changed: 96 additions & 42 deletions

File tree

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

Lines changed: 37 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
1010
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
1111
import { IAction } from 'vs/base/common/actions';
1212
import { createAndFillInContextMenuActions, createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
13-
import { ISCMResource, ISCMResourceGroup, ISCMProvider } from 'vs/workbench/contrib/scm/common/scm';
13+
import { ISCMResource, ISCMResourceGroup, ISCMProvider, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
1414
import { isSCMResource } from './util';
1515
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
1616
import { equals } from 'vs/base/common/arrays';
17-
import { ISplice } from 'vs/base/common/sequence';
17+
import { ISplice, ISequence } from 'vs/base/common/sequence';
1818
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
19-
import { memoize } from 'vs/base/common/decorators';
2019

2120
function actionEquals(a: IAction, b: IAction): boolean {
2221
return a.id === b.id;
@@ -65,8 +64,8 @@ export class SCMRepositoryMenus implements IDisposable {
6564

6665
if (provider) {
6766
scmProviderKey.set(provider.contextValue);
68-
this.onDidSpliceGroups({ start: 0, deleteCount: 0, toInsert: provider.groups.elements });
6967
provider.groups.onDidSplice(this.onDidSpliceGroups, this, this.disposables);
68+
this.onDidSpliceGroups({ start: 0, deleteCount: 0, toInsert: provider.groups.elements });
7069
} else {
7170
scmProviderKey.set('');
7271
}
@@ -188,23 +187,46 @@ export class SCMRepositoryMenus implements IDisposable {
188187

189188
export class SCMMenus {
190189

191-
private menus = new WeakMap<ISCMProvider, SCMRepositoryMenus>();
192-
193-
constructor(@IInstantiationService private instantiationService: IInstantiationService) { }
190+
private readonly disposables = new DisposableStore();
191+
private readonly entries: { repository: ISCMRepository, dispose: () => void }[] = [];
192+
private readonly menus = new Map<ISCMProvider, SCMRepositoryMenus>();
194193

195-
@memoize
196-
getDefaultMenus(): SCMRepositoryMenus {
197-
return this.instantiationService.createInstance(SCMRepositoryMenus, undefined);
194+
constructor(
195+
repositories: ISequence<ISCMRepository>,
196+
@IInstantiationService private instantiationService: IInstantiationService
197+
) {
198+
repositories.onDidSplice(this.onDidSplice, this, this.disposables);
199+
this.onDidSplice({ start: 0, deleteCount: 0, toInsert: repositories.elements });
198200
}
199201

200202
getRepositoryMenus(provider: ISCMProvider): SCMRepositoryMenus {
201-
let result = this.menus.get(provider);
203+
if (!this.menus.has(provider)) {
204+
throw new Error('SCM Repository menu not found');
205+
}
206+
207+
return this.menus.get(provider)!;
208+
}
202209

203-
if (!result) {
204-
result = this.instantiationService.createInstance(SCMRepositoryMenus, provider);
205-
this.menus.set(provider, result);
210+
private onDidSplice({ start, deleteCount, toInsert }: ISplice<ISCMRepository>): void {
211+
const entriesToInsert = toInsert.map(repository => {
212+
const menus = this.instantiationService.createInstance(SCMRepositoryMenus, repository.provider);
213+
const dispose = () => {
214+
menus.dispose();
215+
this.menus.delete(repository.provider);
216+
};
217+
218+
this.menus.set(repository.provider, menus);
219+
return { repository, dispose };
220+
});
221+
222+
const deletedEntries = this.entries.splice(start, deleteCount, ...entriesToInsert);
223+
224+
for (const entry of deletedEntries) {
225+
entry.dispose();
206226
}
227+
}
207228

208-
return result;
229+
dispose(): void {
230+
this.disposables.dispose();
209231
}
210232
}

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

Lines changed: 56 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ class ViewModel {
826826
constructor(
827827
private repositories: ISequence<ISCMRepository>,
828828
private tree: WorkbenchCompressibleObjectTree<TreeElement, FuzzyScore>,
829+
private menus: SCMMenus,
829830
private _mode: ViewModelMode,
830831
private _sortKey: ViewModelSortKey,
831832
@IEditorService protected editorService: IEditorService,
@@ -989,6 +990,40 @@ class ViewModel {
989990
}
990991
}
991992

993+
getViewActions(): IAction[] {
994+
if (this.items.length !== 1) {
995+
return [];
996+
}
997+
998+
const menus = this.menus.getRepositoryMenus(this.items[0].element.provider);
999+
return menus.getTitleActions();
1000+
}
1001+
1002+
getViewSecondaryActions(): IAction[] {
1003+
const viewAction = new SCMViewSubMenuAction(this);
1004+
1005+
if (this.items.length !== 1) {
1006+
return [viewAction];
1007+
}
1008+
1009+
const menus = this.menus.getRepositoryMenus(this.items[0].element.provider);
1010+
const secondaryActions = menus.getTitleSecondaryActions();
1011+
1012+
if (secondaryActions.length === 0) {
1013+
return [viewAction];
1014+
}
1015+
1016+
return [viewAction, new Separator(), ...secondaryActions];
1017+
}
1018+
1019+
getViewActionsContext(): any {
1020+
if (this.items.length !== 1) {
1021+
return undefined;
1022+
}
1023+
1024+
return this.items[0].element.provider;
1025+
}
1026+
9921027
dispose(): void {
9931028
this.visibilityDisposables.dispose();
9941029
this.disposables.dispose();
@@ -1365,7 +1400,7 @@ export class SCMViewPane extends ViewPane {
13651400
private tree!: WorkbenchCompressibleObjectTree<TreeElement, FuzzyScore>;
13661401
private viewModel!: ViewModel;
13671402
private listLabels!: ResourceLabels;
1368-
private menus: SCMMenus;
1403+
private menus!: SCMMenus;
13691404

13701405
constructor(
13711406
options: IViewPaneOptions,
@@ -1387,7 +1422,6 @@ export class SCMViewPane extends ViewPane {
13871422
@ITelemetryService telemetryService: ITelemetryService,
13881423
) {
13891424
super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
1390-
this.menus = instantiationService.createInstance(SCMMenus);
13911425
this._register(Event.any(this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository)(() => this._onDidChangeViewWelcomeState.fire()));
13921426
}
13931427

@@ -1401,6 +1435,12 @@ export class SCMViewPane extends ViewPane {
14011435
Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.alwaysShowActions'))(updateActionsVisibility);
14021436
updateActionsVisibility();
14031437

1438+
const repositories = new SimpleSequence(this.scmService.repositories, this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository);
1439+
this._register(repositories);
1440+
1441+
this.menus = this.instantiationService.createInstance(SCMMenus, repositories);
1442+
this._register(this.menus);
1443+
14041444
const delegate = new ProviderListDelegate();
14051445

14061446
const actionViewItemProvider = (action: IAction) => this.getActionViewItem(action);
@@ -1456,10 +1496,7 @@ export class SCMViewPane extends ViewPane {
14561496
viewMode = storageMode;
14571497
}
14581498

1459-
const repositories = new SimpleSequence(this.scmService.repositories, this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository);
1460-
this._register(repositories);
1461-
1462-
this.viewModel = this.instantiationService.createInstance(ViewModel, repositories, this.tree, viewMode, ViewModelSortKey.Path);
1499+
this.viewModel = this.instantiationService.createInstance(ViewModel, repositories, this.tree, this.menus, viewMode, ViewModelSortKey.Path);
14631500
this._register(this.viewModel);
14641501

14651502
addClass(this.listContainer, 'file-icon-themable-tree');
@@ -1539,26 +1576,20 @@ export class SCMViewPane extends ViewPane {
15391576
// }
15401577
}
15411578

1542-
// TODO@joao
15431579
getActions(): IAction[] {
1544-
return [];
1545-
// return this.menus.getRepositoryMenusTitleActions(;
1580+
if (!this.viewModel) {
1581+
return [];
1582+
}
1583+
1584+
return this.viewModel.getViewActions();
15461585
}
15471586

1548-
// TODO@joao
15491587
getSecondaryActions(): IAction[] {
15501588
if (!this.viewModel) {
15511589
return [];
15521590
}
15531591

1554-
const result: IAction[] = [new SCMViewSubMenuAction(this.viewModel)];
1555-
// const secondaryActions = this.menus.getRepositoryMenusTitleSecondaryActions(;
1556-
1557-
// if (secondaryActions.length > 0) {
1558-
// result.push(new Separator(), ...secondaryActions);
1559-
// }
1560-
1561-
return result;
1592+
return this.viewModel.getViewSecondaryActions();
15621593
}
15631594

15641595
getActionViewItem(action: IAction): IActionViewItem | undefined {
@@ -1569,10 +1600,13 @@ export class SCMViewPane extends ViewPane {
15691600
return new ContextAwareMenuEntryActionViewItem(action, this.keybindingService, this.notificationService, this.contextMenuService);
15701601
}
15711602

1572-
// TODO@joao
1573-
// getActionsContext(): any {
1574-
// return this.repository.provider;
1575-
// }
1603+
getActionsContext(): any {
1604+
if (!this.viewModel) {
1605+
return [];
1606+
}
1607+
1608+
return this.viewModel.getViewActionsContext();
1609+
}
15761610

15771611
private async open(e: IOpenEvent<TreeElement | null>): Promise<void> {
15781612
if (!e.element || isSCMRepository(e.element) || isSCMInput(e.element) || isSCMResourceGroup(e.element) || ResourceTree.isResourceNode(e.element)) {

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

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
1111
import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView';
1212
import { ICommandService } from 'vs/platform/commands/common/commands';
1313
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
14-
import { SCMMenus } from './menus';
14+
import { SCMRepositoryMenus } from './menus';
1515
import { IThemeService } from 'vs/platform/theme/common/themeService';
1616
import { IStorageService } from 'vs/platform/storage/common/storage';
1717
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -25,8 +25,6 @@ import { addClass } from 'vs/base/browser/dom';
2525

2626
export class SCMViewPaneContainer extends ViewPaneContainer {
2727

28-
private menus: SCMMenus;
29-
3028
constructor(
3129
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
3230
@ITelemetryService telemetryService: ITelemetryService,
@@ -46,8 +44,8 @@ export class SCMViewPaneContainer extends ViewPaneContainer {
4644
) {
4745
super(VIEWLET_ID, { mergeViewWithContainerWhenSingleView: true }, instantiationService, configurationService, layoutService, contextMenuService, telemetryService, extensionService, themeService, storageService, contextService, viewDescriptorService);
4846

49-
this.menus = instantiationService.createInstance(SCMMenus);
50-
const menus = this.menus.getDefaultMenus();
47+
const menus = instantiationService.createInstance(SCMRepositoryMenus, undefined);
48+
this._register(menus);
5149
this._register(menus.onDidChangeTitle(this.updateTitleArea, this));
5250
}
5351

0 commit comments

Comments
 (0)