提交 38f87ec0 编写于 作者: D Daniel Imms

Make terminal pane focus directional generic, add up/down

上级 e0404c55
......@@ -182,6 +182,13 @@ 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[];
......@@ -189,8 +196,7 @@ export interface ITerminalTab {
onDisposed: Event<ITerminalTab>;
onInstancesChanged: Event<void>;
focusLeft(): void;
focusRight(): void;
focusDirection(direction: Direction): void;
setActiveInstanceByIndex(index: number): void;
attachToElement(element: HTMLElement): void;
setVisible(visible: boolean): void;
......
......@@ -18,7 +18,7 @@ import { TERMINAL_DEFAULT_SHELL_UNIX_LIKE, TERMINAL_DEFAULT_SHELL_WINDOWS } 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 } 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, FocusTerminalLeftAction, FocusTerminalRightAction, FocusTerminalUpAction, FocusTerminalDownAction } 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';
......@@ -424,6 +424,14 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(FocusTerminalRig
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 To Down', 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 To Up', 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 } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalService, TERMINAL_PANEL_ID, ITerminalInstance, Direction } 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';
......@@ -317,12 +317,10 @@ export class SplitVerticalTerminalAction extends Action {
}
}
export class FocusTerminalLeftAction extends Action {
public static readonly ID = 'workbench.action.terminal.focusTerminalLeft';
public static readonly LABEL = nls.localize('workbench.action.terminal.focusTerminalLeft', "Focus terminal to the left");
export abstract class BaseFocusDirectionTerminalAction extends Action {
constructor(
id: string, label: string,
private _direction: Direction,
@ITerminalService private _terminalService: ITerminalService
) {
super(id, label);
......@@ -333,29 +331,44 @@ export class FocusTerminalLeftAction extends Action {
if (!tab) {
return TPromise.as(void 0);
}
tab.focusLeft();
tab.focusDirection(this._direction);
return this._terminalService.showPanel(true);
}
}
export class FocusTerminalRightAction extends Action {
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");
constructor(
id: string, label: string,
@ITerminalService private _terminalService: ITerminalService
) {
super(id, label);
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Right, terminalService);
}
}
public run(event?: any): TPromise<any> {
const tab = this._terminalService.getActiveTab();
if (!tab) {
return TPromise.as(void 0);
}
tab.focusRight();
return this._terminalService.showPanel(true);
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 to the up");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Up, terminalService);
}
}
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 to the down");
constructor(id: string, label: string, @ITerminalService terminalService: ITerminalService) {
super(id, label, Direction.Down, terminalService);
}
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITerminalInstance, IShellLaunchConfig, ITerminalTab } from 'vs/workbench/parts/terminal/common/terminal';
import { ITerminalInstance, IShellLaunchConfig, ITerminalTab, Direction } 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';
......@@ -172,6 +172,13 @@ class RootSplitPane extends SplitPane {
}
}
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;
......@@ -203,9 +210,8 @@ export class TerminalTab extends Disposable implements ITerminalTab {
undefined,
shellLaunchConfig);
this._terminalInstances.push(instance);
this._initInstanceListeners(instance);
this._activeInstanceIndex = 0;
instance.addDisposable(instance.onDisposed(instance => this._onInstanceDisposed(instance)));
instance.addDisposable(instance.onFocused(instance => this._setActiveInstance(instance)));
this._rootSplitPane = new RootSplitPane();
this._rootSplitPane.instance = instance;
......@@ -232,6 +238,11 @@ export class TerminalTab extends Disposable implements ITerminalTab {
return this._terminalInstances[this._activeInstanceIndex];
}
private _initInstanceListeners(instance: ITerminalInstance): void {
instance.addDisposable(instance.onDisposed(instance => this._onInstanceDisposed(instance)));
instance.addDisposable(instance.onFocused(instance => this._setActiveInstance(instance)));
}
private _onInstanceDisposed(instance: ITerminalInstance): void {
// Get the index of the instance and remove it from the list
const index = this._terminalInstances.indexOf(instance);
......@@ -365,7 +376,7 @@ export class TerminalTab extends Disposable implements ITerminalTab {
undefined,
shellLaunchConfig);
this._terminalInstances.push(instance);
instance.addDisposable(instance.onDisposed(instance => this._onInstanceDisposed(instance)));
this._initInstanceListeners(instance);
if (this._rootSplitPane.instance) {
this._rootSplitPane.orientation = Orientation.HORIZONTAL;
......@@ -391,12 +402,15 @@ export class TerminalTab extends Disposable implements ITerminalTab {
this._rootSplitPane.layoutBox(width, height);
}
public focusLeft(): void {
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);
......@@ -404,16 +418,24 @@ export class TerminalTab extends Disposable implements ITerminalTab {
let ancestorIndex: number;
while (--index >= 0) {
const pane = panePath[index];
// Continue up the path if not horizontal
if (pane.orientation !== Orientation.HORIZONTAL) {
// 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]);
if (ancestorIndex > 0) {
closestHorizontalPane = pane;
break;
// 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;
}
}
}
......@@ -422,18 +444,22 @@ export class TerminalTab extends Disposable implements ITerminalTab {
return;
}
// Find the bottom/right-most instance
let current = closestHorizontalPane.children[ancestorIndex - 1];
while (current.children && current.children.length > 0) {
current = current.children[current.children.length - 1];
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];
}
}
// Focus the instance to the left
current.instance.focus();
}
public focusRight(): void {
// TODO: Do a proper implementation for > 2 instances, make focusLeft more generic
this.setActiveInstanceByIndex(1);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册