<commit_before>/*---------------------------------------------------------------------------------------------
 *  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, disposeAll } from 'vs/base/common/lifecycle';
import strings = require('vs/base/common/strings');
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/workbench/services/workspace/common/contextService';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IEventService } from 'vs/platform/event/common/event';
import { IFileService, IFileStat } from 'vs/platform/files/common/files';
import { IMessageService, IConfirmation } from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
import { IGitService, IFileStatus, Status, StatusType, ServiceState,
	IModel, IBranch, GitErrorCodes, ServiceOperations }
	from 'vs/workbench/parts/git/common/git';
import {IQuickOpenService, IPickOpenEntry} from 'vs/workbench/services/quickopen/common/quickOpenService';

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 [<model.FileStatus> context];

	} else if (context instanceof model.StatusGroup) {
		return (<model.StatusGroup> context).all();

	} else if (context.tree) {
		var elements = (<ITree> 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) {
		this.gitService = gitService;
		super(id, label, cssClass, false);

		this.toDispose = [this.gitService.addBulkListener2(() => 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 = disposeAll(this.toDispose);

		super.dispose();
	}
}

export class OpenChangeAction extends GitAction {

	static ID = 'workbench.action.openChange';
	protected editorService: IWorkbenchEditorService;

	constructor(@IWorkbenchEditorService editorService: IWorkbenchEditorService, @IGitService gitService: IGitService) {
		this.editorService = editorService;
		super(OpenChangeAction.ID, nls.localize('openChange', "Open Change"), 'git-action open-change', gitService);
	}

	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.openFile';

	private fileService: IFileService;
	private editorService: IWorkbenchEditorService;
	private contextService: IWorkspaceContextService;

	constructor(@IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @IGitService gitService: IGitService, @IWorkspaceContextService contextService: IWorkspaceContextService) {
		this.fileService = fileService;
		this.editorService = editorService;
		this.contextService = contextService;
		super(OpenFileAction.ID, nls.localize('openFile', "Open File"), 'git-action open-file', gitService);
	}

	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 is has been deleted.'));
		}

		var path = this.getPath(status);

		return this.fileService.resolveFile(this.contextService.toResource(path)).then((stat: IFileStat) => {
			return this.editorService.openEditor({
				resource: stat.resource,
				mime: stat.mime,
				options: {
					forceOpen: true
				}
			});
		});
	}
}

export class InitAction extends GitAction {

	static ID = 'workbench.action.init';

	constructor(@IGitService gitService: IGitService) {
		super(InitAction.ID, nls.localize('init', "Init"), 'git-action init', gitService);
	}<commit_msg>fix open file git action for out of workspace repo<commit_after>/*---------------------------------------------------------------------------------------------
 *  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, disposeAll } from 'vs/base/common/lifecycle';
import strings = require('vs/base/common/strings');
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/workbench/services/workspace/common/contextService';
import { IEditor } from 'vs/platform/editor/common/editor';
import { IEventService } from 'vs/platform/event/common/event';
import { IFileService, IFileStat } from 'vs/platform/files/common/files';
import { IMessageService, IConfirmation } from 'vs/platform/message/common/message';
import Severity from 'vs/base/common/severity';
import { IGitService, IFileStatus, Status, StatusType, ServiceState,
	IModel, IBranch, GitErrorCodes, ServiceOperations }
	from 'vs/workbench/parts/git/common/git';
import {IQuickOpenService, IPickOpenEntry} from 'vs/workbench/services/quickopen/common/quickOpenService';
import paths = require('vs/base/common/paths');
import URI from 'vs/base/common/uri';

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 [<model.FileStatus> context];

	} else if (context instanceof model.StatusGroup) {
		return (<model.StatusGroup> context).all();

	} else if (context.tree) {
		var elements = (<ITree> 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) {
		this.gitService = gitService;
		super(id, label, cssClass, false);

		this.toDispose = [this.gitService.addBulkListener2(() => 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 = disposeAll(this.toDispose);

		super.dispose();
	}
}

export class OpenChangeAction extends GitAction {

	static ID = 'workbench.action.openChange';
	protected editorService: IWorkbenchEditorService;

	constructor(@IWorkbenchEditorService editorService: IWorkbenchEditorService, @IGitService gitService: IGitService) {
		this.editorService = editorService;
		super(OpenChangeAction.ID, nls.localize('openChange', "Open Change"), 'git-action open-change', gitService);
	}

	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.openFile';

	private fileService: IFileService;
	private editorService: IWorkbenchEditorService;
	private contextService: IWorkspaceContextService;

	constructor(@IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @IGitService gitService: IGitService, @IWorkspaceContextService contextService: IWorkspaceContextService) {
		this.fileService = fileService;
		this.editorService = editorService;
		this.contextService = contextService;
		super(OpenFileAction.ID, nls.localize('openFile', "Open File"), 'git-action open-file', gitService);
	}

	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 is 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,
				mime: stat.mime,
				options: { forceOpen: true }
			}));
	}
}

export class InitAction extends GitAction {

	static ID = 'workbench.action.init';

	constructor(@IGitService gitService: IGitService) {
		super(InitAction.ID, nls.localize('init', "Init"), 'git-action init', gitService);
	}
{'fraction_non_alphanumeric': 0.1554377054078279, 'fraction_numerical': 0.00089632506722438, 'mean_word_length': 4.4559902200489, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 23, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '128089', 'n_tokens_mistral': 4167, 'n_tokens_neox': 3909, 'n_words': 890}