<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 { TPromise } from 'vs/base/common/winjs.base';
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { mixin } from 'vs/base/common/objects';
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
import { EditorInput, TextEditorOptions, EditorOptions, IEditorIdentifier, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult, IEditorCommandsContext } from 'vs/workbench/common/editor';
import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { Position, IEditor, Direction, IResourceInput, IEditorInput, POSITIONS } from 'vs/platform/editor/common/editor';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IEditorGroupService, GroupArrangement } from 'vs/workbench/services/group/common/groupService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { CLOSE_EDITOR_COMMAND_ID, NAVIGATE_IN_GROUP_ONE_PREFIX, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, NAVIGATE_IN_GROUP_THREE_PREFIX, NAVIGATE_IN_GROUP_TWO_PREFIX } from 'vs/workbench/browser/parts/editor/editorCommands';
import { INextEditorGroupsService, GroupDirection as SplitDirection, INextEditorGroup } from 'vs/workbench/services/group/common/nextEditorGroupsService';

// TODo@grid this action should be removed in favour of the split vertical/horizontal actions
export class SplitEditorAction extends Action {

	public static readonly ID = 'workbench.action.splitEditor';
	public static readonly LABEL = nls.localize('splitEditor', "Split Editor");

	constructor(
		id: string,
		label: string,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IEditorGroupService private editorGroupService: IEditorGroupService
	) {
		super(id, label, 'split-editor-action');
	}

	public run(context?: IEditorCommandsContext): TPromise<any> {
		let editorToSplit: IEditor;
		if (context) {
			const stacks = this.editorGroupService.getStacksModel();
			editorToSplit = this.editorService.getVisibleEditors()[stacks.positionOfGroup(stacks.getGroup(context.groupId))];
		} else {
			editorToSplit = this.editorService.getActiveEditor();
		}

		// Can only split with target editor
		if (!editorToSplit) {
			return TPromise.as(true);
		}

		// Return if the editor to split does not support split editing
		if (editorToSplit.input instanceof EditorInput && !(<EditorInput>editorToSplit.input).supportsSplitEditor()) {
			return TPromise.as(true);
		}

		// Options
		let options: EditorOptions;
		const codeEditor = getCodeEditor(editorToSplit);
		if (codeEditor) {
			options = TextEditorOptions.fromEditor(codeEditor);
		} else {
			options = new EditorOptions();
		}
		options.pinned = true;

		// Count editors
		const visibleEditors = this.editorService.getVisibleEditors();
		const editorCount = visibleEditors.length;
		let targetPosition: Position;

		switch (editorCount) {

			// Open split editor to the right/bottom of left/top one
			case 1:
				targetPosition = Position.TWO;
				break;

			// Special case two editors opened
			case 2:

				// Continue splitting to the right/bottom
				if (editorToSplit.position === Position.TWO) {
					targetPosition = Position.THREE;
				}

				// Push the second group to the right/bottom to make room for the splitted input
				else if (editorToSplit.position === Position.ONE) {
					options.preserveFocus = true;

					return this.editorService.openEditor(editorToSplit.input, options, Position.THREE).then(() => {
						this.editorGroupService.moveGroup(Position.THREE, Position.TWO);
						this.editorGroupService.focusGroup(Position.TWO);
					});
				}
		}

		// Only split if we have a target position to split to
		if (typeof targetPosition === 'number') {
			return this.editorService.openEditor(editorToSplit.input, options, targetPosition);
		}

		return TPromise.as(true);
	}
}

export class BaseSplitEditorGroupAction extends Action {

	constructor(
		id: string,
		label: string,
		clazz: string,
		private direction: SplitDirection,
		private nextEditorGroupsService: INextEditorGroupsService
	) {
		super(id, label, clazz);
	}

