diff --git a/extensions/git/src/autofetch.ts b/extensions/git/src/autofetch.ts index 930fc2f05f327228b437eea505936dcddd5da505..a984a20c6b61405cbb4bc23890c59ce8ad2b7829 100644 --- a/extensions/git/src/autofetch.ts +++ b/extensions/git/src/autofetch.ts @@ -5,16 +5,23 @@ 'use strict'; -import { workspace, Disposable } from 'vscode'; +import { workspace, Disposable, EventEmitter } from 'vscode'; import { GitErrorCodes } from './git'; import { Repository } from './repository'; -import { throttle } from './decorators'; +import { eventToPromise, filterEvent } from './util'; export class AutoFetcher { private static Period = 3 * 60 * 1000 /* three minutes */; + + private _onDidChange = new EventEmitter(); + private onDidChange = this._onDidChange.event; + + private _enabled: boolean = false; + get enabled(): boolean { return this._enabled; } + set enabled(enabled: boolean) { this._enabled = enabled; this._onDidChange.fire(enabled); } + private disposables: Disposable[] = []; - private timer: NodeJS.Timer; constructor(private repository: Repository) { workspace.onDidChangeConfiguration(this.onConfiguration, this, this.disposables); @@ -32,26 +39,41 @@ export class AutoFetcher { } enable(): void { - if (this.timer) { + if (this.enabled) { return; } - this.fetch(); - this.timer = setInterval(() => this.fetch(), AutoFetcher.Period); + this.enabled = true; + this.run(); } disable(): void { - clearInterval(this.timer); + this.enabled = false; } - @throttle - private async fetch(): Promise { - try { - await this.repository.fetch(); - } catch (err) { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - this.disable(); + private async run(): Promise { + while (this.enabled) { + await this.repository.whenIdleAndFocused(); + + if (!this.enabled) { + return; } + + try { + await this.repository.fetch(); + } catch (err) { + if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { + this.disable(); + } + } + + if (!this.enabled) { + return; + } + + const timeout = new Promise(c => setTimeout(c, AutoFetcher.Period)); + const whenDisabled = eventToPromise(filterEvent(this.onDidChange, enabled => !enabled)); + await Promise.race([timeout, whenDisabled]); } } diff --git a/extensions/git/src/contentProvider.ts b/extensions/git/src/contentProvider.ts index ff8529d1612b587bf447152ffd7b691070ca1c99..78852ec6685e03de21cef44f13763af435fd2643 100644 --- a/extensions/git/src/contentProvider.ts +++ b/extensions/git/src/contentProvider.ts @@ -6,9 +6,10 @@ 'use strict'; import { workspace, Uri, Disposable, Event, EventEmitter, window } from 'vscode'; -import { debounce } from './decorators'; +import { debounce, throttle } from './decorators'; import { fromGitUri } from './uri'; import { Model, ModelChangeEvent } from './model'; +import { filterEvent, eventToPromise } from './util'; interface CacheRow { uri: Uri; @@ -50,7 +51,13 @@ export class GitContentProvider { this.fireChangeEvents(); } - private fireChangeEvents(): void { + @throttle + private async fireChangeEvents(): Promise { + if (!window.state.focused) { + const onDidFocusWindow = filterEvent(window.onDidChangeWindowState, e => e.focused); + await eventToPromise(onDidFocusWindow); + } + Object.keys(this.cache).forEach(key => { const uri = this.cache[key].uri; const fsPath = uri.fsPath; diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 7f2e3e213c6b8890be280fbf99d37ddb10065f13..da1549397449510e1702467bc4203e9140001170 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -816,7 +816,7 @@ export class Repository implements Disposable { await timeout(5000); } - private async whenIdleAndFocused(): Promise { + async whenIdleAndFocused(): Promise { while (true) { if (!this.operations.isIdle()) { await eventToPromise(this.onDidRunOperation);