Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCM - Sort repositories by name #145264

Merged
merged 5 commits into from Mar 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
26 changes: 5 additions & 21 deletions src/vs/workbench/contrib/scm/browser/scmRepositoriesViewPane.ts
Expand Up @@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPane';
import { append, $ } from 'vs/base/browser/dom';
import { IListVirtualDelegate, IListContextMenuEvent, IListEvent } from 'vs/base/browser/ui/list/list';
import { ISCMRepository, ISCMService, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { ISCMRepository, ISCMViewService } from 'vs/workbench/contrib/scm/common/scm';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
Expand Down Expand Up @@ -41,7 +41,6 @@ export class SCMRepositoriesViewPane extends ViewPane {

constructor(
options: IViewPaneOptions,
@ISCMService protected scmService: ISCMService,
@ISCMViewService protected scmViewService: ISCMViewService,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
Expand Down Expand Up @@ -85,15 +84,9 @@ export class SCMRepositoriesViewPane extends ViewPane {
this._register(this.list.onDidChangeSelection(this.onListSelectionChange, this));
this._register(this.list.onContextMenu(this.onListContextMenu, this));

this._register(this.scmViewService.onDidChangeRepositories(this.onDidChangeRepositories, this));
this._register(this.scmViewService.onDidChangeVisibleRepositories(this.updateListSelection, this));

this._register(this.scmService.onDidAddRepository(this.onDidAddRepository, this));
this._register(this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this));

for (const repository of this.scmService.repositories) {
this.onDidAddRepository(repository);
}

if (this.orientation === Orientation.VERTICAL) {
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('scm.repositories.visible')) {
Expand All @@ -102,21 +95,12 @@ export class SCMRepositoriesViewPane extends ViewPane {
}));
}

this.onDidChangeRepositories();
this.updateListSelection();
}

private onDidAddRepository(repository: ISCMRepository): void {
this.list.splice(this.list.length, 0, [repository]);
this.updateBodySize();
}

