From 24cd191ac236022ee02e1716f459828484657fa1 Mon Sep 17 00:00:00 2001 From: Joao Moreno Date: Fri, 24 Mar 2017 17:51:00 +0100 Subject: [PATCH] :sparkles: scm: require uris on resources and groups --- extensions/git/src/commands.ts | 41 ++++++---- extensions/git/src/merge.ts | 2 +- extensions/git/src/model.ts | 61 +++++++++------ src/vs/vscode.proposed.d.ts | 30 ++++++-- src/vs/workbench/api/node/extHost.api.impl.ts | 5 -- src/vs/workbench/api/node/extHost.protocol.ts | 11 ++- src/vs/workbench/api/node/extHostSCM.ts | 77 ++----------------- src/vs/workbench/api/node/mainThreadSCM.ts | 9 ++- .../parts/scm/electron-browser/scmMenus.ts | 4 +- .../parts/scm/electron-browser/scmUtil.ts | 19 +---- .../parts/scm/electron-browser/scmViewlet.ts | 11 ++- src/vs/workbench/services/scm/common/scm.ts | 2 + 12 files changed, 119 insertions(+), 153 deletions(-) diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 6997c3a80e2..f13a85f3a0e 100644 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -137,7 +137,7 @@ export class CommandCenter { return resource.original.with({ scheme: 'git', query: 'HEAD' }); case Status.MODIFIED: - return resource.uri.with({ scheme: 'git', query: '~' }); + return resource.sourceUri.with({ scheme: 'git', query: '~' }); } } @@ -146,34 +146,34 @@ export class CommandCenter { case Status.INDEX_MODIFIED: case Status.INDEX_ADDED: case Status.INDEX_COPIED: - return resource.uri.with({ scheme: 'git' }); + return resource.sourceUri.with({ scheme: 'git' }); case Status.INDEX_RENAMED: - return resource.uri.with({ scheme: 'git' }); + return resource.sourceUri.with({ scheme: 'git' }); case Status.INDEX_DELETED: case Status.DELETED: - return resource.uri.with({ scheme: 'git', query: 'HEAD' }); + return resource.sourceUri.with({ scheme: 'git', query: 'HEAD' }); case Status.MODIFIED: case Status.UNTRACKED: case Status.IGNORED: - const uriString = resource.uri.toString(); - const [indexStatus] = this.model.indexGroup.resources.filter(r => r.uri.toString() === uriString); + const uriString = resource.sourceUri.toString(); + const [indexStatus] = this.model.indexGroup.resources.filter(r => r.sourceUri.toString() === uriString); if (indexStatus && indexStatus.rename) { return indexStatus.rename; } - return resource.uri; + return resource.sourceUri; case Status.BOTH_MODIFIED: - return resource.uri; + return resource.sourceUri; } } private getTitle(resource: Resource): string { - const basename = path.basename(resource.uri.fsPath); + const basename = path.basename(resource.sourceUri.fsPath); switch (resource.type) { case Status.INDEX_MODIFIED: @@ -274,7 +274,7 @@ export class CommandCenter { return; } - return await commands.executeCommand('vscode.open', resource.uri); + return await commands.executeCommand('vscode.open', resource.sourceUri); } @command('git.openChange') @@ -449,7 +449,7 @@ export class CommandCenter { } const message = resources.length === 1 - ? localize('confirm discard', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].uri.fsPath)) + ? localize('confirm discard', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].sourceUri.fsPath)) : localize('confirm discard multiple', "Are you sure you want to discard changes in {0} files?", resources.length); const yes = localize('discard', "Discard Changes"); @@ -792,9 +792,18 @@ export class CommandCenter { return undefined; } - if (uri.scheme === 'scm' && uri.authority === 'git') { - const resource = scm.getResourceFromURI(uri); - return resource instanceof Resource ? resource : undefined; + if (uri.scheme === 'git-resource') { + const {resourceGroupId} = JSON.parse(uri.query) as { resourceGroupId: string, sourceUri: string }; + const [resourceGroup] = this.model.resources.filter(g => g.id === resourceGroupId); + + if (!resourceGroup) { + return; + } + + const uriStr = uri.toString(); + const [resource] = resourceGroup.resources.filter(r => r.uri.toString() === uriStr); + + return resource; } if (uri.scheme === 'git') { @@ -804,8 +813,8 @@ export class CommandCenter { if (uri.scheme === 'file') { const uriString = uri.toString(); - return this.model.workingTreeGroup.resources.filter(r => r.uri.toString() === uriString)[0] - || this.model.indexGroup.resources.filter(r => r.uri.toString() === uriString)[0]; + return this.model.workingTreeGroup.resources.filter(r => r.sourceUri.toString() === uriString)[0] + || this.model.indexGroup.resources.filter(r => r.sourceUri.toString() === uriString)[0]; } } diff --git a/extensions/git/src/merge.ts b/extensions/git/src/merge.ts index 1ac237c3748..0e7a17c7884 100644 --- a/extensions/git/src/merge.ts +++ b/extensions/git/src/merge.ts @@ -62,7 +62,7 @@ class TextEditorMergeDecorator { return; } - if (this.model.mergeGroup.resources.some(r => r.type === Status.BOTH_MODIFIED && r.uri.toString() === this.uri)) { + if (this.model.mergeGroup.resources.some(r => r.type === Status.BOTH_MODIFIED && r.sourceUri.toString() === this.uri)) { decorations = decorate(this.editor.document); } diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 7025799b967..c192512c123 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -54,16 +54,28 @@ export enum Status { export class Resource implements SCMResource { + @memoize get uri(): Uri { + return new Uri().with({ + scheme: 'git-resource', + query: JSON.stringify({ + resourceGroupId: this.resourceGroupId, + sourceUri: this.sourceUri.toString() + }) + }); + } + + @memoize + get sourceUri(): Uri { if (this.rename && (this._type === Status.MODIFIED || this._type === Status.DELETED || this._type === Status.INDEX_RENAMED)) { return this.rename; } - return this._uri; + return this._sourceUri; } get type(): Status { return this._type; } - get original(): Uri { return this._uri; } + get original(): Uri { return this._sourceUri; } get rename(): Uri | undefined { return this._rename; } private static Icons = { @@ -130,13 +142,16 @@ export class Resource implements SCMResource { return { strikeThrough: this.strikeThrough, light, dark }; } - constructor(private _uri: Uri, private _type: Status, private _rename?: Uri) { + constructor(private resourceGroupId: string, private _sourceUri: Uri, private _type: Status, private _rename?: Uri) { // console.log(this); } } export class ResourceGroup implements SCMResourceGroup { + @memoize + get uri(): Uri { return Uri.parse(`git-resource-group:${this.id}`); } + get id(): string { return this._id; } get label(): string { return this._label; } get resources(): Resource[] { return this._resources; } @@ -399,7 +414,7 @@ export class Model implements Disposable { @throttle async add(...resources: Resource[]): Promise { - await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.uri.fsPath))); + await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.sourceUri.fsPath))); } @throttle @@ -410,7 +425,7 @@ export class Model implements Disposable { @throttle async revertFiles(...resources: Resource[]): Promise { - await this.run(Operation.RevertFiles, () => this.repository.revertFiles('HEAD', resources.map(r => r.uri.fsPath))); + await this.run(Operation.RevertFiles, () => this.repository.revertFiles('HEAD', resources.map(r => r.sourceUri.fsPath))); } @throttle @@ -434,11 +449,11 @@ export class Model implements Disposable { switch (r.type) { case Status.UNTRACKED: case Status.IGNORED: - toClean.push(r.uri.fsPath); + toClean.push(r.sourceUri.fsPath); break; default: - toCheckout.push(r.uri.fsPath); + toCheckout.push(r.sourceUri.fsPath); break; } }); @@ -629,30 +644,30 @@ export class Model implements Disposable { const renameUri = raw.rename ? Uri.file(path.join(this.repository.root, raw.rename)) : undefined; switch (raw.x + raw.y) { - case '??': return workingTree.push(new Resource(uri, Status.UNTRACKED)); - case '!!': return workingTree.push(new Resource(uri, Status.IGNORED)); - case 'DD': return merge.push(new Resource(uri, Status.BOTH_DELETED)); - case 'AU': return merge.push(new Resource(uri, Status.ADDED_BY_US)); - case 'UD': return merge.push(new Resource(uri, Status.DELETED_BY_THEM)); - case 'UA': return merge.push(new Resource(uri, Status.ADDED_BY_THEM)); - case 'DU': return merge.push(new Resource(uri, Status.DELETED_BY_US)); - case 'AA': return merge.push(new Resource(uri, Status.BOTH_ADDED)); - case 'UU': return merge.push(new Resource(uri, Status.BOTH_MODIFIED)); + case '??': return workingTree.push(new Resource(WorkingTreeGroup.ID, uri, Status.UNTRACKED)); + case '!!': return workingTree.push(new Resource(WorkingTreeGroup.ID, uri, Status.IGNORED)); + case 'DD': return merge.push(new Resource(MergeGroup.ID, uri, Status.BOTH_DELETED)); + case 'AU': return merge.push(new Resource(MergeGroup.ID, uri, Status.ADDED_BY_US)); + case 'UD': return merge.push(new Resource(MergeGroup.ID, uri, Status.DELETED_BY_THEM)); + case 'UA': return merge.push(new Resource(MergeGroup.ID, uri, Status.ADDED_BY_THEM)); + case 'DU': return merge.push(new Resource(MergeGroup.ID, uri, Status.DELETED_BY_US)); + case 'AA': return merge.push(new Resource(MergeGroup.ID, uri, Status.BOTH_ADDED)); + case 'UU': return merge.push(new Resource(MergeGroup.ID, uri, Status.BOTH_MODIFIED)); } let isModifiedInIndex = false; switch (raw.x) { - case 'M': index.push(new Resource(uri, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break; - case 'A': index.push(new Resource(uri, Status.INDEX_ADDED)); break; - case 'D': index.push(new Resource(uri, Status.INDEX_DELETED)); break; - case 'R': index.push(new Resource(uri, Status.INDEX_RENAMED, renameUri)); break; - case 'C': index.push(new Resource(uri, Status.INDEX_COPIED)); break; + case 'M': index.push(new Resource(IndexGroup.ID, uri, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break; + case 'A': index.push(new Resource(IndexGroup.ID, uri, Status.INDEX_ADDED)); break; + case 'D': index.push(new Resource(IndexGroup.ID, uri, Status.INDEX_DELETED)); break; + case 'R': index.push(new Resource(IndexGroup.ID, uri, Status.INDEX_RENAMED, renameUri)); break; + case 'C': index.push(new Resource(IndexGroup.ID, uri, Status.INDEX_COPIED)); break; } switch (raw.y) { - case 'M': workingTree.push(new Resource(uri, Status.MODIFIED, renameUri)); break; - case 'D': workingTree.push(new Resource(uri, Status.DELETED, renameUri)); break; + case 'M': workingTree.push(new Resource(WorkingTreeGroup.ID, uri, Status.MODIFIED, renameUri)); break; + case 'D': workingTree.push(new Resource(WorkingTreeGroup.ID, uri, Status.DELETED, renameUri)); break; } }); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index 6ffbbb98c12..d09cbd0ba1e 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -619,15 +619,27 @@ declare module 'vscode' { } /** - * An SCM resource is the source control state of an underlying resource. + * An SCM resource represents a state of an underlying workspace resource + * within a certain SCM provider state. + * + * For example, consider file A to be modified. An SCM resource which would + * represent such state could have the following properties: + * + * - `uri = 'git:workingtree/A'` + * - `sourceUri = 'file:A'` */ export interface SCMResource { /** - * The [uri](#Uri) of the underlying resource. + * The [uri](#Uri) of this SCM resource. */ readonly uri: Uri; + /** + * The [uri](#Uri) of the underlying resource inside the workspace. + */ + readonly sourceUri: Uri; + /** * The [decorations](#SCMResourceDecorations) for this SCM resource. */ @@ -640,7 +652,13 @@ declare module 'vscode' { export interface SCMResourceGroup { /** - * The identifier of the SCM resource group. + * The [uri](#Uri) of this SCM resource group. + */ + readonly uri: Uri; + + /** + * The identifier of the SCM resource group, which will be used to populate + * the value of the `scmResourceGroup` context key. */ readonly id: string; @@ -662,7 +680,8 @@ declare module 'vscode' { export interface SCMProvider { /** - * The identifier of the SCM provider. + * The identifier of the SCM provider, which will be used to populate + * the value of the `scmProvider` context key. */ readonly id: string; @@ -753,9 +772,6 @@ declare module 'vscode' { */ export const inputBox: SCMInputBox; - // TODO@Joao - export function getResourceFromURI(uri: Uri): SCMResource | SCMResourceGroup | undefined; - /** * Registers an [SCM provider](#SCMProvider). * diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 76d57ea198f..a66cfafa891 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -456,11 +456,6 @@ export function createApiFactory(initData: IInitData, threadService: IThreadServ return extHostSCM.inputBox; } - @proposed(extension) - getResourceFromURI(uri) { - return extHostSCM.getResourceFromURI(uri); - } - @proposed(extension) registerSCMProvider(provider) { return extHostSCM.registerSCMProvider(provider); diff --git a/src/vs/workbench/api/node/extHost.protocol.ts b/src/vs/workbench/api/node/extHost.protocol.ts index 8a23a5e4c41..0e44c44a332 100644 --- a/src/vs/workbench/api/node/extHost.protocol.ts +++ b/src/vs/workbench/api/node/extHost.protocol.ts @@ -258,10 +258,17 @@ export interface SCMProviderFeatures { export type SCMRawResource = [ string /*uri*/, + string /*sourceUri*/, string[] /*icons: light, dark*/, boolean /*strike through*/ ]; -export type SCMRawResourceGroup = [string /*id*/, string /*label*/, SCMRawResource[]]; + +export type SCMRawResourceGroup = [ + string /*uri*/, + string /*id*/, + string /*label*/, + SCMRawResource[] +]; export abstract class MainThreadSCMShape { $register(id: string, features: SCMProviderFeatures): void { throw ni(); } @@ -409,7 +416,7 @@ export abstract class ExtHostTerminalServiceShape { } export abstract class ExtHostSCMShape { - $open(id: string, resourceGroupId: string, uri: string): TPromise { throw ni(); } + $open(id: string, uri: string): TPromise { throw ni(); } $acceptChanges(id: string): TPromise { throw ni(); } $getOriginalResource(id: string, uri: URI): TPromise { throw ni(); } $onInputBoxValueChange(value: string): TPromise { throw ni(); } diff --git a/src/vs/workbench/api/node/extHostSCM.ts b/src/vs/workbench/api/node/extHostSCM.ts index b7bae0228fd..52ae24cd9a4 100644 --- a/src/vs/workbench/api/node/extHostSCM.ts +++ b/src/vs/workbench/api/node/extHostSCM.ts @@ -26,10 +26,7 @@ function getIconPath(decorations: vscode.SCMResourceThemableDecorations) { export interface Cache { [providerId: string]: { - [groupId: string]: { - resourceGroup: vscode.SCMResourceGroup, - resources: { [uri: string]: vscode.SCMResource } - }; + [resourceUri: string]: vscode.SCMResource; }; } @@ -87,60 +84,6 @@ export class ExtHostSCM { this._inputBox = new ExtHostSCMInputBox(this._proxy); } - getResourceFromURI(uri: vscode.Uri): vscode.SCMResource | vscode.SCMResourceGroup | undefined { - if (uri.scheme !== 'scm') { - return undefined; - } - - const providerId = uri.authority; - const providerCache = this.cache[providerId]; - - if (!providerCache) { - return undefined; - } - - const match = /^\/([^/]+)(\/(.*))?$/.exec(uri.path); - - if (!match) { - return undefined; - } - - const resourceGroupId = match[1]; - const resourceGroupRef = providerCache[resourceGroupId]; - - if (!resourceGroupRef) { - return undefined; - } - - const rawResourceUri = match[3]; - - if (!rawResourceUri) { - return resourceGroupRef.resourceGroup; - } - - let resourceUri: string; - - try { - const rawResource = JSON.parse(rawResourceUri); - const resource = URI.from(rawResource); - resourceUri = resource.toString(); - } catch (err) { - resourceUri = undefined; - } - - if (!resourceUri) { - return undefined; - } - - const resource = resourceGroupRef.resources[resourceUri]; - - if (!resource) { - return undefined; - } - - return resource; - } - registerSCMProvider(provider: vscode.SCMProvider): Disposable { const providerId = provider.id; @@ -163,10 +106,11 @@ export class ExtHostSCM { this.cache[providerId] = Object.create(null); const rawResourceGroups = resourceGroups.map(g => { - const resources: { [id: string]: vscode.SCMResource; } = Object.create(null); - const rawResources = g.resources.map(r => { const uri = r.uri.toString(); + this.cache[providerId][uri] = r; + + const sourceUri = r.sourceUri.toString(); const iconPath = getIconPath(r.decorations); const lightIconPath = r.decorations && getIconPath(r.decorations.light) || iconPath; const darkIconPath = r.decorations && getIconPath(r.decorations.dark) || iconPath; @@ -181,14 +125,11 @@ export class ExtHostSCM { } const strikeThrough = r.decorations && !!r.decorations.strikeThrough; - resources[uri] = r; - return [uri, icons, strikeThrough] as SCMRawResource; + return [uri, sourceUri, icons, strikeThrough] as SCMRawResource; }); - this.cache[providerId][g.id] = { resourceGroup: g, resources }; - - return [g.id, g.label, rawResources] as SCMRawResourceGroup; + return [g.uri.toString(), g.id, g.label, rawResources] as SCMRawResourceGroup; }); this._proxy.$onChange(providerId, rawResourceGroups, provider.count, provider.state); @@ -201,16 +142,14 @@ export class ExtHostSCM { }); } - $open(providerId: string, resourceGroupId: string, uri: string): TPromise { + $open(providerId: string, uri: string): TPromise { const provider = this._providers[providerId]; if (!provider) { return TPromise.as(null); } - const providerCache = this.cache[providerId]; - const resourceGroup = providerCache[resourceGroupId]; - const resource = resourceGroup && resourceGroup.resources[uri]; + const resource = this.cache[providerId][uri]; if (!resource) { return TPromise.as(null); diff --git a/src/vs/workbench/api/node/mainThreadSCM.ts b/src/vs/workbench/api/node/mainThreadSCM.ts index eeafb005721..fbd9b74b082 100644 --- a/src/vs/workbench/api/node/mainThreadSCM.ts +++ b/src/vs/workbench/api/node/mainThreadSCM.ts @@ -49,7 +49,7 @@ class MainThreadSCMProvider implements ISCMProvider { return TPromise.as(null); } - return this.proxy.$open(this.id, resource.resourceGroupId, resource.uri.toString()); + return this.proxy.$open(this.id, resource.uri.toString()); } acceptChanges(): TPromise { @@ -76,10 +76,10 @@ class MainThreadSCMProvider implements ISCMProvider { $onChange(rawResourceGroups: SCMRawResourceGroup[], count: number | undefined, state: string | undefined): void { this._resources = rawResourceGroups.map(rawGroup => { - const [id, label, rawResources] = rawGroup; + const [uri, id, label, rawResources] = rawGroup; const resources = rawResources.map(rawResource => { - const [uri, icons, strikeThrough] = rawResource; + const [uri, sourceUri, icons, strikeThrough] = rawResource; const icon = icons[0]; const iconDark = icons[1] || icon; @@ -93,11 +93,12 @@ class MainThreadSCMProvider implements ISCMProvider { return { resourceGroupId: id, uri: URI.parse(uri), + sourceUri: URI.parse(sourceUri), decorations }; }); - return { id, label, resources }; + return { uri: URI.parse(uri), id, label, resources }; }); this._count = count; diff --git a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts index 07f78ec647a..92bff17cc66 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmMenus.ts @@ -13,7 +13,7 @@ import { IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IAction } from 'vs/base/common/actions'; import { fillInActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm'; -import { getSCMResourceURI, getSCMResourceGroupId } from './scmUtil'; +import { getSCMResourceGroupId } from './scmUtil'; export class SCMMenus implements IDisposable { @@ -105,7 +105,7 @@ export class SCMMenus implements IDisposable { const primary = []; const secondary = []; const result = { primary, secondary }; - fillInActions(menu, getSCMResourceURI(this.activeProviderId, resource), result, g => g === 'inline'); + fillInActions(menu, resource.uri, result, g => g === 'inline'); menu.dispose(); contextKeyService.dispose(); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts b/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts index a9b5b261175..865685bc782 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmUtil.ts @@ -6,26 +6,9 @@ 'use strict'; import { ISCMResourceGroup, ISCMResource } from 'vs/workbench/services/scm/common/scm'; -import URI from 'vs/base/common/uri'; export function isSCMResource(element: ISCMResourceGroup | ISCMResource): element is ISCMResource { - return !!(element as ISCMResource).uri; -} - -export function getSCMResourceURI(providerId: string, resource: ISCMResourceGroup | ISCMResource): URI { - if (isSCMResource(resource)) { - return URI.from({ - scheme: 'scm', - authority: providerId, - path: `/${resource.resourceGroupId}/${JSON.stringify(resource.uri)}` - }); - } else { - return URI.from({ - scheme: 'scm', - authority: providerId, - path: `/${resource.id}` - }); - } + return !!(element as ISCMResource).sourceUri; } export function getSCMResourceGroupId(resource: ISCMResourceGroup | ISCMResource): string { diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index d29196ca9d3..687267e9adf 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -40,12 +40,12 @@ import { InputBox } from 'vs/base/browser/ui/inputbox/inputBox'; import { IModelService } from 'vs/editor/common/services/modelService'; import { comparePaths } from 'vs/base/common/comparers'; import URI from 'vs/base/common/uri'; -import { isSCMResource, getSCMResourceURI } from './scmUtil'; +import { isSCMResource } from './scmUtil'; import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; function getElementId(element: ISCMResourceGroup | ISCMResource) { if (isSCMResource(element)) { - return `${element.resourceGroupId}:${element.uri.toString()}`; + return `${element.resourceGroupId}:${element.sourceUri.toString()}`; } else { return `${element.id}`; } @@ -155,7 +155,7 @@ class ResourceRenderer implements IRenderer { } renderElement(resource: ISCMResource, index: number, template: ResourceTemplate): void { - template.fileLabel.setFile(resource.uri); + template.fileLabel.setFile(resource.sourceUri); template.actionBar.clear(); template.actionBar.push(this.scmMenus.getResourceActions(resource)); toggleClass(template.name, 'strike-through', resource.decorations.strikeThrough); @@ -185,7 +185,7 @@ class Delegate implements IDelegate { } function resourceSorter(a: ISCMResource, b: ISCMResource): number { - return comparePaths(a.uri.fsPath, b.uri.fsPath); + return comparePaths(a.sourceUri.fsPath, b.sourceUri.fsPath); } export class SCMViewlet extends Viewlet { @@ -368,8 +368,7 @@ export class SCMViewlet extends Viewlet { } private getSelectedResources(): URI[] { - return this.list.getSelectedElements() - .map(r => getSCMResourceURI(this.activeProviderId, r)); + return this.list.getSelectedElements().map(r => r.uri); } dispose(): void { diff --git a/src/vs/workbench/services/scm/common/scm.ts b/src/vs/workbench/services/scm/common/scm.ts index 18729498965..a599f5af349 100644 --- a/src/vs/workbench/services/scm/common/scm.ts +++ b/src/vs/workbench/services/scm/common/scm.ts @@ -26,10 +26,12 @@ export interface ISCMResourceDecorations { export interface ISCMResource { readonly resourceGroupId: string; readonly uri: URI; + readonly sourceUri: URI; readonly decorations: ISCMResourceDecorations; } export interface ISCMResourceGroup { + readonly uri: URI; readonly id: string; readonly label: string; readonly resources: ISCMResource[]; -- GitLab