提交 1a59decd 编写于 作者: D Daniel Imms

Simplify terminal split model, only allow one dimension

上级 1633d095
......@@ -182,13 +182,6 @@ export interface ITerminalService {
setWorkspaceShellAllowed(isAllowed: boolean): void;
}
export const enum Direction {
Left = 0,
Right = 1,
Up = 2,
Down = 3
}
export interface ITerminalTab {
activeInstance: ITerminalInstance;
terminalInstances: ITerminalInstance[];
......@@ -196,7 +189,8 @@ export interface ITerminalTab {
onDisposed: Event<ITerminalTab>;
onInstancesChanged: Event<void>;
focusDirection(direction: Direction): void;
focusPreviousPane(): void;
focusNextPane(): void;
setActiveInstanceByIndex(index: number): void;
attachToElement(element: HTMLElement): void;
setVisible(visible: boolean): void;
......
......@@ -18,7 +18,7 @@ import { getTerminalDefaultShellUnixLike, getTerminalDefaultShellWindows } from
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, MoveToLineStartTerminalAction, MoveToLineEndTerminalAction, SplitVerticalTerminalAction, FocusTerminalLeftAction, FocusTerminalRightAction, FocusTerminalUpAction, FocusTerminalDownAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions';
import { KillTerminalAction, CopyTerminalSelectionAction, CreateNewTerminalAction, CreateNewInActiveWorkspaceTerminalAction, FocusActiveTerminalAction, FocusNextTerminalAction, FocusPreviousTerminalAction, SelectDefaultShellWindowsTerminalAction, RunSelectedTextInTerminalAction, RunActiveFileInTerminalAction, ScrollDownTerminalAction, ScrollDownPageTerminalAction, ScrollToBottomTerminalAction, ScrollUpTerminalAction, ScrollUpPageTerminalAction, ScrollToTopTerminalAction, TerminalPasteAction, ToggleTerminalAction, ClearTerminalAction, AllowWorkspaceShellTerminalCommand, DisallowWorkspaceShellTerminalCommand, RenameTerminalAction, SelectAllTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, ShowNextFindTermTerminalFindWidgetAction, ShowPreviousFindTermTerminalFindWidgetAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, TERMINAL_PICKER_PREFIX, MoveToLineStartTerminalAction, MoveToLineEndTerminalAction, SplitVerticalTerminalAction, FocusPreviousPaneTerminalAction, FocusNextPaneTerminalAction } from 'vs/workbench/parts/terminal/electron-browser/terminalActions';
import { Registry } from 'vs/platform/registry/common/platform';
import { ShowAllCommandsAction } from 'vs/workbench/parts/quickopen/browser/commandsHandler';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
......@@ -274,8 +274,8 @@ configurationRegistry.registerConfiguration({
TogglePanelAction.ID,
'workbench.action.quickOpenView',
SplitVerticalTerminalAction.ID,
FocusTerminalLeftAction.ID,
FocusTerminalRightAction.ID
FocusPreviousPaneTerminalAction.ID,
FocusNextPaneTerminalAction.ID
].sort()
},
'terminal.integrated.env.osx': {
......@@ -416,22 +416,14 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitVerticalTer
primary: null,
mac: { primary: KeyMod.CtrlCmd | KeyCode.KEY_D }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Split Vertically', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalLeftAction, FocusTerminalLeftAction.ID, FocusTerminalLeftAction.LABEL, {
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusPreviousPaneTerminalAction, FocusPreviousPaneTerminalAction.ID, FocusPreviousPaneTerminalAction.LABEL, {
primary: KeyMod.Alt | KeyCode.LeftArrow,
mac: { primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.LeftArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Terminal To Left', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalRightAction, FocusTerminalRightAction.ID, FocusTerminalRightAction.LABEL, {
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Previous Pane', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusNextPaneTerminalAction, FocusNextPaneTerminalAction.ID, FocusNextPaneTerminalAction.LABEL, {
primary: KeyMod.Alt | KeyCode.RightArrow,
mac: { primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.RightArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Terminal To Right', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalDownAction, FocusTerminalDownAction.ID, FocusTerminalDownAction.LABEL, {
primary: KeyMod.Alt | KeyCode.DownArrow,
mac: { primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.DownArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Terminal Below', category);
actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalUpAction, FocusTerminalUpAction.ID, FocusTerminalUpAction.LABEL, {
primary: KeyMod.Alt | KeyCode.UpArrow,
mac: { primary: KeyMod.Alt | KeyMod.CtrlCmd | KeyCode.UpArrow }
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Terminal Above', category);
}, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Focus Next Pane', category);
terminalCommands.setup();
......
......@@ -8,7 +8,7 @@ import * as os from 'os';
import { Action, IAction } from 'vs/base/common/actions';
import { EndOfLinePreference } from 'vs/editor/common/model';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance } from 'vs/workbench/parts/terminal/common/terminal';
import { SelectActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { TPromise } from 'vs/base/common/winjs.base';
import { TogglePanelAction } from 'vs/workbench/browser/panel';
......@@ -298,7 +298,7 @@ export class CreateNewInActiveWorkspaceTerminalAction extends Action {
export class SplitVerticalTerminalAction extends Action {
public static readonly ID = 'workbench.action.terminal.splitVertical';
public static readonly LABEL = nls.localize('workbench.action.terminal.splitVertical', "Split the terminal vertically");
public static readonly LABEL = nls.localize('workbench.action.terminal.splitVertical', "Split Terminal Vertically");
constructor(
id: string, label: string,
......@@ -317,10 +317,12 @@ export class SplitVerticalTerminalAction extends Action {
}
}
export abstract class BaseFocusDirectionTerminalAction extends Action {
export class FocusPreviousPaneTerminalAction extends Action {
public static readonly ID = 'workbench.action.terminal.focusPreviousPane';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusPreviousPane', "Focus Previous Pane");
constructor(
id: string, label: string,
private _direction: Direction,
@ITerminalService private readonly _terminalService: ITerminalService
) {
super(id, label);
......@@ -331,44 +333,29 @@ export abstract class BaseFocusDirectionTerminalAction extends Action {
if (!tab) {
return TPromise.as(void 0);
}
tab.focusDirection(this._direction);
tab.focusPreviousPane();
return this._terminalService.showPanel(true);
}
}
export class FocusTerminalLeftAction extends BaseFocusDirectionTerminalAction {
public static readonly ID = 'workbench.action.terminal.focusTerminalLeft';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusTerminalLeft', "Focus terminal to the left");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Left, terminalService);
}
}
export class FocusTerminalRightAction extends BaseFocusDirectionTerminalAction {
public static readonly ID = 'workbench.action.terminal.focusTerminalRight';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusTerminalRight', "Focus terminal to the right");
export class FocusNextPaneTerminalAction extends Action {
public static readonly ID = 'workbench.action.terminal.focusNextPane';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusNextPane', "Focus Next Pane");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Right, terminalService);
}
}
export class FocusTerminalUpAction extends BaseFocusDirectionTerminalAction {
public static readonly ID = 'workbench.action.terminal.focusTerminalUp';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusTerminalUp', "Focus terminal above");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Up, terminalService);
constructor(
id: string, label: string,
@ITerminalService private readonly _terminalService: ITerminalService
) {
super(id, label);
}
}
export class FocusTerminalDownAction extends BaseFocusDirectionTerminalAction {
public static readonly ID = 'workbench.action.terminal.focusTerminalDown';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusTerminalDown', "Focus terminal below");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Down, terminalService);
public run(event?: any): TPromise<any> {
const tab = this._terminalService.getActiveTab();
if (!tab) {
return TPromise.as(void 0);
}
tab.focusNextPane();
return this._terminalService.showPanel(true);
}
}
......
......@@ -237,8 +237,5 @@ export class TerminalService extends AbstractTerminalService implements ITermina
this._configHelper.panelContainer = panelContainer;
this._terminalContainer = terminalContainer;
this._terminalTabs.forEach(tab => tab.attachToElement(this._terminalContainer));
this._terminalInstances.forEach(terminalInstance => {
terminalInstance.attachToElement(this._terminalContainer);
});
}
}
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalInstance, IShellLaunchConfig, ITerminalTab } from 'vs/workbench/parts/terminal/common/terminal';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { TerminalConfigHelper } from 'vs/workbench/parts/terminal/electron-browser/terminalConfigHelper';
import { IContextKey } from 'vs/platform/contextkey/common/contextkey';
......@@ -12,60 +12,48 @@ import Event, { Emitter, anyEvent } from 'vs/base/common/event';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { SplitView, Orientation, IView } from 'vs/base/browser/ui/splitview/splitview';
class SplitPane implements IView {
public minimumSize: number = 100;
class SplitPaneContainer implements IView {
public minimumSize: number = 40;
public maximumSize: number = Number.MAX_VALUE;
public instance: ITerminalInstance;
public orientation: Orientation | undefined;
protected _size: number;
private _splitView: SplitView | undefined;
// TODO: Swap height and width when rotation is implemented
private _height: number;
private _width: number;
private _splitView: SplitView;
private _children: SplitPane[] = [];
private _container: HTMLElement;
private _isContainerSet: boolean = false;
private _onDidChange: Event<number | undefined> = Event.None;
public get children(): SplitPane[] { return this._children; }
private _onDidChange: Event<number | undefined> = Event.None;
public get onDidChange(): Event<number | undefined> { return this._onDidChange; }
constructor(
private _parent?: SplitPane,
public orthogonalSize?: number,
private _needsReattach?: boolean
private _container: HTMLElement,
public orientation: Orientation
) {
}
protected branch(container: HTMLElement, orientation: Orientation, instance: ITerminalInstance): void {
this.orientation = orientation;
container.removeChild((<any>this.instance)._wrapperElement);
this._splitView = new SplitView(container, { orientation });
this._width = this._container.offsetWidth;
this._height = this._container.offsetHeight;
this._splitView = new SplitView(this._container, { orientation: this.orientation });
this._splitView.onDidSashReset(() => this._resetSize());
this.layout(this._size);
this.orthogonalLayout(this.orthogonalSize);
this.addChild(this.orthogonalSize / 2, this._size, this.instance, 0, this._isContainerSet);
this.addChild(this.orthogonalSize / 2, this._size, instance);
this.render(this._container);
this._splitView.layout(this._width);
}
// Instance is now owned by the first child
this.instance = null;
public split(instance: ITerminalInstance, index: number = this._children.length): void {
this._addChild(this._width / (this._children.length + 1), instance, index);
}
public split(instance: ITerminalInstance): void {
if (this._parent && this._parent.orientation === this.orientation) {
// TODO: Splitting sizes can be a bit weird when not splitting the right-most pane
// If we kept proportions when adding the view to the splitview it would be alright
const index = this._parent._children.indexOf(this);
this._parent.addChild(this._size / 2, this.orthogonalSize, instance, index + 1);
} else {
this.branch(this._container, this.orientation, instance);
private _resetSize(): void {
let totalSize = 0;
for (let i = 0; i < this._splitView.length; i++) {
totalSize += this._splitView.getViewSize(i);
}
const newSize = Math.floor(totalSize / this._splitView.length);
for (let i = 0; i < this._splitView.length - 1; i++) {
this._splitView.resizeView(i, newSize);
}
}
private addChild(size: number, orthogonalSize: number, instance: ITerminalInstance, index?: number, needsReattach?: boolean): void {
const child = new SplitPane(this, orthogonalSize, needsReattach);
private _addChild(size: number, instance: ITerminalInstance, index: number): void {
const child = new SplitPane(this._height);
child.orientation = this.orientation;
child.instance = instance;
this._splitView.addView(child, size, index);
......@@ -76,45 +64,81 @@ class SplitPane implements IView {
this._children.push(child);
}
this._resetSize();
this._onDidChange = anyEvent(...this._children.map(c => c.onDidChange));
}
private _resetSize(): void {
let totalSize = 0;
for (let i = 0; i < this._splitView.length; i++) {
totalSize += this._splitView.getViewSize(i);
public render(container: HTMLElement): void {
this._container = container;
}
public remove(instance: ITerminalInstance): void {
let index = null;
for (let i = 0; i < this._children.length; i++) {
if (this._children[i].instance === instance) {
index = i;
}
}
const newSize = Math.floor(totalSize / this._splitView.length);
for (let i = 0; i < this._splitView.length - 1; i++) {
this._splitView.resizeView(i, newSize);
if (index !== null) {
this._children.splice(index, 1);
this._splitView.removeView(index);
this._resetSize();
}
}
public layoutBox(width: number, height: number): void {
if (this.orientation === Orientation.HORIZONTAL) {
this.layout(height);
this.orthogonalLayout(width);
} else {
this.layout(width);
this.orthogonalLayout(height);
}
}
public remove(): void {
if (!this._parent) {
public layout(size: number): void {
// Only layout when both sizes are known
this._height = size;
if (!this._height) {
return;
}
this._parent.removeChild(this);
this._children.forEach(c => c.orthogonalLayout(this._height));
}
public removeChild(child: SplitPane): void {
const index = this._children.indexOf(child);
this._children.splice(index, 1);
this._splitView.removeView(index);
public orthogonalLayout(size: number): void {
this._width = size;
if (this._splitView) {
this._splitView.layout(this._width);
}
}
}
class SplitPane implements IView {
public minimumSize: number = 40;
public maximumSize: number = Number.MAX_VALUE;
public instance: ITerminalInstance;
public orientation: Orientation | undefined;
protected _size: number;
private _isContainerSet: boolean = false;
private _onDidChange: Event<number | undefined> = Event.None;
public get onDidChange(): Event<number | undefined> { return this._onDidChange; }
constructor(
public orthogonalSize: number
) {
}
public render(container: HTMLElement): void {
if (!container) {
return;
}
this._container = container;
if (!this._isContainerSet && this.instance) {
if (this._needsReattach) {
(<any>this.instance).reattachToElement(container);
} else {
this.instance.attachToElement(container);
}
this.instance.attachToElement(container);
this._isContainerSet = true;
}
}
......@@ -126,75 +150,21 @@ class SplitPane implements IView {
return;
}
if (this.instance) {
if (this.orientation === Orientation.VERTICAL) {
this.instance.layout({ width: this.orthogonalSize, height: this._size });
} else {
this.instance.layout({ width: this._size, height: this.orthogonalSize });
}
return;
}
for (const child of this.children) {
child.orthogonalLayout(this._size);
if (this.orientation === Orientation.VERTICAL) {
this.instance.layout({ width: this.orthogonalSize, height: this._size });
} else {
this.instance.layout({ width: this._size, height: this.orthogonalSize });
}
}
public orthogonalLayout(size: number): void {
this.orthogonalSize = size;
if (this._splitView) {
this._splitView.layout(this.orthogonalSize);
}
}
}
class RootSplitPane extends SplitPane {
private static _lastKnownWidth: number;
private static _lastKnownHeight: number;
private _width: number;
private _height: number;
protected branch(container: HTMLElement, orientation: Orientation, instance: ITerminalInstance): void {
if (orientation === Orientation.VERTICAL) {
this._size = this._width || RootSplitPane._lastKnownWidth;
this.orthogonalSize = this._height || RootSplitPane._lastKnownHeight;
} else {
this._size = this._height || RootSplitPane._lastKnownHeight;
this.orthogonalSize = this._width || RootSplitPane._lastKnownWidth;
}
super.branch(container, orientation, instance);
}
public layoutBox(width: number, height: number): void {
RootSplitPane._lastKnownWidth = width;
RootSplitPane._lastKnownHeight = height;
if (this.orientation === Orientation.VERTICAL) {
this.layout(width);
this.orthogonalLayout(height);
} else if (this.orientation === Orientation.HORIZONTAL) {
this.layout(height);
this.orthogonalLayout(width);
} else {
this._width = width;
this._height = height;
this.instance.layout({ width, height });
}
}
}
const directionOrientation: { [direction: number]: Orientation } = {
[Direction.Left]: Orientation.HORIZONTAL,
[Direction.Right]: Orientation.HORIZONTAL,
[Direction.Up]: Orientation.VERTICAL,
[Direction.Down]: Orientation.VERTICAL
};
export class TerminalTab extends Disposable implements ITerminalTab {
private _terminalInstances: ITerminalInstance[] = [];
private _rootSplitPane: RootSplitPane;
private _splitPaneContainer: SplitPaneContainer | undefined;
private _tabElement: HTMLElement;
private _activeInstanceIndex: number;
......@@ -226,9 +196,6 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this._initInstanceListeners(instance);
this._activeInstanceIndex = 0;
this._rootSplitPane = new RootSplitPane();
this._rootSplitPane.instance = instance;
if (this._container) {
this.attachToElement(this._container);
}
......@@ -272,10 +239,9 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this.activeInstance.focus(true);
}
// Find the instance's SplitPane and unsplit it
const pane = this._findSplitPane(instance);
if (pane) {
pane.remove();
// Remove the instance from the split pane if it has been created
if (this._splitPaneContainer) {
this._splitPaneContainer.remove(instance);
}
// Fire events and dispose tab if it was the last instance
......@@ -286,44 +252,6 @@ export class TerminalTab extends Disposable implements ITerminalTab {
}
}
private _findSplitPane(instance: ITerminalInstance): SplitPane {
const openList: SplitPane[] = [this._rootSplitPane];
while (openList.length > 0) {
const current = openList.shift();
if (current.instance === instance) {
return current;
}
openList.push.apply(openList, current.children);
}
return null;
}
// TODO: Should this live inside SplitPane?
private _findSplitPanePath(instance: ITerminalInstance, path: SplitPane[] = [this._rootSplitPane]): SplitPane[] {
// Gets all split panes from the root to the pane containing the instance.
const pane = path[path.length - 1];
// Base case: path found
if (pane.instance === instance) {
return path;
}
// Rescurse child panes
for (let i = 0; i < pane.children.length; i++) {
const child = pane.children[i];
const subPath = path.slice();
subPath.push(child);
const result = this._findSplitPanePath(instance, subPath);
if (result) {
return result;
}
}
// No children contain instance
return null;
}
private _setActiveInstance(instance: ITerminalInstance): void {
this.setActiveInstanceByIndex(this._getIndexFromId(instance.id));
}
......@@ -343,7 +271,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
public setActiveInstanceByIndex(index: number): void {
// Check for invalid value
if (index >= this._terminalInstances.length) {
if (index < 0 || index >= this._terminalInstances.length) {
return;
}
......@@ -360,7 +288,10 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this._tabElement = document.createElement('div');
this._tabElement.classList.add('terminal-tab');
this._container.appendChild(this._tabElement);
this._rootSplitPane.render(this._tabElement);
if (!this._splitPaneContainer) {
this._splitPaneContainer = new SplitPaneContainer(this._tabElement, Orientation.HORIZONTAL);
this.terminalInstances.forEach(instance => this._splitPaneContainer.split(instance));
}
}
public get title(): string {
......@@ -390,22 +321,13 @@ export class TerminalTab extends Disposable implements ITerminalTab {
shellLaunchConfig);
// TODO: Should this be pulled from the splitpanes instead? Currently there are 2 sources of truth.
// _terminalInstances is also the order they were created, not the order in which they appear
this._terminalInstances.push(instance);
this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance);
this._initInstanceListeners(instance);
this._setActiveInstance(instance);
if (this._rootSplitPane.instance) {
this._rootSplitPane.orientation = Orientation.HORIZONTAL;
this._rootSplitPane.split(instance);
} else {
// The original branch has already occured, find the inner SplitPane and split it
const activePane = this._findSplitPane(this.activeInstance);
activePane.orientation = Orientation.HORIZONTAL;
activePane.split(instance);
}
if (this._tabElement) {
this._rootSplitPane.render(this._tabElement);
if (this._splitPaneContainer) {
this._splitPaneContainer.split(instance, this._activeInstanceIndex);
}
this._setActiveInstance(instance);
return instance;
}
......@@ -415,67 +337,16 @@ export class TerminalTab extends Disposable implements ITerminalTab {
}
public layout(width: number, height: number): void {
this._rootSplitPane.layoutBox(width, height);
}
public focusDirection(direction: Direction): void {
const activeInstance = this.activeInstance;
if (!activeInstance) {
return null;
}
const desiredOrientation = directionOrientation[direction];
const isUpOrLeft = direction === Direction.Left || direction === Direction.Up;
// Find the closest horizontal SplitPane ancestor with a child to the left
let closestHorizontalPane: SplitPane = null;
const panePath = this._findSplitPanePath(activeInstance);
let index = panePath.length - 1;
let ancestorIndex: number;
while (--index >= 0) {
const pane = panePath[index];
// Continue up the path if not the desired orientation
if (pane.orientation !== desiredOrientation) {
continue;
}
// Find index of the panePath pane and break out of loop if it's not the left-most child
ancestorIndex = pane.children.indexOf(panePath[index + 1]);
// Make sure that the pane is not on the boundary
if (isUpOrLeft) {
if (ancestorIndex > 0) {
closestHorizontalPane = pane;
break;
}
} else {
if (ancestorIndex < pane.children.length - 1) {
closestHorizontalPane = pane;
break;
}
}
}
// There are no panes to the left
if (!closestHorizontalPane) {
return;
if (this._splitPaneContainer) {
this._splitPaneContainer.layoutBox(width, height);
}
}
let current: SplitPane;
if (isUpOrLeft) {
// Find the bottom/right-most instance
current = closestHorizontalPane.children[ancestorIndex - 1];
while (current.children && current.children.length > 0) {
current = current.children[current.children.length - 1];
}
} else {
// Find the top/left-most instance
current = closestHorizontalPane.children[ancestorIndex + 1];
while (current.children && current.children.length > 0) {
current = current.children[0];
}
}
public focusPreviousPane(): void {
this.setActiveInstanceByIndex(this._activeInstanceIndex - 1);
}
// Focus the instance to the left
current.instance.focus();
public focusNextPane(): void {
this.setActiveInstanceByIndex(this._activeInstanceIndex + 1);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册