diff --git a/src/vs/workbench/parts/git/browser/gitServices.ts b/src/vs/workbench/parts/git/browser/gitServices.ts index 8ee4d8bb64d..5020e0db18d 100644 --- a/src/vs/workbench/parts/git/browser/gitServices.ts +++ b/src/vs/workbench/parts/git/browser/gitServices.ts @@ -388,7 +388,7 @@ export class GitService extends ee.EventEmitter private editorService: IWorkbenchEditorService; private lifecycleService: ILifecycleService; private outputService: IOutputService; - private raw: git.IRawGitService; + protected raw: git.IRawGitService; private state: git.ServiceState; private operations: git.IGitOperation[]; @@ -398,6 +398,7 @@ export class GitService extends ee.EventEmitter private needsRefresh: boolean; private refreshDelayer: async.ThrottledDelayer; private autoFetcher: AutoFetcher; + allowHugeRepositories: boolean; get onOutput(): Event { return this.raw.onOutput; } @@ -410,7 +411,8 @@ export class GitService extends ee.EventEmitter @IOutputService outputService: IOutputService, @IWorkspaceContextService contextService: IWorkspaceContextService, @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService storageService: IStorageService + @IStorageService storageService: IStorageService, + @IConfigurationService private configurationService: IConfigurationService ) { super(); @@ -431,6 +433,7 @@ export class GitService extends ee.EventEmitter this.needsRefresh = false; this.refreshDelayer = new async.PeriodThrottledDelayer(500, 10000); this.autoFetcher = this.instantiationService.createInstance(AutoFetcher, this); + this.allowHugeRepositories = false; this.registerListeners(); @@ -474,6 +477,18 @@ export class GitService extends ee.EventEmitter this.toDispose.push(this.eventService.addListener2(FileEventType.FILE_CHANGES,(e) => this.onFileChanges(e))); this.toDispose.push(this.eventService.addListener2(filesCommon.EventType.FILE_SAVED, (e) => this.onTextFileChange(e))); this.toDispose.push(this.eventService.addListener2(filesCommon.EventType.FILE_REVERTED, (e) => this.onTextFileChange(e))); + this.toDispose.push(this.configurationService.onDidUpdateConfiguration(() => { + if (this.allowHugeRepositories) { + return; + } + + const config = this.configurationService.getConfiguration('git'); + this.allowHugeRepositories = config.allowLargeRepositories; + + if (this.allowHugeRepositories) { + this.triggerStatus(true); + } + })); this.lifecycleService.onShutdown(this.dispose, this); } @@ -551,7 +566,20 @@ export class GitService extends ee.EventEmitter } public status(): winjs.Promise { - return this.run(git.ServiceOperations.STATUS, () => this.raw.status()); + const config = this.configurationService.getConfiguration('git'); + + if (this.allowHugeRepositories || config.allowLargeRepositories) { + return this.run(git.ServiceOperations.STATUS, () => this.raw.status()); + } + + return this.raw.statusCount().then(count => { + if (count > 5000 && !this.allowHugeRepositories) { + this.transition(git.ServiceState.Huge); + return winjs.TPromise.as(this.model); + } + + return this.run(git.ServiceOperations.STATUS, () => this.raw.status()); + }); } public init(): winjs.Promise { diff --git a/src/vs/workbench/parts/git/browser/gitViewlet.ts b/src/vs/workbench/parts/git/browser/gitViewlet.ts index 9c56bcd9bb0..c3ef3fe5b42 100644 --- a/src/vs/workbench/parts/git/browser/gitViewlet.ts +++ b/src/vs/workbench/parts/git/browser/gitViewlet.ts @@ -21,6 +21,7 @@ import gitless = require('vs/workbench/parts/git/browser/views/gitless/gitlessVi import notroot = require('vs/workbench/parts/git/browser/views/notroot/notrootView'); import noworkspace = require('vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView'); import { DisabledView } from './views/disabled/disabledView'; +import { HugeView } from './views/huge/hugeView'; import {IInstantiationService} from 'vs/platform/instantiation/common/instantiation'; import {IProgressService, IProgressRunner} from 'vs/platform/progress/common/progress'; import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry'; @@ -61,7 +62,8 @@ export class GitViewlet this.instantiationService.createInstance(gitless.GitlessView), new notroot.NotRootView(), new noworkspace.NoWorkspaceView(), - new DisabledView() + new DisabledView(), + this.instantiationService.createInstance(HugeView) ]; views.forEach(v => { @@ -192,6 +194,9 @@ export class GitViewlet } else if (this.gitService.getState() === git.ServiceState.NotAtRepoRoot) { this.setView('notroot'); this.progressRunner = null; + } else if (this.gitService.getState() === git.ServiceState.Huge) { + this.setView('huge'); + this.progressRunner = null; } else if (this.gitService.isIdle()) { this.setView('changes'); this.progressRunner = null; diff --git a/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts b/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts index 8f84641260f..88da067b6d1 100644 --- a/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts +++ b/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts @@ -532,6 +532,11 @@ export function registerContributions(): void { type: 'boolean', description: nls.localize('gitLongCommit', "Whether long commit messages should be warned about."), default: true + }, + 'git.allowLargeRepositories': { + type: 'boolean', + description: nls.localize('gitLargeRepos', "Always allow large repositories to be managed by Code."), + default: false } } }); diff --git a/src/vs/workbench/parts/git/browser/views/huge/hugeView.css b/src/vs/workbench/parts/git/browser/views/huge/hugeView.css new file mode 100644 index 00000000000..a428d2328c0 --- /dev/null +++ b/src/vs/workbench/parts/git/browser/views/huge/hugeView.css @@ -0,0 +1,12 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +.git-viewlet > .huge-view { + padding: 0 20px 0 20px; +} + +.git-viewlet > .huge-view > p { + line-height: 1.5em; +} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts b/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts new file mode 100644 index 00000000000..b278d6c6105 --- /dev/null +++ b/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts @@ -0,0 +1,83 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +'use strict'; + +import 'vs/css!./hugeView'; +import nls = require('vs/nls'); +import winjs = require('vs/base/common/winjs.base'); +import ee = require('vs/base/common/eventEmitter'); +import view = require('vs/workbench/parts/git/browser/views/view'); +import builder = require('vs/base/browser/builder'); +import actions = require('vs/base/common/actions'); +import * as dom from 'vs/base/browser/dom'; +import { IGitService } from 'vs/workbench/parts/git/common/git'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import {Button} from 'vs/base/browser/ui/button/button'; + +const $ = dom.emmet; + +export class HugeView extends ee.EventEmitter implements view.IView { + + ID = 'huge'; + private _element: HTMLElement; + + constructor(@IGitService private gitService: IGitService) { + super(); + } + + get element(): HTMLElement { + if (!this._element) { + this.render(); + } + + return this._element; + } + + private render(): void { + this._element = $('.huge-view'); + + dom.append(this._element, $('p')).textContent = nls.localize('huge', "Your repository appears to have many active changes.\nThis can cause Code to become very slow."); + + const settingP = dom.append(this._element, $('p')); + dom.append(settingP, document.createTextNode(nls.localize('setting', "You can permanently disable this warning with the following setting:"))); + dom.append(settingP, document.createTextNode(' ')); + const pre = dom.append(settingP, $('pre')); + pre.style.display = 'inline'; + pre.textContent = 'git.allowLargeRepositories'; + + const button = new Button(this._element); + button.label = nls.localize('allo', "Allow large repositories"); + button.addListener2('click', (e) => { + dom.EventHelper.stop(e); + this.gitService.allowHugeRepositories = true; + this.gitService.status().done(null, onUnexpectedError); + }); + } + + focus(): void { + return; + } + + layout(dimension: builder.Dimension): void { + return; + } + + setVisible(visible:boolean): winjs.TPromise { + return winjs.TPromise.as(null); + } + + getControl(): ee.IEventEmitter { + return null; + } + + getActions(): actions.IAction[] { + return []; + } + + getSecondaryActions(): actions.IAction[] { + return []; + } +} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/common/git.ts b/src/vs/workbench/parts/git/common/git.ts index 3181503da96..a8f1b233a19 100644 --- a/src/vs/workbench/parts/git/common/git.ts +++ b/src/vs/workbench/parts/git/common/git.ts @@ -154,6 +154,7 @@ export enum ServiceState { NotARepo, NotAtRepoRoot, OK, + Huge, NoGit, Disabled, NotAWorkspace @@ -231,6 +232,7 @@ export interface IGitConfiguration { path: string; autofetch: boolean; enableLongCommitWarning: boolean; + allowLargeRepositories: boolean; } // Service interfaces @@ -264,6 +266,7 @@ export interface IRawGitService { onOutput: Event; getVersion(): TPromise; serviceState(): TPromise; + statusCount(): TPromise; status(): TPromise; init(): TPromise; add(filesPaths?: string[]): TPromise; @@ -289,6 +292,7 @@ export var IGitService = createDecorator(GIT_SERVICE_ID); export interface IGitService extends IEventEmitter { serviceId: ServiceIdentifier; + allowHugeRepositories: boolean; onOutput: Event; status(): TPromise; init(): TPromise; diff --git a/src/vs/workbench/parts/git/common/gitIpc.ts b/src/vs/workbench/parts/git/common/gitIpc.ts index 26798d0b371..b0db7eb4ccc 100644 --- a/src/vs/workbench/parts/git/common/gitIpc.ts +++ b/src/vs/workbench/parts/git/common/gitIpc.ts @@ -13,6 +13,7 @@ import { IRawGitService, RawServiceState, IRawStatus, IPushOptions, IAskpassServ export interface IGitChannel extends IChannel { call(command: 'getVersion'): TPromise; call(command: 'serviceState'): TPromise; + call(command: 'statusCount'): TPromise; call(command: 'status'): TPromise; call(command: 'init'): TPromise; call(command: 'add', filesPaths?: string[]): TPromise; @@ -42,7 +43,7 @@ export class GitChannel implements IGitChannel { switch (command) { case 'getVersion': return this.service.then(s => s.getVersion()); case 'serviceState': return this.service.then(s => s.serviceState()); - case 'status': return this.service.then(s => s.status()); + case 'statusCount': return this.service.then(s => s.statusCount()); case 'status': return this.service.then(s => s.status()); case 'init': return this.service.then(s => s.init()); case 'add': return this.service.then(s => s.add(args)); @@ -90,6 +91,10 @@ export class GitChannelClient implements IRawGitService { return this.channel.call('serviceState'); } + statusCount(): TPromise { + return this.channel.call('statusCount'); + } + status(): TPromise { return this.channel.call('status'); } diff --git a/src/vs/workbench/parts/git/common/noopGitService.ts b/src/vs/workbench/parts/git/common/noopGitService.ts index ed3507d80ef..ddfd63bbab6 100644 --- a/src/vs/workbench/parts/git/common/noopGitService.ts +++ b/src/vs/workbench/parts/git/common/noopGitService.ts @@ -30,6 +30,10 @@ export class NoOpGitService implements IRawGitService { return TPromise.as(RawServiceState.OK); } + statusCount(): TPromise { + return TPromise.as(0); + } + status(): TPromise { return TPromise.as(NoOpGitService.STATUS); } diff --git a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts b/src/vs/workbench/parts/git/electron-browser/electronGitService.ts index bf997cab174..4e07fda9bec 100644 --- a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts +++ b/src/vs/workbench/parts/git/electron-browser/electronGitService.ts @@ -198,6 +198,6 @@ export class ElectronGitService extends GitService { raw = new GitChannelClient(channel); } - super(raw, instantiationService, eventService, messageService, editorService, outputService, contextService, lifecycleService, storageService); + super(raw, instantiationService, eventService, messageService, editorService, outputService, contextService, lifecycleService, storageService, configurationService); } } diff --git a/src/vs/workbench/parts/git/node/rawGitService.ts b/src/vs/workbench/parts/git/node/rawGitService.ts index dfaad0012e9..052977c6a50 100644 --- a/src/vs/workbench/parts/git/node/rawGitService.ts +++ b/src/vs/workbench/parts/git/node/rawGitService.ts @@ -50,6 +50,10 @@ export class RawGitService implements IRawGitService { ); } + statusCount(): TPromise { + return this.status().then(r => r.status.length); + } + status(): TPromise { return this.repo.getStatus() .then(status => this.repo.getHEAD()