diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 151d6ac5b20..03609bc5772 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -20,8 +20,6 @@ import { UpdateChannel } from 'vs/platform/update/common/updateIpc'; import { UpdateService } from 'vs/platform/update/electron-main/updateService'; import { Server as ElectronIPCServer } from 'vs/base/parts/ipc/electron-main/ipc.electron-main'; import { Server, connect, Client } from 'vs/base/parts/ipc/node/ipc.net'; -import { AskpassChannel } from 'vs/workbench/parts/git/common/gitIpc'; -import { GitAskpassService } from 'vs/workbench/parts/git/electron-main/askpassService'; import { SharedProcess } from 'vs/code/electron-main/sharedProcess'; import { Mutex } from 'windows-mutex'; import { LaunchService, LaunchChannel, ILaunchService } from './launch'; @@ -138,11 +136,6 @@ export class VSCodeApplication { app.setAppUserModelId(product.win32AppUserModelId); } - // Register Main IPC connections - const askpassService = new GitAskpassService(); - const askpassChannel = new AskpassChannel(askpassService); - this.mainIpcServer.registerChannel('askpass', askpassChannel); - // Create Electron IPC Server this.electronIpcServer = new ElectronIPCServer(); diff --git a/src/vs/workbench/api/node/mainThreadExtensionService.ts b/src/vs/workbench/api/node/mainThreadExtensionService.ts index 414cc32accf..05ca99e2f24 100644 --- a/src/vs/workbench/api/node/mainThreadExtensionService.ts +++ b/src/vs/workbench/api/node/mainThreadExtensionService.ts @@ -60,8 +60,6 @@ export class MainProcessExtensionService extends AbstractExtensionService scm viewlet - - const map = SCMPreview.enabled - ? (id => id === 'workbench.view.git' ? 'workbench.view.scm' : id) - : (id => id === 'workbench.view.scm' ? 'workbench.view.git' : id); - this.pinnedViewlets = pinnedViewlets - .map(map) + // TODO@Ben: Migrate git => scm viewlet + .map(id => id === 'workbench.view.git' ? 'workbench.view.scm' : id) .filter(arrays.uniqueFilter(str => str)); } else { diff --git a/src/vs/workbench/electron-browser/shell.ts b/src/vs/workbench/electron-browser/shell.ts index 03296bc74ab..33d9257064c 100644 --- a/src/vs/workbench/electron-browser/shell.ts +++ b/src/vs/workbench/electron-browser/shell.ts @@ -97,7 +97,6 @@ import { MainProcessTextMateSyntax } from 'vs/editor/electron-browser/textMate/T import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { restoreFontInfo, readFontInfo, saveFontInfo } from 'vs/editor/browser/config/configuration'; import * as browser from 'vs/base/browser/browser'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; import { readdir } from 'vs/base/node/pfs'; import { join } from 'path'; import 'vs/platform/opener/browser/opener.contribution'; @@ -386,9 +385,7 @@ export class WorkbenchShell { this.timerService.beforeExtensionLoad = Date.now(); - // TODO@Joao: remove - const disabledExtensions = SCMPreview.enabled ? [] : ['vscode.git']; - this.extensionService = instantiationService.createInstance(MainProcessExtensionService, disabledExtensions); + this.extensionService = instantiationService.createInstance(MainProcessExtensionService); serviceCollection.set(IExtensionService, this.extensionService); extensionHostProcessWorker.start(this.extensionService); this.extensionService.onReady().done(() => { diff --git a/src/vs/workbench/electron-browser/workbench.main.ts b/src/vs/workbench/electron-browser/workbench.main.ts index 8b287038985..f71d678b112 100644 --- a/src/vs/workbench/electron-browser/workbench.main.ts +++ b/src/vs/workbench/electron-browser/workbench.main.ts @@ -45,11 +45,6 @@ import 'vs/workbench/parts/search/browser/openAnythingHandler'; // can be packag import 'vs/workbench/parts/scm/electron-browser/scm.contribution'; import 'vs/workbench/parts/scm/electron-browser/scmViewlet'; // can be packaged separately -import 'vs/workbench/parts/git/electron-browser/git.contribution'; -import 'vs/workbench/parts/git/browser/gitQuickOpen'; -import 'vs/workbench/parts/git/browser/gitActions.contribution'; -import 'vs/workbench/parts/git/browser/gitViewlet'; // can be packaged separately - import 'vs/workbench/parts/debug/electron-browser/debug.contribution'; import 'vs/workbench/parts/debug/browser/debugQuickOpen'; import 'vs/workbench/parts/debug/electron-browser/repl'; diff --git a/src/vs/workbench/parts/git/browser/gitActions.contribution.ts b/src/vs/workbench/parts/git/browser/gitActions.contribution.ts deleted file mode 100644 index 6d2ea142908..00000000000 --- a/src/vs/workbench/parts/git/browser/gitActions.contribution.ts +++ /dev/null @@ -1,749 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 nls = require('vs/nls'); -import lifecycle = require('vs/base/common/lifecycle'); -import platform = require('vs/platform/platform'); -import abr = require('vs/workbench/browser/actionBarRegistry'); -import { TPromise } from 'vs/base/common/winjs.base'; -import editorbrowser = require('vs/editor/browser/editorBrowser'); -import editorcommon = require('vs/editor/common/editorCommon'); -import baseeditor = require('vs/workbench/browser/parts/editor/baseEditor'); -import WorkbenchEditorCommon = require('vs/workbench/common/editor'); -import tdeditor = require('vs/workbench/browser/parts/editor/textDiffEditor'); -import teditor = require('vs/workbench/browser/parts/editor/textEditor'); -import filesCommon = require('vs/workbench/parts/files/common/files'); -import gitcontrib = require('vs/workbench/parts/git/browser/gitWorkbenchContributions'); -import diffei = require('vs/workbench/common/editor/diffEditorInput'); -import { IGitService, Status, IFileStatus, StatusType } from 'vs/workbench/parts/git/common/git'; -import gitei = require('vs/workbench/parts/git/browser/gitEditorInputs'); -import { getSelectedChanges, applyChangesToModel, getChangeRevertEdits } from 'vs/workbench/parts/git/common/stageRanges'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IViewlet } from 'vs/workbench/common/viewlet'; -import { IPartService, Parts } from 'vs/workbench/services/part/common/partService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import wbar = require('vs/workbench/common/actionRegistry'); -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { - OpenChangeAction, OpenFileAction, SyncAction, PullAction, PushAction, - PushToRemoteAction, PublishAction, StartGitBranchAction, StartGitCheckoutAction, - InputCommitAction, UndoLastCommitAction, BaseStageAction, BaseUnstageAction, - PullWithRebaseAction -} from './gitActions'; -import paths = require('vs/base/common/paths'); -import URI from 'vs/base/common/uri'; -import { FileEditorInput } from 'vs/workbench/parts/files/common/editors/fileEditorInput'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; -import { IMessageService } from 'vs/platform/message/common/message'; - -function getStatus(gitService: IGitService, contextService: IWorkspaceContextService, input: WorkbenchEditorCommon.IFileEditorInput): IFileStatus { - const model = gitService.getModel(); - const repositoryRoot = model.getRepositoryRoot(); - const statusModel = model.getStatus(); - const repositoryRelativePath = paths.normalize(paths.relative(repositoryRoot, input.getResource().fsPath)); - - return statusModel.getWorkingTreeStatus().find(repositoryRelativePath) || - statusModel.getIndexStatus().find(repositoryRelativePath) || - statusModel.getMergeStatus().find(repositoryRelativePath); -} - -class OpenInDiffAction extends baseeditor.EditorInputAction { - - static ID = 'workbench.action.git.openInDiff'; - static Label = nls.localize('switchToChangesView', "Switch to Changes View"); - - private gitService: IGitService; - private viewletService: IViewletService; - private editorService: IWorkbenchEditorService; - private partService: IPartService; - private contextService: IWorkspaceContextService; - private toDispose: lifecycle.IDisposable[]; - - constructor( @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IGitService gitService: IGitService, @IViewletService viewletService: IViewletService, @IPartService partService: IPartService, @IWorkspaceContextService contextService: IWorkspaceContextService) { - super(OpenInDiffAction.ID, OpenInDiffAction.Label); - - this.class = 'git-action open-in-diff'; - this.gitService = gitService; - this.viewletService = viewletService; - this.editorService = editorService; - this.partService = partService; - this.contextService = contextService; - - this.toDispose = [this.gitService.addBulkListener(() => this.onGitStateChanged())]; - - this.enabled = this.isEnabled(); - } - - public isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - const model = this.gitService.getModel(); - if (!model || !(typeof model.getRepositoryRoot() === 'string')) { - return false; - } - - var status = this.getStatus(); - - return status && ( - status.getStatus() === Status.MODIFIED || - status.getStatus() === Status.INDEX_MODIFIED || - status.getStatus() === Status.INDEX_RENAMED - ); - } - - private onGitStateChanged(): void { - if (this.gitService.isIdle()) { - this.enabled = this.isEnabled(); - } - } - - private getStatus(): IFileStatus { - return getStatus(this.gitService, this.contextService, this.input); - } - - public run(context?: WorkbenchEditorCommon.IEditorContext): TPromise { - const event = context ? context.event : null; - const sideBySide = !!(event && (event.ctrlKey || event.metaKey)); - const editor = this.editorService.getActiveEditor().getControl(); - const viewState = editor ? editor.saveViewState() : null; - - return this.gitService.getInput(this.getStatus()).then((input) => { - var promise = TPromise.as(null); - - if (this.partService.isVisible(Parts.SIDEBAR_PART)) { - promise = this.viewletService.openViewlet(gitcontrib.VIEWLET_ID, false); - } - - return promise.then(() => { - var options = new WorkbenchEditorCommon.TextDiffEditorOptions(); - options.forceOpen = true; - options.autoRevealFirstChange = false; - - return this.editorService.openEditor(input, options, sideBySide).then((editor) => { - if (viewState) { - var codeEditor = this.editorService.getActiveEditor().getControl(); - codeEditor.restoreViewState({ - original: { - cursorState: undefined, - viewState: undefined, - contributionsState: undefined - }, - modified: viewState - }); - } - }); - }); - }); - } - - public dispose(): void { - this.toDispose = lifecycle.dispose(this.toDispose); - } -} - -class OpenInEditorAction extends baseeditor.EditorInputAction { - - private static DELETED_STATES = [Status.BOTH_DELETED, Status.DELETED, Status.DELETED_BY_US, Status.INDEX_DELETED]; - static ID = 'workbench.action.git.openInEditor'; - static LABEL = nls.localize('openInEditor', "Switch to Editor View"); - - private gitService: IGitService; - private fileService: IFileService; - private viewletService: IViewletService; - private editorService: IWorkbenchEditorService; - private partService: IPartService; - private contextService: IWorkspaceContextService; - - constructor( @IFileService fileService: IFileService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IGitService gitService: IGitService, @IViewletService viewletService: IViewletService, @IPartService partService: IPartService, @IWorkspaceContextService contextService: IWorkspaceContextService) { - super(OpenInEditorAction.ID, OpenInEditorAction.LABEL); - - this.class = 'git-action open-in-editor'; - this.gitService = gitService; - this.fileService = fileService; - this.viewletService = viewletService; - this.editorService = editorService; - this.partService = partService; - this.contextService = contextService; - - this.enabled = this.isEnabled(); - } - - public isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - const model = this.gitService.getModel(); - if (!model || !(typeof model.getRepositoryRoot() === 'string')) { - return false; - } - - var status: IFileStatus = (this.input).getFileStatus(); - if (OpenInEditorAction.DELETED_STATES.indexOf(status.getStatus()) > -1) { - return false; - } - - return true; - } - - public run(context?: WorkbenchEditorCommon.IEditorContext): TPromise { - const model = this.gitService.getModel(); - const resource = URI.file(paths.join(model.getRepositoryRoot(), this.getRepositoryRelativePath())); - const event = context ? context.event : null; - const sideBySide = !!(event && (event.ctrlKey || event.metaKey)); - const modifiedViewState = this.saveTextViewState(); - - return this.fileService.resolveFile(resource).then(stat => { - return this.editorService.openEditor({ - resource: stat.resource, - options: { - forceOpen: true - } - }, sideBySide).then(editor => { - this.restoreTextViewState(modifiedViewState); - - if (this.partService.isVisible(Parts.SIDEBAR_PART)) { - return this.viewletService.openViewlet(filesCommon.VIEWLET_ID, false); - } - return undefined; - }); - }); - } - - private saveTextViewState(): editorcommon.ICodeEditorViewState { - var textEditor = this.getTextEditor(); - if (textEditor) { - return textEditor.saveViewState(); - } - - return null; - } - - private restoreTextViewState(state: editorcommon.ICodeEditorViewState): void { - var textEditor = this.getTextEditor(); - if (textEditor) { - return textEditor.restoreViewState(state); - } - } - - private getTextEditor(): editorcommon.ICommonCodeEditor { - var editor = this.editorService.getActiveEditor(); - - if (editor instanceof tdeditor.TextDiffEditor) { - return (editor.getControl()).getModifiedEditor(); - } else if (editor instanceof teditor.BaseTextEditor) { - return editor.getControl(); - } - - return null; - } - - private getRepositoryRelativePath(): string { - var status: IFileStatus = (this.input).getFileStatus(); - - if (status.getStatus() === Status.INDEX_RENAMED) { - return status.getRename(); - } else { - var indexStatus = this.gitService.getModel().getStatus().find(status.getPath(), StatusType.INDEX); - - if (indexStatus && indexStatus.getStatus() === Status.INDEX_RENAMED) { - return indexStatus.getRename(); - } else { - return status.getPath(); - } - } - } -} - -export class WorkbenchStageAction extends BaseStageAction { - - static ID = 'workbench.action.git.stage'; - static LABEL = nls.localize('workbenchStage', "Stage"); - private contextService: IWorkspaceContextService; - - constructor( - id = WorkbenchStageAction.ID, - label = WorkbenchStageAction.LABEL, - @IGitService gitService: IGitService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IWorkspaceContextService contextService: IWorkspaceContextService - ) { - super(id, label, '', gitService, editorService); - this.contextService = contextService; - this.onGitServiceChange(); - } - - protected updateEnablement(): void { - if (this.contextService) { - this.enabled = this.isEnabled(); - } else { - this.enabled = super.isEnabled(); - } - } - - isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - const editor = this.editorService.getActiveEditor(); - if (!editor || !(editor instanceof baseeditor.BaseEditor)) { - return false; - } - - return true; - } - - run(context?: any): TPromise { - const input = this.editorService.getActiveEditor().input; - let fileStatus: IFileStatus; - - if (gitei.isGitEditorInput(input)) { - const gitInput = input as gitei.GitDiffEditorInput; - fileStatus = gitInput.getFileStatus(); - } else { - fileStatus = getStatus(this.gitService, this.contextService, input as WorkbenchEditorCommon.IFileEditorInput); - } - - if (!fileStatus) { - return TPromise.as(null); - } - - return super.run(fileStatus); - } -} - -export class WorkbenchUnstageAction extends BaseUnstageAction { - - static ID = 'workbench.action.git.unstage'; - static LABEL = nls.localize('workbenchUnstage', "Unstage"); - private contextService: IWorkspaceContextService; - - constructor( - id = WorkbenchUnstageAction.ID, - label = WorkbenchUnstageAction.LABEL, - @IGitService gitService: IGitService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IWorkspaceContextService contextService: IWorkspaceContextService - ) { - super(id, label, '', gitService, editorService); - this.contextService = contextService; - this.onGitServiceChange(); - } - - protected updateEnablement(): void { - if (this.contextService) { - this.enabled = this.isEnabled(); - } else { - this.enabled = super.isEnabled(); - } - } - - isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - const editor = this.editorService.getActiveEditor(); - if (!editor || !(editor instanceof baseeditor.BaseEditor)) { - return false; - } - - return true; - } - - run(context?: any): TPromise { - const input = this.editorService.getActiveEditor().input; - let fileStatus: IFileStatus; - - if (gitei.isGitEditorInput(input)) { - const gitInput = input as gitei.GitDiffEditorInput; - fileStatus = gitInput.getFileStatus(); - } else { - fileStatus = getStatus(this.gitService, this.contextService, input as WorkbenchEditorCommon.IFileEditorInput); - } - - if (!fileStatus) { - return TPromise.as(null); - } - - return super.run(fileStatus); - } -} - -export abstract class BaseStageRangesAction extends baseeditor.EditorInputAction { - private gitService: IGitService; - private editorService: IWorkbenchEditorService; - private editor: editorbrowser.IDiffEditor; - - constructor(id: string, label: string, editor: tdeditor.TextDiffEditor, @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(id, label); - - this.editorService = editorService; - this.gitService = gitService; - this.editor = editor.getControl(); - this.editor.getModifiedEditor().onDidChangeCursorSelection(() => this.updateEnablement()); - this.editor.onDidUpdateDiff(() => this.updateEnablement()); - this.class = 'git-action stage-ranges'; - } - - public isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService || !this.editorService) { - return false; - } - - var changes = this.editor.getLineChanges(); - var selections = this.editor.getSelections(); - - if (!changes || !selections || selections.length === 0) { - return false; - } - - return getSelectedChanges(changes, selections).length > 0; - } - - protected getRangesAppliedResult(editor: editorbrowser.IDiffEditor) { - var selections = editor.getSelections(); - var changes = getSelectedChanges(editor.getLineChanges(), selections); - return applyChangesToModel(editor.getModel().original, editor.getModel().modified, changes); - } - - public run(): TPromise { - var result = this.getRangesAppliedResult(this.editor); - - var status = (this.input).getFileStatus(); - var path = status.getPath(); - var viewState = this.editor.saveViewState(); - - return this.gitService.stage(status.getPath(), result).then(() => { - var statusModel = this.gitService.getModel().getStatus(); - - status = statusModel.getWorkingTreeStatus().find(path) || statusModel.getIndexStatus().find(path); - - if (status) { - return this.gitService.getInput(status).then((input) => { - var options = new WorkbenchEditorCommon.TextDiffEditorOptions(); - options.forceOpen = true; - options.autoRevealFirstChange = false; - - return this.editorService.openEditor(input, options, this.position).then(() => { - this.editor.restoreViewState(viewState); - }); - }); - } - return undefined; - }); - } - - private updateEnablement(): void { - this.enabled = this.isEnabled(); - } -} - -export class StageRangesAction extends BaseStageRangesAction { - static ID = 'workbench.action.git.stageRanges'; - static LABEL = nls.localize('stageSelectedLines', "Stage Selected Lines"); - - constructor(editor: tdeditor.TextDiffEditor, @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(StageRangesAction.ID, StageRangesAction.LABEL, editor, gitService, editorService); - } -} - -export class UnstageRangesAction extends BaseStageRangesAction { - static ID = 'workbench.action.git.unstageRanges'; - static LABEL = nls.localize('unstageSelectedLines', "Unstage Selected Lines"); - - constructor(editor: tdeditor.TextDiffEditor, @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(UnstageRangesAction.ID, UnstageRangesAction.LABEL, editor, gitService, editorService); - } - - protected getRangesAppliedResult(editor: editorbrowser.IDiffEditor) { - const selections = editor.getSelections(); - const changes = getSelectedChanges(editor.getLineChanges(), selections) - .map(c => ({ - modifiedStartLineNumber: c.originalStartLineNumber, - modifiedEndLineNumber: c.originalEndLineNumber, - originalStartLineNumber: c.modifiedStartLineNumber, - originalEndLineNumber: c.modifiedEndLineNumber - })); - - return applyChangesToModel(editor.getModel().modified, editor.getModel().original, changes); - } -} - -export class RevertRangesAction extends baseeditor.EditorInputAction { - static ID = 'workbench.action.git.revertRanges'; - static LABEL = nls.localize('revertSelectedLines', "Revert Selected Lines"); - - private editor: editorbrowser.IDiffEditor; - - constructor( - editor: tdeditor.TextDiffEditor, - @IWorkbenchEditorService private editorService: IWorkbenchEditorService, - @IMessageService private messageService: IMessageService - ) { - super(RevertRangesAction.ID, RevertRangesAction.LABEL); - - this.editor = editor.getControl(); - this.editor.getModifiedEditor().onDidChangeCursorSelection(() => this.updateEnablement()); - this.editor.onDidUpdateDiff(() => this.updateEnablement()); - this.class = 'git-action revert-ranges'; - } - - public isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.editorService) { - return false; - } - - const changes = this.editor.getLineChanges(); - const selections = this.editor.getSelections(); - - if (!changes || !selections || selections.length === 0) { - return false; - } - - return getSelectedChanges(changes, selections).length > 0; - } - - public run(): TPromise { - const selections = this.editor.getSelections(); - const changes = getSelectedChanges(this.editor.getLineChanges(), selections); - const { original, modified } = this.editor.getModel(); - - const revertEdits = getChangeRevertEdits(original, modified, changes); - - if (revertEdits.length === 0) { - return TPromise.as(null); - } - - const confirm = { - message: nls.localize('confirmRevertMessage', "Are you sure you want to revert the selected changes?"), - detail: nls.localize('irreversible', "This action is irreversible!"), - primaryButton: nls.localize({ key: 'revertChangesLabel', comment: ['&& denotes a mnemonic'] }, "&&Revert Changes") - }; - - if (!this.messageService.confirm(confirm)) { - return TPromise.as(null); - } - - modified.pushEditOperations(selections, revertEdits, () => selections); - modified.pushStackElement(); - - return TPromise.wrap(null); - } - - private updateEnablement(): void { - this.enabled = this.isEnabled(); - } -} - -class FileEditorActionContributor extends baseeditor.EditorInputActionContributor { - private instantiationService: IInstantiationService; - - constructor( @IInstantiationService instantiationService: IInstantiationService) { - super(); - - this.instantiationService = instantiationService; - } - - public hasActionsForEditorInput(context: baseeditor.IEditorInputActionContext): boolean { - return context.input instanceof FileEditorInput; - } - - public getActionsForEditorInput(context: baseeditor.IEditorInputActionContext): baseeditor.IEditorInputAction[] { - return [this.instantiationService.createInstance(OpenInDiffAction)]; - } -} - -class GitEditorActionContributor extends baseeditor.EditorInputActionContributor { - private instantiationService: IInstantiationService; - - constructor( @IInstantiationService instantiationService: IInstantiationService) { - super(); - - this.instantiationService = instantiationService; - } - - public hasActionsForEditorInput(context: baseeditor.IEditorInputActionContext): boolean { - return gitei.isGitEditorInput(context.input); - } - - public getActionsForEditorInput(context: baseeditor.IEditorInputActionContext): baseeditor.IEditorInputAction[] { - return [this.instantiationService.createInstance(OpenInEditorAction)]; - } -} - -class GitWorkingTreeDiffEditorActionContributor extends baseeditor.EditorInputActionContributor { - private instantiationService: IInstantiationService; - - constructor( @IInstantiationService instantiationService: IInstantiationService) { - super(); - - this.instantiationService = instantiationService; - } - - public hasSecondaryActionsForEditorInput(context: baseeditor.IEditorInputActionContext): boolean { - return (context.input instanceof gitei.GitDiffEditorInput && context.editor instanceof tdeditor.TextDiffEditor); - } - - public getSecondaryActionsForEditorInput(context: baseeditor.IEditorInputActionContext): baseeditor.IEditorInputAction[] { - if (context.input instanceof gitei.GitIndexDiffEditorInput) { - return [this.instantiationService.createInstance(UnstageRangesAction, context.editor)]; - } - - return [ - this.instantiationService.createInstance(StageRangesAction, context.editor), - this.instantiationService.createInstance(RevertRangesAction, context.editor)]; - } -} - -class GlobalOpenChangeAction extends OpenChangeAction { - - static ID = 'workbench.action.git.globalOpenChange'; - static LABEL = nls.localize('openChange', "Open Change"); - - constructor( - id: string, - label: string, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IGitService gitService: IGitService, - @IWorkspaceContextService protected contextService: IWorkspaceContextService, - @IViewletService protected viewletService: IViewletService, - @IPartService protected partService: IPartService - ) { - super(editorService, gitService); - } - - public getInput(): WorkbenchEditorCommon.IFileEditorInput { - const input = this.editorService.getActiveEditorInput(); - if (input instanceof FileEditorInput) { - return input; - } - - return null; - } - - public run(context?: any): TPromise { - let input = this.getInput(); - - if (!input) { - return TPromise.as(null); - } - - let status = getStatus(this.gitService, this.contextService, input); - - if (!status) { - return TPromise.as(null); - } - - var sideBySide = !!(context && (context.ctrlKey || context.metaKey)); - var editor = this.editorService.getActiveEditor().getControl(); - var viewState = editor ? editor.saveViewState() : null; - - return this.gitService.getInput(status).then((input) => { - var promise = TPromise.as(null); - - if (this.partService.isVisible(Parts.SIDEBAR_PART)) { - promise = this.viewletService.openViewlet(gitcontrib.VIEWLET_ID, false); - } - - return promise.then(() => { - var options = new WorkbenchEditorCommon.TextDiffEditorOptions(); - options.forceOpen = true; - options.autoRevealFirstChange = false; - - return this.editorService.openEditor(input, options, sideBySide).then((editor) => { - if (viewState) { - var codeEditor = this.editorService.getActiveEditor().getControl(); - codeEditor.restoreViewState({ - original: { - cursorState: undefined, - viewState: undefined, - contributionsState: undefined - }, - modified: viewState - }); - } - }); - }); - }); - } -} - -class GlobalOpenInEditorAction extends OpenFileAction { - - static ID = 'workbench.action.git.globalOpenFile'; - static LABEL = nls.localize('openFile', "Open File"); - - constructor( - id = GlobalOpenInEditorAction.ID, - label = GlobalOpenInEditorAction.LABEL, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IFileService fileService: IFileService, - @IGitService gitService: IGitService, - @IWorkspaceContextService contextService: IWorkspaceContextService - ) { - super(editorService, fileService, gitService, contextService); - } - - public run(event?: any): TPromise { - let input = this.editorService.getActiveEditorInput(); - if (input instanceof diffei.DiffEditorInput) { - input = input.modifiedInput; - } - - if (!(input instanceof FileEditorInput)) { - return TPromise.as(null); - } - - const status = getStatus(this.gitService, this.contextService, input); - - if (!status) { - return TPromise.as(null); - } - - return super.run(status); - } -} - -if (!SCMPreview.enabled) { - var actionBarRegistry = platform.Registry.as(abr.Extensions.Actionbar); - actionBarRegistry.registerActionBarContributor(abr.Scope.EDITOR, FileEditorActionContributor); - actionBarRegistry.registerActionBarContributor(abr.Scope.EDITOR, GitEditorActionContributor); - actionBarRegistry.registerActionBarContributor(abr.Scope.EDITOR, GitWorkingTreeDiffEditorActionContributor); - - let workbenchActionRegistry = (platform.Registry.as(wbar.Extensions.WorkbenchActions)); - - // Register Actions - const category = nls.localize('git', "Git"); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalOpenChangeAction, GlobalOpenChangeAction.ID, GlobalOpenChangeAction.LABEL), 'Git: Open Change', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(GlobalOpenInEditorAction, GlobalOpenInEditorAction.ID, GlobalOpenInEditorAction.LABEL), 'Git: Open File', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PullAction, PullAction.ID, PullAction.LABEL), 'Git: Pull', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PullWithRebaseAction, PullWithRebaseAction.ID, PullWithRebaseAction.LABEL), 'Git: Pull (Rebase)', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PushAction, PushAction.ID, PushAction.LABEL), 'Git: Push', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PushToRemoteAction, PushToRemoteAction.ID, PushToRemoteAction.LABEL), 'Git: Push to...', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SyncAction, SyncAction.ID, SyncAction.LABEL), 'Git: Sync', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(PublishAction, PublishAction.ID, PublishAction.LABEL), 'Git: Publish', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(StartGitBranchAction, StartGitBranchAction.ID, StartGitBranchAction.LABEL), 'Git: Branch', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(StartGitCheckoutAction, StartGitCheckoutAction.ID, StartGitCheckoutAction.LABEL), 'Git: Checkout', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(InputCommitAction, InputCommitAction.ID, InputCommitAction.LABEL), 'Git: Commit', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(UndoLastCommitAction, UndoLastCommitAction.ID, UndoLastCommitAction.LABEL), 'Git: Undo Last Commit', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(WorkbenchStageAction, WorkbenchStageAction.ID, WorkbenchStageAction.LABEL), 'Git: Stage', category); - workbenchActionRegistry.registerWorkbenchAction(new SyncActionDescriptor(WorkbenchUnstageAction, WorkbenchUnstageAction.ID, WorkbenchUnstageAction.LABEL), 'Git: Unstage', category); -} diff --git a/src/vs/workbench/parts/git/browser/gitActions.ts b/src/vs/workbench/parts/git/browser/gitActions.ts deleted file mode 100644 index 0b80d5e1663..00000000000 --- a/src/vs/workbench/parts/git/browser/gitActions.ts +++ /dev/null @@ -1,1299 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { Promise, TPromise } from 'vs/base/common/winjs.base'; -import nls = require('vs/nls'); -import { IEventEmitter } from 'vs/base/common/eventEmitter'; -import { ITree } from 'vs/base/parts/tree/browser/tree'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { isString } from 'vs/base/common/types'; -import { Action } from 'vs/base/common/actions'; -import { IDiffEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import model = require('vs/workbench/parts/git/common/gitModel'); -import inputs = require('vs/workbench/parts/git/browser/gitEditorInputs'); -import { TextDiffEditorOptions } from 'vs/workbench/common/editor'; -import errors = require('vs/base/common/errors'); -import platform = require('vs/base/common/platform'); -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IEditor } from 'vs/platform/editor/common/editor'; -import { IFileService, IFileStat } from 'vs/platform/files/common/files'; -import { IMessageService, IConfirmation, IChoiceService } from 'vs/platform/message/common/message'; -import Severity from 'vs/base/common/severity'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IGitService, IFileStatus, Status, StatusType, ServiceState, IModel, IBranch, GitErrorCodes, IGitConfiguration } from 'vs/workbench/parts/git/common/git'; -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import paths = require('vs/base/common/paths'); -import URI from 'vs/base/common/uri'; -import { IConfigurationEditingService, ConfigurationTarget } from 'vs/workbench/services/configuration/common/configurationEditing'; - -function flatten(context?: any, preferFocus = false): IFileStatus[] { - if (!context) { - return context; - - } else if (Array.isArray(context)) { - if (context.some((c: any) => !(c instanceof model.FileStatus))) { - throw new Error('Invalid context.'); - } - return context; - - } else if (context instanceof model.FileStatus) { - return [context]; - - } else if (context instanceof model.StatusGroup) { - return (context).all(); - - } else if (context.tree) { - var elements = (context.tree).getSelection(); - return elements.indexOf(context.fileStatus) > -1 ? elements : [context.fileStatus]; - - } else if (context.selection) { - return !preferFocus && context.selection.indexOf(context.focus) > -1 ? context.selection : [context.focus]; - - } else { - throw new Error('Invalid context.'); - } -} - -export abstract class GitAction extends Action { - - protected gitService: IGitService; - protected toDispose: IDisposable[]; - - constructor(id: string, label: string, cssClass: string, gitService: IGitService) { - super(id, label, cssClass, false); - - this.gitService = gitService; - this.toDispose = [this.gitService.addBulkListener(() => this.onGitServiceChange())]; - this.onGitServiceChange(); - } - - protected onGitServiceChange(): void { - this.updateEnablement(); - } - - protected updateEnablement(): void { - this.enabled = this.isEnabled(); - } - - protected isEnabled(): boolean { - return !!this.gitService; - } - - public abstract run(e?: any): Promise; - - public dispose(): void { - this.gitService = null; - this.toDispose = dispose(this.toDispose); - - super.dispose(); - } -} - -export class OpenChangeAction extends GitAction { - - static ID = 'workbench.action.git.openChange'; - protected editorService: IWorkbenchEditorService; - - constructor( @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IGitService gitService: IGitService) { - super(OpenChangeAction.ID, nls.localize('openChange', "Open Change"), 'git-action open-change', gitService); - this.editorService = editorService; - this.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && !!this.editorService; - } - - public run(context?: any): Promise { - var statuses = flatten(context, true); - - return this.gitService.getInput(statuses[0]).then((input) => { - var options = new TextDiffEditorOptions(); - - options.forceOpen = true; - - return this.editorService.openEditor(input, options); - }); - } -} - -export class OpenFileAction extends GitAction { - - private static DELETED_STATES = [Status.BOTH_DELETED, Status.DELETED, Status.DELETED_BY_US, Status.INDEX_DELETED]; - static ID = 'workbench.action.git.openFile'; - - protected fileService: IFileService; - protected editorService: IWorkbenchEditorService; - protected contextService: IWorkspaceContextService; - - constructor( @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @IGitService gitService: IGitService, @IWorkspaceContextService contextService: IWorkspaceContextService) { - super(OpenFileAction.ID, nls.localize('openFile', "Open File"), 'git-action open-file', gitService); - this.fileService = fileService; - this.editorService = editorService; - this.contextService = contextService; - this.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && !!this.editorService || !!this.fileService; - } - - private getPath(status: IFileStatus): string { - if (status.getStatus() === Status.INDEX_RENAMED) { - return status.getRename(); - } else { - var indexStatus = this.gitService.getModel().getStatus().find(status.getPath(), StatusType.INDEX); - - if (indexStatus && indexStatus.getStatus() === Status.INDEX_RENAMED) { - return status.getRename(); - } else { - return status.getPath(); - } - } - } - - public run(context?: any): Promise { - var statuses = flatten(context, true); - var status = statuses[0]; - - if (!(status instanceof model.FileStatus)) { - return Promise.wrapError(new Error('Can\'t open file.')); - } - - if (OpenFileAction.DELETED_STATES.indexOf(status.getStatus()) > -1) { - return Promise.wrapError(new Error('Can\'t open file which has been deleted.')); - } - - const resource = URI.file(paths.join(this.gitService.getModel().getRepositoryRoot(), this.getPath(status))); - - return this.fileService.resolveFile(resource) - .then(stat => this.editorService.openEditor({ - resource: stat.resource, - options: { forceOpen: true } - })); - } -} - -export class InitAction extends GitAction { - - static ID = 'workbench.action.git.init'; - - constructor( @IGitService gitService: IGitService) { - super(InitAction.ID, nls.localize('init', "Init"), 'git-action init', gitService); - } - - protected isEnabled(): boolean { - return super.isEnabled() && this.gitService.getState() === ServiceState.NotARepo; - } - - public run(): Promise { - return this.gitService.init(); - } -} - -export class RefreshAction extends GitAction { - - static ID = 'workbench.action.git.refresh'; - - constructor( @IGitService gitService: IGitService) { - super(RefreshAction.ID, nls.localize('refresh', "Refresh"), 'git-action refresh', gitService); - } - - public run(): Promise { - return this.gitService.status(); - } -} - -export abstract class BaseStageAction extends GitAction { - protected editorService: IWorkbenchEditorService; - - constructor(id: string, label: string, className: string, gitService: IGitService, editorService: IWorkbenchEditorService) { - super(id, label, className, gitService); - this.editorService = editorService; - } - - public run(context?: any): Promise { - var flatContext = flatten(context); - - return this.gitService.add(flatContext).then(status => { - var targetEditor = this.findGitWorkingTreeEditor(); - if (!targetEditor) { - return TPromise.as(status); - } - - var currentGitEditorInput = (targetEditor.input); - var currentFileStatus = currentGitEditorInput.getFileStatus(); - - if (flatContext && flatContext.every((f) => f !== currentFileStatus)) { - return TPromise.as(status); - } - - var path = currentGitEditorInput.getFileStatus().getPath(); - var fileStatus = status.getStatus().find(path, StatusType.INDEX); - - if (!fileStatus) { - return TPromise.as(status); - } - - var editorControl = targetEditor.getControl(); - var viewState = editorControl ? editorControl.saveViewState() : null; - - return this.gitService.getInput(fileStatus).then(input => { - var options = new TextDiffEditorOptions(); - options.forceOpen = true; - - return this.editorService.openEditor(input, options, targetEditor.position).then((editor) => { - if (viewState) { - editorControl.restoreViewState(viewState); - } - - return status; - }); - }); - }); - } - - private findGitWorkingTreeEditor(): IEditor { - var editors = this.editorService.getVisibleEditors(); - for (var i = 0; i < editors.length; i++) { - var editor = editors[i]; - if (inputs.isGitEditorInput(editor.input)) { - return editor; - } - } - - return null; - } - - public dispose(): void { - this.editorService = null; - - super.dispose(); - } -} - -export class StageAction extends BaseStageAction { - static ID = 'workbench.action.git.stage'; - static LABEL = nls.localize('stageChanges', "Stage"); - - constructor( - @IGitService gitService: IGitService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService - ) { - super(StageAction.ID, StageAction.LABEL, 'git-action stage', gitService, editorService); - } -} - -export class GlobalStageAction extends BaseStageAction { - - static ID = 'workbench.action.git.stageAll'; - - constructor( @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(GlobalStageAction.ID, nls.localize('stageAllChanges', "Stage All"), 'git-action stage', gitService, editorService); - } - - protected isEnabled(): boolean { - return super.isEnabled() && this.gitService.getModel().getStatus().getWorkingTreeStatus().all().length > 0; - } - - public run(context?: any): Promise { - return super.run(); - } -} - -export abstract class BaseUndoAction extends GitAction { - - private editorService: IWorkbenchEditorService; - private messageService: IMessageService; - private fileService: IFileService; - private contextService: IWorkspaceContextService; - - constructor(id: string, label: string, className: string, gitService: IGitService, messageService: IMessageService, fileService: IFileService, editorService: IWorkbenchEditorService, contextService: IWorkspaceContextService) { - super(id, label, className, gitService); - this.editorService = editorService; - this.messageService = messageService; - this.fileService = fileService; - this.contextService = contextService; - this.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && !!this.editorService && !!this.fileService; - } - - public run(context?: any): Promise { - if (!this.messageService.confirm(this.getConfirm(context))) { - return TPromise.as(null); - } - - var promises: Promise[] = []; - - if (context instanceof model.StatusGroup) { - promises = [this.gitService.undo()]; - - } else { - var all: IFileStatus[] = flatten(context); - var toClean: IFileStatus[] = []; - var toCheckout: IFileStatus[] = []; - - for (var i = 0; i < all.length; i++) { - var status = all[i].clone(); - - switch (status.getStatus()) { - case Status.UNTRACKED: - case Status.IGNORED: - toClean.push(status); - break; - - default: - toCheckout.push(status); - break; - } - } - - if (toClean.length > 0) { - promises.push(this.gitService.clean(toClean)); - } - - if (toCheckout.length > 0) { - promises.push(this.gitService.checkout('', toCheckout)); - } - } - - return Promise.join(promises).then((statuses: IModel[]) => { - if (statuses.length === 0) { - return TPromise.as(null); - } - - var status = statuses[statuses.length - 1]; - - var targetEditor = this.findWorkingTreeDiffEditor(); - if (!targetEditor) { - return TPromise.as(status); - } - - var currentGitEditorInput = targetEditor.input; - var currentFileStatus = currentGitEditorInput.getFileStatus(); - - if (all && all.every((f) => f !== currentFileStatus)) { - return TPromise.as(status); - } - - var path = currentGitEditorInput.getFileStatus().getPath(); - - var editor = targetEditor.getControl(); - var modifiedEditorControl = editor ? editor.getModifiedEditor() : null; - var modifiedViewState = modifiedEditorControl ? modifiedEditorControl.saveViewState() : null; - - return this.fileService.resolveFile(this.contextService.toResource(path)).then((stat: IFileStat) => { - return this.editorService.openEditor({ - resource: stat.resource, - options: { - forceOpen: true - } - }, targetEditor.position).then((editor) => { - if (modifiedViewState) { - var codeEditor = targetEditor.getControl(); - - if (codeEditor) { - codeEditor.restoreViewState(modifiedViewState); - } - } - }); - }); - }).then(null, (errors: any[]): Promise => { - console.error('One or more errors occurred', errors); - return Promise.wrapError(errors[0]); - }); - } - - private findWorkingTreeDiffEditor(): IEditor { - var editors = this.editorService.getVisibleEditors(); - for (var i = 0; i < editors.length; i++) { - var editor = editors[i]; - if (editor.input instanceof inputs.GitWorkingTreeDiffEditorInput) { - return editor; - } - } - - return null; - } - - private getConfirm(context: any): IConfirmation { - const all = flatten(context); - - if (all.length > 1) { - const count = all.length; - - return { - message: nls.localize('confirmUndoMessage', "Are you sure you want to clean all changes?"), - detail: count === 1 - ? nls.localize('confirmUndoAllOne', "There are unstaged changes in {0} file.\n\nThis action is irreversible!", count) - : nls.localize('confirmUndoAllMultiple', "There are unstaged changes in {0} files.\n\nThis action is irreversible!", count), - primaryButton: nls.localize({ key: 'cleanChangesLabel', comment: ['&& denotes a mnemonic'] }, "&&Clean Changes") - }; - } - - const label = all[0].getPathComponents().reverse()[0]; - - return { - message: nls.localize('confirmUndo', "Are you sure you want to clean changes in '{0}'?", label), - detail: nls.localize('irreversible', "This action is irreversible!"), - primaryButton: nls.localize({ key: 'cleanChangesLabel', comment: ['&& denotes a mnemonic'] }, "&&Clean Changes") - }; - } - - public dispose(): void { - this.editorService = null; - this.fileService = null; - - super.dispose(); - } -} - -export class UndoAction extends BaseUndoAction { - static ID = 'workbench.action.git.undo'; - constructor( @IGitService gitService: IGitService, @IMessageService messageService: IMessageService, @IFileService fileService: IFileService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IWorkspaceContextService contextService: IWorkspaceContextService) { - super(UndoAction.ID, nls.localize('undoChanges', "Clean"), 'git-action undo', gitService, messageService, fileService, editorService, contextService); - } -} - -export class GlobalUndoAction extends BaseUndoAction { - - static ID = 'workbench.action.git.undoAll'; - - constructor( @IGitService gitService: IGitService, @IMessageService messageService: IMessageService, @IFileService fileService: IFileService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IWorkspaceContextService contextService: IWorkspaceContextService) { - super(GlobalUndoAction.ID, nls.localize('undoAllChanges', "Clean All"), 'git-action undo', gitService, messageService, fileService, editorService, contextService); - } - - protected isEnabled(): boolean { - return super.isEnabled() && this.gitService.getModel().getStatus().getWorkingTreeStatus().all().length > 0; - } - - public run(context?: any): Promise { - return super.run(this.gitService.getModel().getStatus().getWorkingTreeStatus()); - } -} - -export abstract class BaseUnstageAction extends GitAction { - - protected editorService: IWorkbenchEditorService; - - constructor(id: string, label: string, className: string, gitService: IGitService, editorService: IWorkbenchEditorService) { - super(id, label, className, gitService); - this.editorService = editorService; - this.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && !!this.editorService; - } - - public run(context?: any): Promise { - var flatContext = flatten(context); - - return this.gitService.revertFiles('HEAD', flatContext).then((status: IModel) => { - var targetEditor = this.findGitIndexEditor(); - if (!targetEditor) { - return TPromise.as(status); - } - - var currentGitEditorInput = (targetEditor.input); - var currentFileStatus = currentGitEditorInput.getFileStatus(); - - if (flatContext && flatContext.every((f) => f !== currentFileStatus)) { - return TPromise.as(status); - } - - var path = currentGitEditorInput.getFileStatus().getPath(); - var fileStatus = status.getStatus().find(path, StatusType.WORKING_TREE); - - if (!fileStatus) { - return TPromise.as(status); - } - - var editorControl = targetEditor.getControl(); - var viewState = editorControl ? editorControl.saveViewState() : null; - - return this.gitService.getInput(fileStatus).then((input) => { - var options = new TextDiffEditorOptions(); - options.forceOpen = true; - - return this.editorService.openEditor(input, options, targetEditor.position).then((editor) => { - if (viewState) { - editorControl.restoreViewState(viewState); - } - - return status; - }); - }); - }); - } - - private findGitIndexEditor(): IEditor { - var editors = this.editorService.getVisibleEditors(); - for (var i = 0; i < editors.length; i++) { - var editor = editors[i]; - if (inputs.isGitEditorInput(editor.input)) { - return editor; - } - } - - return null; - } - - public dispose(): void { - this.editorService = null; - - super.dispose(); - } -} - -export class UnstageAction extends BaseUnstageAction { - static ID = 'workbench.action.git.unstage'; - static LABEL = nls.localize('unstage', "Unstage"); - - constructor( - @IGitService gitService: IGitService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService - ) { - super(UnstageAction.ID, UnstageAction.LABEL, 'git-action unstage', gitService, editorService); - } -} - -export class GlobalUnstageAction extends BaseUnstageAction { - - static ID = 'workbench.action.git.unstageAll'; - - constructor( @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(GlobalUnstageAction.ID, nls.localize('unstageAllChanges', "Unstage All"), 'git-action unstage', gitService, editorService); - } - - protected isEnabled(): boolean { - return super.isEnabled() && this.gitService.getModel().getStatus().getIndexStatus().all().length > 0; - } - - public run(context?: any): Promise { - return super.run(); - } -} - -enum LifecycleState { - Alive, - Disposing, - Disposed -} - -export class CheckoutAction extends GitAction { - - static ID = 'workbench.action.git.checkout'; - private editorService: IWorkbenchEditorService; - private branch: IBranch; - private HEAD: IBranch; - - private state: LifecycleState; - private runPromises: Promise[]; - - constructor(branch: IBranch, @IGitService gitService: IGitService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(CheckoutAction.ID, branch.name, 'git-action checkout', gitService); - - this.editorService = editorService; - this.branch = branch; - this.HEAD = null; - this.state = LifecycleState.Alive; - this.runPromises = []; - this.onGitServiceChange(); - } - - protected onGitServiceChange(): void { - if (this.gitService.getState() === ServiceState.OK) { - this.HEAD = this.gitService.getModel().getHEAD(); - - if (this.HEAD && this.HEAD.name === this.branch.name) { - this.class = 'git-action checkout HEAD'; - } else { - this.class = 'git-action checkout'; - } - } - - super.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && !!this.HEAD; - } - - public run(context?: any): Promise { - if (this.state !== LifecycleState.Alive) { - return Promise.wrapError('action disposed'); - } else if (this.HEAD && this.HEAD.name === this.branch.name) { - return TPromise.as(null); - } - - var result = this.gitService.checkout(this.branch.name).then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.DirtyWorkTree) { - return Promise.wrapError(new Error(nls.localize('dirtyTreeCheckout', "Can't checkout. Please commit or stash your work first."))); - } - - return Promise.wrapError(err); - }); - - this.runPromises.push(result); - result.done(() => this.runPromises.splice(this.runPromises.indexOf(result), 1)); - - return result; - } - - public dispose(): void { - if (this.state !== LifecycleState.Alive) { - return; - } - - this.state = LifecycleState.Disposing; - Promise.join(this.runPromises).done(() => this.actuallyDispose()); - } - - private actuallyDispose(): void { - this.editorService = null; - this.branch = null; - this.HEAD = null; - - super.dispose(); - - this.state = LifecycleState.Disposed; - } -} - -export class BranchAction extends GitAction { - - static ID = 'workbench.action.git.branch'; - private checkout: boolean; - - constructor(checkout: boolean, @IGitService gitService: IGitService) { - super(BranchAction.ID, 'Branch', 'git-action checkout', gitService); - this.checkout = checkout; - } - - public run(context?: any): Promise { - if (!isString(context)) { - return TPromise.as(false); - } - - return this.gitService.branch(context, this.checkout); - } -} - -export interface ICommitState extends IEventEmitter { - getCommitMessage(): string; - onEmptyCommitMessage(): void; -} - -export abstract class BaseCommitAction extends GitAction { - protected commitState: ICommitState; - - constructor(commitState: ICommitState, id: string, label: string, cssClass: string, gitService: IGitService) { - super(id, label, cssClass, gitService); - - this.commitState = commitState; - - this.toDispose.push(commitState.addListener('change/commitInputBox', () => { - this.updateEnablement(); - })); - - this.onGitServiceChange(); - } - - protected isEnabled(): boolean { - return super.isEnabled() && this.gitService.getModel().getStatus().getIndexStatus().all().length > 0; - } - - public run(context?: any): Promise { - if (!this.commitState.getCommitMessage()) { - this.commitState.onEmptyCommitMessage(); - return TPromise.as(null); - } - - return this.commit(); - } - - protected abstract commit(): Promise; -} - -export class CommitAction extends BaseCommitAction { - - static ID = 'workbench.action.git.commit'; - - constructor(commitState: ICommitState, @IGitService gitService: IGitService) { - super(commitState, CommitAction.ID, nls.localize('commitStaged', "Commit Staged"), 'git-action commit', gitService); - } - - protected commit(): Promise { - return this.gitService.commit(this.commitState.getCommitMessage()); - } -} - -export class CommitAmendAction extends BaseCommitAction { - - static ID = 'workbench.action.git.commitAmend'; - - constructor(commitState: ICommitState, @IGitService gitService: IGitService) { - super(commitState, CommitAction.ID, nls.localize('commitStagedAmend', "Commit Staged (Amend)"), 'git-action commit-amend', gitService); - } - - protected commit(): Promise { - return this.gitService.commit(this.commitState.getCommitMessage(), true); - } -} - -export class CommitSignedOffAction extends BaseCommitAction { - - static ID = 'workbench.action.git.commitSignedOff'; - - constructor(commitState: ICommitState, @IGitService gitService: IGitService) { - super(commitState, CommitAction.ID, nls.localize('commitStagedSignedOff', "Commit Staged (Signed Off)"), 'git-action commit-signed-off', gitService); - } - - protected commit(): Promise { - return this.gitService.commit(this.commitState.getCommitMessage(), undefined, undefined, true); - } -} - -export class InputCommitAction extends GitAction { - - static ID = 'workbench.action.git.input-commit'; - static LABEL = nls.localize('commit', "Commit"); - - constructor( - id = InputCommitAction.ID, - label = InputCommitAction.LABEL, - @IGitService gitService: IGitService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, '', gitService); - } - - protected isEnabled(): boolean { - if (!this.gitService) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - const status = this.gitService.getModel().getStatus(); - - return status.getIndexStatus().all().length > 0 || status.getWorkingTreeStatus().all().length > 0; - } - - run(): TPromise { - if (!this.enabled) { - return TPromise.as(null); - } - - const status = this.gitService.getModel().getStatus(); - - return this.quickOpenService.input({ prompt: nls.localize('commitMessage', "Commit Message") }) - .then(message => message && this.gitService.commit(message, false, status.getIndexStatus().all().length === 0)); - } -} - -export class StageAndCommitAction extends BaseCommitAction { - - static ID = 'workbench.action.git.stageAndCommit'; - static LABEL = nls.localize('commitAll', "Commit All"); - static CSSCLASS = 'git-action stage-and-commit'; - - constructor( - commitState: ICommitState, - id: string = StageAndCommitAction.ID, - label: string = StageAndCommitAction.LABEL, - cssClass: string = StageAndCommitAction.CSSCLASS, - @IGitService gitService: IGitService - ) { - super(commitState, id, label, cssClass, gitService); - } - - protected isEnabled(): boolean { - if (!this.gitService) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - var status = this.gitService.getModel().getStatus(); - - return status.getIndexStatus().all().length > 0 - || status.getWorkingTreeStatus().all().length > 0; - } - - protected commit(): Promise { - return this.gitService.commit(this.commitState.getCommitMessage(), false, true); - } -} - -export class StageAndCommitSignedOffAction extends StageAndCommitAction { - - static ID = 'workbench.action.git.stageAndCommitSignedOff'; - - constructor(commitState: ICommitState, @IGitService gitService: IGitService) { - super(commitState, StageAndCommitAction.ID, nls.localize('commitAllSignedOff', "Commit All (Signed Off)"), 'git-action stage-and-commit-signed-off', gitService); - } - - protected commit(): Promise { - return this.gitService.commit(this.commitState.getCommitMessage(), false, true, true); - } -} - -export class SmartCommitAction extends BaseCommitAction { - - static ID = 'workbench.action.git.commitAll'; - private static ALL = nls.localize('commitAll2', "Commit All"); - private static STAGED = nls.localize('commitStaged2', "Commit Staged"); - - private messageService: IMessageService; - - constructor(commitState: ICommitState, @IGitService gitService: IGitService, @IMessageService messageService: IMessageService) { - super(commitState, SmartCommitAction.ID, SmartCommitAction.ALL, 'git-action smart-commit', gitService); - this.messageService = messageService; - this.onGitServiceChange(); - } - - protected onGitServiceChange(): void { - super.onGitServiceChange(); - - if (!this.enabled) { - this.label = SmartCommitAction.ALL; - return; - } - - var status = this.gitService.getModel().getStatus(); - - if (status.getIndexStatus().all().length > 0) { - this.label = SmartCommitAction.STAGED; - } else { - this.label = SmartCommitAction.ALL; - } - - this.label += ' (' + (platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter') + ')'; - } - - protected isEnabled(): boolean { - if (!this.gitService) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - var status = this.gitService.getModel().getStatus(); - - return status.getIndexStatus().all().length > 0 - || status.getWorkingTreeStatus().all().length > 0; - } - - protected commit(): Promise { - const status = this.gitService.getModel().getStatus(); - return this.gitService.commit(this.commitState.getCommitMessage(), false, status.getIndexStatus().all().length === 0); - } -} - -export class PullAction extends GitAction { - - static ID = 'workbench.action.git.pull'; - static LABEL = 'Pull'; - - constructor( - id = PullAction.ID, - label = PullAction.LABEL, - @IGitService gitService: IGitService - ) { - super(id, label, 'git-action pull', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - var model = this.gitService.getModel(); - var HEAD = model.getHEAD(); - - if (!HEAD || !HEAD.name || !HEAD.upstream) { - return false; - } - - return true; - } - - public run(context?: any): Promise { - return this.pull(); - } - - protected pull(rebase = false): Promise { - return this.gitService.pull(rebase).then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.DirtyWorkTree) { - return Promise.wrapError(errors.create(nls.localize('dirtyTreePull', "Can't pull. Please commit or stash your work first."), { severity: Severity.Warning })); - } else if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return Promise.wrapError(errors.create(nls.localize('authFailed', "Authentication failed on the git remote."))); - } - - return Promise.wrapError(err); - }); - } -} - -export class PullWithRebaseAction extends PullAction { - - static ID = 'workbench.action.git.pull.rebase'; - static LABEL = 'Pull (Rebase)'; - - constructor( - id = PullWithRebaseAction.ID, - label = PullWithRebaseAction.LABEL, - @IGitService gitService: IGitService - ) { - super(id, label, gitService); - } - - public run(context?: any): Promise { - return this.pull(true); - } -} - -export class PushAction extends GitAction { - - static ID = 'workbench.action.git.push'; - static LABEL = 'Push'; - - constructor( - id: string = PushAction.ID, - label: string = PushAction.LABEL, - @IGitService gitService: IGitService - ) { - super(id, label, 'git-action push', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - var model = this.gitService.getModel(); - var HEAD = model.getHEAD(); - - if (!HEAD || !HEAD.name || !HEAD.upstream) { - return false; - } - - if (!HEAD.ahead) { // no commits to pull or push - return false; - } - - return true; - } - - public run(context?: any): Promise { - return this.gitService.push().then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return Promise.wrapError(errors.create(nls.localize('authFailed', "Authentication failed on the git remote."))); - } - - return Promise.wrapError(err); - }); - } -} - -export class PushToRemoteAction extends GitAction { - - static ID = 'workbench.action.git.pushToRemote'; - static LABEL = nls.localize('pushToRemote', "Push to..."); - - constructor( - id: string = PushToRemoteAction.ID, - label: string = PushToRemoteAction.LABEL, - @IGitService gitService: IGitService, - @IQuickOpenService private quickOpenService: IQuickOpenService - ) { - super(id, label, 'git-action publish', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - const model = this.gitService.getModel(); - - if (model.getRemotes().length === 0) { - return false; - } - - const HEAD = model.getHEAD(); - - if (!HEAD || !HEAD.name) { - return false; - } - - return true; - } - - public run(context?: any): Promise { - const model = this.gitService.getModel(); - const remotes = model.getRemotes(); - const branchName = model.getHEAD().name; - const picks = remotes.map(({ name, url }) => ({ label: name, description: url })); - const placeHolder = nls.localize('pushToRemotePickMessage', "Pick a remote to push the branch '{0}' to:", branchName); - - return this.quickOpenService.pick(picks, { placeHolder }) - .then(pick => pick && pick.label) - .then(remote => remote && this.gitService.push(remote, branchName)) - .then(null, err => { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return Promise.wrapError(errors.create(nls.localize('authFailed', "Authentication failed on the git remote."))); - } - - return Promise.wrapError(err); - }); - } -} - -export class PublishAction extends GitAction { - - static ID = 'workbench.action.git.publish'; - static LABEL = nls.localize('publish', "Publish"); - - constructor( - id: string = PublishAction.ID, - label: string = PublishAction.LABEL, - @IGitService gitService: IGitService, - @IQuickOpenService private quickOpenService: IQuickOpenService, - @IMessageService private messageService: IMessageService - ) { - super(id, label, 'git-action publish', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - const model = this.gitService.getModel(); - - if (model.getRemotes().length === 0) { - return false; - } - - const HEAD = model.getHEAD(); - - if (!HEAD || !HEAD.name || HEAD.upstream) { - return false; - } - - return true; - } - - public run(context?: any): Promise { - const model = this.gitService.getModel(); - const remotes = model.getRemotes(); - const branchName = model.getHEAD().name; - let promise: TPromise; - - if (remotes.length === 1) { - const remoteName = remotes[0].name; - - const result = this.messageService.confirm({ - message: nls.localize('confirmPublishMessage', "Are you sure you want to publish '{0}' to '{1}'?", branchName, remoteName), - primaryButton: nls.localize({ key: 'confirmPublishMessageButton', comment: ['&& denotes a mnemonic'] }, "&&Publish") - }); - - promise = TPromise.as(result ? remoteName : null); - } else { - const picks = remotes.map(({ name, url }) => ({ - label: name, - description: url - })); - - const placeHolder = nls.localize('publishPickMessage', "Pick a remote to publish the branch '{0}' to:", branchName); - - promise = this.quickOpenService.pick(picks, { placeHolder }) - .then(pick => pick && pick.label); - } - - return promise - .then(remote => remote && this.gitService.push(remote, branchName, { setUpstream: true })) - .then(null, err => { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return Promise.wrapError(errors.create(nls.localize('authFailed', "Authentication failed on the git remote."))); - } - - return Promise.wrapError(err); - }); - } -} - -export class SyncAction extends GitAction { - - static ID = 'workbench.action.git.sync'; - static LABEL = 'Sync'; - - constructor(id: string, label: string, - @IGitService gitService: IGitService, - @IConfigurationService private configurationService: IConfigurationService, - @IConfigurationEditingService private configurationEditingService: IConfigurationEditingService, - @IChoiceService private choiceService: IChoiceService - ) { - super(id, label, 'git-action sync', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - var model = this.gitService.getModel(); - var HEAD = model.getHEAD(); - - if (!HEAD || !HEAD.name || !HEAD.upstream) { - return false; - } - - return true; - } - - public run(context?: any): Promise { - if (!this.enabled) { - return TPromise.as(null); - } - - const shouldPrompt = this.configurationService.getConfiguration('git').confirmSync; - - if (!shouldPrompt) { - return this.sync(); - } - - - const model = this.gitService.getModel(); - const HEAD = model.getHEAD(); - const message = nls.localize('sync is unpredictable', "This action will push and pull commits to and from '{0}'.", HEAD.upstream); - const options = [nls.localize('ok', "OK"), nls.localize('cancel', "Cancel"), nls.localize('never again', "OK, Never Show Again")]; - - return this.choiceService.choose(Severity.Warning, message, options, 1).then(choice => { - switch (choice) { - case 0: - return this.sync(); - case 1: - return TPromise.as(null); - case 2: - return this.configurationEditingService.writeConfiguration(ConfigurationTarget.USER, { key: 'git.confirmSync', value: false }) - .then(() => this.sync()); - default: - return TPromise.as(null); - } - }); - } - - private sync(): TPromise { - return this.gitService.sync().then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return Promise.wrapError(errors.create(nls.localize('authFailed', "Authentication failed on the git remote."))); - } - - return Promise.wrapError(err); - }); - } -} - -export class UndoLastCommitAction extends GitAction { - - static ID = 'workbench.action.git.undoLastCommit'; - static LABEL = nls.localize('undoLastCommit', "Undo Last Commit"); - - constructor( - id = UndoLastCommitAction.ID, - label = UndoLastCommitAction.LABEL, - @IGitService gitService: IGitService - ) { - super(UndoLastCommitAction.ID, UndoLastCommitAction.LABEL, 'git-action undo-last-commit', gitService); - } - - protected isEnabled(): boolean { - if (!super.isEnabled()) { - return false; - } - - if (!this.gitService.isIdle()) { - return false; - } - - const model = this.gitService.getModel(); - const HEAD = model.getHEAD(); - - return !!(HEAD && HEAD.commit); - } - - public run(): Promise { - return this.gitService.reset('HEAD~'); - } -} - -export class StartGitCheckoutAction extends Action { - - public static ID = 'workbench.action.git.startGitCheckout'; - public static LABEL = 'Checkout'; - private quickOpenService: IQuickOpenService; - - constructor(id: string, label: string, @IQuickOpenService quickOpenService: IQuickOpenService) { - super(id, label); - this.quickOpenService = quickOpenService; - } - - public run(event?: any): Promise { - this.quickOpenService.show('git checkout '); - return TPromise.as(null); - } -} - -export class StartGitBranchAction extends Action { - - public static ID = 'workbench.action.git.startGitBranch'; - public static LABEL = 'Branch'; - private quickOpenService: IQuickOpenService; - - constructor(id: string, label: string, @IQuickOpenService quickOpenService: IQuickOpenService) { - super(id, label); - this.quickOpenService = quickOpenService; - } - - public run(event?: any): Promise { - this.quickOpenService.show('git branch '); - return TPromise.as(null); - } -} diff --git a/src/vs/workbench/parts/git/browser/gitEditorContributions.ts b/src/vs/workbench/parts/git/browser/gitEditorContributions.ts deleted file mode 100644 index c303f0d05eb..00000000000 --- a/src/vs/workbench/parts/git/browser/gitEditorContributions.ts +++ /dev/null @@ -1,181 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; -import { IModel, IModelDeltaDecoration, IModelDecorationOptions, OverviewRulerLane, IEditorContribution, TrackedRangeStickiness } from 'vs/editor/common/editorCommon'; -import { IGitService, ModelEvents, StatusType } from 'vs/workbench/parts/git/common/git'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { Delayer } from 'vs/base/common/async'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; - -const pattern = /^<<<<<<<|^=======|^>>>>>>>/; - -function decorate(model: IModel): IModelDeltaDecoration[] { - const options = MergeDecorator.DECORATION_OPTIONS; - - return model.getLinesContent() - .map((line, i) => pattern.test(line) ? i : null) - .filter(i => i !== null) - .map(i => ({ startLineNumber: i + 1, startColumn: 1, endLineNumber: i + 1, endColumn: 1 })) - .map(range => ({ range, options })); -} - -class MergeDecoratorBoundToModel extends Disposable { - - private decorations: string[]; - - constructor( - private editor: ICodeEditor, - private model: IModel, - private filePath: string, - private gitService: IGitService - ) { - super(); - - this.decorations = []; - - const delayer = new Delayer(300); - delayer.trigger(() => this.redecorate()); - - const gitModel = gitService.getModel(); - this._register(model.onDidChangeContent(() => delayer.trigger(() => this.redecorate()))); - this._register(gitModel.addListener(ModelEvents.STATUS_MODEL_UPDATED, () => delayer.trigger(() => this.redecorate()))); - } - - private _setDecorations(newDecorations: IModelDeltaDecoration[]): void { - this.decorations = this.editor.deltaDecorations(this.decorations, newDecorations); - } - - private redecorate(): void { - if (this.model.isDisposed()) { - return; - } - - const gitModel = this.gitService.getModel(); - - if (!gitModel) { - return; - } - - const mergeStatus = gitModel.getStatus().find(this.filePath, StatusType.MERGE); - - if (!mergeStatus) { - return; - } - - this._setDecorations(decorate(this.model)); - } - - dispose(): void { - this._setDecorations([]); - super.dispose(); - } -} - -export class MergeDecorator extends Disposable implements IEditorContribution { - - static ID = 'vs.git.editor.merge.decorator'; - - static DECORATION_OPTIONS: IModelDecorationOptions = { - className: 'git-merge-control-decoration', - isWholeLine: true, - overviewRuler: { - color: 'rgb(197, 118, 0)', - darkColor: 'rgb(197, 118, 0)', - position: OverviewRulerLane.Left - }, - stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges - }; - - private mergeDecorator: MergeDecoratorBoundToModel; - - constructor( - private editor: ICodeEditor, - @IGitService private gitService: IGitService, - @IWorkspaceContextService private contextService: IWorkspaceContextService - ) { - super(); - - this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); - this.mergeDecorator = null; - } - - getId(): string { - return MergeDecorator.ID; - } - - private onModelChanged(): void { - if (this.mergeDecorator) { - this.mergeDecorator.dispose(); - this.mergeDecorator = null; - } - - if (!this.contextService || !this.gitService) { - return; - } - - const model = this.editor.getModel(); - if (!model) { - return; - } - - const resource = model.uri; - if (!resource) { - return; - } - - const path = this.contextService.toWorkspaceRelativePath(resource); - if (!path) { - return; - } - - this.mergeDecorator = new MergeDecoratorBoundToModel(this.editor, model, path, this.gitService); - } - - dispose(): void { - if (this.mergeDecorator) { - this.mergeDecorator.dispose(); - this.mergeDecorator = null; - } - - super.dispose(); - } -} - -// TODO@Joao: remove -@editorContribution -export class MergeDecoratorWrapper extends Disposable implements IEditorContribution { - - static ID = 'vs.git.editor.merge.decoratorwrapper'; - private decorator: MergeDecorator; - - constructor( - private editor: ICodeEditor, - @IInstantiationService instantiationService: IInstantiationService - ) { - super(); - - if (SCMPreview.enabled) { - return; - } - - this.decorator = instantiationService.createInstance(MergeDecorator, editor); - } - - getId(): string { - return MergeDecoratorWrapper.ID; - } - - dispose(): void { - if (this.decorator) { - this.decorator.dispose(); - this.decorator = null; - } - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/gitEditorInputs.ts b/src/vs/workbench/parts/git/browser/gitEditorInputs.ts deleted file mode 100644 index 3cc7c790f50..00000000000 --- a/src/vs/workbench/parts/git/browser/gitEditorInputs.ts +++ /dev/null @@ -1,160 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 winjs = require('vs/base/common/winjs.base'); -import lifecycle = require('vs/base/common/lifecycle'); -import async = require('vs/base/common/async'); -import WorkbenchEditorCommon = require('vs/workbench/common/editor'); -import stringei = require('vs/workbench/common/editor/stringEditorInput'); -import diffei = require('vs/workbench/common/editor/diffEditorInput'); -import git = require('vs/workbench/parts/git/common/git'); -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IEditorInput } from 'vs/platform/editor/common/editor'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; - -import IGitService = git.IGitService; - -export interface IEditorInputWithStatus { - getFileStatus(): git.IFileStatus; -} - -export function isGitEditorInput(input: IEditorInput): boolean { - return input instanceof GitDiffEditorInput || input instanceof NativeGitIndexStringEditorInput; -} - -export class GitDiffEditorInput - extends diffei.DiffEditorInput - implements IEditorInputWithStatus { - private status: git.IFileStatus; - - constructor(name: string, description: string, originalInput: WorkbenchEditorCommon.EditorInput, modifiedInput: WorkbenchEditorCommon.EditorInput, status: git.IFileStatus) { - super(name, description, originalInput, modifiedInput); - - this.status = status; - } - - public getFileStatus(): git.IFileStatus { - return this.status; - } - - public contains(otherInput: any): boolean { - if (this.matches(otherInput)) { - return true; - } - - var originalInput = this.originalInput; - if (originalInput && originalInput.matches(otherInput)) { - return true; - } - - var modifiedInput = this.modifiedInput; - if (modifiedInput && modifiedInput.matches(otherInput)) { - return true; - } - - return false; - } -} - -export class GitWorkingTreeDiffEditorInput extends GitDiffEditorInput { - - static ID = 'vs.git.workingTreeDiffInput'; - - constructor(name: string, description: string, originalInput: WorkbenchEditorCommon.EditorInput, modifiedInput: WorkbenchEditorCommon.EditorInput, status: git.IFileStatus) { - super(name, description, originalInput, modifiedInput, status); - } - - public getTypeId(): string { - return GitWorkingTreeDiffEditorInput.ID; - } -} - -export class GitIndexDiffEditorInput extends GitDiffEditorInput { - - static ID: string = 'vs.git.indexDiffInput'; - - constructor(name: string, description: string, originalInput: WorkbenchEditorCommon.EditorInput, modifiedInput: WorkbenchEditorCommon.EditorInput, status: git.IFileStatus) { - super(name, description, originalInput, modifiedInput, status); - } - - public getTypeId(): string { - return GitIndexDiffEditorInput.ID; - } -} - -export class NativeGitIndexStringEditorInput - extends stringei.StringEditorInput - implements IEditorInputWithStatus { - public static ID = 'vs.git.stringEditorInput'; - - private gitService: IGitService; - private editorService: IWorkbenchEditorService; - private status: git.IFileStatus; - private path: string; - private treeish: string; - private delayer: async.ThrottledDelayer; - private toDispose: lifecycle.IDisposable[]; - - constructor(name: any, description: string, mime: string, status: git.IFileStatus, path: string, treeish: string, - @IGitService gitService: IGitService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IInstantiationService instantiationService: IInstantiationService - ) { - super(name, description, null, mime, false, instantiationService); - - this.gitService = gitService; - this.editorService = editorService; - this.status = status; - this.path = path; - this.treeish = treeish; - this.delayer = new async.ThrottledDelayer(1000); - - this.toDispose = []; - this.toDispose.push(this.gitService.addListener(git.ServiceEvents.STATE_CHANGED, () => this.onGitServiceStateChange())); - this.toDispose.push(this.gitService.addListener(git.ServiceEvents.OPERATION_END, () => this.onGitServiceStateChange())); - } - - public getTypeId(): string { - return NativeGitIndexStringEditorInput.ID; - } - - public getFileStatus(): git.IFileStatus { - return this.status; - } - - public resolve(refresh?: boolean): winjs.TPromise { - if (refresh || !this.getValue()) { - return this.gitService.buffer(this.path, this.treeish).then(contents => { - if (this.getValue() !== contents) { - this.setValue(contents); - } - - return super.resolve(refresh); - }); - } else { - return super.resolve(refresh); - } - } - - private onGitServiceStateChange(): void { - var isVisible = this.editorService.isVisible(this, true); - if (!isVisible) { - return; - } - - this.delayer.trigger(() => this.resolve(true)); - } - - public dispose(): void { - if (this.delayer) { - this.delayer.cancel(); - this.delayer = null; - } - - this.toDispose = lifecycle.dispose(this.toDispose); - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/git/browser/gitOperations.ts b/src/vs/workbench/parts/git/browser/gitOperations.ts deleted file mode 100644 index 669c5a92320..00000000000 --- a/src/vs/workbench/parts/git/browser/gitOperations.ts +++ /dev/null @@ -1,25 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { IGitOperation, IRawStatus } from 'vs/workbench/parts/git/common/git'; -import { TPromise } from 'vs/base/common/winjs.base'; - -export class GitOperation implements IGitOperation { - - id: string; - - constructor(id: string, private fn: () => TPromise) { - this.id = id; - } - - run(): TPromise { - return this.fn(); - } - - dispose(): void { - // noop - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/gitOutput.ts b/src/vs/workbench/parts/git/browser/gitOutput.ts deleted file mode 100644 index f760e2e3d33..00000000000 --- a/src/vs/workbench/parts/git/browser/gitOutput.ts +++ /dev/null @@ -1,42 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IGitService, ServiceEvents } from 'vs/workbench/parts/git/common/git'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IOutputService } from 'vs/workbench/parts/output/common/output'; - -export class GitOutput implements IWorkbenchContribution { - - static ID = 'vs.git.output'; - - private outputListener: IDisposable; - private gitService: IGitService; - private outputService: IOutputService; - - constructor( @IGitService gitService: IGitService, @IOutputService outputService: IOutputService) { - this.gitService = gitService; - this.outputService = outputService; - - const listener = gitService.addListener(ServiceEvents.OPERATION_START, () => { - this.outputListener = this.gitService.onOutput(output => this.onOutput(output)); - listener.dispose(); - }); - } - - getId(): string { - return GitOutput.ID; - } - - private onOutput(output: string): void { - this.outputService.getChannel('Git').append(output); - } - - dispose(): void { - this.outputListener = dispose(this.outputListener); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/gitQuickOpen.ts b/src/vs/workbench/parts/git/browser/gitQuickOpen.ts deleted file mode 100644 index bbe0a035bac..00000000000 --- a/src/vs/workbench/parts/git/browser/gitQuickOpen.ts +++ /dev/null @@ -1,271 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { localize } from 'vs/nls'; -import { matchesContiguousSubString } from 'vs/base/common/filters'; -import { TPromise } from 'vs/base/common/winjs.base'; -import Severity from 'vs/base/common/severity'; -import { IGitService, RefType, IRef, IGitConfiguration } from 'vs/workbench/parts/git/common/git'; -import { ICommand, CommandQuickOpenHandler } from 'vs/workbench/browser/quickopen'; -import { Mode } from 'vs/base/parts/quickopen/common/quickOpen'; -import { QuickOpenEntry, IHighlight, IContext, QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel'; -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; - -class AbstractRefEntry extends QuickOpenEntry { - - protected gitService: IGitService; - protected messageService: IMessageService; - protected ref: IRef; - - constructor(gitService: IGitService, messageService: IMessageService, ref: IRef, highlights: IHighlight[]) { - super(highlights); - - this.gitService = gitService; - this.messageService = messageService; - this.ref = ref; - } - - getIcon(): string { return 'git'; } - getLabel(): string { return this.ref.name; } - getDescription(): string { return ''; } - getAriaLabel(): string { return localize('refAriaLabel', "{0}, git", this.getLabel()); } - - run(mode: Mode, context: IContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - return true; - } -} - -class CheckoutHeadEntry extends AbstractRefEntry { - - getDescription(): string { return localize('checkoutBranch', "Branch at {0}", this.ref.commit.substr(0, 8)); } - - run(mode: Mode, context: IContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - this.gitService.checkout(this.ref.name).done(null, e => this.messageService.show(Severity.Error, e)); - return true; - } -} - -class CheckoutRemoteHeadEntry extends AbstractRefEntry { - - getDescription(): string { return localize('checkoutRemoteBranch', "Remote branch at {0}", this.ref.commit.substr(0, 8)); } - - run(mode: Mode, context: IContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - const match = /^[^/]+\/(.*)$/.exec(this.ref.name); - const name = match ? match[1] : this.ref.name; - - this.gitService.checkout(name).done(null, e => this.messageService.show(Severity.Error, e)); - return true; - } -} - -class CheckoutTagEntry extends AbstractRefEntry { - - getDescription(): string { return localize('checkoutTag', "Tag at {0}", this.ref.commit.substr(0, 8)); } - - run(mode: Mode, context: IContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - this.gitService.checkout(this.ref.name).done(null, e => this.messageService.show(Severity.Error, e)); - return true; - } -} - -class CurrentHeadEntry extends AbstractRefEntry { - getDescription(): string { return localize('alreadyCheckedOut', "Branch {0} is already the current branch", this.ref.name); } -} - -class BranchEntry extends QuickOpenEntry { - - private gitService: IGitService; - private messageService: IMessageService; - private name: string; - - constructor(gitService: IGitService, messageService: IMessageService, name: string) { - super([{ start: 0, end: name.length }]); - - this.gitService = gitService; - this.messageService = messageService; - - // sanitize name - this.name = name.replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$/g, '-'); - } - - getIcon(): string { return 'git'; } - getLabel(): string { return this.name; } - getAriaLabel(): string { return localize({ key: 'branchAriaLabel', comment: ['the branch name'] }, "{0}, git branch", this.getLabel()); } - getDescription(): string { return localize('createBranch', "Create branch {0}", this.name); } - - run(mode: Mode, context: IContext): boolean { - if (mode === Mode.PREVIEW) { - return false; - } - - this.gitService.branch(this.name, true).done(null, e => this.messageService.show(Severity.Error, e)); - return true; - } -} - -// Commands - -class CheckoutCommand implements ICommand { - - aliases = ['checkout', 'co']; - icon = 'git'; - - constructor(private gitService: IGitService, private messageService: IMessageService, private configurationService: IConfigurationService) { - // noop - } - - getResults(input: string): TPromise { - input = input.trim(); - - const config = this.configurationService.getConfiguration('git'); - const checkoutType = config.checkoutType; - const includeTags = checkoutType === 'all' || checkoutType === 'tags'; - const includeRemotes = checkoutType === 'all' || checkoutType === 'remote'; - - const gitModel = this.gitService.getModel(); - const currentHead = gitModel.getHEAD(); - const refs = gitModel.getRefs(); - const heads = refs.filter(ref => ref.type === RefType.Head); - const tags = includeTags ? refs.filter(ref => ref.type === RefType.Tag) : []; - const remoteHeads = includeRemotes ? refs.filter(ref => ref.type === RefType.RemoteHead) : []; - - const headMatches = heads - .map(head => ({ head, highlights: matchesContiguousSubString(input, head.name) })) - .filter(({ highlights }) => !!highlights); - - const headEntries: QuickOpenEntry[] = headMatches - .filter(({ head }) => head.name !== currentHead.name) - .map(({ head, highlights }) => new CheckoutHeadEntry(this.gitService, this.messageService, head, highlights)); - - const tagMatches = tags - .map(head => ({ head, highlights: matchesContiguousSubString(input, head.name) })) - .filter(({ highlights }) => !!highlights); - - const tagEntries = tagMatches - .filter(({ head }) => head.name !== currentHead.name) - .map(({ head, highlights }) => new CheckoutTagEntry(this.gitService, this.messageService, head, highlights)); - - const checkoutEntries = headEntries - .concat(tagEntries) - .sort((a, b) => a.getLabel().localeCompare(b.getLabel())); - - const remoteHeadMatches = remoteHeads - .map(head => ({ head, highlights: matchesContiguousSubString(input, head.name) })) - .filter(({ highlights }) => !!highlights); - - const remoteHeadEntries: QuickOpenEntry[] = remoteHeadMatches - .filter(({ head }) => head.name !== currentHead.name) - .map(({ head, highlights }) => new CheckoutRemoteHeadEntry(this.gitService, this.messageService, head, highlights)) - .sort((a, b) => a.getLabel().localeCompare(b.getLabel())); - - if (checkoutEntries.length > 0) { - checkoutEntries[0] = new QuickOpenEntryGroup(checkoutEntries[0], 'checkout', false); - } - - if (remoteHeadEntries.length > 0) { - remoteHeadEntries[0] = new QuickOpenEntryGroup(remoteHeadEntries[0], 'checkout remote', checkoutEntries.length > 0); - } - - const entries = checkoutEntries - .sort((a, b) => a.getLabel().localeCompare(b.getLabel())) - .concat(remoteHeadEntries); - - const allMatches = headMatches.concat(tagMatches).concat(remoteHeadMatches); - const exactMatches = allMatches.filter(({ head }) => head.name === input); - const currentHeadMatches = exactMatches.filter(({ head }) => head.name === currentHead.name); - - if (currentHeadMatches.length > 0) { - entries.unshift(new CurrentHeadEntry(this.gitService, this.messageService, currentHeadMatches[0].head, currentHeadMatches[0].highlights)); - - } else if (exactMatches.length === 0 && input) { - const branchEntry = new BranchEntry(this.gitService, this.messageService, input); - entries.push(new QuickOpenEntryGroup(branchEntry, 'branch', checkoutEntries.length > 0 || remoteHeadEntries.length > 0)); - } - - return TPromise.as(entries); - } - - getEmptyLabel(input: string): string { - return localize('noBranches', "No other branches"); - } -} - -class BranchCommand implements ICommand { - - aliases = ['branch']; - icon = 'git'; - - constructor(private gitService: IGitService, private messageService: IMessageService) { - // noop - } - - getResults(input: string): TPromise { - input = input.trim(); - - if (!input) { - return TPromise.as([]); - } - - const gitModel = this.gitService.getModel(); - const currentHead = gitModel.getHEAD(); - - const matches = gitModel.getRefs() - .map(head => ({ head, highlights: matchesContiguousSubString(input, head.name) })) - .filter(({ highlights }) => !!highlights); - - const exactMatches = matches.filter(({ head }) => head.name === input); - const headMatches = exactMatches.filter(({ head }) => head.name === currentHead.name); - - if (headMatches.length > 0) { - return TPromise.as([new CurrentHeadEntry(this.gitService, this.messageService, headMatches[0].head, headMatches[0].highlights)]); - } else if (exactMatches.length > 0) { - return TPromise.as([new CheckoutHeadEntry(this.gitService, this.messageService, exactMatches[0].head, exactMatches[0].highlights)]); - } - - const branchEntry = new BranchEntry(this.gitService, this.messageService, input); - return TPromise.as([new QuickOpenEntryGroup(branchEntry, 'branch', false)]); - } - - getEmptyLabel(input: string): string { - return localize('notValidBranchName', "Please provide a valid branch name"); - } -} - -export class GitCommandQuickOpenHandler extends CommandQuickOpenHandler { - - constructor( - @IQuickOpenService quickOpenService: IQuickOpenService, - @IGitService gitService: IGitService, - @IMessageService messageService: IMessageService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(quickOpenService, { - prefix: 'git', - commands: [ - new CheckoutCommand(gitService, messageService, configurationService), - new BranchCommand(gitService, messageService) - ] - }); - } -} diff --git a/src/vs/workbench/parts/git/browser/gitScm.ts b/src/vs/workbench/parts/git/browser/gitScm.ts deleted file mode 100644 index b0c345413e4..00000000000 --- a/src/vs/workbench/parts/git/browser/gitScm.ts +++ /dev/null @@ -1,125 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { TPromise } from 'vs/base/common/winjs.base'; -import Event, { Emitter } from 'vs/base/common/event'; -import { dispose } from 'vs/base/common/lifecycle'; -import URI from 'vs/base/common/uri'; -import { IModel } from 'vs/editor/common/editorCommon'; -import { ISCMService, ISCMProvider, ISCMResource, ISCMResourceGroup } from 'vs/workbench/services/scm/common/scm'; -import { ITextModelResolverService, ITextModelContentProvider } from 'vs/editor/common/services/resolverService'; -import { IModelService } from 'vs/editor/common/services/modelService'; -import { Throttler } from 'vs/base/common/async'; -import * as paths from 'vs/base/common/paths'; -import { IGitService, StatusType, ServiceEvents, ServiceOperations, ServiceState } from 'vs/workbench/parts/git/common/git'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; - -// TODO@Joao: remove -export class GitSCMProvider implements IWorkbenchContribution, ISCMProvider, ITextModelContentProvider { - - get id() { return 'git-internal'; } - get label() { return 'Git'; } - get resources() { return []; } - - private _onDidChange = new Emitter(); - get onDidChange(): Event { - return this._onDidChange.event; - } - - constructor( - @ITextModelResolverService textModelResolverService: ITextModelResolverService, - @IModelService private modelService: IModelService, - @IGitService private gitService: IGitService, - @ISCMService scmService: ISCMService - ) { - scmService.registerSCMProvider(this); - textModelResolverService.registerTextModelContentProvider('git', this); - } - - getId(): string { - return 'git.contentprovider'; - } - - open(uri: ISCMResource): TPromise { - return TPromise.wrapError('not implemented'); - } - - acceptChanges(): TPromise { - return TPromise.wrapError('not implemented'); - } - - drag(from: ISCMResource, to: ISCMResourceGroup): TPromise { - return TPromise.wrapError('not implemented'); - } - - getOriginalResource(uri: URI): TPromise { - if (uri.scheme !== 'file') { - return TPromise.as(null); - } - - return TPromise.as(uri.with({ scheme: 'git' })); - } - - provideTextContent(uri: URI): TPromise { - const model = this.modelService.createModel('', null, uri); - const throttler = new Throttler(); - - const setModelContents = contents => { - if (model.isDisposed()) { - return; - } - - model.setValue(contents || ''); - }; - - const updateModel = () => { - const gitModel = this.gitService.getModel(); - const root = gitModel.getRepositoryRoot(); - - if (!root) { - return TPromise.as(null); - } - - const path = uri.fsPath; - const relativePath = paths.relative(root, path).replace(/\\/g, '/'); - - if (/^\.\./.test(relativePath)) { - return TPromise.as(null); - } - - const treeish = gitModel.getStatus().find(relativePath, StatusType.INDEX) ? '~' : 'HEAD'; - - return this.gitService.buffer(path, treeish).then(setModelContents); - }; - - const triggerModelUpdate = () => { - if (this.gitService.getState() !== ServiceState.OK) { - return; - } - - throttler.queue(updateModel); - }; - - const disposables = [ - this.gitService.addListener(ServiceEvents.STATE_CHANGED, triggerModelUpdate), - this.gitService.addListener(ServiceEvents.OPERATION_END, e => { - if (e.operation.id !== ServiceOperations.BACKGROUND_FETCH) { - triggerModelUpdate(); - } - }) - ]; - - model.onWillDispose(() => dispose(disposables)); - triggerModelUpdate(); - - return TPromise.as(model); - } - - dispose(): void { - - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/gitServices.ts b/src/vs/workbench/parts/git/browser/gitServices.ts deleted file mode 100644 index f494f7ef3b4..00000000000 --- a/src/vs/workbench/parts/git/browser/gitServices.ts +++ /dev/null @@ -1,908 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { localize } from 'vs/nls'; -import * as platform from 'vs/base/common/platform'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { Action } from 'vs/base/common/actions'; -import { isPromiseCanceledError, create as createError } from 'vs/base/common/errors'; -import * as mime from 'vs/base/common/mime'; -import * as paths from 'vs/base/common/paths'; -import Event, { once } from 'vs/base/common/event'; -import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { EditorInput } from 'vs/workbench/common/editor'; -import { - IFileStatus, IGitServiceError, GitErrorCodes, Status, StatusType, AutoFetcherState, IGitConfiguration, IAutoFetcher, ServiceEvents, ServiceState, - IModel, IGitOperation, IRawGitService, IGitService, RawServiceState, ServiceOperations, IPushOptions, ICommit, IRawStatus -} from 'vs/workbench/parts/git/common/git'; -import { Model } from 'vs/workbench/parts/git/common/gitModel'; -import { NativeGitIndexStringEditorInput, GitIndexDiffEditorInput, GitWorkingTreeDiffEditorInput, GitDiffEditorInput } from 'vs/workbench/parts/git/browser/gitEditorInputs'; -import { GitOperation } from 'vs/workbench/parts/git/browser/gitOperations'; -import { TextFileModelChangeEvent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IFileService, FileChangesEvent, FileChangeType } from 'vs/platform/files/common/files'; -import { ThrottledDelayer, PeriodThrottledDelayer } from 'vs/base/common/async'; -import severity from 'vs/base/common/severity'; -import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService, CloseAction } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import URI from 'vs/base/common/uri'; -import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { domEvent } from 'vs/base/browser/event'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; - -function toReadablePath(path: string): string { - if (!platform.isWindows) { - return path; - } - - return path.replace(/\//g, '\\'); -} - -class EditorInputCache { - private gitService: GitService; - private fileService: IFileService; - private instantiationService: IInstantiationService; - private editorService: IWorkbenchEditorService; - private editorGroupService: IEditorGroupService; - private contextService: IWorkspaceContextService; - private cache: { [key: string]: TPromise }; - private toDispose: IDisposable[]; - - constructor(gitService: GitService, - @IInstantiationService instantiationService: IInstantiationService, - @IFileService fileService: IFileService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEditorGroupService editorGroupService: IEditorGroupService, - @IWorkspaceContextService contextService: IWorkspaceContextService - ) { - this.instantiationService = instantiationService; - this.fileService = fileService; - this.editorService = editorService; - this.editorGroupService = editorGroupService; - this.contextService = contextService; - - this.gitService = gitService; - - this.cache = {}; - this.toDispose = []; - - this.toDispose.push(this.gitService.getModel().addListener('fileStatus:dispose', (fileStatus: IFileStatus) => this.onFileStatusDispose(fileStatus))); - } - - getInput(status: IFileStatus): TPromise { - var result = this.cache[status.getId()]; - - if (result) { - return result; - } - - result = this.createInput(status); - this.cache[status.getId()] = result; - return result; - } - - private createInput(status: IFileStatus): TPromise { - return TPromise.join([this.createLeftInput(status), this.createRightInput(status)]).then((result) => { - var leftInput = result[0]; - var rightInput = result[1]; - - var fileSegment: string; - var folderSegment: string; - - if (status.getStatus() === Status.INDEX_RENAMED) { - let pathComponents = status.getRename().split('/'); - fileSegment = pathComponents[pathComponents.length - 1]; - folderSegment = toReadablePath(pathComponents.slice(0, pathComponents.length - 1).join('/')); - } else { - let pathComponents = status.getPathComponents(); - fileSegment = pathComponents[pathComponents.length - 1]; - folderSegment = toReadablePath(pathComponents.slice(0, pathComponents.length - 1).join('/')); - } - - if (!leftInput) { - if (!rightInput) { - var error = new Error(localize('cantOpen', "Can't open this git resource.")); - (error).gitErrorCode = GitErrorCodes.CantOpenResource; - return TPromise.wrapError(error); - } - - return TPromise.as(rightInput); - } - - switch (status.getStatus()) { - case Status.INDEX_MODIFIED: - return TPromise.as(new GitIndexDiffEditorInput(localize('gitIndexChanges', "{0} (index) ↔ {1}", fileSegment, fileSegment), localize('gitIndexChangesDesc', "{0} - Changes on index", folderSegment), leftInput, rightInput, status)); - case Status.INDEX_RENAMED: - return TPromise.as(new GitIndexDiffEditorInput(localize('gitIndexChangesRenamed', "{0} ← {1}", status.getRename(), status.getPath()), localize('gitIndexChangesRenamedDesc', "{0} - Renamed - Changes on index", folderSegment), leftInput, rightInput, status)); - case Status.MODIFIED: - return TPromise.as(new GitWorkingTreeDiffEditorInput(localize('workingTreeChanges', "{0} (HEAD) ↔ {1}", fileSegment, fileSegment), localize('workingTreeChangesDesc', "{0} - Changes on working tree", folderSegment), leftInput, rightInput, status)); - default: - return TPromise.as(new GitDiffEditorInput(localize('gitMergeChanges', "{0} (merge) ↔ {1}", fileSegment, fileSegment), localize('gitMergeChangesDesc', "{0} - Merge changes", folderSegment), leftInput, rightInput, status)); - } - }).then((editorInput: EditorInput) => { - const onceDispose = once(editorInput.onDispose); - onceDispose(() => { - delete this.cache[status.getId()]; - }); - - return editorInput; - }, (errs) => { - return TPromise.wrapError(Array.isArray(errs) ? errs[0] || errs[1] : errs); - }); - } - - private createLeftInput(status: IFileStatus): TPromise { - var path = status.getPath(); - var model = this.gitService.getModel(); - - switch (status.getStatus()) { - case Status.INDEX_MODIFIED: - case Status.INDEX_RENAMED: - return this.gitService.show(path, status, 'HEAD', status.getMimetype()); - - case Status.MODIFIED: - var indexStatus = model.getStatus().find(path, StatusType.INDEX); - - if (indexStatus && indexStatus.getStatus() === Status.INDEX_RENAMED) { - return this.gitService.show(indexStatus.getRename(), status, '~', status.getMimetype()); - } - - if (indexStatus) { - return this.gitService.show(path, status, '~', status.getMimetype()); - } - - return this.gitService.show(path, status, 'HEAD', status.getMimetype()); - - default: - return TPromise.as(null); - } - } - - private createRightInput(status: IFileStatus): TPromise { - const model = this.gitService.getModel(); - const path = status.getPath(); - let resource = URI.file(paths.join(model.getRepositoryRoot(), path)); - - switch (status.getStatus()) { - case Status.INDEX_MODIFIED: - case Status.INDEX_ADDED: - case Status.INDEX_COPIED: - return this.gitService.show(path, status, '~', status.getMimetype()); - - case Status.INDEX_RENAMED: - return this.gitService.show(status.getRename(), status, '~', status.getMimetype()); - - case Status.INDEX_DELETED: - case Status.DELETED: - return this.gitService.show(path, status, 'HEAD', status.getMimetype()); - - case Status.MODIFIED: - case Status.UNTRACKED: - case Status.IGNORED: - var indexStatus = model.getStatus().find(path, StatusType.INDEX); - - if (indexStatus && indexStatus.getStatus() === Status.INDEX_RENAMED) { - resource = URI.file(paths.join(model.getRepositoryRoot(), indexStatus.getRename())); - } - - return TPromise.as(this.editorService.createInput({ resource }) as EditorInput); - - case Status.BOTH_MODIFIED: - return TPromise.as(this.editorService.createInput({ resource }) as EditorInput); - - default: - return TPromise.as(null); - } - } - - private onFileStatusDispose(fileStatus: IFileStatus): void { - var id = fileStatus.getId(); - var editorInputPromise = this.cache[id]; - - if (editorInputPromise) { - editorInputPromise.done((editorInput) => { this.eventuallyDispose(editorInput); }); - } - } - - /** - * If the disposed status is the same as this input's status, we must try to dispose the input. - * But we should not do it while the input is still open. This method will eventually call dispose - * when the editor input goes out of the visible editors. - */ - private eventuallyDispose(editorInput: EditorInput): void { - if (!this.maybeDispose(editorInput)) { - var listener = this.editorGroupService.onEditorsChanged(() => { - if (this.maybeDispose(editorInput)) { - listener.dispose(); - } - }); - } - } - - private maybeDispose(editorInput: EditorInput): boolean { - if (!editorInput.isDirty() && !this.editorService.getVisibleEditors().some((editor) => editor.input && editor.input.matches(editorInput))) { - editorInput.dispose(); - return true; - } - - return false; - } - - dispose(): void { - Object.keys(this.cache).forEach(key => { - this.cache[key].done((editorInput) => { editorInput.dispose(); }); - delete this.cache[key]; - }); - - this.toDispose = dispose(this.toDispose); - } -} - -export class AutoFetcher implements IAutoFetcher, IDisposable { - private static MIN_TIMEOUT = 2 * 60 * 1000; // every two minutes - private static MAX_TIMEOUT = 5 * 60 * 1000; // every five minutes - - private _state: AutoFetcherState; - private gitService: GitService; - private messageService: IMessageService; - private configurationService: IConfigurationService; - private instantiationService: IInstantiationService; - private currentRequest: TPromise; - private timeout: number; - private toDispose: IDisposable[]; - private gitServiceStateDisposable: IDisposable; - - constructor(gitService: GitService, // gitService passed as argument, not by injection - @IMessageService messageService: IMessageService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IConfigurationService configurationService: IConfigurationService, - @IInstantiationService instantiationService: IInstantiationService - ) { - this._state = AutoFetcherState.Disabled; - this.gitService = gitService; - this.messageService = messageService; - this.configurationService = configurationService; - this.instantiationService = instantiationService; - this.currentRequest = null; - this.timeout = AutoFetcher.MIN_TIMEOUT; - - this.toDispose = []; - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onConfiguration(e.config.git))); - this.onConfiguration(configurationService.getConfiguration('git')); - } - - get state(): AutoFetcherState { - return this._state; - } - - private onConfiguration(config: IGitConfiguration): void { - if (config.autofetch === false) { - this.disable(); - } else { - this.enable(); - } - } - - enable(): void { - if (this._state !== AutoFetcherState.Disabled) { - return; - } - - this.gitServiceStateDisposable = this.gitService.addListener(ServiceEvents.STATE_CHANGED, (e) => this.onGitServiceStateChange(e)); - this._state = AutoFetcherState.Active; - this.onGitServiceStateChange(this.gitService.getState()); - } - - disable(): void { - if (this.gitServiceStateDisposable) { - this.gitServiceStateDisposable.dispose(); - this.gitServiceStateDisposable = null; - } - - this.deactivate(); - this._state = AutoFetcherState.Disabled; - } - - private onGitServiceStateChange(state: ServiceState): void { - if (state === ServiceState.OK) { - this.activate(); - } else { - this.deactivate(); - } - } - - activate(): void { - if (this.currentRequest) { - this.currentRequest.cancel(); - } - - this._state = AutoFetcherState.Active; - this.loop(); - } - - deactivate(): void { - if (!this.currentRequest) { - return; - } - - this._state = AutoFetcherState.Inactive; - this.currentRequest.cancel(); - this.currentRequest = null; - } - - private loop(): void { - this._state = AutoFetcherState.Fetching; - - const model = this.gitService.getModel(); - const remotes = model ? model.getRemotes() : []; - - if (remotes.length === 0) { - this.timeout = AutoFetcher.MIN_TIMEOUT; - this.currentRequest = TPromise.as(null); - } else { - this.currentRequest = this.gitService.fetch().then(() => { - this.timeout = AutoFetcher.MIN_TIMEOUT; - }, (err) => { - if (isPromiseCanceledError(err)) { - return TPromise.wrapError(err); - } else if (err.gitErrorCode === GitErrorCodes.AuthenticationFailed) { - return TPromise.wrapError(err); - } else { - this.timeout = Math.min(Math.round(this.timeout * 1.2), AutoFetcher.MAX_TIMEOUT); // backoff - } - return undefined; - }); - } - - this.currentRequest.then(() => { - this._state = AutoFetcherState.Active; - this.currentRequest = TPromise.timeout(this.timeout); - return this.currentRequest; - }).then(() => this.loop(), (err) => this.deactivate()); - } - - dispose(): void { - this.disable(); - } -} - -const IgnoreOldGitStorageKey = 'settings.workspace.git.ignoreOld'; - -export class GitService extends EventEmitter - implements - IGitService { - - _serviceBrand: any; - - private contextService: IWorkspaceContextService; - private messageService: IMessageService; - private textFileService: ITextFileService; - private instantiationService: IInstantiationService; - private editorService: IWorkbenchEditorService; - private lifecycleService: ILifecycleService; - private outputService: IOutputService; - protected raw: IRawGitService; - - private state: ServiceState; - private operations: IGitOperation[]; - private model: IModel; - private inputCache: EditorInputCache; - private toDispose: IDisposable[]; - private needsRefresh: boolean; - private statusDelayer: ThrottledDelayer; - private reactiveStatusDelayer: PeriodThrottledDelayer; - private autoFetcher: AutoFetcher; - private isStatusPending = false; - - private _allowHugeRepositories: boolean; - get allowHugeRepositories(): boolean { return this._allowHugeRepositories; } - set allowHugeRepositories(value: boolean) { - this._allowHugeRepositories = value; - - if (value && this.state === ServiceState.Huge) { - this.transition(ServiceState.OK); - } - } - - get onOutput(): Event { return this.raw.onOutput; } - - constructor( - raw: IRawGitService, - @IInstantiationService instantiationService: IInstantiationService, - @IFileService private fileService: IFileService, - @IMessageService messageService: IMessageService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IOutputService outputService: IOutputService, - @ITextFileService textFileService: ITextFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService storageService: IStorageService, - @IConfigurationService private configurationService: IConfigurationService - ) { - super(); - - this.instantiationService = instantiationService; - this.messageService = messageService; - this.editorService = editorService; - this.textFileService = textFileService; - this.outputService = outputService; - this.contextService = contextService; - this.lifecycleService = lifecycleService; - - this.raw = raw; - this.state = ServiceState.NotInitialized; - this.operations = []; - this.model = new Model(); - this.toDispose = []; - - this.needsRefresh = false; - this.statusDelayer = new ThrottledDelayer(500); - this.reactiveStatusDelayer = new PeriodThrottledDelayer(500, 10000); - this.autoFetcher = this.instantiationService.createInstance(AutoFetcher, this); - this._allowHugeRepositories = false; - - this.registerListeners(); - - this.inputCache = this.instantiationService.createInstance(EditorInputCache, this); - - this.triggerAutoStatus(true); // trigger initial status - - if (!storageService.getBoolean(IgnoreOldGitStorageKey, StorageScope.GLOBAL, false)) { - this.raw.serviceState().done(state => { - if (state !== RawServiceState.OK) { - return undefined; - } - - return this.raw.getVersion().then(version => { - const match = /^(\d+)\.\d+\.\d+/.exec(version || ''); - const major = match && parseInt(match[1]); - - if (major && major < 2) { - messageService.show(severity.Warning, { - message: localize('updateGit', "You seem to have git {0} installed. Code works best with git >=2.0.0.", version), - actions: [ - new Action('downloadLatest', localize('download', "Download"), '', true, () => { - window.open('https://git-scm.com/'); - return null; - }), - new Action('neverShowAgain', localize('neverShowAgain', "Don't show again"), null, true, () => { - storageService.store(IgnoreOldGitStorageKey, true, StorageScope.GLOBAL); - return null; - }), - CloseAction - ] - }); - } - }); - }); - } - } - - private registerListeners(): void { - this.toDispose.push(this.fileService.onFileChanges((e) => this.onFileChanges(e))); - this.toDispose.push(this.textFileService.models.onModelSaved((e) => this.onTextFileChange(e))); - this.toDispose.push(this.textFileService.models.onModelReverted((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.triggerAutoStatus(); - } - })); - this.lifecycleService.onShutdown(this.dispose, this); - - const focusEvent = domEvent(window, 'focus'); - this.toDispose.push(focusEvent(() => { - if (this.isStatusPending) { - this.triggerAutoStatus(); - } - })); - } - - private onTextFileChange(e: TextFileModelChangeEvent): void { - var shouldTriggerStatus = paths.basename(e.resource.fsPath) === '.gitignore'; - - if (!shouldTriggerStatus) { - return; - } - - this.triggerAutoStatus(); - } - - private onFileChanges(e: FileChangesEvent): void { - var isIdle = this.isIdle(); - - var shouldTriggerStatus = e.changes.some(c => { - var workspacePath = this.contextService.toWorkspaceRelativePath(c.resource); - if (!workspacePath) { - return false; // ignore out of workspace files - } - - // for .gitindex, the service must be idle - if ('.git/index' === workspacePath) { - return isIdle; - } - - // for anything other that .git* - if (!/^\.git/.test(workspacePath)) { - return true; - } - - // added or deleted .git folder - if (workspacePath === '.git') { - return c.type === FileChangeType.ADDED || c.type === FileChangeType.DELETED; - } - - return ['.git/index.lock', '.git/FETCH_HEAD', '.gitignore', '.gitmodules'].indexOf(workspacePath) === -1; - }); - - if (!shouldTriggerStatus) { - return; - } - - this.triggerAutoStatus(); - } - - private onGitServiceOperationEnd(e: { operation: IGitOperation; }): void { - if (e.operation.id === ServiceOperations.COMMAND) { - this.triggerAutoStatus(); - } - } - - getState(): ServiceState { - return this.state; - } - - getModel(): IModel { - return this.model; - } - - status(): TPromise { - return this.statusDelayer.trigger(() => this._status()); - } - - private _status(): TPromise { - const config = this.configurationService.getConfiguration('git'); - - if (this._allowHugeRepositories || config.allowLargeRepositories) { - return this.run(ServiceOperations.STATUS, () => this.raw.status()); - } - - if (this.state === ServiceState.Huge) { - return TPromise.as(this.model); - } - - return this.raw.statusCount().then(count => { - if (count > 5000 && !this._allowHugeRepositories) { - this.transition(ServiceState.Huge); - return TPromise.as(this.model); - } - - return this.run(ServiceOperations.STATUS, () => this.raw.status()); - }); - } - - private triggerAutoStatus(force = false): void { - this.isStatusPending = true; - - if (!document.hasFocus() && !force) { - return; - } - - this.isStatusPending = false; - - const config = this.configurationService.getConfiguration('git'); - - if (!config.autorefresh) { - return; - } - - this.reactiveStatusDelayer.trigger(() => this.status()).done(null, e => { - if (isPromiseCanceledError(e)) { - return; - } - - this.messageService.show(severity.Error, e); - }); - } - - init(): TPromise { - return this.run(ServiceOperations.INIT, () => this.raw.init()); - } - - add(files?: IFileStatus[]): TPromise { - return this.run(ServiceOperations.ADD, () => this.raw.add(GitService.toPaths(files))); - } - - stage(filePath: string, content: string): TPromise { - return this.run(ServiceOperations.STAGE, () => this.raw.stage(filePath, content)); - } - - branch(name: string, checkout: boolean = false): TPromise { - return this.run(ServiceOperations.BRANCH, () => this.raw.branch(name, checkout)); - } - - checkout(treeish: string = '', files: IFileStatus[] = null): TPromise { - return this.run(ServiceOperations.CHECKOUT, () => this.raw.checkout(treeish, GitService.toPaths(files))); - } - - clean(files: IFileStatus[]): TPromise { - return this.run(ServiceOperations.CLEAN, () => this.raw.clean(files.map((s) => s.getPath()))); - } - - undo(): TPromise { - return this.run(ServiceOperations.UNDO, () => this.raw.undo()); - } - - reset(treeish: string, hard?: boolean): TPromise { - return this.run(ServiceOperations.RESET, () => this.raw.reset(treeish, hard)); - } - - revertFiles(treeish: string, files?: IFileStatus[]): TPromise { - return this.run(ServiceOperations.REVERT, () => this.raw.revertFiles(treeish, (files || []).map((s) => s.getPath()))); - } - - fetch(): TPromise { - return this.run(ServiceOperations.BACKGROUND_FETCH, () => this.raw.fetch()); - } - - pull(rebase?: boolean): TPromise { - return this.run(ServiceOperations.PULL, () => this.raw.pull(rebase)); - } - - push(remote?: string, name?: string, options?: IPushOptions): TPromise { - return this.run(ServiceOperations.PUSH, () => this.raw.push(remote, name, options)); - } - - sync(rebase?: boolean): TPromise { - const head = this.model.getHEAD(); - const isAhead = head && head.upstream && !!head.ahead; - - if (!isAhead) { - return this.run(ServiceOperations.SYNC, () => this.raw.pull(rebase)); - } else { - return this.run(ServiceOperations.SYNC, () => this.raw.sync()); - } - } - - commit(message: string, amend: boolean = false, stage: boolean = false, signoff: boolean = false): TPromise { - return this.run(ServiceOperations.COMMIT, () => this.raw.commit(message, amend, stage, signoff)); - } - - getCommitTemplate(): TPromise { - return this.raw.getCommitTemplate(); - } - - getCommit(ref: string): TPromise { - return this.raw.getCommit(ref); - } - - detectMimetypes(path: string, treeish: string = '~'): TPromise { - return this.raw.detectMimetypes(path, treeish); - } - - clone(url: string, parentPath: string): TPromise { - return this.raw.clone(url, parentPath) - .then(null, e => this.wrapGitError(e)); - } - - private run(operationId: string, fn: () => TPromise): TPromise { - return this.raw.serviceState().then(state => { - if (state === RawServiceState.GitNotFound) { - this.transition(ServiceState.NoGit); - return TPromise.as(null); - } else if (state === RawServiceState.Disabled) { - this.transition(ServiceState.Disabled); - return TPromise.as(null); - } else { - return this._run(operationId, fn); - } - }); - } - - private _run(operationId: string, fn: () => TPromise): TPromise { - var operation = new GitOperation(operationId, fn); - - this.operations.push(operation); - this.emit(ServiceEvents.OPERATION_START, operation); - this.emit(ServiceEvents.OPERATION, operation); - - var onDone = (error: any = null) => { - var index = this.operations.indexOf(operation); - - if (index > -1) { - this.operations.splice(index, 1); - } - - var e = { operation: operation, error: error }; - this.emit(ServiceEvents.OPERATION_END, e); - this.onGitServiceOperationEnd(e); - this.emit(ServiceEvents.OPERATION, operation); - }; - - return operation.run().then((status: IRawStatus) => { - this.model.update(status); - - onDone(); - - if (status) { - this.transition(status.state === null || status.state === undefined ? ServiceState.OK : status.state); - } else { - this.transition(ServiceState.NotARepo); - } - - return this.model; - }, (e) => { - onDone(e); - - if (isPromiseCanceledError(e)) { - return TPromise.wrapError(e); - } - - var gitErrorCode: string = e.gitErrorCode || null; - - if (gitErrorCode === GitErrorCodes.NotAtRepositoryRoot) { - this.transition(ServiceState.NotAtRepoRoot); - return TPromise.as(this.model); - } - - this.emit(ServiceEvents.ERROR, e); - this.transition(ServiceState.OK); - - if (gitErrorCode === GitErrorCodes.NoUserNameConfigured || gitErrorCode === GitErrorCodes.NoUserEmailConfigured) { - this.messageService.show(severity.Warning, localize('configureUsernameEmail', "Please configure your git user name and e-mail.")); - - return TPromise.as(null); - - } else if (gitErrorCode === GitErrorCodes.BadConfigFile) { - this.messageService.show(severity.Error, localize('badConfigFile', "Git {0}", e.message)); - return TPromise.as(null); - - } else if (gitErrorCode === GitErrorCodes.UnmergedChanges) { - this.messageService.show(severity.Warning, localize('unmergedChanges', "You should first resolve the unmerged changes before committing your changes.")); - return TPromise.as(null); - } - - return this.wrapGitError(e); - }); - } - - private wrapGitError(e: any): TPromise { - const gitErrorCode: string = e.gitErrorCode || null; - const showOutputAction = new Action('show.gitOutput', localize('showOutput', "Show Output"), null, true, () => this.outputService.getChannel('Git').show()); - const cancelAction = new Action('close.message', localize('cancel', "Cancel"), null, true, () => TPromise.as(true)); - const error = createError( - localize('checkNativeConsole', "There was an issue running a git operation. Please review the output or use a console to check the state of your repository."), - { actions: [cancelAction, showOutputAction] } - ); - - (error).gitErrorCode = gitErrorCode; - (error).stdout = e.stdout; - (error).stderr = e.stderr; - - return TPromise.wrapError(error); - } - - private transition(state: ServiceState): void { - var oldState = this.state; - - this.state = state; - - if (state !== oldState) { - this.emit(ServiceEvents.STATE_CHANGED, state); - } - } - - buffer(path: string, treeish: string = '~'): TPromise { - return this.raw.show(path, treeish); - } - - show(path: string, status: IFileStatus, treeish: string = '~', mimetype: string = 'text/plain'): TPromise { - return this.detectMimetypes(path, treeish).then((mimetypes: string[]) => { - var pathComponents = status.getPathComponents(); - var fileSegment = pathComponents[pathComponents.length - 1]; - var folderSegment = toReadablePath(pathComponents.slice(0, pathComponents.length - 1).join('/')); - - var label: string; - var description: string; - - if (treeish === '~') { - label = localize('changesFromIndex', "{0} (index)", fileSegment); - description = localize('changesFromIndexDesc', "{0} - Changes on index", folderSegment); - } else { - label = localize('changesFromTree', "{0} ({1})", fileSegment, treeish); - description = localize('changesFromTreeDesc', "{0} - Changes on {1}", folderSegment, treeish); - } - - if (mime.isUnspecific(mimetypes)) { - mimetypes = mime.guessMimeTypes(path); // guess from path if our detection did not yield results - } - - // Binary: our story is weak here for binary files on the index. Since we run natively, we do not have a way currently - // to e.g. show images as binary inside the renderer because images need to be served through a URL to show. We could revisit this by - // allowing to use data URLs for resource inputs to render them. However, this would mean potentially loading a large file into memory - // - // Our solution now is to detect binary files and immediately return an input that is flagged as binary unknown mime type. - if (mime.isBinaryMime(mime.guessMimeTypes(path)) || mimetypes.indexOf(mime.MIME_BINARY) >= 0) { - return TPromise.wrapError(new Error('The resource seems to be binary and cannot be displayed')); - } - - // Text - return TPromise.as(this.instantiationService.createInstance(NativeGitIndexStringEditorInput, label, description, mimetypes.join(', '), status, path, treeish)); - }); - } - - getInput(status: IFileStatus): TPromise { - return this.inputCache.getInput(status).then(null, (err) => { - if (err.gitErrorCode = GitErrorCodes.CantOpenResource) { - this.messageService.show(severity.Warning, localize('cantOpenResource', "Can't open this git resource.")); - return TPromise.as(null); - } - - return TPromise.wrapError(err); - }); - } - - isInitialized(): boolean { - return this.state === ServiceState.OK; - } - - isIdle(): boolean { - return this.isInitialized() && !this.operations.some(op => op.id !== ServiceOperations.BACKGROUND_FETCH); - } - - getRunningOperations(): IGitOperation[] { - return this.operations; - } - - getAutoFetcher(): IAutoFetcher { - return this.autoFetcher; - } - - private static toPaths(files: IFileStatus[]): string[] { - if (!files) { - return null; - } - - return files.map((status) => { - /* In the case that a file was renamed in the index and (changed || deleted) in the - working tree, we must use its new name, running the checkout command. - */ - - switch (status.getStatus()) { - case Status.MODIFIED: - case Status.DELETED: - if (status.getRename()) { - return status.getRename(); - } - - default: - return status.getPath(); - } - }); - } - - dispose(): void { - this.emit(ServiceEvents.DISPOSE); - - if (this.model) { - this.model.dispose(); - this.model = null; - } - - super.dispose(); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/gitViewlet.ts b/src/vs/workbench/parts/git/browser/gitViewlet.ts deleted file mode 100644 index 02b64d84ded..00000000000 --- a/src/vs/workbench/parts/git/browser/gitViewlet.ts +++ /dev/null @@ -1,215 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./media/gitViewlet'; -import winjs = require('vs/base/common/winjs.base'); -import lifecycle = require('vs/base/common/lifecycle'); -import eventemitter = require('vs/base/common/eventEmitter'); -import $ = require('vs/base/browser/builder'); -import actions = require('vs/base/common/actions'); -import viewlet = require('vs/workbench/browser/viewlet'); -import git = require('vs/workbench/parts/git/common/git'); -import contrib = require('vs/workbench/parts/git/browser/gitWorkbenchContributions'); -import view = require('vs/workbench/parts/git/browser/views/view'); -import changes = require('vs/workbench/parts/git/browser/views/changes/changesView'); -import empty = require('vs/workbench/parts/git/browser/views/empty/emptyView'); -import gitless = require('vs/workbench/parts/git/browser/views/gitless/gitlessView'); -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'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; - -import IGitService = git.IGitService; - -export class GitViewlet - extends viewlet.Viewlet - implements view.IController { - private progressService: IProgressService; - private gitService: git.IGitService; - private instantiationService: IInstantiationService; - - private $el: $.Builder; - private currentView: view.IView; - private progressRunner: IProgressRunner; - - private currentDimension: $.Dimension; - private views: { [id: string]: view.IView; }; - - private toDispose: lifecycle.IDisposable[]; - - constructor( @ITelemetryService telemetryService: ITelemetryService, @IProgressService progressService: IProgressService, @IInstantiationService instantiationService: IInstantiationService, @IGitService gitService: IGitService, @IThemeService themeService: IThemeService) { - super(contrib.VIEWLET_ID, telemetryService, themeService); - - this.progressService = progressService; - this.instantiationService = instantiationService; - this.gitService = gitService; - - this.progressRunner = null; - this.views = {}; - this.toDispose = []; - - var views: view.IView[] = [ - this.instantiationService.createInstance(changes.ChangesView, this.getActionRunner()), - this.instantiationService.createInstance(empty.EmptyView, this, this.getActionRunner()), - this.instantiationService.createInstance(gitless.GitlessView), - new notroot.NotRootView(), - this.instantiationService.createInstance(noworkspace.NoWorkspaceView, this.getActionRunner()), - new DisabledView(), - this.instantiationService.createInstance(HugeView) - ]; - - views.forEach(v => { - this.views[v.ID] = v; - this.toDispose.push(v); - }); - - this.toUnbind.push(this.gitService.addBulkListener(() => this.onGitServiceChanges())); - } - - // GitView.IController - - public setView(id: string): winjs.Promise { - if (!this.$el) { - return winjs.TPromise.as(null); - } - - var view = this.views[id]; - - if (!view) { - return winjs.Promise.wrapError(new Error('Could not find view.')); - } - - if (this.currentView === view) { - return winjs.TPromise.as(null); - } - - var promise = winjs.TPromise.as(null); - - if (this.currentView) { - promise = this.currentView.setVisible(false); - } - - var element = view.element; - this.currentView = view; - this.updateTitleArea(); - - var el = this.$el.getHTMLElement(); - while (el.firstChild) { - el.removeChild(el.firstChild); - } - - el.appendChild(element); - view.layout(this.currentDimension); - - return promise.then(() => view.setVisible(true)); - } - - // Viewlet - - public create(parent: $.Builder): winjs.TPromise { - super.create(parent); - - this.$el = parent.div().addClass('git-viewlet'); - - return winjs.TPromise.as(null); - } - - public setVisible(visible: boolean): winjs.TPromise { - if (visible) { - this.onGitServiceChanges(); - - this.gitService.status().done(); - - return super.setVisible(visible).then(() => { - if (this.currentView) { - return this.currentView.setVisible(visible); - } - return undefined; - }); - } else { - return (this.currentView ? this.currentView.setVisible(visible) : winjs.TPromise.as(null)).then(() => { - super.setVisible(visible); - }); - } - } - - public focus(): void { - super.focus(); - - if (this.currentView) { - this.currentView.focus(); - } - } - - public layout(dimension: $.Dimension = this.currentDimension): void { - this.currentDimension = dimension; - - if (this.currentView) { - this.currentView.layout(dimension); - } - } - - public getActions(): actions.IAction[] { - return this.currentView ? this.currentView.getActions() : []; - } - - public getSecondaryActions(): actions.IAction[] { - return this.currentView ? this.currentView.getSecondaryActions() : []; - } - - public getControl(): eventemitter.IEventEmitter { - if (!this.currentView) { - return null; - } - - return this.currentView.getControl(); - } - - // Event handlers - - private onGitServiceChanges(): void { - if (this.progressRunner) { - this.progressRunner.done(); - } - - if (this.gitService.getState() === git.ServiceState.NoGit) { - this.setView('gitless'); - this.progressRunner = null; - } else if (this.gitService.getState() === git.ServiceState.Disabled) { - this.setView('disabled'); - this.progressRunner = null; - } else if (this.gitService.getState() === git.ServiceState.NotARepo) { - this.setView('empty'); - this.progressRunner = null; - } else if (this.gitService.getState() === git.ServiceState.NotAWorkspace) { - this.setView('noworkspace'); - this.progressRunner = null; - } 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; - } else { - this.progressRunner = this.progressService.show(true); - } - } - - public dispose(): void { - this.toDispose = lifecycle.dispose(this.toDispose); - this.views = null; - - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/git/browser/gitWidgets.ts b/src/vs/workbench/parts/git/browser/gitWidgets.ts deleted file mode 100644 index d2db61f03d1..00000000000 --- a/src/vs/workbench/parts/git/browser/gitWidgets.ts +++ /dev/null @@ -1,209 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import nls = require('vs/nls'); -import strings = require('vs/base/common/strings'); -import { Delayer } from 'vs/base/common/async'; -import { $, append, show, hide, toggleClass } from 'vs/base/browser/dom'; -import { IAction } from 'vs/base/common/actions'; -import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; -import { IGitService, ServiceState, IBranch, ServiceOperations, IRemote } from 'vs/workbench/parts/git/common/git'; -import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { SyncAction, PublishAction } from './gitActions'; -import Severity from 'vs/base/common/severity'; -import { IMessageService } from 'vs/platform/message/common/message'; - -interface IState { - serviceState: ServiceState; - isBusy: boolean; - isSyncing: boolean; - HEAD: IBranch; - remotes: IRemote[]; - ps1: string; -} - -const DisablementDelay = 500; - -export class GitStatusbarItem implements IStatusbarItem { - - private instantiationService: IInstantiationService; - private gitService: IGitService; - private quickOpenService: IQuickOpenService; - private state: IState; - private element: HTMLElement; - private branchElement: HTMLElement; - private publishElement: HTMLElement; - private syncElement: HTMLElement; - private syncLabelElement: HTMLElement; - private disablementDelayer: Delayer; - - private syncAction: SyncAction; - private publishAction: PublishAction; - - private toDispose: IDisposable[]; - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IGitService gitService: IGitService, - @IQuickOpenService quickOpenService: IQuickOpenService, - @IMessageService private messageService: IMessageService, - @ITelemetryService private telemetryService: ITelemetryService - ) { - this.instantiationService = instantiationService; - this.gitService = gitService; - this.quickOpenService = quickOpenService; - this.disablementDelayer = new Delayer(DisablementDelay); - - this.syncAction = instantiationService.createInstance(SyncAction, SyncAction.ID, SyncAction.LABEL); - this.publishAction = instantiationService.createInstance(PublishAction, PublishAction.ID, PublishAction.LABEL); - - this.toDispose = [ - this.syncAction, - this.publishAction - ]; - - this.state = { - serviceState: ServiceState.NotInitialized, - isBusy: false, - isSyncing: false, - HEAD: null, - remotes: [], - ps1: '' - }; - } - - public render(container: HTMLElement): IDisposable { - this.element = append(container, $('.git-statusbar-group')); - - this.branchElement = append(this.element, $('a')); - - this.publishElement = append(this.element, $('a.octicon.octicon-cloud-upload')); - this.publishElement.title = nls.localize('publishBranch', "Publish Branch"); - this.publishElement.onclick = () => this.onPublishClick(); - - this.syncElement = append(this.element, $('a.git-statusbar-sync-item')); - this.syncElement.title = nls.localize('syncBranch', "Synchronize Changes"); - this.syncElement.onclick = () => this.onSyncClick(); - append(this.syncElement, $('span.octicon.octicon-sync')); - - this.syncLabelElement = append(this.syncElement, $('span.ahead-behind')); - - this.setState(this.state); - this.toDispose.push(this.gitService.addBulkListener(() => this.onGitServiceChange())); - return combinedDisposable(this.toDispose); - } - - private onGitServiceChange(): void { - const model = this.gitService.getModel(); - - this.setState({ - serviceState: this.gitService.getState(), - isBusy: this.gitService.getRunningOperations().some(op => op.id === ServiceOperations.CHECKOUT || op.id === ServiceOperations.BRANCH), - isSyncing: this.gitService.getRunningOperations().some(op => op.id === ServiceOperations.SYNC), - HEAD: model.getHEAD(), - remotes: model.getRemotes(), - ps1: model.getPS1() - }); - } - - private setState(state: IState): void { - this.state = state; - - let isGitDisabled = false; - let className = 'git-statusbar-branch-item'; - let textContent: string; - let aheadBehindLabel = ''; - let title = ''; - let onclick: () => void = null; - - if (state.serviceState !== ServiceState.OK) { - isGitDisabled = true; - className += ' disabled'; - title = nls.localize('gitNotEnabled', "Git is not enabled in this workspace."); - textContent = '\u00a0'; - } else { - const HEAD = state.HEAD; - - if (state.isBusy) { - className += ' busy'; - } else { - onclick = () => this.onBranchClick(); - } - - if (!HEAD) { - textContent = state.ps1; - } else if (!HEAD.name) { - textContent = state.ps1; - className += ' headless'; - } else if (!HEAD.commit || !HEAD.upstream || (!HEAD.ahead && !HEAD.behind)) { - textContent = state.ps1; - } else { - textContent = state.ps1; - aheadBehindLabel = strings.format('{0}↓ {1}↑', HEAD.behind, HEAD.ahead); - } - } - - this.branchElement.className = className; - this.branchElement.title = title; - this.branchElement.textContent = textContent; - this.branchElement.onclick = onclick; - this.syncLabelElement.textContent = aheadBehindLabel; - - if (isGitDisabled) { - hide(this.branchElement); - hide(this.publishElement); - hide(this.syncElement); - } else { - show(this.branchElement); - - if (state.HEAD && !!state.HEAD.upstream) { - show(this.syncElement); - toggleClass(this.syncElement, 'syncing', this.state.isSyncing); - toggleClass(this.syncElement, 'empty', !aheadBehindLabel); - this.disablementDelayer.trigger( - () => toggleClass(this.syncElement, 'disabled', !this.syncAction.enabled), - this.syncAction.enabled ? 0 : DisablementDelay - ); - hide(this.publishElement); - } else if (state.remotes.length > 0) { - hide(this.syncElement); - show(this.publishElement); - this.disablementDelayer.trigger( - () => toggleClass(this.publishElement, 'disabled', !this.publishAction.enabled), - this.publishAction.enabled ? 0 : DisablementDelay - ); - } else { - hide(this.syncElement); - hide(this.publishElement); - } - } - } - - private onBranchClick(): void { - this.quickOpenService.show('git checkout '); - } - - private onPublishClick(): void { - this.runAction(this.publishAction); - } - - private onSyncClick(): void { - this.runAction(this.syncAction); - } - - private runAction(action: IAction): void { - if (!action.enabled) { - return; - } - - this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'status bar' }); - - action.run() - .done(null, err => this.messageService.show(Severity.Error, err)); - } -} diff --git a/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts b/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts deleted file mode 100644 index e35495db433..00000000000 --- a/src/vs/workbench/parts/git/browser/gitWorkbenchContributions.ts +++ /dev/null @@ -1,241 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./media/git.contribution'; -import nls = require('vs/nls'); -import async = require('vs/base/common/async'); -import lifecycle = require('vs/base/common/lifecycle'); -import ext = require('vs/workbench/common/contributions'); -import git = require('vs/workbench/parts/git/common/git'); -import viewlet = require('vs/workbench/browser/viewlet'); -import statusbar = require('vs/workbench/browser/parts/statusbar/statusbar'); -import platform = require('vs/platform/platform'); -import widgets = require('vs/workbench/parts/git/browser/gitWidgets'); -import wbar = require('vs/workbench/common/actionRegistry'); -import gitoutput = require('vs/workbench/parts/git/browser/gitOutput'); -import output = require('vs/workbench/parts/output/common/output'); -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import confregistry = require('vs/platform/configuration/common/configurationRegistry'); -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import quickopen = require('vs/workbench/browser/quickopen'); -import 'vs/workbench/parts/git/browser/gitEditorContributions'; -import { IActivityBarService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activityBarService'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; -import { GitSCMProvider } from './gitScm'; - -import IGitService = git.IGitService; - -export class StatusUpdater implements ext.IWorkbenchContribution { - static ID = 'vs.git.statusUpdater'; - - private gitService: IGitService; - private activityBarService: IActivityBarService; - private messageService: IMessageService; - private configurationService: IConfigurationService; - private progressBadgeDelayer: async.Delayer; - private badgeHandle: lifecycle.IDisposable; - private toDispose: lifecycle.IDisposable[]; - - constructor( - @IGitService gitService: IGitService, - @IActivityBarService activityBarService: IActivityBarService, - @IMessageService messageService: IMessageService, - @IConfigurationService configurationService: IConfigurationService - ) { - this.gitService = gitService; - this.activityBarService = activityBarService; - this.messageService = messageService; - this.configurationService = configurationService; - - this.progressBadgeDelayer = new async.Delayer(200); - - this.toDispose = []; - this.toDispose.push(this.configurationService.onDidUpdateConfiguration(e => this.onGitServiceChange())); - this.toDispose.push(this.gitService.addBulkListener(e => this.onGitServiceChange())); - } - - private onGitServiceChange(): void { - - lifecycle.dispose(this.badgeHandle); - - if (this.gitService.getState() !== git.ServiceState.OK) { - this.progressBadgeDelayer.cancel(); - - } else if (this.gitService.isIdle()) { - this.showChangesBadge(); - } else { - this.progressBadgeDelayer.trigger(() => { - this.badgeHandle = this.activityBarService.showActivity('workbench.view.git', new ProgressBadge(() => nls.localize('gitProgressBadge', 'Running git status')), 'git-viewlet-label-progress'); - }); - } - } - - private showChangesBadge(): void { - this.progressBadgeDelayer.cancel(); - - const { countBadge } = this.configurationService.getConfiguration('git'); - - if (countBadge === 'off') { - return; - } - - const filter = countBadge === 'tracked' - ? s => s.getStatus() !== git.Status.UNTRACKED - : () => true; - - const statuses = this.gitService.getModel().getStatus().getGroups() - .map(g => g.all()) - .reduce((r, g) => r.concat(g), []) - .filter(filter); - - const badge = new NumberBadge(statuses.length, num => nls.localize('gitPendingChangesBadge', '{0} pending changes', num)); - this.badgeHandle = this.activityBarService.showActivity('workbench.view.git', badge, 'git-viewlet-label'); - } - - public getId(): string { - return StatusUpdater.ID; - } - - public dispose(): void { - this.toDispose = lifecycle.dispose(this.toDispose); - lifecycle.dispose(this.badgeHandle); - } -} - -export const VIEWLET_ID = 'workbench.view.git'; - -class OpenGitViewletAction extends viewlet.ToggleViewletAction { - public static ID = VIEWLET_ID; - public static LABEL = nls.localize('toggleGitViewlet', "Show Git"); - - constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(id, label, VIEWLET_ID, viewletService, editorService); - } -} - -export function registerContributions(): void { - - // Register Statusbar item - (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( - widgets.GitStatusbarItem, - statusbar.StatusbarAlignment.LEFT, - 100 /* High Priority */ - )); - - // Register Output Channel - var outputChannelRegistry = platform.Registry.as(output.Extensions.OutputChannels); - outputChannelRegistry.registerChannel('Git', nls.localize('git', "Git")); - - // Register Git Output - (platform.Registry.as(ext.Extensions.Workbench)).registerWorkbenchContribution( - gitoutput.GitOutput - ); - - // Register Viewlet - (platform.Registry.as(viewlet.Extensions.Viewlets)).registerViewlet(new viewlet.ViewletDescriptor( - 'vs/workbench/parts/git/browser/gitViewlet', - 'GitViewlet', - VIEWLET_ID, - nls.localize('git', "Git"), - 'git', - 35 - )); - - // Register Action to Open Viewlet - (platform.Registry.as(wbar.Extensions.WorkbenchActions)).registerWorkbenchAction( - new SyncActionDescriptor(OpenGitViewletAction, OpenGitViewletAction.ID, OpenGitViewletAction.LABEL, { - primary: null, - win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_G } - }), - 'View: Show Git', - nls.localize('view', "View") - ); - - // Register StatusUpdater - (platform.Registry.as(ext.Extensions.Workbench)).registerWorkbenchContribution( - StatusUpdater - ); - - // Register GitSCMProvider - (platform.Registry.as(ext.Extensions.Workbench)).registerWorkbenchContribution( - GitSCMProvider - ); - - // Register Quick Open for git - (platform.Registry.as(quickopen.Extensions.Quickopen)).registerQuickOpenHandler( - new quickopen.QuickOpenHandlerDescriptor( - 'vs/workbench/parts/git/browser/gitQuickOpen', - 'GitCommandQuickOpenHandler', - 'git ', - nls.localize('gitCommands', "Git Commands") - ) - ); - - // Register configuration - var configurationRegistry = platform.Registry.as(confregistry.Extensions.Configuration); - configurationRegistry.registerConfiguration({ - id: 'git', - order: 15, - title: nls.localize('gitConfigurationTitle', "Git"), - type: 'object', - properties: { - 'git.enabled': { - type: 'boolean', - description: nls.localize('gitEnabled', "Is git enabled"), - default: true - }, - 'git.path': { - type: ['string', 'null'], - description: nls.localize('gitPath', "Path to the git executable"), - default: null, - isExecutable: true - }, - 'git.autorefresh': { - type: 'boolean', - description: nls.localize('gitAutoRefresh', "Whether auto refreshing is enabled"), - default: true - }, - 'git.autofetch': { - type: 'boolean', - description: nls.localize('gitAutoFetch', "Whether auto fetching is enabled."), - default: true - }, - 'git.enableLongCommitWarning': { - 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 - }, - 'git.confirmSync': { - type: 'boolean', - description: nls.localize('confirmSync', "Confirm before synchronizing git repositories."), - default: true - }, - 'git.countBadge': { - type: 'string', - enum: ['all', 'tracked', 'off'], - default: 'all', - description: nls.localize('countBadge', "Controls the git badge counter."), - }, - 'git.checkoutType': { - type: 'string', - enum: ['all', 'local', 'tags', 'remote'], - default: 'all', - description: nls.localize('checkoutType', "Controls what type of branches are listed."), - } - } - }); -} diff --git a/src/vs/workbench/parts/git/browser/media/Compare.svg b/src/vs/workbench/parts/git/browser/media/Compare.svg deleted file mode 100644 index 3a205509bca..00000000000 --- a/src/vs/workbench/parts/git/browser/media/Compare.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/Compare_inverse.svg b/src/vs/workbench/parts/git/browser/media/Compare_inverse.svg deleted file mode 100644 index c951728abac..00000000000 --- a/src/vs/workbench/parts/git/browser/media/Compare_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/OpenEditor.svg b/src/vs/workbench/parts/git/browser/media/OpenEditor.svg deleted file mode 100644 index 85a001dccc2..00000000000 --- a/src/vs/workbench/parts/git/browser/media/OpenEditor.svg +++ /dev/null @@ -1,3 +0,0 @@ - -]> \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/OpenEditor_inverse.svg b/src/vs/workbench/parts/git/browser/media/OpenEditor_inverse.svg deleted file mode 100644 index f6302185aa4..00000000000 --- a/src/vs/workbench/parts/git/browser/media/OpenEditor_inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/Refresh.svg b/src/vs/workbench/parts/git/browser/media/Refresh.svg deleted file mode 100644 index e0345748192..00000000000 --- a/src/vs/workbench/parts/git/browser/media/Refresh.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/add-focus.svg b/src/vs/workbench/parts/git/browser/media/add-focus.svg deleted file mode 100644 index 5e9f5851e8b..00000000000 --- a/src/vs/workbench/parts/git/browser/media/add-focus.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/add-inverse.svg b/src/vs/workbench/parts/git/browser/media/add-inverse.svg deleted file mode 100644 index 3475c1e1963..00000000000 --- a/src/vs/workbench/parts/git/browser/media/add-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/add.svg b/src/vs/workbench/parts/git/browser/media/add.svg deleted file mode 100644 index bdecdb0e45b..00000000000 --- a/src/vs/workbench/parts/git/browser/media/add.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/check-inverse.svg b/src/vs/workbench/parts/git/browser/media/check-inverse.svg deleted file mode 100644 index c225b2f597f..00000000000 --- a/src/vs/workbench/parts/git/browser/media/check-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/check.svg b/src/vs/workbench/parts/git/browser/media/check.svg deleted file mode 100644 index d45df06edf8..00000000000 --- a/src/vs/workbench/parts/git/browser/media/check.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/git-dark.svg b/src/vs/workbench/parts/git/browser/media/git-dark.svg deleted file mode 100644 index c08b1c2e403..00000000000 --- a/src/vs/workbench/parts/git/browser/media/git-dark.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/git.contribution.css b/src/vs/workbench/parts/git/browser/media/git.contribution.css deleted file mode 100644 index 80ad1fe1419..00000000000 --- a/src/vs/workbench/parts/git/browser/media/git.contribution.css +++ /dev/null @@ -1,155 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Appbar */ - -.monaco-workbench .git-action.open-in-diff { - background: url('Compare.svg') center center no-repeat; -} - -.monaco-workbench .git-action.open-in-editor { - background: url('OpenEditor.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .git-action.open-in-diff, -.hc-black .monaco-workbench .git-action.open-in-diff { - background: url('Compare_inverse.svg') center center no-repeat; -} - -.vs-dark .monaco-workbench .git-action.open-in-editor, -.hc-black .monaco-workbench .git-action.open-in-editor { - background: url('OpenEditor_inverse.svg') center center no-repeat; -} - -/* Activity Bar */ -.monaco-workbench > .activitybar .monaco-action-bar .action-label.git { - -webkit-mask: url('git-dark.svg') no-repeat 50% 50%; -} - -/* Status / Quick Open */ -.monaco-shell .git-statusbar-group > .git-statusbar-branch-item, -.vs-dark .monaco-workbench .quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.git { - background-image: url('git-dark.svg'); -} - -/* Git viewlet label */ - -.git-viewlet-label-progress > .badge-content { - background-image: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNCIgdmlld0JveD0iMiAyIDE0IDE0IiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDIgMiAxNCAxNCI+PHBhdGggZmlsbD0iI2ZmZiIgZD0iTTkgMTZjLTMuODYgMC03LTMuMTQtNy03czMuMTQtNyA3LTdjMy44NTkgMCA3IDMuMTQxIDcgN3MtMy4xNDEgNy03IDd6bTAtMTIuNmMtMy4wODggMC01LjYgMi41MTMtNS42IDUuNnMyLjUxMiA1LjYgNS42IDUuNiA1LjYtMi41MTIgNS42LTUuNi0yLjUxMi01LjYtNS42LTUuNnptMy44NiA3LjFsLTMuMTYtMS44OTZ2LTMuODA0aC0xLjR2NC41OTZsMy44NCAyLjMwNS43Mi0xLjIwMXoiLz48L3N2Zz4="); - background-position: center center; - background-repeat: no-repeat; -} - -/* Git merge editor decorations */ -.monaco-editor .git-merge-control-decoration { - background-color: rgba(255, 139, 0, 0.3); -} -.monaco-editor.vs-dark .git-merge-control-decoration { - background-color: rgba(235, 59, 0, 0.3); -} - -.monaco-shell .git-branch-dropdown-menu .action-label.git-action.checkout.HEAD { - font-weight: bold; -} - -.monaco-shell .git-branch-dropdown-menu .monaco-inputbox { - font-size: 12px; - width: 100%; -} - -.monaco-shell .git-branch-dropdown-menu .monaco-inputbox > .wrapper > .input { - background-color: transparent; -} - -.monaco-shell .git-branch-dropdown-menu .monaco-inputbox > .wrapper > .input { - padding: 0.8em 1em; -} - -/* Quick Open */ - -.monaco-workbench .quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.git { - background-size: 100%; -} - -.vs .monaco-workbench .quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon.git { - background-image: url('git.svg'); -} - -/* Actions */ - -.monaco-shell .git-action.live-sync.icon { - background: url('sync.svg') 7px center no-repeat; -} - -.monaco-shell .git-action.live-sync.icon.loading { - animation: spin-forever 1.6s linear infinite; -} - -@keyframes spin-forever { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } - -/* High Contrast Theming */ -.hc-black .monaco-workbench > .activitybar .monaco-action-bar .badge.git-viewlet-label-progress .badge-content { - width: 1px; -} - -/* Status bar */ - -.monaco-shell .git-statusbar-group > a { - padding: 0 5px; -} - -.monaco-shell .git-statusbar-group > a.disabled { - opacity: 0.7; -} - -.monaco-shell .git-statusbar-group > a.octicon { - line-height: 22px; - width: 16px; - text-align: center; -} - -.monaco-shell .git-statusbar-group .octicon { - font-size: 14px; -} - -.monaco-shell .git-statusbar-group > .git-statusbar-sync-item:not(.empty) > span.octicon { - margin-right: 6px; -} - -@keyframes spin { - from { transform: rotate(0deg); } - to { transform: rotate(1080deg); } -} - -.monaco-shell .git-statusbar-group > .git-statusbar-sync-item.syncing > .octicon { - animation: 2s ease-in-out infinite spin; -} - -.monaco-shell .git-statusbar-group > .git-statusbar-sync-item.disabled > .ahead-behind, -.monaco-shell .git-statusbar-group > .git-statusbar-sync-item.busy > .ahead-behind { - cursor: default; -} - -.monaco-shell .git-statusbar-group > .git-statusbar-branch-item { - background-repeat: no-repeat; - background-position: 4px 50%; - background-size: 17px; - cursor: default; - padding: 0 5px 0 22px; -} - -.monaco-shell .git-statusbar-group > a:not(.disabled):not(.busy) { - cursor: pointer; -} - -.monaco-shell .git-statusbar-group > .busy, -.monaco-shell .git-statusbar-group > .disabled, { - opacity: 0.6; - cursor: default; -} - -.monaco-shell .git-statusbar-group > .git-statusbar-branch-item.headless { - font-style: italic; -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/git.svg b/src/vs/workbench/parts/git/browser/media/git.svg deleted file mode 100644 index d1049a44d0d..00000000000 --- a/src/vs/workbench/parts/git/browser/media/git.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/gitViewlet.css b/src/vs/workbench/parts/git/browser/media/gitViewlet.css deleted file mode 100644 index 10037adab11..00000000000 --- a/src/vs/workbench/parts/git/browser/media/gitViewlet.css +++ /dev/null @@ -1,93 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Git viewlet */ - -.git-viewlet { - height: 100%; -} - -/* Actionbar actions */ - -.git-action.refresh { - background: url('Refresh.svg') center center no-repeat; -} - -.git-action.smart-commit { - background: url('check.svg') center center no-repeat; -} - -.git-action.run-pull { - background: url('pull.svg') center center no-repeat; -} - -.git-action.run-push { - background: url('push.svg') center center no-repeat; -} - -/* Tree actions */ - -.git-action.stage { - background: url('add.svg') center center no-repeat; -} - -.git-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .git-action.stage { - background: url('add-focus.svg') center center no-repeat; -} - -.git-action.undo { - background: url('undo.svg') center center no-repeat; -} - -.git-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .git-action.undo { - background: url('undo-focus.svg') center center no-repeat; -} - -.git-action.unstage { - background: url('subtract.svg') center center no-repeat; -} - -.git-viewlet .focused .monaco-tree-row.selected:not(.highlighted) > .content.actions .git-action.unstage { - background: url('subtract-focus.svg') center center no-repeat; -} - -/* Dark theme actions */ - -.vs-dark .git-action.refresh, -.hc-black .git-action.refresh { - background: url('refresh-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.commit, -.hc-black .git-action.commit, -.vs-dark .git-action.stage-and-commit, -.hc-black .git-action.stage-and-commit, -.vs-dark .git-action.smart-commit, -.hc-black .git-action.smart-commit { - background: url('check-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.run-pull { - background: url('pull-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.run-push { - background: url('push-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.stage, -.hc-black .git-action.stage { - background: url('add-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.undo, -.hc-black .git-action.undo { - background: url('undo-inverse.svg') center center no-repeat; -} - -.vs-dark .git-action.unstage, -.hc-black .git-action.unstage { - background: url('subtract-inverse.svg') center center no-repeat; -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/pull-inverse.svg b/src/vs/workbench/parts/git/browser/media/pull-inverse.svg deleted file mode 100644 index 6f2df243de8..00000000000 --- a/src/vs/workbench/parts/git/browser/media/pull-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/pull.svg b/src/vs/workbench/parts/git/browser/media/pull.svg deleted file mode 100644 index 6d2ccb64649..00000000000 --- a/src/vs/workbench/parts/git/browser/media/pull.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/push-inverse.svg b/src/vs/workbench/parts/git/browser/media/push-inverse.svg deleted file mode 100644 index 5afca6bc64e..00000000000 --- a/src/vs/workbench/parts/git/browser/media/push-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/push.svg b/src/vs/workbench/parts/git/browser/media/push.svg deleted file mode 100644 index 7b57be602b9..00000000000 --- a/src/vs/workbench/parts/git/browser/media/push.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/refresh-inverse.svg b/src/vs/workbench/parts/git/browser/media/refresh-inverse.svg deleted file mode 100644 index d79fdaa4e8e..00000000000 --- a/src/vs/workbench/parts/git/browser/media/refresh-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/subtract-focus.svg b/src/vs/workbench/parts/git/browser/media/subtract-focus.svg deleted file mode 100644 index 64cecb0d222..00000000000 --- a/src/vs/workbench/parts/git/browser/media/subtract-focus.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/subtract-inverse.svg b/src/vs/workbench/parts/git/browser/media/subtract-inverse.svg deleted file mode 100644 index 2de46fcf5b5..00000000000 --- a/src/vs/workbench/parts/git/browser/media/subtract-inverse.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/subtract.svg b/src/vs/workbench/parts/git/browser/media/subtract.svg deleted file mode 100644 index f5d128b2df8..00000000000 --- a/src/vs/workbench/parts/git/browser/media/subtract.svg +++ /dev/null @@ -1 +0,0 @@ -Layer 1 \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/sync.svg b/src/vs/workbench/parts/git/browser/media/sync.svg deleted file mode 100644 index 5a4bf0799e4..00000000000 --- a/src/vs/workbench/parts/git/browser/media/sync.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/undo-focus.svg b/src/vs/workbench/parts/git/browser/media/undo-focus.svg deleted file mode 100644 index c2d0cda307a..00000000000 --- a/src/vs/workbench/parts/git/browser/media/undo-focus.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/undo-inverse.svg b/src/vs/workbench/parts/git/browser/media/undo-inverse.svg deleted file mode 100644 index 9f175633389..00000000000 --- a/src/vs/workbench/parts/git/browser/media/undo-inverse.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/media/undo.svg b/src/vs/workbench/parts/git/browser/media/undo.svg deleted file mode 100644 index 1fa6ba48a19..00000000000 --- a/src/vs/workbench/parts/git/browser/media/undo.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesView.css b/src/vs/workbench/parts/git/browser/views/changes/changesView.css deleted file mode 100644 index bd5892f7cc4..00000000000 --- a/src/vs/workbench/parts/git/browser/views/changes/changesView.css +++ /dev/null @@ -1,171 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/* Commit view */ - -.git-viewlet > .changes-view > .commit-view { - box-sizing: border-box; - padding: 5px 9px 5px 16px; -} - -.git-viewlet > .changes-view > .commit-view > .monaco-inputbox { - width: 100%; -} - -.git-viewlet > .changes-view > .commit-view > .monaco-inputbox > .wrapper > .mirror { - max-height: 134px; -} - -.git-viewlet > .changes-view > .commit-view > .monaco-inputbox > .wrapper > textarea.input { - min-height: 26px; -} - -.git-viewlet > .changes-view > .commit-view.scroll > .monaco-inputbox > .wrapper > textarea.input { - overflow-y: scroll; -} - -/* Status view */ - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .content { - line-height: 22px; - display: flex; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .content .monaco-action-bar { - display: none; - margin-right: 12px; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .content .monaco-action-bar .action-item { - margin-top: 2px; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .content .monaco-action-bar .action-label { - width: 16px; - height: 16px; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row:hover .content .monaco-action-bar, -.git-viewlet > .changes-view > .status-view > .monaco-tree.focused .monaco-tree-row.focused .content .monaco-action-bar { - display: block; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row:hover .content .monaco-count-badge, -.git-viewlet > .changes-view > .status-view > .monaco-tree.focused .monaco-tree-row.focused .content .monaco-count-badge { - display: none; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-rows > .monaco-tree-row > .content:before { - background: none; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group { - font-size: 11px; - font-weight: bold; - text-transform: uppercase; - cursor: default; -} - -/* Bold font style does not go well with CJK fonts */ -.git-viewlet:lang(zh-Hans) > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group, -.git-viewlet:lang(zh-Hant) > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group, -.git-viewlet:lang(ja) > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group, -.git-viewlet:lang(ko) > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group { font-weight: normal; } - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .count-badge-wrapper { - padding-right: 12px; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group, -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status { - overflow: hidden; - text-overflow: ellipsis; - flex: 1; -} - -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .status-group { - color: inherit; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.out-of-workspace { - opacity: 0.5; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .status { - padding: 2px 4px; - font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Inconsolata", "Courier New", monospace, "Droid Sans Fallback"; - font-size: 70%; - color: white; - text-align: center; - border-radius: 0.5em; - vertical-align: bottom; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .name { - margin-left: 0.4em; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.modified .status { background-color: #007ACC; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.added .status { background-color: #2d883e; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted .status { background-color: #B9131A; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.renamed .status { background-color: #4668C5; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.copied .status { background-color: #682079; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.untracked .status { background-color: #6C6C6C; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.ignored .status { background-color: #969696; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.conflict .status { background-color: #9B4F96; } -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row.selected .file-status .status { background-color: #ffffff; color: #666; } - -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.modified .status { background-color: #1B80B2; } -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.added .status { background-color: #3c8746; } -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted .status { background-color: #9E121D; } -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.copied .status { background-color: #692C77; } -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.conflict .status { background-color: #7F4E7E; } -.vs-dark .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row.selected .file-status .status { background-color: #ffffff; color: #666; } - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted .name, -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.both-deleted .name, -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted-by-them .name, -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted-by-us .name { - text-decoration: line-through; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status:not(.renamed) > .rename { - display: none; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .rename-name:not(:empty), -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .rename-arrow { - margin-left: 0.4em; -} - -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .rename-folder:not(:empty), -.git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .folder:not(:empty) { - opacity: 0.7; - font-size: 0.9em; - margin-left: 0.8em; -} - -/* High Contrast Theming */ -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .content { - line-height: 20px; -} - -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status .status { - top: 2px; -} - -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.modified .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.added .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.deleted .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.renamed .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.copied .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.untracked .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.ignored .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row .file-status.conflict .status, -.hc-black .git-viewlet > .changes-view > .status-view > .monaco-tree .monaco-tree-row.selected .file-status .status { - background-color: #000; - color: #fff; - border: 1px solid #6FC3DF; -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts b/src/vs/workbench/parts/git/browser/views/changes/changesView.ts deleted file mode 100644 index 6f92d464832..00000000000 --- a/src/vs/workbench/parts/git/browser/views/changes/changesView.ts +++ /dev/null @@ -1,496 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./changesView'; -import nls = require('vs/nls'); -import Platform = require('vs/base/common/platform'); -import Lifecycle = require('vs/base/common/lifecycle'); -import EventEmitter = require('vs/base/common/eventEmitter'); -import Strings = require('vs/base/common/strings'); -import Errors = require('vs/base/common/errors'); -import * as paths from 'vs/base/common/paths'; -import WinJS = require('vs/base/common/winjs.base'); -import Builder = require('vs/base/browser/builder'); -import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import Actions = require('vs/base/common/actions'); -import ActionBar = require('vs/base/browser/ui/actionbar/actionbar'); -import Tree = require('vs/base/parts/tree/browser/tree'); -import TreeImpl = require('vs/base/parts/tree/browser/treeImpl'); -import git = require('vs/workbench/parts/git/common/git'); -import GitView = require('vs/workbench/parts/git/browser/views/view'); -import GitActions = require('vs/workbench/parts/git/browser/gitActions'); -import GitModel = require('vs/workbench/parts/git/common/gitModel'); -import Viewer = require('vs/workbench/parts/git/browser/views/changes/changesViewer'); -import GitEditorInputs = require('vs/workbench/parts/git/browser/gitEditorInputs'); -import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import WorkbenchEditorCommon = require('vs/workbench/common/editor'); -import InputBox = require('vs/base/browser/ui/inputbox/inputBox'); -import Severity from 'vs/base/common/severity'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; -import { IEditorInput } from 'vs/platform/editor/common/editor'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isEqualOrParent } from 'vs/platform/files/common/files'; -import { attachInputBoxStyler, attachListStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; - -import IGitService = git.IGitService; - -var $ = Builder.$; - -export class ChangesView extends EventEmitter.EventEmitter implements GitView.IView, GitActions.ICommitState { - - public ID = 'changes'; - - private static COMMIT_KEYBINDING = Platform.isMacintosh ? 'Cmd+Enter' : 'Ctrl+Enter'; - private static NEED_MESSAGE = nls.localize('needMessage', "Please provide a commit message. You can always press **{0}** to commit changes. If there are any staged changes, only those will be committed; otherwise, all changes will.", ChangesView.COMMIT_KEYBINDING); - private static NOTHING_TO_COMMIT = nls.localize('nothingToCommit', "Once there are some changes to commit, type in the commit message and either press **{0}** to commit changes. If there are any staged changes, only those will be committed; otherwise, all changes will.", ChangesView.COMMIT_KEYBINDING); - private static LONG_COMMIT = nls.localize('longCommit', "It is recommended to keep the commit's first line under 50 characters. Feel free to use more lines for extra information."); - - private instantiationService: IInstantiationService; - private editorService: IWorkbenchEditorService; - private messageService: IMessageService; - private contextViewService: IContextViewService; - private contextService: IWorkspaceContextService; - private gitService: IGitService; - private outputService: IOutputService; - - private $el: Builder.Builder; - private $commitView: Builder.Builder; - private $statusView: Builder.Builder; - private commitInputBox: InputBox.InputBox; - private tree: Tree.ITree; - - private visible: boolean; - private currentDimension: Builder.Dimension; - - private smartCommitAction: GitActions.SmartCommitAction; - private actions: Actions.IAction[]; - private secondaryActions: Actions.IAction[]; - private actionRunner: Actions.IActionRunner; - - private toDispose: Lifecycle.IDisposable[]; - - constructor(actionRunner: Actions.IActionRunner, - @IInstantiationService instantiationService: IInstantiationService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IEditorGroupService editorGroupService: IEditorGroupService, - @IMessageService messageService: IMessageService, - @IContextViewService contextViewService: IContextViewService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @IGitService gitService: IGitService, - @IOutputService outputService: IOutputService, - @IConfigurationService private configurationService: IConfigurationService, - @IThemeService private themeService: IThemeService - ) { - super(); - - this.instantiationService = instantiationService; - this.editorService = editorService; - this.messageService = messageService; - this.contextViewService = contextViewService; - this.contextService = contextService; - this.gitService = gitService; - this.outputService = outputService; - - this.visible = false; - this.currentDimension = null; - this.actionRunner = actionRunner; - - this.toDispose = [ - this.smartCommitAction = this.instantiationService.createInstance(GitActions.SmartCommitAction, this), - editorGroupService.onEditorsChanged(() => this.onEditorsChanged(this.editorService.getActiveEditorInput()).done(null, Errors.onUnexpectedError)), - this.gitService.addListener(git.ServiceEvents.OPERATION_START, (e) => this.onGitOperationStart(e)), - this.gitService.addListener(git.ServiceEvents.OPERATION_END, (e) => this.onGitOperationEnd(e)), - this.gitService.getModel().addListener(git.ModelEvents.MODEL_UPDATED, this.onGitModelUpdate.bind(this)) - ]; - } - - // IView - - public get element(): HTMLElement { - this.render(); - return this.$el.getHTMLElement(); - } - - private render(): void { - if (this.$el) { - return; - } - - this.$el = $('.changes-view'); - this.$commitView = $('.commit-view').appendTo(this.$el); - - // Commit view - - this.commitInputBox = new InputBox.InputBox(this.$commitView.getHTMLElement(), this.contextViewService, { - placeholder: nls.localize('commitMessage', "Message (press {0} to commit)", ChangesView.COMMIT_KEYBINDING), - validationOptions: { - showMessage: true, - validation: (value): InputBox.IMessage => { - const config = this.configurationService.getConfiguration('git'); - - if (!config.enableLongCommitWarning) { - return null; - } - - if (/^[^\n]{51}/.test(value)) { - return { - content: ChangesView.LONG_COMMIT, - type: InputBox.MessageType.WARNING - }; - } - - return null; - } - }, - ariaLabel: nls.localize('commitMessageAriaLabel', "Git: Type commit message and press {0} to commit", ChangesView.COMMIT_KEYBINDING), - flexibleHeight: true - }); - this.toDispose.push(attachInputBoxStyler(this.commitInputBox, this.themeService)); - - this.commitInputBox.onDidChange((value) => this.emit('change', value)); - this.commitInputBox.onDidHeightChange((value) => this.emit('heightchange', value)); - - $(this.commitInputBox.inputElement).on('keydown', (e: KeyboardEvent) => { - var keyboardEvent = new StandardKeyboardEvent(e); - - if (keyboardEvent.equals(KeyMod.CtrlCmd | KeyCode.Enter) || keyboardEvent.equals(KeyMod.CtrlCmd | KeyCode.KEY_S)) { - if (this.smartCommitAction.enabled) { - this.actionRunner.run(this.smartCommitAction).done(); - } else { - this.commitInputBox.showMessage({ content: ChangesView.NOTHING_TO_COMMIT, formatContent: true, type: InputBox.MessageType.INFO }); - } - } - }).on('blur', () => { - this.commitInputBox.hideMessage(); - }); - - // Status view - - this.$statusView = $('.status-view').appendTo(this.$el); - - var actionProvider = this.instantiationService.createInstance(Viewer.ActionProvider); - var renderer = this.instantiationService.createInstance(Viewer.Renderer, actionProvider, this.actionRunner); - var dnd = this.instantiationService.createInstance(Viewer.DragAndDrop); - var controller = this.instantiationService.createInstance(Viewer.Controller, actionProvider); - - this.tree = new TreeImpl.Tree(this.$statusView.getHTMLElement(), { - dataSource: new Viewer.DataSource(), - renderer: renderer, - filter: new Viewer.Filter(), - sorter: new Viewer.Sorter(), - accessibilityProvider: new Viewer.AccessibilityProvider(), - dnd: dnd, - controller: controller - }, { - indentPixels: 0, - twistiePixels: 20, - ariaLabel: nls.localize('treeAriaLabel', "Git Changes View") - }); - - this.toDispose.push(attachListStyler(this.tree, this.themeService)); - this.tree.setInput(this.gitService.getModel().getStatus()); - this.tree.expandAll(this.gitService.getModel().getStatus().getGroups()); - - this.toDispose.push(this.tree.addListener('selection', (e) => this.onSelection(e))); - this.toDispose.push(this.commitInputBox.onDidHeightChange(() => this.layout())); - } - - public focus(): void { - var selection = this.tree.getSelection(); - if (selection.length > 0) { - this.tree.reveal(selection[0], 0.5).done(null, Errors.onUnexpectedError); - } - - this.commitInputBox.focus(); - } - - public layout(dimension: Builder.Dimension = this.currentDimension): void { - if (!dimension) { - return; - } - - this.currentDimension = dimension; - - this.commitInputBox.layout(); - var statusViewHeight = dimension.height - (this.commitInputBox.height + 12 /* margin */); - this.$statusView.size(dimension.width, statusViewHeight); - this.tree.layout(statusViewHeight); - - if (this.commitInputBox.height === 134) { - this.$commitView.addClass('scroll'); - } else { - this.$commitView.removeClass('scroll'); - } - } - - public setVisible(visible: boolean): WinJS.TPromise { - this.visible = visible; - - if (visible) { - this.tree.onVisible(); - this.updateCommitInputTemplate(); - return this.onEditorsChanged(this.editorService.getActiveEditorInput()); - } else { - this.tree.onHidden(); - return WinJS.TPromise.as(null); - } - } - - private onUndoLastCommit(commit: git.ICommit): void { - if (this.commitInputBox.value) { - return; - } - - this.commitInputBox.value = commit.message; - } - - private updateCommitInputTemplate(): void { - if (this.commitInputBox.value) { - return; - } - - this.gitService.getCommitTemplate() - .then(template => template && (this.commitInputBox.value = template)) - .done(null, Errors.onUnexpectedError); - } - - public getControl(): Tree.ITree { - return this.tree; - } - - public getActions(): Actions.IAction[] { - if (!this.actions) { - this.actions = [ - this.smartCommitAction, - this.instantiationService.createInstance(GitActions.RefreshAction) - ]; - - this.actions.forEach(a => this.toDispose.push(a)); - } - - return this.actions; - } - - public getSecondaryActions(): Actions.IAction[] { - if (!this.secondaryActions) { - this.secondaryActions = [ - this.instantiationService.createInstance(GitActions.SyncAction, GitActions.SyncAction.ID, GitActions.SyncAction.LABEL), - this.instantiationService.createInstance(GitActions.PullAction, GitActions.PullAction.ID, GitActions.PullAction.LABEL), - this.instantiationService.createInstance(GitActions.PullWithRebaseAction, GitActions.PullWithRebaseAction.ID, GitActions.PullWithRebaseAction.LABEL), - this.instantiationService.createInstance(GitActions.PushAction, GitActions.PushAction.ID, GitActions.PushAction.LABEL), - this.instantiationService.createInstance(GitActions.PushToRemoteAction, GitActions.PushToRemoteAction.ID, GitActions.PushToRemoteAction.LABEL), - new ActionBar.Separator(), - this.instantiationService.createInstance(GitActions.PublishAction, GitActions.PublishAction.ID, GitActions.PublishAction.LABEL), - new ActionBar.Separator(), - this.instantiationService.createInstance(GitActions.CommitAction, this), - this.instantiationService.createInstance(GitActions.CommitSignedOffAction, this), - this.instantiationService.createInstance(GitActions.CommitAmendAction, this), - this.instantiationService.createInstance(GitActions.StageAndCommitAction, this, GitActions.StageAndCommitAction.ID, GitActions.StageAndCommitAction.LABEL, GitActions.StageAndCommitAction.CSSCLASS), - this.instantiationService.createInstance(GitActions.StageAndCommitSignedOffAction, this), - this.instantiationService.createInstance(GitActions.UndoLastCommitAction, GitActions.UndoLastCommitAction.ID, GitActions.UndoLastCommitAction.LABEL), - new ActionBar.Separator(), - this.instantiationService.createInstance(GitActions.GlobalUnstageAction), - this.instantiationService.createInstance(GitActions.GlobalUndoAction), - new ActionBar.Separator(), - new Actions.Action('show.gitOutput', nls.localize('showOutput', "Show Git Output"), null, true, () => this.outputService.getChannel('Git').show()) - ]; - - this.secondaryActions.forEach(a => this.toDispose.push(a)); - } - - return this.secondaryActions; - } - - // ICommitState - - public getCommitMessage(): string { - return Strings.trim(this.commitInputBox.value); - } - - public onEmptyCommitMessage(): void { - this.commitInputBox.focus(); - this.commitInputBox.showMessage({ content: ChangesView.NEED_MESSAGE, formatContent: true, type: InputBox.MessageType.INFO }); - } - - // Events - - private onGitModelUpdate(): void { - if (this.tree) { - this.tree.refresh().done(() => { - return this.tree.expandAll(this.gitService.getModel().getStatus().getGroups()); - }); - } - } - - private onEditorsChanged(input: IEditorInput): WinJS.TPromise { - if (!this.tree) { - return WinJS.TPromise.as(null); - } - - var status = this.getStatusFromInput(input); - - if (!status) { - this.tree.clearSelection(); - } - - if (this.visible && this.tree.getSelection().indexOf(status) === -1) { - return this.tree.reveal(status, 0.5).then(() => { - this.tree.setSelection([status], { origin: 'implicit' }); - }); - } - - return WinJS.TPromise.as(null); - } - - private onSelection(e: Tree.ISelectionEvent): void { - if (e.payload && e.payload && e.payload.origin === 'implicit') { - return; - } - - if (e.selection.length !== 1) { - return; - } - - var element = e.selection[0]; - - if (!(element instanceof GitModel.FileStatus)) { - return; - } - - if (e.payload && e.payload.origin === 'keyboard' && !(e.payload.originalEvent).equals(KeyCode.Enter)) { - return; - } - - var isMouseOrigin = e.payload && (e.payload.origin === 'mouse'); - - if (isMouseOrigin && (e.payload.originalEvent.metaKey || e.payload.originalEvent.shiftKey)) { - return; - } - - var isDoubleClick = isMouseOrigin && e.payload.originalEvent && e.payload.originalEvent.detail === 2; - - var status = element; - - this.gitService.getInput(status).done((input) => { - var options = new WorkbenchEditorCommon.TextDiffEditorOptions(); - - if (isMouseOrigin) { - options.preserveFocus = true; - - var originalEvent: MouseEvent = e && e.payload && e.payload.origin === 'mouse' && e.payload.originalEvent; - if (originalEvent && originalEvent.detail === 2) { - options.preserveFocus = false; - originalEvent.preventDefault(); // focus moves to editor, we need to prevent default - } - } - - options.forceOpen = true; - options.pinned = isDoubleClick; - - var sideBySide = (e && e.payload && e.payload.originalEvent && e.payload.originalEvent.altKey); - - return this.editorService.openEditor(input, options, sideBySide); - }, (e) => { - if (e.gitErrorCode === git.GitErrorCodes.CantOpenResource) { - this.messageService.show(Severity.Warning, e); - return; - } - - this.messageService.show(Severity.Error, e); - }); - } - - private onGitOperationStart(operation: git.IGitOperation): void { - if (operation.id === git.ServiceOperations.COMMIT) { - if (this.commitInputBox) { - this.commitInputBox.disable(); - } - } else if (operation.id === git.ServiceOperations.RESET) { - const promise = this.gitService.getCommit('HEAD'); - const listener = this.gitService.addListener(git.ServiceEvents.OPERATION_END, e => { - if (e.operation.id === git.ServiceOperations.RESET && !e.error) { - promise.done(c => this.onUndoLastCommit(c)); - listener.dispose(); - } - }); - } - } - - private onGitOperationEnd(e: { operation: git.IGitOperation; error: any; }): void { - if (e.operation.id === git.ServiceOperations.COMMIT) { - if (this.commitInputBox) { - this.commitInputBox.enable(); - - if (!e.error) { - this.commitInputBox.value = ''; - this.updateCommitInputTemplate(); - } - } - } - } - - // Misc - - private getStatusFromInput(input: IEditorInput): git.IFileStatus { - if (!input) { - return null; - } - - if (input instanceof GitEditorInputs.GitDiffEditorInput) { - return (input).getFileStatus(); - } - - if (input instanceof GitEditorInputs.NativeGitIndexStringEditorInput) { - return (input).getFileStatus() || null; - } - - const resource = WorkbenchEditorCommon.toResource(input, { filter: 'file' }); - if (resource) { - const workspaceRoot = this.contextService.getWorkspace().resource.fsPath; - if (!workspaceRoot || !isEqualOrParent(resource.fsPath, workspaceRoot, !Platform.isLinux /* ignorecase */)) { - return null; // out of workspace not yet supported - } - - const repositoryRoot = this.gitService.getModel().getRepositoryRoot(); - if (!repositoryRoot || !isEqualOrParent(resource.fsPath, repositoryRoot, !Platform.isLinux /* ignorecase */)) { - return null; // out of repository not supported - } - - const repositoryRelativePath = paths.normalize(paths.relative(repositoryRoot, resource.fsPath)); - - var status = this.gitService.getModel().getStatus().getWorkingTreeStatus().find(repositoryRelativePath); - if (status && (status.getStatus() === git.Status.UNTRACKED || status.getStatus() === git.Status.IGNORED)) { - return status; - } - - status = this.gitService.getModel().getStatus().getMergeStatus().find(repositoryRelativePath); - if (status) { - return status; - } - } - - return null; - } - - public dispose(): void { - if (this.$el) { - this.$el.dispose(); - this.$el = null; - } - - this.toDispose = Lifecycle.dispose(this.toDispose); - - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts b/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts deleted file mode 100644 index 4dd5130e987..00000000000 --- a/src/vs/workbench/parts/git/browser/views/changes/changesViewer.ts +++ /dev/null @@ -1,921 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 winjs = require('vs/base/common/winjs.base'); -import nls = require('vs/nls'); -import platform = require('vs/base/common/platform'); -import paths = require('vs/base/common/paths'); -import severity from 'vs/base/common/severity'; -import lifecycle = require('vs/base/common/lifecycle'); -import dom = require('vs/base/browser/dom'); -import keyboard = require('vs/base/browser/keyboardEvent'); -import mouse = require('vs/base/browser/mouseEvent'); -import comparers = require('vs/base/common/comparers'); -import actions = require('vs/base/common/actions'); -import actionbar = require('vs/base/browser/ui/actionbar/actionbar'); -import countbadge = require('vs/base/browser/ui/countBadge/countBadge'); -import tree = require('vs/base/parts/tree/browser/tree'); -import treednd = require('vs/base/parts/tree/browser/treeDnd'); -import treedefaults = require('vs/base/parts/tree/browser/treeDefaults'); -import * as git from 'vs/workbench/parts/git/common/git'; -import gitmodel = require('vs/workbench/parts/git/common/gitModel'); -import gitactions = require('vs/workbench/parts/git/browser/gitActions'); -import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import URI from 'vs/base/common/uri'; - -import IGitService = git.IGitService; - -function toReadablePath(path: string): string { - if (!platform.isWindows) { - return path; - } - - return path.replace(/\//g, '\\'); -} - -const $ = dom.$; - -export class ActionContainer implements lifecycle.IDisposable { - - private cache: { [actionId: string]: actions.IAction; }; - private instantiationService: IInstantiationService; - - constructor(instantiationService: IInstantiationService) { - this.cache = {}; - this.instantiationService = instantiationService; - } - - protected getAction(ctor: any, ...args: any[]): any { - var action = this.cache[ctor.ID]; - - if (!action) { - args.unshift(ctor); - action = this.cache[ctor.ID] = this.instantiationService.createInstance.apply(this.instantiationService, args); - } - - return action; - } - - public dispose(): void { - Object.keys(this.cache).forEach(k => { - this.cache[k].dispose(); - }); - - this.cache = null; - } -} - -export class DataSource implements tree.IDataSource { - - public getId(tree: tree.ITree, element: any): string { - if (element instanceof gitmodel.StatusModel) { - return 'root'; - } else if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - - switch (statusGroup.getType()) { - case git.StatusType.INDEX: return 'index'; - case git.StatusType.WORKING_TREE: return 'workingTree'; - case git.StatusType.MERGE: return 'merge'; - default: throw new Error('Invalid group type'); - } - } - - var status = element; - return status.getId(); - } - - public hasChildren(tree: tree.ITree, element: any): boolean { - if (element instanceof gitmodel.StatusModel) { - return true; - } else if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - return statusGroup.all().length > 0; - } - return false; - } - - public getChildren(tree: tree.ITree, element: any): winjs.Promise { - if (element instanceof gitmodel.StatusModel) { - var model = element; - return winjs.TPromise.as(model.getGroups()); - - } else if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - return winjs.TPromise.as(statusGroup.all()); - } - - return winjs.TPromise.as([]); - } - - public getParent(tree: tree.ITree, element: any): winjs.Promise { - return winjs.TPromise.as(null); - } -} - -export class ActionProvider extends ActionContainer implements tree.IActionProvider { - - private gitService: git.IGitService; - - constructor( @IInstantiationService instantiationService: IInstantiationService, @IGitService gitService: IGitService) { - super(instantiationService); - this.gitService = gitService; - } - - public hasActions(tree: tree.ITree, element: any): boolean { - if (element instanceof gitmodel.FileStatus) { - return true; - } else if (element instanceof gitmodel.StatusGroup && (element).all().length > 0) { - return true; - } - return false; - } - - public getActions(tree: tree.ITree, element: any): winjs.TPromise { - if (element instanceof gitmodel.StatusGroup) { - return winjs.TPromise.as(this.getActionsForGroupStatusType(element.getType())); - } else { - return winjs.TPromise.as(this.getActionsForFileStatusType(element.getType())); - } - } - - public getActionsForFileStatusType(statusType: git.StatusType): actions.IAction[] { - switch (statusType) { - case git.StatusType.INDEX: - return [this.getAction(gitactions.UnstageAction)]; - case git.StatusType.WORKING_TREE: - return [this.getAction(gitactions.UndoAction), this.getAction(gitactions.StageAction)]; - case git.StatusType.MERGE: - return [this.getAction(gitactions.StageAction)]; - default: - return []; - } - } - - public getActionsForGroupStatusType(statusType: git.StatusType): actions.IAction[] { - switch (statusType) { - case git.StatusType.INDEX: - return [this.getAction(gitactions.GlobalUnstageAction)]; - case git.StatusType.WORKING_TREE: - return [this.getAction(gitactions.GlobalUndoAction), this.getAction(gitactions.GlobalStageAction)]; - case git.StatusType.MERGE: - return [this.getAction(gitactions.StageAction)]; - default: - return []; - } - } - - public hasSecondaryActions(tree: tree.ITree, element: any): boolean { - return this.hasActions(tree, element); - } - - public getSecondaryActions(tree: tree.ITree, element: any): winjs.TPromise { - return this.getActions(tree, element).then((actions: actions.IAction[]) => { - - if (element instanceof gitmodel.FileStatus) { - var fileStatus = element; - var status = fileStatus.getStatus(); - - actions.push(new actionbar.Separator()); - - if (status !== git.Status.DELETED && status !== git.Status.INDEX_DELETED) { - actions.push(this.getAction(gitactions.OpenFileAction)); - } - - actions.push(this.getAction(gitactions.OpenChangeAction)); - } - - actions.reverse(); - return actions; - }); - } - - public getActionItem(tree: tree.ITree, element: any, action: actions.IAction): actionbar.IActionItem { - return null; - } -} - -interface IFileStatusTemplateData { - root: HTMLElement; - status: HTMLElement; - name: HTMLElement; - folder: HTMLElement; - renameName: HTMLElement; - renameFolder: HTMLElement; - actionBar: actionbar.ActionBar; -} - -interface IStatusGroupTemplateData { - root: HTMLElement; - count: countbadge.CountBadge; - actionBar: actionbar.ActionBar; -} - -const STAGED_CHANGES = nls.localize('stagedChanges', "Staged Changes"); -const CHANGES = nls.localize('allChanges', "Changes"); -const MERGE_CHANGES = nls.localize('mergeChanges', "Merge Changes"); - -export class Renderer implements tree.IRenderer { - - constructor( - private actionProvider: ActionProvider, - private actionRunner: actions.IActionRunner, - @IMessageService private messageService: IMessageService, - @IGitService private gitService: IGitService, - @IWorkspaceContextService private contextService: IWorkspaceContextService - ) { - // noop - } - - public getHeight(tree: tree.ITree, element: any): number { - return 22; - } - - public getTemplateId(tree: tree.ITree, element: any): string { - if (element instanceof gitmodel.StatusGroup) { - switch (element.getType()) { - case git.StatusType.INDEX: return 'index'; - case git.StatusType.WORKING_TREE: return 'workingTree'; - case git.StatusType.MERGE: return 'merge'; - } - } - - if (element instanceof gitmodel.FileStatus) { - switch (element.getType()) { - case git.StatusType.INDEX: return 'file:index'; - case git.StatusType.WORKING_TREE: return 'file:workingTree'; - case git.StatusType.MERGE: return 'file:merge'; - } - } - - return null; - } - - public renderTemplate(tree: tree.ITree, templateId: string, container: HTMLElement): any { - if (/^file:/.test(templateId)) { - return this.renderFileStatusTemplate(Renderer.templateIdToStatusType(templateId), container); - } else { - return this.renderStatusGroupTemplate(Renderer.templateIdToStatusType(templateId), container); - } - } - - private renderStatusGroupTemplate(statusType: git.StatusType, container: HTMLElement): IStatusGroupTemplateData { - var data: IStatusGroupTemplateData = Object.create(null); - - data.root = dom.append(container, $('.status-group')); - - switch (statusType) { - case git.StatusType.INDEX: data.root.textContent = STAGED_CHANGES; break; - case git.StatusType.WORKING_TREE: data.root.textContent = CHANGES; break; - case git.StatusType.MERGE: data.root.textContent = MERGE_CHANGES; break; - } - - const wrapper = dom.append(container, $('.count-badge-wrapper')); - data.count = new countbadge.CountBadge(wrapper); - - data.actionBar = new actionbar.ActionBar(container, { actionRunner: this.actionRunner }); - data.actionBar.push(this.actionProvider.getActionsForGroupStatusType(statusType), { icon: true, label: false }); - data.actionBar.addListener('run', e => e.error && this.onError(e.error)); - - return data; - } - - private renderFileStatusTemplate(statusType: git.StatusType, container: HTMLElement): IFileStatusTemplateData { - var data: IFileStatusTemplateData = Object.create(null); - - data.root = dom.append(container, $('.file-status')); - data.status = dom.append(data.root, $('span.status')); - data.name = dom.append(data.root, $('a.name.plain')); - data.folder = dom.append(data.root, $('span.folder')); - - var rename = dom.append(data.root, $('span.rename')); - var arrow = dom.append(rename, $('span.rename-arrow')); - arrow.textContent = '←'; - - data.renameName = dom.append(rename, $('span.rename-name')); - data.renameFolder = dom.append(rename, $('span.rename-folder')); - - data.actionBar = new actionbar.ActionBar(container, { actionRunner: this.actionRunner }); - data.actionBar.push(this.actionProvider.getActionsForFileStatusType(statusType), { icon: true, label: false }); - data.actionBar.addListener('run', e => e.error && this.onError(e.error)); - - return data; - } - - public renderElement(tree: tree.ITree, element: any, templateId: string, templateData: any): void { - if (/^file:/.test(templateId)) { - this.renderFileStatus(tree, element, templateData); - } else { - Renderer.renderStatusGroup(element, templateData); - } - } - - private static renderStatusGroup(statusGroup: git.IStatusGroup, data: IStatusGroupTemplateData): void { - data.actionBar.context = statusGroup; - data.count.setCount(statusGroup.all().length); - } - - private renderFileStatus(tree: tree.ITree, fileStatus: git.IFileStatus, data: IFileStatusTemplateData): void { - data.actionBar.context = { - tree: tree, - fileStatus: fileStatus - }; - - const repositoryRoot = this.gitService.getModel().getRepositoryRoot(); - - const status = fileStatus.getStatus(); - const renamePath = fileStatus.getRename(); - const path = fileStatus.getPath(); - const lastSlashIndex = path.lastIndexOf('/'); - const name = lastSlashIndex === -1 ? path : path.substr(lastSlashIndex + 1, path.length); - const folder = (lastSlashIndex === -1 ? '' : path.substr(0, lastSlashIndex)); - - data.root.className = 'file-status ' + Renderer.statusToClass(status); - data.status.textContent = Renderer.statusToChar(status); - data.status.title = Renderer.statusToTitle(status); - - const resource = URI.file(paths.normalize(paths.join(repositoryRoot, path))); - let isInWorkspace = this.contextService.isInsideWorkspace(resource); - - let rename = ''; - let renameFolder = ''; - - if (renamePath) { - const renameLastSlashIndex = renamePath.lastIndexOf('/'); - rename = renameLastSlashIndex === -1 ? renamePath : renamePath.substr(renameLastSlashIndex + 1, renamePath.length); - renameFolder = (renameLastSlashIndex === -1 ? '' : renamePath.substr(0, renameLastSlashIndex)); - - data.renameName.textContent = name; - data.renameFolder.textContent = folder; - - const resource = URI.file(paths.normalize(paths.join(repositoryRoot, renamePath))); - isInWorkspace = this.contextService.isInsideWorkspace(resource); - } - - if (isInWorkspace) { - data.root.title = ''; - } else { - data.root.title = nls.localize('outsideOfWorkspace', "This file is located outside the current workspace."); - data.root.className += ' out-of-workspace'; - } - - data.name.textContent = rename || name; - data.name.title = renamePath || path; - data.folder.textContent = toReadablePath(renameFolder || folder); - } - - public disposeTemplate(tree: tree.ITree, templateId: string, templateData: any): void { - if (/^file:/.test(templateId)) { - Renderer.disposeFileStatusTemplate(templateData); - } - } - - private static disposeFileStatusTemplate(templateData: IFileStatusTemplateData): void { - templateData.actionBar.dispose(); - } - - private static statusToChar(status: git.Status): string { - switch (status) { - case git.Status.INDEX_MODIFIED: return nls.localize('modified-char', "M"); - case git.Status.MODIFIED: return nls.localize('modified-char', "M"); - case git.Status.INDEX_ADDED: return nls.localize('added-char', "A"); - case git.Status.INDEX_DELETED: return nls.localize('deleted-char', "D"); - case git.Status.DELETED: return nls.localize('deleted-char', "D"); - case git.Status.INDEX_RENAMED: return nls.localize('renamed-char', "R"); - case git.Status.INDEX_COPIED: return nls.localize('copied-char', "C"); - case git.Status.UNTRACKED: return nls.localize('untracked-char', "U"); - case git.Status.IGNORED: return nls.localize('ignored-char', "!"); - case git.Status.BOTH_DELETED: return nls.localize('deleted-char', "D"); - case git.Status.ADDED_BY_US: return nls.localize('added-char', "A"); - case git.Status.DELETED_BY_THEM: return nls.localize('deleted-char', "D"); - case git.Status.ADDED_BY_THEM: return nls.localize('added-char', "A"); - case git.Status.DELETED_BY_US: return nls.localize('deleted-char', "D"); - case git.Status.BOTH_ADDED: return nls.localize('added-char', "A"); - case git.Status.BOTH_MODIFIED: return nls.localize('modified-char', "M"); - default: return ''; - } - } - - public static statusToTitle(status: git.Status): string { - switch (status) { - case git.Status.INDEX_MODIFIED: return nls.localize('title-index-modified', "Modified in index"); - case git.Status.MODIFIED: return nls.localize('title-modified', "Modified"); - case git.Status.INDEX_ADDED: return nls.localize('title-index-added', "Added to index"); - case git.Status.INDEX_DELETED: return nls.localize('title-index-deleted', "Deleted in index"); - case git.Status.DELETED: return nls.localize('title-deleted', "Deleted"); - case git.Status.INDEX_RENAMED: return nls.localize('title-index-renamed', "Renamed in index"); - case git.Status.INDEX_COPIED: return nls.localize('title-index-copied', "Copied in index"); - case git.Status.UNTRACKED: return nls.localize('title-untracked', "Untracked"); - case git.Status.IGNORED: return nls.localize('title-ignored', "Ignored"); - case git.Status.BOTH_DELETED: return nls.localize('title-conflict-both-deleted', "Conflict: both deleted"); - case git.Status.ADDED_BY_US: return nls.localize('title-conflict-added-by-us', "Conflict: added by us"); - case git.Status.DELETED_BY_THEM: return nls.localize('title-conflict-deleted-by-them', "Conflict: deleted by them"); - case git.Status.ADDED_BY_THEM: return nls.localize('title-conflict-added-by-them', "Conflict: added by them"); - case git.Status.DELETED_BY_US: return nls.localize('title-conflict-deleted-by-us', "Conflict: deleted by us"); - case git.Status.BOTH_ADDED: return nls.localize('title-conflict-both-added', "Conflict: both added"); - case git.Status.BOTH_MODIFIED: return nls.localize('title-conflict-both-modified', "Conflict: both modified"); - default: return ''; - } - } - - private static statusToClass(status: git.Status): string { - switch (status) { - case git.Status.INDEX_MODIFIED: return 'modified'; - case git.Status.MODIFIED: return 'modified'; - case git.Status.INDEX_ADDED: return 'added'; - case git.Status.INDEX_DELETED: return 'deleted'; - case git.Status.DELETED: return 'deleted'; - case git.Status.INDEX_RENAMED: return 'renamed'; - case git.Status.INDEX_COPIED: return 'copied'; - case git.Status.UNTRACKED: return 'untracked'; - case git.Status.IGNORED: return 'ignored'; - case git.Status.BOTH_DELETED: return 'conflict both-deleted'; - case git.Status.ADDED_BY_US: return 'conflict added-by-us'; - case git.Status.DELETED_BY_THEM: return 'conflict deleted-by-them'; - case git.Status.ADDED_BY_THEM: return 'conflict added-by-them'; - case git.Status.DELETED_BY_US: return 'conflict deleted-by-us'; - case git.Status.BOTH_ADDED: return 'conflict both-added'; - case git.Status.BOTH_MODIFIED: return 'conflict both-modified'; - default: return ''; - } - } - - private static templateIdToStatusType(templateId: string): git.StatusType { - if (/index$/.test(templateId)) { - return git.StatusType.INDEX; - } else if (/workingTree$/.test(templateId)) { - return git.StatusType.WORKING_TREE; - } else { - return git.StatusType.MERGE; - } - } - - private onError(error: any): void { - this.messageService.show(severity.Error, error); - } -} - -export class Filter implements tree.IFilter { - - public isVisible(tree: tree.ITree, element: any): boolean { - if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - - switch (statusGroup.getType()) { - case git.StatusType.INDEX: - case git.StatusType.MERGE: - return statusGroup.all().length > 0; - case git.StatusType.WORKING_TREE: - return true; - } - } - - return true; - } -} - -export class Sorter implements tree.ISorter { - - public compare(tree: tree.ITree, element: any, otherElement: any): number { - if (!(element instanceof gitmodel.FileStatus && otherElement instanceof gitmodel.FileStatus)) { - return 0; - } - - return Sorter.compareStatus(element, otherElement); - } - - private static compareStatus(element: git.IFileStatus, otherElement: git.IFileStatus): number { - var one = element.getPathComponents(); - var other = otherElement.getPathComponents(); - var lastOne = one.length - 1; - var lastOther = other.length - 1; - - var endOne: boolean, endOther: boolean, onePart: string, otherPart: string; - - for (var i = 0; ; i++) { - endOne = lastOne === i; - endOther = lastOther === i; - - if (endOne && endOther) { - return comparers.compareFileNames(one[i], other[i]); - } else if (endOne) { - return -1; - } else if (endOther) { - return 1; - } else if ((onePart = one[i].toLowerCase()) !== (otherPart = other[i].toLowerCase())) { - return onePart < otherPart ? -1 : 1; - } - } - } -} - -export class DragAndDrop extends ActionContainer implements tree.IDragAndDrop { - - private gitService: git.IGitService; - private messageService: IMessageService; - - constructor( @IInstantiationService instantiationService: IInstantiationService, @IGitService gitService: IGitService, @IMessageService messageService: IMessageService) { - super(instantiationService); - this.gitService = gitService; - this.messageService = messageService; - } - - public getDragURI(tree: tree.ITree, element: any): string { - if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - return 'git:' + statusGroup.getType(); - } else if (element instanceof gitmodel.FileStatus) { - var status = element; - return 'git:' + status.getType() + ':' + status.getPath(); - } - - return null; - } - - getDragLabel(tree: tree.ITree, elements: any[]): string { - if (elements.length > 1) { - return String(elements.length); - } - - const element = elements[0]; - - if (element instanceof gitmodel.StatusGroup) { - const group = element as gitmodel.StatusGroup; - - switch (group.getType()) { - case git.StatusType.INDEX: return STAGED_CHANGES; - case git.StatusType.WORKING_TREE: return CHANGES; - case git.StatusType.MERGE: return MERGE_CHANGES; - } - } - - const status = element as gitmodel.FileStatus; - return paths.basename(status.getPath()); - } - - public onDragStart(tree: tree.ITree, data: tree.IDragAndDropData, originalEvent: mouse.DragMouseEvent): void { - // no-op - } - - public onDragOver(_tree: tree.ITree, data: tree.IDragAndDropData, targetElement: any, originalEvent: mouse.DragMouseEvent): tree.IDragOverReaction { - if (!this.gitService.isIdle()) { - return tree.DRAG_OVER_REJECT; - } - - if (!(data instanceof treednd.ElementsDragAndDropData)) { - return tree.DRAG_OVER_REJECT; - } - - var elements: any[] = data.getData(); - var element = elements[0]; - - if (element instanceof gitmodel.StatusGroup) { - var statusGroup = element; - return this.onDrag(targetElement, statusGroup.getType()); - - } else if (element instanceof gitmodel.FileStatus) { - var status = element; - return this.onDrag(targetElement, status.getType()); - - } else { - return tree.DRAG_OVER_REJECT; - } - } - - private onDrag(targetElement: any, type: git.StatusType): tree.IDragOverReaction { - if (type === git.StatusType.WORKING_TREE) { - return this.onDragWorkingTree(targetElement); - } else if (type === git.StatusType.INDEX) { - return this.onDragIndex(targetElement); - } else if (type === git.StatusType.MERGE) { - return this.onDragMerge(targetElement); - } else { - return tree.DRAG_OVER_REJECT; - } - } - - private onDragWorkingTree(targetElement: any): tree.IDragOverReaction { - if (targetElement instanceof gitmodel.StatusGroup) { - var targetStatusGroup = targetElement; - return targetStatusGroup.getType() === git.StatusType.INDEX ? tree.DRAG_OVER_ACCEPT_BUBBLE_DOWN(false) : tree.DRAG_OVER_REJECT; - } else if (targetElement instanceof gitmodel.FileStatus) { - var targetStatus = targetElement; - return targetStatus.getType() === git.StatusType.INDEX ? tree.DRAG_OVER_ACCEPT_BUBBLE_UP : tree.DRAG_OVER_REJECT; - } else { - return tree.DRAG_OVER_REJECT; - } - } - - private onDragIndex(targetElement: any): tree.IDragOverReaction { - if (targetElement instanceof gitmodel.StatusGroup) { - var targetStatusGroup = targetElement; - return targetStatusGroup.getType() === git.StatusType.WORKING_TREE ? tree.DRAG_OVER_ACCEPT_BUBBLE_DOWN(false) : tree.DRAG_OVER_REJECT; - } else if (targetElement instanceof gitmodel.FileStatus) { - var targetStatus = targetElement; - return targetStatus.getType() === git.StatusType.WORKING_TREE ? tree.DRAG_OVER_ACCEPT_BUBBLE_UP : tree.DRAG_OVER_REJECT; - } else { - return tree.DRAG_OVER_REJECT; - } - } - - private onDragMerge(targetElement: any): tree.IDragOverReaction { - if (targetElement instanceof gitmodel.StatusGroup) { - var targetStatusGroup = targetElement; - return targetStatusGroup.getType() === git.StatusType.INDEX ? tree.DRAG_OVER_ACCEPT_BUBBLE_DOWN(false) : tree.DRAG_OVER_REJECT; - } else if (targetElement instanceof gitmodel.FileStatus) { - var targetStatus = targetElement; - return targetStatus.getType() === git.StatusType.INDEX ? tree.DRAG_OVER_ACCEPT_BUBBLE_UP : tree.DRAG_OVER_REJECT; - } else { - return tree.DRAG_OVER_REJECT; - } - } - - public drop(tree: tree.ITree, data: tree.IDragAndDropData, targetElement: any, originalEvent: mouse.DragMouseEvent): void { - var elements: any[] = data.getData(); - var element = elements[0]; - var files: git.IFileStatus[]; - - if (element instanceof gitmodel.StatusGroup) { - files = (element).all(); - // } else if (element instanceof gitmodel.FileStatus) { - // files = [ element ]; - } else { - files = elements; - // throw new Error('Invalid drag and drop data.'); - } - - var targetGroup = targetElement; - - // Add files to index - if (targetGroup.getType() === git.StatusType.INDEX) { - this.getAction(gitactions.StageAction).run(files).done(null, (e: Error) => this.onError(e)); - } - - // Remove files from index - if (targetGroup.getType() === git.StatusType.WORKING_TREE) { - this.getAction(gitactions.UnstageAction).run(files).done(null, (e: Error) => this.onError(e)); - } - } - - private onError(error: any): void { - this.messageService.show(severity.Error, error); - } -} - -export class AccessibilityProvider implements tree.IAccessibilityProvider { - - public getAriaLabel(tree: tree.ITree, element: any): string { - if (element instanceof gitmodel.FileStatus) { - const fileStatus = element; - const status = fileStatus.getStatus(); - const path = fileStatus.getPath(); - const lastSlashIndex = path.lastIndexOf('/'); - const name = lastSlashIndex === -1 ? path : path.substr(lastSlashIndex + 1, path.length); - const folder = (lastSlashIndex === -1 ? '' : path.substr(0, lastSlashIndex)); - - return nls.localize('fileStatusAriaLabel', "File {0} in folder {1} has status: {2}, Git", name, folder, Renderer.statusToTitle(status)); - } - - if (element instanceof gitmodel.StatusGroup) { - switch ((element).getType()) { - case git.StatusType.INDEX: return nls.localize('ariaLabelStagedChanges', "Staged Changes, Git"); - case git.StatusType.WORKING_TREE: return nls.localize('ariaLabelChanges', "Changes, Git"); - case git.StatusType.MERGE: return nls.localize('ariaLabelMerge', "Merge, Git"); - } - } - return undefined; - } -} - -export class Controller extends treedefaults.DefaultController { - - private contextMenuService: IContextMenuService; - private actionProvider: tree.IActionProvider; - - constructor(actionProvider: tree.IActionProvider, @IContextMenuService contextMenuService: IContextMenuService) { - super({ clickBehavior: treedefaults.ClickBehavior.ON_MOUSE_UP }); - - this.actionProvider = actionProvider; - this.contextMenuService = contextMenuService; - - this.downKeyBindingDispatcher.set(KeyMod.Shift | KeyCode.UpArrow, this.onUp.bind(this)); - this.downKeyBindingDispatcher.set(KeyMod.Shift | KeyCode.DownArrow, this.onDown.bind(this)); - this.downKeyBindingDispatcher.set(KeyMod.Shift | KeyCode.PageUp, this.onPageUp.bind(this)); - this.downKeyBindingDispatcher.set(KeyMod.Shift | KeyCode.PageDown, this.onPageDown.bind(this)); - } - - protected onLeftClick(tree: tree.ITree, element: any, event: mouse.IMouseEvent): boolean { - // Status group should never get selected nor expanded/collapsed - if (element instanceof gitmodel.StatusGroup) { - event.preventDefault(); - event.stopPropagation(); - - return true; - } - - if (event.shiftKey) { - var focus = tree.getFocus(); - - if (!(focus instanceof gitmodel.FileStatus) || !(element instanceof gitmodel.FileStatus)) { - return undefined; - } - - var focusStatus = focus; - var elementStatus = element; - - if (focusStatus.getType() !== elementStatus.getType()) { - return undefined; - } - - if (this.canSelect(tree, element)) { - tree.setFocus(element); - if (tree.isSelected(element)) { - tree.deselectRange(focusStatus, elementStatus); - } else { - tree.selectRange(focusStatus, elementStatus); - } - } - - return undefined; - } - - tree.setFocus(element); - - if (platform.isMacintosh ? event.metaKey : event.ctrlKey) { - if (this.canSelect(tree, element)) { - tree.toggleSelection(element, { origin: 'mouse', originalEvent: event }); - } - - return undefined; - } - - return super.onLeftClick(tree, element, event); - } - - protected onEnter(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var element = tree.getFocus(); - - // Status group should never get selected nor expanded/collapsed - if (element instanceof gitmodel.StatusGroup) { - event.preventDefault(); - event.stopPropagation(); - - return true; - } - - return super.onEnter(tree, event); - } - - protected onSpace(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var focus = tree.getFocus(); - - if (!focus) { - event.preventDefault(); - event.stopPropagation(); - return true; - } - - if (!this.canSelect(tree, focus)) { - return false; - } - - tree.toggleSelection(focus, { origin: 'keyboard', originalEvent: event }); - event.preventDefault(); - event.stopPropagation(); - return true; - } - - public onContextMenu(tree: tree.ITree, element: any, event: tree.ContextMenuEvent): boolean { - if (event.target && event.target.tagName && event.target.tagName.toLowerCase() === 'input') { - return false; - } - - event.preventDefault(); - event.stopPropagation(); - - tree.setFocus(element); - - if (this.actionProvider.hasSecondaryActions(tree, element)) { - var anchor = { x: event.posx + 1, y: event.posy }; - var context = { - selection: tree.getSelection(), - focus: element - }; - - this.contextMenuService.showContextMenu({ - getAnchor: () => anchor, - getActions: () => this.actionProvider.getSecondaryActions(tree, element), - getActionItem: this.actionProvider.getActionItem.bind(this.actionProvider, tree, element), - getActionsContext: () => context, - onHide: (wasCancelled?: boolean) => { - if (wasCancelled) { - tree.DOMFocus(); - } - } - }); - - return true; - } - - return false; - } - - protected onLeft(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - return true; - } - - protected onRight(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - return true; - } - - protected onUp(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var oldFocus = tree.getFocus(); - var base = super.onUp(tree, event); - - if (!base || !event.shiftKey) { - return false; - } - - return this.shiftSelect(tree, oldFocus, event); - } - - protected onPageUp(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var oldFocus = tree.getFocus(); - var base = super.onPageUp(tree, event); - - if (!base || !event.shiftKey) { - return false; - } - - return this.shiftSelect(tree, oldFocus, event); - } - - protected onDown(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var oldFocus = tree.getFocus(); - var base = super.onDown(tree, event); - - if (!base || !event.shiftKey) { - return false; - } - - return this.shiftSelect(tree, oldFocus, event); - } - - protected onPageDown(tree: tree.ITree, event: keyboard.IKeyboardEvent): boolean { - var oldFocus = tree.getFocus(); - var base = super.onPageDown(tree, event); - - if (!base || !event.shiftKey) { - return false; - } - - return this.shiftSelect(tree, oldFocus, event); - } - - private canSelect(tree: tree.ITree, ...elements: any[]): boolean { - if (elements.some(e => e instanceof gitmodel.StatusGroup || e instanceof gitmodel.StatusModel)) { - return false; - } - - return elements.every(e => { - var first = tree.getSelection()[0]; - var clicked = e; - return !first || (first.getType() === clicked.getType()); - }); - } - - private shiftSelect(tree: tree.ITree, oldFocus: any, event: keyboard.IKeyboardEvent): boolean { - var payload = { origin: 'keyboard', originalEvent: event }; - var focus = tree.getFocus(); - - if (focus === oldFocus) { - return false; - } - - var oldFocusIsSelected = tree.isSelected(oldFocus); - var focusIsSelected = tree.isSelected(focus); - - if (oldFocusIsSelected && focusIsSelected) { - tree.deselectRange(focus, oldFocus, payload); - } else if (!oldFocusIsSelected && !focusIsSelected) { - if (this.canSelect(tree, oldFocus, focus)) { - tree.selectRange(focus, oldFocus, payload); - } - } else if (oldFocusIsSelected) { - if (this.canSelect(tree, focus)) { - tree.selectRange(focus, oldFocus, payload); - } - } else { - tree.deselectRange(focus, oldFocus, payload); - } - - return true; - } -} diff --git a/src/vs/workbench/parts/git/browser/views/disabled/disabledView.css b/src/vs/workbench/parts/git/browser/views/disabled/disabledView.css deleted file mode 100644 index f5e5b1994a5..00000000000 --- a/src/vs/workbench/parts/git/browser/views/disabled/disabledView.css +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.git-viewlet > .disabled-view { - padding: 0 20px 0 20px; -} diff --git a/src/vs/workbench/parts/git/browser/views/disabled/disabledView.ts b/src/vs/workbench/parts/git/browser/views/disabled/disabledView.ts deleted file mode 100644 index 43351e73218..00000000000 --- a/src/vs/workbench/parts/git/browser/views/disabled/disabledView.ts +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./disabledView'; -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'); - -var $ = builder.$; - -export class DisabledView - extends ee.EventEmitter - implements view.IView { - public ID = 'disabled'; - private _element: HTMLElement; - - public get element(): HTMLElement { - if (!this._element) { - this.render(); - } - - return this._element; - } - - private render(): void { - this._element = $([ - '
', - '

', nls.localize('disabled', "Git is disabled in the settings."), '

', - '
' - ].join('')).getHTMLElement(); - } - - public focus(): void { - return; - } - - public layout(dimension: builder.Dimension): void { - return; - } - - public setVisible(visible: boolean): winjs.TPromise { - return winjs.TPromise.as(null); - } - - public getControl(): ee.IEventEmitter { - return null; - } - - public getActions(): actions.IAction[] { - return []; - } - - public getSecondaryActions(): actions.IAction[] { - return []; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/empty/emptyView.css b/src/vs/workbench/parts/git/browser/views/empty/emptyView.css deleted file mode 100644 index e7b57f201fd..00000000000 --- a/src/vs/workbench/parts/git/browser/views/empty/emptyView.css +++ /dev/null @@ -1,30 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.git-viewlet > .empty-view { - padding: 0 20px 0 20px; -} - -.git-viewlet > .empty-view > .section:not(:empty) { - margin: 20px 0; - padding-top: 20px; - border-top: 1px solid rgba(0, 0, 0, 0.05); -} - -.git-viewlet > .empty-view > .section > p:first-child { - margin-top: 0; -} - -.git-viewlet > .empty-view .monaco-inputbox { - width: 100%; - margin-bottom: 10px; -} - -.git-viewlet > .empty-view .combo-box { - width: 100%; - min-width: inherit; - padding: 4px 4px 4px 0; - margin-bottom: 10px; -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts b/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts deleted file mode 100644 index 730837e4a38..00000000000 --- a/src/vs/workbench/parts/git/browser/views/empty/emptyView.ts +++ /dev/null @@ -1,174 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./emptyView'; -import nls = require('vs/nls'); -import Lifecycle = require('vs/base/common/lifecycle'); -import EventEmitter = require('vs/base/common/eventEmitter'); -import DOM = require('vs/base/browser/dom'); -import { Button } from 'vs/base/browser/ui/button/button'; -import WinJS = require('vs/base/common/winjs.base'); -import Builder = require('vs/base/browser/builder'); -import Actions = require('vs/base/common/actions'); -import InputBox = require('vs/base/browser/ui/inputbox/inputBox'); -import GitView = require('vs/workbench/parts/git/browser/views/view'); -import GitActions = require('vs/workbench/parts/git/browser/gitActions'); -import { IFileService } from 'vs/platform/files/common/files'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IGitService } from 'vs/workbench/parts/git/common/git'; -import { attachButtonStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; - -var $ = Builder.$; - -export class EmptyView extends EventEmitter.EventEmitter implements GitView.IView { - - public ID = 'empty'; - - private static EMPTY_MESSAGE = nls.localize('noGit', "This workspace isn't yet under git source control."); - - private gitService: IGitService; - private instantiationService: IInstantiationService; - private messageService: IMessageService; - private fileService: IFileService; - - private actionRunner: Actions.IActionRunner; - private refreshAction: Actions.IAction; - private isVisible: boolean; - private needsRender: boolean; - private $el: Builder.Builder; - private urlInputBox: InputBox.InputBox; - private cloneButton: Button; - private initButton: Button; - private controller: GitView.IController; - private toDispose: Lifecycle.IDisposable[]; - - constructor(controller: GitView.IController, actionRunner: Actions.IActionRunner, - @IGitService gitService: IGitService, - @IInstantiationService instantiationService: IInstantiationService, - @IMessageService messageService: IMessageService, - @IFileService fileService: IFileService, - @IThemeService private themeService: IThemeService - ) { - super(); - - this.gitService = gitService; - this.instantiationService = instantiationService; - this.messageService = messageService; - this.fileService = fileService; - - this.actionRunner = actionRunner; - this.isVisible = false; - this.needsRender = false; - this.controller = controller; - this.toDispose = []; - } - - // Properties - - private _initAction: GitActions.InitAction; - private get initAction(): GitActions.InitAction { - if (!this._initAction) { - this._initAction = this.instantiationService.createInstance(GitActions.InitAction); - } - - return this._initAction; - } - - // IView - - public get element(): HTMLElement { - this.render(); - return this.$el.getHTMLElement(); - } - - private render(): void { - if (this.$el) { - return; - } - - this.$el = $('.empty-view'); - - $('p').appendTo(this.$el).text(EmptyView.EMPTY_MESSAGE); - - var initSection = $('.section').appendTo(this.$el); - this.initButton = new Button(initSection); - attachButtonStyler(this.initButton, this.themeService); - this.initButton.label = nls.localize('gitinit', 'Initialize Git Repository'); - this.initButton.addListener('click', (e) => { - DOM.EventHelper.stop(e); - - this.disableUI(); - this.actionRunner.run(this.initAction).done(() => this.enableUI()); - }); - } - - private disableUI(): void { - if (this.urlInputBox) { - this.urlInputBox.disable(); - } - - if (this.cloneButton) { - this.cloneButton.enabled = false; - } - - this.initButton.enabled = false; - } - - private enableUI(): void { - if (this.gitService.getRunningOperations().length > 0) { - return; - } - - if (this.urlInputBox) { - this.urlInputBox.enable(); - this.urlInputBox.validate(); - } - - this.initButton.enabled = true; - } - - public focus(): void { - this.initButton.focus(); - } - - public layout(dimension: Builder.Dimension): void { - // no-op - } - - public setVisible(visible: boolean): WinJS.TPromise { - this.isVisible = visible; - - return WinJS.TPromise.as(null); - } - - public getControl(): EventEmitter.IEventEmitter { - return null; - } - - public getActions(): Actions.IAction[] { - return this.refreshAction ? [this.refreshAction] : []; - } - - public getSecondaryActions(): Actions.IAction[] { - return []; - } - - // Events - - public dispose(): void { - if (this.$el) { - this.$el.dispose(); - this.$el = null; - } - - this.toDispose = Lifecycle.dispose(this.toDispose); - - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.css b/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.css deleted file mode 100644 index a06817221da..00000000000 --- a/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.css +++ /dev/null @@ -1,23 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.git-viewlet > .gitless-view { - padding: 0 20px 0 20px; -} - -.git-viewlet > .gitless-view > p { - line-height: 1.5em; -} - -.git-viewlet > .gitless-view .code { - display: inline; -} - -.git-viewlet > .gitless-view a -{ - color: inherit; - font-weight: bold; - text-decoration: underline; -} diff --git a/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.ts b/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.ts deleted file mode 100644 index e615cf87e76..00000000000 --- a/src/vs/workbench/parts/git/browser/views/gitless/gitlessView.ts +++ /dev/null @@ -1,98 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./gitlessView'; -import nls = require('vs/nls'); -import platform = require('vs/base/common/platform'); -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'); - -var $ = builder.$; - -export class GitlessView - extends ee.EventEmitter - implements view.IView { - public ID = 'gitless'; - private _element: HTMLElement; - - constructor() { - super(); - } - - public get element(): HTMLElement { - if (!this._element) { - this.render(); - } - - return this._element; - } - - private render(): void { - var instructions: string; - - if (platform.isMacintosh) { - instructions = nls.localize('macInstallWith', - "You can either install it with {0}, download it from {1} or install the {2} command line developer tools, by simply typing {3} on a Terminal prompt.", - 'Homebrew', - 'git-scm.com', - 'XCode', - 'git' - ); - } else if (platform.isWindows) { - instructions = nls.localize('winInstallWith', - "You can either install it with {0} or download it from {1}.", - 'Chocolatey', - 'git-scm.com' - ); - } else if (platform.isLinux) { - instructions = nls.localize('linuxDownloadFrom', - "You can download it from {0}.", - 'git-scm.com' - ); - } else { - instructions = nls.localize('downloadFrom', - "You can download it from {0}.", - 'git-scm.com' - ); - } - - this._element = $([ - '
', - '

', nls.localize('looksLike', "It looks like git is not installed on your system."), '

', - '

', instructions, '

', - '

', nls.localize('pleaseRestart', "Once git is installed, please restart VSCode."), '

', - '
' - ].join('')).getHTMLElement(); - } - - public focus(): void { - return; - } - - public layout(dimension: builder.Dimension): void { - return; - } - - public setVisible(visible: boolean): winjs.TPromise { - return winjs.TPromise.as(null); - } - - public getControl(): ee.IEventEmitter { - return null; - } - - public getActions(): actions.IAction[] { - return []; - } - - public getSecondaryActions(): actions.IAction[] { - return []; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/huge/hugeView.css b/src/vs/workbench/parts/git/browser/views/huge/hugeView.css deleted file mode 100644 index a428d2328c0..00000000000 --- a/src/vs/workbench/parts/git/browser/views/huge/hugeView.css +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 deleted file mode 100644 index 7e6173e8422..00000000000 --- a/src/vs/workbench/parts/git/browser/views/huge/hugeView.ts +++ /dev/null @@ -1,86 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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'; -import { attachButtonStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; - -const $ = dom.$; - -export class HugeView extends ee.EventEmitter implements view.IView { - - ID = 'huge'; - private _element: HTMLElement; - - constructor( @IGitService private gitService: IGitService, @IThemeService private themeService: IThemeService) { - 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); - attachButtonStyler(button, this.themeService); - button.label = nls.localize('allo', "Allow large repositories"); - button.addListener('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/browser/views/notroot/notrootView.css b/src/vs/workbench/parts/git/browser/views/notroot/notrootView.css deleted file mode 100644 index 85665d2e346..00000000000 --- a/src/vs/workbench/parts/git/browser/views/notroot/notrootView.css +++ /dev/null @@ -1,23 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.git-viewlet > .notroot-view { - padding: 0 20px 0 20px; -} - -.git-viewlet > .notroot-view > p { - line-height: 1.5em; -} - -.git-viewlet > .notroot-view .code { - display: inline; -} - -.git-viewlet > .notroot-view a -{ - color: inherit; - font-weight: bold; - text-decoration: underline; -} diff --git a/src/vs/workbench/parts/git/browser/views/notroot/notrootView.ts b/src/vs/workbench/parts/git/browser/views/notroot/notrootView.ts deleted file mode 100644 index 2e9263bcb8d..00000000000 --- a/src/vs/workbench/parts/git/browser/views/notroot/notrootView.ts +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./notrootView'; -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'); -const $ = builder.$; - -export class NotRootView - extends ee.EventEmitter - implements view.IView { - public ID = 'notroot'; - private _element: HTMLElement; - - public get element(): HTMLElement { - if (!this._element) { - this.render(); - } - - return this._element; - } - - private render(): void { - this._element = $([ - '
', - '

', nls.localize('wrongRoot', "This directory seems to be contained in a git repository."), '

', - '

', nls.localize('pleaseRestart', "Open the repository's root directory in order to access Git features."), '

', - '
' - ].join('')).getHTMLElement(); - } - - public focus(): void { - return; - } - - public layout(dimension: builder.Dimension): void { - return; - } - - public setVisible(visible: boolean): winjs.TPromise { - return winjs.TPromise.as(null); - } - - public getControl(): ee.IEventEmitter { - return null; - } - - public getActions(): actions.IAction[] { - return []; - } - - public getSecondaryActions(): actions.IAction[] { - return []; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.css b/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.css deleted file mode 100644 index c9e3e1780c0..00000000000 --- a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.css +++ /dev/null @@ -1,12 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -.git-viewlet > .noworkspace-view { - padding: 0 20px 0 20px; -} - -.git-viewlet > .noworkspace-view > p { - line-height: 1.5em; -} diff --git a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts b/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts deleted file mode 100644 index a75f8f249c6..00000000000 --- a/src/vs/workbench/parts/git/browser/views/noworkspace/noworkspaceView.ts +++ /dev/null @@ -1,95 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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!./noworkspaceView'; -import nls = require('vs/nls'); -import * as errors from 'vs/base/common/errors'; -import winjs = require('vs/base/common/winjs.base'); -import ee = require('vs/base/common/eventEmitter'); -import env = require('vs/base/common/platform'); -import view = require('vs/workbench/parts/git/browser/views/view'); -import builder = require('vs/base/browser/builder'); -import { Button } from 'vs/base/browser/ui/button/button'; -import { IActionRunner, IAction } from 'vs/base/common/actions'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { OpenFolderAction, OpenFileFolderAction } from 'vs/workbench/browser/actions/fileActions'; -import { attachButtonStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -const $ = builder.$; - -export class NoWorkspaceView - extends ee.EventEmitter - implements view.IView { - public ID = 'noworkspace'; - private _element: HTMLElement; - private _openFolderButton: Button; - - constructor( - private actionRunner: IActionRunner, - @IInstantiationService private instantiationService: IInstantiationService, - @IThemeService private themeService: IThemeService - ) { - super(); - } - - public get element(): HTMLElement { - if (!this._element) { - this.render(); - } - - return this._element; - } - - private render(): void { - this._element = $([ - '
', - '

', nls.localize('noWorkspaceHelp', "You have not yet opened a folder."), '

', - '

', nls.localize('pleaseRestart', "Open a folder with a Git repository in order to access Git features."), '

', - '
' - ].join('')).getHTMLElement(); - - this._openFolderButton = new Button(this._element); - attachButtonStyler(this._openFolderButton, this.themeService); - this._openFolderButton.label = nls.localize('openFolder', "Open Folder"); - this._openFolderButton.addListener('click', () => { - const actionClass = env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; - const action = this.instantiationService.createInstance(actionClass, actionClass.ID, actionClass.LABEL); - this.actionRunner.run(action).done(() => { - action.dispose(); - }, err => { - action.dispose(); - errors.onUnexpectedError(err); - }); - }); - } - - public focus(): void { - if (this._openFolderButton) { - this._openFolderButton.getElement().focus(); - } - } - - public layout(dimension: builder.Dimension): void { - return; - } - - public setVisible(visible: boolean): winjs.TPromise { - return winjs.TPromise.as(null); - } - - public getControl(): ee.IEventEmitter { - return null; - } - - public getActions(): IAction[] { - return []; - } - - public getSecondaryActions(): IAction[] { - return []; - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/browser/views/view.ts b/src/vs/workbench/parts/git/browser/views/view.ts deleted file mode 100644 index fc0c209607a..00000000000 --- a/src/vs/workbench/parts/git/browser/views/view.ts +++ /dev/null @@ -1,24 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import Lifecycle = require('vs/base/common/lifecycle'); -import WinJS = require('vs/base/common/winjs.base'); -import EventEmitter = require('vs/base/common/eventEmitter'); -import Builder = require('vs/base/browser/builder'); -import Actions = require('vs/base/common/actions'); - -export interface IView extends Lifecycle.IDisposable { - ID: string; - element: HTMLElement; - focus(): void; - layout(dimension: Builder.Dimension): void; - setVisible(visible: boolean): WinJS.Promise; - getControl(): EventEmitter.IEventEmitter; - getActions(): Actions.IAction[]; - getSecondaryActions(): Actions.IAction[]; -} - -export interface IController { - setView(id: string): WinJS.Promise; -} diff --git a/src/vs/workbench/parts/git/common/git.ts b/src/vs/workbench/parts/git/common/git.ts deleted file mode 100644 index 1c5ddfd4875..00000000000 --- a/src/vs/workbench/parts/git/common/git.ts +++ /dev/null @@ -1,342 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { TPromise } from 'vs/base/common/winjs.base'; -import { EditorInput } from 'vs/workbench/common/editor'; -import { IEventEmitter } from 'vs/base/common/eventEmitter'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; -import Event from 'vs/base/common/event'; - -// Model raw interfaces - -export interface IRawFileStatus { - x: string; - y: string; - path: string; - mimetype: string; - rename?: string; -} - -export interface IRemote { - name: string; - url: string; -} - -export enum RefType { - Head, - RemoteHead, - Tag -} - -export interface IRef { - name: string; - commit: string; - type: RefType; - remote?: string; -} - -export interface IBranch extends IRef { - upstream?: string; - ahead?: number; - behind?: number; -} - -export interface IRawStatus { - repositoryRoot: string; - state?: ServiceState; - status: IRawFileStatus[]; - HEAD: IBranch; - refs: IRef[]; - remotes: IRemote[]; -} - -export interface ICommit { - hash: string; - message: string; -} - -// Model enums - -export enum StatusType { - INDEX, - WORKING_TREE, - MERGE -} - -export enum Status { - INDEX_MODIFIED, - INDEX_ADDED, - INDEX_DELETED, - INDEX_RENAMED, - INDEX_COPIED, - - MODIFIED, - DELETED, - UNTRACKED, - IGNORED, - - ADDED_BY_US, - ADDED_BY_THEM, - DELETED_BY_US, - DELETED_BY_THEM, - BOTH_ADDED, - BOTH_DELETED, - BOTH_MODIFIED -} - -// Model events - -export const ModelEvents = { - MODEL_UPDATED: 'ModelUpdated', - STATUS_MODEL_UPDATED: 'StatusModelUpdated', - HEAD_UPDATED: 'HEADUpdated', - REFS_UPDATED: 'RefsUpdated', - REMOTES_UPDATED: 'RemotesUpdated' -}; - -// Model interfaces - -export interface IFileStatus { - getId(): string; - getType(): StatusType; - getPath(): string; - getPathComponents(): string[]; - getMimetype(): string; - getStatus(): Status; - getRename(): string; - clone(): IFileStatus; - update(other: IFileStatus): void; -} - -export interface IStatusGroup extends IEventEmitter { - getType(): StatusType; - update(statusList: IFileStatus[]): void; - all(): IFileStatus[]; - find(path: string): IFileStatus; -} - -export interface IStatusSummary { - hasWorkingTreeChanges: boolean; - hasIndexChanges: boolean; - hasMergeChanges: boolean; -} - -export interface IStatusModel extends IEventEmitter { - getSummary(): IStatusSummary; - update(status: IRawFileStatus[]): void; - getIndexStatus(): IStatusGroup; - getWorkingTreeStatus(): IStatusGroup; - getMergeStatus(): IStatusGroup; - getGroups(): IStatusGroup[]; - find(path: string, type: StatusType): IFileStatus; -} - -export interface IModel extends IEventEmitter { - getRepositoryRoot(): string; - getStatus(): IStatusModel; - getHEAD(): IBranch; - getRefs(): IRef[]; - getRemotes(): IRemote[]; - update(status: IRawStatus): void; - getPS1(): string; -} - -// Service operations - -export interface IGitOperation extends IDisposable { - id: string; - run(): TPromise; -} - -// Service enums - -export enum ServiceState { - NotInitialized, - NotARepo, - NotAtRepoRoot, - OK, - Huge, - NoGit, - Disabled, - NotAWorkspace -} - -export enum RawServiceState { - OK, - GitNotFound, - Disabled -} - -export const GitErrorCodes = { - BadConfigFile: 'BadConfigFile', - AuthenticationFailed: 'AuthenticationFailed', - NoUserNameConfigured: 'NoUserNameConfigured', - NoUserEmailConfigured: 'NoUserEmailConfigured', - NoRemoteRepositorySpecified: 'NoRemoteRepositorySpecified', - NotAGitRepository: 'NotAGitRepository', - NotAtRepositoryRoot: 'NotAtRepositoryRoot', - Conflict: 'Conflict', - UnmergedChanges: 'UnmergedChanges', - PushRejected: 'PushRejected', - RemoteConnectionError: 'RemoteConnectionError', - DirtyWorkTree: 'DirtyWorkTree', - CantOpenResource: 'CantOpenResource', - GitNotFound: 'GitNotFound', - CantCreatePipe: 'CantCreatePipe', - CantAccessRemote: 'CantAccessRemote', - RepositoryNotFound: 'RepositoryNotFound' -}; - -export enum AutoFetcherState { - Disabled, - Inactive, - Active, - Fetching -} - -// Service events - -export const ServiceEvents = { - STATE_CHANGED: 'stateChanged', - REPO_CHANGED: 'repoChanged', - OPERATION_START: 'operationStart', - OPERATION_END: 'operationEnd', - OPERATION: 'operation', - ERROR: 'error', - DISPOSE: 'dispose' -}; - -// Service operations - -export const ServiceOperations = { - STATUS: 'status', - INIT: 'init', - ADD: 'add', - STAGE: 'stage', - BRANCH: 'branch', - CHECKOUT: 'checkout', - CLEAN: 'clean', - UNDO: 'undo', - RESET: 'reset', - REVERT: 'revert', - COMMIT: 'commit', - COMMAND: 'command', - BACKGROUND_FETCH: 'backgroundfetch', - PULL: 'pull', - PUSH: 'push', - SYNC: 'sync' -}; - -// Service config - -export interface IGitConfiguration { - enabled: boolean; - path: string; - autorefresh: boolean; - autofetch: boolean; - enableLongCommitWarning: boolean; - allowLargeRepositories: boolean; - confirmSync: boolean; - countBadge: string; - checkoutType: string; -} - -// Service interfaces - -export interface IAutoFetcher { - state: AutoFetcherState; - activate(): void; - deactivate(): void; -} - -export interface IGitCredentialScope { - protocol: string; - host: string; - path: string; -} - -export interface ICredentials { - username: string; - password: string; -} - -export interface IGitServiceError extends Error { - gitErrorCode: string; -} - -export interface IPushOptions { - setUpstream?: boolean; -} - -export interface IRawGitService { - onOutput: Event; - getVersion(): TPromise; - serviceState(): TPromise; - statusCount(): TPromise; - status(): TPromise; - init(): TPromise; - add(filesPaths?: string[]): TPromise; - stage(filePath: string, content: string): TPromise; - branch(name: string, checkout?: boolean): TPromise; - checkout(treeish?: string, filePaths?: string[]): TPromise; - clean(filePaths: string[]): TPromise; - undo(): TPromise; - reset(treeish: string, hard?: boolean): TPromise; - revertFiles(treeish: string, filePaths?: string[]): TPromise; - fetch(): TPromise; - pull(rebase?: boolean): TPromise; - push(remote?: string, name?: string, options?: IPushOptions): TPromise; - sync(): TPromise; - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise; - detectMimetypes(path: string, treeish?: string): TPromise; - show(path: string, treeish?: string): TPromise; - clone(url: string, parentPath: string): TPromise; - getCommitTemplate(): TPromise; - getCommit(ref: string): TPromise; -} - -export const GIT_SERVICE_ID = 'gitService'; - -export const IGitService = createDecorator(GIT_SERVICE_ID); - -export interface IGitService extends IEventEmitter { - _serviceBrand: any; - allowHugeRepositories: boolean; - onOutput: Event; - status(): TPromise; - init(): TPromise; - add(files?: IFileStatus[]): TPromise; - stage(filePath: string, content: string): TPromise; - branch(name: string, checkout?: boolean): TPromise; - checkout(treeish?: string, files?: IFileStatus[]): TPromise; - clean(files: IFileStatus[]): TPromise; - undo(): TPromise; - reset(treeish: string, hard?: boolean): TPromise; - revertFiles(treeish: string, files?: IFileStatus[]): TPromise; - fetch(): TPromise; - pull(rebase?: boolean): TPromise; - push(remote?: string, name?: string, options?: IPushOptions): TPromise; - sync(): TPromise; - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise; - detectMimetypes(path: string, treeish?: string): TPromise; - buffer(path: string, treeish?: string): TPromise; - clone(url: string, parentPath: string): TPromise; - - getState(): ServiceState; - getModel(): IModel; - getInput(status: IFileStatus): TPromise; - isInitialized(): boolean; - isIdle(): boolean; - getRunningOperations(): IGitOperation[]; - getAutoFetcher(): IAutoFetcher; - getCommitTemplate(): TPromise; - getCommit(ref: string): TPromise; -} - -export interface IAskpassService { - askpass(id: string, host: string, command: string): TPromise; -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/common/gitIpc.ts b/src/vs/workbench/parts/git/common/gitIpc.ts deleted file mode 100644 index 6f52b28e5dd..00000000000 --- a/src/vs/workbench/parts/git/common/gitIpc.ts +++ /dev/null @@ -1,267 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { TPromise } from 'vs/base/common/winjs.base'; -import { IChannel, eventToCall, eventFromCall } from 'vs/base/parts/ipc/common/ipc'; -import Event from 'vs/base/common/event'; -import { - IRawGitService, RawServiceState, IRawStatus, IPushOptions, IAskpassService, ICredentials, - ServiceState, IRawFileStatus, IBranch, RefType, IRef, IRemote, ICommit -} from './git'; - -type ISerializer = { to(a: A): B; from(b: B): A; }; - -export type IPCRawFileStatus = [string, string, string, string, string]; -const RawFileStatusSerializer: ISerializer = { - to: a => [a.x, a.y, a.path, a.mimetype, a.rename], - from: b => ({ x: b[0], y: b[1], path: b[2], mimetype: b[3], rename: b[4] }) -}; - -export type IPCBranch = [string, string, RefType, string, string, number, number]; -const BranchSerializer: ISerializer = { - to: a => [a.name, a.commit, a.type, a.remote, a.upstream, a.ahead, a.behind], - from: b => ({ name: b[0], commit: b[1], type: b[2], remote: b[3], upstream: b[4], ahead: b[5], behind: b[6] }) -}; - -export type IPCRef = [string, string, RefType, string]; -const RefSerializer: ISerializer = { - to: a => [a.name, a.commit, a.type, a.remote], - from: b => ({ name: b[0], commit: b[1], type: b[2], remote: b[3] }) -}; - -export type IPCRemote = [string, string]; -const RemoteSerializer: ISerializer = { - to: a => [a.name, a.url], - from: b => ({ name: b[0], url: b[1] }) -}; - -export type IPCRawStatus = [ - string, - ServiceState, - IPCRawFileStatus[], - IPCBranch, - IPCRef[], - IPCRemote[] -]; - -const RawStatusSerializer: ISerializer = { - to: a => !a ? null : [ - a.repositoryRoot, - a.state, - a.status.map(RawFileStatusSerializer.to), - BranchSerializer.to(a.HEAD), - a.refs.map(RefSerializer.to), - a.remotes.map(RemoteSerializer.to) - ], - from: b => !b ? null : { - repositoryRoot: b[0], - state: b[1], - status: b[2].map(RawFileStatusSerializer.from), - HEAD: BranchSerializer.from(b[3]), - refs: b[4].map(RefSerializer.from), - remotes: b[5].map(RemoteSerializer.from) - } -}; - -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; - call(command: 'stage', args: [string, string]): TPromise; - call(command: 'branch', args: [string, boolean]): TPromise; - call(command: 'checkout', args: [string, string[]]): TPromise; - call(command: 'clean', filePaths: string[]): TPromise; - call(command: 'undo'): TPromise; - call(command: 'reset', args: [string, boolean]): TPromise; - call(command: 'revertFiles', args: [string, string[]]): TPromise; - call(command: 'fetch'): TPromise; - call(command: 'pull', rebase?: boolean): TPromise; - call(command: 'push', args: [string, string, IPushOptions]): TPromise; - call(command: 'sync'): TPromise; - call(command: 'commit', args: [string, boolean, boolean, boolean]): TPromise; - call(command: 'detectMimetypes', args: [string, string]): TPromise; - call(command: 'show', args: [string, string]): TPromise; - call(command: 'clone', args: [string, string]): TPromise; - call(command: 'onOutput'): TPromise; - call(command: 'getCommitTemplate'): TPromise; - call(command: 'getCommit', ref: string): TPromise; - call(command: string, args?: any): TPromise; -} - -export class GitChannel implements IGitChannel { - - constructor(private service: TPromise) { } - - call(command: string, args?: any): TPromise { - switch (command) { - case 'getVersion': return this.service.then(s => s.getVersion()); - case 'serviceState': return this.service.then(s => s.serviceState()); - case 'statusCount': return this.service.then(s => s.statusCount()); - case 'status': return this.service.then(s => s.status()).then(RawStatusSerializer.to); - case 'init': return this.service.then(s => s.init()).then(RawStatusSerializer.to); - case 'add': return this.service.then(s => s.add(args)).then(RawStatusSerializer.to); - case 'stage': return this.service.then(s => s.stage(args[0], args[1])).then(RawStatusSerializer.to); - case 'branch': return this.service.then(s => s.branch(args[0], args[1])).then(RawStatusSerializer.to); - case 'checkout': return this.service.then(s => s.checkout(args[0], args[1])).then(RawStatusSerializer.to); - case 'clean': return this.service.then(s => s.clean(args)).then(RawStatusSerializer.to); - case 'undo': return this.service.then(s => s.undo()).then(RawStatusSerializer.to); - case 'reset': return this.service.then(s => s.reset(args[0], args[1])).then(RawStatusSerializer.to); - case 'revertFiles': return this.service.then(s => s.revertFiles(args[0], args[1])).then(RawStatusSerializer.to); - case 'fetch': return this.service.then(s => s.fetch()).then(RawStatusSerializer.to); - case 'pull': return this.service.then(s => s.pull(args)).then(RawStatusSerializer.to); - case 'push': return this.service.then(s => s.push(args[0], args[1], args[2])).then(RawStatusSerializer.to); - case 'sync': return this.service.then(s => s.sync()).then(RawStatusSerializer.to); - case 'commit': return this.service.then(s => s.commit(args[0], args[1], args[2], args[3])).then(RawStatusSerializer.to); - case 'detectMimetypes': return this.service.then(s => s.detectMimetypes(args[0], args[1])); - case 'show': return this.service.then(s => s.show(args[0], args[1])); - case 'clone': return this.service.then(s => s.clone(args[0], args[1])); - case 'onOutput': return this.service.then(s => eventToCall(s.onOutput)); - case 'getCommitTemplate': return this.service.then(s => s.getCommitTemplate()); - case 'getCommit': return this.service.then(s => s.getCommit(args)); - } - return undefined; - } -} - -export class UnavailableGitChannel implements IGitChannel { - - call(command: string): TPromise { - switch (command) { - case 'serviceState': return TPromise.as(RawServiceState.GitNotFound); - default: return TPromise.as(null); - } - } -} - -export class GitChannelClient implements IRawGitService { - - constructor(private channel: IGitChannel) { } - - private _onOutput = eventFromCall(this.channel, 'onOutput'); - get onOutput(): Event { return this._onOutput; } - - getVersion(): TPromise { - return this.channel.call('getVersion'); - } - - serviceState(): TPromise { - return this.channel.call('serviceState'); - } - - statusCount(): TPromise { - return this.channel.call('statusCount'); - } - - status(): TPromise { - return this.channel.call('status').then(RawStatusSerializer.from); - } - - init(): TPromise { - return this.channel.call('init').then(RawStatusSerializer.from); - } - - add(filesPaths?: string[]): TPromise { - return this.channel.call('add', filesPaths).then(RawStatusSerializer.from); - } - - stage(filePath: string, content: string): TPromise { - return this.channel.call('stage', [filePath, content]).then(RawStatusSerializer.from); - } - - branch(name: string, checkout?: boolean): TPromise { - return this.channel.call('branch', [name, checkout]).then(RawStatusSerializer.from); - } - - checkout(treeish?: string, filePaths?: string[]): TPromise { - return this.channel.call('checkout', [treeish, filePaths]).then(RawStatusSerializer.from); - } - - clean(filePaths: string[]): TPromise { - return this.channel.call('clean', filePaths).then(RawStatusSerializer.from); - } - - undo(): TPromise { - return this.channel.call('undo').then(RawStatusSerializer.from); - } - - reset(treeish: string, hard?: boolean): TPromise { - return this.channel.call('reset', [treeish, hard]).then(RawStatusSerializer.from); - } - - revertFiles(treeish: string, filePaths?: string[]): TPromise { - return this.channel.call('revertFiles', [treeish, filePaths]).then(RawStatusSerializer.from); - } - - fetch(): TPromise { - return this.channel.call('fetch').then(RawStatusSerializer.from); - } - - pull(rebase?: boolean): TPromise { - return this.channel.call('pull', rebase).then(RawStatusSerializer.from); - } - - push(remote?: string, name?: string, options?: IPushOptions): TPromise { - return this.channel.call('push', [remote, name, options]).then(RawStatusSerializer.from); - } - - sync(): TPromise { - return this.channel.call('sync').then(RawStatusSerializer.from); - } - - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { - return this.channel.call('commit', [message, amend, stage, signoff]).then(RawStatusSerializer.from); - } - - detectMimetypes(path: string, treeish?: string): TPromise { - return this.channel.call('detectMimetypes', [path, treeish]); - } - - show(path: string, treeish?: string): TPromise { - return this.channel.call('show', [path, treeish]); - } - - clone(url: string, parentPath: string): TPromise { - return this.channel.call('clone', [url, parentPath]); - } - - getCommitTemplate(): TPromise { - return this.channel.call('getCommitTemplate'); - } - - getCommit(ref: string): TPromise { - return this.channel.call('getCommit', ref); - } -} - -export interface IAskpassChannel extends IChannel { - call(command: 'askpass', args: [string, string, string]): TPromise; - call(command: string, args: any[]): TPromise; -} - -export class AskpassChannel implements IAskpassChannel { - - constructor(private service: IAskpassService) { } - - call(command: string, args: [string, string, string]): TPromise { - switch (command) { - case 'askpass': return this.service.askpass(args[0], args[1], args[2]); - } - return undefined; - } -} - -export class AskpassChannelClient implements IAskpassService { - - constructor(private channel: IAskpassChannel) { } - - askpass(id: string, host: string, command: string): TPromise { - return this.channel.call('askpass', [id, host, command]); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/common/gitModel.ts b/src/vs/workbench/parts/git/common/gitModel.ts deleted file mode 100644 index 30baf2cf6d2..00000000000 --- a/src/vs/workbench/parts/git/common/gitModel.ts +++ /dev/null @@ -1,412 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { format } from 'vs/base/common/strings'; -import { EventEmitter } from 'vs/base/common/eventEmitter'; -import { - IStatusModel, IStatusSummary, IRawFileStatus, ModelEvents, - IFileStatus, IStatusGroup, Status, StatusType, - IBranch, IRef, IRemote, IModel, IRawStatus, RefType -} from 'vs/workbench/parts/git/common/git'; - -export class FileStatus implements IFileStatus { - - private id: string; - private pathComponents: string[]; - - constructor( - private path: string, - private mimetype: string, - private status: Status, - private rename?: string, - isModifiedInIndex?: boolean - ) { - this.id = FileStatus.typeOf(status) + ':' + path + (rename ? ':' + rename : '') + (isModifiedInIndex ? '$' : ''); - this.pathComponents = path.split('/'); - } - - getPath(): string { - return this.path; - } - - getPathComponents(): string[] { - return this.pathComponents.slice(0); - } - - getMimetype(): string { - return this.mimetype; - } - - getStatus(): Status { - return this.status; - } - - getRename(): string { - return this.rename; - } - - getId(): string { - return this.id; - } - - getType(): StatusType { - switch (FileStatus.typeOf(this.status)) { - case 'index': return StatusType.INDEX; - case 'workingTree': return StatusType.WORKING_TREE; - default: return StatusType.MERGE; - } - } - - clone(): IFileStatus { - return new FileStatus(this.path, this.mimetype, this.status, this.rename); - } - - update(other: FileStatus): void { - this.status = other.getStatus(); - this.rename = other.getRename(); - } - - static typeOf(s: Status): string { - switch (s) { - case Status.INDEX_MODIFIED: - case Status.INDEX_ADDED: - case Status.INDEX_DELETED: - case Status.INDEX_RENAMED: - case Status.INDEX_COPIED: - return 'index'; - - case Status.MODIFIED: - case Status.DELETED: - case Status.UNTRACKED: - case Status.IGNORED: - return 'workingTree'; - - default: - return 'merge'; - } - } -} - -interface IStatusSet { - [path: string]: IFileStatus; -} - -export class StatusGroup extends EventEmitter implements IStatusGroup { - - private type: StatusType; - private statusSet: IStatusSet; - private statusList: IFileStatus[]; - private statusByName: IStatusSet; - private statusByRename: IStatusSet; - - constructor(type: StatusType) { - super(); - - this.type = type; - this.statusSet = Object.create(null); - this.statusList = []; - this.statusByName = Object.create(null); - this.statusByRename = Object.create(null); - } - - getType(): StatusType { - return this.type; - } - - update(statusList: FileStatus[]): void { - const toDelete: IStatusSet = Object.create(null); - - let id: string, path: string, rename: string; - let status: IFileStatus; - - for (id in this.statusSet) { - toDelete[id] = this.statusSet[id]; - } - - for (let i = 0; i < statusList.length; i++) { - status = statusList[i]; - id = status.getId(); - path = status.getPath(); - rename = status.getRename(); - - if (toDelete[id]) { - this.statusSet[id].update(status); - toDelete[id] = null; - - } else { - this.statusSet[id] = status; - } - } - - for (id in toDelete) { - if (status = toDelete[id]) { - this.emit('fileStatus:dispose', status); - delete this.statusSet[id]; - } - } - - this.statusList = []; - this.statusByName = Object.create(null); - this.statusByRename = Object.create(null); - - for (id in this.statusSet) { - status = this.statusSet[id]; - this.statusList.push(status); - - if (status.getRename()) { - this.statusByRename[status.getPath()] = status; - } else { - this.statusByName[status.getPath()] = status; - } - } - } - - all(): IFileStatus[] { - return this.statusList; - } - - find(path: string): IFileStatus { - return this.statusByName[path] || this.statusByRename[path] || null; - } - - dispose(): void { - this.type = null; - this.statusSet = null; - this.statusList = null; - this.statusByName = null; - this.statusByRename = null; - - super.dispose(); - } -} - -export class StatusModel extends EventEmitter implements IStatusModel { - - private indexStatus: StatusGroup; - private workingTreeStatus: StatusGroup; - private mergeStatus: StatusGroup; - private toDispose: IDisposable[]; - - constructor() { - super(); - - this.indexStatus = new StatusGroup(StatusType.INDEX); - this.workingTreeStatus = new StatusGroup(StatusType.WORKING_TREE); - this.mergeStatus = new StatusGroup(StatusType.MERGE); - - this.toDispose = [ - this.addEmitter(this.indexStatus), - this.addEmitter(this.workingTreeStatus), - this.addEmitter(this.mergeStatus) - ]; - } - - getSummary(): IStatusSummary { - return { - hasWorkingTreeChanges: this.getWorkingTreeStatus().all().length > 0, - hasIndexChanges: this.getIndexStatus().all().length > 0, - hasMergeChanges: this.getMergeStatus().all().length > 0 - }; - } - - update(status: IRawFileStatus[]): void { - const index: FileStatus[] = []; - const workingTree: FileStatus[] = []; - const merge: FileStatus[] = []; - - status.forEach(raw => { - switch (raw.x + raw.y) { - case '??': return workingTree.push(new FileStatus(raw.path, raw.mimetype, Status.UNTRACKED)); - case '!!': return workingTree.push(new FileStatus(raw.path, raw.mimetype, Status.IGNORED)); - case 'DD': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.BOTH_DELETED)); - case 'AU': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.ADDED_BY_US)); - case 'UD': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.DELETED_BY_THEM)); - case 'UA': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.ADDED_BY_THEM)); - case 'DU': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.DELETED_BY_US)); - case 'AA': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.BOTH_ADDED)); - case 'UU': return merge.push(new FileStatus(raw.path, raw.mimetype, Status.BOTH_MODIFIED)); - } - - let isModifiedInIndex = false; - - switch (raw.x) { - case 'M': index.push(new FileStatus(raw.path, raw.mimetype, Status.INDEX_MODIFIED)); isModifiedInIndex = true; break; - case 'A': index.push(new FileStatus(raw.path, raw.mimetype, Status.INDEX_ADDED)); break; - case 'D': index.push(new FileStatus(raw.path, raw.mimetype, Status.INDEX_DELETED)); break; - case 'R': index.push(new FileStatus(raw.path, raw.mimetype, Status.INDEX_RENAMED, raw.rename)); break; - case 'C': index.push(new FileStatus(raw.path, raw.mimetype, Status.INDEX_COPIED)); break; - } - - switch (raw.y) { - case 'M': workingTree.push(new FileStatus(raw.path, raw.mimetype, Status.MODIFIED, raw.rename, isModifiedInIndex)); break; - case 'D': workingTree.push(new FileStatus(raw.path, raw.mimetype, Status.DELETED, raw.rename)); break; - } - - return undefined; - }); - - this.indexStatus.update(index); - this.workingTreeStatus.update(workingTree); - this.mergeStatus.update(merge); - - this.emit(ModelEvents.STATUS_MODEL_UPDATED); - } - - getIndexStatus(): IStatusGroup { - return this.indexStatus; - } - - getWorkingTreeStatus(): IStatusGroup { - return this.workingTreeStatus; - } - - getMergeStatus(): IStatusGroup { - return this.mergeStatus; - } - - getGroups(): IStatusGroup[] { - return [this.mergeStatus, this.indexStatus, this.workingTreeStatus]; - } - - find(path: string, type: StatusType): IFileStatus { - switch (type) { - case StatusType.INDEX: - return this.indexStatus.find(path); - case StatusType.WORKING_TREE: - return this.workingTreeStatus.find(path); - case StatusType.MERGE: - return this.mergeStatus.find(path); - default: - return null; - } - } - - dispose(): void { - this.toDispose = dispose(this.toDispose); - - if (this.indexStatus) { - this.indexStatus.dispose(); - this.indexStatus = null; - } - - if (this.workingTreeStatus) { - this.workingTreeStatus.dispose(); - this.workingTreeStatus = null; - } - - if (this.mergeStatus) { - this.mergeStatus.dispose(); - this.mergeStatus = null; - } - - super.dispose(); - } -} - -export class Model extends EventEmitter implements IModel { - - private repositoryRoot: string; - private status: IStatusModel; - private HEAD: IBranch; - private refs: IRef[]; - private remotes: IRemote[]; - private toDispose: IDisposable[]; - - constructor() { - super(); - - this.toDispose = []; - - this.repositoryRoot = null; - this.status = new StatusModel(); - this.toDispose.push(this.addEmitter(this.status)); - - this.HEAD = null; - this.refs = []; - this.remotes = []; - } - - getRepositoryRoot(): string { - return this.repositoryRoot; - } - - getStatus(): IStatusModel { - return this.status; - } - - getHEAD(): IBranch { - return this.HEAD; - } - - getRefs(): IRef[] { - return this.refs; - } - - getRemotes(): IRemote[] { - return this.remotes; - } - - update(status: IRawStatus): void { - if (!status) { - status = { - repositoryRoot: null, - status: [], - HEAD: null, - refs: [], - remotes: [] - }; - } - - this.repositoryRoot = status.repositoryRoot; - this.status.update(status.status); - - this.HEAD = status.HEAD; - this.emit(ModelEvents.HEAD_UPDATED); - - this.refs = status.refs; - this.emit(ModelEvents.REFS_UPDATED); - - this.remotes = status.remotes; - this.emit(ModelEvents.REMOTES_UPDATED); - - this.emit(ModelEvents.MODEL_UPDATED); - } - - getStatusSummary(): IStatusSummary { - const status = this.getStatus(); - - return { - hasWorkingTreeChanges: status.getWorkingTreeStatus().all().length > 0, - hasIndexChanges: status.getIndexStatus().all().length > 0, - hasMergeChanges: status.getMergeStatus().all().length > 0 - }; - } - - getPS1(): string { - if (!this.HEAD) { - return ''; - } - - const tag = this.getRefs().filter(iref => iref.type === RefType.Tag && iref.commit === this.HEAD.commit)[0]; - const tagName = tag && tag.name; - const head = this.HEAD.name || tagName || this.HEAD.commit.substr(0, 8); - - const statusSummary = this.getStatus().getSummary(); - - return format('{0}{1}{2}{3}', - head, - statusSummary.hasWorkingTreeChanges ? '*' : '', - statusSummary.hasIndexChanges ? '+' : '', - statusSummary.hasMergeChanges ? '!' : '' - ); - } - - dispose(): void { - this.toDispose = dispose(this.toDispose); - super.dispose(); - } -} diff --git a/src/vs/workbench/parts/git/common/stageRanges.ts b/src/vs/workbench/parts/git/common/stageRanges.ts deleted file mode 100644 index e4a30f88be3..00000000000 --- a/src/vs/workbench/parts/git/common/stageRanges.ts +++ /dev/null @@ -1,238 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { IChange, IModel, IIdentifiedSingleEditOperation } from 'vs/editor/common/editorCommon'; -import { Range } from 'vs/editor/common/core/range'; -import { Position } from 'vs/editor/common/core/position'; -import { Selection } from 'vs/editor/common/core/selection'; -import { EditOperation } from 'vs/editor/common/core/editOperation'; - -/** - * Represents the selected portion of an IChange, and includes the start/end line numbers of the full change - */ -export class SelectedChange implements IChange { - readonly originalStartLineNumber: number; - readonly originalEndLineNumber: number; - readonly modifiedStartLineNumber: number; - readonly modifiedEndLineNumber: number; - - readonly fullModifiedStartLineNumber: number; - readonly fullModifiedEndLineNumber: number; - - constructor(selected: IChange, full: IChange) { - this.originalStartLineNumber = selected.originalStartLineNumber; - this.originalEndLineNumber = selected.originalEndLineNumber; - this.modifiedStartLineNumber = selected.modifiedStartLineNumber; - this.modifiedEndLineNumber = selected.modifiedEndLineNumber; - - this.fullModifiedStartLineNumber = full.modifiedStartLineNumber; - this.fullModifiedEndLineNumber = full.modifiedEndLineNumber; - } - - /** - * True when the change is entirely selected - */ - get isCompletelySelected(): boolean { - return this.modifiedStartLineNumber === this.fullModifiedStartLineNumber && - this.modifiedEndLineNumber === this.fullModifiedEndLineNumber; - } -} - -function sortChanges(changes: IChange[]): void { - changes.sort((left, right) => { - if (left.originalStartLineNumber < right.originalStartLineNumber) { - return -1; - } else if (left.originalStartLineNumber > right.originalStartLineNumber) { - return 1; - } else if (left.modifiedStartLineNumber < right.modifiedStartLineNumber) { - return -1; - } - return 1; - }); -} - -function sortSelections(selections: Selection[]): void { - selections.sort((left, right) => { - if (left.getStartPosition().lineNumber < right.getStartPosition().lineNumber) { - return -1; - } - return 1; - }); -} - -function isInsertion(change: IChange): boolean { - return change.originalEndLineNumber <= 0; -} - -function isDeletion(change: IChange): boolean { - return change.modifiedEndLineNumber <= 0; -} - - -/** - * Returns an intersection between a change and a selection. - * Returns null if intersection does not exist. - */ -export function intersectChangeAndSelection(change: IChange, selection: Selection) { - var result = { - modifiedStartLineNumber: Math.max(change.modifiedStartLineNumber, selection.startLineNumber), - modifiedEndLineNumber: Math.min(change.modifiedEndLineNumber, selection.endLineNumber), - originalStartLineNumber: change.originalStartLineNumber, - originalEndLineNumber: change.originalEndLineNumber - }; - // Deletions have modifiedEndLineNumber = 0. In that case we can not use the simple check if there is an intersection. - var isDeletionSelected = isDeletion(result) && - (change.modifiedStartLineNumber >= selection.startLineNumber) && (change.modifiedStartLineNumber <= selection.endLineNumber); - - if ((result.modifiedStartLineNumber <= result.modifiedEndLineNumber) || isDeletionSelected) { - return result; - } - return null; -} - -/** - * Returns all selected changes (there can be multiple selections due to multiple cursors). - * If a change is partially selected, the selected part of the change will be returned. - */ -export function getSelectedChanges(changes: IChange[], selections: Selection[]): SelectedChange[] { - sortChanges(changes); - sortSelections(selections); - var result: SelectedChange[] = []; - var currentSelection = 0; - var lastLineAdded = -1; - - for (var i = 0; i < changes.length; ++i) { - // We have to check the previous selection. Since it can contain two changes. - currentSelection = Math.max(0, currentSelection - 1); - // Find all selections that are not after the current change. - while (currentSelection < selections.length && - (selections[currentSelection].startLineNumber <= changes[i].modifiedEndLineNumber || isDeletion(changes[i]))) { - var intersectedChange = intersectChangeAndSelection(changes[i], selections[currentSelection]); - if (intersectedChange !== null) { - // Each change needs to be disjoint so we check if we already added this line. - if (lastLineAdded !== intersectedChange.modifiedStartLineNumber) { - result.push(new SelectedChange(intersectedChange, changes[i])); - lastLineAdded = intersectedChange.modifiedEndLineNumber; - } else { - // Update change such that we do not add same line twice. - intersectedChange.modifiedStartLineNumber++; - if (intersectedChange.modifiedStartLineNumber <= intersectedChange.modifiedEndLineNumber) { - result.push(new SelectedChange(intersectedChange, changes[i])); - lastLineAdded = intersectedChange.modifiedEndLineNumber; - } - } - } - currentSelection++; - } - } - return result; -} - -function appendValueFromRange(base: string, model: IModel, range: Range): string { - var result = base; - if (result !== '') { - result += model.getEOL(); - } - return result + model.getValueInRange(range); -} - -/** - * Applies a list of changes to the original model and returns the new IModel. - * First sorts changes by line number. - */ -export function applyChangesToModel(original: IModel, modified: IModel, changes: IChange[]): string { - sortChanges(changes); - var result = ''; - var positionInOriginal = 1; - - for (var i = 0; i < changes.length; ++i) { - // We have to update orginalStartLineNumber for insertions, their start line is always one line behind. - var originalStartLineUpdated = isInsertion(changes[i]) ? changes[i].originalStartLineNumber + 1 : changes[i].originalStartLineNumber; - if (positionInOriginal < originalStartLineUpdated) { - result = appendValueFromRange(result, original, - new Range(positionInOriginal, 1, originalStartLineUpdated - 1, original.getLineMaxColumn(originalStartLineUpdated - 1))); - positionInOriginal = originalStartLineUpdated; - } - - if (!isDeletion(changes[i])) { - result = appendValueFromRange(result, modified, - new Range(changes[i].modifiedStartLineNumber, 1, changes[i].modifiedEndLineNumber, modified.getLineMaxColumn(changes[i].modifiedEndLineNumber))); - } - // Update position in the original file where we continue to concatanate. - // Only update position if it was not an insertion. - if (!isInsertion(changes[i])) { - positionInOriginal = changes[i].originalEndLineNumber + 1; - } - } - - // Append the last chunk after all the changes. - if (positionInOriginal <= original.getLineCount()) { - result = appendValueFromRange(result, original, - new Range(positionInOriginal, 1, original.getLineCount(), original.getLineMaxColumn(original.getLineCount()))); - } - - return result; -} - -export function getChangeRevertEdits(original: IModel, modified: IModel, changes: SelectedChange[]): IIdentifiedSingleEditOperation[] { - sortChanges(changes); - - const getDeleteOperation = (change: IChange) => { - const fullRange = getLinesRangeWithOneSurroundingNewline(modified, change.modifiedStartLineNumber, change.modifiedEndLineNumber); - return EditOperation.delete(fullRange); - }; - - return changes.map((change, i) => { - if (isInsertion(change)) { - // Delete inserted range - return getDeleteOperation(change); - } else if (isDeletion(change)) { - // Get the original lines and insert at the deleted position - const value = original.getValueInRange(getLinesRangeWithOneSurroundingNewline(original, change.originalStartLineNumber, change.originalEndLineNumber)); - return EditOperation.insert(new Position(change.modifiedStartLineNumber + 1, 1), value); - } else if (change.isCompletelySelected) { - // If the entire change is selected, then revert the whole thing. - const value = original.getValueInRange(new Range(change.originalStartLineNumber, 1, change.originalEndLineNumber + 1, 1)); - return EditOperation.replace(new Range(change.modifiedStartLineNumber, 1, change.modifiedEndLineNumber + 1, 1), value); - } else { - // If only a portion is selected, replace with the matching lines - e.g. if lines 2-4 are selected, replace with lines 2-4 from the original model (if they exist) - const copyOffset = change.modifiedStartLineNumber - change.fullModifiedStartLineNumber; - const numLinesToCopy = change.modifiedEndLineNumber - change.modifiedStartLineNumber; - const copyStartLine = change.originalStartLineNumber + copyOffset; - const copyEndLine = Math.min(copyStartLine + numLinesToCopy, original.getLineCount()); - if (copyStartLine > copyEndLine) { - return getDeleteOperation(change); - } - - // Compute the range to copy, and intersect with the full original range to validate - const originalRange = new Range(change.originalStartLineNumber, 1, change.originalEndLineNumber, original.getLineMaxColumn(change.originalEndLineNumber)); - const rangeToCopy = originalRange.intersectRanges( - new Range(copyStartLine, 1, copyEndLine, original.getLineMaxColumn(copyEndLine))); - - // No intersection, so delete the added text - if (!rangeToCopy) { - return getDeleteOperation(change); - } - - const value = original.getValueInRange(rangeToCopy); - return EditOperation.replace(new Range(change.modifiedStartLineNumber, 1, change.modifiedEndLineNumber, modified.getLineMaxColumn(change.modifiedEndLineNumber)), value); - } - }); -} - -function getLinesRangeWithOneSurroundingNewline(model: IModel, startLine: number, endLine: number): Range { - let startColumn = 1; - let endColumn = model.getLineMaxColumn(endLine); - if (endLine < model.getLineCount()) { - endLine++; - endColumn = 1; - } else if (startLine > 1) { - startLine--; - startColumn = model.getLineMaxColumn(startLine); - } - - return new Range(startLine, startColumn, endLine, endColumn); -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts b/src/vs/workbench/parts/git/electron-browser/electronGitService.ts deleted file mode 100644 index 3f6390c51ca..00000000000 --- a/src/vs/workbench/parts/git/electron-browser/electronGitService.ts +++ /dev/null @@ -1,235 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { TPromise } from 'vs/base/common/winjs.base'; -import { IRawGitService, RawServiceState, IGitConfiguration } from 'vs/workbench/parts/git/common/git'; -import { UnscopedGitService } from 'vs/workbench/parts/git/node/unscopedGitService'; -import { GitService } from 'vs/workbench/parts/git/browser/gitServices'; -import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; -import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IOutputService } from 'vs/workbench/parts/output/common/output'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { getDelayedChannel, getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; -import { Client } from 'vs/base/parts/ipc/node/ipc.cp'; -import { GitChannelClient, UnavailableGitChannel } from 'vs/workbench/parts/git/common/gitIpc'; -import { RawGitService, DelayedRawGitService } from 'vs/workbench/parts/git/node/rawGitService'; -import URI from 'vs/base/common/uri'; -import { spawn, exec } from 'child_process'; -import { join } from 'path'; -import { IStorageService } from 'vs/platform/storage/common/storage'; -import { readdir } from 'vs/base/node/pfs'; -import { IFileService } from 'vs/platform/files/common/files'; - -interface IGit { - path: string; - version: string; -} - -function parseVersion(raw: string): string { - return raw.replace(/^git version /, ''); -} - -function findSpecificGit(path: string): TPromise { - return new TPromise((c, e) => { - const buffers: Buffer[] = []; - const child = spawn(path, ['--version']); - child.stdout.on('data', b => buffers.push(b as Buffer)); - child.on('error', e); - child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) })); - }); -} - -function findGitDarwin(): TPromise { - return new TPromise((c, e) => { - exec('which git', (err, gitPathBuffer) => { - if (err) { - return e('git not found'); - } - - const path = gitPathBuffer.toString().replace(/^\s+|\s+$/g, ''); - - function getVersion(path: string) { - // make sure git executes - exec('git --version', (err, stdout: Buffer) => { - if (err) { - return e('git not found'); - } - - return c({ path, version: parseVersion(stdout.toString('utf8').trim()) }); - }); - } - - if (path !== '/usr/bin/git') { - return getVersion(path); - } - - // must check if XCode is installed - exec('xcode-select -p', (err: any) => { - if (err && err.code === 2) { - // git is not installed, and launching /usr/bin/git - // will prompt the user to install it - - return e('git not found'); - } - - getVersion(path); - }); - }); - }); -} - -function findSystemGitWin32(base: string): TPromise { - if (!base) { - return TPromise.wrapError('Not found'); - } - - return findSpecificGit(join(base, 'Git', 'cmd', 'git.exe')); -} - -function findGitHubGitWin32(): TPromise { - const github = join(process.env['LOCALAPPDATA'], 'GitHub'); - - return readdir(github).then(children => { - const git = children.filter(child => /^PortableGit/.test(child))[0]; - - if (!git) { - return TPromise.wrapError('Not found'); - } - - return findSpecificGit(join(github, git, 'cmd', 'git.exe')); - }); -} - -function findGitWin32(): TPromise { - return findSystemGitWin32(process.env['ProgramW6432']) - .then(null, () => findSystemGitWin32(process.env['ProgramFiles(x86)'])) - .then(null, () => findSystemGitWin32(process.env['ProgramFiles'])) - .then(null, () => findSpecificGit('git')) - .then(null, () => findGitHubGitWin32()); -} - -function findGit(hint: string): TPromise { - var first = hint ? findSpecificGit(hint) : TPromise.wrapError(null); - - return first.then(null, () => { - switch (process.platform) { - case 'darwin': return findGitDarwin(); - case 'win32': return findGitWin32(); - default: return findSpecificGit('git'); - } - }); -} - -class DisabledRawGitService extends RawGitService { - constructor() { - super(null); - } - - serviceState(): TPromise { - return TPromise.as(RawServiceState.Disabled); - } -} - -function createRemoteRawGitService(gitPath: string, execPath: string, workspaceRoot: string, encoding: string, verbose: boolean): IRawGitService { - const promise = TPromise.timeout(0) // free event loop cos finding git costs - .then(() => findGit(gitPath)) - .then(({ path, version }) => { - const client = new Client( - URI.parse(require.toUrl('bootstrap')).fsPath, - { - serverName: 'Git', - timeout: 1000 * 60, - args: [path, workspaceRoot, encoding, execPath, version], - env: { - ELECTRON_RUN_AS_NODE: 1, - PIPE_LOGGING: 'true', - AMD_ENTRYPOINT: 'vs/workbench/parts/git/node/gitApp', - VERBOSE_LOGGING: String(verbose) - } - } - ); - - return client.getChannel('git'); - }) - .then(null, () => new UnavailableGitChannel()); - - const channel = getNextTickChannel(getDelayedChannel(promise)); - return new GitChannelClient(channel); -} - -interface IRawGitServiceBootstrap { - createRawGitService(gitPath: string, workspaceRoot: string, defaultEncoding: string, exePath: string, version: string): TPromise; -} - -function createRawGitService(gitPath: string, execPath: string, workspaceRoot: string, encoding: string, verbose: boolean): IRawGitService { - const requirePromise = new TPromise((c, e) => { - return require(['vs/workbench/parts/git/node/rawGitServiceBootstrap'], c, e); - }); - - const servicePromise = requirePromise.then(({ createRawGitService }) => { - return findGit(gitPath) - .then(({ path, version }) => createRawGitService(path, workspaceRoot, encoding, execPath, version)) - .then(null, () => new RawGitService(null)); - }); - - return new DelayedRawGitService(servicePromise); -} - -function createUnscopedRawGitService(gitPath: string, execPath: string, encoding: string): IRawGitService { - const promise = findGit(gitPath) - .then(({ path, version }) => new UnscopedGitService(path, version, encoding, execPath)) - .then(null, () => new RawGitService(null)); - - return new DelayedRawGitService(promise); -} - -export class ElectronGitService extends GitService { - - private static USE_REMOTE_PROCESS_SERVICE = true; - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @IFileService fileService: IFileService, - @IMessageService messageService: IMessageService, - @IWorkbenchEditorService editorService: IWorkbenchEditorService, - @IOutputService outputService: IOutputService, - @ITextFileService textFileService: ITextFileService, - @IWorkspaceContextService contextService: IWorkspaceContextService, - @ILifecycleService lifecycleService: ILifecycleService, - @IStorageService storageService: IStorageService, - @IEnvironmentService environmentService: IEnvironmentService, - @IConfigurationService configurationService: IConfigurationService - ) { - const conf = configurationService.getConfiguration('git'); - const filesConf = configurationService.getConfiguration('files'); - const workspace = contextService.getWorkspace(); - const gitPath = conf.path || null; - const encoding = (filesConf && filesConf.encoding) || 'utf8'; - const verbose = !environmentService.isBuilt || environmentService.verbose; - - let raw: IRawGitService; - - if (!conf.enabled) { - raw = new DisabledRawGitService(); - } else if (!workspace) { - raw = createUnscopedRawGitService(gitPath, environmentService.execPath, encoding); - } else { - const workspaceRoot = workspace.resource.fsPath; - - if (ElectronGitService.USE_REMOTE_PROCESS_SERVICE) { - raw = createRemoteRawGitService(gitPath, environmentService.execPath, workspaceRoot, encoding, verbose); - } else { - raw = createRawGitService(gitPath, environmentService.execPath, workspaceRoot, encoding, verbose); - } - } - - super(raw, instantiationService, fileService, messageService, editorService, outputService, textFileService, contextService, lifecycleService, storageService, configurationService); - } -} diff --git a/src/vs/workbench/parts/git/electron-browser/git.contribution.ts b/src/vs/workbench/parts/git/electron-browser/git.contribution.ts deleted file mode 100644 index 93c3bdb17f3..00000000000 --- a/src/vs/workbench/parts/git/electron-browser/git.contribution.ts +++ /dev/null @@ -1,44 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { localize } from 'vs/nls'; -import { registerContributions } from 'vs/workbench/parts/git/browser/gitWorkbenchContributions'; -import { ElectronGitService } from 'vs/workbench/parts/git/electron-browser/electronGitService'; -import { IGitService } from 'vs/workbench/parts/git/common/git'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { Registry } from 'vs/platform/platform'; -import { CloneAction } from './gitActions'; -import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } from 'vs/workbench/common/actionRegistry'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; -import { ToggleViewletAction } from 'vs/workbench/browser/viewlet'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; - -// TODO@joao: remove -class OpenScmViewletAction extends ToggleViewletAction { - - static ID = 'workbench.view.git'; // fake redirect - static LABEL = localize('toggleSCMViewlet', "Show SCM"); - - constructor(id: string, label: string, @IViewletService viewletService: IViewletService, @IWorkbenchEditorService editorService: IWorkbenchEditorService) { - super(id, label, 'workbench.view.scm', viewletService, editorService); - } -} - -if (SCMPreview.enabled) { - Registry.as(WorkbenchActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(OpenScmViewletAction, OpenScmViewletAction.ID, OpenScmViewletAction.LABEL), 'View: Show SCM', 'View'); -} else { - registerContributions(); - - // Register Service - registerSingleton(IGitService, ElectronGitService); - - const category = localize('git', "Git"); - - Registry.as(WorkbenchActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(CloneAction, CloneAction.ID, CloneAction.LABEL), 'Git: Clone', category); -} diff --git a/src/vs/workbench/parts/git/electron-browser/gitActions.ts b/src/vs/workbench/parts/git/electron-browser/gitActions.ts deleted file mode 100644 index b168acb47bd..00000000000 --- a/src/vs/workbench/parts/git/electron-browser/gitActions.ts +++ /dev/null @@ -1,92 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { localize } from 'vs/nls'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { always } from 'vs/base/common/async'; -import { Action } from 'vs/base/common/actions'; -import { IMessageService } from 'vs/platform/message/common/message'; -import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import Severity from 'vs/base/common/severity'; -import { IGitService } from 'vs/workbench/parts/git/common/git'; -import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import * as url from 'url'; -import { remote } from 'electron'; -import { ITelemetryService, ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -import { isPromiseCanceledError } from 'vs/base/common/errors'; - -const dialog = remote.dialog; - -export class CloneAction extends Action { - - static ID = 'workbench.action.git.clone'; - static LABEL = 'Clone'; - - constructor(id: string, label: string, - @IGitService private gitService: IGitService, - @IQuickOpenService private quickOpenService: IQuickOpenService, - @IMessageService private messageService: IMessageService, - @IWindowsService private windowsService: IWindowsService, - @ITelemetryService private telemetryService: ITelemetryService, - @IWorkspaceContextService private workspaceService: IWorkspaceContextService - ) { - super(id, label); - } - - run(event?: any, data?: ITelemetryData): TPromise { - return this.quickOpenService.input({ - prompt: localize('valid', "Provide a valid git repository URL"), - placeHolder: localize('url', "Repository URL"), - validateInput: input => { - const parsedUrl = url.parse(input); - - if (!parsedUrl.protocol || !parsedUrl.host) { - return TPromise.as(localize('valid', "Provide a valid git repository URL")); - } - - return TPromise.as(''); - } - }) - .then(url => { - if (!url) { - this.telemetryService.publicLog('gitClone', { ...data, outcome: 'no_URL' }); - return TPromise.as(null); - } - - const result = dialog.showOpenDialog(remote.getCurrentWindow(), { - title: localize('directory', "Destination clone directory"), - properties: ['openDirectory', 'createDirectory'] - }); - - if (!result || result.length === 0) { - this.telemetryService.publicLog('gitClone', { ...data, outcome: 'no_directory' }); - return TPromise.as(null); - } - - const promise = TPromise.timeout(200) - .then(() => this.messageService.show(Severity.Info, localize('cloning', "Cloning repository '{0}'...", url))) - .then(close => new TPromise(() => null, close)); - - const clone = always(this.gitService.clone(url, result[0]), () => promise.cancel()); - - return clone.then(path => { - this.telemetryService.publicLog('gitClone', { ...data, outcome: 'success' }); - const forceNewWindow = this.workspaceService.hasWorkspace(); - return this.windowsService.openWindow([path], { forceNewWindow, forceReuseWindow: !forceNewWindow }); - - }).then(null, e => { - if (/already exists and is not an empty directory/.test(e.stderr || '')) { - this.telemetryService.publicLog('gitClone', { ...data, outcome: 'directory_not_empty' }); - return TPromise.wrapError(localize('already exists', "Destination repository already exists, please pick another directory to clone to.")); - } - - this.telemetryService.publicLog('gitClone', { ...data, outcome: isPromiseCanceledError(e) ? 'canceled' : 'error' }); - return TPromise.wrapError(e); - }); - }); - } -} diff --git a/src/vs/workbench/parts/git/electron-main/askpassService.ts b/src/vs/workbench/parts/git/electron-main/askpassService.ts deleted file mode 100644 index dbe43c01379..00000000000 --- a/src/vs/workbench/parts/git/electron-main/askpassService.ts +++ /dev/null @@ -1,75 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { ipcMain as ipc, BrowserWindow } from 'electron'; -import platform = require('vs/base/common/platform'); -import { TPromise } from 'vs/base/common/winjs.base'; -import { IAskpassService } from 'vs/workbench/parts/git/common/git'; - -export interface ICredentials { - username: string; - password: string; -} - -interface ICredentialsResult { - id: number; - credentials: ICredentials; -} - -interface IContext { - credentials: ICredentials; - window: Electron.BrowserWindow; -} - -export class GitAskpassService implements IAskpassService { - - private askpassCache: { [id: string]: IContext } = Object.create(null); - - constructor() { - ipc.on('git:askpass', (event, result: ICredentialsResult) => { - this.askpassCache[result.id].credentials = result.credentials; - }); - } - - public askpass(id: string, host: string, command: string): TPromise { - return new TPromise((c, e) => { - let cachedResult = this.askpassCache[id]; - - if (typeof cachedResult !== 'undefined') { - return c(cachedResult.credentials); - } - - if (command === 'fetch') { - return c({ username: '', password: '' }); - } - - let win = new BrowserWindow({ - alwaysOnTop: true, - skipTaskbar: true, - resizable: false, - width: 450, - height: platform.isWindows ? 280 : 260, - show: true, - title: nls.localize('git', "Git") - }); - - win.setMenuBarVisibility(false); - - this.askpassCache[id] = { - window: win, - credentials: null - }; - - win.loadURL(require.toUrl('vs/workbench/parts/git/electron-main/index.html')); - win.webContents.executeJavaScript('init(' + JSON.stringify({ id, host, command }) + ')'); - - win.once('closed', () => { - c(this.askpassCache[id].credentials); - setTimeout(() => delete this.askpassCache[id], 1000 * 10); - }); - }); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/electron-main/git.svg b/src/vs/workbench/parts/git/electron-main/git.svg deleted file mode 100644 index dfd62bc16c6..00000000000 --- a/src/vs/workbench/parts/git/electron-main/git.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/parts/git/electron-main/index.html b/src/vs/workbench/parts/git/electron-main/index.html deleted file mode 100644 index 3ae54ce146c..00000000000 --- a/src/vs/workbench/parts/git/electron-main/index.html +++ /dev/null @@ -1,138 +0,0 @@ - - - - - - - - - -

Authentication Required

-
-

-
-

-

-

- - -

-
-
- -
- - diff --git a/src/vs/workbench/parts/git/node/askpass.sh b/src/vs/workbench/parts/git/node/askpass.sh deleted file mode 100755 index 2f30f91ef9a..00000000000 --- a/src/vs/workbench/parts/git/node/askpass.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh -VSCODE_GIT_ASKPASS_PIPE=`mktemp` -AMD_ENTRYPOINT="$VSCODE_GIT_ASKPASS_MODULE_ID" VSCODE_GIT_ASKPASS_PIPE="$VSCODE_GIT_ASKPASS_PIPE" "$VSCODE_GIT_ASKPASS_NODE" "$VSCODE_GIT_ASKPASS_BOOTSTRAP" $* -cat $VSCODE_GIT_ASKPASS_PIPE -rm $VSCODE_GIT_ASKPASS_PIPE \ No newline at end of file diff --git a/src/vs/workbench/parts/git/node/askpass.ts b/src/vs/workbench/parts/git/node/askpass.ts deleted file mode 100644 index f2b45f8f1b6..00000000000 --- a/src/vs/workbench/parts/git/node/askpass.ts +++ /dev/null @@ -1,58 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { connect } from 'vs/base/parts/ipc/node/ipc.net'; -import { IAskpassChannel, AskpassChannelClient } from 'vs/workbench/parts/git/common/gitIpc'; -import * as fs from 'fs'; - -function fatal(err: any): void { - console.error(err); - process.exit(1); -} - -function main(argv: string[]): void { - if (argv.length !== 5) { - return fatal('Wrong number of arguments'); - } - - if (!process.env['VSCODE_IPC_HOOK']) { - return fatal('Missing ipc hook'); - } - - if (!process.env['VSCODE_GIT_REQUEST_ID']) { - return fatal('Missing git id'); - } - - if (!process.env['VSCODE_GIT_ASKPASS_PIPE']) { - return fatal('Missing pipe'); - } - - var id = process.env['VSCODE_GIT_REQUEST_ID']; - var output = process.env['VSCODE_GIT_ASKPASS_PIPE']; - var request = argv[2]; - var host = argv[4].substring(1, argv[4].length - 2); - - connect(process.env['VSCODE_IPC_HOOK'], 'askpass') - .then(client => { - const channel = client.getChannel('askpass'); - const service = new AskpassChannelClient(channel); - - return service.askpass(id, host, process.env['MONACO_GIT_COMMAND']).then(result => { - if (result) { - fs.writeFileSync(output, (/^Username$/i.test(request) ? result.username : result.password) + '\n'); - } - - return client; - }); - }) - .done(c => { - c.dispose(); - setTimeout(() => process.exit(0), 0); - }); -} - -main(process.argv); diff --git a/src/vs/workbench/parts/git/node/git.lib.ts b/src/vs/workbench/parts/git/node/git.lib.ts deleted file mode 100644 index 98fdbd0c5d4..00000000000 --- a/src/vs/workbench/parts/git/node/git.lib.ts +++ /dev/null @@ -1,735 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the MIT License. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as os from 'os'; -import * as path from 'path'; -import { Promise, TPromise } from 'vs/base/common/winjs.base'; -import * as pfs from 'vs/base/node/pfs'; -import { guessMimeTypes, isBinaryMime } from 'vs/base/common/mime'; -import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; -import { assign } from 'vs/base/common/objects'; -import { sequence } from 'vs/base/common/async'; -import { v4 as UUIDv4 } from 'vs/base/common/uuid'; -import { localize } from 'vs/nls'; -import { uniqueFilter, index } from 'vs/base/common/arrays'; -import { IRawFileStatus, RefType, IRef, IBranch, IRemote, GitErrorCodes, IPushOptions } from 'vs/workbench/parts/git/common/git'; -import { detectMimesFromStream } from 'vs/base/node/mime'; -import { IFileOperationResult, FileOperationResult } from 'vs/platform/files/common/files'; -import { spawn, ChildProcess } from 'child_process'; -import { decode, encodingExists } from 'vs/base/node/encoding'; - -export interface IExecutionResult { - exitCode: number; - stdout: string; - stderr: string; -} - -function exec(child: ChildProcess, encoding = 'utf8'): TPromise { - const disposables: IDisposable[] = []; - - const once = (ee: NodeJS.EventEmitter, name: string, fn: Function) => { - ee.once(name, fn); - disposables.push(toDisposable(() => ee.removeListener(name, fn))); - }; - - const on = (ee: NodeJS.EventEmitter, name: string, fn: Function) => { - ee.on(name, fn); - disposables.push(toDisposable(() => ee.removeListener(name, fn))); - }; - - return TPromise.join([ - new TPromise((c, e) => { - once(child, 'error', e); - once(child, 'exit', c); - }), - new TPromise(c => { - let buffers: Buffer[] = []; - on(child.stdout, 'data', b => buffers.push(b)); - once(child.stdout, 'close', () => c(decode(Buffer.concat(buffers), encoding))); - }), - new TPromise(c => { - let buffers: Buffer[] = []; - on(child.stderr, 'data', b => buffers.push(b)); - once(child.stderr, 'close', () => c(decode(Buffer.concat(buffers), encoding))); - }) - ]).then(values => { - dispose(disposables); - - return { - exitCode: values[0], - stdout: values[1], - stderr: values[2] - }; - }); -} - -export interface IGitErrorData { - error?: Error; - message?: string; - stdout?: string; - stderr?: string; - exitCode?: number; - gitErrorCode?: string; - gitCommand?: string; -} - -export class GitError { - - error: Error; - message: string; - stdout: string; - stderr: string; - exitCode: number; - gitErrorCode: string; - gitCommand: string; - - constructor(data: IGitErrorData) { - if (data.error) { - this.error = data.error; - this.message = data.error.message; - } else { - this.error = null; - } - - this.message = this.message || data.message || 'Git error'; - this.stdout = data.stdout || null; - this.stderr = data.stderr || null; - this.exitCode = data.exitCode || null; - this.gitErrorCode = data.gitErrorCode || null; - this.gitCommand = data.gitCommand || null; - } - - toString(): string { - let result = this.message + ' ' + JSON.stringify({ - exitCode: this.exitCode, - gitErrorCode: this.gitErrorCode, - gitCommand: this.gitCommand, - stdout: this.stdout, - stderr: this.stderr - }, null, 2); - - if (this.error) { - result += (this.error).stack; - } - - return result; - } -} - -export interface IGitOptions { - gitPath: string; - version: string; - defaultEncoding?: string; - env?: any; -} - -export class Git { - - private gitPath: string; - private _version: string; - private env: any; - private defaultEncoding: string; - private outputListeners: { (output: string): void; }[]; - - constructor(options: IGitOptions) { - this.gitPath = options.gitPath; - this._version = options.version; - - const encoding = options.defaultEncoding || 'utf8'; - this.defaultEncoding = encodingExists(encoding) ? encoding : 'utf8'; - - this.env = options.env || {}; - this.outputListeners = []; - } - - get version(): string { - return this._version; - } - - run(cwd: string, args: string[], options: any = {}): TPromise { - options = assign({ cwd: cwd }, options || {}); - return this.exec(args, options); - } - - stream(cwd: string, args: string[], options: any = {}): ChildProcess { - options = assign({ cwd: cwd }, options || {}); - return this.spawn(args, options); - } - - open(repository: string, env: any = {}): Repository { - return new Repository(this, repository, this.defaultEncoding, env); - } - - clone(url: string, parentPath: string): TPromise { - const folderName = url.replace(/^.*\//, '').replace(/\.git$/, '') || 'repository'; - const folderPath = path.join(parentPath, folderName); - - return this.exec(['clone', url, folderPath]) - .then(() => folderPath); - } - - config(name: string, value: string): Promise { - return this.exec(['config', '--global', name, value]); - } - - private exec(args: string[], options: any = {}): TPromise { - const child = this.spawn(args, options); - - if (options.input) { - child.stdin.end(options.input, 'utf8'); - } - - return exec(child).then(result => { - if (result.exitCode) { - let gitErrorCode: string = null; - - if (/Authentication failed/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.AuthenticationFailed; - } else if (/Not a git repository/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.NotAGitRepository; - } else if (/bad config file/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.BadConfigFile; - } else if (/cannot make pipe for command substitution|cannot create standard input pipe/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.CantCreatePipe; - } else if (/Repository not found/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.RepositoryNotFound; - } else if (/unable to access/.test(result.stderr)) { - gitErrorCode = GitErrorCodes.CantAccessRemote; - } - - if (options.log !== false) { - this.log(result.stderr); - } - - return TPromise.wrapError(new GitError({ - message: 'Failed to execute git', - stdout: result.stdout, - stderr: result.stderr, - exitCode: result.exitCode, - gitErrorCode, - gitCommand: args[0] - })); - } - - return result; - }); - } - - spawn(args: string[], options: any = {}): ChildProcess { - if (!this.gitPath) { - throw new Error('git could not be found in the system.'); - } - - if (!options) { - options = {}; - } - - if (!options.stdio && !options.input) { - options.stdio = ['ignore', null, null]; // Unless provided, ignore stdin and leave default streams for stdout and stderr - } - - options.env = assign({}, options.env || {}, this.env, { - LANG: 'en_US.UTF-8', - VSCODE_GIT_REQUEST_ID: UUIDv4().asHex(), - MONACO_GIT_COMMAND: args[0] - }); - - if (options.log !== false) { - this.log(`git ${args.join(' ')}\n`); - } - - return spawn(this.gitPath, args, options); - } - - onOutput(listener: (output: string) => void): () => void { - this.outputListeners.push(listener); - return () => this.outputListeners.splice(this.outputListeners.indexOf(listener), 1); - } - - private log(output: string): void { - this.outputListeners.forEach(l => l(output)); - } -} - -export interface ICommit { - hash: string; - message: string; -} - -export class Repository { - - constructor( - private _git: Git, - private repository: string, - private defaultEncoding: string, - private env: any = {} - ) { } - - get git(): Git { - return this._git; - } - - get path(): string { - return this.repository; - } - - run(args: string[], options: any = {}): TPromise { - options.env = assign({}, options.env || {}); - options.env = assign(options.env, this.env); - - return this.git.run(this.repository, args, options); - } - - stream(args: string[], options: any = {}): ChildProcess { - options.env = assign({}, options.env || {}); - options.env = assign(options.env, this.env); - - return this.git.stream(this.repository, args, options); - } - - spawn(args: string[], options: any = {}): ChildProcess { - options.env = assign({}, options.env || {}); - options.env = assign(options.env, this.env); - - return this.git.spawn(args, options); - } - - init(): Promise { - return this.run(['init']); - } - - config(scope: string, key: string, value: any, options: any): TPromise { - const args = ['config']; - - if (scope) { - args.push('--' + scope); - } - - args.push(key); - - if (value) { - args.push(value); - } - - return this.run(args, options).then((result) => result.stdout); - } - - show(object: string): ChildProcess { - return this.stream(['show', object]); - } - - buffer(object: string): TPromise { - const child = this.show(object); - - if (!child.stdout) { - return TPromise.wrapError(localize('errorBuffer', "Can't open file from git")); - } - - return detectMimesFromStream(child.stdout, null).then(result => { - return isBinaryMime(result.mimes) ? - TPromise.wrapError({ - message: localize('fileBinaryError', "File seems to be binary and cannot be opened as text"), - fileOperationResult: FileOperationResult.FILE_IS_BINARY - }) : - this.doBuffer(object); - }); - } - - private doBuffer(object: string): TPromise { - const child = this.show(object); - - return exec(child, this.defaultEncoding).then(({ exitCode, stdout }) => { - if (exitCode) { - return TPromise.wrapError(new GitError({ - message: 'Could not buffer object.', - exitCode - })); - } - - return TPromise.as(stdout); - }); - } - - add(paths: string[]): Promise { - const args = ['add', '-A', '--']; - - if (paths && paths.length) { - args.push.apply(args, paths); - } else { - args.push('.'); - } - - return this.run(args); - } - - stage(path: string, data: string): Promise { - const child = this.stream(['hash-object', '--stdin', '-w'], { stdio: [null, null, null] }); - child.stdin.end(data, 'utf8'); - - return exec(child).then(({ exitCode, stdout }) => { - if (exitCode) { - return TPromise.wrapError(new GitError({ - message: 'Could not hash object.', - exitCode: exitCode - })); - } - - return this.run(['update-index', '--cacheinfo', '100644', stdout, path]); - }); - } - - checkout(treeish: string, paths: string[]): Promise { - const args = ['checkout', '-q']; - - if (treeish) { - args.push(treeish); - } - - if (paths && paths.length) { - args.push('--'); - args.push.apply(args, paths); - } - - return this.run(args).then(null, (err: GitError) => { - if (/Please, commit your changes or stash them/.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.DirtyWorkTree; - } - - return Promise.wrapError(err); - }); - } - - commit(message: string, all: boolean, amend: boolean, signoff: boolean): Promise { - const args = ['commit', '--quiet', '--allow-empty-message', '--file', '-']; - - if (all) { - args.push('--all'); - } - - if (amend) { - args.push('--amend'); - } - - if (signoff) { - args.push('--signoff'); - } - - return this.run(args, { input: message || '' }).then(null, (commitErr: GitError) => { - if (/not possible because you have unmerged files/.test(commitErr.stderr)) { - commitErr.gitErrorCode = GitErrorCodes.UnmergedChanges; - return Promise.wrapError(commitErr); - } - - return this.run(['config', '--get-all', 'user.name']).then(null, (err: GitError) => { - err.gitErrorCode = GitErrorCodes.NoUserNameConfigured; - return Promise.wrapError(err); - }).then(() => { - return this.run(['config', '--get-all', 'user.email']).then(null, (err: GitError) => { - err.gitErrorCode = GitErrorCodes.NoUserEmailConfigured; - return Promise.wrapError(err); - }).then(() => { - return Promise.wrapError(commitErr); - }); - }); - }); - } - - branch(name: string, checkout: boolean): Promise { - const args = checkout ? ['checkout', '-q', '-b', name] : ['branch', '-q', name]; - return this.run(args); - } - - clean(paths: string[]): Promise { - const byDirname = index(paths, p => path.dirname(p), (p, r) => (r || []).concat([p])); - const groups = Object.keys(byDirname).map(key => byDirname[key]); - const tasks = groups.map(group => () => this.run(['clean', '-f', '-q', '--'].concat(group))); - - return sequence(tasks); - } - - undo(): Promise { - return this.run(['clean', '-fd']).then(() => { - return this.run(['checkout', '--', '.']).then(null, (err: GitError) => { - if (/did not match any file\(s\) known to git\./.test(err.stderr)) { - return TPromise.as(null); - } - - return Promise.wrapError(err); - }); - }); - } - - reset(treeish: string, hard: boolean = false): Promise { - const args = ['reset']; - - if (hard) { - args.push('--hard'); - } - - args.push(treeish); - - return this.run(args); - } - - revertFiles(treeish: string, paths: string[]): Promise { - return this.run(['branch']).then((result) => { - let args: string[]; - - // In case there are no branches, we must use rm --cached - if (!result.stdout) { - args = ['rm', '--cached', '-r', '--']; - } else { - args = ['reset', '-q', treeish, '--']; - } - - if (paths && paths.length) { - args.push.apply(args, paths); - } else { - args.push('.'); - } - - return this.run(args).then(null, (err: GitError) => { - // In case there are merge conflicts to be resolved, git reset will output - // some "needs merge" data. We try to get around that. - if (/([^:]+: needs merge\n)+/m.test(err.stdout)) { - return TPromise.as(null); - } - - return Promise.wrapError(err); - }); - }); - } - - fetch(): Promise { - return this.run(['fetch']).then(null, (err: GitError) => { - if (/No remote repository specified\./.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.NoRemoteRepositorySpecified; - } else if (/Could not read from remote repository/.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.RemoteConnectionError; - } - - return Promise.wrapError(err); - }); - } - - pull(rebase?: boolean): Promise { - const args = ['pull']; - if (rebase) { args.push('-r'); } - - return this.run(args).then(null, (err: GitError) => { - if (/^CONFLICT \([^)]+\): \b/m.test(err.stdout)) { - err.gitErrorCode = GitErrorCodes.Conflict; - } else if (/Please tell me who you are\./.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.NoUserNameConfigured; - } else if (/Could not read from remote repository/.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.RemoteConnectionError; - } else if (/Pull is not possible because you have unmerged files|Cannot pull with rebase: You have unstaged changes|Your local changes to the following files would be overwritten|Please, commit your changes before you can merge/.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.DirtyWorkTree; - } - - return Promise.wrapError(err); - }); - } - - push(remote?: string, name?: string, options?: IPushOptions): Promise { - const args = ['push']; - if (options && options.setUpstream) { args.push('-u'); } - if (remote) { args.push(remote); } - if (name) { args.push(name); } - - return this.run(args).then(null, (err: GitError) => { - if (/^error: failed to push some refs to\b/m.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.PushRejected; - } else if (/Could not read from remote repository/.test(err.stderr)) { - err.gitErrorCode = GitErrorCodes.RemoteConnectionError; - } - - return Promise.wrapError(err); - }); - } - - sync(): Promise { - return this.pull().then(() => this.push()); - } - - getRoot(): TPromise { - return this.run(['rev-parse', '--show-toplevel'], { log: false }).then(result => result.stdout.trim()); - } - - getStatus(): TPromise { - return this.run(['status', '-z', '-u'], { log: false }).then((executionResult) => { - const status = executionResult.stdout; - const result: IRawFileStatus[] = []; - let current: IRawFileStatus; - let i = 0; - - function readName(): string { - const start = i; - let c: string; - while ((c = status.charAt(i)) !== '\u0000') { i++; } - return status.substring(start, i++); - } - - while (i < status.length) { - current = { - x: status.charAt(i++), - y: status.charAt(i++), - path: null, - mimetype: null - }; - - i++; - - if (current.x === 'R') { - current.rename = readName(); - } - - current.path = readName(); - current.mimetype = guessMimeTypes(current.path)[0]; - - // If path ends with slash, it must be a nested git repo - if (current.path[current.path.length - 1] === '/') { - continue; - } - - result.push(current); - } - - return TPromise.as(result); - }); - } - - getHEAD(): TPromise { - return this.run(['symbolic-ref', '--short', 'HEAD'], { log: false }).then((result) => { - if (!result.stdout) { - return TPromise.wrapError(new Error('Not in a branch')); - } - - return TPromise.as({ name: result.stdout.trim(), commit: void 0, type: RefType.Head }); - }, (err) => { - return this.run(['rev-parse', 'HEAD'], { log: false }).then((result) => { - if (!result.stdout) { - return TPromise.wrapError(new Error('Error parsing HEAD')); - } - - return TPromise.as({ name: void 0, commit: result.stdout.trim(), type: RefType.Head }); - }); - }); - } - - getRefs(): TPromise { - return this.run(['for-each-ref', '--format', '%(refname) %(objectname)'], { log: false }).then(result => { - return result.stdout.trim().split('\n') - .filter(line => !!line) - .map(line => { - let match: RegExpExecArray; - - if (match = /^refs\/heads\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { - return { name: match[1], commit: match[2], type: RefType.Head }; - } else if (match = /^refs\/remotes\/([^/]+)\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { - return { name: `${match[1]}/${match[2]}`, commit: match[3], type: RefType.RemoteHead, remote: match[1] }; - } else if (match = /^refs\/tags\/([^ ]+) ([0-9a-f]{40})$/.exec(line)) { - return { name: match[1], commit: match[2], type: RefType.Tag }; - } - - return null; - }) - .filter(ref => !!ref); - }); - } - - getRemotes(): TPromise { - const regex = /^([^\s]+)\s+([^\s]+)\s/; - - return this.run(['remote', '--verbose'], { log: false }) - .then(result => result.stdout - .trim() - .split('\n') - .filter(b => !!b) - .map(line => regex.exec(line)) - .filter(g => !!g) - .map(groups => ({ name: groups[1], url: groups[2] })) - .filter(uniqueFilter<{ name: string; }>(g => g.name)) - ); - } - - getBranch(branch: string): TPromise { - if (branch === 'HEAD') { - return this.getHEAD(); - } - - return this.run(['rev-parse', branch], { log: false }).then((result) => { - if (!result.stdout) { - return TPromise.wrapError(new Error('No such branch')); - } - - const commit = result.stdout.trim(); - - return this.run(['rev-parse', '--symbolic-full-name', '--abbrev-ref', branch + '@{u}'], { log: false }).then((result: IExecutionResult) => { - const upstream = result.stdout.trim(); - - return this.run(['rev-list', '--left-right', branch + '...' + upstream], { log: false }).then((result) => { - let ahead = 0, behind = 0; - let i = 0; - - while (i < result.stdout.length) { - switch (result.stdout.charAt(i)) { - case '<': ahead++; break; - case '>': behind++; break; - default: i++; break; - } - - while (result.stdout.charAt(i++) !== '\n') { /* no-op */ } - } - - return { - name: branch, - commit: commit, - upstream: upstream, - ahead: ahead, - behind: behind - }; - }); - }, () => { - return { name: branch, commit: commit }; - }); - }); - } - - getCommitTemplate(): TPromise { - return this.run(['config', '--get', 'commit.template']).then(result => { - if (!result.stdout) { - return ''; - } - - // https://github.com/git/git/blob/3a0f269e7c82aa3a87323cb7ae04ac5f129f036b/path.c#L612 - const homedir = os.homedir(); - let templatePath = result.stdout.trim() - .replace(/^~([^\/]*)\//, (_, user) => `${user ? path.join(path.dirname(homedir), user) : homedir}/`); - - if (!path.isAbsolute(templatePath)) { - templatePath = path.join(this.repository, templatePath); - } - - return pfs.readFile(templatePath, 'utf8').then(raw => raw.replace(/^\s*#.*$\n?/gm, '').trim()); - }, () => ''); - } - - getCommit(ref: string): TPromise { - return this.run(['show', '-s', '--format=%H\n%B', ref]).then(result => { - const match = /^([0-9a-f]{40})\n([^]*)$/m.exec(result.stdout.trim()); - - if (!match) { - return TPromise.wrapError('bad commit format'); - } - - return { hash: match[1], message: match[2] }; - }); - } - - onOutput(listener: (output: string) => void): () => void { - return this.git.onOutput(listener); - } -} diff --git a/src/vs/workbench/parts/git/node/gitApp.ts b/src/vs/workbench/parts/git/node/gitApp.ts deleted file mode 100644 index 141fa65f2e3..00000000000 --- a/src/vs/workbench/parts/git/node/gitApp.ts +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { Server } from 'vs/base/parts/ipc/node/ipc.cp'; -import { createRawGitService } from './rawGitServiceBootstrap'; -import { GitChannel } from 'vs/workbench/parts/git/common/gitIpc'; - -const server = new Server(); -const service = createRawGitService(process.argv[2], process.argv[3], process.argv[4], process.argv[5], process.argv[6]); -const channel = new GitChannel(service); -server.registerChannel('git', channel); diff --git a/src/vs/workbench/parts/git/node/rawGitService.ts b/src/vs/workbench/parts/git/node/rawGitService.ts deleted file mode 100644 index 1127fc6daef..00000000000 --- a/src/vs/workbench/parts/git/node/rawGitService.ts +++ /dev/null @@ -1,237 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { join, isAbsolute, relative } from 'path'; -import { TPromise, Promise } from 'vs/base/common/winjs.base'; -import { detectMimesFromFile, detectMimesFromStream } from 'vs/base/node/mime'; -import { realpath, exists } from 'vs/base/node/pfs'; -import { Repository, GitError } from 'vs/workbench/parts/git/node/git.lib'; -import { IRawGitService, RawServiceState, IRawStatus, IRef, GitErrorCodes, IPushOptions, ICommit } from 'vs/workbench/parts/git/common/git'; -import Event, { Emitter, delayed } from 'vs/base/common/event'; - -export class RawGitService implements IRawGitService { - - private repo: Repository; - private _repositoryRoot: TPromise; - private _onOutput: Emitter; - get onOutput(): Event { return this._onOutput.event; } - - constructor(repo: Repository) { - this.repo = repo; - - let listener: () => void; - - this._onOutput = new Emitter({ - onFirstListenerAdd: () => { - listener = this.repo.onOutput(output => this._onOutput.fire(output)); - }, - onLastListenerRemove: () => { - listener(); - listener = null; - } - }); - } - - getVersion(): TPromise { - if (!this.repo) { - return TPromise.as(null); - } - - return TPromise.as(this.repo.git.version); - } - - private getRepositoryRoot(): TPromise { - return this._repositoryRoot || (this._repositoryRoot = realpath(this.repo.path)); - } - - serviceState(): TPromise { - return TPromise.as(this.repo - ? RawServiceState.OK - : RawServiceState.GitNotFound - ); - } - - statusCount(): TPromise { - if (!this.repo) { - return TPromise.as(0); - } - - return this.status().then(r => r ? r.status.length : 0); - } - - status(): TPromise { - return this.repo.getStatus() - .then(status => this.repo.getHEAD() - .then(HEAD => { - if (HEAD.name) { - return this.repo.getBranch(HEAD.name).then(null, () => HEAD); - } else { - return HEAD; - } - }, (): IRef => null) - .then(HEAD => Promise.join([this.getRepositoryRoot(), this.repo.getRefs(), this.repo.getRemotes()]).then(r => { - return { - repositoryRoot: r[0], - status: status, - HEAD: HEAD, - refs: r[1], - remotes: r[2] - }; - }))) - .then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.BadConfigFile) { - return Promise.wrapError(err); - } else if (err.gitErrorCode === GitErrorCodes.NotAtRepositoryRoot) { - return Promise.wrapError(err); - } - - return null; - }); - } - - init(): TPromise { - return this.repo.init().then(() => this.status()); - } - - add(filePaths?: string[]): TPromise { - return this.repo.add(filePaths).then(() => this.status()); - } - - stage(filePath: string, content: string): TPromise { - return this.repo.stage(filePath, content).then(() => this.status()); - } - - branch(name: string, checkout?: boolean): TPromise { - return this.repo.branch(name, checkout).then(() => this.status()); - } - - checkout(treeish?: string, filePaths?: string[]): TPromise { - return this.repo.checkout(treeish, filePaths).then(() => this.status()); - } - - clean(filePaths: string[]): TPromise { - return this.repo.clean(filePaths).then(() => this.status()); - } - - undo(): TPromise { - return this.repo.undo().then(() => this.status()); - } - - reset(treeish: string, hard?: boolean): TPromise { - return this.repo.reset(treeish, hard).then(() => this.status()); - } - - revertFiles(treeish: string, filePaths?: string[]): TPromise { - return this.repo.revertFiles(treeish, filePaths).then(() => this.status()); - } - - fetch(): TPromise { - return this.repo.fetch().then(null, (err) => { - if (err.gitErrorCode === GitErrorCodes.NoRemoteRepositorySpecified) { - return TPromise.as(null); - } - - return Promise.wrapError(err); - }).then(() => this.status()); - } - - pull(rebase?: boolean): TPromise { - return this.repo.pull(rebase).then(() => this.status()); - } - - push(remote?: string, name?: string, options?: IPushOptions): TPromise { - return this.repo.push(remote, name, options).then(() => this.status()); - } - - sync(): TPromise { - return this.repo.sync().then(() => this.status()); - } - - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { - let promise: Promise = TPromise.as(null); - - if (stage) { - promise = this.repo.add(null); - } - - return promise - .then(() => this.repo.commit(message, stage, amend, signoff)) - .then(() => this.status()); - } - - detectMimetypes(filePath: string, treeish?: string): TPromise { - return exists(join(this.repo.path, filePath)).then((exists) => { - if (exists) { - return detectMimesFromFile(join(this.repo.path, filePath)) - .then(result => result.mimes); - } - - const child = this.repo.show(treeish + ':' + filePath); - - return new TPromise((c, e) => - detectMimesFromStream(child.stdout, filePath) - .then(result => result.mimes) - ); - }); - } - - // careful, this buffers the whole object into memory - show(filePath: string, treeish?: string): TPromise { - treeish = (!treeish || treeish === '~') ? '' : treeish; - - if (isAbsolute(filePath)) { - filePath = relative(this.repo.path, filePath).replace(/\\/g, '/'); - } - - return this.repo.buffer(treeish + ':' + filePath).then(null, e => { - if (e instanceof GitError) { - return ''; // mostly untracked files end up in a git error - } - - return TPromise.wrapError(e); - }); - } - - clone(url: string, parentPath: string): TPromise { - return this.repo.git.clone(url, parentPath); - } - - getCommitTemplate(): TPromise { - return this.repo.getCommitTemplate(); - } - - getCommit(ref: string): TPromise { - return this.repo.getCommit(ref); - } -} - -export class DelayedRawGitService implements IRawGitService { - constructor(private raw: TPromise) { } - onOutput: Event = delayed(this.raw.then(r => r.onOutput)); - getVersion(): TPromise { return this.raw.then(r => r.getVersion()); } - serviceState(): TPromise { return this.raw.then(r => r.serviceState()); } - statusCount(): TPromise { return this.raw.then(r => r.statusCount()); } - status(): TPromise { return this.raw.then(r => r.status()); } - init(): TPromise { return this.raw.then(r => r.init()); } - add(filesPaths?: string[]): TPromise { return this.raw.then(r => r.add(filesPaths)); } - stage(filePath: string, content: string): TPromise { return this.raw.then(r => r.stage(filePath, content)); } - branch(name: string, checkout?: boolean): TPromise { return this.raw.then(r => r.branch(name, checkout)); } - checkout(treeish?: string, filePaths?: string[]): TPromise { return this.raw.then(r => r.checkout(treeish, filePaths)); } - clean(filePaths: string[]): TPromise { return this.raw.then(r => r.clean(filePaths)); } - undo(): TPromise { return this.raw.then(r => r.undo()); } - reset(treeish: string, hard?: boolean): TPromise { return this.raw.then(r => r.reset(treeish, hard)); } - revertFiles(treeish: string, filePaths?: string[]): TPromise { return this.raw.then(r => r.revertFiles(treeish, filePaths)); } - fetch(): TPromise { return this.raw.then(r => r.fetch()); } - pull(rebase?: boolean): TPromise { return this.raw.then(r => r.pull(rebase)); } - push(remote?: string, name?: string, options?: IPushOptions): TPromise { return this.raw.then(r => r.push(remote, name, options)); } - sync(): TPromise { return this.raw.then(r => r.sync()); } - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { return this.raw.then(r => r.commit(message, amend, stage, signoff)); } - detectMimetypes(path: string, treeish?: string): TPromise { return this.raw.then(r => r.detectMimetypes(path, treeish)); } - show(path: string, treeish?: string): TPromise { return this.raw.then(r => r.show(path, treeish)); } - clone(url: string, parentPath: string): TPromise { return this.raw.then(r => r.clone(url, parentPath)); } - getCommitTemplate(): TPromise { return this.raw.then(r => r.getCommitTemplate()); } - getCommit(ref: string): TPromise { return this.raw.then(r => r.getCommit(ref)); } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/node/rawGitServiceBootstrap.ts b/src/vs/workbench/parts/git/node/rawGitServiceBootstrap.ts deleted file mode 100644 index 666250e9fd9..00000000000 --- a/src/vs/workbench/parts/git/node/rawGitServiceBootstrap.ts +++ /dev/null @@ -1,52 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { TPromise } from 'vs/base/common/winjs.base'; -import objects = require('vs/base/common/objects'); -import uri from 'vs/base/common/uri'; -import { GitErrorCodes, IRawGitService } from 'vs/workbench/parts/git/common/git'; -import gitlib = require('vs/workbench/parts/git/node/git.lib'); -import { RawGitService } from 'vs/workbench/parts/git/node/rawGitService'; -import { join, normalize } from 'path'; -import { realpath } from 'vs/base/node/pfs'; - -export function createRawGitService(gitPath: string, workspaceRoot: string, defaultEncoding: string, exePath: string, version: string): TPromise { - if (!gitPath) { - return TPromise.as(new RawGitService(null)); - } - - const gitRootPath = uri.parse(require.toUrl('vs/workbench/parts/git/node')).fsPath; - const bootstrapPath = `${uri.parse(require.toUrl('bootstrap')).fsPath}.js`; - workspaceRoot = normalize(workspaceRoot); - - const env = objects.assign({}, process.env, { - GIT_ASKPASS: join(gitRootPath, 'askpass.sh'), - VSCODE_GIT_ASKPASS_BOOTSTRAP: bootstrapPath, - VSCODE_GIT_ASKPASS_NODE: exePath, - VSCODE_GIT_ASKPASS_MODULE_ID: 'vs/workbench/parts/git/node/askpass' - }); - - const git = new gitlib.Git({ - gitPath, version, - defaultEncoding: defaultEncoding, - env: env - }); - - const repo = git.open(workspaceRoot); - - return repo.getRoot() - .then(null, (err: gitlib.GitError) => { - if (err instanceof gitlib.GitError && err.gitErrorCode === GitErrorCodes.NotAGitRepository) { - return workspaceRoot; - } - - return TPromise.wrapError(err); - }) - .then(root => realpath(root)) - .then(root => git.open(root)) - .then(repo => new RawGitService(repo)); -} diff --git a/src/vs/workbench/parts/git/node/unscopedGitService.ts b/src/vs/workbench/parts/git/node/unscopedGitService.ts deleted file mode 100644 index 158604c7e00..00000000000 --- a/src/vs/workbench/parts/git/node/unscopedGitService.ts +++ /dev/null @@ -1,135 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 * as path from 'path'; -import { IRawGitService, IRawStatus, ServiceState, RawServiceState, ICommit } from 'vs/workbench/parts/git/common/git'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { assign } from 'vs/base/common/objects'; -import Event, { Emitter } from 'vs/base/common/event'; -import uri from 'vs/base/common/uri'; -import { Git } from './git.lib'; - -export class UnscopedGitService implements IRawGitService { - - private git: Git; - - private _onOutput = new Emitter(); - get onOutput(): Event { return this._onOutput.event; } - - private static STATUS: IRawStatus = { - repositoryRoot: null, - state: ServiceState.NotAWorkspace, - status: [], - HEAD: null, - refs: [], - remotes: [] - }; - - constructor(gitPath: string, version: string, defaultEncoding: string, exePath: string) { - const gitRootPath = uri.parse(require.toUrl('vs/workbench/parts/git/node')).fsPath; - const bootstrapPath = `${uri.parse(require.toUrl('bootstrap')).fsPath}.js`; - const env = assign({}, process.env, { - GIT_ASKPASS: path.join(gitRootPath, 'askpass.sh'), - VSCODE_GIT_ASKPASS_BOOTSTRAP: bootstrapPath, - VSCODE_GIT_ASKPASS_NODE: exePath, - VSCODE_GIT_ASKPASS_MODULE_ID: 'vs/workbench/parts/git/node/askpass' - }); - - this.git = new Git({ gitPath, version, defaultEncoding, env }); - } - - getVersion(): TPromise { - return TPromise.as(null); - } - - serviceState(): TPromise { - return TPromise.as(RawServiceState.OK); - } - - statusCount(): TPromise { - return TPromise.as(0); - } - - status(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - init(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - add(filesPaths?: string[]): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - stage(filePath: string, content: string): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - branch(name: string, checkout?: boolean): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - checkout(treeish?: string, filePaths?: string[]): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - clean(filePaths: string[]): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - undo(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - reset(treeish: string, hard?: boolean): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - revertFiles(treeish: string, filePaths?: string[]): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - fetch(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - pull(rebase?: boolean): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - push(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - sync(): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - commit(message: string, amend?: boolean, stage?: boolean, signoff?: boolean): TPromise { - return TPromise.as(UnscopedGitService.STATUS); - } - - detectMimetypes(path: string, treeish?: string): TPromise { - return TPromise.as([]); - } - - show(path: string, treeish?: string): TPromise { - return TPromise.as(null); - } - - clone(url: string, parentPath: string): TPromise { - return this.git.clone(url, parentPath); - } - - getCommitTemplate(): TPromise { - return TPromise.as(null); - } - - getCommit(ref: string): TPromise { - return TPromise.as(null); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/git/test/common/gitModel.test.ts b/src/vs/workbench/parts/git/test/common/gitModel.test.ts deleted file mode 100644 index 8b35789d6e9..00000000000 --- a/src/vs/workbench/parts/git/test/common/gitModel.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 assert = require('assert'); -import Git = require('vs/workbench/parts/git/common/git'); -import Model = require('vs/workbench/parts/git/common/gitModel'); - -suite('Git - StatusModel', () => { - var model: Git.IStatusModel; - - setup(() => { - model = new Model.StatusModel(); - }); - - teardown(() => { - model = null; - }); - - test('simple update', () => { - model.update([ - { path: 'hello', x: '?', y: '?', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 0); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - }); - - test('simple update same file twice', () => { - model.update([ - { path: 'hello', x: '?', y: '?', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 0); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - - model.update([ - { path: 'hello', x: '?', y: '?', mimetype: 'application/octet-stream' } - ]); - - index = model.getIndexStatus().all(); - workingTree = model.getWorkingTreeStatus().all(); - merge = model.getMergeStatus().all(); - - assert.equal(index.length, 0); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - }); - - test('simple update same file twice, first untracked, then ignored', () => { - model.update([ - { path: 'hello', x: '?', y: '?', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 0); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - - model.update([ - { path: 'hello', x: '!', y: '!', mimetype: 'application/octet-stream' } - ]); - - index = model.getIndexStatus().all(); - workingTree = model.getWorkingTreeStatus().all(); - merge = model.getMergeStatus().all(); - - assert.equal(index.length, 0); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - }); - - test('same file, both modified in index, deleted in working tree', () => { - model.update([ - { path: 'hello', x: 'M', y: 'D', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 1); - assert.equal(workingTree.length, 1); - assert.equal(merge.length, 0); - - assert.equal(index[0].getPath(), 'hello'); - assert.equal(index[0].getStatus(), Git.Status.INDEX_MODIFIED); - - assert.equal(workingTree[0].getPath(), 'hello'); - assert.equal(workingTree[0].getStatus(), Git.Status.DELETED); - }); - - test('index and working tree matches', () => { - model.update([ - { path: 'f1', x: 'M', y: ' ', mimetype: 'application/octet-stream' }, - { path: 'f2', x: 'A', y: ' ', mimetype: 'application/octet-stream' }, - { path: 'f3', x: 'R', y: ' ', mimetype: 'application/octet-stream' }, - { path: 'f4', x: 'C', y: ' ', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 4); - assert.equal(workingTree.length, 0); - assert.equal(merge.length, 0); - - assert.equal(index[0].getStatus(), Git.Status.INDEX_MODIFIED); - assert.equal(index[1].getStatus(), Git.Status.INDEX_ADDED); - assert.equal(index[2].getStatus(), Git.Status.INDEX_RENAMED); - assert.equal(index[3].getStatus(), Git.Status.INDEX_COPIED); - }); - - test('work tree changed since index', () => { - model.update([ - { path: 'f1', x: ' ', y: 'M', mimetype: 'application/octet-stream' }, - { path: 'f2', x: 'M', y: 'M', mimetype: 'application/octet-stream' }, - { path: 'f3', x: 'A', y: 'M', mimetype: 'application/octet-stream' }, - { path: 'f4', x: 'R', y: 'M', mimetype: 'application/octet-stream' }, - { path: 'f5', x: 'C', y: 'M', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 4); - assert.equal(workingTree.length, 5); - assert.equal(merge.length, 0); - - assert.equal(index[0].getStatus(), Git.Status.INDEX_MODIFIED); - assert.equal(index[1].getStatus(), Git.Status.INDEX_ADDED); - assert.equal(index[2].getStatus(), Git.Status.INDEX_RENAMED); - assert.equal(index[3].getStatus(), Git.Status.INDEX_COPIED); - - assert.equal(workingTree[0].getStatus(), Git.Status.MODIFIED); - assert.equal(workingTree[1].getStatus(), Git.Status.MODIFIED); - assert.equal(workingTree[2].getStatus(), Git.Status.MODIFIED); - assert.equal(workingTree[3].getStatus(), Git.Status.MODIFIED); - assert.equal(workingTree[3].getStatus(), Git.Status.MODIFIED); - }); - - test('deleted in work tree', () => { - model.update([ - { path: 'f1', x: ' ', y: 'D', mimetype: 'application/octet-stream' }, - { path: 'f2', x: 'M', y: 'D', mimetype: 'application/octet-stream' }, - { path: 'f3', x: 'A', y: 'D', mimetype: 'application/octet-stream' }, - { path: 'f4', x: 'R', y: 'D', mimetype: 'application/octet-stream' }, - { path: 'f5', x: 'C', y: 'D', mimetype: 'application/octet-stream' } - ]); - - var index = model.getIndexStatus().all(); - var workingTree = model.getWorkingTreeStatus().all(); - var merge = model.getMergeStatus().all(); - - assert.equal(index.length, 4); - assert.equal(workingTree.length, 5); - assert.equal(merge.length, 0); - - assert.equal(index[0].getStatus(), Git.Status.INDEX_MODIFIED); - assert.equal(index[1].getStatus(), Git.Status.INDEX_ADDED); - assert.equal(index[2].getStatus(), Git.Status.INDEX_RENAMED); - assert.equal(index[3].getStatus(), Git.Status.INDEX_COPIED); - - assert.equal(workingTree[0].getStatus(), Git.Status.DELETED); - assert.equal(workingTree[1].getStatus(), Git.Status.DELETED); - assert.equal(workingTree[2].getStatus(), Git.Status.DELETED); - assert.equal(workingTree[3].getStatus(), Git.Status.DELETED); - assert.equal(workingTree[3].getStatus(), Git.Status.DELETED); - }); -}); diff --git a/src/vs/workbench/parts/git/test/common/stageRanges.test.ts b/src/vs/workbench/parts/git/test/common/stageRanges.test.ts deleted file mode 100644 index cd8b50cd1c1..00000000000 --- a/src/vs/workbench/parts/git/test/common/stageRanges.test.ts +++ /dev/null @@ -1,475 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 * as assert from 'assert'; -import { SelectedChange, getSelectedChanges, applyChangesToModel, getChangeRevertEdits } from 'vs/workbench/parts/git/common/stageRanges'; -import { Model } from 'vs/editor/common/model/model'; -import { IChange } from 'vs/editor/common/editorCommon'; -import { Selection } from 'vs/editor/common/core/selection'; - -function changesEqual(actual: IChange[], expected: IChange[]) { - assert.equal(actual.length, expected.length); - if (actual.length === expected.length) { - for (var i = 0; i < actual.length; ++i) { - assert.equal(actual[i].modifiedStartLineNumber, expected[i].modifiedStartLineNumber); - assert.equal(actual[i].modifiedEndLineNumber, expected[i].modifiedEndLineNumber); - assert.equal(actual[i].originalStartLineNumber, expected[i].originalStartLineNumber); - assert.equal(actual[i].originalEndLineNumber, expected[i].originalEndLineNumber); - } - } -} - -function createChange(modifiedStart: number, modifiedEnd: number, originalStart: number, originalEnd: number): IChange { - return { - modifiedStartLineNumber: modifiedStart, - modifiedEndLineNumber: modifiedEnd, - originalStartLineNumber: originalStart, - originalEndLineNumber: originalEnd - }; -} - -function createSelectedChange(modifiedStart: number, modifiedEnd: number, originalStart: number, originalEnd: number, fullModifiedStart = modifiedStart, fullModifiedEnd = modifiedEnd): SelectedChange { - return new SelectedChange( - createChange(modifiedStart, modifiedEnd, originalStart, originalEnd), - createChange(fullModifiedStart, fullModifiedEnd, originalStart, originalEnd)); -} - -suite('Git - Stage ranges', () => { - - test('Get selected changes test - no change selected (selection before changes)', () => { - var selections: Selection[] = []; - selections.push(new Selection(1, 1, 1, 1)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 1)); - var result = getSelectedChanges(changes, selections); - assert.equal(result.length, 0); - }); - - test('Get selected changes test - no change selected (selection after changes)', () => { - var selections: Selection[] = []; - selections.push(new Selection(5, 3, 7, 8)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 1)); - var result = getSelectedChanges(changes, selections); - assert.equal(result.length, 0); - }); - - test('Get selected changes test - one change fully selected', () => { - var selections: Selection[] = []; - selections.push(new Selection(5, 3, 7, 8)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 1), createChange(5, 7, 2, 6)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(5, 7, 2, 6)); - changesEqual(result, expected); - }); - - test('Get selected changes test - one change fully selected(deletion)', () => { - var selections: Selection[] = []; - selections.push(new Selection(5, 3, 7, 8)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 1), createChange(5, 0, 5, 6)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(5, 0, 5, 6)); - changesEqual(result, expected); - }); - - test('Get selected changes test - one change (insertion) partially selected', () => { - var selections: Selection[] = []; - selections.push(new Selection(5, 3, 6, 1)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 0), createChange(5, 7, 2, 0)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(5, 6, 2, 0)); - changesEqual(result, expected); - }); - - test('Get selected changes test - multiple changes selected with one selection', () => { - var selections: Selection[] = []; - selections.push(new Selection(2, 7, 7, 1)); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 1, 1), createChange(5, 7, 2, 6)); - var result = getSelectedChanges(changes, selections); - var expected = changes; - changesEqual(result, expected); - }); - - test('Get selected changes test - one change partially seleceted with multiple selections', () => { - var selections: Selection[] = []; - selections.push(new Selection(2, 2, 5, 5), new Selection(7, 2, 9, 1)); - var changes: IChange[] = []; - changes.push(createChange(1, 15, 1, 10), createChange(120, 127, 122, 126)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(2, 5, 1, 10), createChange(7, 9, 1, 10)); - changesEqual(result, expected); - }); - - test('Get selected changes test - one change partially seleceted with overlapping selections', () => { - var selections: Selection[] = []; - selections.push(new Selection(2, 2, 5, 5), new Selection(5, 2, 9, 1)); - var changes: IChange[] = []; - changes.push(createChange(1, 15, 1, 10), createChange(120, 127, 122, 126)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(2, 5, 1, 10), createChange(6, 9, 1, 10)); - changesEqual(result, expected); - }); - - test('Get selected changes test - multiple changes partially selected with multiple selections', () => { - var selections: Selection[] = []; - selections.push(new Selection(3, 1, 9, 5), new Selection(115, 2, 129, 1)); - var changes: IChange[] = []; - changes.push(createChange(1, 15, 1, 10), createChange(116, 135, 122, 126)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(3, 9, 1, 10), createChange(116, 129, 122, 126)); - changesEqual(result, expected); - }); - - test('Get selected changes test - multiple changes selected with multiple selections. Multiple changes not selected', () => { - var selections: Selection[] = []; - selections.push(new Selection(33, 11, 79, 15), new Selection(155, 21, 189, 11)); - var changes: IChange[] = []; - changes.push(createChange(1, 45, 1, 0), createChange(80, 89, 72, 79), createChange(154, 190, 152, 186), createChange(216, 235, 222, 226)); - var result = getSelectedChanges(changes, selections); - var expected: IChange[] = []; - expected.push(createChange(33, 45, 1, 0), createChange(155, 189, 152, 186)); - changesEqual(result, expected); - }); - - function createModel(text: string): Model { - return Model.createFromString(text); - } - - test('Apply changes to model - no changes', () => { - var original = createModel('One line that is equal. '); - var modified = createModel('One line that is equal. \n Second line is new.'); - var changes: IChange[] = []; - var result = applyChangesToModel(original, modified, changes); - var expected = original; - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Apply changes to model - one line change at the end', () => { - var original = createModel('One line that is equal. '); - var modified = createModel('One line that is equal. \n Second line is new.'); - var changes: IChange[] = []; - changes.push(createChange(2, 2, 2, 2)); - var result = applyChangesToModel(original, modified, changes); - var expected = modified; - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Apply changes to model - one line insertion in the middle', () => { - var original = createModel('One line that is equal. \n Last line same. '); - var modified = createModel('One line that is equal. \n Second line is new. \n Last line same. '); - var changes: IChange[] = []; - changes.push(createChange(2, 2, 1, 0)); - var result = applyChangesToModel(original, modified, changes); - var expected = modified; - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Apply changes to model - three empty lines insertion in the middle', () => { - var original = createModel('hello\n there\n isidor\n'); - var modified = createModel('hello\n there\n \n \n \n isidor\n'); - var changes: IChange[] = []; - changes.push(createChange(3, 5, 2, 0)); - var result = applyChangesToModel(original, modified, changes); - var expected = modified; - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Apply changes to model - one line deletion', () => { - var original = createModel('One line that is equal. \n Second line is old. \n Third line same. \n Forth line not important'); - var modified = createModel('One line that is equal. \n Third line same. '); - var changes: IChange[] = []; - changes.push(createChange(2, 0, 2, 2)); - var result = applyChangesToModel(original, modified, changes); - var expected = createModel('One line that is equal. \n Third line same. \n Forth line not important'); - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Apply changes to model - one multi line change', () => { - var original = createModel('One line that is equal. \n Second line is different. \n Third line also different. \n Forth line is same. \n Fifth line is different.'); - var modified = createModel('One line that is equal. \n 2nd line is different. \n 3rd line also different. \n Forth line is same. \n 5th line is different.'); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 2, 3)); - var result = applyChangesToModel(original, modified, changes); - var expected = createModel('One line that is equal. \n 2nd line is different. \n 3rd line also different. \n Forth line is same. \n Fifth line is different.'); - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Apply changes to model - two overlapping changes', () => { - var original = createModel(' One \n Two \n Three \n Four \n Five \n'); - var modified = createModel(' One \n 2 \n 3 \n 4 \n NotSelected \n'); - var changes: IChange[] = []; - changes.push(createChange(2, 3, 2, 4), createChange(4, 4, 2, 4)); - var result = applyChangesToModel(original, modified, changes); - var expected = createModel(' One \n 2 \n 3 \n 4 \n Five \n'); - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Apply changes to model - multiple small changes', () => { - var original = createModel(' One \n Two \n Three \n Four \n Five \n Six \n Seven \n Eight \n'); - var modified = createModel(' One \n 2 \n Three \n 4 \n 5 \n Six \n 7 \n 8 \n'); - var changes: IChange[] = []; - changes.push(createChange(1, 2, 1, 2), createChange(5, 5, 5, 5), createChange(7, 8, 7, 8)); - var result = applyChangesToModel(original, modified, changes); - var expected = createModel(' One \n 2 \n Three \n Four \n 5 \n Six \n 7 \n 8 \n'); - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Apply changes to model - multiple changes - insertion, deletion and modification', () => { - var original = createModel(' One \n Two \n Three \n Four \n Five \n Six \n Seven \n Eight \n Nine \n Ten'); - var modified = createModel(' 1 \n Three \n 4 \n 5 \n Six \n 7 \n NEWLINE \n Eight '); - var changes: IChange[] = []; - changes.push(createChange(1, 1, 1, 1), createChange(2, 0, 2, 2), createChange(3, 3, 4, 4), createChange(7, 7, 7, 0), createChange(7, 0, 9, 10)); - var result = applyChangesToModel(original, modified, changes); - var expected = createModel(' 1 \n Three \n 4 \n Five \n Six \n Seven \n NEWLINE \n Eight '); - assert.equal(result, expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - no changes', () => { - var original = createModel('One line that is equal. '); - var modified = createModel('One line that is equal. \n Second line is new.'); - var changes: SelectedChange[] = []; - const edits = getChangeRevertEdits(original, modified, changes); - - assert.equal(edits.length, 0); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line insertion at the beginning', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel(' One line that is equal. '); - const modified = createModel('Inserted line is new. \n One line that is equal. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 1, 0, 0)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line insertion in the middle', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Last line same. '); - const modified = createModel('One line that is equal. \n Second line is new. \n Last line same. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(2, 2, 1, 0)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line insertion at the end', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. '); - const modified = createModel('One line that is equal. \n Second line is new.'); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(2, 2, 1, 0)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line deletion at the beginning', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('First line is deleted. \n One line that is equal. '); - const modified = createModel(' One line that is equal. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(0, 0, 1, 1)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line deletion in the middle', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Second line is deleted. \n Last line same. '); - const modified = createModel('One line that is equal. \n Last line same. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 0, 2, 2)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line deletion at the end', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Second line is deleted.'); - const modified = createModel('One line that is equal. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(2, 0, 2, 2)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - three empty lines insertion in the middle', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('hello\n there\n isidor\n'); - const modified = createModel('hello\n there\n \n \n \n isidor\n'); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(3, 5, 2, 0)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - }); - - test('Revert changes on model - one line deletion', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Second line is old. \n Third line same. \n Forth line not important'); - const modified = createModel('One line that is equal. \n Third line same. '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 0, 2, 2)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = createModel('One line that is equal. \n Second line is old. \n Third line same. '); - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - one multi line change', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Second line is different. \n Third line also different. \n Forth line is same. \n Fifth line is different.'); - const modified = createModel('One line that is equal. \n 2nd line is different. \n 3rd line also different. \n Forth line is same. \n 5th line is different.'); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(2, 3, 2, 3)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = createModel('One line that is equal. \n Second line is different. \n Third line also different. \n Forth line is same. \n 5th line is different.'); - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - one multi line change - partial revert', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel('One line that is equal. \n Second line is different. \n Third line also different. \n Forth line is same. \n Fifth line is different.'); - const modified = createModel('One line that is equal. \n 2nd line is different. \n 3rd line also different. \n Forth line is same. \n 5th line is different.'); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(3, 3, 2, 3, 2, 3)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = createModel('One line that is equal. \n 2nd line is different. \n Third line also different. \n Forth line is same. \n 5th line is different.'); - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - multiple small changes', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel(' One \n Two \n Three \n Four \n Five \n Six \n Seven \n Eight \n'); - const modified = createModel(' One \n 2 \n Three \n 4 \n 5 \n Six \n 7 \n 8 \n'); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 2, 1, 2), createSelectedChange(4, 5, 4, 5), createSelectedChange(7, 8, 7, 8)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - multiple changes - insertion, deletion and modification', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel(' One \n Two \n Three \n Four \n Five \n Six \n Seven \n Eight \n Nine \n Ten'); - const modified = createModel(' 1 \n Three \n 4 \n 5 \n Six \n 7 \n NEWLINE \n Eight '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 1, 1, 1), createSelectedChange(1, 0, 2, 2), createSelectedChange(3, 4, 4, 5), createSelectedChange(6, 7, 7, 7), createSelectedChange(8, 0, 9, 10)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); - - test('Revert changes on model - multiple changes - partial revert', () => { - const selections = [new Selection(1, 1, 1, 1)]; - const original = createModel(' One \n Two \n Three \n Four \n Five \n Six \n Seven \n Eight \n Nine \n Ten'); - const modified = createModel(' 1 \n Three \n 4 \n 5 \n Six \n 7 \n NEWLINE \n Eight '); - const changes: SelectedChange[] = []; - changes.push(createSelectedChange(1, 1, 1, 1), createSelectedChange(1, 0, 2, 2), createSelectedChange(3, 4, 4, 5), createSelectedChange(6, 7, 7, 7), createSelectedChange(8, 0, 9, 10)); - const edits = getChangeRevertEdits(original, modified, changes); - - modified.pushEditOperations(selections, edits, () => selections); - const expected = original; - assert.equal(modified.getValue(), expected.getValue()); - original.dispose(); - modified.dispose(); - expected.dispose(); - }); -}); diff --git a/src/vs/workbench/parts/scm/browser/scmPreview.ts b/src/vs/workbench/parts/scm/browser/scmPreview.ts deleted file mode 100644 index 0f2db3ad70a..00000000000 --- a/src/vs/workbench/parts/scm/browser/scmPreview.ts +++ /dev/null @@ -1,96 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * 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 { Action } from 'vs/base/common/actions'; -import { TPromise } from 'vs/base/common/winjs.base'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IMessageService } from 'vs/platform/message/common/message'; - -// tslint:disable -import pkg from 'vs/platform/node/package'; -// tslint:enable - -// Enable this by default -function getDefaultValue(): boolean { - const minorVersion = pkg.version.replace(/^(\d+\.\d+).*$/, '$1'); - const forcedVersion = window.localStorage.getItem('forcedPreviewSCMVersion'); - - if (forcedVersion !== minorVersion) { - window.localStorage.setItem('forcedPreviewSCMVersion', minorVersion); - window.localStorage.setItem('enablePreviewSCM', 'true'); - } - - const value = window.localStorage.getItem('enablePreviewSCM'); - return value !== 'false'; -} - -export default class SCMPreview { - - private static readonly _enabled = getDefaultValue(); - - static get enabled(): boolean { - return this._enabled; - } - - static set enabled(enabled: boolean) { - window.localStorage.setItem('enablePreviewSCM', enabled ? 'true' : 'false'); - } -} - -export class EnableSCMPreviewAction extends Action { - - static ID = 'enablescmpreview'; - static LABEL = 'Disable Legacy Git'; - - constructor( - id = EnableSCMPreviewAction.ID, - label = EnableSCMPreviewAction.LABEL, - @IWindowService private windowService: IWindowService, - @IMessageService private messageService: IMessageService, - ) { - super(EnableSCMPreviewAction.ID, EnableSCMPreviewAction.LABEL, '', true); - } - - run(): TPromise { - const message = 'This will reload this window, do you want to continue?'; - const result = this.messageService.confirm({ message }); - - if (!result) { - return undefined; - } - - SCMPreview.enabled = true; - return this.windowService.reloadWindow(); - } -} - -export class DisableSCMPreviewAction extends Action { - - static ID = 'disablescmpreview'; - static LABEL = 'Enable Legacy Git'; - - constructor( - id = DisableSCMPreviewAction.ID, - label = DisableSCMPreviewAction.LABEL, - @IWindowService private windowService: IWindowService, - @IMessageService private messageService: IMessageService, - ) { - super(DisableSCMPreviewAction.ID, DisableSCMPreviewAction.LABEL, '', true); - } - - run(): TPromise { - const message = 'This will reload this window, do you want to continue?'; - const result = this.messageService.confirm({ message }); - - if (!result) { - return undefined; - } - - SCMPreview.enabled = false; - return this.windowService.reloadWindow(); - } -} \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts index b372695a4bd..2646a7185f3 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scm.contribution.ts @@ -21,7 +21,6 @@ import { ISCMService } from 'vs/workbench/services/scm/common/scm'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService'; import { StatusUpdater } from './scmActivity'; -import SCMPreview, { DisableSCMPreviewAction, EnableSCMPreviewAction } from '../browser/scmPreview'; class OpenSCMViewletAction extends ToggleViewletAction { @@ -60,40 +59,32 @@ export class SwitchProvider extends Action { Registry.as(WorkbenchExtensions.Workbench) .registerWorkbenchContribution(DirtyDiffDecorator); -if (SCMPreview.enabled) { - const viewletDescriptor = new ViewletDescriptor( - 'vs/workbench/parts/scm/electron-browser/scmViewlet', - 'SCMViewlet', - VIEWLET_ID, - localize('source control', "Source Control"), - 'scm', - 36 - ); +const viewletDescriptor = new ViewletDescriptor( + 'vs/workbench/parts/scm/electron-browser/scmViewlet', + 'SCMViewlet', + VIEWLET_ID, + localize('source control', "Source Control"), + 'scm', + 36 +); - Registry.as(ViewletExtensions.Viewlets) - .registerViewlet(viewletDescriptor); +Registry.as(ViewletExtensions.Viewlets) + .registerViewlet(viewletDescriptor); - Registry.as(WorkbenchExtensions.Workbench) - .registerWorkbenchContribution(StatusUpdater); +Registry.as(WorkbenchExtensions.Workbench) + .registerWorkbenchContribution(StatusUpdater); - // Register Action to Open Viewlet - Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( - new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { - primary: null, - win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, - linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, - mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_G } - }), - 'View: Show SCM', - localize('view', "View") - ); +// Register Action to Open Viewlet +Registry.as(WorkbenchActionExtensions.WorkbenchActions).registerWorkbenchAction( + new SyncActionDescriptor(OpenSCMViewletAction, VIEWLET_ID, localize('toggleSCMViewlet', "Show SCM"), { + primary: null, + win: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, + linux: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_G }, + mac: { primary: KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_G } + }), + 'View: Show SCM', + localize('view', "View") +); - Registry.as(WorkbenchActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(SwitchProvider, SwitchProvider.ID, SwitchProvider.LABEL), 'SCM: Switch Provider', 'SCM'); - - Registry.as(WorkbenchActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(DisableSCMPreviewAction, DisableSCMPreviewAction.ID, DisableSCMPreviewAction.LABEL), 'SCM: Disable Preview SCM', 'SCM'); -} else { - Registry.as(WorkbenchActionExtensions.WorkbenchActions) - .registerWorkbenchAction(new SyncActionDescriptor(EnableSCMPreviewAction, EnableSCMPreviewAction.ID, EnableSCMPreviewAction.LABEL), 'SCM: Enable Preview SCM', 'SCM'); -} +Registry.as(WorkbenchActionExtensions.WorkbenchActions) + .registerWorkbenchAction(new SyncActionDescriptor(SwitchProvider, SwitchProvider.ID, SwitchProvider.LABEL), 'SCM: Switch Provider', 'SCM'); diff --git a/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts index 33a812a71de..8a3bb16246a 100644 --- a/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/parts/welcome/overlay/browser/welcomeOverlay.ts @@ -17,7 +17,6 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -50,7 +49,7 @@ const keys: Key[] = [ id: 'git', arrow: '←', label: localize('welcomeOverlay.git', "Source code management"), - command: SCMPreview.enabled ? 'workbench.view.scm' : 'workbench.view.git' + command: 'workbench.view.scm' }, { id: 'debug', diff --git a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts index 1acc0111dd9..7da8192ba26 100644 --- a/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts +++ b/src/vs/workbench/parts/welcome/walkThrough/electron-browser/walkThroughPart.ts @@ -33,7 +33,6 @@ import { Scope } from 'vs/workbench/common/memento'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { once } from 'vs/base/common/event'; -import SCMPreview from 'vs/workbench/parts/scm/browser/scmPreview'; import { isObject } from 'vs/base/common/types'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ICodeEditorService } from 'vs/editor/common/services/codeEditorService'; @@ -430,7 +429,9 @@ export class WalkThroughPart extends BaseEditor { private updateMarkerClasses() { const innerContent = this.content.firstElementChild; - if (SCMPreview.enabled && innerContent) { + + // TODO@christof + if (true && innerContent) { innerContent.classList.add('scmEnabled'); } }