mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-22 09:38:38 +01:00
scm: move from pull to push model
This commit is contained in:
@@ -112,7 +112,12 @@ export class CommandCenter {
|
||||
await this.model.status();
|
||||
}
|
||||
|
||||
async open(resource: Resource): Promise<void> {
|
||||
@command('git.openResource')
|
||||
async openResource(resource: Resource): Promise<void> {
|
||||
await this._openResource(resource);
|
||||
}
|
||||
|
||||
private async _openResource(resource: Resource): Promise<void> {
|
||||
const left = this.getLeftResource(resource);
|
||||
const right = this.getRightResource(resource);
|
||||
const title = this.getTitle(resource);
|
||||
@@ -137,7 +142,7 @@ export class CommandCenter {
|
||||
return resource.original.with({ scheme: 'git', query: 'HEAD' });
|
||||
|
||||
case Status.MODIFIED:
|
||||
return resource.sourceUri.with({ scheme: 'git', query: '~' });
|
||||
return resource.resourceUri.with({ scheme: 'git', query: '~' });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,34 +151,34 @@ export class CommandCenter {
|
||||
case Status.INDEX_MODIFIED:
|
||||
case Status.INDEX_ADDED:
|
||||
case Status.INDEX_COPIED:
|
||||
return resource.sourceUri.with({ scheme: 'git' });
|
||||
return resource.resourceUri.with({ scheme: 'git' });
|
||||
|
||||
case Status.INDEX_RENAMED:
|
||||
return resource.sourceUri.with({ scheme: 'git' });
|
||||
return resource.resourceUri.with({ scheme: 'git' });
|
||||
|
||||
case Status.INDEX_DELETED:
|
||||
case Status.DELETED:
|
||||
return resource.sourceUri.with({ scheme: 'git', query: 'HEAD' });
|
||||
return resource.resourceUri.with({ scheme: 'git', query: 'HEAD' });
|
||||
|
||||
case Status.MODIFIED:
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
const uriString = resource.sourceUri.toString();
|
||||
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.sourceUri.toString() === uriString);
|
||||
const uriString = resource.resourceUri.toString();
|
||||
const [indexStatus] = this.model.indexGroup.resources.filter(r => r.resourceUri.toString() === uriString);
|
||||
|
||||
if (indexStatus && indexStatus.rename) {
|
||||
return indexStatus.rename;
|
||||
if (indexStatus && indexStatus.renameResourceUri) {
|
||||
return indexStatus.renameResourceUri;
|
||||
}
|
||||
|
||||
return resource.sourceUri;
|
||||
return resource.resourceUri;
|
||||
|
||||
case Status.BOTH_MODIFIED:
|
||||
return resource.sourceUri;
|
||||
return resource.resourceUri;
|
||||
}
|
||||
}
|
||||
|
||||
private getTitle(resource: Resource): string {
|
||||
const basename = path.basename(resource.sourceUri.fsPath);
|
||||
const basename = path.basename(resource.resourceUri.fsPath);
|
||||
|
||||
switch (resource.type) {
|
||||
case Status.INDEX_MODIFIED:
|
||||
@@ -251,7 +256,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
return await commands.executeCommand<void>('vscode.open', resource.sourceUri);
|
||||
return await commands.executeCommand<void>('vscode.open', resource.resourceUri);
|
||||
}
|
||||
|
||||
@command('git.openChange')
|
||||
@@ -262,7 +267,7 @@ export class CommandCenter {
|
||||
return;
|
||||
}
|
||||
|
||||
return await this.open(resource);
|
||||
return await this._openResource(resource);
|
||||
}
|
||||
|
||||
@command('git.stage')
|
||||
@@ -426,7 +431,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].sourceUri.fsPath))
|
||||
? localize('confirm discard', "Are you sure you want to discard changes in {0}?", path.basename(resources[0].resourceUri.fsPath))
|
||||
: localize('confirm discard multiple', "Are you sure you want to discard changes in {0} files?", resources.length);
|
||||
|
||||
const yes = localize('discard', "Discard Changes");
|
||||
@@ -769,20 +774,6 @@ export class CommandCenter {
|
||||
return 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.contextKey === resourceGroupId);
|
||||
|
||||
if (!resourceGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uriStr = uri.toString();
|
||||
const [resource] = resourceGroup.resources.filter(r => r.uri.toString() === uriStr);
|
||||
|
||||
return resource;
|
||||
}
|
||||
|
||||
if (uri.scheme === 'git') {
|
||||
uri = uri.with({ scheme: 'file' });
|
||||
}
|
||||
@@ -790,8 +781,8 @@ export class CommandCenter {
|
||||
if (uri.scheme === 'file') {
|
||||
const uriString = uri.toString();
|
||||
|
||||
return this.model.workingTreeGroup.resources.filter(r => r.sourceUri.toString() === uriString)[0]
|
||||
|| this.model.indexGroup.resources.filter(r => r.sourceUri.toString() === uriString)[0];
|
||||
return this.model.workingTreeGroup.resources.filter(r => r.resourceUri.toString() === uriString)[0]
|
||||
|| this.model.indexGroup.resources.filter(r => r.resourceUri.toString() === uriString)[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -78,10 +78,10 @@ async function init(context: ExtensionContext, disposables: Disposable[]): Promi
|
||||
}
|
||||
}
|
||||
|
||||
filterEvent(scm.onDidAcceptInputValue, () => scm.activeProvider === provider)
|
||||
filterEvent(scm.onDidAcceptInputValue, () => scm.activeSourceControl === provider.sourceControl)
|
||||
(commandCenter.commitWithInput, commandCenter, disposables);
|
||||
|
||||
if (scm.activeProvider === provider) {
|
||||
if (scm.activeSourceControl === provider.sourceControl) {
|
||||
scm.inputBox.value = await model.getCommitTemplate();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class TextEditorMergeDecorator {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.model.mergeGroup.resources.some(r => r.type === Status.BOTH_MODIFIED && r.sourceUri.toString() === this.uri)) {
|
||||
if (this.model.mergeGroup.resources.some(r => r.type === Status.BOTH_MODIFIED && r.resourceUri.toString() === this.uri)) {
|
||||
decorations = decorate(this.editor.document);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { Uri, EventEmitter, Event, SCMResource, SCMResourceDecorations, SCMResourceGroup, Disposable, window, workspace } from 'vscode';
|
||||
import { Uri, Command, EventEmitter, Event, SourceControlResourceState, SourceControlResourceDecorations, Disposable, window, workspace } from 'vscode';
|
||||
import { Git, Repository, Ref, Branch, Remote, PushOptions, Commit, GitErrorCodes, GitError } from './git';
|
||||
import { anyEvent, eventToPromise, filterEvent, mapEvent, EmptyDisposable, combinedDisposable, dispose } from './util';
|
||||
import { memoize, throttle, debounce } from './decorators';
|
||||
@@ -51,31 +51,29 @@ export enum Status {
|
||||
BOTH_MODIFIED
|
||||
}
|
||||
|
||||
export class Resource implements SCMResource {
|
||||
export class Resource implements SourceControlResourceState {
|
||||
|
||||
@memoize
|
||||
get uri(): Uri {
|
||||
return new Uri().with({
|
||||
scheme: 'git-resource',
|
||||
query: JSON.stringify({
|
||||
resourceGroupId: this.resourceGroupId,
|
||||
sourceUri: this.sourceUri.toString()
|
||||
})
|
||||
});
|
||||
get resourceUri(): Uri {
|
||||
if (this.renameResourceUri && (this._type === Status.MODIFIED || this._type === Status.DELETED || this._type === Status.INDEX_RENAMED)) {
|
||||
return this.renameResourceUri;
|
||||
}
|
||||
|
||||
return this._resourceUri;
|
||||
}
|
||||
|
||||
@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._sourceUri;
|
||||
get command(): Command {
|
||||
return {
|
||||
command: 'git.openResource',
|
||||
title: localize('open', "Open"),
|
||||
arguments: [this]
|
||||
};
|
||||
}
|
||||
|
||||
get type(): Status { return this._type; }
|
||||
get original(): Uri { return this._sourceUri; }
|
||||
get rename(): Uri | undefined { return this._rename; }
|
||||
get original(): Uri { return this._resourceUri; }
|
||||
get renameResourceUri(): Uri | undefined { return this._renameResourceUri; }
|
||||
|
||||
private static Icons = {
|
||||
light: {
|
||||
@@ -134,23 +132,19 @@ export class Resource implements SCMResource {
|
||||
}
|
||||
}
|
||||
|
||||
get decorations(): SCMResourceDecorations {
|
||||
get decorations(): SourceControlResourceDecorations {
|
||||
const light = { iconPath: this.getIconPath('light') };
|
||||
const dark = { iconPath: this.getIconPath('dark') };
|
||||
|
||||
return { strikeThrough: this.strikeThrough, light, dark };
|
||||
}
|
||||
|
||||
constructor(private resourceGroupId: string, private _sourceUri: Uri, private _type: Status, private _rename?: Uri) {
|
||||
// console.log(this);
|
||||
}
|
||||
constructor(private resourceGroupId: string, private _resourceUri: Uri, private _type: Status, private _renameResourceUri?: Uri) { }
|
||||
}
|
||||
|
||||
export class ResourceGroup implements SCMResourceGroup {
|
||||
|
||||
@memoize
|
||||
get uri(): Uri { return Uri.parse(`git-resource-group:${this.contextKey}`); }
|
||||
export class ResourceGroup {
|
||||
|
||||
get id(): string { return this._id; }
|
||||
get contextKey(): string { return this._id; }
|
||||
get label(): string { return this._label; }
|
||||
get resources(): Resource[] { return this._resources; }
|
||||
@@ -280,8 +274,8 @@ export class Model implements Disposable {
|
||||
private _onDidChangeState = new EventEmitter<State>();
|
||||
readonly onDidChangeState: Event<State> = this._onDidChangeState.event;
|
||||
|
||||
private _onDidChangeResources = new EventEmitter<SCMResourceGroup[]>();
|
||||
readonly onDidChangeResources: Event<SCMResourceGroup[]> = this._onDidChangeResources.event;
|
||||
private _onDidChangeResources = new EventEmitter<void>();
|
||||
readonly onDidChangeResources: Event<void> = this._onDidChangeResources.event;
|
||||
|
||||
@memoize
|
||||
get onDidChange(): Event<void> {
|
||||
@@ -308,22 +302,6 @@ export class Model implements Disposable {
|
||||
private _workingTreeGroup = new WorkingTreeGroup([]);
|
||||
get workingTreeGroup(): WorkingTreeGroup { return this._workingTreeGroup; }
|
||||
|
||||
get resources(): ResourceGroup[] {
|
||||
const result: ResourceGroup[] = [];
|
||||
|
||||
if (this._mergeGroup.resources.length > 0) {
|
||||
result.push(this._mergeGroup);
|
||||
}
|
||||
|
||||
if (this._indexGroup.resources.length > 0) {
|
||||
result.push(this._indexGroup);
|
||||
}
|
||||
|
||||
result.push(this._workingTreeGroup);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _HEAD: Branch | undefined;
|
||||
get HEAD(): Branch | undefined {
|
||||
return this._HEAD;
|
||||
@@ -356,7 +334,7 @@ export class Model implements Disposable {
|
||||
this._mergeGroup = new MergeGroup();
|
||||
this._indexGroup = new IndexGroup();
|
||||
this._workingTreeGroup = new WorkingTreeGroup();
|
||||
this._onDidChangeResources.fire(this.resources);
|
||||
this._onDidChangeResources.fire();
|
||||
}
|
||||
|
||||
private onWorkspaceChange: Event<Uri>;
|
||||
@@ -412,7 +390,7 @@ export class Model implements Disposable {
|
||||
|
||||
@throttle
|
||||
async add(...resources: Resource[]): Promise<void> {
|
||||
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.sourceUri.fsPath)));
|
||||
await this.run(Operation.Add, () => this.repository.add(resources.map(r => r.resourceUri.fsPath)));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -423,7 +401,7 @@ export class Model implements Disposable {
|
||||
|
||||
@throttle
|
||||
async revertFiles(...resources: Resource[]): Promise<void> {
|
||||
await this.run(Operation.RevertFiles, () => this.repository.revertFiles('HEAD', resources.map(r => r.sourceUri.fsPath)));
|
||||
await this.run(Operation.RevertFiles, () => this.repository.revertFiles('HEAD', resources.map(r => r.resourceUri.fsPath)));
|
||||
}
|
||||
|
||||
@throttle
|
||||
@@ -447,11 +425,11 @@ export class Model implements Disposable {
|
||||
switch (r.type) {
|
||||
case Status.UNTRACKED:
|
||||
case Status.IGNORED:
|
||||
toClean.push(r.sourceUri.fsPath);
|
||||
toClean.push(r.resourceUri.fsPath);
|
||||
break;
|
||||
|
||||
default:
|
||||
toCheckout.push(r.sourceUri.fsPath);
|
||||
toCheckout.push(r.resourceUri.fsPath);
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -671,7 +649,7 @@ export class Model implements Disposable {
|
||||
this._mergeGroup = new MergeGroup(merge);
|
||||
this._indexGroup = new IndexGroup(index);
|
||||
this._workingTreeGroup = new WorkingTreeGroup(workingTree);
|
||||
this._onDidChangeResources.fire(this.resources);
|
||||
this._onDidChangeResources.fire();
|
||||
}
|
||||
|
||||
private onFSChange(uri: Uri): void {
|
||||
|
||||
@@ -5,17 +5,15 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
import { scm, Uri, Disposable, SCMProvider, SCMResourceGroup, Event, workspace } from 'vscode';
|
||||
import { Model, Resource, State } from './model';
|
||||
import { scm, Uri, Disposable, SourceControl, SourceControlResourceGroup, Event, workspace, commands } from 'vscode';
|
||||
import { Model, State } from './model';
|
||||
import { CommandCenter } from './commands';
|
||||
import { mapEvent } from './util';
|
||||
|
||||
export class GitSCMProvider implements SCMProvider {
|
||||
export class GitSCMProvider {
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
get contextKey(): string { return 'git'; }
|
||||
get resources(): SCMResourceGroup[] { return this.model.resources; }
|
||||
|
||||
get onDidChange(): Event<this> {
|
||||
return mapEvent(this.model.onDidChange, () => this);
|
||||
@@ -38,16 +36,40 @@ export class GitSCMProvider implements SCMProvider {
|
||||
switch (countBadge) {
|
||||
case 'off': return 0;
|
||||
case 'tracked': return this.model.indexGroup.resources.length;
|
||||
default: return this.model.resources.reduce((r, g) => r + g.resources.length, 0);
|
||||
default:
|
||||
return this.model.mergeGroup.resources.length
|
||||
+ this.model.indexGroup.resources.length
|
||||
+ this.model.workingTreeGroup.resources.length;
|
||||
}
|
||||
}
|
||||
|
||||
constructor(private model: Model, private commandCenter: CommandCenter) {
|
||||
scm.registerSCMProvider(this);
|
||||
private _sourceControl: SourceControl;
|
||||
|
||||
get sourceControl(): SourceControl {
|
||||
return this._sourceControl;
|
||||
}
|
||||
|
||||
open(resource: Resource): void {
|
||||
this.commandCenter.open(resource);
|
||||
private mergeGroup: SourceControlResourceGroup;
|
||||
private indexGroup: SourceControlResourceGroup;
|
||||
private workingTreeGroup: SourceControlResourceGroup;
|
||||
|
||||
constructor(private model: Model, private commandCenter: CommandCenter) {
|
||||
this._sourceControl = scm.createSourceControl('git', 'Git');
|
||||
this._sourceControl.quickDiffProvider = this;
|
||||
this.disposables.push(this._sourceControl);
|
||||
|
||||
this.mergeGroup = this._sourceControl.createResourceGroup(model.mergeGroup.id, model.mergeGroup.label);
|
||||
this.indexGroup = this._sourceControl.createResourceGroup(model.indexGroup.id, model.indexGroup.label);
|
||||
this.workingTreeGroup = this._sourceControl.createResourceGroup(model.workingTreeGroup.id, model.workingTreeGroup.label);
|
||||
|
||||
this.mergeGroup.hideWhenEmpty = true;
|
||||
this.indexGroup.hideWhenEmpty = true;
|
||||
|
||||
this.disposables.push(this.mergeGroup);
|
||||
this.disposables.push(this.indexGroup);
|
||||
this.disposables.push(this.workingTreeGroup);
|
||||
|
||||
model.onDidChange(this.onDidModelChange, this, this.disposables);
|
||||
}
|
||||
|
||||
provideOriginalResource(uri: Uri): Uri | undefined {
|
||||
@@ -60,6 +82,14 @@ export class GitSCMProvider implements SCMProvider {
|
||||
return new Uri().with({ scheme: 'git-original', query: uri.path, path: uri.path + '.git' });
|
||||
}
|
||||
|
||||
private onDidModelChange(): void {
|
||||
this.mergeGroup.resourceStates = this.model.mergeGroup.resources;
|
||||
this.indexGroup.resourceStates = this.model.indexGroup.resources;
|
||||
this.workingTreeGroup.resourceStates = this.model.workingTreeGroup.resources;
|
||||
this._sourceControl.count = this.count;
|
||||
commands.executeCommand('setContext', 'gitState', this.stateContextKey);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables.forEach(d => d.dispose());
|
||||
this.disposables = [];
|
||||
|
||||
Reference in New Issue
Block a user