	public run(context?: IEditorIdentifier): TPromise<any> {
		let group: INextEditorGroup;
		if (context && context.group) {
			group = this.nextEditorGroupsService.getGroup(context.group.id);
		}

		if (!group) {
			group = this.nextEditorGroupsService.activeGroup;
		}

		const activeEditor = group.activeEditor;
		if (!activeEditor) {
			return TPromise.as(false);
		}

		if (activeEditor instanceof EditorInput && !activeEditor.supportsSplitEditor()) {
			return TPromise.as(false);
		}

		// Add group
		const newGroup = this.nextEditorGroupsService.addGroup(group, this.direction);

		// Open editor
		let options: EditorOptions;
		const codeEditor = getCodeEditor(group.activeControl);
		if (codeEditor) {
			options = TextEditorOptions.fromEditor(codeEditor);
		} else {
			options = new EditorOptions();
		}
		options.pinned = true;

		newGroup.openEditor(activeEditor, options);

		return TPromise.as(true);
	}
}

export class SplitEditorGroupVerticalAction extends BaseSplitEditorGroupAction {

	public static readonly ID = 'workbench.action.splitEditorGroupVertical';
	public static readonly LABEL = nls.localize('splitEditorGroupVertical', "Split Editor Group Vertically");

	constructor(
		id: string,
		label: string,
		@INextEditorGroupsService nextEditorGroupsService: INextEditorGroupsService
	) {
		super(id, label, 'split-editor-vertical-action', SplitDirection.DOWN, nextEditorGroupsService);
	}
}

export class SplitEditorGroupHorizontalAction extends BaseSplitEditorGroupAction {

	public static readonly ID = 'workbench.action.splitEditorGroupHorizontal';
	public static readonly LABEL = nls.localize('splitEditorGroupHorizontal', "Split Editor Group Horizontally");

	constructor(
		id: string,<commit_msg>grid - allow to split even empty groups<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 { TPromise } from 'vs/base/common/winjs.base';
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { mixin } from 'vs/base/common/objects';
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
import { EditorInput, TextEditorOptions, EditorOptions, IEditorIdentifier, ActiveEditorMoveArguments, ActiveEditorMovePositioning, EditorCommands, ConfirmResult, IEditorCommandsContext } from 'vs/workbench/common/editor';
import { QuickOpenEntryGroup } from 'vs/base/parts/quickopen/browser/quickOpenModel';
import { EditorQuickOpenEntry, EditorQuickOpenEntryGroup, IEditorQuickOpenEntry, QuickOpenAction } from 'vs/workbench/browser/quickopen';
import { IWorkbenchEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { Position, IEditor, Direction, IResourceInput, IEditorInput, POSITIONS } from 'vs/platform/editor/common/editor';
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IEditorGroupService, GroupArrangement } from 'vs/workbench/services/group/common/groupService';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWindowsService } from 'vs/platform/windows/common/windows';
import { CLOSE_EDITOR_COMMAND_ID, NAVIGATE_IN_GROUP_ONE_PREFIX, NAVIGATE_ALL_EDITORS_GROUP_PREFIX, NAVIGATE_IN_GROUP_THREE_PREFIX, NAVIGATE_IN_GROUP_TWO_PREFIX } from 'vs/workbench/browser/parts/editor/editorCommands';
import { INextEditorGroupsService, GroupDirection as SplitDirection, INextEditorGroup } from 'vs/workbench/services/group/common/nextEditorGroupsService';

// TODo@grid this action should be removed in favour of the split vertical/horizontal actions
export class SplitEditorAction extends Action {

	public static readonly ID = 'workbench.action.splitEditor';
	public static readonly LABEL = nls.localize('splitEditor', "Split Editor");

	constructor(
		id: string,
		label: string,
		@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
		@IEditorGroupService private editorGroupService: IEditorGroupService
	) {
		super(id, label, 'split-editor-action');
	}

