Skip to content

Commit

Permalink
wip: try to use vscode.open and vscode.diff in git/scm
Browse files Browse the repository at this point in the history
related to #110397
  • Loading branch information
joaomoreno committed Nov 13, 2020
1 parent c6efea0 commit ed4d86e
Show file tree
Hide file tree
Showing 7 changed files with 149 additions and 44 deletions.
129 changes: 104 additions & 25 deletions extensions/git/src/repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,7 @@ export class Resource implements SourceControlResourceState {

@memoize
get command(): Command {
return {
command: 'git.openResource',
title: localize('open', "Open"),
arguments: [this]
};
return this._commandResolver.resolveResourceCommand(this);
}

get resourceGroupType(): ResourceGroupType { return this._resourceGroupType; }
Expand Down Expand Up @@ -262,11 +258,12 @@ export class Resource implements SourceControlResourceState {
}

constructor(
private _commandResolver: ResourceCommandResolver,
private _resourceGroupType: ResourceGroupType,
private _resourceUri: Uri,
private _type: Status,
private _useIcons: boolean,
private _renameResourceUri?: Uri
private _renameResourceUri?: Uri,
) { }
}

Expand Down Expand Up @@ -553,6 +550,87 @@ class DotGitWatcher implements IFileWatcher {
}
}

class ResourceCommandResolver {

constructor(private repository: Repository) { }

resolveResourceCommand(resource: Resource): Command {
const left = this.getLeftResource(resource);
const right = this.getRightResource(resource);

if (!left) {
return {
command: 'vscode.open',
title: localize('open', "Open"),
arguments: [right]
};
} else {
return {
command: 'vscode.diff',
title: localize('open', "Open"),
arguments: [left, right, 'GIT DIFF']
};
}
}

private getLeftResource(resource: Resource): Uri | undefined {
switch (resource.type) {
case Status.INDEX_MODIFIED:
case Status.INDEX_RENAMED:
case Status.INDEX_ADDED:
return toGitUri(resource.original, 'HEAD');

case Status.MODIFIED:
case Status.UNTRACKED:
return toGitUri(resource.resourceUri, '~');

case Status.DELETED_BY_US:
case Status.DELETED_BY_THEM:
return toGitUri(resource.resourceUri, '~1');
}
return undefined;
}

private getRightResource(resource: Resource): Uri {
switch (resource.type) {
case Status.INDEX_MODIFIED:
case Status.INDEX_ADDED:
case Status.INDEX_COPIED:
case Status.INDEX_RENAMED:
return toGitUri(resource.resourceUri, '');

case Status.INDEX_DELETED:
case Status.DELETED:
return toGitUri(resource.resourceUri, 'HEAD');

case Status.DELETED_BY_US:
return toGitUri(resource.resourceUri, '~3');

case Status.DELETED_BY_THEM:
return toGitUri(resource.resourceUri, '~2');

case Status.MODIFIED:
case Status.UNTRACKED:
case Status.IGNORED:
case Status.INTENT_TO_ADD:
const uriString = resource.resourceUri.toString();
const [indexStatus] = this.repository.indexGroup.resourceStates.filter(r => r.resourceUri.toString() === uriString);

if (indexStatus && indexStatus.renameResourceUri) {
return indexStatus.renameResourceUri;
}

return resource.resourceUri;

case Status.BOTH_ADDED:
case Status.BOTH_MODIFIED:
return resource.resourceUri;
}

throw new Error('Should never happen');
}
}

export class Repository implements Disposable {

private _onDidChangeRepository = new EventEmitter<Uri>();
Expand Down Expand Up @@ -683,6 +761,7 @@ export class Repository implements Disposable {
private isRepositoryHuge = false;
private didWarnAboutLimit = false;

private resourceCommandResolver = new ResourceCommandResolver(this);
private disposables: Disposable[] = [];

constructor(
Expand Down Expand Up @@ -1637,36 +1716,36 @@ export class Repository implements Disposable {

switch (raw.x + raw.y) {
case '??': switch (untrackedChanges) {
case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons));
case 'mixed': return workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.UNTRACKED, useIcons));
case 'separate': return untracked.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.UNTRACKED, useIcons));
default: return undefined;
}
case '!!': switch (untrackedChanges) {
case 'mixed': return workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
case 'separate': return untracked.push(new Resource(ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons));
case 'mixed': return workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.IGNORED, useIcons));
case 'separate': return untracked.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Untracked, uri, Status.IGNORED, useIcons));
default: return undefined;
}
case 'DD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
case 'AU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
case 'UD': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons));
case 'UA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM, useIcons));
case 'DU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.DELETED_BY_US, useIcons));
case 'AA': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_ADDED, useIcons));
case 'UU': return merge.push(new Resource(ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
case 'DD': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_DELETED, useIcons));
case 'AU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.ADDED_BY_US, useIcons));
case 'UD': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.DELETED_BY_THEM, useIcons));
case 'UA': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.ADDED_BY_THEM, useIcons));
case 'DU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.DELETED_BY_US, useIcons));
case 'AA': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_ADDED, useIcons));
case 'UU': return merge.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Merge, uri, Status.BOTH_MODIFIED, useIcons));
}

