diff --git a/extensions/git/src/main.ts b/extensions/git/src/main.ts index 0b846f921f3..160bc44973c 100644 --- a/extensions/git/src/main.ts +++ b/extensions/git/src/main.ts @@ -5,7 +5,7 @@ 'use strict'; -import { scm, ExtensionContext, workspace, Uri, window, Disposable } from 'vscode'; +import { scm, ExtensionContext, workspace, Uri, window, Disposable, SCMProvider, SCMResource, SCMResourceGroup, EventEmitter, Event } from 'vscode'; import * as path from 'path'; import { findGit, Git } from './git'; import { Model } from './model'; @@ -18,9 +18,40 @@ export function log(...args: any[]): void { console.log.apply(console, ['git:', ...args]); } -class GitSCMProvider { - resourceGroups = []; - onDidChangeResourceGroup: any = null; +const Status: any = {}; + +class GitSCMResource implements SCMResource { + + get uri(): Uri { return this._uri; } + + constructor(private _uri: Uri, type: any) { + + } +} + +class GitSCMResourceGroup implements SCMResourceGroup { + resources: GitSCMResource[] = []; +} + +class GitSCMProvider implements SCMProvider { + + private disposables: Disposable[] = []; + + private merge: GitSCMResourceGroup = new GitSCMResourceGroup(); + private index: GitSCMResourceGroup = new GitSCMResourceGroup(); + private workingTree: GitSCMResourceGroup = new GitSCMResourceGroup(); + + get resourceGroups(): SCMResourceGroup[] { + return [this.merge, this.index, this.workingTree]; + } + + private _onDidChangeResourceGroup = new EventEmitter(); + get onDidChangeResourceGroup(): Event { return this._onDidChangeResourceGroup.event; } + + constructor(private model: Model) { + model.onDidChange(this.onModelChange, this, this.disposables); + model.update(true); + } getOriginalResource(uri: Uri): Uri | undefined { if (uri.scheme !== 'file') { @@ -29,6 +60,57 @@ class GitSCMProvider { return uri.with({ scheme: 'git-index' }); } + + private onModelChange(): void { + const status = this.model.status; + const index: GitSCMResource[] = []; + const workingTree: GitSCMResource[] = []; + const merge: GitSCMResource[] = []; + + status.forEach(raw => { + const uri = Uri.file(path.join(this.model.repositoryRoot, raw.path)); + + switch (raw.x + raw.y) { + case '??': return workingTree.push(new GitSCMResource(uri, Status.UNTRACKED)); + case '!!': return workingTree.push(new GitSCMResource(uri, Status.IGNORED)); + case 'DD': return merge.push(new GitSCMResource(uri, Status.BOTH_DELETED)); + case 'AU': return merge.push(new GitSCMResource(uri, Status.ADDED_BY_US)); + case 'UD': return merge.push(new GitSCMResource(uri, Status.DELETED_BY_THEM)); + case 'UA': return merge.push(new GitSCMResource(uri, Status.ADDED_BY_THEM)); + case 'DU': return merge.push(new GitSCMResource(uri, Status.DELETED_BY_US)); + case 'AA': return merge.push(new GitSCMResource(uri, Status.BOTH_ADDED)); + case 'UU': return merge.push(new GitSCMResource(uri, Status.BOTH_MODIFIED)); + } + + let isModifiedInIndex = false; + + switch (raw.x) { + case 'M': index.push(new GitSCMResource(uri, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break; + case 'A': index.push(new GitSCMResource(uri, Status.INDEX_ADDED)); break; + case 'D': index.push(new GitSCMResource(uri, Status.INDEX_DELETED)); break; + case 'R': index.push(new GitSCMResource(uri, Status.INDEX_RENAMED/*, raw.rename*/)); break; + case 'C': index.push(new GitSCMResource(uri, Status.INDEX_COPIED)); break; + } + + switch (raw.y) { + case 'M': workingTree.push(new GitSCMResource(uri, Status.MODIFIED/*, raw.rename*/)); break; + case 'D': workingTree.push(new GitSCMResource(uri, Status.DELETED/*, raw.rename*/)); break; + } + }); + + this.merge.resources = merge; + this.index.resources = index; + this.workingTree.resources = workingTree; + + this._onDidChangeResourceGroup.fire(this.merge); + this._onDidChangeResourceGroup.fire(this.index); + this._onDidChangeResourceGroup.fire(this.workingTree); + } + + dispose(): void { + this.disposables.forEach(d => d.dispose()); + this.disposables = []; + } } class TextDocumentContentProvider { @@ -63,10 +145,12 @@ async function init(disposables: Disposable[]): Promise { const info = await findGit(pathHint); const git = new Git({ gitPath: info.path, version: info.version }); const repository = git.open(rootPath); - const model = new Model(repository); + const repositoryRoot = await repository.getRoot(); + const model = new Model(repositoryRoot, repository); + const provider = new GitSCMProvider(model); - model.onDidChange(() => { - console.log(model.status); + provider.onDidChangeResourceGroup(g => { + console.log(g.resources); }); const outputChannel = window.createOutputChannel('git'); @@ -75,7 +159,7 @@ async function init(disposables: Disposable[]): Promise { disposables.push( registerCommands(), - scm.registerSCMProvider('git', new GitSCMProvider()), + scm.registerSCMProvider('git', provider), workspace.registerTextDocumentContentProvider('git-index', new TextDocumentContentProvider(git, rootPath)), outputChannel ); diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 203d81639b2..f8e7e898f25 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -15,10 +15,14 @@ export class Model { private _onDidChange = new EventEmitter(); readonly onDidChange: Event = this._onDidChange.event; - constructor(private repository: Repository) { + constructor(private _repositoryRoot: string, private repository: Repository) { } + get repositoryRoot(): string { + return this._repositoryRoot; + } + private _status: IFileStatus[]; get status(): IFileStatus[] { return this._status; @@ -39,14 +43,21 @@ export class Model { return this._remotes; } + update(now = false): void { + if (now) { + this._update(); + } else { + this.eventuallyUpdate(); + } + } + @debounce(500) - triggerUpdate(): void { + private eventuallyUpdate(): void { this.update(); } @decorate(throttle) - private async update(): Promise { - console.log('START'); + private async _update(): Promise { const status = await this.repository.getStatus(); let HEAD: IRef | undefined; @@ -70,7 +81,6 @@ export class Model { this._HEAD = HEAD; this._refs = refs; this._remotes = remotes; - console.log('END'); this._onDidChange.fire(); } } \ No newline at end of file