mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-29 18:09:01 +01:00
introduce scm view service
This commit is contained in:
@@ -10,9 +10,9 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { ISCMResource, ISCMResourceGroup, ISCMProvider, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ISCMResource, ISCMResourceGroup, ISCMProvider, ISCMRepository, ISCMService } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { equals } from 'vs/base/common/arrays';
|
||||
import { ISplice, ISequence } from 'vs/base/common/sequence';
|
||||
import { ISplice } from 'vs/base/common/sequence';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
|
||||
@@ -237,44 +237,37 @@ export class SCMMenus {
|
||||
|
||||
readonly titleMenu: SCMTitleMenu;
|
||||
private readonly disposables = new DisposableStore();
|
||||
private readonly entries: { repository: ISCMRepository, dispose: () => void }[] = [];
|
||||
private readonly menus = new Map<ISCMProvider, SCMRepositoryMenus>();
|
||||
private readonly menus = new Map<ISCMProvider, { menus: SCMRepositoryMenus, dispose: () => void }>();
|
||||
|
||||
constructor(
|
||||
repositories: ISequence<ISCMRepository>,
|
||||
@ISCMService scmService: ISCMService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService
|
||||
) {
|
||||
this.titleMenu = instantiationService.createInstance(SCMTitleMenu);
|
||||
scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables);
|
||||
}
|
||||
|
||||
repositories.onDidSplice(this.onDidSplice, this, this.disposables);
|
||||
this.onDidSplice({ start: 0, deleteCount: 0, toInsert: repositories.elements });
|
||||
private onDidRemoveRepository(repository: ISCMRepository): void {
|
||||
const menus = this.menus.get(repository.provider);
|
||||
menus?.dispose();
|
||||
this.menus.delete(repository.provider);
|
||||
}
|
||||
|
||||
getRepositoryMenus(provider: ISCMProvider): SCMRepositoryMenus {
|
||||
if (!this.menus.has(provider)) {
|
||||
throw new Error('SCM Repository menu not found');
|
||||
}
|
||||
let result = this.menus.get(provider);
|
||||
|
||||
return this.menus.get(provider)!;
|
||||
}
|
||||
|
||||
private onDidSplice({ start, deleteCount, toInsert }: ISplice<ISCMRepository>): void {
|
||||
const entriesToInsert = toInsert.map(repository => {
|
||||
const menus = this.instantiationService.createInstance(SCMRepositoryMenus, repository.provider);
|
||||
if (!result) {
|
||||
const menus = this.instantiationService.createInstance(SCMRepositoryMenus, provider);
|
||||
const dispose = () => {
|
||||
menus.dispose();
|
||||
this.menus.delete(repository.provider);
|
||||
this.menus.delete(provider);
|
||||
};
|
||||
|
||||
this.menus.set(repository.provider, menus);
|
||||
return { repository, dispose };
|
||||
});
|
||||
|
||||
const deletedEntries = this.entries.splice(start, deleteCount, ...entriesToInsert);
|
||||
|
||||
for (const entry of deletedEntries) {
|
||||
entry.dispose();
|
||||
result = { menus, dispose };
|
||||
this.menus.set(provider, result);
|
||||
}
|
||||
|
||||
return result.menus;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
|
||||
@@ -7,7 +7,7 @@ import { localize } from 'vs/nls';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { DirtyDiffWorkbenchController } from './dirtydiffDecorator';
|
||||
import { VIEWLET_ID, ISCMRepository, ISCMService, VIEW_PANE_ID, ISCMProvider } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { VIEWLET_ID, ISCMRepository, ISCMService, VIEW_PANE_ID, ISCMProvider, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { SCMStatusController } from './activity';
|
||||
@@ -24,6 +24,7 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||
import { ModesRegistry } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { SCMViewPane } from 'vs/workbench/contrib/scm/browser/scmViewPane';
|
||||
import { SCMViewService } from 'vs/workbench/contrib/scm/common/scmViewService';
|
||||
|
||||
ModesRegistry.registerLanguage({
|
||||
id: 'scminput',
|
||||
@@ -225,3 +226,4 @@ MenuRegistry.appendMenuItem(MenuId.SCMSourceControl, {
|
||||
});
|
||||
|
||||
registerSingleton(ISCMService, SCMService);
|
||||
registerSingleton(ISCMViewService, SCMViewService);
|
||||
|
||||
@@ -6,11 +6,11 @@
|
||||
import 'vs/css!./media/scm';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { basename, dirname, isEqual } from 'vs/base/common/resources';
|
||||
import { IDisposable, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, Disposable, DisposableStore, combinedDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { append, $, addClass, toggleClass, removeClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
|
||||
import { ISCMResourceGroup, ISCMResource, InputValidationType, ISCMService, ISCMRepository, ISCMInput, IInputValidation } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ISCMResourceGroup, ISCMResource, InputValidationType, ISCMService, ISCMRepository, ISCMInput, IInputValidation, ISCMViewService, ISCMViewVisibleRepositoryChangeEvent } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
@@ -31,7 +31,7 @@ import { IConfigurationService, ConfigurationTarget, IConfigurationChangeEvent }
|
||||
import { disposableTimeout, ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { ITreeNode, ITreeFilter, ITreeSorter, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
|
||||
import { ResourceTree, IResourceNode } from 'vs/base/common/resourceTree';
|
||||
import { ISequence, ISplice, SimpleSequence } from 'vs/base/common/sequence';
|
||||
import { ISplice } from 'vs/base/common/sequence';
|
||||
import { ICompressibleTreeRenderer, ICompressibleKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/tree/objectTree';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
import { ICompressedTreeNode, ICompressedTreeElement } from 'vs/base/browser/ui/tree/compressedObjectTreeModel';
|
||||
@@ -803,13 +803,13 @@ interface IGroupItem {
|
||||
readonly element: ISCMResourceGroup;
|
||||
readonly resources: ISCMResource[];
|
||||
readonly tree: ResourceTree<ISCMResource, ISCMResourceGroup>;
|
||||
readonly disposable: IDisposable;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
interface IRepositoryItem {
|
||||
readonly element: ISCMRepository;
|
||||
readonly groupItems: IGroupItem[];
|
||||
readonly disposable: IDisposable;
|
||||
dispose(): void;
|
||||
}
|
||||
|
||||
function isRepositoryItem(item: IRepositoryItem | IGroupItem): item is IRepositoryItem {
|
||||
@@ -848,7 +848,7 @@ class ViewModel {
|
||||
set mode(mode: ViewModelMode) {
|
||||
this._mode = mode;
|
||||
|
||||
for (const item of this.items) {
|
||||
for (const [, item] of this.items) {
|
||||
for (const groupItem of item.groupItems) {
|
||||
groupItem.tree.clear();
|
||||
|
||||
@@ -872,7 +872,7 @@ class ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
private items: IRepositoryItem[] = [];
|
||||
private items = new Map<ISCMRepository, IRepositoryItem>();
|
||||
private visibilityDisposables = new DisposableStore();
|
||||
private scrollTop: number | undefined;
|
||||
private alwaysShowRepositories = false;
|
||||
@@ -882,7 +882,6 @@ class ViewModel {
|
||||
private disposables = new DisposableStore();
|
||||
|
||||
constructor(
|
||||
readonly repositories: ISequence<ISCMRepository>,
|
||||
private tree: WorkbenchCompressibleObjectTree<TreeElement, FuzzyScore>,
|
||||
private menus: SCMMenus,
|
||||
private inputRenderer: InputRenderer,
|
||||
@@ -890,6 +889,7 @@ class ViewModel {
|
||||
private _sortKey: ViewModelSortKey,
|
||||
@IEditorService protected editorService: IEditorService,
|
||||
@IConfigurationService protected configurationService: IConfigurationService,
|
||||
@ISCMViewService private scmViewService: ISCMViewService
|
||||
) {
|
||||
this.onDidChangeRepositoryCollapseState = Event.any(
|
||||
this._onDidChangeRepositoryCollapseState.event,
|
||||
@@ -907,26 +907,27 @@ class ViewModel {
|
||||
}
|
||||
}
|
||||
|
||||
private _onDidSpliceRepositories({ start, deleteCount, toInsert }: ISplice<ISCMRepository>): void {
|
||||
const itemsToInsert = toInsert.map(repository => {
|
||||
private _onDidChangeVisibleRepositories({ added, removed }: ISCMViewVisibleRepositoryChangeEvent): void {
|
||||
for (const repository of added) {
|
||||
const disposable = combinedDisposable(
|
||||
repository.provider.groups.onDidSplice(splice => this._onDidSpliceGroups(item, splice)),
|
||||
repository.input.onDidChangeVisibility(() => this.refresh(item))
|
||||
);
|
||||
const groupItems = repository.provider.groups.elements.map(group => this.createGroupItem(group));
|
||||
const item: IRepositoryItem = { element: repository, groupItems, disposable };
|
||||
const item: IRepositoryItem = {
|
||||
element: repository, groupItems, dispose() {
|
||||
dispose(this.groupItems);
|
||||
disposable.dispose();
|
||||
}
|
||||
};
|
||||
|
||||
return item;
|
||||
});
|
||||
this.items.set(repository, item);
|
||||
}
|
||||
|
||||
const itemsToDispose = this.items.splice(start, deleteCount, ...itemsToInsert);
|
||||
|
||||
for (const item of itemsToDispose) {
|
||||
for (const groupItem of item.groupItems) {
|
||||
groupItem.disposable.dispose();
|
||||
}
|
||||
|
||||
item.disposable.dispose();
|
||||
for (const repository of removed) {
|
||||
const item = this.items.get(repository)!;
|
||||
item.dispose();
|
||||
this.items.delete(repository);
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
@@ -937,7 +938,7 @@ class ViewModel {
|
||||
const itemsToDispose = item.groupItems.splice(start, deleteCount, ...itemsToInsert);
|
||||
|
||||
for (const item of itemsToDispose) {
|
||||
item.disposable.dispose();
|
||||
item.dispose();
|
||||
}
|
||||
|
||||
this.refresh();
|
||||
@@ -951,7 +952,7 @@ class ViewModel {
|
||||
group.onDidSplice(splice => this._onDidSpliceGroup(item, splice))
|
||||
);
|
||||
|
||||
const item: IGroupItem = { element: group, resources, tree, disposable };
|
||||
const item: IGroupItem = { element: group, resources, tree, dispose() { disposable.dispose(); } };
|
||||
|
||||
if (this._mode === ViewModelMode.Tree) {
|
||||
for (const resource of resources) {
|
||||
@@ -987,8 +988,8 @@ class ViewModel {
|
||||
setVisible(visible: boolean): void {
|
||||
if (visible) {
|
||||
this.visibilityDisposables = new DisposableStore();
|
||||
this.repositories.onDidSplice(this._onDidSpliceRepositories, this, this.visibilityDisposables);
|
||||
this._onDidSpliceRepositories({ start: 0, deleteCount: 0, toInsert: this.repositories.elements });
|
||||
this.scmViewService.onDidChangeVisibleRepositories(this._onDidChangeVisibleRepositories, this, this.visibilityDisposables);
|
||||
this._onDidChangeVisibleRepositories({ added: this.scmViewService.visibleRepositories, removed: Iterable.empty() });
|
||||
this.repositoryCollapseStates = undefined;
|
||||
|
||||
if (typeof this.scrollTop === 'number') {
|
||||
@@ -999,16 +1000,16 @@ class ViewModel {
|
||||
this.editorService.onDidActiveEditorChange(this.onDidActiveEditorChange, this, this.visibilityDisposables);
|
||||
this.onDidActiveEditorChange();
|
||||
} else {
|
||||
if (this.items.length > 1) {
|
||||
if (this.items.size > 1) {
|
||||
this.repositoryCollapseStates = new Map();
|
||||
|
||||
for (const item of this.items) {
|
||||
for (const [, item] of this.items) {
|
||||
this.repositoryCollapseStates.set(item.element, this.tree.isCollapsed(item.element));
|
||||
}
|
||||
}
|
||||
|
||||
this.visibilityDisposables.dispose();
|
||||
this._onDidSpliceRepositories({ start: 0, deleteCount: this.items.length, toInsert: [] });
|
||||
this._onDidChangeVisibleRepositories({ added: Iterable.empty(), removed: [...this.items.keys()] });
|
||||
this.scrollTop = this.tree.scrollTop;
|
||||
}
|
||||
|
||||
@@ -1019,12 +1020,14 @@ class ViewModel {
|
||||
private refresh(item?: IRepositoryItem | IGroupItem): void {
|
||||
const focusedInput = this.inputRenderer.getFocusedInput();
|
||||
|
||||
if (!this.alwaysShowRepositories && (this.items.length === 1 && (!item || isRepositoryItem(item)))) {
|
||||
this.tree.setChildren(null, this.render(this.items[0]).children);
|
||||
if (!this.alwaysShowRepositories && (this.items.size === 1 && (!item || isRepositoryItem(item)))) {
|
||||
const item = Iterable.first(this.items.values())!;
|
||||
this.tree.setChildren(null, this.render(item).children);
|
||||
} else if (item) {
|
||||
this.tree.setChildren(item.element, this.render(item).children);
|
||||
} else {
|
||||
this.tree.setChildren(null, this.items.map(item => this.render(item)));
|
||||
const items = this.scmViewService.visibleRepositories.map(r => this.items.get(r)!);
|
||||
this.tree.setChildren(null, items.map(item => this.render(item)));
|
||||
}
|
||||
|
||||
if (focusedInput) {
|
||||
@@ -1043,7 +1046,7 @@ class ViewModel {
|
||||
const children: ICompressedTreeElement<TreeElement>[] = [];
|
||||
const hasSomeChanges = item.groupItems.some(item => item.element.elements.length > 0);
|
||||
|
||||
if (this.items.length === 1 || hasSomeChanges) {
|
||||
if (this.items.size === 1 || hasSomeChanges) {
|
||||
if (item.element.input.visible) {
|
||||
children.push({ element: item.element.input, incompressible: true, collapsible: false });
|
||||
}
|
||||
@@ -1085,8 +1088,9 @@ class ViewModel {
|
||||
return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < this.items.length; i++) {
|
||||
const item = this.items[i];
|
||||
for (const repository of this.scmViewService.visibleRepositories) {
|
||||
const item = this.items.get(repository)!;
|
||||
|
||||
// go backwards from last group
|
||||
for (let j = item.groupItems.length - 1; j >= 0; j--) {
|
||||
const groupItem = item.groupItems[j];
|
||||
@@ -1105,7 +1109,7 @@ class ViewModel {
|
||||
}
|
||||
|
||||
focus() {
|
||||
for (const repository of this.repositories.elements) {
|
||||
for (const repository of this.scmViewService.visibleRepositories) {
|
||||
const widget = this.inputRenderer.getRenderedInputWidget(repository.input);
|
||||
|
||||
if (widget) {
|
||||
@@ -1118,20 +1122,20 @@ class ViewModel {
|
||||
}
|
||||
|
||||
getViewActions(): IAction[] {
|
||||
if (this.repositories.elements.length === 0) {
|
||||
if (this.scmViewService.visibleRepositories.length === 0) {
|
||||
return this.menus.titleMenu.actions;
|
||||
}
|
||||
|
||||
if (this.alwaysShowRepositories || this.repositories.elements.length !== 1) {
|
||||
if (this.alwaysShowRepositories || this.scmViewService.visibleRepositories.length !== 1) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const menus = this.menus.getRepositoryMenus(this.repositories.elements[0].provider);
|
||||
const menus = this.menus.getRepositoryMenus(this.scmViewService.visibleRepositories[0].provider);
|
||||
return menus.titleMenu.actions;
|
||||
}
|
||||
|
||||
getViewSecondaryActions(): IAction[] {
|
||||
if (this.repositories.elements.length === 0) {
|
||||
if (this.scmViewService.visibleRepositories.length === 0) {
|
||||
return this.menus.titleMenu.secondaryActions;
|
||||
}
|
||||
|
||||
@@ -1140,11 +1144,11 @@ class ViewModel {
|
||||
this.disposables.add(this.viewSubMenuAction);
|
||||
}
|
||||
|
||||
if (this.alwaysShowRepositories || this.repositories.elements.length !== 1) {
|
||||
if (this.alwaysShowRepositories || this.scmViewService.visibleRepositories.length !== 1) {
|
||||
return this.viewSubMenuAction.actions;
|
||||
}
|
||||
|
||||
const menus = this.menus.getRepositoryMenus(this.repositories.elements[0].provider);
|
||||
const menus = this.menus.getRepositoryMenus(this.scmViewService.visibleRepositories[0].provider);
|
||||
const secondaryActions = menus.titleMenu.secondaryActions;
|
||||
|
||||
if (secondaryActions.length === 0) {
|
||||
@@ -1155,19 +1159,19 @@ class ViewModel {
|
||||
}
|
||||
|
||||
getViewActionsContext(): any {
|
||||
if (this.repositories.elements.length === 0) {
|
||||
if (this.scmViewService.visibleRepositories.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (this.alwaysShowRepositories || this.repositories.elements.length !== 1) {
|
||||
if (this.alwaysShowRepositories || this.scmViewService.visibleRepositories.length !== 1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this.repositories.elements[0].provider;
|
||||
return this.scmViewService.visibleRepositories[0].provider;
|
||||
}
|
||||
|
||||
collapseAllProviders(): void {
|
||||
for (const repository of this.repositories.elements) {
|
||||
for (const repository of this.scmViewService.visibleRepositories) {
|
||||
if (this.tree.isCollapsible(repository)) {
|
||||
this.tree.collapse(repository);
|
||||
}
|
||||
@@ -1175,7 +1179,7 @@ class ViewModel {
|
||||
}
|
||||
|
||||
expandAllProviders(): void {
|
||||
for (const repository of this.repositories.elements) {
|
||||
for (const repository of this.scmViewService.visibleRepositories) {
|
||||
if (this.tree.isCollapsible(repository)) {
|
||||
this.tree.expand(repository);
|
||||
}
|
||||
@@ -1183,30 +1187,26 @@ class ViewModel {
|
||||
}
|
||||
|
||||
isAnyProviderCollapsible(): boolean {
|
||||
if (!this.visible || this.repositories.elements.length === 1) {
|
||||
if (!this.visible || this.scmViewService.visibleRepositories.length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.repositories.elements.some(r => this.tree.hasElement(r) && this.tree.isCollapsible(r));
|
||||
return this.scmViewService.visibleRepositories.some(r => this.tree.hasElement(r) && this.tree.isCollapsible(r));
|
||||
}
|
||||
|
||||
areAllProvidersCollapsed(): boolean {
|
||||
if (!this.visible || this.repositories.elements.length === 1) {
|
||||
if (!this.visible || this.scmViewService.visibleRepositories.length === 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.repositories.elements.every(r => this.tree.hasElement(r) && (!this.tree.isCollapsible(r) || this.tree.isCollapsed(r)));
|
||||
return this.scmViewService.visibleRepositories.every(r => this.tree.hasElement(r) && (!this.tree.isCollapsible(r) || this.tree.isCollapsed(r)));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.visibilityDisposables.dispose();
|
||||
this.disposables.dispose();
|
||||
|
||||
for (const item of this.items) {
|
||||
item.disposable.dispose();
|
||||
}
|
||||
|
||||
this.items = [];
|
||||
dispose(this.items.values());
|
||||
this.items.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1656,6 +1656,7 @@ export class SCMViewPane extends ViewPane {
|
||||
constructor(
|
||||
options: IViewPaneOptions,
|
||||
@ISCMService private scmService: ISCMService,
|
||||
@ISCMViewService private scmViewService: ISCMViewService,
|
||||
@IKeybindingService protected keybindingService: IKeybindingService,
|
||||
@IThemeService protected themeService: IThemeService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@@ -1696,14 +1697,11 @@ export class SCMViewPane extends ViewPane {
|
||||
this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.providerCountBadge'))(updateProviderCountVisibility));
|
||||
updateProviderCountVisibility();
|
||||
|
||||
const repositories = new SimpleSequence(this.scmService.repositories, this.scmService.onDidAddRepository, this.scmService.onDidRemoveRepository);
|
||||
this._register(repositories);
|
||||
|
||||
this.menus = this.instantiationService.createInstance(SCMMenus, repositories);
|
||||
this.menus = this.instantiationService.createInstance(SCMMenus);
|
||||
this._register(this.menus);
|
||||
this._register(this.menus.titleMenu.onDidChangeTitle(this.updateActions, this));
|
||||
|
||||
this._register(repositories.onDidSplice(() => this.updateActions()));
|
||||
this._register(this.scmViewService.onDidChangeVisibleRepositories(() => this.updateActions()));
|
||||
|
||||
this.inputRenderer = this.instantiationService.createInstance(InputRenderer, this.layoutCache, (input, height) => this.tree.updateElementHeight(input, height));
|
||||
const delegate = new ProviderListDelegate(this.inputRenderer);
|
||||
@@ -1762,7 +1760,7 @@ export class SCMViewPane extends ViewPane {
|
||||
viewMode = storageMode;
|
||||
}
|
||||
|
||||
this.viewModel = this.instantiationService.createInstance(ViewModel, repositories, this.tree, this.menus, this.inputRenderer, viewMode, ViewModelSortKey.Path);
|
||||
this.viewModel = this.instantiationService.createInstance(ViewModel, this.tree, this.menus, this.inputRenderer, viewMode, ViewModelSortKey.Path);
|
||||
this._register(this.viewModel);
|
||||
|
||||
addClass(this.listContainer, 'file-icon-themable-tree');
|
||||
@@ -1829,7 +1827,7 @@ export class SCMViewPane extends ViewPane {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (this.viewModel.repositories.elements.length < 2) {
|
||||
if (this.scmViewService.visibleRepositories.length < 2) {
|
||||
return [...result, ...this.viewModel.getViewActions()];
|
||||
}
|
||||
|
||||
|
||||
@@ -113,3 +113,17 @@ export interface ISCMService {
|
||||
|
||||
registerSCMProvider(provider: ISCMProvider): ISCMRepository;
|
||||
}
|
||||
|
||||
export const ISCMViewService = createDecorator<ISCMViewService>('scmView');
|
||||
|
||||
export interface ISCMViewVisibleRepositoryChangeEvent {
|
||||
readonly added: Iterable<ISCMRepository>;
|
||||
readonly removed: Iterable<ISCMRepository>;
|
||||
}
|
||||
|
||||
export interface ISCMViewService {
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
visibleRepositories: ISCMRepository[];
|
||||
readonly onDidChangeVisibleRepositories: Event<ISCMViewVisibleRepositoryChangeEvent>;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { ISCMViewService, ISCMRepository, ISCMService, ISCMViewVisibleRepositoryChangeEvent } from './scm';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
|
||||
export class SCMViewService implements ISCMViewService {
|
||||
|
||||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private disposables = new DisposableStore();
|
||||
|
||||
private _visibleRepositoriesSet = new Set<ISCMRepository>();
|
||||
private _visibleRepositories: ISCMRepository[] = [];
|
||||
|
||||
get visibleRepositories(): ISCMRepository[] {
|
||||
return this._visibleRepositories;
|
||||
}
|
||||
|
||||
set visibleRepositories(visibleRepositories: ISCMRepository[]) {
|
||||
const set = new Set(visibleRepositories);
|
||||
const added = new Set<ISCMRepository>();
|
||||
const removed = new Set<ISCMRepository>();
|
||||
|
||||
for (const repository of visibleRepositories) {
|
||||
if (!this._visibleRepositoriesSet.has(repository)) {
|
||||
added.add(repository);
|
||||
}
|
||||
}
|
||||
|
||||
for (const repository of this._visibleRepositories) {
|
||||
if (!set.has(repository)) {
|
||||
removed.add(repository);
|
||||
}
|
||||
}
|
||||
|
||||
if (added.size === 0 && removed.size === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._visibleRepositories = visibleRepositories;
|
||||
this._visibleRepositoriesSet = set;
|
||||
this._onDidChangeVisibleRepositories.fire({ added, removed });
|
||||
}
|
||||
|
||||
private _onDidChangeVisibleRepositories = new Emitter<ISCMViewVisibleRepositoryChangeEvent>();
|
||||
readonly onDidChangeVisibleRepositories = this._onDidChangeVisibleRepositories.event;
|
||||
|
||||
constructor(@ISCMService scmService: ISCMService) {
|
||||
scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables);
|
||||
scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables);
|
||||
|
||||
for (const repository of scmService.repositories) {
|
||||
this.onDidAddRepository(repository);
|
||||
}
|
||||
}
|
||||
|
||||
private onDidAddRepository(repository: ISCMRepository): void {
|
||||
this._visibleRepositories.push(repository);
|
||||
this._visibleRepositoriesSet.add(repository);
|
||||
this._onDidChangeVisibleRepositories.fire({ added: [repository], removed: Iterable.empty() });
|
||||
}
|
||||
|
||||
private onDidRemoveRepository(repository: ISCMRepository): void {
|
||||
const index = this._visibleRepositories.indexOf(repository);
|
||||
|
||||
if (index > -1) {
|
||||
this._visibleRepositories.splice(index, 1);
|
||||
this._visibleRepositoriesSet.delete(repository);
|
||||
this._onDidChangeVisibleRepositories.fire({ added: Iterable.empty(), removed: [repository] });
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.dispose();
|
||||
this._onDidChangeVisibleRepositories.dispose();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user