diff --git a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts index 85707031cf9..f200f2bfe37 100644 --- a/src/vs/workbench/api/electron-browser/mainThreadSCM.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadSCM.ts @@ -10,23 +10,38 @@ import URI from 'vs/base/common/uri'; import Event, { Emitter } from 'vs/base/common/event'; import { assign } from 'vs/base/common/objects'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations } from 'vs/workbench/services/scm/common/scm'; +import { ISCMService, ISCMRepository, ISCMProvider, ISCMResource, ISCMResourceGroup, ISCMResourceDecorations, ISCMResourceCollection, ISCMResourceSplice } from 'vs/workbench/services/scm/common/scm'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ExtHostContext, MainThreadSCMShape, ExtHostSCMShape, SCMProviderFeatures, SCMRawResourceSplices, SCMGroupFeatures, MainContext, IExtHostContext } from '../node/extHost.protocol'; import { Command } from 'vs/editor/common/modes'; import { extHostNamedCustomer } from 'vs/workbench/api/electron-browser/extHostCustomers'; +class MainThreadSCMResourceCollection implements ISCMResourceCollection { + + readonly resources: ISCMResource[] = []; + + private _onDidSplice = new Emitter(); + readonly onDidSplice = this._onDidSplice.event; + + splice(start: number, deleteCount: number, resources: ISCMResource[]) { + this.resources.splice(start, deleteCount, ...resources); + this._onDidSplice.fire({ start, deleteCount, resources }); + } +} + class MainThreadSCMResourceGroup implements ISCMResourceGroup { + readonly resourceCollection = new MainThreadSCMResourceCollection(); + get hideWhenEmpty(): boolean { return this.features.hideWhenEmpty; } + constructor( private sourceControlHandle: number, private handle: number, public provider: ISCMProvider, public features: SCMGroupFeatures, public label: string, - public id: string, - public resources: ISCMResource[] + public id: string ) { } toJSON(): any { @@ -71,7 +86,7 @@ class MainThreadSCMProvider implements ISCMProvider { get resources(): ISCMResourceGroup[] { return this._groups - .filter(g => g.resources.length > 0 || !g.features.hideWhenEmpty); + .filter(g => g.resourceCollection.resources.length > 0 || !g.features.hideWhenEmpty); } private _onDidChangeResources = new Emitter(); @@ -125,8 +140,7 @@ class MainThreadSCMProvider implements ISCMProvider { this, {}, label, - id, - [] + id ); this._groups.push(group); @@ -190,7 +204,7 @@ class MainThreadSCMProvider implements ISCMProvider { ); }); - group.resources.splice(start, deleteCount, ...resources); + group.resourceCollection.splice(start, deleteCount, resources); } } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index f9dc7223126..c40bc15665e 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -13,8 +13,9 @@ import { asWinJsPromise } from 'vs/base/common/async'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/node/extHostCommands'; import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext } from './extHost.protocol'; -import * as vscode from 'vscode'; import { LcsDiff, ISequence } from 'vs/base/common/diff/diff'; +import { comparePaths } from 'vs/base/common/comparers'; +import * as vscode from 'vscode'; function getIconPath(decorations: vscode.SourceControlResourceThemableDecorations) { if (!decorations) { @@ -27,6 +28,10 @@ function getIconPath(decorations: vscode.SourceControlResourceThemableDecoration return undefined; } +function resourceSorter(a: vscode.SourceControlResourceState, b: vscode.SourceControlResourceState): number { + return comparePaths(a.resourceUri.fsPath, b.resourceUri.fsPath); +} + export class ExtHostSCMInputBox { private _value: string = ''; @@ -115,8 +120,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG } _snapshot(): SCMRawResourceSplice[] { + const snapshot = [...this._resourceStates].sort(resourceSorter); const original = new ResourceSequence(this._resourcesSnapshot); - const modified = new ResourceSequence(this._resourceStates); + const modified = new ResourceSequence(snapshot); const lcs = new LcsDiff(original, modified); const diffs = lcs.ComputeDiff(false); const handlesToDelete: number[] = []; @@ -126,7 +132,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG const deleteCount = diff.originalLength; const handles: number[] = []; - const rawResources = this._resourceStates + const rawResources = snapshot .slice(diff.modifiedStart, diff.modifiedStart + diff.modifiedLength) .map(r => { const handle = this._resourceHandlePool++; @@ -167,7 +173,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG this._resourceStatesRollingDisposables.shift()(); } - this._resourcesSnapshot = this._resourceStates; + this._resourcesSnapshot = snapshot; return splices; } diff --git a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts index 2e5ff3d99f4..81489a979b4 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts @@ -57,7 +57,7 @@ export class StatusUpdater implements IWorkbenchContribution { if (typeof repository.provider.count === 'number') { return r + repository.provider.count; } else { - return r + repository.provider.resources.reduce((r, g) => r + g.resources.length, 0); + return r + repository.provider.resources.reduce((r, g) => r + g.resourceCollection.resources.length, 0); } }, 0); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index df6083d0734..a1b3031f826 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -36,7 +36,6 @@ import { MenuItemActionItem } from 'vs/platform/actions/browser/menuItemActionIt import { SCMMenus } from './scmMenus'; import { ActionBar, IActionItemProvider, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { IThemeService, LIGHT } from 'vs/platform/theme/common/themeService'; -import { comparePaths } from 'vs/base/common/comparers'; import { isSCMResource } from './scmUtil'; import { attachListStyler, attachBadgeStyler, attachInputBoxStyler } from 'vs/platform/theme/common/styler'; import Severity from 'vs/base/common/severity'; @@ -121,7 +120,7 @@ class ResourceGroupRenderer implements IRenderer { } } -function resourceSorter(a: ISCMResource, b: ISCMResource): number { - return comparePaths(a.sourceUri.fsPath, b.sourceUri.fsPath); -} - class SourceControlViewDescriptor implements IViewDescriptor { // This ID magic needs to happen in order to preserve @@ -411,7 +406,13 @@ class SourceControlView extends CollapsibleView { private updateList(): void { const elements = this.repository.provider.resources - .reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => [...r, g, ...g.resources.sort(resourceSorter)], []); + .reduce<(ISCMResourceGroup | ISCMResource)[]>((r, g) => { + if (g.resourceCollection.resources.length === 0 && g.hideWhenEmpty) { + return r; + } + + return [...r, g, ...g.resourceCollection.resources]; + }, []); this.list.splice(0, this.list.length, elements); } diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 114bbb27328..1f5214686b3 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -26,6 +26,17 @@ export interface ISCMResourceDecorations { faded?: boolean; } +export interface ISCMResourceSplice { + start: number; + deleteCount: number; + resources: ISCMResource[]; +} + +export interface ISCMResourceCollection { + readonly resources: ISCMResource[]; + readonly onDidSplice: Event; +} + export interface ISCMResource { readonly resourceGroup: ISCMResourceGroup; readonly sourceUri: URI; @@ -37,7 +48,8 @@ export interface ISCMResourceGroup { readonly provider: ISCMProvider; readonly label: string; readonly id: string; - readonly resources: ISCMResource[]; + readonly resourceCollection: ISCMResourceCollection; + readonly hideWhenEmpty: boolean; } export interface ISCMProvider extends IDisposable {