switch (raw.x) {
case 'M': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
case 'A': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
case 'D': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
case 'R': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
case 'C': index.push(new Resource(ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
case 'M': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_MODIFIED, useIcons)); break;
case 'A': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_ADDED, useIcons)); break;
case 'D': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_DELETED, useIcons)); break;
case 'R': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_RENAMED, useIcons, renameUri)); break;
case 'C': index.push(new Resource(this.resourceCommandResolver, ResourceGroupType.Index, uri, Status.INDEX_COPIED, useIcons, renameUri)); break;
}

switch (raw.y) {
case 'M': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
case 'D': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
case 'A': workingTree.push(new Resource(ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
case 'M': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.MODIFIED, useIcons, renameUri)); break;
case 'D': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.DELETED, useIcons, renameUri)); break;
case 'A': workingTree.push(new Resource(this.resourceCommandResolver, ResourceGroupType.WorkingTree, uri, Status.INTENT_TO_ADD, useIcons, renameUri)); break;
}

return undefined;
Expand Down
8 changes: 5 additions & 3 deletions src/vs/workbench/api/browser/mainThreadSCM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ class MainThreadSCMResource implements ISCMResource {
readonly sourceUri: URI,
readonly resourceGroup: ISCMResourceGroup,
readonly decorations: ISCMResourceDecorations,
readonly contextValue: string | undefined
readonly contextValue: string | undefined,
readonly command: Command | undefined
) { }

