Skip to content

Commit

Permalink
and shift F6 to navigate across workbench
Browse files Browse the repository at this point in the history
  • Loading branch information
isidorn committed Apr 15, 2020
1 parent c6dc471 commit 89d725e
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 1 deletion.
58 changes: 58 additions & 0 deletions src/vs/workbench/browser/actions/navigationActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { IPanel } from 'vs/workbench/common/panel';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { Direction } from 'vs/base/browser/ui/grid/grid';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';

abstract class BaseNavigationAction extends Action {

Expand Down Expand Up @@ -200,10 +201,67 @@ class NavigateDownAction extends BaseNavigationAction {
}
}

function findVisibleNeighbour(layoutService: IWorkbenchLayoutService, part: Parts, next: boolean): Parts {
const neighbour = part === Parts.EDITOR_PART ? (next ? Parts.STATUSBAR_PART : Parts.PANEL_PART) : part === Parts.STATUSBAR_PART ? (next ? Parts.SIDEBAR_PART : Parts.EDITOR_PART) :
part === Parts.SIDEBAR_PART ? (next ? Parts.PANEL_PART : Parts.STATUSBAR_PART) : part === Parts.PANEL_PART ? (next ? Parts.EDITOR_PART : Parts.SIDEBAR_PART) : Parts.EDITOR_PART;
if (layoutService.isVisible(neighbour) || neighbour === Parts.EDITOR_PART) {
return neighbour;
}

return findVisibleNeighbour(layoutService, neighbour, next);
}

function focusNextOrPreviousPart(layoutService: IWorkbenchLayoutService, next: boolean): void {
const currentlyFocusedPart = layoutService.hasFocus(Parts.EDITOR_PART) ? Parts.EDITOR_PART : layoutService.hasFocus(Parts.STATUSBAR_PART) ? Parts.STATUSBAR_PART :
layoutService.hasFocus(Parts.SIDEBAR_PART) ? Parts.SIDEBAR_PART : layoutService.hasFocus(Parts.PANEL_PART) ? Parts.PANEL_PART : undefined;
let partToFocus = Parts.EDITOR_PART;
if (currentlyFocusedPart) {
partToFocus = findVisibleNeighbour(layoutService, currentlyFocusedPart, next);
}

layoutService.focusPart(partToFocus);
}

export class FocusNextPart extends Action {
static readonly ID = 'workbench.action.focusNextPart';
static readonly LABEL = nls.localize('focusNextPart', "Focus Next Part");

constructor(
id: string,
label: string,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super(id, label);
}

async run(): Promise<void> {
focusNextOrPreviousPart(this.layoutService, true);
}
}

export class FocusPreviousPart extends Action {
static readonly ID = 'workbench.action.focusPreviousPart';
static readonly LABEL = nls.localize('focusPreviousPart', "Focus Previous Part");

constructor(
id: string,
label: string,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super(id, label);
}

async run(): Promise<void> {
focusNextOrPreviousPart(this.layoutService, false);
}
}

const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
const viewCategory = nls.localize('view', "View");

registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, undefined), 'View: Navigate to the View Above', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, undefined), 'View: Navigate to the View Below', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, undefined), 'View: Navigate to the View on the Left', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, undefined), 'View: Navigate to the View on the Right', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusNextPart, FocusNextPart.ID, FocusNextPart.LABEL, { primary: KeyCode.F6 }), 'View: Focus Next Part', viewCategory);
registry.registerWorkbenchAction(SyncActionDescriptor.create(FocusPreviousPart, FocusPreviousPart.ID, FocusPreviousPart.LABEL, { primary: KeyMod.Shift | KeyCode.F6 }), 'View: Focus Previous Part', viewCategory);
26 changes: 26 additions & 0 deletions src/vs/workbench/browser/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,32 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return !!container && isAncestor(activeElement, container);
}

focusPart(part: Parts): void {
switch (part) {
case Parts.EDITOR_PART:
this.editorGroupService.activeGroup.focus();
break;
case Parts.PANEL_PART:
const activePanel = this.panelService.getActivePanel();
if (activePanel) {
activePanel.focus();
}
break;
case Parts.SIDEBAR_PART:
const activeViewlet = this.viewletService.getActiveViewlet();
if (activeViewlet) {
activeViewlet.focus();
}
break;
default:
// Status Bar, Activity Bar and Title Bar simply pass focus to container
const container = this.getContainer(part);
if (container) {
container.focus();
}
}
}

getContainer(part: Parts): HTMLElement | undefined {
switch (part) {
case Parts.TITLEBAR_PART:
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/browser/parts/statusbar/statusbarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.leftItemsContainer = document.createElement('div');
addClasses(this.leftItemsContainer, 'left-items', 'items-container');
this.element.appendChild(this.leftItemsContainer);
this.element.tabIndex = -1;

// Right items container
this.rightItemsContainer = document.createElement('div');
Expand Down Expand Up @@ -624,6 +625,10 @@ export class StatusbarPart extends Part implements IStatusbarService {
return itemContainer;
}

focus(): void {
this.getContainer();
}

layout(width: number, height: number): void {
super.layout(width, height);
super.layoutContents(width, height);
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/contrib/debug/browser/debugCommands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ export function registerCommands(): void {

KeybindingsRegistry.registerCommandAndKeybindingRule({
id: PAUSE_ID,
weight: KeybindingWeight.WorkbenchContrib,
weight: KeybindingWeight.WorkbenchContrib + 2, // take priority over focus next part while we are debugging
primary: KeyCode.F6,
when: CONTEXT_DEBUG_STATE.isEqualTo('running'),
handler: (accessor: ServicesAccessor, _: string, context: CallStackContext | unknown) => {
Expand Down
5 changes: 5 additions & 0 deletions src/vs/workbench/services/layout/browser/layoutService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,11 @@ export interface IWorkbenchLayoutService extends ILayoutService {
*/
hasFocus(part: Parts): boolean;

/**
* Focuses the part. If the part is not visible this is a noop.
*/
focusPart(part: Parts): void;

/**
* Returns the parts HTML element, if there is one.
*/
Expand Down
1 change: 1 addition & 0 deletions src/vs/workbench/test/browser/workbenchTestServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,7 @@ export class TestLayoutService implements IWorkbenchLayoutService {

isRestored(): boolean { return true; }
hasFocus(_part: Parts): boolean { return false; }
focusPart(_part: Parts): void { }
hasWindowBorder(): boolean { return false; }
getWindowBorderRadius(): string | undefined { return undefined; }
isVisible(_part: Parts): boolean { return true; }
Expand Down

0 comments on commit 89d725e

Please sign in to comment.