	public run(context?: IEditorCommandsContext): TPromise<any> {
		let editorToSplit: IEditor;
		if (context) {
			const stacks = this.editorGroupService.getStacksModel();
			editorToSplit = this.editorService.getVisibleEditors()[stacks.positionOfGroup(stacks.getGroup(context.groupId))];
		} else {
			editorToSplit = this.editorService.getActiveEditor();
		}

		// Can only split with target editor
		if (!editorToSplit) {
			return TPromise.as(true);
		}

		// Return if the editor to split does not support split editing
		if (editorToSplit.input instanceof EditorInput && !(<EditorInput>editorToSplit.input).supportsSplitEditor()) {
			return TPromise.as(true);
		}

		// Options
		let options: EditorOptions;
		const codeEditor = getCodeEditor(editorToSplit);
		if (codeEditor) {
			options = TextEditorOptions.fromEditor(codeEditor);
		} else {
			options = new EditorOptions();
		}
		options.pinned = true;

		// Count editors
		const visibleEditors = this.editorService.getVisibleEditors();
		const editorCount = visibleEditors.length;
		let targetPosition: Position;

		switch (editorCount) {

			// Open split editor to the right/bottom of left/top one
			case 1:
				targetPosition = Position.TWO;
				break;

			// Special case two editors opened
			case 2:

				// Continue splitting to the right/bottom
				if (editorToSplit.position === Position.TWO) {
					targetPosition = Position.THREE;
				}

				// Push the second group to the right/bottom to make room for the splitted input
				else if (editorToSplit.position === Position.ONE) {
					options.preserveFocus = true;

					return this.editorService.openEditor(editorToSplit.input, options, Position.THREE).then(() => {
						this.editorGroupService.moveGroup(Position.THREE, Position.TWO);
						this.editorGroupService.focusGroup(Position.TWO);
					});
				}
		}

		// Only split if we have a target position to split to
		if (typeof targetPosition === 'number') {
			return this.editorService.openEditor(editorToSplit.input, options, targetPosition);
		}

		return TPromise.as(true);
	}
}

export class BaseSplitEditorGroupAction extends Action {

	constructor(
		id: string,
		label: string,
		clazz: string,
		private direction: SplitDirection,
		private nextEditorGroupsService: INextEditorGroupsService
	) {
		super(id, label, clazz);
	}

	public run(context?: IEditorIdentifier): TPromise<any> {
		let group: INextEditorGroup;
		if (context && context.group) {
			group = this.nextEditorGroupsService.getGroup(context.group.id);
		}

		if (!group) {
			group = this.nextEditorGroupsService.activeGroup;
		}

		const activeEditor = group.activeEditor;
		if (activeEditor instanceof EditorInput && !activeEditor.supportsSplitEditor()) {
			return TPromise.as(false);
		}

		// Add group
		const newGroup = this.nextEditorGroupsService.addGroup(group, this.direction);

		// Open editor
		if (activeEditor) {
			let options: EditorOptions;
			const codeEditor = getCodeEditor(group.activeControl);
			if (codeEditor) {
				options = TextEditorOptions.fromEditor(codeEditor);
			} else {
				options = new EditorOptions();
			}
			options.pinned = true;

			newGroup.openEditor(activeEditor, options);
		}

		return TPromise.as(true);
	}
}

export class SplitEditorGroupVerticalAction extends BaseSplitEditorGroupAction {

	public static readonly ID = 'workbench.action.splitEditorGroupVertical';
	public static readonly LABEL = nls.localize('splitEditorGroupVertical', "Split Editor Group Vertically");

	constructor(
		id: string,
		label: string,
		@INextEditorGroupsService nextEditorGroupsService: INextEditorGroupsService
	) {
		super(id, label, 'split-editor-vertical-action', SplitDirection.DOWN, nextEditorGroupsService);
	}
}

export class SplitEditorGroupHorizontalAction extends BaseSplitEditorGroupAction {

	public static readonly ID = 'workbench.action.splitEditorGroupHorizontal';
	public static readonly LABEL = nls.localize('splitEditorGroupHorizontal', "Split Editor Group Horizontally");

	constructor(
		id: string,
{'fraction_non_alphanumeric': 0.12401189353832766, 'fraction_numerical': 0.00029008630067445067, 'mean_word_length': 4.342890352576521, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, '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': '7585820', 'n_tokens_mistral': 4200, 'n_tokens_neox': 3801, 'n_words': 929}