private onDidRemoveRepository(repository: ISCMRepository): void {
const index = this.list.indexOf(repository);

if (index > -1) {
this.list.splice(index, 1);
}

private onDidChangeRepositories(): void {
this.list.splice(0, this.list.length, this.scmViewService.repositories);
this.updateBodySize();
}

Expand Down
71 changes: 59 additions & 12 deletions src/vs/workbench/contrib/scm/browser/scmViewService.ts
Expand Up @@ -11,11 +11,24 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { SCMMenus } from 'vs/workbench/contrib/scm/browser/menus';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { debounce } from 'vs/base/common/decorators';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { compareFileNames } from 'vs/base/common/comparers';
import { basename } from 'vs/base/common/resources';
import { binarySearch } from 'vs/base/common/arrays';

function getProviderStorageKey(provider: ISCMProvider): string {
return `${provider.contextValue}:${provider.label}${provider.rootUri ? `:${provider.rootUri.toString()}` : ''}`;
}

function getRepositoryName(workspaceContextService: IWorkspaceContextService, repository: ISCMRepository): string {
if (!repository.provider.rootUri) {
return repository.provider.label;
}

const folder = workspaceContextService.getWorkspaceFolder(repository.provider.rootUri);
return folder?.uri.toString() === repository.provider.rootUri.toString() ? folder.name : basename(repository.provider.rootUri);
}

export interface ISCMViewServiceState {
readonly all: string[];
readonly visible: number[];
Expand All @@ -32,6 +45,15 @@ export class SCMViewService implements ISCMViewService {
private previousState: ISCMViewServiceState | undefined;
private disposables = new DisposableStore();

private _repositories: ISCMRepository[] = [];

get repositories(): ISCMRepository[] {
return this._repositories;
}

private _onDidChangeRepositories = new Emitter<ISCMViewVisibleRepositoryChangeEvent>();
readonly onDidChangeRepositories = this._onDidChangeRepositories.event;

private _visibleRepositoriesSet = new Set<ISCMRepository>();
private _visibleRepositories: ISCMRepository[] = [];

Expand Down Expand Up @@ -60,7 +82,7 @@ export class SCMViewService implements ISCMViewService {
return;
}

this._visibleRepositories = visibleRepositories;
this._visibleRepositories = visibleRepositories.sort(this._compareRepositories);
this._visibleRepositoriesSet = set;
this._onDidSetVisibleRepositories.fire({ added, removed });

Expand All @@ -69,7 +91,6 @@ export class SCMViewService implements ISCMViewService {
}
}

private _onDidChangeRepositories = new Emitter<ISCMViewVisibleRepositoryChangeEvent>();
private _onDidSetVisibleRepositories = new Emitter<ISCMViewVisibleRepositoryChangeEvent>();
readonly onDidChangeVisibleRepositories = Event.any(
this._onDidSetVisibleRepositories.event,
Expand All @@ -96,13 +117,23 @@ export class SCMViewService implements ISCMViewService {
private _onDidFocusRepository = new Emitter<ISCMRepository | undefined>();
readonly onDidFocusRepository = this._onDidFocusRepository.event;

private _compareRepositories: (op1: ISCMRepository, op2: ISCMRepository) => number;

constructor(
@ISCMService private readonly scmService: ISCMService,
@IInstantiationService instantiationService: IInstantiationService,
@IStorageService private readonly storageService: IStorageService
@IStorageService private readonly storageService: IStorageService,
@IWorkspaceContextService workspaceContextService: IWorkspaceContextService
) {
this.menus = instantiationService.createInstance(SCMMenus);

this._compareRepositories = (op1: ISCMRepository, op2: ISCMRepository): number => {
const name1 = getRepositoryName(workspaceContextService, op1);
const name2 = getRepositoryName(workspaceContextService, op2);

return compareFileNames(name1, name2);
};

scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables);
scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.disposables);

Expand All @@ -124,6 +155,7 @@ export class SCMViewService implements ISCMViewService {
this.eventuallyFinishLoading();
}

this.insertRepository(this._repositories, repository);
let removed: Iterable<ISCMRepository> = Iterable.empty();

if (this.previousState) {
Expand All @@ -137,8 +169,8 @@ export class SCMViewService implements ISCMViewService {
}
}

this._visibleRepositories = [...this.scmService.repositories];
this._visibleRepositoriesSet = new Set(this.scmService.repositories);
this._visibleRepositories = [...this.scmService.repositories.sort(this._compareRepositories)];
this._onDidChangeRepositories.fire({ added, removed: Iterable.empty() });
this.finishLoading();
return;
Expand All @@ -150,6 +182,7 @@ export class SCMViewService implements ISCMViewService {
if (this._visibleRepositories.length === 0) { // should make it visible, until other repos come along
this.provisionalVisibleRepository = repository;
} else {
this._onDidChangeRepositories.fire({ added: Iterable.empty(), removed: Iterable.empty() });
return;
}
} else {
Expand All @@ -162,8 +195,8 @@ export class SCMViewService implements ISCMViewService {
}
}

this._visibleRepositories.push(repository);
this._visibleRepositoriesSet.add(repository);
this.insertRepository(this._visibleRepositories, repository);
this._onDidChangeRepositories.fire({ added: [repository], removed });

if (!this._focusedRepository) {
Expand All @@ -176,22 +209,29 @@ export class SCMViewService implements ISCMViewService {
this.eventuallyFinishLoading();
}

const index = this._visibleRepositories.indexOf(repository);
let added: Iterable<ISCMRepository> = Iterable.empty();

if (index > -1) {
let added: Iterable<ISCMRepository> = Iterable.empty();
const repositoriesIndex = this._repositories.indexOf(repository);
const visibleRepositoriesIndex = this._visibleRepositories.indexOf(repository);

if (repositoriesIndex > -1) {
this._repositories.splice(repositoriesIndex, 1);
}

this._visibleRepositories.splice(index, 1);
if (visibleRepositoriesIndex > -1) {
this._visibleRepositories.splice(visibleRepositoriesIndex, 1);
this._visibleRepositoriesSet.delete(repository);

if (this._visibleRepositories.length === 0 && this.scmService.repositories.length > 0) {
const first = this.scmService.repositories[0];
if (this._repositories.length > 0 && this._visibleRepositories.length === 0) {
const first = this._repositories[0];

this._visibleRepositories.push(first);
this._visibleRepositoriesSet.add(first);
added = [first];
}
}

if (repositoriesIndex > -1 || visibleRepositoriesIndex > -1) {
this._onDidChangeRepositories.fire({ added, removed: [repository] });
}

Expand Down Expand Up @@ -234,12 +274,19 @@ export class SCMViewService implements ISCMViewService {
this._onDidFocusRepository.fire(repository);
}

private insertRepository(repositories: ISCMRepository[], repository: ISCMRepository): void {
const index = binarySearch(repositories, repository, this._compareRepositories);
if (index < 0) {
repositories.splice(~index, 0, repository);
}
}

private onWillSaveState(): void {
if (!this.didFinishLoading) { // don't remember state, if the workbench didn't really finish loading
return;
}

const all = this.scmService.repositories.map(r => getProviderStorageKey(r.provider));
const all = this.repositories.map(r => getProviderStorageKey(r.provider));
const visible = this.visibleRepositories.map(r => all.indexOf(getProviderStorageKey(r.provider)));
const raw = JSON.stringify({ all, visible });

Expand Down
3 changes: 3 additions & 0 deletions src/vs/workbench/contrib/scm/common/scm.ts
Expand Up @@ -180,6 +180,9 @@ export interface ISCMViewService {

readonly menus: ISCMMenus;

repositories: ISCMRepository[];
readonly onDidChangeRepositories: Event<ISCMViewVisibleRepositoryChangeEvent>;

visibleRepositories: ISCMRepository[];
readonly onDidChangeVisibleRepositories: Event<ISCMViewVisibleRepositoryChangeEvent>;
lszomoru marked this conversation as resolved.
Show resolved Hide resolved

Expand Down