diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index b13e2b91b4b..bbdda5ec461 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -6,9 +6,9 @@ 'use strict'; import { workspace, WorkspaceFoldersChangeEvent, Uri, window, Event, EventEmitter, QuickPickItem, Disposable, SourceControl, SourceControlResourceGroup, TextEditor } from 'vscode'; -import { Repository } from './repository'; -import { memoize, sequentialize } from './decorators'; -import { dispose } from './util'; +import { Repository, RepositoryState } from './repository'; +import { memoize, sequentialize, debounce } from './decorators'; +import { dispose, anyEvent, filterEvent } from './util'; import { Git, GitErrorCodes } from './git'; import * as path from 'path'; import * as nls from 'vscode-nls'; @@ -44,6 +44,8 @@ export class Model { private openRepositories: OpenRepository[] = []; get repositories(): Repository[] { return this.openRepositories.map(r => r.repository); } + private possibleGitRepositoryPaths = new Set(); + private disposables: Disposable[] = []; constructor(private git: Git) { @@ -52,6 +54,29 @@ export class Model { window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); this.onDidChangeVisibleTextEditors(window.visibleTextEditors); + + const fsWatcher = workspace.createFileSystemWatcher('**'); + this.disposables.push(fsWatcher); + + const onWorkspaceChange = anyEvent(fsWatcher.onDidChange, fsWatcher.onDidCreate, fsWatcher.onDidDelete); + const onGitRepositoryChange = filterEvent(onWorkspaceChange, uri => /\/\.git\//.test(uri.path)); + const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); + onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); + } + + private onPossibleGitRepositoryChange(uri: Uri): void { + const possibleGitRepositoryPath = uri.fsPath.replace(/\.git.*$/, ''); + this.possibleGitRepositoryPaths.add(possibleGitRepositoryPath); + this.eventuallyScanPossibleGitRepositories(); + } + + @debounce(500) + private eventuallyScanPossibleGitRepositories(): void { + for (const path of this.possibleGitRepositoryPaths) { + this.tryOpenRepository(path); + } + + this.possibleGitRepositoryPaths = new Set(); } private async onDidChangeWorkspaceFolders({ added, removed }: WorkspaceFoldersChangeEvent): Promise { @@ -112,11 +137,11 @@ export class Model { } private open(repository: Repository): void { - // const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === State.Disposed); - // const disappearListener = onDidDisappearRepository(() => disposable.dispose()); + const onDidDisappearRepository = filterEvent(repository.onDidChangeState, state => state === RepositoryState.Disposed); + const disappearListener = onDidDisappearRepository(() => dispose()); const changeListener = repository.onDidChangeRepository(uri => this._onDidChangeRepository.fire({ repository, uri })); const dispose = () => { - // disappearListener.dispose(); + disappearListener.dispose(); changeListener.dispose(); repository.dispose(); this.openRepositories = this.openRepositories.filter(e => e !== openRepository); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 6d724a195fe..89cbb093f03 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -25,7 +25,7 @@ function getIconUri(iconName: string, theme: string): Uri { return Uri.file(path.join(iconsRootPath, theme, `${iconName}.svg`)); } -export enum State { +export enum RepositoryState { Idle, Disposed } @@ -296,8 +296,8 @@ export class Repository implements Disposable { private _onDidChangeRepository = new EventEmitter(); readonly onDidChangeRepository: Event = this._onDidChangeRepository.event; - private _onDidChangeState = new EventEmitter(); - readonly onDidChangeState: Event = this._onDidChangeState.event; + private _onDidChangeState = new EventEmitter(); + readonly onDidChangeState: Event = this._onDidChangeState.event; private _onDidChangeStatus = new EventEmitter(); readonly onDidChangeStatus: Event = this._onDidChangeStatus.event; @@ -345,9 +345,9 @@ export class Repository implements Disposable { private _operations = new OperationsImpl(); get operations(): Operations { return this._operations; } - private _state = State.Idle; - get state(): State { return this._state; } - set state(state: State) { + private _state = RepositoryState.Idle; + get state(): RepositoryState { return this._state; } + set state(state: RepositoryState) { this._state = state; this._onDidChangeState.fire(state); @@ -630,7 +630,7 @@ export class Repository implements Disposable { } private async run(operation: Operation, runOperation: () => Promise = () => Promise.resolve(null)): Promise { - if (this.state !== State.Idle) { + if (this.state !== RepositoryState.Idle) { throw new Error('Repository not initialized'); } @@ -648,7 +648,7 @@ export class Repository implements Disposable { return result; } catch (err) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { - this.state = State.Disposed; + this.state = RepositoryState.Disposed; } throw err; @@ -780,8 +780,8 @@ export class Repository implements Disposable { let stateContextKey = ''; switch (this.state) { - case State.Idle: stateContextKey = 'idle'; break; - case State.Disposed: stateContextKey = 'norepo'; break; + case RepositoryState.Idle: stateContextKey = 'idle'; break; + case RepositoryState.Disposed: stateContextKey = 'norepo'; break; } this._onDidChangeStatus.fire(); diff --git a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts index bbbb4dbee95..defd35c848d 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmActivity.ts @@ -37,6 +37,7 @@ export class StatusUpdater implements IWorkbenchContribution { const removeDisposable = onDidRemove(() => { disposable.dispose(); this.disposables = this.disposables.filter(d => d !== removeDisposable); + this.render(); }); const disposable = combinedDisposable([changeDisposable, removeDisposable]);