open(preserveFocus: boolean): Promise<void> {
Expand Down Expand Up @@ -201,7 +202,7 @@ class MainThreadSCMProvider implements ISCMProvider {

for (const [start, deleteCount, rawResources] of groupSlices) {
const resources = rawResources.map(rawResource => {
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] = rawResource;
const [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command] = rawResource;
const icon = icons[0];
const iconDark = icons[1] || icon;
const decorations = {
Expand All @@ -220,7 +221,8 @@ class MainThreadSCMProvider implements ISCMProvider {
URI.revive(sourceUri),
group,
decorations,
contextValue || undefined
contextValue || undefined,
command
);
});

Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/api/common/extHost.protocol.ts
Original file line number Diff line number Diff line change
Expand Up @@ -865,7 +865,8 @@ export type SCMRawResource = [
string /*tooltip*/,
boolean /*strike through*/,
boolean /*faded*/,
string /*context value*/
string /*context value*/,
ICommandDto | undefined /*command*/
];

export type SCMRawResourceSplice = [
Expand Down
17 changes: 12 additions & 5 deletions src/vs/workbench/api/common/extHostCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { revive } from 'vs/base/common/marshalling';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IPosition, Position } from 'vs/editor/common/core/position';
import { URI } from 'vs/base/common/uri';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { ISelection } from 'vs/editor/common/core/selection';
Expand Down Expand Up @@ -274,7 +274,8 @@ export class CommandsConverter {

toInternal(command: vscode.Command, disposables: DisposableStore): ICommandDto;
toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined;
toInternal(command: vscode.Command | undefined, disposables: DisposableStore): ICommandDto | undefined {
toInternal(command: vscode.Command): { command: ICommandDto, disposable: IDisposable };
toInternal(command: vscode.Command | undefined, disposables?: DisposableStore): ICommandDto | { command: ICommandDto, disposable: IDisposable } | undefined {

if (!command || !command.command) {
return undefined;
Expand All @@ -287,6 +288,7 @@ export class CommandsConverter {
tooltip: command.tooltip
};

let disposable: IDisposable = Disposable.None;

const apiCommand = this._lookupApiCommand(command.command);
if (apiCommand) {
Expand All @@ -301,10 +303,11 @@ export class CommandsConverter {

const id = ++this._cachIdPool;
this._cache.set(id, command);
disposables.add(toDisposable(() => {
disposable = toDisposable(() => {
this._cache.delete(id);
this._logService.trace('CommandsConverter#DISPOSE', id);
}));
});
disposables?.add(disposable);
result.$ident = id;

result.id = this._delegatingCommandId;
Expand All @@ -313,7 +316,11 @@ export class CommandsConverter {
this._logService.trace('CommandsConverter#CREATE', command.command, id);
}

return result;
if (disposables) {
return result;
} else {
return { command: result, disposable };
}
}

fromInternal(command: modes.Command): vscode.Command | undefined {
Expand Down
18 changes: 14 additions & 4 deletions src/vs/workbench/api/common/extHostSCM.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,8 +223,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
private _resourceHandlePool: number = 0;
private _resourceStates: vscode.SourceControlResourceState[] = [];

private _resourceStatesMap: Map<ResourceStateHandle, vscode.SourceControlResourceState> = new Map<ResourceStateHandle, vscode.SourceControlResourceState>();
private _resourceStatesCommandsMap: Map<ResourceStateHandle, vscode.Command> = new Map<ResourceStateHandle, vscode.Command>();
private _resourceStatesMap = new Map<ResourceStateHandle, vscode.SourceControlResourceState>();
private _resourceStatesCommandsMap = new Map<ResourceStateHandle, vscode.Command>();
private _resourceStatesDisposablesMap = new Map<ResourceStateHandle, IDisposable>();

private readonly _onDidUpdateResourceStates = new Emitter<void>();
readonly onDidUpdateResourceStates = this._onDidUpdateResourceStates.event;
Expand Down Expand Up @@ -302,9 +303,16 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const lightIconUri = r.decorations && getIconResource(r.decorations.light) || iconUri;
const darkIconUri = r.decorations && getIconResource(r.decorations.dark) || iconUri;
const icons: UriComponents[] = [];
let command: ICommandDto | undefined;

if (r.command) {
this._resourceStatesCommandsMap.set(handle, r.command);
if (r.command.command === 'vscode.open' || r.command.command === 'vscode.diff') {
const internalCommand = this._commands.converter.toInternal(r.command);
command = internalCommand.command;
this._resourceStatesDisposablesMap.set(handle, internalCommand.disposable);
} else {
this._resourceStatesCommandsMap.set(handle, r.command);
}
}

if (lightIconUri) {
Expand All @@ -320,7 +328,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
const faded = r.decorations && !!r.decorations.faded;
const contextValue = r.contextValue || '';

const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] as SCMRawResource;
const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue, command] as SCMRawResource;

return { rawResource, handle };
});
Expand All @@ -340,6 +348,8 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
for (const handle of handlesToDelete) {
this._resourceStatesMap.delete(handle);
this._resourceStatesCommandsMap.delete(handle);
this._resourceStatesDisposablesMap.get(handle)?.dispose();
this._resourceStatesDisposablesMap.delete(handle);
}
}

Expand Down
15 changes: 10 additions & 5 deletions src/vs/workbench/contrib/scm/browser/scmViewPane.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ import { ColorScheme } from 'vs/platform/theme/common/theme';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { LabelFuzzyScore } from 'vs/base/browser/ui/tree/abstractTree';
import { Selection } from 'vs/editor/common/core/selection';
import { API_OPEN_DIFF_EDITOR_COMMAND_ID, API_OPEN_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';

type TreeElement = ISCMRepository | ISCMInput | ISCMResourceGroup | IResourceNode<ISCMResource, ISCMResourceGroup> | ISCMResource;

Expand Down Expand Up @@ -1936,13 +1937,17 @@ export class SCMViewPane extends ViewPane {
}

// ISCMResource
await e.element.open(!!e.editorOptions.preserveFocus);
if (e.element.command?.id === API_OPEN_EDITOR_COMMAND_ID || e.element.command?.id === API_OPEN_DIFF_EDITOR_COMMAND_ID) {
await this.commandService.executeCommand(e.element.command.id, ...(e.element.command.arguments || []), e);
} else {
await e.element.open(!!e.editorOptions.preserveFocus);

if (e.editorOptions.pinned) {
const activeEditorPane = this.editorService.activeEditorPane;
if (e.editorOptions.pinned) {
const activeEditorPane = this.editorService.activeEditorPane;

if (activeEditorPane) {
activeEditorPane.group.pinEditor(activeEditorPane.input);
if (activeEditorPane) {
activeEditorPane.group.pinEditor(activeEditorPane.input);
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/vs/workbench/contrib/scm/common/scm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ export interface ISCMResource {
readonly resourceGroup: ISCMResourceGroup;
readonly sourceUri: URI;
readonly decorations: ISCMResourceDecorations;
readonly contextValue?: string;
readonly contextValue: string | undefined;
readonly command: Command | undefined;
open(preserveFocus: boolean): Promise<void>;
}

Expand Down

0 comments on commit ed4d86e

Please sign in to comment.