提交 f54be931 编写于 作者: B Benjamin Pasero 提交者: GitHub

Merge pull request #22005 from misoguy/feature/navigation

Add Command for navigating around visible editors/viewlets/repl
......@@ -843,8 +843,8 @@ export interface IEditorStacksModel {
positionOfGroup(group: IEditorGroup): Position;
groupAt(position: Position): IEditorGroup;
next(jumpGroups: boolean): IEditorIdentifier;
previous(jumpGroups: boolean): IEditorIdentifier;
next(jumpGroups: boolean, cycleAtEnd?: boolean): IEditorIdentifier;
previous(jumpGroups: boolean, cycleAtStart?: boolean): IEditorIdentifier;
isOpen(editor: IEditorInput): boolean;
isOpen(resource: URI): boolean;
......
......@@ -975,7 +975,7 @@ export class EditorStacksModel implements IEditorStacksModel {
return this._groups[position];
}
public next(jumpGroups: boolean): IEditorIdentifier {
public next(jumpGroups: boolean, cycleAtEnd = true): IEditorIdentifier {
this.ensureLoaded();
if (!this.activeGroup) {
......@@ -991,6 +991,9 @@ export class EditorStacksModel implements IEditorStacksModel {
// Return first if we are not jumping groups
if (!jumpGroups) {
if (!cycleAtEnd) {
return null;
}
return { group: this.activeGroup, editor: this.activeGroup.getEditor(0) };
}
......@@ -1001,12 +1004,17 @@ export class EditorStacksModel implements IEditorStacksModel {
return { group: nextGroup, editor: nextGroup.getEditor(0) };
}
// Return null if we are not cycling at the end
if (!cycleAtEnd) {
return null;
}
// Return first in first group
const firstGroup = this.groups[0];
return { group: firstGroup, editor: firstGroup.getEditor(0) };
}
public previous(jumpGroups: boolean): IEditorIdentifier {
public previous(jumpGroups: boolean, cycleAtStart = true): IEditorIdentifier {
this.ensureLoaded();
if (!this.activeGroup) {
......@@ -1022,6 +1030,9 @@ export class EditorStacksModel implements IEditorStacksModel {
// Return last if we are not jumping groups
if (!jumpGroups) {
if (!cycleAtStart) {
return null;
}
return { group: this.activeGroup, editor: this.activeGroup.getEditor(this.activeGroup.count - 1) };
}
......@@ -1032,6 +1043,11 @@ export class EditorStacksModel implements IEditorStacksModel {
return { group: previousGroup, editor: previousGroup.getEditor(previousGroup.count - 1) };
}
// Return null if we are not cycling at the start
if (!cycleAtStart) {
return null;
}
// Return last in last group
const lastGroup = this.groups[this.groups.length - 1];
return { group: lastGroup, editor: lastGroup.getEditor(lastGroup.count - 1) };
......
......@@ -30,6 +30,10 @@ import * as browser from 'vs/base/browser/browser';
import { IIntegrityService } from 'vs/platform/integrity/common/integrity';
import { IEntryRunContext } from 'vs/base/parts/quickopen/common/quickOpen';
import { ITimerService, IStartupMetrics } from 'vs/workbench/services/timer/common/timerService';
import { IEditorGroupService } from 'vs/workbench/services/group/common/groupService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IPartService, Parts, Position as SidebarPosition } from 'vs/workbench/services/part/common/partService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import * as os from 'os';
import { webFrame } from 'electron';
......@@ -918,4 +922,269 @@ export class ToggleSharedProcessAction extends Action {
run(): TPromise<void> {
return this.windowsService.toggleSharedProcess();
}
}
\ No newline at end of file
}
enum Direction {
Next,
Previous,
}
export abstract class BaseNavigationAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupService protected groupService: IEditorGroupService,
@IPanelService protected panelService: IPanelService,
@IPartService protected partService: IPartService,
@IViewletService protected viewletService: IViewletService
) {
super(id, label);
}
public run(): TPromise<any> {
const isEditorFocus = this.partService.hasFocus(Parts.EDITOR_PART);
const isPanelFocus = this.partService.hasFocus(Parts.PANEL_PART);
const isSidebarFocus = this.partService.hasFocus(Parts.SIDEBAR_PART);
const isEditorGroupVertical = this.groupService.getGroupOrientation() === 'vertical';
const isSidebarPositionLeft = this.partService.getSideBarPosition() === SidebarPosition.LEFT;
if (isEditorFocus) {
return this.navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft);
}
if (isPanelFocus) {
return this.navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft);
}
if (isSidebarFocus) {
return this.navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft);
}
return TPromise.as(false);
}
protected navigateOnEditorFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
return TPromise.as(true);
}
protected navigateOnPanelFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
return TPromise.as(true);
}
protected navigateOnSidebarFocus(isEditorGroupVertical: boolean, isSidebarPositionLeft: boolean): TPromise<boolean> {
return TPromise.as(true);
}
protected navigateToPanel(): TPromise<any> {
if (!this.partService.isVisible(Parts.PANEL_PART)) {
return TPromise.as(false);
}
const activePanelId = this.panelService.getActivePanel().getId();
return this.panelService.openPanel(activePanelId, true);
}
protected navigateToSidebar(): TPromise<any> {
if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
return TPromise.as(false);
}
const activeViewletId = this.viewletService.getActiveViewlet().getId();
return this.viewletService.openViewlet(activeViewletId, true);
}
protected navigateAcrossEditorGroup(direction): TPromise<any> {
const model = this.groupService.getStacksModel();
const currentPosition = model.positionOfGroup(model.activeGroup);
const nextPosition = direction === Direction.Next ? currentPosition + 1 : currentPosition - 1;
if (nextPosition < 0 || nextPosition > model.groups.length - 1) {
return TPromise.as(false);
}
this.groupService.focusGroup(nextPosition);
return TPromise.as(true);
}
protected navigateToLastActiveGroup(): TPromise<any> {
const model = this.groupService.getStacksModel();
const lastActiveGroup = model.activeGroup;
this.groupService.focusGroup(lastActiveGroup);
return TPromise.as(true);
}
protected navigateToFirstEditorGroup(): TPromise<any> {
this.groupService.focusGroup(0);
return TPromise.as(true);
}
protected navigateToLastEditorGroup(): TPromise<any> {
const model = this.groupService.getStacksModel();
const lastEditorGroupPosition = model.groups.length - 1;
this.groupService.focusGroup(lastEditorGroupPosition);
return TPromise.as(true);
}
}
export class NavigateLeftAction extends BaseNavigationAction {
public static ID = 'workbench.action.navigateLeft';
public static LABEL = nls.localize('navigateLeft', "Move to the View Part on the Left");
constructor(
id: string,
label: string,
@IEditorGroupService groupService: IEditorGroupService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, groupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (!isEditorGroupVertical) {
if (isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(false);
}
return this.navigateAcrossEditorGroup(Direction.Previous)
.then(didNavigate => {
if (!didNavigate && isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(true);
});
}
protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(false);
}
protected navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (isSidebarPositionLeft) {
return TPromise.as(false);
}
if (isEditorGroupVertical) {
return this.navigateToLastEditorGroup();
}
return this.navigateToLastActiveGroup();
}
}
export class NavigateRightAction extends BaseNavigationAction {
public static ID = 'workbench.action.navigateRight';
public static LABEL = nls.localize('navigateRight', "Move to the View Part on the Right");
constructor(
id: string,
label: string,
@IEditorGroupService groupService: IEditorGroupService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, groupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (!isEditorGroupVertical) {
if (!isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(false);
}
return this.navigateAcrossEditorGroup(Direction.Next)
.then(didNavigate => {
if (!didNavigate && !isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(true);
});
}
protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (!isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return TPromise.as(false);
}
protected navigateOnSidebarFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (!isSidebarPositionLeft) {
return TPromise.as(false);
}
if (isEditorGroupVertical) {
return this.navigateToFirstEditorGroup();
}
return this.navigateToLastActiveGroup();
}
}
export class NavigateUpAction extends BaseNavigationAction {
public static ID = 'workbench.action.navigateUp';
public static LABEL = nls.localize('navigateUp', "Move to the View Part Above");
constructor(
id: string,
label: string,
@IEditorGroupService groupService: IEditorGroupService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, groupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (isEditorGroupVertical) {
return TPromise.as(false);
}
return this.navigateAcrossEditorGroup(Direction.Previous);
}
protected navigateOnPanelFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (isEditorGroupVertical) {
return this.navigateToLastActiveGroup();
}
return this.navigateToLastEditorGroup();
}
}
export class NavigateDownAction extends BaseNavigationAction {
public static ID = 'workbench.action.navigateDown';
public static LABEL = nls.localize('navigateDown', "Move to the View Part Below");
constructor(
id: string,
label: string,
@IEditorGroupService groupService: IEditorGroupService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, groupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isEditorGroupVertical, isSidebarPositionLeft): TPromise<boolean> {
if (isEditorGroupVertical) {
return this.navigateToPanel();
}
return this.navigateAcrossEditorGroup(Direction.Next)
.then(didNavigate => {
if (didNavigate) {
return TPromise.as(true);
}
return this.navigateToPanel();
});
}
}
......@@ -13,7 +13,7 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actionRegistry';
import { KeyMod, KeyChord, KeyCode } from 'vs/base/common/keyCodes';
import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform';
import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction } from 'vs/workbench/electron-browser/actions';
import { CloseEditorAction, KeybindingsReferenceAction, OpenDocumentationUrlAction, OpenIntroductoryVideosUrlAction, ReportIssueAction, ReportPerformanceIssueAction, ZoomResetAction, ZoomOutAction, ZoomInAction, ToggleFullScreenAction, ToggleMenuBarAction, CloseFolderAction, CloseWindowAction, SwitchWindow, NewWindowAction, CloseMessagesAction, NavigateUpAction, NavigateDownAction, NavigateLeftAction, NavigateRightAction } from 'vs/workbench/electron-browser/actions';
import { MessagesVisibleContext } from 'vs/workbench/electron-browser/workbench';
import { IJSONSchema } from 'vs/base/common/jsonSchema';
import { registerCommands } from 'vs/workbench/electron-browser/commands';
......@@ -66,6 +66,10 @@ workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(Toggle
if (isWindows || isLinux) {
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory);
}
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, null), 'View: Move to the View Part Above', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, null), 'View: Move to the View Part Below', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, null), 'View: Move to the View Part on the Left', viewCategory);
workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, null), 'View: Move to the View Part on the Right', viewCategory);
// Configuration: Workbench
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
......
......@@ -1461,14 +1461,20 @@ suite('Editor Stacks Model', () => {
model.setActive(group1);
group1.setActive(input1);
let previous = model.previous(true /* jump groups */);
let previous = model.previous(true, false /* jump groups, do NOT cycle at start*/);
assert.equal(previous, null);
previous = model.previous(true /* jump groups */);
assert.equal(previous.group, group2);
assert.equal(previous.editor, input6);
model.setActive(<EditorGroup>previous.group);
(<EditorGroup>previous.group).setActive(<EditorInput>previous.editor);
let next = model.next(true /* jump groups */);
let next = model.next(true, false /* jump groups, do NOT cycle at end */);
assert.equal(next, null);
next = model.next(true /* jump groups */);
assert.equal(next.group, group1);
assert.equal(next.editor, input1);
......@@ -1512,14 +1518,20 @@ suite('Editor Stacks Model', () => {
model.setActive(group1);
group1.setActive(input1);
let previous = model.previous(false /* do NOT jump groups */);
let previous = model.previous(false, false /* do NOT jump groups, do NOT cycle at start*/);
assert.equal(previous, null);
previous = model.previous(false /* do NOT jump groups */);
assert.equal(previous.group, group1);
assert.equal(previous.editor, input3);
model.setActive(<EditorGroup>previous.group);
(<EditorGroup>previous.group).setActive(<EditorInput>previous.editor);
let next = model.next(false /* do NOT jump groups */);
let next = model.next(false, false /* do NOT jump groups, do NOT cycle at end */);
assert.equal(next, null);
next = model.next(false /* do NOT jump groups */);
assert.equal(next.group, group1);
assert.equal(next.editor, input1);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册