Merge VS Code 1.31.1 (#4283)

This commit is contained in:
Matt Irvine
2019-03-15 13:09:45 -07:00
committed by GitHub
parent 7d31575149
commit 86bac90001
1716 changed files with 53308 additions and 48375 deletions

View File

@@ -45,7 +45,7 @@ export class ActionBarContributor {
/**
* Can return a specific IActionItem to render the given action.
*/
getActionItem(context: any, action: Action): BaseActionItem {
getActionItem(context: any, action: Action): BaseActionItem | null {
return null;
}
}
@@ -54,6 +54,7 @@ export class ActionBarContributor {
* Some predefined scopes to contribute actions to
*/
export const Scope = {
/**
* Actions inside tree widgets.
*/
@@ -81,8 +82,7 @@ export class ContributableActionProvider implements IActionProvider {
const context = this.toContext(tree, element);
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
for (let i = 0; i < contributors.length; i++) {
const contributor = contributors[i];
for (const contributor of contributors) {
if (contributor.hasActions(context)) {
return true;
}
@@ -97,8 +97,7 @@ export class ContributableActionProvider implements IActionProvider {
// Collect Actions
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
for (let i = 0; i < contributors.length; i++) {
const contributor = contributors[i];
for (const contributor of contributors) {
if (contributor.hasActions(context)) {
actions.push(...contributor.getActions(context));
}
@@ -111,8 +110,7 @@ export class ContributableActionProvider implements IActionProvider {
const context = this.toContext(tree, element);
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
for (let i = 0; i < contributors.length; i++) {
const contributor = contributors[i];
for (const contributor of contributors) {
if (contributor.hasSecondaryActions(context)) {
return true;
}
@@ -127,8 +125,7 @@ export class ContributableActionProvider implements IActionProvider {
// Collect Actions
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
for (let i = 0; i < contributors.length; i++) {
const contributor = contributors[i];
for (const contributor of contributors) {
if (contributor.hasSecondaryActions(context)) {
actions.push(...contributor.getSecondaryActions(context));
}
@@ -137,7 +134,7 @@ export class ContributableActionProvider implements IActionProvider {
return prepareActions(actions);
}
getActionItem(tree: ITree, element: any, action: Action): BaseActionItem {
getActionItem(tree: ITree, element: any, action: Action): BaseActionItem | null {
const contributors = this.registry.getActionBarContributors(Scope.VIEWER);
const context = this.toContext(tree, element);
@@ -225,7 +222,7 @@ export interface IActionBarRegistry {
* Goes through all action bar contributors and asks them for contributed action item for
* the provided scope and context.
*/
getActionItemForContext(scope: string, context: any, action: Action): BaseActionItem;
getActionItemForContext(scope: string, context: any, action: Action): BaseActionItem | null;
/**
* Registers an Actionbar contributor. It will be called to contribute actions to all the action bars
@@ -250,7 +247,7 @@ class ActionBarRegistry implements IActionBarRegistry {
this.instantiationService = service;
while (this.actionBarContributorConstructors.length > 0) {
const entry = this.actionBarContributorConstructors.shift();
const entry = this.actionBarContributorConstructors.shift()!;
this.createActionBarContributor(entry.scope, entry.ctor);
}
}
@@ -298,10 +295,9 @@ class ActionBarRegistry implements IActionBarRegistry {
return actions;
}
getActionItemForContext(scope: string, context: any, action: Action): BaseActionItem {
getActionItemForContext(scope: string, context: any, action: Action): BaseActionItem | null {
const contributors = this.getContributors(scope);
for (let i = 0; i < contributors.length; i++) {
const contributor = contributors[i];
for (const contributor of contributors) {
const item = contributor.getActionItem(context, action);
if (item) {
return item;

View File

@@ -0,0 +1,511 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/actions';
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/group/common/editorGroupsService';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { MenuBarVisibility } from 'vs/platform/windows/common/windows';
import { isWindows, isLinux } from 'vs/base/common/platform';
import { IsMacContext } from 'vs/platform/workbench/common/contextkeys';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { InEditorZenModeContext } from 'vs/workbench/common/editor';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
const viewCategory = nls.localize('view', "View");
// --- Toggle Activity Bar
export class ToggleActivityBarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleActivityBarVisibility';
static readonly LABEL = nls.localize('toggleActivityBar', "Toggle Activity Bar Visibility");
private static readonly activityBarVisibleKey = 'workbench.activityBar.visible';
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const visibility = this.partService.isVisible(Parts.ACTIVITYBAR_PART);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, ToggleActivityBarVisibilityAction.LABEL), 'View: Toggle Activity Bar Visibility', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleActivityBarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar")
},
order: 4
});
// --- Toggle Centered Layout
class ToggleCenteredLayout extends Action {
static readonly ID = 'workbench.action.toggleCenteredLayout';
static readonly LABEL = nls.localize('toggleCenteredLayout', "Toggle Centered Layout");
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
this.partService.centerEditorLayout(!this.partService.isEditorLayoutCentered());
return Promise.resolve(null);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCenteredLayout, ToggleCenteredLayout.ID, ToggleCenteredLayout.LABEL), 'View: Toggle Centered Layout', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleCenteredLayout.ID,
title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout")
},
order: 3
});
// --- Toggle Editor Layout
export class ToggleEditorLayoutAction extends Action {
static readonly ID = 'workbench.action.toggleEditorGroupLayout';
static readonly LABEL = nls.localize('flipLayout', "Toggle Vertical/Horizontal Editor Layout");
private toDispose: IDisposable[];
constructor(
id: string,
label: string,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
this.toDispose = [];
this.class = 'flip-editor-layout';
this.updateEnablement();
this.registerListeners();
}
private registerListeners(): void {
this.toDispose.push(this.editorGroupService.onDidAddGroup(() => this.updateEnablement()));
this.toDispose.push(this.editorGroupService.onDidRemoveGroup(() => this.updateEnablement()));
}
private updateEnablement(): void {
this.enabled = this.editorGroupService.count > 1;
}
run(): Promise<any> {
const newOrientation = (this.editorGroupService.orientation === GroupOrientation.VERTICAL) ? GroupOrientation.HORIZONTAL : GroupOrientation.VERTICAL;
this.editorGroupService.setGroupOrientation(newOrientation);
return Promise.resolve(null);
}
dispose(): void {
this.toDispose = dispose(this.toDispose);
super.dispose();
}
}
CommandsRegistry.registerCommand('_workbench.editor.setGroupOrientation', function (accessor: ServicesAccessor, args: [GroupOrientation]) {
const editorGroupService = accessor.get(IEditorGroupsService);
const [orientation] = args;
editorGroupService.setGroupOrientation(orientation);
return Promise.resolve(null);
});
const group = viewCategory;
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Flip Editor Group Layout', group);
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: 'z_flip',
command: {
id: ToggleEditorLayoutAction.ID,
title: nls.localize({ key: 'miToggleEditorLayout', comment: ['&& denotes a mnemonic'] }, "Flip &&Layout")
},
order: 1
});
// --- Toggle Sidebar Position
export class ToggleSidebarPositionAction extends Action {
static readonly ID = 'workbench.action.toggleSidebarPosition';
static readonly LABEL = nls.localize('toggleSidebarPosition', "Toggle Side Bar Position");
private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService && !!this.configurationService;
}
run(): Promise<any> {
const position = this.partService.getSideBarPosition();
const newPositionValue = (position === Position.LEFT) ? 'right' : 'left';
return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER);
}
static getLabel(partService: IPartService): string {
return partService.getSideBarPosition() === Position.LEFT ? nls.localize('moveSidebarRight', "Move Side Bar Right") : nls.localize('moveSidebarLeft', "Move Side Bar Left");
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right")
},
order: 2
});
// --- Toggle Sidebar Visibility
export class ToggleEditorVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleEditorVisibility';
static readonly LABEL = nls.localize('toggleEditor', "Toggle Editor Area");
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const hideEditor = this.partService.isVisible(Parts.EDITOR_PART);
this.partService.setEditorHidden(hideEditor);
return Promise.resolve(null);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorVisibilityAction, ToggleEditorVisibilityAction.ID, ToggleEditorVisibilityAction.LABEL), 'View: Toggle Editor Area Visibility', viewCategory, ContextKeyExpr.equals('config.workbench.useExperimentalGridLayout', true));
export class ToggleSidebarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleSidebarVisibility';
static readonly LABEL = nls.localize('toggleSidebar', "Toggle Side Bar Visibility");
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const hideSidebar = this.partService.isVisible(Parts.SIDEBAR_PART);
this.partService.setSideBarHidden(hideSidebar);
return Promise.resolve(null);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarVisibilityAction, ToggleSidebarVisibilityAction.ID, ToggleSidebarVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_B }), 'View: Toggle Side Bar Visibility', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar")
},
order: 1
});
// --- Toggle Statusbar Visibility
class ToggleStatusbarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleStatusbarVisibility';
static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility");
private static readonly statusbarVisibleKey = 'workbench.statusBar.visible';
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const visibility = this.partService.isVisible(Parts.STATUSBAR_PART);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, ToggleStatusbarVisibilityAction.LABEL), 'View: Toggle Status Bar Visibility', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleStatusbarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar")
},
order: 3
});
// --- Toggle Tabs Visibility
class ToggleTabsVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleTabsVisibility';
static readonly LABEL = nls.localize('toggleTabs', "Toggle Tab Visibility");
private static readonly tabsVisibleKey = 'workbench.editor.showTabs';
constructor(
id: string,
label: string,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
}
run(): Promise<any> {
const visibility = this.configurationService.getValue<string>(ToggleTabsVisibilityAction.tabsVisibleKey);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleTabsVisibilityAction.tabsVisibleKey, newVisibilityValue);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W }), 'View: Toggle Tab Visibility', viewCategory);
// --- Toggle Zen Mode
class ToggleZenMode extends Action {
static readonly ID = 'workbench.action.toggleZenMode';
static readonly LABEL = nls.localize('toggleZenMode', "Toggle Zen Mode");
constructor(
id: string,
label: string,
@IPartService private readonly partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
this.partService.toggleZenMode();
return Promise.resolve(null);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleZenMode, ToggleZenMode.ID, ToggleZenMode.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) }), 'View: Toggle Zen Mode', viewCategory);
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleZenMode.ID,
title: nls.localize('miToggleZenMode', "Toggle Zen Mode")
},
order: 2
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'workbench.action.exitZenMode',
weight: KeybindingWeight.EditorContrib - 1000,
handler(accessor: ServicesAccessor) {
const partService = accessor.get(IPartService);
partService.toggleZenMode();
},
when: InEditorZenModeContext,
primary: KeyChord(KeyCode.Escape, KeyCode.Escape)
});
// --- Toggle Menu Bar
export class ToggleMenuBarAction extends Action {
static readonly ID = 'workbench.action.toggleMenuBar';
static LABEL = nls.localize('toggleMenuBar', "Toggle Menu Bar");
private static readonly menuBarVisibilityKey = 'window.menuBarVisibility';
constructor(
id: string,
label: string,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
}
run(): Promise<void> {
let currentVisibilityValue = this.configurationService.getValue<MenuBarVisibility>(ToggleMenuBarAction.menuBarVisibilityKey);
if (typeof currentVisibilityValue !== 'string') {
currentVisibilityValue = 'default';
}
let newVisibilityValue: string;
if (currentVisibilityValue === 'visible' || currentVisibilityValue === 'default') {
newVisibilityValue = 'toggle';
} else {
newVisibilityValue = 'default';
}
this.configurationService.updateValue(ToggleMenuBarAction.menuBarVisibilityKey, newVisibilityValue, ConfigurationTarget.USER);
return Promise.resolve();
}
}
if (isWindows || isLinux) {
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMenuBarAction, ToggleMenuBarAction.ID, ToggleMenuBarAction.LABEL), 'View: Toggle Menu Bar', viewCategory);
}
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleMenuBarAction.ID,
title: nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar")
},
when: IsMacContext.toNegated(),
order: 4
});
// --- Resize View
export abstract class BaseResizeViewAction extends Action {
protected static RESIZE_INCREMENT = 6.5; // This is a media-size percentage
constructor(
id: string,
label: string,
@IPartService protected partService: IPartService
) {
super(id, label);
}
protected resizePart(sizeChange: number): void {
const isEditorFocus = this.partService.hasFocus(Parts.EDITOR_PART);
const isSidebarFocus = this.partService.hasFocus(Parts.SIDEBAR_PART);
const isPanelFocus = this.partService.hasFocus(Parts.PANEL_PART);
let part: Parts | undefined;
if (isSidebarFocus) {
part = Parts.SIDEBAR_PART;
} else if (isPanelFocus) {
part = Parts.PANEL_PART;
} else if (isEditorFocus) {
part = Parts.EDITOR_PART;
}
if (part) {
this.partService.resizePart(part, sizeChange);
}
}
}
export class IncreaseViewSizeAction extends BaseResizeViewAction {
static readonly ID = 'workbench.action.increaseViewSize';
static readonly LABEL = nls.localize('increaseViewSize', "Increase Current View Size");
constructor(
id: string,
label: string,
@IPartService partService: IPartService
) {
super(id, label, partService);
}
run(): Promise<boolean> {
this.resizePart(BaseResizeViewAction.RESIZE_INCREMENT);
return Promise.resolve(true);
}
}
export class DecreaseViewSizeAction extends BaseResizeViewAction {
static readonly ID = 'workbench.action.decreaseViewSize';
static readonly LABEL = nls.localize('decreaseViewSize', "Decrease Current View Size");
constructor(
id: string,
label: string,
@IPartService partService: IPartService
) {
super(id, label, partService);
}
run(): Promise<boolean> {
this.resizePart(-BaseResizeViewAction.RESIZE_INCREMENT);
return Promise.resolve(true);
}
}
registry.registerWorkbenchAction(new SyncActionDescriptor(IncreaseViewSizeAction, IncreaseViewSizeAction.ID, IncreaseViewSizeAction.LABEL, undefined), 'View: Increase Current View Size', viewCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(DecreaseViewSizeAction, DecreaseViewSizeAction.ID, DecreaseViewSizeAction.LABEL, undefined), 'View: Decrease Current View Size', viewCategory);

View File

@@ -0,0 +1,782 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { WorkbenchListFocusContextKey, IListService, WorkbenchListSupportsMultiSelectContextKey, ListWidget, WorkbenchListHasSelectionOrFocus, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService';
import { PagedList } from 'vs/base/browser/ui/list/listPaging';
import { range } from 'vs/base/common/arrays';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { ObjectTree } from 'vs/base/browser/ui/tree/objectTree';
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
import { DataTree } from 'vs/base/browser/ui/tree/dataTree';
import { ITreeNode } from 'vs/base/browser/ui/tree/tree';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
function ensureDOMFocus(widget: ListWidget): void {
// it can happen that one of the commands is executed while
// DOM focus is within another focusable control within the
// list/tree item. therefor we should ensure that the
// list/tree has DOM focus again after the command ran.
if (widget && widget.getHTMLElement() !== document.activeElement) {
widget.domFocus();
}
}
function focusDown(accessor: ServicesAccessor, arg2?: number, loop: boolean = true): void {
const focused = accessor.get(IListService).lastFocusedList;
const count = typeof arg2 === 'number' ? arg2 : 1;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusNext(count);
const listFocus = list.getFocus();
if (listFocus.length) {
list.reveal(listFocus[0]);
}
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.focusNext(count, loop, fakeKeyboardEvent);
const listFocus = tree.getFocus();
if (listFocus.length) {
tree.reveal(listFocus[0]);
}
}
// Tree
else if (focused) {
const tree = focused;
tree.focusNext(count, { origin: 'keyboard' });
tree.reveal(tree.getFocus());
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusDown',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.DownArrow,
mac: {
primary: KeyCode.DownArrow,
secondary: [KeyMod.WinCtrl | KeyCode.KEY_N]
},
handler: (accessor, arg2) => focusDown(accessor, arg2)
});
function expandMultiSelection(focused: List<any> | PagedList<any> | ITree | ObjectTree<any, any> | DataTree<any, any, any> | AsyncDataTree<any, any, any>, previousFocus: any): void {
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
const focus = list.getFocus() ? list.getFocus()[0] : undefined;
const selection = list.getSelection();
if (selection && selection.indexOf(focus) >= 0) {
list.setSelection(selection.filter(s => s !== previousFocus));
} else {
list.setSelection(selection.concat(focus));
}
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const focus = list.getFocus() ? list.getFocus()[0] : undefined;
if (previousFocus === focus) {
return;
}
const selection = list.getSelection();
const fakeKeyboardEvent = new KeyboardEvent('keydown', { shiftKey: true });
if (selection && selection.indexOf(focus) >= 0) {
list.setSelection(selection.filter(s => s !== previousFocus), fakeKeyboardEvent);
} else {
list.setSelection(selection.concat(focus), fakeKeyboardEvent);
}
}
// Tree
else if (focused) {
const tree = focused;
const focus = tree.getFocus();
const selection = tree.getSelection();
if (selection && selection.indexOf(focus) >= 0) {
tree.setSelection(selection.filter(s => s !== previousFocus));
} else {
tree.setSelection(selection.concat(focus));
}
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.expandSelectionDown',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListSupportsMultiSelectContextKey),
primary: KeyMod.Shift | KeyCode.DownArrow,
handler: (accessor, arg2) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
// Focus down first
const previousFocus = list.getFocus() ? list.getFocus()[0] : undefined;
focusDown(accessor, arg2, false);
// Then adjust selection
expandMultiSelection(focused, previousFocus);
}
// Tree
else if (focused) {
const tree = focused;
// Focus down first
const previousFocus = tree.getFocus();
focusDown(accessor, arg2);
// Then adjust selection
expandMultiSelection(focused, previousFocus);
}
}
});
function focusUp(accessor: ServicesAccessor, arg2?: number, loop: boolean = true): void {
const focused = accessor.get(IListService).lastFocusedList;
const count = typeof arg2 === 'number' ? arg2 : 1;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusPrevious(count);
const listFocus = list.getFocus();
if (listFocus.length) {
list.reveal(listFocus[0]);
}
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.focusPrevious(count, loop, fakeKeyboardEvent);
const listFocus = tree.getFocus();
if (listFocus.length) {
tree.reveal(listFocus[0]);
}
}
// Tree
else if (focused) {
const tree = focused;
tree.focusPrevious(count, { origin: 'keyboard' });
tree.reveal(tree.getFocus());
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusUp',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.UpArrow,
mac: {
primary: KeyCode.UpArrow,
secondary: [KeyMod.WinCtrl | KeyCode.KEY_P]
},
handler: (accessor, arg2) => focusUp(accessor, arg2)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.expandSelectionUp',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListSupportsMultiSelectContextKey),
primary: KeyMod.Shift | KeyCode.UpArrow,
handler: (accessor, arg2) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList || focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
// Focus up first
const previousFocus = list.getFocus() ? list.getFocus()[0] : undefined;
focusUp(accessor, arg2, false);
// Then adjust selection
expandMultiSelection(focused, previousFocus);
}
// Tree
else if (focused) {
const tree = focused;
// Focus up first
const previousFocus = tree.getFocus();
focusUp(accessor, arg2);
// Then adjust selection
expandMultiSelection(focused, previousFocus);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.collapse',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.LeftArrow,
mac: {
primary: KeyCode.LeftArrow,
secondary: [KeyMod.CtrlCmd | KeyCode.UpArrow]
},
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// Tree only
if (focused && !(focused instanceof List || focused instanceof PagedList)) {
if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const focusedElements = tree.getFocus();
if (focusedElements.length === 0) {
return;
}
const focus = focusedElements[0];
if (!tree.collapse(focus)) {
const parent = tree.getParentElement(focus);
if (parent) {
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.setFocus([parent], fakeKeyboardEvent);
tree.reveal(parent);
}
}
} else {
const tree = focused;
const focus = tree.getFocus();
tree.collapse(focus).then(didCollapse => {
if (focus && !didCollapse) {
tree.focusParent({ origin: 'keyboard' });
return tree.reveal(tree.getFocus());
}
return undefined;
});
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.expand',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.RightArrow,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// Tree only
if (focused && !(focused instanceof List || focused instanceof PagedList)) {
if (focused instanceof ObjectTree || focused instanceof DataTree) {
// TODO@Joao: instead of doing this here, just delegate to a tree method
const tree = focused;
const focusedElements = tree.getFocus();
if (focusedElements.length === 0) {
return;
}
const focus = focusedElements[0];
if (!tree.expand(focus)) {
const child = tree.getFirstElementChild(focus);
if (child) {
const node = tree.getNode(child);
if (node.visible) {
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.setFocus([child], fakeKeyboardEvent);
tree.reveal(child);
}
}
}
} else if (focused instanceof AsyncDataTree) {
// TODO@Joao: instead of doing this here, just delegate to a tree method
const tree = focused;
const focusedElements = tree.getFocus();
if (focusedElements.length === 0) {
return;
}
const focus = focusedElements[0];
tree.expand(focus).then(didExpand => {
if (focus && !didExpand) {
const child = tree.getFirstElementChild(focus);
if (child) {
const node = tree.getNode(child);
if (node.visible) {
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.setFocus([child], fakeKeyboardEvent);
tree.reveal(child);
}
}
}
});
} else {
const tree = focused;
const focus = tree.getFocus();
tree.expand(focus).then(didExpand => {
if (focus && !didExpand) {
tree.focusFirstChild({ origin: 'keyboard' });
return tree.reveal(tree.getFocus());
}
return undefined;
});
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusPageUp',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.PageUp,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusPreviousPage();
list.reveal(list.getFocus()[0]);
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
list.focusPreviousPage(fakeKeyboardEvent);
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusPreviousPage({ origin: 'keyboard' });
tree.reveal(tree.getFocus());
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusPageDown',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.PageDown,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusNextPage();
list.reveal(list.getFocus()[0]);
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
list.focusNextPage(fakeKeyboardEvent);
list.reveal(list.getFocus()[0]);
}
// Tree
else if (focused) {
const tree = focused;
tree.focusNextPage({ origin: 'keyboard' });
tree.reveal(tree.getFocus());
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusFirst',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.Home,
handler: accessor => listFocusFirst(accessor)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusFirstChild',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: 0,
handler: accessor => listFocusFirst(accessor, { fromFocused: true })
});
function listFocusFirst(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
const focused = accessor.get(IListService).lastFocusedList;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.setFocus([0]);
list.reveal(0);
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.focusFirst(fakeKeyboardEvent);
const focus = tree.getFocus();
if (focus.length > 0) {
tree.reveal(focus[0]);
}
}
// Tree
else if (focused) {
const tree = focused;
tree.focusFirst({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : undefined);
tree.reveal(tree.getFocus());
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusLast',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.End,
handler: accessor => listFocusLast(accessor)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusLastChild',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: 0,
handler: accessor => listFocusLast(accessor, { fromFocused: true })
});
function listFocusLast(accessor: ServicesAccessor, options?: { fromFocused: boolean }): void {
const focused = accessor.get(IListService).lastFocusedList;
// Ensure DOM Focus
ensureDOMFocus(focused);
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.setFocus([list.length - 1]);
list.reveal(list.length - 1);
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.focusLast(fakeKeyboardEvent);
const focus = tree.getFocus();
if (focus.length > 0) {
tree.reveal(focus[0]);
}
}
// Tree
else if (focused) {
const tree = focused;
tree.focusLast({ origin: 'keyboard' }, options && options.fromFocused ? tree.getFocus() : undefined);
tree.reveal(tree.getFocus());
}
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.select',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.Enter,
mac: {
primary: KeyCode.Enter,
secondary: [KeyMod.CtrlCmd | KeyCode.DownArrow]
},
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.setSelection(list.getFocus());
list.open(list.getFocus());
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = getSelectionKeyboardEvent('keydown', false);
list.setSelection(list.getFocus(), fakeKeyboardEvent);
list.open(list.getFocus());
}
// Tree
else if (focused) {
const tree = focused;
const focus = tree.getFocus();
if (focus) {
tree.setSelection([focus], { origin: 'keyboard' });
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.selectAll',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListSupportsMultiSelectContextKey),
primary: KeyMod.CtrlCmd | KeyCode.KEY_A,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.setSelection(range(list.length));
}
// Trees
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const focus = tree.getFocus();
const selection = tree.getSelection();
// Which element should be considered to start selecting all?
let start: any | undefined = undefined;
if (focus.length > 0 && (selection.length === 0 || selection.indexOf(focus[0]) === -1)) {
start = focus[0];
}
if (!start && selection.length > 0) {
start = selection[0];
}
// What is the scope of select all?
let scope: any | undefined = undefined;
if (!start) {
scope = undefined;
} else {
const selectedNode = tree.getNode(start);
const parentNode = selectedNode.parent;
if (!parentNode.parent) { // root
scope = undefined;
} else {
scope = parentNode.element;
}
}
const newSelection: any[] = [];
const visit = (node: ITreeNode<any, any>) => {
for (const child of node.children) {
if (child.visible) {
newSelection.push(child.element);
if (!child.collapsed) {
visit(child);
}
}
}
};
// Add the whole scope subtree to the new selection
visit(tree.getNode(scope));
// If the scope isn't the tree root, it should be part of the new selection
if (scope && selection.length === newSelection.length) {
newSelection.unshift(scope);
}
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.setSelection(newSelection, fakeKeyboardEvent);
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.toggleExpand',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
primary: KeyCode.Space,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// Tree only
if (focused && !(focused instanceof List || focused instanceof PagedList)) {
if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
const focus = tree.getFocus();
if (focus.length === 0) {
return;
}
tree.toggleCollapsed(focus[0]);
} else {
const tree = focused;
const focus = tree.getFocus();
if (focus) {
tree.toggleExpansion(focus);
}
}
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.clear',
weight: KeybindingWeight.WorkbenchContrib,
when: ContextKeyExpr.and(WorkbenchListFocusContextKey, WorkbenchListHasSelectionOrFocus),
primary: KeyCode.Escape,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
if (list.getSelection().length > 0) {
list.setSelection([]);
} else if (list.getFocus().length > 0) {
list.setFocus([]);
}
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
if (list.getSelection().length > 0) {
list.setSelection([], fakeKeyboardEvent);
} else if (list.getFocus().length > 0) {
list.setFocus([], fakeKeyboardEvent);
}
}
// Tree
else if (focused) {
const tree = focused;
if (tree.getSelection().length) {
tree.clearSelection({ origin: 'keyboard' });
} else if (tree.getFocus()) {
tree.clearFocus({ origin: 'keyboard' });
}
}
}
});
CommandsRegistry.registerCommand({
id: 'list.toggleKeyboardNavigation',
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
// TODO@joao
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
tree.toggleKeyboardNavigation();
}
}
});
CommandsRegistry.registerCommand({
id: 'list.toggleFilterOnType',
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
// List
if (focused instanceof List || focused instanceof PagedList) {
// TODO@joao
}
// ObjectTree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const tree = focused;
tree.updateOptions({ filterOnType: !tree.filterOnType });
}
}
});

View File

@@ -0,0 +1,272 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { IEditorGroupsService, GroupDirection, GroupLocation, IFindGroupScope } from 'vs/workbench/services/group/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IPartService, Parts, Position as PartPosition } from 'vs/workbench/services/part/common/partService';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IPanel } from 'vs/workbench/common/panel';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
abstract class BaseNavigationAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService protected editorGroupService: IEditorGroupsService,
@IPanelService protected panelService: IPanelService,
@IPartService protected partService: IPartService,
@IViewletService protected viewletService: IViewletService
) {
super(id, label);
}
run(): Promise<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 isSidebarPositionLeft = this.partService.getSideBarPosition() === PartPosition.LEFT;
const isPanelPositionDown = this.partService.getPanelPosition() === PartPosition.BOTTOM;
if (isEditorFocus) {
return this.navigateOnEditorFocus(isSidebarPositionLeft, isPanelPositionDown);
}
if (isPanelFocus) {
return this.navigateOnPanelFocus(isSidebarPositionLeft, isPanelPositionDown);
}
if (isSidebarFocus) {
return Promise.resolve(this.navigateOnSidebarFocus(isSidebarPositionLeft, isPanelPositionDown));
}
return Promise.resolve(false);
}
protected navigateOnEditorFocus(_isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): Promise<boolean | IViewlet | IPanel> {
return Promise.resolve(true);
}
protected navigateOnPanelFocus(_isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): Promise<boolean | IPanel> {
return Promise.resolve(true);
}
protected navigateOnSidebarFocus(_isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): boolean | IViewlet {
return true;
}
protected navigateToPanel(): IPanel | boolean {
if (!this.partService.isVisible(Parts.PANEL_PART)) {
return false;
}
const activePanelId = this.panelService.getActivePanel().getId();
return this.panelService.openPanel(activePanelId, true);
}
protected navigateToSidebar(): Promise<IViewlet | boolean> {
if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
return Promise.resolve(false);
}
const activeViewletId = this.viewletService.getActiveViewlet().getId();
return this.viewletService.openViewlet(activeViewletId, true)
.then(value => value === null ? false : value);
}
protected navigateAcrossEditorGroup(direction: GroupDirection): boolean {
return this.doNavigateToEditorGroup({ direction });
}
protected navigateToEditorGroup(location: GroupLocation): boolean {
return this.doNavigateToEditorGroup({ location });
}
private doNavigateToEditorGroup(scope: IFindGroupScope): boolean {
const targetGroup = this.editorGroupService.findGroup(scope, this.editorGroupService.activeGroup);
if (targetGroup) {
targetGroup.focus();
return true;
}
return false;
}
}
class NavigateLeftAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateLeft';
static readonly LABEL = nls.localize('navigateLeft', "Navigate to the View on the Left");
constructor(
id: string,
label: string,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, editorGroupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): Promise<boolean | IViewlet> {
const didNavigate = this.navigateAcrossEditorGroup(GroupDirection.LEFT);
if (didNavigate) {
return Promise.resolve(true);
}
if (isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return Promise.resolve(false);
}
protected navigateOnPanelFocus(isSidebarPositionLeft: boolean, isPanelPositionDown: boolean): Promise<boolean | IViewlet> {
if (isPanelPositionDown && isSidebarPositionLeft) {
return this.navigateToSidebar();
}
if (!isPanelPositionDown) {
return Promise.resolve(this.navigateToEditorGroup(GroupLocation.LAST));
}
return Promise.resolve(false);
}
protected navigateOnSidebarFocus(isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): boolean {
if (!isSidebarPositionLeft) {
return this.navigateToEditorGroup(GroupLocation.LAST);
}
return false;
}
}
class NavigateRightAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateRight';
static readonly LABEL = nls.localize('navigateRight', "Navigate to the View on the Right");
constructor(
id: string,
label: string,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, editorGroupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(isSidebarPositionLeft: boolean, isPanelPositionDown: boolean): Promise<boolean | IViewlet | IPanel> {
const didNavigate = this.navigateAcrossEditorGroup(GroupDirection.RIGHT);
if (didNavigate) {
return Promise.resolve(true);
}
if (!isPanelPositionDown) {
return Promise.resolve(this.navigateToPanel());
}
if (!isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return Promise.resolve(false);
}
protected navigateOnPanelFocus(isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): Promise<boolean | IViewlet> {
if (!isSidebarPositionLeft) {
return this.navigateToSidebar();
}
return Promise.resolve(false);
}
protected navigateOnSidebarFocus(isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): boolean {
if (isSidebarPositionLeft) {
return this.navigateToEditorGroup(GroupLocation.FIRST);
}
return false;
}
}
class NavigateUpAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateUp';
static readonly LABEL = nls.localize('navigateUp', "Navigate to the View Above");
constructor(
id: string,
label: string,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, editorGroupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(_isSidebarPositionLeft: boolean, _isPanelPositionDown: boolean): Promise<boolean> {
return Promise.resolve(this.navigateAcrossEditorGroup(GroupDirection.UP));
}
protected navigateOnPanelFocus(_isSidebarPositionLeft: boolean, isPanelPositionDown: boolean): Promise<boolean> {
if (isPanelPositionDown) {
return Promise.resolve(this.navigateToEditorGroup(GroupLocation.LAST));
}
return Promise.resolve(false);
}
}
class NavigateDownAction extends BaseNavigationAction {
static readonly ID = 'workbench.action.navigateDown';
static readonly LABEL = nls.localize('navigateDown', "Navigate to the View Below");
constructor(
id: string,
label: string,
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IPanelService panelService: IPanelService,
@IPartService partService: IPartService,
@IViewletService viewletService: IViewletService
) {
super(id, label, editorGroupService, panelService, partService, viewletService);
}
protected navigateOnEditorFocus(_isSidebarPositionLeft: boolean, isPanelPositionDown: boolean): Promise<boolean | IPanel> {
const didNavigate = this.navigateAcrossEditorGroup(GroupDirection.DOWN);
if (didNavigate) {
return Promise.resolve(true);
}
if (isPanelPositionDown) {
return Promise.resolve(this.navigateToPanel());
}
return Promise.resolve(false);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
const viewCategory = nls.localize('view', "View");
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateUpAction, NavigateUpAction.ID, NavigateUpAction.LABEL, undefined), 'View: Navigate to the View Above', viewCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateDownAction, NavigateDownAction.ID, NavigateDownAction.LABEL, undefined), 'View: Navigate to the View Below', viewCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateLeftAction, NavigateLeftAction.ID, NavigateLeftAction.LABEL, undefined), 'View: Navigate to the View on the Left', viewCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateRightAction, NavigateRightAction.ID, NavigateRightAction.LABEL, undefined), 'View: Navigate to the View on the Right', viewCategory);

View File

@@ -1,50 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuId, MenuRegistry } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
export class ToggleActivityBarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleActivityBarVisibility';
static readonly LABEL = nls.localize('toggleActivityBar', "Toggle Activity Bar Visibility");
private static readonly activityBarVisibleKey = 'workbench.activityBar.visible';
constructor(
id: string,
label: string,
@IPartService private partService: IPartService,
@IConfigurationService private configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const visibility = this.partService.isVisible(Parts.ACTIVITYBAR_PART);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleActivityBarVisibilityAction, ToggleActivityBarVisibilityAction.ID, ToggleActivityBarVisibilityAction.LABEL), 'View: Toggle Activity Bar Visibility', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleActivityBarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar")
},
order: 4
});

View File

@@ -1,44 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IPartService } from 'vs/workbench/services/part/common/partService';
class ToggleCenteredLayout extends Action {
static readonly ID = 'workbench.action.toggleCenteredLayout';
static readonly LABEL = nls.localize('toggleCenteredLayout', "Toggle Centered Layout");
constructor(
id: string,
label: string,
@IPartService private partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
this.partService.centerEditorLayout(!this.partService.isEditorLayoutCentered());
return Promise.resolve(null);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleCenteredLayout, ToggleCenteredLayout.ID, ToggleCenteredLayout.LABEL), 'View: Toggle Centered Layout', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleCenteredLayout.ID,
title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout")
},
order: 3
});

View File

@@ -1,83 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/actions';
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/group/common/editorGroupsService';
export class ToggleEditorLayoutAction extends Action {
static readonly ID = 'workbench.action.toggleEditorGroupLayout';
static readonly LABEL = nls.localize('flipLayout', "Toggle Vertical/Horizontal Editor Layout");
private toDispose: IDisposable[];
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
) {
super(id, label);
this.toDispose = [];
this.class = 'flip-editor-layout';
this.updateEnablement();
this.registerListeners();
}
private registerListeners(): void {
this.toDispose.push(this.editorGroupService.onDidAddGroup(() => this.updateEnablement()));
this.toDispose.push(this.editorGroupService.onDidRemoveGroup(() => this.updateEnablement()));
}
private updateEnablement(): void {
this.enabled = this.editorGroupService.count > 1;
}
run(): Promise<any> {
const newOrientation = (this.editorGroupService.orientation === GroupOrientation.VERTICAL) ? GroupOrientation.HORIZONTAL : GroupOrientation.VERTICAL;
this.editorGroupService.setGroupOrientation(newOrientation);
return Promise.resolve(null);
}
dispose(): void {
this.toDispose = dispose(this.toDispose);
super.dispose();
}
}
CommandsRegistry.registerCommand('_workbench.editor.setGroupOrientation', function (accessor: ServicesAccessor, args: [GroupOrientation]) {
const editorGroupService = accessor.get(IEditorGroupsService);
const [orientation] = args;
editorGroupService.setGroupOrientation(orientation);
return Promise.resolve(null);
});
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
const group = nls.localize('view', "View");
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEditorLayoutAction, ToggleEditorLayoutAction.ID, ToggleEditorLayoutAction.LABEL, { primary: KeyMod.Shift | KeyMod.Alt | KeyCode.KEY_0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_0 } }), 'View: Flip Editor Group Layout', group);
MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
group: 'z_flip',
command: {
id: ToggleEditorLayoutAction.ID,
title: nls.localize({ key: 'miToggleEditorLayout', comment: ['&& denotes a mnemonic'] }, "Flip &&Layout")
},
order: 1
});

View File

@@ -1,54 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IPartService, Position } from 'vs/workbench/services/part/common/partService';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
export class ToggleSidebarPositionAction extends Action {
static readonly ID = 'workbench.action.toggleSidebarPosition';
static readonly LABEL = nls.localize('toggleSidebarPosition', "Toggle Side Bar Position");
private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location';
constructor(
id: string,
label: string,
@IPartService private partService: IPartService,
@IConfigurationService private configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService && !!this.configurationService;
}
run(): Promise<any> {
const position = this.partService.getSideBarPosition();
const newPositionValue = (position === Position.LEFT) ? 'right' : 'left';
return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER);
}
static getLabel(partService: IPartService): string {
return partService.getSideBarPosition() === Position.LEFT ? nls.localize('moveSidebarRight', "Move Side Bar Right") : nls.localize('moveSidebarLeft', "Move Side Bar Left");
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleSidebarPositionAction.ID,
title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right")
},
order: 2
});

View File

@@ -1,47 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
export class ToggleSidebarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleSidebarVisibility';
static readonly LABEL = nls.localize('toggleSidebar', "Toggle Side Bar Visibility");
constructor(
id: string,
label: string,
@IPartService private partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Thenable<any> {
const hideSidebar = this.partService.isVisible(Parts.SIDEBAR_PART);
this.partService.setSideBarHidden(hideSidebar);
return Promise.resolve(null);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarVisibilityAction, ToggleSidebarVisibilityAction.ID, ToggleSidebarVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyCode.KEY_B }), 'View: Toggle Side Bar Visibility', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleSidebarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar")
},
order: 1
});

View File

@@ -1,50 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
export class ToggleStatusbarVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleStatusbarVisibility';
static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility");
private static readonly statusbarVisibleKey = 'workbench.statusBar.visible';
constructor(
id: string,
label: string,
@IPartService private partService: IPartService,
@IConfigurationService private configurationService: IConfigurationService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
const visibility = this.partService.isVisible(Parts.STATUSBAR_PART);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, ToggleStatusbarVisibilityAction.LABEL), 'View: Toggle Status Bar Visibility', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '2_workbench_layout',
command: {
id: ToggleStatusbarVisibilityAction.ID,
title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar")
},
order: 3
});

View File

@@ -1,38 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
export class ToggleTabsVisibilityAction extends Action {
static readonly ID = 'workbench.action.toggleTabsVisibility';
static readonly LABEL = nls.localize('toggleTabs', "Toggle Tab Visibility");
private static readonly tabsVisibleKey = 'workbench.editor.showTabs';
constructor(
id: string,
label: string,
@IConfigurationService private configurationService: IConfigurationService
) {
super(id, label);
}
run(): Promise<any> {
const visibility = this.configurationService.getValue<string>(ToggleTabsVisibilityAction.tabsVisibleKey);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleTabsVisibilityAction.tabsVisibleKey, newVisibilityValue);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleTabsVisibilityAction, ToggleTabsVisibilityAction.ID, ToggleTabsVisibilityAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.WinCtrl | KeyCode.KEY_W }), 'View: Toggle Tab Visibility', nls.localize('view', "View"));

View File

@@ -1,45 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes';
import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IPartService } from 'vs/workbench/services/part/common/partService';
class ToggleZenMode extends Action {
static readonly ID = 'workbench.action.toggleZenMode';
static readonly LABEL = nls.localize('toggleZenMode', "Toggle Zen Mode");
constructor(
id: string,
label: string,
@IPartService private partService: IPartService
) {
super(id, label);
this.enabled = !!this.partService;
}
run(): Promise<any> {
this.partService.toggleZenMode();
return Promise.resolve(null);
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleZenMode, ToggleZenMode.ID, ToggleZenMode.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_Z) }), 'View: Toggle Zen Mode', nls.localize('view', "View"));
MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
group: '1_toggle_view',
command: {
id: ToggleZenMode.ID,
title: nls.localize('miToggleZenMode', "Toggle Zen Mode")
},
order: 2
});

View File

@@ -17,6 +17,7 @@ import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDE
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
export class OpenFileAction extends Action {
@@ -26,12 +27,12 @@ export class OpenFileAction extends Action {
constructor(
id: string,
label: string,
@IFileDialogService private dialogService: IFileDialogService
@IFileDialogService private readonly dialogService: IFileDialogService
) {
super(id, label);
}
run(event?: any, data?: ITelemetryData): Thenable<any> {
run(event?: any, data?: ITelemetryData): Promise<any> {
return this.dialogService.pickFileAndOpen({ forceNewWindow: false, telemetryExtraData: data });
}
}
@@ -44,12 +45,12 @@ export class OpenFolderAction extends Action {
constructor(
id: string,
label: string,
@IFileDialogService private dialogService: IFileDialogService
@IFileDialogService private readonly dialogService: IFileDialogService
) {
super(id, label);
}
run(event?: any, data?: ITelemetryData): Thenable<any> {
run(event?: any, data?: ITelemetryData): Promise<any> {
return this.dialogService.pickFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data });
}
}
@@ -62,12 +63,12 @@ export class OpenFileFolderAction extends Action {
constructor(
id: string,
label: string,
@IFileDialogService private dialogService: IFileDialogService
@IFileDialogService private readonly dialogService: IFileDialogService
) {
super(id, label);
}
run(event?: any, data?: ITelemetryData): Thenable<any> {
run(event?: any, data?: ITelemetryData): Promise<any> {
return this.dialogService.pickFileFolderAndOpen({ forceNewWindow: false, telemetryExtraData: data });
}
}
@@ -80,12 +81,12 @@ export class AddRootFolderAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
return this.commandService.executeCommand(ADD_ROOT_FOLDER_COMMAND_ID);
}
}
@@ -98,14 +99,14 @@ export class GlobalRemoveRootFolderAction extends Action {
constructor(
id: string,
label: string,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@ICommandService private commandService: ICommandService
@IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const state = this.contextService.getWorkbenchState();
// Workspace / Folder
@@ -131,34 +132,31 @@ export class SaveWorkspaceAsAction extends Action {
constructor(
id: string,
label: string,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
@IFileDialogService private dialogService: IFileDialogService
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService,
@IFileDialogService private readonly dialogService: IFileDialogService
) {
super(id, label);
}
run(): Thenable<any> {
return this.getNewWorkspaceConfigPath().then(configPathUri => {
run(): Promise<any> {
return this.getNewWorkspaceConfigPath().then((configPathUri): Promise<void> | void => {
if (configPathUri) {
const configPath = configPathUri.fsPath;
switch (this.contextService.getWorkbenchState()) {
case WorkbenchState.EMPTY:
case WorkbenchState.FOLDER:
const folders = this.contextService.getWorkspace().folders.map(folder => ({ uri: folder.uri }));
return this.workspaceEditingService.createAndEnterWorkspace(folders, configPath);
return this.workspaceEditingService.createAndEnterWorkspace(folders, configPathUri);
case WorkbenchState.WORKSPACE:
return this.workspaceEditingService.saveAndEnterWorkspace(configPath);
return this.workspaceEditingService.saveAndEnterWorkspace(configPathUri);
}
}
return null;
});
}
private getNewWorkspaceConfigPath(): Thenable<URI> {
private getNewWorkspaceConfigPath(): Promise<URI | undefined> {
return this.dialogService.showSaveDialog({
saveLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")),
title: nls.localize('saveWorkspace', "Save Workspace"),
@@ -176,16 +174,42 @@ export class OpenWorkspaceAction extends Action {
constructor(
id: string,
label: string,
@IFileDialogService private dialogService: IFileDialogService
@IFileDialogService private readonly dialogService: IFileDialogService
) {
super(id, label);
}
run(event?: any, data?: ITelemetryData): Thenable<any> {
run(event?: any, data?: ITelemetryData): Promise<any> {
return this.dialogService.pickWorkspaceAndOpen({ telemetryExtraData: data });
}
}
export class CloseWorkspaceAction extends Action {
static readonly ID = 'workbench.action.closeFolder';
static LABEL = nls.localize('closeWorkspace', "Close Workspace");
constructor(
id: string,
label: string,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@INotificationService private readonly notificationService: INotificationService,
@IWindowService private readonly windowService: IWindowService
) {
super(id, label);
}
run(): Promise<void> {
if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) {
this.notificationService.info(nls.localize('noWorkspaceOpened', "There is currently no workspace opened in this instance to close."));
return Promise.resolve(undefined);
}
return this.windowService.closeWorkspace();
}
}
export class OpenWorkspaceConfigFileAction extends Action {
static readonly ID = 'workbench.action.openWorkspaceConfigFile';
@@ -194,16 +218,20 @@ export class OpenWorkspaceConfigFileAction extends Action {
constructor(
id: string,
label: string,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IEditorService private editorService: IEditorService
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IEditorService private readonly editorService: IEditorService
) {
super(id, label);
this.enabled = !!this.workspaceContextService.getWorkspace().configuration;
}
run(): Thenable<any> {
return this.editorService.openEditor({ resource: this.workspaceContextService.getWorkspace().configuration });
run(): Promise<any> {
const configuration = this.workspaceContextService.getWorkspace().configuration;
if (configuration) {
return this.editorService.openEditor({ resource: configuration });
}
return Promise.resolve();
}
}
@@ -215,18 +243,18 @@ export class DuplicateWorkspaceInNewWindowAction extends Action {
constructor(
id: string,
label: string,
@IWorkspaceContextService private workspaceContextService: IWorkspaceContextService,
@IWorkspaceEditingService private workspaceEditingService: IWorkspaceEditingService,
@IWindowService private windowService: IWindowService,
@IWorkspacesService private workspacesService: IWorkspacesService
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IWorkspaceEditingService private readonly workspaceEditingService: IWorkspaceEditingService,
@IWindowService private readonly windowService: IWindowService,
@IWorkspacesService private readonly workspacesService: IWorkspacesService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const folders = this.workspaceContextService.getWorkspace().folders;
return this.workspacesService.createWorkspace(folders).then(newWorkspace => {
return this.workspacesService.createUntitledWorkspace(folders).then(newWorkspace => {
return this.workspaceEditingService.copyWorkspaceSettings(newWorkspace).then(() => {
return this.windowService.openWindow([URI.file(newWorkspace.configPath)], { forceNewWindow: true });
});

View File

@@ -65,7 +65,7 @@ CommandsRegistry.registerCommand({
canSelectFolders: true,
canSelectMany: true,
defaultUri: dialogsService.defaultFolderPath(Schemas.file)
}).then(folders => {
}).then((folders): Promise<any> | null => {
if (!folders || !folders.length) {
return null;
}
@@ -73,7 +73,7 @@ CommandsRegistry.registerCommand({
// Add and show Files Explorer viewlet
return workspaceEditingService.addFolders(folders.map(folder => ({ uri: folder })))
.then(() => viewletService.openViewlet(viewletService.getDefaultViewletId(), true))
.then(() => void 0);
.then(() => undefined);
});
}
});
@@ -87,26 +87,19 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, function (acc
const folders = contextService.getWorkspace().folders;
if (!folders.length) {
return void 0;
return undefined;
}
const folderPicks = folders.map(folder => {
return {
label: folder.name,
description: labelService.getUriLabel(resources.dirname(folder.uri), { relative: true }),
description: labelService.getUriLabel(resources.dirname(folder.uri)!, { relative: true }),
folder,
iconClasses: getIconClasses(modelService, modeService, folder.uri, FileKind.ROOT_FOLDER)
} as IQuickPickItem;
});
let options: IPickOptions<IQuickPickItem>;
if (args) {
options = args[0];
}
if (!options) {
options = Object.create(null);
}
const options: IPickOptions<IQuickPickItem> = (args ? args[0] : undefined) || Object.create(null);
if (!options.activeItem) {
options.activeItem = folderPicks[0];
@@ -120,18 +113,11 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, function (acc
options.matchOnDescription = true;
}
let token: CancellationToken;
if (args) {
token = args[1];
}
if (!token) {
token = CancellationToken.None;
}
const token: CancellationToken = (args ? args[1] : undefined) || CancellationToken.None;
return quickInputService.pick(folderPicks, options, token).then(pick => {
if (!pick) {
return void 0;
return undefined;
}
return folders[folderPicks.indexOf(pick)];

View File

@@ -32,6 +32,9 @@ export abstract class Composite extends Component implements IComposite {
private readonly _onTitleAreaUpdate: Emitter<void> = this._register(new Emitter<void>());
get onTitleAreaUpdate(): Event<void> { return this._onTitleAreaUpdate.event; }
private readonly _onDidChangeVisibility: Emitter<boolean> = this._register(new Emitter<boolean>());
get onDidChangeVisibility(): Event<boolean> { return this._onDidChangeVisibility.event; }
private _onDidFocus: Emitter<void>;
get onDidFocus(): Event<void> {
if (!this._onDidFocus) {
@@ -64,9 +67,6 @@ export abstract class Composite extends Component implements IComposite {
private visible: boolean;
private parent: HTMLElement;
/**
* Create a new composite with the given ID and context.
*/
constructor(
id: string,
private _telemetryService: ITelemetryService,
@@ -78,7 +78,7 @@ export abstract class Composite extends Component implements IComposite {
this.visible = false;
}
getTitle(): string {
getTitle(): string | null {
return null;
}
@@ -122,7 +122,11 @@ export abstract class Composite extends Component implements IComposite {
* If there is a long running opertaion it is fine to have it running in the background asyncly and return before.
*/
setVisible(visible: boolean): void {
this.visible = visible;
if (this.visible !== !!visible) {
this.visible = visible;
this._onDidChangeVisibility.fire(visible);
}
}
/**
@@ -165,7 +169,7 @@ export abstract class Composite extends Component implements IComposite {
* of an action. Returns null to indicate that the action is not rendered through
* an action item.
*/
getActionItem(action: IAction): IActionItem {
getActionItem(action: IAction): IActionItem | null {
return null;
}
@@ -201,7 +205,7 @@ export abstract class Composite extends Component implements IComposite {
/**
* Returns the underlying composite control or null if it is not accessible.
*/
getControl(): ICompositeControl {
getControl(): ICompositeControl | null {
return null;
}
}
@@ -210,24 +214,15 @@ export abstract class Composite extends Component implements IComposite {
* A composite descriptor is a leightweight descriptor of a composite in the workbench.
*/
export abstract class CompositeDescriptor<T extends Composite> {
id: string;
name: string;
cssClass: string;
order: number;
keybindingId: string;
enabled: boolean;
private ctor: IConstructorSignature0<T>;
constructor(ctor: IConstructorSignature0<T>, id: string, name: string, cssClass?: string, order?: number, keybindingId?: string, ) {
this.ctor = ctor;
this.id = id;
this.name = name;
this.cssClass = cssClass;
this.order = order;
this.enabled = true;
this.keybindingId = keybindingId;
}
constructor(
private readonly ctor: IConstructorSignature0<T>,
public readonly id: string,
public readonly name: string,
public readonly cssClass?: string,
public readonly order?: number,
public readonly keybindingId?: string,
) { }
instantiate(instantiationService: IInstantiationService): T {
return instantiationService.createInstance(this.ctor);
@@ -239,6 +234,9 @@ export abstract class CompositeRegistry<T extends Composite> extends Disposable
private readonly _onDidRegister: Emitter<CompositeDescriptor<T>> = this._register(new Emitter<CompositeDescriptor<T>>());
get onDidRegister(): Event<CompositeDescriptor<T>> { return this._onDidRegister.event; }
private readonly _onDidDeregister: Emitter<CompositeDescriptor<T>> = this._register(new Emitter<CompositeDescriptor<T>>());
get onDidDeregister(): Event<CompositeDescriptor<T>> { return this._onDidDeregister.event; }
private composites: CompositeDescriptor<T>[] = [];
protected registerComposite(descriptor: CompositeDescriptor<T>): void {
@@ -250,7 +248,17 @@ export abstract class CompositeRegistry<T extends Composite> extends Disposable
this._onDidRegister.fire(descriptor);
}
getComposite(id: string): CompositeDescriptor<T> {
protected deregisterComposite(id: string): void {
const descriptor = this.compositeById(id);
if (descriptor === null) {
return;
}
this.composites.splice(this.composites.indexOf(descriptor), 1);
this._onDidDeregister.fire(descriptor);
}
getComposite(id: string): CompositeDescriptor<T> | null {
return this.compositeById(id);
}
@@ -258,10 +266,10 @@ export abstract class CompositeRegistry<T extends Composite> extends Disposable
return this.composites.slice(0);
}
private compositeById(id: string): CompositeDescriptor<T> {
for (let i = 0; i < this.composites.length; i++) {
if (this.composites[i].id === id) {
return this.composites[i];
private compositeById(id: string): CompositeDescriptor<T> | null {
for (const composite of this.composites) {
if (composite.id === id) {
return composite;
}
}

View File

@@ -15,12 +15,12 @@ import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/un
import { DefaultEndOfLine } from 'vs/editor/common/model';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEditorViewState } from 'vs/editor/common/editorCommon';
import { DataTransfers } from 'vs/base/browser/dnd';
import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { DefaultDragAndDrop } from 'vs/base/parts/tree/browser/treeDefaults';
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { MIME_BINARY } from 'vs/base/common/mime';
import { ITree, IDragAndDropData } from 'vs/base/parts/tree/browser/tree';
import { ITree } from 'vs/base/parts/tree/browser/tree';
import { isWindows } from 'vs/base/common/platform';
import { coalesce } from 'vs/base/common/arrays';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -69,8 +69,8 @@ export const CodeDataTransfers = {
FILES: 'CodeFiles'
};
export function extractResources(e: DragEvent, externalOnly?: boolean): (IDraggedResource | IDraggedEditor)[] {
const resources: (IDraggedResource | IDraggedEditor)[] = [];
export function extractResources(e: DragEvent, externalOnly?: boolean): Array<IDraggedResource | IDraggedEditor> {
const resources: Array<IDraggedResource | IDraggedEditor> = [];
if (e.dataTransfer.types.length > 0) {
// Check for window-to-window DND
@@ -82,7 +82,7 @@ export function extractResources(e: DragEvent, externalOnly?: boolean): (IDragge
try {
const draggedEditors = JSON.parse(rawEditorsData) as ISerializedDraggedEditor[];
draggedEditors.forEach(draggedEditor => {
resources.push({ resource: URI.parse(draggedEditor.resource), backupResource: draggedEditor.backupResource ? URI.parse(draggedEditor.backupResource) : void 0, viewState: draggedEditor.viewState, isExternal: false });
resources.push({ resource: URI.parse(draggedEditor.resource), backupResource: draggedEditor.backupResource ? URI.parse(draggedEditor.backupResource) : undefined, viewState: draggedEditor.viewState, isExternal: false });
});
} catch (error) {
// Invalid transfer
@@ -153,15 +153,15 @@ export class ResourcesDropHandler {
constructor(
private options: IResourcesDropHandlerOptions,
@IFileService private fileService: IFileService,
@IWindowsService private windowsService: IWindowsService,
@IWindowService private windowService: IWindowService,
@IWorkspacesService private workspacesService: IWorkspacesService,
@ITextFileService private textFileService: ITextFileService,
@IBackupFileService private backupFileService: IBackupFileService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
@IEditorService private editorService: IEditorService,
@IConfigurationService private configurationService: IConfigurationService
@IFileService private readonly fileService: IFileService,
@IWindowsService private readonly windowsService: IWindowsService,
@IWindowService private readonly windowService: IWindowService,
@IWorkspacesService private readonly workspacesService: IWorkspacesService,
@ITextFileService private readonly textFileService: ITextFileService,
@IBackupFileService private readonly backupFileService: IBackupFileService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
}
@@ -177,7 +177,7 @@ export class ResourcesDropHandler {
// Check for special things being dropped
return this.doHandleDrop(untitledOrFileResources).then(isWorkspaceOpening => {
if (isWorkspaceOpening) {
return void 0; // return early if the drop operation resulted in this window changing to a workspace
return undefined; // return early if the drop operation resulted in this window changing to a workspace
}
// Add external ones to recently open list unless dropped resource is a workspace
@@ -206,7 +206,7 @@ export class ResourcesDropHandler {
});
}
private doHandleDrop(untitledOrFileResources: (IDraggedResource | IDraggedEditor)[]): Thenable<boolean> {
private doHandleDrop(untitledOrFileResources: Array<IDraggedResource | IDraggedEditor>): Promise<boolean> {
// Check for dirty editors being dropped
const resourcesWithBackups: IDraggedEditor[] = untitledOrFileResources.filter(resource => !resource.isExternal && !!(resource as IDraggedEditor).backupResource);
@@ -225,7 +225,7 @@ export class ResourcesDropHandler {
return Promise.resolve(false);
}
private handleDirtyEditorDrop(droppedDirtyEditor: IDraggedEditor): Thenable<boolean> {
private handleDirtyEditorDrop(droppedDirtyEditor: IDraggedEditor): Promise<boolean> {
// Untitled: always ensure that we open a new untitled for each file we drop
if (droppedDirtyEditor.resource.scheme === Schemas.untitled) {
@@ -254,7 +254,7 @@ export class ResourcesDropHandler {
return DefaultEndOfLine.LF;
}
private handleWorkspaceFileDrop(fileOnDiskResources: URI[]): Thenable<boolean> {
private handleWorkspaceFileDrop(fileOnDiskResources: URI[]): Promise<boolean> {
const workspaceResources: { workspaces: URI[], folders: URI[] } = {
workspaces: [],
folders: []
@@ -266,7 +266,7 @@ export class ResourcesDropHandler {
if (extname(fileOnDiskResource.fsPath) === `.${WORKSPACE_EXTENSION}`) {
workspaceResources.workspaces.push(fileOnDiskResource);
return void 0;
return undefined;
}
// Check for Folder
@@ -274,7 +274,7 @@ export class ResourcesDropHandler {
if (stat.isDirectory) {
workspaceResources.folders.push(stat.resource);
}
}, error => void 0);
}, error => undefined);
})).then(_ => {
const { workspaces, folders } = workspaceResources;
@@ -286,7 +286,7 @@ export class ResourcesDropHandler {
// Pass focus to window
this.windowService.focusWindow();
let workspacesToOpen: Thenable<URI[]>;
let workspacesToOpen: Promise<URI[]>;
// Open in separate windows if we drop workspaces or just one folder
if (workspaces.length > 0 || folders.length === 1) {
@@ -295,7 +295,7 @@ export class ResourcesDropHandler {
// Multiple folders: Create new workspace with folders and open
else if (folders.length > 1) {
workspacesToOpen = this.workspacesService.createWorkspace(folders.map(folder => ({ uri: folder }))).then(workspace => [URI.file(workspace.configPath)]);
workspacesToOpen = this.workspacesService.createUntitledWorkspace(folders.map(folder => ({ uri: folder }))).then(workspace => [URI.file(workspace.configPath)]);
}
// Open
@@ -323,7 +323,7 @@ export class SimpleFileResourceDragAndDrop extends DefaultDragAndDrop {
return resource.toString();
}
return void 0;
return undefined;
}
getDragLabel(tree: ITree, elements: any[]): string {
@@ -336,7 +336,7 @@ export class SimpleFileResourceDragAndDrop extends DefaultDragAndDrop {
return basenameOrAuthority(resource);
}
return void 0;
return undefined;
}
onDragStart(tree: ITree, data: IDragAndDropData, originalEvent: DragMouseEvent): void {
@@ -390,8 +390,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
// Try to find editor view state from the visible editors that match given resource
let viewState: IEditorViewState;
const textEditorWidgets = editorService.visibleTextEditorWidgets;
for (let i = 0; i < textEditorWidgets.length; i++) {
const textEditorWidget = textEditorWidgets[i];
for (const textEditorWidget of textEditorWidgets) {
if (isCodeEditor(textEditorWidget)) {
const model = textEditorWidget.getModel();
if (model && model.uri && model.uri.toString() === file.resource.toString()) {
@@ -404,7 +403,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
// Add as dragged editor
draggedEditors.push({
resource: file.resource.toString(),
backupResource: textFileService.isDirty(file.resource) ? backupFileService.toBackupResource(file.resource).toString() : void 0,
backupResource: textFileService.isDirty(file.resource) ? backupFileService.toBackupResource(file.resource).toString() : undefined,
viewState
});
});
@@ -438,8 +437,8 @@ export class LocalSelectionTransfer<T> {
clearData(proto: T): void {
if (this.hasData(proto)) {
this.proto = void 0;
this.data = void 0;
this.proto = undefined;
this.data = undefined;
}
}
@@ -448,7 +447,7 @@ export class LocalSelectionTransfer<T> {
return this.data;
}
return void 0;
return undefined;
}
setData(data: T[], proto: T): void {

View File

@@ -36,12 +36,12 @@ export interface IEditorRegistry {
/**
* Returns the editor descriptor for the given input or null if none.
*/
getEditor(input: EditorInput): IEditorDescriptor;
getEditor(input: EditorInput): IEditorDescriptor | null;
/**
* Returns the editor descriptor for the given identifier or null if none.
*/
getEditorById(editorId: string): IEditorDescriptor;
getEditorById(editorId: string): IEditorDescriptor | null;
/**
* Returns an array of registered editors known to the platform.
@@ -103,15 +103,14 @@ class EditorRegistry implements IEditorRegistry {
this.editors.push(descriptor);
}
getEditor(input: EditorInput): EditorDescriptor {
getEditor(input: EditorInput): EditorDescriptor | null {
const findEditorDescriptors = (input: EditorInput, byInstanceOf?: boolean): EditorDescriptor[] => {
const matchingDescriptors: EditorDescriptor[] = [];
for (let i = 0; i < this.editors.length; i++) {
const editor = this.editors[i];
for (const editor of this.editors) {
const inputDescriptors = <SyncDescriptor<EditorInput>[]>editor[INPUT_DESCRIPTORS_PROPERTY];
for (let j = 0; j < inputDescriptors.length; j++) {
const inputClass = inputDescriptors[j].ctor;
for (const inputDescriptor of inputDescriptors) {
const inputClass = inputDescriptor.ctor;
// Direct check on constructor type (ignores prototype chain)
if (!byInstanceOf && input.constructor === inputClass) {
@@ -155,9 +154,8 @@ class EditorRegistry implements IEditorRegistry {
return null;
}
getEditorById(editorId: string): EditorDescriptor {
for (let i = 0; i < this.editors.length; i++) {
const editor = this.editors[i];
getEditorById(editorId: string): EditorDescriptor | null {
for (const editor of this.editors) {
if (editor.getId() === editorId) {
return editor;
}
@@ -176,8 +174,7 @@ class EditorRegistry implements IEditorRegistry {
getEditorInputs(): any[] {
const inputClasses: any[] = [];
for (let i = 0; i < this.editors.length; i++) {
const editor = this.editors[i];
for (const editor of this.editors) {
const editorInputDescriptors = <SyncDescriptor<EditorInput>[]>editor[INPUT_DESCRIPTORS_PROPERTY];
inputClasses.push(...editorInputDescriptors.map(descriptor => descriptor.ctor));
}

View File

@@ -22,11 +22,13 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Event, Emitter } from 'vs/base/common/event';
import { ILabelService } from 'vs/platform/label/common/label';
import { getIconClasses, getConfiguredLangId } from 'vs/editor/common/services/getIconClasses';
import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export interface IResourceLabel {
export interface IResourceLabelProps {
resource?: uri;
name: string;
description?: string;
resource?: uri;
}
export interface IResourceLabelOptions extends IIconLabelValueOptions {
@@ -34,68 +36,231 @@ export interface IResourceLabelOptions extends IIconLabelValueOptions {
fileDecorations?: { colors: boolean, badges: boolean, data?: IDecorationData };
}
export class ResourceLabel extends IconLabel {
export interface IFileLabelOptions extends IResourceLabelOptions {
hideLabel?: boolean;
hidePath?: boolean;
}
export interface IResourceLabel extends IDisposable {
readonly element: HTMLElement;
readonly onDidRender: Event<void>;
/**
* Most generic way to apply a label with raw information.
*/
setLabel(label?: string, description?: string, options?: IIconLabelValueOptions): void;
/**
* Convinient method to apply a label by passing a resource along.
*
* Note: for file resources consider to use the #setFile() method instead.
*/
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void;
/**
* Convinient method to render a file label based on a resource.
*/
setFile(resource: uri, options?: IFileLabelOptions): void;
/**
* Convinient method to apply a label by passing an editor along.
*/
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void;
/**
* Resets the label to be empty.
*/
clear(): void;
}
export interface IResourceLabelsContainer {
readonly onDidChangeVisibility: Event<boolean>;
}
export const DEFAULT_LABELS_CONTAINER: IResourceLabelsContainer = {
onDidChangeVisibility: Event.None
};
export class ResourceLabels extends Disposable {
private _widgets: ResourceLabelWidget[] = [];
private _labels: IResourceLabel[] = [];
constructor(
container: IResourceLabelsContainer,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IExtensionService private readonly extensionService: IExtensionService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IModelService private readonly modelService: IModelService,
@IDecorationsService private readonly decorationsService: IDecorationsService,
@IThemeService private readonly themeService: IThemeService
) {
super();
this.registerListeners(container);
}
private registerListeners(container: IResourceLabelsContainer): void {
// notify when visibility changes
this._register(container.onDidChangeVisibility(visible => {
this._widgets.forEach(widget => widget.notifyVisibilityChanged(visible));
}));
// notify when extensions are registered with potentially new languages
this._register(this.extensionService.onDidRegisterExtensions(() => this._widgets.forEach(widget => widget.notifyExtensionsRegistered())));
// notify when model mode changes
this._register(this.modelService.onModelModeChanged(e => {
if (!e.model.uri) {
return; // we need the resource to compare
}
if (e.model.uri.scheme === Schemas.file && e.oldModeId === PLAINTEXT_MODE_ID) { // todo@remote does this apply?
return; // ignore transitions in files from no mode to specific mode because this happens each time a model is created
}
this._widgets.forEach(widget => widget.notifyModelModeChanged(e));
}));
// notify when file decoration changes
this._register(this.decorationsService.onDidChangeDecorations(e => this._widgets.forEach(widget => widget.notifyFileDecorationsChanges(e))));
// notify when theme changes
this._register(this.themeService.onThemeChange(() => this._widgets.forEach(widget => widget.notifyThemeChange())));
// notify when files.associations changes
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) {
this._widgets.forEach(widget => widget.notifyFileAssociationsChange());
}
}));
}
get(index: number): IResourceLabel {
return this._labels[index];
}
create(container: HTMLElement, options?: IIconLabelCreationOptions): IResourceLabel {
const widget = this.instantiationService.createInstance(ResourceLabelWidget, container, options);
// Only expose a handle to the outside
const label: IResourceLabel = {
element: widget.element,
onDidRender: widget.onDidRender,
setLabel: (label?: string, description?: string, options?: IIconLabelValueOptions) => widget.setLabel(label, description, options),
setResource: (label: IResourceLabelProps, options?: IResourceLabelOptions) => widget.setResource(label, options),
setEditor: (editor: IEditorInput, options?: IResourceLabelOptions) => widget.setEditor(editor, options),
setFile: (resource: uri, options?: IFileLabelOptions) => widget.setFile(resource, options),
clear: () => widget.clear(),
dispose: () => this.disposeWidget(widget)
};
// Store
this._labels.push(label);
this._widgets.push(widget);
return label;
}
private disposeWidget(widget: ResourceLabelWidget): void {
const index = this._widgets.indexOf(widget);
if (index > -1) {
this._widgets.splice(index, 1);
this._labels.splice(index, 1);
}
dispose(widget);
}
clear(): void {
this._widgets = dispose(this._widgets);
this._labels = [];
}
dispose(): void {
super.dispose();
this.clear();
}
}
/**
* Note: please consider to use ResourceLabels if you are in need
* of more than one label for your widget.
*/
export class ResourceLabel extends ResourceLabels {
private _label: IResourceLabel;
constructor(
container: HTMLElement,
options: IIconLabelCreationOptions,
@IInstantiationService instantiationService: IInstantiationService,
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@IModelService modelService: IModelService,
@IDecorationsService decorationsService: IDecorationsService,
@IThemeService themeService: IThemeService,
@ILabelService labelService: ILabelService
) {
super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService);
this._label = this._register(this.create(container, options));
}
get element(): IResourceLabel {
return this._label;
}
}
enum Redraw {
Basic = 1,
Full = 2
}
class ResourceLabelWidget extends IconLabel {
private _onDidRender = this._register(new Emitter<void>());
get onDidRender(): Event<void> { return this._onDidRender.event; }
private label: IResourceLabel;
private label: IResourceLabelProps;
private options: IResourceLabelOptions;
private computedIconClasses: string[];
private lastKnownConfiguredLangId: string;
private computedPathLabel: string;
private needsRedraw: Redraw;
private isHidden: boolean = false;
constructor(
container: HTMLElement,
options: IIconLabelCreationOptions,
@IExtensionService private extensionService: IExtensionService,
@IConfigurationService private configurationService: IConfigurationService,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService,
@IDecorationsService protected decorationsService: IDecorationsService,
@IThemeService private themeService: IThemeService,
@ILabelService protected labelService: ILabelService
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@IDecorationsService private readonly decorationsService: IDecorationsService,
@ILabelService private readonly labelService: ILabelService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
) {
super(container, options);
this.registerListeners();
}
private registerListeners(): void {
notifyVisibilityChanged(visible: boolean): void {
if (visible === this.isHidden) {
this.isHidden = !visible;
// update when extensions are registered with potentially new languages
this._register(this.extensionService.onDidRegisterExtensions(() => this.render(true /* clear cache */)));
// react to model mode changes
this._register(this.modelService.onModelModeChanged(e => this.onModelModeChanged(e)));
// react to file decoration changes
this._register(this.decorationsService.onDidChangeDecorations(this.onFileDecorationsChanges, this));
// react to theme changes
this._register(this.themeService.onThemeChange(() => this.render(false)));
// react to files.associations changes
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(FILES_ASSOCIATIONS_CONFIG)) {
this.render(true /* clear cache */);
if (visible && this.needsRedraw) {
this.render(this.needsRedraw === Redraw.Basic ? false : true);
this.needsRedraw = undefined;
}
}));
}
}
private onModelModeChanged(e: { model: ITextModel; oldModeId: string; }): void {
notifyModelModeChanged(e: { model: ITextModel; oldModeId: string; }): void {
if (!this.label || !this.label.resource) {
return; // only update if label exists
}
if (!e.model.uri) {
return; // we need the resource to compare
}
if (e.model.uri.scheme === Schemas.file && e.oldModeId === PLAINTEXT_MODE_ID) { // todo@remote does this apply?
return; // ignore transitions in files from no mode to specific mode because this happens each time a model is created
}
if (e.model.uri.toString() === this.label.resource.toString()) {
if (this.lastKnownConfiguredLangId !== e.model.getLanguageIdentifier().language) {
this.render(true); // update if the language id of the model has changed from our last known state
@@ -103,7 +268,7 @@ export class ResourceLabel extends IconLabel {
}
}
private onFileDecorationsChanges(e: IResourceDecorationChangeEvent): void {
notifyFileDecorationsChanges(e: IResourceDecorationChangeEvent): void {
if (!this.options || !this.label || !this.label.resource) {
return;
}
@@ -113,25 +278,37 @@ export class ResourceLabel extends IconLabel {
}
}
setLabel(label: IResourceLabel, options?: IResourceLabelOptions): void {
notifyExtensionsRegistered(): void {
this.render(true);
}
notifyThemeChange(): void {
this.render(false);
}
notifyFileAssociationsChange(): void {
this.render(true);
}
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void {
const hasResourceChanged = this.hasResourceChanged(label, options);
this.label = label;
this.options = options;
if (hasResourceChanged) {
this.computedPathLabel = void 0; // reset path label due to resource change
this.computedPathLabel = undefined; // reset path label due to resource change
}
this.render(hasResourceChanged);
}
private hasResourceChanged(label: IResourceLabel, options: IResourceLabelOptions): boolean {
const newResource = label ? label.resource : void 0;
const oldResource = this.label ? this.label.resource : void 0;
private hasResourceChanged(label: IResourceLabelProps, options: IResourceLabelOptions): boolean {
const newResource = label ? label.resource : undefined;
const oldResource = this.label ? this.label.resource : undefined;
const newFileKind = options ? options.fileKind : void 0;
const oldFileKind = this.options ? this.options.fileKind : void 0;
const newFileKind = options ? options.fileKind : undefined;
const oldFileKind = this.options ? this.options.fileKind : undefined;
if (newFileKind !== oldFileKind) {
return true; // same resource but different kind (file, folder)
@@ -152,17 +329,62 @@ export class ResourceLabel extends IconLabel {
return true;
}
clear(): void {
this.label = void 0;
this.options = void 0;
this.lastKnownConfiguredLangId = void 0;
this.computedIconClasses = void 0;
this.computedPathLabel = void 0;
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void {
this.setResource({
resource: toResource(editor, { supportSideBySide: true }),
name: editor.getName(),
description: editor.getDescription()
}, options);
}
this.setValue();
setFile(resource: uri, options?: IFileLabelOptions): void {
const hideLabel = options && options.hideLabel;
let name: string;
if (!hideLabel) {
if (options && options.fileKind === FileKind.ROOT_FOLDER) {
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
if (workspaceFolder) {
name = workspaceFolder.name;
}
}
if (!name) {
name = resources.basenameOrAuthority(resource);
}
}
let description: string;
const hidePath = (options && options.hidePath) || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource));
if (!hidePath) {
description = this.labelService.getUriLabel(resources.dirname(resource), { relative: true });
}
this.setResource({ resource, name, description }, options);
}
clear(): void {
this.label = undefined;
this.options = undefined;
this.lastKnownConfiguredLangId = undefined;
this.computedIconClasses = undefined;
this.computedPathLabel = undefined;
this.setLabel();
}
private render(clearIconCache: boolean): void {
if (this.isHidden) {
if (!this.needsRedraw) {
this.needsRedraw = clearIconCache ? Redraw.Full : Redraw.Basic;
}
if (this.needsRedraw === Redraw.Basic && clearIconCache) {
this.needsRedraw = Redraw.Full;
}
return;
}
if (this.label) {
const configuredLangId = getConfiguredLangId(this.modelService, this.label.resource);
if (this.lastKnownConfiguredLangId !== configuredLangId) {
@@ -172,7 +394,7 @@ export class ResourceLabel extends IconLabel {
}
if (clearIconCache) {
this.computedIconClasses = void 0;
this.computedIconClasses = undefined;
}
if (!this.label) {
@@ -231,7 +453,7 @@ export class ResourceLabel extends IconLabel {
}
}
this.setValue(label, this.label.description, iconLabelOptions);
this.setLabel(label, this.label.description, iconLabelOptions);
this._onDidRender.fire();
}
@@ -239,70 +461,10 @@ export class ResourceLabel extends IconLabel {
dispose(): void {
super.dispose();
this.label = void 0;
this.options = void 0;
this.lastKnownConfiguredLangId = void 0;
this.computedIconClasses = void 0;
this.computedPathLabel = void 0;
}
}
export class EditorLabel extends ResourceLabel {
setEditor(editor: IEditorInput, options?: IResourceLabelOptions): void {
this.setLabel({
resource: toResource(editor, { supportSideBySide: true }),
name: editor.getName(),
description: editor.getDescription()
}, options);
}
}
export interface IFileLabelOptions extends IResourceLabelOptions {
hideLabel?: boolean;
hidePath?: boolean;
}
export class FileLabel extends ResourceLabel {
constructor(
container: HTMLElement,
options: IIconLabelCreationOptions,
@IExtensionService extensionService: IExtensionService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IConfigurationService configurationService: IConfigurationService,
@IModeService modeService: IModeService,
@IModelService modelService: IModelService,
@IDecorationsService decorationsService: IDecorationsService,
@IThemeService themeService: IThemeService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
@ILabelService labelService: ILabelService
) {
super(container, options, extensionService, configurationService, modeService, modelService, decorationsService, themeService, labelService);
}
setFile(resource: uri, options?: IFileLabelOptions): void {
const hideLabel = options && options.hideLabel;
let name: string;
if (!hideLabel) {
if (options && options.fileKind === FileKind.ROOT_FOLDER) {
const workspaceFolder = this.contextService.getWorkspaceFolder(resource);
if (workspaceFolder) {
name = workspaceFolder.name;
}
}
if (!name) {
name = resources.basenameOrAuthority(resource);
}
}
let description: string;
const hidePath = (options && options.hidePath) || (resource.scheme === Schemas.untitled && !this.untitledEditorService.hasAssociatedFilePath(resource));
if (!hidePath) {
description = this.labelService.getUriLabel(resources.dirname(resource), { relative: true });
}
this.setLabel({ resource, name, description }, options);
this.label = undefined;
this.options = undefined;
this.lastKnownConfiguredLangId = undefined;
this.computedIconClasses = undefined;
this.computedPathLabel = undefined;
}
}

View File

@@ -82,12 +82,12 @@ export class WorkbenchLayout extends Disposable implements IVerticalSashLayoutPr
private quickInput: QuickInputService,
private notificationsCenter: NotificationsCenter,
private notificationsToasts: NotificationsToasts,
@IStorageService private storageService: IStorageService,
@IContextViewService private contextViewService: IContextViewService,
@IPartService private partService: IPartService,
@IViewletService private viewletService: IViewletService,
@IThemeService private themeService: IThemeService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IStorageService private readonly storageService: IStorageService,
@IContextViewService private readonly contextViewService: IContextViewService,
@IPartService private readonly partService: IPartService,
@IViewletService private readonly viewletService: IViewletService,
@IThemeService private readonly themeService: IThemeService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super();

View File

@@ -3,34 +3,34 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .part > .title {
.monaco-workbench .part > .title {
display: none; /* Parts have to opt in to show title area */
}
.monaco-workbench > .part > .title {
.monaco-workbench .part > .title {
height: 35px;
display: flex;
box-sizing: border-box;
overflow: hidden;
}
.monaco-workbench > .part > .title {
.monaco-workbench .part > .title {
padding-left: 8px;
padding-right: 8px;
}
.monaco-workbench > .part > .title > .title-label {
.monaco-workbench .part > .title > .title-label {
line-height: 35px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-workbench > .part > .title > .title-label {
.monaco-workbench .part > .title > .title-label {
padding-left: 12px;
}
.monaco-workbench > .part > .title > .title-label h2 {
.monaco-workbench .part > .title > .title-label h2 {
font-size: 11px;
cursor: default;
font-weight: normal;
@@ -41,19 +41,19 @@
text-overflow: ellipsis;
}
.monaco-workbench > .part > .title > .title-label a {
.monaco-workbench .part > .title > .title-label a {
text-decoration: none;
font-size: 13px;
cursor: default;
}
.monaco-workbench > .part > .title > .title-actions {
.monaco-workbench .part > .title > .title-actions {
height: 35px;
flex: 1;
padding-left: 5px;
}
.monaco-workbench > .part > .title > .title-actions .action-label {
.monaco-workbench .part > .title > .title-actions .action-label {
display: block;
height: 35px;
line-height: 35px;
@@ -63,16 +63,16 @@
background-repeat: no-repeat;
}
.monaco-workbench > .part > .title > .title-actions .action-label .label {
.monaco-workbench .part > .title > .title-actions .action-label .label {
display: none;
}
.monaco-workbench > .part > .content {
.monaco-workbench .part > .content {
font-size: 13px;
}
.monaco-workbench > .part > .content > .monaco-progress-container,
.monaco-workbench > .part.editor > .content .monaco-progress-container {
.monaco-workbench .part > .content > .monaco-progress-container,
.monaco-workbench .part.editor > .content .monaco-progress-container {
position: absolute;
left: 0;
top: 33px; /* at the bottom of the 35px height title container */
@@ -80,7 +80,7 @@
height: 2px;
}
.monaco-workbench > .part > .content > .monaco-progress-container .progress-bit,
.monaco-workbench > .part.editor > .content .monaco-progress-container .progress-bit {
.monaco-workbench .part > .content > .monaco-progress-container .progress-bit,
.monaco-workbench .part.editor > .content .monaco-progress-container .progress-bit {
height: 2px;
}

View File

@@ -34,6 +34,13 @@ export class PanelRegistry extends CompositeRegistry<Panel> {
super.registerComposite(descriptor);
}
/**
* Deregisters a panel to the platform.
*/
deregisterPanel(id: string): void {
super.deregisterComposite(id);
}
/**
* Returns an array of registered panels known to the platform.
*/
@@ -75,7 +82,7 @@ export abstract class TogglePanelAction extends Action {
this.panelId = panelId;
}
run(): Thenable<any> {
run(): Promise<any> {
if (this.isPanelFocused()) {
this.partService.setPanelHidden(true);
} else {
@@ -94,7 +101,7 @@ export abstract class TogglePanelAction extends Action {
private isPanelFocused(): boolean {
const activeElement = document.activeElement;
return this.isPanelActive() && activeElement && isAncestor(activeElement, this.partService.getContainer(Parts.PANEL_PART));
return !!(this.isPanelActive() && activeElement && isAncestor(activeElement, this.partService.getContainer(Parts.PANEL_PART)));
}
}

View File

@@ -36,14 +36,14 @@ export class ViewletActivityAction extends ActivityAction {
constructor(
activity: IActivity,
@IViewletService private viewletService: IViewletService,
@IPartService private partService: IPartService,
@ITelemetryService private telemetryService: ITelemetryService
@IViewletService private readonly viewletService: IViewletService,
@IPartService private readonly partService: IPartService,
@ITelemetryService private readonly telemetryService: ITelemetryService
) {
super(activity);
}
run(event: any): Thenable<any> {
run(event: any): Promise<any> {
if (event instanceof MouseEvent && event.button === 2) {
return Promise.resolve(false); // do not run on right click
}
@@ -84,13 +84,13 @@ export class ToggleViewletAction extends Action {
constructor(
private _viewlet: ViewletDescriptor,
@IPartService private partService: IPartService,
@IViewletService private viewletService: IViewletService
@IPartService private readonly partService: IPartService,
@IViewletService private readonly viewletService: IViewletService
) {
super(_viewlet.id, _viewlet.name);
}
run(): Thenable<any> {
run(): Promise<any> {
const sideBarVisible = this.partService.isVisible(Parts.SIDEBAR_PART);
const activeViewlet = this.viewletService.getActiveViewlet();
@@ -175,7 +175,7 @@ export class PlaceHolderViewletActivityAction extends ViewletActivityAction {
) {
super({ id, name: id, cssClass: `extensionViewlet-placeholder-${id.replace(/\./g, '-')}` }, viewletService, partService, telemetryService);
const iconClass = `.monaco-workbench > .activitybar .monaco-action-bar .action-label.${this.class}`; // Generate Placeholder CSS to show the icon in the activity bar
const iconClass = `.monaco-workbench .activitybar .monaco-action-bar .action-label.${this.class}`; // Generate Placeholder CSS to show the icon in the activity bar
DOM.createCSSRule(iconClass, `-webkit-mask: url('${iconUrl || ''}') no-repeat 50% 50%`);
}
@@ -187,7 +187,7 @@ export class PlaceHolderViewletActivityAction extends ViewletActivityAction {
export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinnedAction {
constructor(id: string, compositeBar: ICompositeBar) {
super({ id, name: id, cssClass: void 0 }, compositeBar);
super({ id, name: id, cssClass: undefined }, compositeBar);
}
setActivity(activity: IActivity): void {
@@ -200,13 +200,13 @@ class SwitchSideBarViewAction extends Action {
constructor(
id: string,
name: string,
@IViewletService private viewletService: IViewletService,
@IActivityService private activityService: IActivityService
@IViewletService private readonly viewletService: IViewletService,
@IActivityService private readonly activityService: IActivityService
) {
super(id, name);
}
run(offset: number): Thenable<any> {
run(offset: number): Promise<any> {
const pinnedViewletIds = this.activityService.getPinnedViewletIds();
const activeViewlet = this.viewletService.getActiveViewlet();
@@ -238,7 +238,7 @@ export class PreviousSideBarViewAction extends SwitchSideBarViewAction {
super(id, name, viewletService, activityService);
}
run(): Thenable<any> {
run(): Promise<any> {
return super.run(-1);
}
}
@@ -257,7 +257,7 @@ export class NextSideBarViewAction extends SwitchSideBarViewAction {
super(id, name, viewletService, activityService);
}
run(): Thenable<any> {
run(): Promise<any> {
return super.run(1);
}
}
@@ -271,9 +271,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const activeForegroundColor = theme.getColor(ACTIVITY_BAR_FOREGROUND);
if (activeForegroundColor) {
collector.addRule(`
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active .action-label,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus .action-label,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover .action-label {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active .action-label,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus .action-label,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover .action-label {
background-color: ${activeForegroundColor} !important;
}
`);
@@ -283,7 +283,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const outline = theme.getColor(activeContrastBorder);
if (outline) {
collector.addRule(`
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:before {
content: "";
position: absolute;
top: 9px;
@@ -292,26 +292,26 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
width: 32px;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:hover:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.checked:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.checked:hover:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:hover:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:hover:before {
outline: 1px solid;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover:before {
outline: 1px dashed;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before {
border-left-color: ${outline};
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.active:hover:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.checked:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.checked:hover:before,
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:hover:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.active:hover:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.checked:hover:before,
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:hover:before {
outline-color: ${outline};
}
`);
@@ -322,7 +322,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const focusBorderColor = theme.getColor(focusBorder);
if (focusBorderColor) {
collector.addRule(`
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before {
border-left-color: ${focusBorderColor};
}
`);

View File

@@ -6,6 +6,7 @@
import 'vs/css!./media/activitybarpart';
import * as nls from 'vs/nls';
import { illegalArgument } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { GlobalActivityExtensions, IGlobalActivityRegistry } from 'vs/workbench/common/activity';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -15,38 +16,39 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { IPartService, Parts, Position as SideBarPosition } from 'vs/workbench/services/part/common/partService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/toggleActivityBarVisibility';
import { IThemeService, registerThemingParticipant, ITheme } from 'vs/platform/theme/common/themeService';
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { ToggleActivityBarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar } from 'vs/workbench/browser/parts/compositeBar';
import { isMacintosh } from 'vs/base/common/platform';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { scheduleAtNextAnimationFrame, Dimension, addClass } from 'vs/base/browser/dom';
import { Color } from 'vs/base/common/color';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar';
import { Dimension, addClass } from 'vs/base/browser/dom';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors } from 'vs/workbench/browser/parts/compositeBarActions';
import { ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IViewsService, IViewContainersRegistry, Extensions as ViewContainerExtensions, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewDescriptorCollection } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
const SCM_VIEWLET_ID = 'workbench.view.scm';
interface ICachedViewlet {
id: string;
iconUrl: URI;
iconUrl: UriComponents;
pinned: boolean;
order: number;
visible: boolean;
views?: { when: string }[];
}
export class ActivitybarPart extends Part {
export class ActivitybarPart extends Part implements ISerializableView {
private static readonly ACTION_HEIGHT = 50;
private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';
private static readonly CACHED_VIEWLETS = 'workbench.activity.placeholderViewlets';
private dimension: Dimension;
@@ -57,23 +59,37 @@ export class ActivitybarPart extends Part {
private compositeBar: CompositeBar;
private compositeActions: { [compositeId: string]: { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } } = Object.create(null);
element: HTMLElement;
minimumWidth: number = 50;
maximumWidth: number = 50;
minimumHeight: number = 0;
maximumHeight: number = Number.POSITIVE_INFINITY;
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
constructor(
id: string,
@IViewletService private viewletService: IViewletService,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private partService: IPartService,
@IViewletService private readonly viewletService: IViewletService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IThemeService themeService: IThemeService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IStorageService private storageService: IStorageService,
@IExtensionService private extensionService: IExtensionService,
@IViewsService private viewsService: IViewsService,
@IContextKeyService private contextKeyService: IContextKeyService
@IStorageService private readonly storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IViewsService private readonly viewsService: IViewsService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
) {
super(id, { hasTitle: false }, themeService, storageService);
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, {
this.cachedViewlets = this.getCachedViewlets();
for (const cachedViewlet of this.cachedViewlets) {
if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) {
cachedViewlet.visible = false;
}
}
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => (<ICompositeBarItem>{ id: v.id, name: undefined, visible: v.visible, order: v.order, pinned: v.pinned })), {
icon: true,
storageId: ActivitybarPart.PINNED_VIEWLETS,
orientation: ActionsOrientation.VERTICAL,
openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true),
getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction,
@@ -87,16 +103,8 @@ export class ActivitybarPart extends Part {
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
}));
const previousState = this.storageService.get(ActivitybarPart.CACHED_VIEWLETS, StorageScope.GLOBAL, '[]');
this.cachedViewlets = (<ICachedViewlet[]>JSON.parse(previousState)).map(({ id, iconUrl, views }) => ({ id, views, iconUrl: typeof iconUrl === 'object' ? URI.revive(iconUrl) : void 0 }));
for (const cachedViewlet of this.cachedViewlets) {
if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) {
this.compositeBar.hideComposite(cachedViewlet.id);
}
}
this.registerListeners();
this.onDidRegisterViewlets(viewletService.getAllViewlets());
this.onDidRegisterViewlets(viewletService.getViewlets());
}
// {{SQL CARBON EDIT}}
@@ -112,35 +120,40 @@ export class ActivitybarPart extends Part {
}
private registerListeners(): void {
this._register(this.viewletService.onDidViewletRegister(viewlet => this.onDidRegisterViewlets([viewlet])));
this._register(this.viewletService.onDidViewletDeregister(({ id }) => this.removeComposite(id, true)));
// Activate viewlet action on opening of a viewlet
this._register(this.viewletService.onDidViewletOpen(viewlet => this.onDidViewletOpen(viewlet)));
// Deactivate viewlet action on close
this._register(this.viewletService.onDidViewletClose(viewlet => this.compositeBar.deactivateComposite(viewlet.getId())));
this._register(this.viewletService.onDidViewletEnablementChange(({ id, enabled }) => {
if (enabled) {
this.compositeBar.addComposite(this.viewletService.getViewlet(id));
} else {
this.removeComposite(id, true);
}
}));
this._register(this.extensionService.onDidRegisterExtensions(() => this.onDidRegisterExtensions()));
let disposables: IDisposable[] = [];
this._register(this.extensionService.onDidRegisterExtensions(() => {
disposables = dispose(disposables);
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedViewlets(), this, disposables);
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
}));
this._register(toDisposable(() => dispose(disposables)));
}
private onDidRegisterExtensions(): void {
this.removeNotExistingComposites();
for (const viewlet of this.viewletService.getAllViewlets()) {
for (const viewlet of this.viewletService.getViewlets()) {
this.enableCompositeActions(viewlet);
const viewContainer = this.getViewContainer(viewlet.id);
if (viewContainer) {
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
this.onDidChangeActiveViews(viewlet, viewDescriptors);
viewDescriptors.onDidChangeActiveViews(() => this.onDidChangeActiveViews(viewlet, viewDescriptors));
if (viewDescriptors) {
this.onDidChangeActiveViews(viewlet, viewDescriptors);
viewDescriptors.onDidChangeActiveViews(() => this.onDidChangeActiveViews(viewlet, viewDescriptors));
}
}
}
this.saveCachedViewlets();
}
private onDidChangeActiveViews(viewlet: ViewletDescriptor, viewDescriptors: IViewDescriptorCollection): void {
@@ -157,9 +170,12 @@ export class ActivitybarPart extends Part {
this.compositeBar.activateComposite(viewlet.getId());
const viewletDescriptor = this.viewletService.getViewlet(viewlet.getId());
const viewContainer = this.getViewContainer(viewletDescriptor.id);
if (viewContainer && this.viewsService.getViewDescriptors(viewContainer).activeViewDescriptors.length === 0) {
// Update the composite bar by hiding
this.removeComposite(viewletDescriptor.id, true);
if (viewContainer) {
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
if (viewDescriptors && viewDescriptors.activeViewDescriptors.length === 0) {
// Update the composite bar by hiding
this.removeComposite(viewletDescriptor.id, true);
}
}
}
@@ -187,6 +203,7 @@ export class ActivitybarPart extends Part {
}
createContentArea(parent: HTMLElement): HTMLElement {
this.element = parent;
const content = document.createElement('div');
addClass(content, 'content');
parent.appendChild(content);
@@ -201,27 +218,6 @@ export class ActivitybarPart extends Part {
this.createGlobalActivityActionBar(globalActivities);
// TODO@Ben: workaround for https://github.com/Microsoft/vscode/issues/45700
// It looks like there are rendering glitches on macOS with Chrome 61 when
// using --webkit-mask with a background color that is different from the image
// The workaround is to promote the element onto its own drawing layer. We do
// this only after the workbench has loaded because otherwise there is ugly flicker.
if (isMacintosh) {
this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
scheduleAtNextAnimationFrame(() => { // another delay...
scheduleAtNextAnimationFrame(() => { // ...to prevent more flickering on startup
registerThemingParticipant((theme, collector) => {
const activityBarForeground = theme.getColor(ACTIVITY_BAR_FOREGROUND);
if (activityBarForeground && !activityBarForeground.equals(Color.white)) {
// only apply this workaround if the color is different from the image one (white)
collector.addRule('.monaco-workbench .activitybar > .content .monaco-action-bar .action-label { will-change: transform; }');
}
});
});
});
});
}
return content;
}
@@ -287,7 +283,7 @@ export class ActivitybarPart extends Part {
} else {
const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0];
compositeActions = {
activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.iconUrl),
activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite ? URI.revive(cachedComposite.iconUrl) : undefined),
pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar)
};
}
@@ -326,8 +322,8 @@ export class ActivitybarPart extends Part {
}
private removeNotExistingComposites(): void {
const viewlets = this.viewletService.getAllViewlets();
for (const { id } of this.compositeBar.getComposites()) {
const viewlets = this.viewletService.getViewlets();
for (const { id } of this.cachedViewlets) {
if (viewlets.every(viewlet => viewlet.id !== id)) {
this.removeComposite(id, false);
}
@@ -366,13 +362,19 @@ export class ActivitybarPart extends Part {
.map(v => v.id);
}
layout(dimension: Dimension): Dimension[] {
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
if (!this.partService.isVisible(Parts.ACTIVITYBAR_PART)) {
return [dimension];
if (dim1 instanceof Dimension) {
return [dim1];
}
return;
}
// Pass to super
const sizes = super.layout(dimension);
const sizes = super.layout(dim1 instanceof Dimension ? dim1 : new Dimension(dim1, dim2));
this.dimension = sizes[1];
@@ -381,26 +383,114 @@ export class ActivitybarPart extends Part {
// adjust height for global actions showing
availableHeight -= (this.globalActionBar.items.length * ActivitybarPart.ACTION_HEIGHT);
}
this.compositeBar.layout(new Dimension(dimension.width, availableHeight));
this.compositeBar.layout(new Dimension(dim1 instanceof Dimension ? dim1.width : dim1, availableHeight));
return sizes;
if (dim1 instanceof Dimension) {
return sizes;
}
}
protected saveState(): void {
const state: ICachedViewlet[] = [];
for (const { id, iconUrl } of this.viewletService.getAllViewlets()) {
const viewContainer = this.getViewContainer(id);
const views: { when: string }[] = [];
if (viewContainer) {
for (const { when } of this.viewsService.getViewDescriptors(viewContainer).allViewDescriptors) {
views.push({ when: when ? when.serialize() : void 0 });
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
if (e.key === ActivitybarPart.PINNED_VIEWLETS && e.scope === StorageScope.GLOBAL
&& this.cachedViewletsValue !== this.getStoredCachedViewletsValue() /* This checks if current window changed the value or not */) {
this._cachedViewletsValue = null;
const newCompositeItems: ICompositeBarItem[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
const cachedViewlets = this.getCachedViewlets();
for (const cachedViewlet of cachedViewlets) {
// Add and update existing items
const existingItem = compositeItems.filter(({ id }) => id === cachedViewlet.id)[0];
if (existingItem) {
newCompositeItems.push({
id: existingItem.id,
name: existingItem.name,
order: existingItem.order,
pinned: cachedViewlet.pinned,
visible: existingItem.visible
});
}
}
state.push({ id, iconUrl, views });
}
this.storageService.store(ActivitybarPart.CACHED_VIEWLETS, JSON.stringify(state), StorageScope.GLOBAL);
super.saveState();
for (let index = 0; index < compositeItems.length; index++) {
// Add items currently exists but does not exist in new.
if (!newCompositeItems.some(({ id }) => id === compositeItems[index].id)) {
newCompositeItems.splice(index, 0, compositeItems[index]);
}
}
this.compositeBar.setCompositeBarItems(newCompositeItems);
}
}
private saveCachedViewlets(): void {
const state: ICachedViewlet[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
const allViewlets = this.viewletService.getViewlets();
for (const compositeItem of compositeItems) {
const viewContainer = this.getViewContainer(compositeItem.id);
const viewlet = allViewlets.filter(({ id }) => id === compositeItem.id)[0];
if (viewlet) {
const views: { when: string }[] = [];
if (viewContainer) {
const viewDescriptors = this.viewsService.getViewDescriptors(viewContainer);
if (viewDescriptors) {
for (const { when } of viewDescriptors.allViewDescriptors) {
views.push({ when: when ? when.serialize() : undefined });
}
}
}
state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl, views, pinned: compositeItem && compositeItem.pinned, order: compositeItem ? compositeItem.order : undefined, visible: compositeItem && compositeItem.visible });
}
}
this.cachedViewletsValue = JSON.stringify(state);
}
private getCachedViewlets(): ICachedViewlet[] {
const storedStates = <Array<string | ICachedViewlet>>JSON.parse(this.cachedViewletsValue);
const cachedViewlets = <ICachedViewlet[]>storedStates.map(c => {
const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? <ICachedViewlet>{ id: c, pinned: true, order: undefined, visible: true, iconUrl: undefined, views: undefined } : c;
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
return serialized;
});
for (const old of this.loadOldCachedViewlets()) {
const cachedViewlet = cachedViewlets.filter(cached => cached.id === old.id)[0];
if (cachedViewlet) {
cachedViewlet.iconUrl = old.iconUrl;
cachedViewlet.views = old.views;
}
}
return cachedViewlets;
}
private loadOldCachedViewlets(): ICachedViewlet[] {
const previousState = this.storageService.get('workbench.activity.placeholderViewlets', StorageScope.GLOBAL, '[]');
const result = (<ICachedViewlet[]>JSON.parse(previousState));
this.storageService.remove('workbench.activity.placeholderViewlets', StorageScope.GLOBAL);
return result;
}
private _cachedViewletsValue: string;
private get cachedViewletsValue(): string {
if (!this._cachedViewletsValue) {
this._cachedViewletsValue = this.getStoredCachedViewletsValue();
}
return this._cachedViewletsValue;
}
private set cachedViewletsValue(cachedViewletsValue: string) {
if (this.cachedViewletsValue !== cachedViewletsValue) {
this._cachedViewletsValue = cachedViewletsValue;
this.setStoredCachedViewletsValue(cachedViewletsValue);
}
}
private getStoredCachedViewletsValue(): string {
return this.storageService.get(ActivitybarPart.PINNED_VIEWLETS, StorageScope.GLOBAL, '[]');
}
private setStoredCachedViewletsValue(value: string): void {
this.storageService.store(ActivitybarPart.PINNED_VIEWLETS, value, StorageScope.GLOBAL);
}
private getViewContainer(viewletId: string): ViewContainer | undefined {
@@ -411,4 +501,10 @@ export class ActivitybarPart extends Part {
const viewContainerRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
return viewContainerRegistry.get(viewletId);
}
toJSON(): object {
return {
type: Parts.ACTIVITYBAR_PART
};
}
}

View File

@@ -3,13 +3,13 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item {
display: block;
position: relative;
padding: 5px 0;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-label {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-label {
display: flex;
overflow: hidden;
height: 40px;
@@ -20,7 +20,7 @@
font-size: 15px;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item:focus:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item:focus:before {
content: "";
position: absolute;
top: 9px;
@@ -29,19 +29,19 @@
border-left: 2px solid;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .action-item.clicked:focus:before {
.monaco-workbench .activitybar > .content .monaco-action-bar .action-item.clicked:focus:before {
border-left: none !important; /* no focus feedback when using mouse */
}
.monaco-workbench > .activitybar.left > .content .monaco-action-bar .action-item:focus:before {
.monaco-workbench .activitybar.left > .content .monaco-action-bar .action-item:focus:before {
left: 1px;
}
.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-item:focus:before {
.monaco-workbench .activitybar.right > .content .monaco-action-bar .action-item:focus:before {
right: 1px;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .badge {
.monaco-workbench .activitybar > .content .monaco-action-bar .badge {
position: absolute;
top: 5px;
left: 0;
@@ -50,7 +50,7 @@
height: 40px;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar .badge .badge-content {
.monaco-workbench .activitybar > .content .monaco-action-bar .badge .badge-content {
position: absolute;
top: 20px;
right: 8px;
@@ -65,13 +65,13 @@
/* Right aligned */
.monaco-workbench > .activitybar.right > .content .monaco-action-bar .action-label {
.monaco-workbench .activitybar.right > .content .monaco-action-bar .action-label {
margin-left: 0;
padding: 0 50px 0 0;
background-position: calc(100% - 9px) center;
}
.monaco-workbench > .activitybar.right > .content .monaco-action-bar .badge {
.monaco-workbench .activitybar.right > .content .monaco-action-bar .badge {
left: auto;
right: 0;
}

View File

@@ -3,23 +3,23 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .part.activitybar {
.monaco-workbench .part.activitybar {
width: 50px;
}
.monaco-workbench > .activitybar > .content {
.monaco-workbench .activitybar > .content {
height: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.monaco-workbench > .activitybar > .content .monaco-action-bar {
.monaco-workbench .activitybar > .content .monaco-action-bar {
text-align: left;
background-color: inherit;
}
.monaco-workbench > .activitybar .action-item:focus {
.monaco-workbench .activitybar .action-item:focus {
outline: 0 !important; /* activity bar indicates focus custom */
}

View File

@@ -9,7 +9,6 @@ import { illegalArgument } from 'vs/base/common/errors';
import * as arrays from 'vs/base/common/arrays';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ActionBar, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { CompositeActionItem, CompositeOverflowActivityAction, ICompositeActivity, CompositeOverflowActivityActionItem, ActivityAction, ICompositeBar, ICompositeBarColors, DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions';
@@ -20,10 +19,18 @@ import { Widget } from 'vs/base/browser/ui/widget';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
import { ITheme } from 'vs/platform/theme/common/themeService';
import { Emitter, Event } from 'vs/base/common/event';
export interface ICompositeBarItem {
id: string;
name: string;
pinned: boolean;
order: number;
visible: boolean;
}
export interface ICompositeBarOptions {
icon: boolean;
storageId: string;
orientation: ActionsOrientation;
colors: (theme: ITheme) => ICompositeBarColors;
compositeSize: number;
@@ -32,7 +39,7 @@ export interface ICompositeBarOptions {
getCompositePinnedAction: (compositeId: string) => Action;
getOnCompositeClickAction: (compositeId: string) => Action;
getContextMenuActions: () => Action[];
openComposite: (compositeId: string) => Thenable<any>;
openComposite: (compositeId: string) => Promise<any>;
getDefaultCompositeId: () => string;
hidePart: () => void;
}
@@ -51,24 +58,33 @@ export class CompositeBar extends Widget implements ICompositeBar {
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
private readonly _onDidChange: Emitter<void> = this._register(new Emitter<void>());
readonly onDidChange: Event<void> = this._onDidChange.event;
constructor(
items: ICompositeBarItem[],
private options: ICompositeBarOptions,
@IInstantiationService private instantiationService: IInstantiationService,
@IStorageService storageService: IStorageService,
@IContextMenuService private contextMenuService: IContextMenuService
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
super();
this.model = new CompositeBarModel(options, storageService);
this.model = new CompositeBarModel(items, options);
this.visibleComposites = [];
this.compositeSizeInBar = new Map<string, number>();
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
}
getComposites(): ICompositeBarItem[] {
getCompositeBarItems(): ICompositeBarItem[] {
return [...this.model.items];
}
setCompositeBarItems(items: ICompositeBarItem[]): void {
if (this.model.setItems(items)) {
this.updateCompositeSwitcher();
}
}
getPinnedComposites(): ICompositeBarItem[] {
return this.model.pinnedItems;
}
@@ -125,7 +141,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
this.updateCompositeSwitcher();
}
addComposite({ id, name, order }: { id: string; name: string, order: number }): void {
addComposite({ id, name, order }: { id: string; name: string, order?: number }): void {
// Add to the model
if (this.model.add(id, name, order)) {
this.computeSizes([this.model.findItem(id)]);
@@ -254,7 +270,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
return item && item.activityAction;
}
private computeSizes(items: ICompositeBarItem[]): void {
private computeSizes(items: ICompositeBarModelItem[]): void {
const size = this.options.compositeSize;
if (size) {
items.forEach(composite => this.compositeSizeInBar.set(composite.id, size));
@@ -367,7 +383,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
CompositeOverflowActivityActionItem,
this.compositeOverflowAction,
() => this.getOverflowingComposites(),
() => this.model.activeItem ? this.model.activeItem.id : void 0,
() => this.model.activeItem ? this.model.activeItem.id : undefined,
(compositeId: string) => {
const item = this.model.findItem(compositeId);
return item && item.activity[0] && item.activity[0].badge;
@@ -379,8 +395,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
this.compositeSwitcherBar.push(this.compositeOverflowAction, { label: false, icon: true });
}
// Persist
this.model.saveState();
this._onDidChange.fire();
}
private getOverflowingComposites(): { id: string, name: string }[] {
@@ -428,15 +443,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
}
}
interface ISerializedCompositeBarItem {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
interface ICompositeBarItem extends ISerializedCompositeBarItem {
name: string;
interface ICompositeBarModelItem extends ICompositeBarItem {
activityAction: ActivityAction;
pinnedAction: Action;
activity: ICompositeActivity[];
@@ -444,28 +451,63 @@ interface ICompositeBarItem extends ISerializedCompositeBarItem {
class CompositeBarModel {
private _items: ICompositeBarModelItem[];
private readonly options: ICompositeBarOptions;
readonly items: ICompositeBarItem[];
activeItem: ICompositeBarItem;
activeItem: ICompositeBarModelItem;
constructor(
options: ICompositeBarOptions,
private storageService: IStorageService,
items: ICompositeBarItem[],
options: ICompositeBarOptions
) {
this.options = options;
this.items = this.loadItemStates();
this.setItems(items);
}
get visibleItems(): ICompositeBarItem[] {
get items(): ICompositeBarModelItem[] {
return this._items;
}
setItems(items: ICompositeBarItem[]): boolean {
const result: ICompositeBarModelItem[] = [];
let hasChanges: boolean = false;
if (!this.items || this.items.length === 0) {
this._items = items.map(i => this.createCompositeBarItem(i.id, i.name, i.order, i.pinned, i.visible));
hasChanges = true;
} else {
const existingItems = this.items;
for (let index = 0; index < items.length; index++) {
const newItem = items[index];
const existingItem = existingItems.filter(({ id }) => id === newItem.id)[0];
if (existingItem) {
if (
existingItem.pinned !== newItem.pinned ||
index !== existingItems.indexOf(existingItem)
) {
existingItem.pinned = newItem.pinned;
result.push(existingItem);
hasChanges = true;
} else {
result.push(existingItem);
}
} else {
result.push(this.createCompositeBarItem(newItem.id, newItem.name, newItem.order, newItem.pinned, newItem.visible));
hasChanges = true;
}
}
this._items = result;
}
return hasChanges;
}
get visibleItems(): ICompositeBarModelItem[] {
return this.items.filter(item => item.visible);
}
get pinnedItems(): ICompositeBarItem[] {
get pinnedItems(): ICompositeBarModelItem[] {
return this.items.filter(item => item.visible && item.pinned);
}
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarItem {
private createCompositeBarItem(id: string, name: string, order: number, pinned: boolean, visible: boolean): ICompositeBarModelItem {
const options = this.options;
return {
id, name, pinned, order, visible,
@@ -551,8 +593,7 @@ class CompositeBarModel {
}
setPinned(id: string, pinned: boolean): boolean {
for (let index = 0; index < this.items.length; index++) {
const item = this.items[index];
for (const item of this.items) {
if (item.id === id) {
if (item.pinned !== pinned) {
item.pinned = pinned;
@@ -614,8 +655,7 @@ class CompositeBarModel {
if (this.activeItem) {
this.deactivate();
}
for (let index = 0; index < this.items.length; index++) {
const item = this.items[index];
for (const item of this.items) {
if (item.id === id) {
this.activeItem = item;
this.activeItem.activityAction.activate();
@@ -629,13 +669,13 @@ class CompositeBarModel {
deactivate(): boolean {
if (this.activeItem) {
this.activeItem.activityAction.deactivate();
this.activeItem = void 0;
this.activeItem = undefined;
return true;
}
return false;
}
findItem(id: string): ICompositeBarItem {
findItem(id: string): ICompositeBarModelItem {
return this.items.filter(item => item.id === id)[0];
}
@@ -647,17 +687,4 @@ class CompositeBarModel {
}
return -1;
}
private loadItemStates(): ICompositeBarItem[] {
const storedStates = <Array<string | ISerializedCompositeBarItem>>JSON.parse(this.storageService.get(this.options.storageId, StorageScope.GLOBAL, '[]'));
return <ICompositeBarItem[]>storedStates.map(c => {
const serialized: ISerializedCompositeBarItem = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: void 0, visible: true } : c;
return this.createCompositeBarItem(serialized.id, void 0, serialized.order, serialized.pinned, isUndefinedOrNull(serialized.visible) ? true : serialized.visible);
});
}
saveState(): void {
const serialized = this.items.map(({ id, pinned, order, visible }) => ({ id, pinned, order, visible }));
this.storageService.store(this.options.storageId, JSON.stringify(serialized), StorageScope.GLOBAL);
}
}

View File

@@ -207,7 +207,7 @@ export class ActivityActionItem extends BaseActionItem {
}));
// Label
this.label = dom.append(this.element, dom.$('a.action-label'));
this.label = dom.append(this.element, dom.$('a'));
// Badge
this.badge = dom.append(this.element, dom.$('.badge'));
@@ -301,8 +301,9 @@ export class ActivityActionItem extends BaseActionItem {
}
protected updateLabel(): void {
this.label.className = 'action-label';
if (this.activity.cssClass) {
dom.addClasses(this.label, this.activity.cssClass);
dom.addClass(this.label, this.activity.cssClass);
}
if (!this.options.icon) {
this.label.textContent = this.getAction().label;
@@ -358,7 +359,7 @@ export class CompositeOverflowActivityActionItem extends ActivityActionItem {
private getBadge: (compositeId: string) => IBadge,
private getCompositeOpenAction: (compositeId: string) => Action,
colors: (theme: ITheme) => ICompositeBarColors,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IThemeService themeService: IThemeService
) {
super(action, { icon: true, colors }, themeService);
@@ -411,7 +412,7 @@ export class CompositeOverflowActivityActionItem extends ActivityActionItem {
class ManageExtensionAction extends Action {
constructor(
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super('activitybar.manage.extension', nls.localize('manageExtension', "Manage Extension"));
}
@@ -434,7 +435,6 @@ export class CompositeActionItem extends ActivityActionItem {
private static manageExtensionAction: ManageExtensionAction;
private compositeActivity: IActivity;
private cssClass: string;
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
constructor(
@@ -444,14 +444,13 @@ export class CompositeActionItem extends ActivityActionItem {
colors: (theme: ITheme) => ICompositeBarColors,
icon: boolean,
private compositeBar: ICompositeBar,
@IContextMenuService private contextMenuService: IContextMenuService,
@IKeybindingService private keybindingService: IKeybindingService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService
) {
super(compositeActivityAction, { draggable: true, colors, icon }, themeService);
this.cssClass = compositeActivityAction.class;
this.compositeTransfer = LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>();
if (!CompositeActionItem.manageExtensionAction) {
@@ -473,7 +472,7 @@ export class CompositeActionItem extends ActivityActionItem {
this.compositeActivity = {
id: this.compositeActivityAction.activity.id,
cssClass: this.cssClass,
cssClass: this.compositeActivityAction.activity.cssClass,
name: activityName
};
}
@@ -606,17 +605,6 @@ export class CompositeActionItem extends ActivityActionItem {
this.container.focus();
}
protected updateClass(): void {
if (this.cssClass) {
dom.removeClasses(this.label, this.cssClass);
}
this.cssClass = this.getAction().class;
if (this.cssClass) {
dom.addClasses(this.label, this.cssClass);
}
}
protected updateChecked(): void {
if (this.getAction().checked) {
dom.addClass(this.container, 'checked');

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/compositepart';
import * as nls from 'vs/nls';
import { defaultGenerator } from 'vs/base/common/idGenerator';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import * as strings from 'vs/base/common/strings';
import { Emitter } from 'vs/base/common/event';
import * as errors from 'vs/base/common/errors';
@@ -46,6 +46,12 @@ export interface ICompositeTitleLabel {
updateStyles(): void;
}
interface CompositeItem {
composite: Composite;
disposable: IDisposable;
progressService: IProgressService;
}
export abstract class CompositePart<T extends Composite> extends Part {
protected _onDidCompositeOpen = this._register(new Emitter<{ composite: IComposite, focus: boolean }>());
@@ -53,22 +59,20 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected toolBar: ToolBar;
private instantiatedCompositeListeners: IDisposable[];
private mapCompositeToCompositeContainer: { [compositeId: string]: HTMLElement; };
private mapActionsBindingToComposite: { [compositeId: string]: () => void; };
private mapProgressServiceToComposite: { [compositeId: string]: IProgressService; };
private activeComposite: Composite;
private activeComposite: Composite | null;
private lastActiveCompositeId: string;
private instantiatedComposites: Composite[];
private instantiatedCompositeItems: Map<string, CompositeItem>;
private titleLabel: ICompositeTitleLabel;
private progressBar: ProgressBar;
private contentAreaSize: Dimension;
private telemetryActionsListener: IDisposable;
private telemetryActionsListener: IDisposable | null;
private currentCompositeOpenToken: string;
constructor(
private notificationService: INotificationService,
private storageService: IStorageService,
protected storageService: IStorageService,
private telemetryService: ITelemetryService,
protected contextMenuService: IContextMenuService,
protected partService: IPartService,
@@ -86,16 +90,14 @@ export abstract class CompositePart<T extends Composite> extends Part {
) {
super(id, options, themeService, storageService);
this.instantiatedCompositeListeners = [];
this.mapCompositeToCompositeContainer = {};
this.mapActionsBindingToComposite = {};
this.mapProgressServiceToComposite = {};
this.activeComposite = null;
this.instantiatedComposites = [];
this.instantiatedCompositeItems = new Map<string, CompositeItem>();
this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId);
}
protected openComposite(id: string, focus?: boolean): Composite {
protected openComposite(id: string, focus?: boolean): Composite | undefined {
// Check if composite already visible and just focus in that case
if (this.activeComposite && this.activeComposite.getId() === id) {
if (focus) {
@@ -110,7 +112,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
return this.doOpenComposite(id, focus);
}
private doOpenComposite(id: string, focus?: boolean): Composite {
private doOpenComposite(id: string, focus: boolean = false): Composite | undefined {
// Use a generated token to avoid race conditions from long running promises
const currentCompositeOpenToken = defaultGenerator.nextId();
@@ -159,10 +161,9 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected createComposite(id: string, isActive?: boolean): Composite {
// Check if composite is already created
for (let i = 0; i < this.instantiatedComposites.length; i++) {
if (this.instantiatedComposites[i].getId() === id) {
return this.instantiatedComposites[i];
}
const compositeItem = this.instantiatedCompositeItems.get(id);
if (compositeItem) {
return compositeItem.composite;
}
// Instantiate composite from registry otherwise
@@ -172,18 +173,18 @@ export abstract class CompositePart<T extends Composite> extends Part {
const compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection([IProgressService, progressService]));
const composite = compositeDescriptor.instantiate(compositeInstantiationService);
this.mapProgressServiceToComposite[composite.getId()] = progressService;
const disposables: IDisposable[] = [];
// Remember as Instantiated
this.instantiatedComposites.push(composite);
this.instantiatedCompositeItems.set(id, { composite, disposable: toDisposable(() => dispose(disposables)), progressService });
// Register to title area update events from the composite
this.instantiatedCompositeListeners.push(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId())));
composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId()), this, disposables);
return composite;
}
throw new Error(strings.format('Unable to find composite with id {0}', id));
throw new Error(`Unable to find composite with id ${id}`);
}
protected showComposite(composite: Composite): void {
@@ -219,19 +220,22 @@ export abstract class CompositePart<T extends Composite> extends Part {
}
// Report progress for slow loading composites (but only if we did not create the composites before already)
const progressService = this.mapProgressServiceToComposite[composite.getId()];
if (progressService && !compositeContainer) {
this.mapProgressServiceToComposite[composite.getId()].showWhile(Promise.resolve(), this.partService.isRestored() ? 800 : 3200 /* less ugly initial startup */);
const compositeItem = this.instantiatedCompositeItems.get(composite.getId());
if (compositeItem && !compositeContainer) {
compositeItem.progressService.showWhile(Promise.resolve(), this.partService.isRestored() ? 800 : 3200 /* less ugly initial startup */);
}
// Fill Content and Actions
// Make sure that the user meanwhile did not open another composite or closed the part containing the composite
if (!this.activeComposite || composite.getId() !== this.activeComposite.getId()) {
return void 0;
return undefined;
}
// Take Composite on-DOM and show
this.getContentArea().appendChild(compositeContainer);
const contentArea = this.getContentArea();
if (contentArea) {
contentArea.appendChild(compositeContainer);
}
show(compositeContainer);
// Setup action runner
@@ -240,7 +244,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
// Update title with composite title if it differs from descriptor
const descriptor = this.registry.getComposite(composite.getId());
if (descriptor && descriptor.name !== composite.getTitle()) {
this.updateTitle(composite.getId(), composite.getTitle());
this.updateTitle(composite.getId(), composite.getTitle() || undefined);
}
// Handle Composite Actions
@@ -296,7 +300,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
if (this.activeComposite && this.activeComposite.getId() === compositeId) {
// Title
this.updateTitle(this.activeComposite.getId(), this.activeComposite.getTitle());
this.updateTitle(this.activeComposite.getId(), this.activeComposite.getTitle() || undefined);
// Actions
const actionsBinding = this.collectCompositeActions(this.activeComposite);
@@ -322,7 +326,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
const keybinding = this.keybindingService.lookupKeybinding(compositeId);
this.titleLabel.updateTitle(compositeId, compositeTitle, keybinding ? keybinding.getLabel() : undefined);
this.titleLabel.updateTitle(compositeId, compositeTitle, (keybinding && keybinding.getLabel()) || undefined);
this.toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle));
}
@@ -341,7 +345,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
return this.toolBar.setActions(prepareActions(primaryActions), prepareActions(secondaryActions));
}
protected getActiveComposite(): IComposite {
protected getActiveComposite(): IComposite | null {
return this.activeComposite;
}
@@ -349,7 +353,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
return this.lastActiveCompositeId;
}
protected hideActiveComposite(): Composite {
protected hideActiveComposite(): Composite | undefined {
if (!this.activeComposite) {
return undefined; // Nothing to do
}
@@ -423,14 +427,14 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.titleLabel.updateStyles();
}
protected actionItemProvider(action: Action): IActionItem {
protected actionItemProvider(action: Action): IActionItem | null {
// Check Active Composite
if (this.activeComposite) {
return this.activeComposite.getActionItem(action);
}
return undefined;
return null;
}
createContentArea(parent: HTMLElement): HTMLElement {
@@ -443,8 +447,9 @@ export abstract class CompositePart<T extends Composite> extends Part {
return contentContainer;
}
getProgressIndicator(id: string): IProgressService {
return this.mapProgressServiceToComposite[id];
getProgressIndicator(id: string): IProgressService | null {
const compositeItem = this.instantiatedCompositeItems.get(id);
return compositeItem ? compositeItem.progressService : null;
}
protected getActions(): IAction[] {
@@ -459,10 +464,11 @@ export abstract class CompositePart<T extends Composite> extends Part {
return AnchorAlignment.RIGHT;
}
layout(dimension: Dimension): Dimension[] {
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
// Pass to super
const sizes = super.layout(dimension);
const sizes = super.layout(dim1 instanceof Dimension ? dim1 : new Dimension(dim1, dim2!));
// Pass Contentsize to composite
this.contentAreaSize = sizes[1];
@@ -470,20 +476,38 @@ export abstract class CompositePart<T extends Composite> extends Part {
this.activeComposite.layout(this.contentAreaSize);
}
return sizes;
if (dim1 instanceof Dimension) {
return sizes;
}
}
protected removeComposite(compositeId: string): boolean {
if (this.activeComposite && this.activeComposite.getId() === compositeId) {
// do not remove active compoiste
return false;
}
delete this.mapCompositeToCompositeContainer[compositeId];
delete this.mapActionsBindingToComposite[compositeId];
const compositeItem = this.instantiatedCompositeItems.get(compositeId);
if (compositeItem) {
compositeItem.composite.dispose();
dispose(compositeItem.disposable);
this.instantiatedCompositeItems.delete(compositeId);
}
return true;
}
dispose(): void {
this.mapCompositeToCompositeContainer = null;
this.mapProgressServiceToComposite = null;
this.mapActionsBindingToComposite = null;
this.mapCompositeToCompositeContainer = null!; // StrictNullOverride: nulling out ok in dispose
this.mapActionsBindingToComposite = null!; // StrictNullOverride: nulling out ok in dispose
for (let i = 0; i < this.instantiatedComposites.length; i++) {
this.instantiatedComposites[i].dispose();
}
this.instantiatedCompositeItems.forEach(compositeItem => {
compositeItem.composite.dispose();
dispose(compositeItem.disposable);
});
this.instantiatedComposites = [];
this.instantiatedCompositeListeners = dispose(this.instantiatedCompositeListeners);
this.instantiatedCompositeItems.clear();
super.dispose();
}

View File

@@ -12,7 +12,7 @@ import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/group/
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { LRUCache } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { once, Event } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { isEmptyObject } from 'vs/base/common/types';
import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor';
@@ -38,12 +38,12 @@ export abstract class BaseEditor extends Panel implements IEditor {
readonly minimumHeight = DEFAULT_EDITOR_MIN_DIMENSIONS.height;
readonly maximumHeight = DEFAULT_EDITOR_MAX_DIMENSIONS.height;
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }> = Event.None;
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = Event.None;
protected _input: EditorInput;
protected _options: EditorOptions;
protected _input: EditorInput | null;
protected _options: EditorOptions | null;
private _group: IEditorGroup;
private _group?: IEditorGroup;
constructor(
id: string,
@@ -54,15 +54,15 @@ export abstract class BaseEditor extends Panel implements IEditor {
super(id, telemetryService, themeService, storageService);
}
get input(): EditorInput {
get input(): EditorInput | null {
return this._input;
}
get options(): EditorOptions {
get options(): EditorOptions | null {
return this._options;
}
get group(): IEditorGroup {
get group(): IEditorGroup | undefined {
return this._group;
}
@@ -77,7 +77,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
* The provided cancellation token should be used to test if the operation
* was cancelled.
*/
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(input: EditorInput, options: EditorOptions | null, token: CancellationToken): Promise<void> {
this._input = input;
this._options = options;
@@ -100,7 +100,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
* Sets the given options to the editor. Clients should apply the options
* to the current input.
*/
setOptions(options: EditorOptions): void {
setOptions(options: EditorOptions | null): void {
this._options = options;
}
@@ -118,6 +118,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
setVisible(visible: boolean, group?: IEditorGroup): void {
super.setVisible(visible);
// Propagate to Editor
this.setEditorVisible(visible, group);
}
@@ -129,7 +130,7 @@ export abstract class BaseEditor extends Panel implements IEditor {
* @param visible the state of visibility of this editor
* @param group the editor group this editor is in.
*/
protected setEditorVisible(visible: boolean, group: IEditorGroup): void {
protected setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
this._group = group;
}
@@ -205,18 +206,18 @@ export class EditorMemento<T> implements IEditorMemento<T> {
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
once(resourceOrEditor.onDispose)(() => {
Event.once(resourceOrEditor.onDispose)(() => {
this.clearEditorState(resource);
});
}
}
loadEditorState(group: IEditorGroup, resource: URI): T;
loadEditorState(group: IEditorGroup, editor: EditorInput): T;
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput): T {
loadEditorState(group: IEditorGroup, resource: URI): T | undefined;
loadEditorState(group: IEditorGroup, editor: EditorInput): T | undefined;
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput): T | undefined {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return void 0; // we are not in a good state to load any state for a resource
return undefined; // we are not in a good state to load any state for a resource
}
const cache = this.doLoad();
@@ -226,7 +227,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
return mementoForResource[group.id];
}
return void 0;
return undefined;
}
clearEditorState(resource: URI, group?: IEditorGroup): void;
@@ -247,7 +248,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
}
}
private doGetResource(resourceOrEditor: URI | EditorInput): URI {
private doGetResource(resourceOrEditor: URI | EditorInput): URI | null {
if (resourceOrEditor instanceof EditorInput) {
return resourceOrEditor.getResource();
}

View File

@@ -28,7 +28,7 @@ export class BinaryResourceDiffEditor extends SideBySideEditor {
super(telemetryService, instantiationService, themeService, storageService);
}
getMetadata(): string {
getMetadata(): string | null {
const master = this.masterEditor;
const details = this.detailsEditor;

View File

@@ -21,7 +21,7 @@ import { dispose } from 'vs/base/common/lifecycle';
import { IStorageService } from 'vs/platform/storage/common/storage';
export interface IOpenCallbacks {
openInternal: (input: EditorInput, options: EditorOptions) => Thenable<void>;
openInternal: (input: EditorInput, options: EditorOptions) => Promise<void>;
openExternal: (uri: URI) => void;
}
@@ -37,7 +37,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
get onDidOpenInPlace(): Event<void> { return this._onDidOpenInPlace.event; }
private callbacks: IOpenCallbacks;
private metadata: string;
private metadata: string | null;
private binaryContainer: HTMLElement;
private scrollbar: DomScrollableElement;
private resourceViewerContext: ResourceViewerContext;
@@ -55,7 +55,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
this.callbacks = callbacks;
}
getTitle(): string {
getTitle() {
return this.input ? this.input.getName() : nls.localize('binaryEditor', "Binary Viewer");
}
@@ -72,13 +72,13 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
parent.appendChild(this.scrollbar.getDomNode());
}
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
return super.setInput(input, options, token).then(() => {
return input.resolve().then(model => {
// Check for cancellation
if (token.isCancellationRequested) {
return void 0;
return undefined;
}
// Assert Model instance
@@ -97,7 +97,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
meta => this.handleMetadataChanged(meta)
);
return void 0;
return undefined;
});
});
}
@@ -110,13 +110,13 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
});
}
private handleMetadataChanged(meta: string): void {
private handleMetadataChanged(meta: string | null): void {
this.metadata = meta;
this._onMetadataChanged.fire();
}
getMetadata(): string {
getMetadata() {
return this.metadata;
}

View File

@@ -23,7 +23,7 @@ export interface IBreadcrumbsService {
register(group: GroupIdentifier, widget: BreadcrumbsWidget): IDisposable;
getWidget(group: GroupIdentifier): BreadcrumbsWidget;
getWidget(group: GroupIdentifier): BreadcrumbsWidget | undefined;
}
@@ -43,12 +43,12 @@ export class BreadcrumbsService implements IBreadcrumbsService {
};
}
getWidget(group: number): BreadcrumbsWidget {
getWidget(group: number): BreadcrumbsWidget | undefined {
return this._map.get(group);
}
}
registerSingleton(IBreadcrumbsService, BreadcrumbsService);
registerSingleton(IBreadcrumbsService, BreadcrumbsService, true);
//#region config
@@ -59,7 +59,7 @@ export abstract class BreadcrumbsConfig<T> {
onDidChange: Event<void>;
abstract getValue(overrides?: IConfigurationOverrides): T;
abstract updateValue(value: T, overrides?: IConfigurationOverrides): Thenable<void>;
abstract updateValue(value: T, overrides?: IConfigurationOverrides): Promise<void>;
abstract dispose(): void;
private constructor() {
@@ -90,10 +90,18 @@ export abstract class BreadcrumbsConfig<T> {
readonly name = name;
readonly onDidChange = onDidChange.event;
getValue(overrides?: IConfigurationOverrides): T {
return service.getValue(name, overrides);
if (overrides) {
return service.getValue(name, overrides);
} else {
return service.getValue(name);
}
}
updateValue(newValue: T, overrides?: IConfigurationOverrides): Thenable<void> {
return service.updateValue(name, newValue, overrides);
updateValue(newValue: T, overrides?: IConfigurationOverrides): Promise<void> {
if (overrides) {
return service.updateValue(name, newValue, overrides);
} else {
return service.updateValue(name, newValue);
}
}
dispose(): void {
listener.dispose();
@@ -112,7 +120,7 @@ Registry.as<IConfigurationRegistry>(Extensions.Configuration).registerConfigurat
type: 'object',
properties: {
'breadcrumbs.enabled': {
description: localize('enabled', "Enable/disable navigation breadcrumbs"),
description: localize('enabled', "Enable/disable navigation breadcrumbs."),
type: 'boolean',
default: false
},

View File

@@ -35,7 +35,7 @@ import { ColorIdentifier, ColorFunction } from 'vs/platform/theme/common/colorRe
import { attachBreadcrumbsStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { FileLabel } from 'vs/workbench/browser/labels';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import { BreadcrumbsConfig, IBreadcrumbsService } from 'vs/workbench/browser/parts/editor/breadcrumbs';
import { BreadcrumbElement, EditorBreadcrumbsModel, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel';
import { BreadcrumbsPicker, createBreadcrumbsPicker } from 'vs/workbench/browser/parts/editor/breadcrumbsPicker';
@@ -78,8 +78,8 @@ class Item extends BreadcrumbsItem {
render(container: HTMLElement): void {
if (this.element instanceof FileElement) {
// file/folder
let label = this._instantiationService.createInstance(FileLabel, container, {});
label.setFile(this.element.uri, {
let label = this._instantiationService.createInstance(ResourceLabel, container, {});
label.element.setFile(this.element.uri, {
hidePath: true,
hideIcon: this.element.kind === FileKind.FOLDER || !this.options.showFileIcons,
fileKind: this.element.kind,
@@ -98,7 +98,7 @@ class Item extends BreadcrumbsItem {
} else if (this.element instanceof OutlineGroup) {
// provider
let label = new IconLabel(container);
label.setValue(this.element.provider.displayName);
label.setLabel(this.element.provider.displayName);
this._disposables.push(label);
} else if (this.element instanceof OutlineElement) {
@@ -111,7 +111,7 @@ class Item extends BreadcrumbsItem {
}
let label = new IconLabel(container);
let title = this.element.symbol.name.replace(/\r|\n|\r\n/g, '\u23CE');
label.setValue(title);
label.setLabel(title);
this._disposables.push(label);
}
}
@@ -356,7 +356,7 @@ export class BreadcrumbsControl {
},
getAnchor: () => {
let maxInnerWidth = window.innerWidth - 8 /*a little less the full widget*/;
let maxHeight = Math.min(window.innerHeight * .7, 300);
let maxHeight = Math.min(window.innerHeight * 0.7, 300);
let pickerWidth = Math.min(maxInnerWidth, Math.max(240, maxInnerWidth / 4.17));
let pickerArrowSize = 8;
@@ -379,7 +379,7 @@ export class BreadcrumbsControl {
pickerArrowOffset = maxPickerArrowOffset;
}
} else {
pickerArrowOffset = (data.left + (data.width * .3)) - x;
pickerArrowOffset = (data.left + (data.width * 0.3)) - x;
}
picker.setInput(element, maxHeight, pickerWidth, pickerArrowSize, Math.max(0, pickerArrowOffset));
return { x, y };
@@ -453,15 +453,17 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
category: localize('cmd.category', "View")
}
});
MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
group: '5_editor',
order: 99,
command: {
id: 'breadcrumbs.toggle',
title: localize('miToggleBreadcrumbs', "Toggle &&Breadcrumbs"),
toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true)
}
});
// {{SQL CARBON EDIT}} - Disable unused menu item
// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, {
// group: '5_editor',
// order: 99,
// command: {
// id: 'breadcrumbs.toggle',
// title: localize('miToggleBreadcrumbs', "Toggle &&Breadcrumbs"),
// toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true)
// }
// });
// {{SQL CARBON EDIT}} - End
CommandsRegistry.registerCommand('breadcrumbs.toggle', accessor => {
let config = accessor.get(IConfigurationService);
let value = BreadcrumbsConfig.IsEnabled.bindTo(config).getValue();

View File

@@ -8,7 +8,7 @@ import { TimeoutTimer } from 'vs/base/common/async';
import { CancellationTokenSource } from 'vs/base/common/cancellation';
import { size } from 'vs/base/common/collections';
import { onUnexpectedError } from 'vs/base/common/errors';
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
import { Emitter, Event } from 'vs/base/common/event';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { isEqual, dirname } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
@@ -31,7 +31,7 @@ export class FileElement {
export type BreadcrumbElement = FileElement | OutlineModel | OutlineGroup | OutlineElement;
type FileInfo = { path: FileElement[], folder: IWorkspaceFolder };
type FileInfo = { path: FileElement[], folder?: IWorkspaceFolder };
export class EditorBreadcrumbsModel {
@@ -41,7 +41,7 @@ export class EditorBreadcrumbsModel {
private readonly _cfgFilePath: BreadcrumbsConfig<'on' | 'off' | 'last'>;
private readonly _cfgSymbolPath: BreadcrumbsConfig<'on' | 'off' | 'last'>;
private _outlineElements: (OutlineModel | OutlineGroup | OutlineElement)[] = [];
private _outlineElements: Array<OutlineModel | OutlineGroup | OutlineElement> = [];
private _outlineDisposables: IDisposable[] = [];
private _onDidUpdate = new Emitter<this>();
@@ -105,16 +105,21 @@ export class EditorBreadcrumbsModel {
}
let info: FileInfo = {
folder: workspaceService.getWorkspaceFolder(uri),
folder: workspaceService.getWorkspaceFolder(uri) || undefined,
path: []
};
while (uri.path !== '/') {
if (info.folder && isEqual(info.folder.uri, uri)) {
let uriPrefix: URI | null = uri;
while (uriPrefix && uriPrefix.path !== '/') {
if (info.folder && isEqual(info.folder.uri, uriPrefix)) {
break;
}
info.path.unshift(new FileElement(uriPrefix, info.path.length === 0 ? FileKind.FILE : FileKind.FOLDER));
let prevPathLength = uriPrefix.path.length;
uriPrefix = dirname(uriPrefix);
if (!uriPrefix || uriPrefix.path.length === prevPathLength) {
break;
}
info.path.unshift(new FileElement(uri, info.path.length === 0 ? FileKind.FILE : FileKind.FOLDER));
uri = dirname(uri);
}
if (info.folder && workspaceService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
@@ -131,7 +136,7 @@ export class EditorBreadcrumbsModel {
this._disposables.push(DocumentSymbolProviderRegistry.onDidChange(_ => this._updateOutline()));
this._disposables.push(this._editor.onDidChangeModel(_ => this._updateOutline()));
this._disposables.push(this._editor.onDidChangeModelLanguage(_ => this._updateOutline()));
this._disposables.push(debounceEvent(this._editor.onDidChangeModelContent, _ => _, 350)(_ => this._updateOutline(true)));
this._disposables.push(Event.debounce(this._editor.onDidChangeModelContent, _ => _, 350)(_ => this._updateOutline(true)));
this._updateOutline();
// stop when editor dies
@@ -145,7 +150,9 @@ export class EditorBreadcrumbsModel {
this._updateOutlineElements([]);
}
const buffer = this._editor.getModel();
const editor = this._editor!;
const buffer = editor.getModel();
if (!buffer || !DocumentSymbolProviderRegistry.has(buffer) || !isEqual(buffer.uri, this._uri)) {
return;
}
@@ -171,11 +178,11 @@ export class EditorBreadcrumbsModel {
// copy the model
model = model.adopt();
this._updateOutlineElements(this._getOutlineElements(model, this._editor.getPosition()));
this._outlineDisposables.push(this._editor.onDidChangeCursorPosition(_ => {
this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition()));
this._outlineDisposables.push(editor.onDidChangeCursorPosition(_ => {
timeout.cancelAndSet(() => {
if (!buffer.isDisposed() && versionIdThen === buffer.getVersionId() && this._editor.getModel()) {
this._updateOutlineElements(this._getOutlineElements(model, this._editor.getPosition()));
if (!buffer.isDisposed() && versionIdThen === buffer.getVersionId() && editor.getModel()) {
this._updateOutlineElements(this._getOutlineElements(model, editor.getPosition()));
}
}, 150);
}));
@@ -186,22 +193,22 @@ export class EditorBreadcrumbsModel {
});
}
private _getOutlineElements(model: OutlineModel, position: IPosition): (OutlineModel | OutlineGroup | OutlineElement)[] {
if (!model) {
private _getOutlineElements(model: OutlineModel, position: IPosition | null): Array<OutlineModel | OutlineGroup | OutlineElement> {
if (!model || !position) {
return [];
}
let item: OutlineGroup | OutlineElement = model.getItemEnclosingPosition(position);
let item: OutlineGroup | OutlineElement | undefined = model.getItemEnclosingPosition(position);
if (!item) {
return [model];
}
let chain: (OutlineGroup | OutlineElement)[] = [];
let chain: Array<OutlineGroup | OutlineElement> = [];
while (item) {
chain.push(item);
let parent = item.parent;
if (parent instanceof OutlineModel) {
break;
}
if (parent instanceof OutlineGroup && size(parent.parent.children) === 1) {
if (parent instanceof OutlineGroup && parent.parent && size(parent.parent.children) === 1) {
break;
}
item = parent;
@@ -209,7 +216,7 @@ export class EditorBreadcrumbsModel {
return chain.reverse();
}
private _updateOutlineElements(elements: (OutlineModel | OutlineGroup | OutlineElement)[]): void {
private _updateOutlineElements(elements: Array<OutlineModel | OutlineGroup | OutlineElement>): void {
if (!equals(elements, this._outlineElements, EditorBreadcrumbsModel._outlineElementEquals)) {
this._outlineElements = elements;
this._onDidUpdate.fire(this);

View File

@@ -14,7 +14,6 @@ import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import { join } from 'vs/base/common/paths';
import { basename, dirname, isEqual } from 'vs/base/common/resources';
import { URI } from 'vs/base/common/uri';
import { TPromise } from 'vs/base/common/winjs.base';
import { IDataSource, IFilter, IRenderer, ISorter, ITree } from 'vs/base/parts/tree/browser/tree';
import 'vs/css!./media/breadcrumbscontrol';
import { OutlineElement, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel';
@@ -26,7 +25,7 @@ import { IConstructorSignature1, IInstantiationService } from 'vs/platform/insta
import { HighlightingWorkbenchTree, IHighlighter, IHighlightingTreeConfiguration, IHighlightingTreeOptions } from 'vs/platform/list/browser/listService';
import { breadcrumbsPickerBackground, widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
import { FileLabel } from 'vs/workbench/browser/labels';
import { ResourceLabels, IResourceLabel, DEFAULT_LABELS_CONTAINER } from 'vs/workbench/browser/labels';
import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs';
import { BreadcrumbElement, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel';
import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
@@ -160,7 +159,7 @@ export abstract class BreadcrumbsPicker {
// use proper selection, reveal
let selection = this._getInitialSelection(this._tree, input);
if (selection) {
return this._tree.reveal(selection, .5).then(() => {
return this._tree.reveal(selection, 0.5).then(() => {
this._tree.setSelection([selection], this._tree);
this._tree.setFocus(selection);
this._tree.domFocus();
@@ -228,7 +227,7 @@ export class FileDataSource implements IDataSource {
return URI.isUri(element) || IWorkspace.isIWorkspace(element) || IWorkspaceFolder.isIWorkspaceFolder(element) || element.isDirectory;
}
getChildren(tree: ITree, element: IWorkspace | IWorkspaceFolder | IFileStat | URI): TPromise<IWorkspaceFolder[] | IFileStat[]> {
getChildren(tree: ITree, element: IWorkspace | IWorkspaceFolder | IFileStat | URI): Promise<IWorkspaceFolder[] | IFileStat[]> {
if (IWorkspace.isIWorkspace(element)) {
return Promise.resolve(element.folders).then(folders => {
for (let child of folders) {
@@ -253,7 +252,7 @@ export class FileDataSource implements IDataSource {
});
}
getParent(tree: ITree, element: IWorkspace | URI | IWorkspaceFolder | IFileStat): TPromise<IWorkspaceFolder | IFileStat> {
getParent(tree: ITree, element: IWorkspace | URI | IWorkspaceFolder | IFileStat): Promise<IWorkspaceFolder | IFileStat> {
return Promise.resolve(this._parents.get(element));
}
}
@@ -330,7 +329,7 @@ export class FileHighlighter implements IHighlighter {
export class FileRenderer implements IRenderer {
constructor(
@IInstantiationService private readonly _instantiationService: IInstantiationService,
private readonly _labels: ResourceLabels,
@IConfigurationService private readonly _configService: IConfigurationService,
) { }
@@ -343,10 +342,10 @@ export class FileRenderer implements IRenderer {
}
renderTemplate(tree: ITree, templateId: string, container: HTMLElement) {
return this._instantiationService.createInstance(FileLabel, container, { supportHighlights: true });
return this._labels.create(container, { supportHighlights: true });
}
renderElement(tree: ITree, element: IFileStat | IWorkspaceFolder, templateId: string, templateData: FileLabel): void {
renderElement(tree: ITree, element: IFileStat | IWorkspaceFolder, templateId: string, templateData: IResourceLabel): void {
let fileDecorations = this._configService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
let resource: URI;
let fileKind: FileKind;
@@ -366,7 +365,7 @@ export class FileRenderer implements IRenderer {
});
}
disposeTemplate(tree: ITree, templateId: string, templateData: FileLabel): void {
disposeTemplate(tree: ITree, templateId: string, templateData: IResourceLabel): void {
templateData.dispose();
}
}
@@ -428,7 +427,9 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
this._disposables.push(filter);
config.dataSource = this._instantiationService.createInstance(FileDataSource);
config.renderer = this._instantiationService.createInstance(FileRenderer);
const labels = this._instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER /* TODO@Jo visibility propagation */);
this._disposables.push(labels);
config.renderer = this._instantiationService.createInstance(FileRenderer, labels);
config.sorter = new FileSorter();
config.highlighter = new FileHighlighter();
config.filter = filter;

View File

@@ -50,6 +50,7 @@ import { AllEditorsPicker, ActiveEditorGroupPicker } from 'vs/workbench/browser/
import { Schemas } from 'vs/base/common/network';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/editor/editorWidgets';
import { ZoomStatusbarItem } from 'vs/workbench/browser/parts/editor/resourceViewer';
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
@@ -110,7 +111,7 @@ interface ISerializedUntitledEditorInput {
class UntitledEditorInputFactory implements IEditorInputFactory {
constructor(
@ITextFileService private textFileService: ITextFileService
@ITextFileService private readonly textFileService: ITextFileService
) { }
serialize(editorInput: EditorInput): string {
@@ -144,7 +145,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
return instantiationService.invokeFunction<UntitledEditorInput>(accessor => {
const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput);
const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource);
const filePath = resource.scheme === Schemas.file ? resource.fsPath : void 0;
const filePath = resource.scheme === Schemas.file ? resource.fsPath : undefined;
const language = deserialized.modeId;
const encoding = deserialized.encoding;
@@ -226,6 +227,9 @@ registerEditorContribution(OpenWorkspaceButtonContribution);
const statusBar = Registry.as<IStatusbarRegistry>(StatusExtensions.Statusbar);
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(EditorStatus, StatusbarAlignment.RIGHT, 100 /* towards the left of the right hand side */));
// Register Zoom Status
statusBar.registerStatusbarItem(new StatusbarItemDescriptor(ZoomStatusbarItem, StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */));
// Register Status Actions
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeModeAction, ChangeModeAction.ID, ChangeModeAction.LABEL, { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_M) }), 'Change Language Mode');
@@ -235,7 +239,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ChangeEncodingAction,
export class QuickOpenActionContributor extends ActionBarContributor {
private openToSideActionInstance: OpenToSideFromQuickOpenAction;
constructor(@IInstantiationService private instantiationService: IInstantiationService) {
constructor(@IInstantiationService private readonly instantiationService: IInstantiationService) {
super();
}
@@ -745,7 +749,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarLayoutMenu, {
// Forward/Back
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_fwd_back',
group: '1_history_nav',
command: {
id: 'workbench.action.navigateBack',
title: nls.localize({ key: 'miBack', comment: ['&& denotes a mnemonic'] }, "&&Back"),
@@ -755,7 +759,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
});
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_fwd_back',
group: '1_history_nav',
command: {
id: 'workbench.action.navigateForward',
title: nls.localize({ key: 'miForward', comment: ['&& denotes a mnemonic'] }, "&&Forward"),
@@ -764,6 +768,16 @@ MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
order: 2
});
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '1_history_nav',
command: {
id: 'workbench.action.navigateToLastEditLocation',
title: nls.localize({ key: 'miLastEditLocation', comment: ['&& denotes a mnemonic'] }, "&&Last Edit Location"),
precondition: ContextKeyExpr.has('canNavigateToLastEditLocation')
},
order: 3
});
// Switch Editor
MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
group: '1_any',
@@ -802,7 +816,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchEditorMenu, {
});
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '2_switch',
group: '2_editor_nav',
title: nls.localize({ key: 'miSwitchEditor', comment: ['&& denotes a mnemonic'] }, "Switch &&Editor"),
submenu: MenuId.MenubarSwitchEditorMenu,
order: 1
@@ -909,7 +923,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarSwitchGroupMenu, {
});
MenuRegistry.appendMenuItem(MenuId.MenubarGoMenu, {
group: '2_switch',
group: '2_editor_nav',
title: nls.localize({ key: 'miSwitchGroup', comment: ['&& denotes a mnemonic'] }, "Switch &&Group"),
submenu: MenuId.MenubarSwitchGroupMenu,
order: 2

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GroupIdentifier, IWorkbenchEditorConfiguration, IWorkbenchEditorPartConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent } from 'vs/workbench/common/editor';
import { GroupIdentifier, IWorkbenchEditorConfiguration, IWorkbenchEditorPartConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor } from 'vs/workbench/common/editor';
import { EditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IDisposable } from 'vs/base/common/lifecycle';
@@ -30,6 +30,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
highlightModifiedTabs: false,
tabCloseButton: 'right',
tabSizing: 'fit',
focusRecentEditorAfterClose: true,
showIcons: true,
enablePreview: true,
openPositioning: 'right',
@@ -74,9 +75,9 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
* that will be executed instead. By returning another editor promise
* it is possible to override the opening with another editor. It is ok
* to return a promise that resolves to NULL to prevent the opening
* altogether.
* alltogether.
*/
prevent(callback: () => Thenable<any>): void;
prevent(callback: () => Promise<IEditor>): void;
}
export interface IEditorGroupsAccessor {
@@ -102,7 +103,7 @@ export interface IEditorGroupsAccessor {
export interface IEditorGroupView extends IDisposable, ISerializableView, IEditorGroup {
readonly group: EditorGroup;
readonly whenRestored: Thenable<void>;
readonly whenRestored: Promise<void>;
readonly disposed: boolean;
readonly onDidFocus: Event<void>;
@@ -119,7 +120,7 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito
}
export function getActiveTextEditorOptions(group: IEditorGroup, expectedActiveEditor?: IEditorInput, presetOptions?: EditorOptions): EditorOptions {
const activeGroupCodeEditor = group.activeControl ? getCodeEditor(group.activeControl.getControl()) : void 0;
const activeGroupCodeEditor = group.activeControl ? getCodeEditor(group.activeControl.getControl()) : undefined;
if (activeGroupCodeEditor) {
if (!expectedActiveEditor || expectedActiveEditor.matches(group.activeEditor)) {
return TextEditorOptions.fromEditor(activeGroupCodeEditor, presetOptions);
@@ -155,5 +156,5 @@ export interface EditorGroupsServiceImpl extends IEditorGroupsService {
/**
* A promise that resolves when groups have been restored.
*/
readonly whenRestored: Thenable<void>;
readonly whenRestored: Promise<void>;
}

View File

@@ -35,7 +35,7 @@ export class ExecuteCommandAction extends Action {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
return this.commandService.executeCommand(this.commandId, this.commandArgs);
}
}
@@ -182,7 +182,7 @@ export class JoinTwoGroupsAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
@@ -196,8 +196,8 @@ export class JoinTwoGroupsAction extends Action {
}
const targetGroupDirections = [GroupDirection.RIGHT, GroupDirection.DOWN, GroupDirection.LEFT, GroupDirection.UP];
for (let i = 0; i < targetGroupDirections.length; i++) {
const targetGroup = this.editorGroupService.findGroup({ direction: targetGroupDirections[i] }, sourceGroup);
for (const targetGroupDirection of targetGroupDirections) {
const targetGroup = this.editorGroupService.findGroup({ direction: targetGroupDirection }, sourceGroup);
if (targetGroup && sourceGroup !== targetGroup) {
this.editorGroupService.mergeGroup(sourceGroup, targetGroup);
@@ -217,7 +217,7 @@ export class JoinAllGroupsAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
@@ -237,12 +237,12 @@ export class NavigateBetweenGroupsAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const nextGroup = this.editorGroupService.findGroup({ location: GroupLocation.NEXT }, this.editorGroupService.activeGroup, true);
nextGroup.focus();
@@ -258,12 +258,12 @@ export class FocusActiveGroupAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.editorGroupService.activeGroup.focus();
return Promise.resolve(true);
@@ -276,12 +276,12 @@ export abstract class BaseFocusGroupAction extends Action {
id: string,
label: string,
private scope: IFindGroupScope,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const group = this.editorGroupService.findGroup(this.scope, this.editorGroupService.activeGroup, true);
if (group) {
group.focus();
@@ -409,8 +409,8 @@ export class OpenToSideFromQuickOpenAction extends Action {
static readonly OPEN_TO_SIDE_LABEL = nls.localize('openToSide', "Open to the Side");
constructor(
@IEditorService private editorService: IEditorService,
@IConfigurationService private configurationService: IConfigurationService
@IEditorService private readonly editorService: IEditorService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(OpenToSideFromQuickOpenAction.OPEN_TO_SIDE_ID, OpenToSideFromQuickOpenAction.OPEN_TO_SIDE_LABEL);
@@ -423,7 +423,7 @@ export class OpenToSideFromQuickOpenAction extends Action {
this.class = (preferredDirection === GroupDirection.RIGHT) ? 'quick-open-sidebyside-vertical' : 'quick-open-sidebyside-horizontal';
}
run(context: any): Thenable<any> {
run(context: any): Promise<any> {
const entry = toEditorQuickOpenEntry(context);
if (entry) {
const input = entry.getInput();
@@ -467,13 +467,13 @@ export class CloseEditorAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'close-editor-action');
}
run(context?: IEditorCommandsContext): Promise<any> {
return this.commandService.executeCommand(CLOSE_EDITOR_COMMAND_ID, void 0, context);
return this.commandService.executeCommand(CLOSE_EDITOR_COMMAND_ID, undefined, context);
}
}
@@ -485,12 +485,12 @@ export class CloseOneEditorAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label, 'close-editor-action');
}
run(context?: IEditorCommandsContext): Thenable<any> {
run(context?: IEditorCommandsContext): Promise<any> {
let group: IEditorGroup;
let editorIndex: number;
if (context) {
@@ -530,12 +530,12 @@ export class RevertAndCloseEditorAction extends Action {
constructor(
id: string,
label: string,
@IEditorService private editorService: IEditorService
@IEditorService private readonly editorService: IEditorService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const activeControl = this.editorService.activeControl;
if (activeControl) {
const editor = activeControl.input;
@@ -563,13 +563,13 @@ export class CloseLeftEditorsInGroupAction extends Action {
constructor(
id: string,
label: string,
@IEditorService private editorService: IEditorService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService
@IEditorService private readonly editorService: IEditorService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(id, label);
}
run(context?: IEditorIdentifier): Thenable<any> {
run(context?: IEditorIdentifier): Promise<any> {
const { group, editor } = getTarget(this.editorService, this.editorGroupService, context);
if (group && editor) {
return group.closeEditors({ direction: CloseDirection.LEFT, except: editor });
@@ -614,7 +614,7 @@ export abstract class BaseCloseAllAction extends Action {
return groupsToClose;
}
run(): Thenable<any> {
run(): Promise<any> {
// Just close all if there are no or one dirty editor
if (this.textFileService.getDirty().length < 2) {
@@ -624,10 +624,10 @@ export abstract class BaseCloseAllAction extends Action {
// Otherwise ask for combined confirmation
return this.textFileService.confirmSave().then(confirm => {
if (confirm === ConfirmResult.CANCEL) {
return void 0;
return undefined;
}
let saveOrRevertPromise: Thenable<boolean>;
let saveOrRevertPromise: Promise<boolean>;
if (confirm === ConfirmResult.DONT_SAVE) {
saveOrRevertPromise = this.textFileService.revertAll(null, { soft: true }).then(() => true);
} else {
@@ -639,12 +639,12 @@ export abstract class BaseCloseAllAction extends Action {
return this.doCloseAll();
}
return void 0;
return undefined;
});
});
}
protected abstract doCloseAll(): Thenable<any>;
protected abstract doCloseAll(): Promise<any>;
}
export class CloseAllEditorsAction extends BaseCloseAllAction {
@@ -677,7 +677,7 @@ export class CloseAllEditorGroupsAction extends BaseCloseAllAction {
@ITextFileService textFileService: ITextFileService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
) {
super(id, label, void 0, textFileService, editorGroupService);
super(id, label, undefined, textFileService, editorGroupService);
}
protected doCloseAll(): Promise<any> {
@@ -695,12 +695,12 @@ export class CloseEditorsInOtherGroupsAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
) {
super(id, label);
}
run(context?: IEditorIdentifier): Thenable<any> {
run(context?: IEditorIdentifier): Promise<any> {
const groupToSkip = context ? this.editorGroupService.getGroup(context.groupId) : this.editorGroupService.activeGroup;
return Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(g => {
if (g.id === groupToSkip.id) {
@@ -720,13 +720,13 @@ export class CloseEditorInAllGroupsAction extends Action {
constructor(
id: string,
label: string,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IEditorService private editorService: IEditorService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IEditorService private readonly editorService: IEditorService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const activeEditor = this.editorService.activeEditor;
if (activeEditor) {
return Promise.all(this.editorGroupService.getGroups(GroupsOrder.MOST_RECENTLY_ACTIVE).map(g => g.closeEditor(activeEditor)));
@@ -780,14 +780,14 @@ export class BaseMoveGroupAction extends Action {
break;
}
for (let i = 0; i < targetNeighbours.length; i++) {
const targetNeighbour = this.editorGroupService.findGroup({ direction: targetNeighbours[i] }, sourceGroup);
if (targetNeighbour) {
return targetNeighbour;
for (const targetNeighbour of targetNeighbours) {
const targetNeighbourGroup = this.editorGroupService.findGroup({ direction: targetNeighbour }, sourceGroup);
if (targetNeighbourGroup) {
return targetNeighbourGroup;
}
}
return void 0;
return undefined;
}
}
@@ -852,11 +852,11 @@ export class MinimizeOtherGroupsAction extends Action {
static readonly ID = 'workbench.action.minimizeOtherEditors';
static readonly LABEL = nls.localize('minimizeOtherEditorGroups', "Maximize Editor Group");
constructor(id: string, label: string, @IEditorGroupsService private editorGroupService: IEditorGroupsService) {
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.editorGroupService.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS);
return Promise.resolve(false);
@@ -868,11 +868,11 @@ export class ResetGroupSizesAction extends Action {
static readonly ID = 'workbench.action.evenEditorWidths';
static readonly LABEL = nls.localize('evenEditorGroups', "Reset Editor Group Sizes");
constructor(id: string, label: string, @IEditorGroupsService private editorGroupService: IEditorGroupsService) {
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.editorGroupService.arrangeGroups(GroupsArrangement.EVEN);
return Promise.resolve(false);
@@ -887,14 +887,14 @@ export class MaximizeGroupAction extends Action {
constructor(
id: string,
label: string,
@IEditorService private editorService: IEditorService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IPartService private partService: IPartService
@IEditorService private readonly editorService: IEditorService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IPartService private readonly partService: IPartService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
if (this.editorService.activeEditor) {
this.editorGroupService.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS);
this.partService.setSideBarHidden(true);
@@ -915,7 +915,7 @@ export abstract class BaseNavigateEditorAction extends Action {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const result = this.navigate();
if (!result) {
return Promise.resolve(false);
@@ -964,7 +964,7 @@ export class OpenNextEditor extends BaseNavigateEditorAction {
return { editor: previousGroupEditors[0], groupId: nextGroup.id };
}
return void 0;
return undefined;
}
}
@@ -999,7 +999,7 @@ export class OpenPreviousEditor extends BaseNavigateEditorAction {
return { editor: previousGroupEditors[previousGroupEditors.length - 1], groupId: previousGroup.id };
}
return void 0;
return undefined;
}
}
@@ -1098,11 +1098,11 @@ export class NavigateForwardAction extends Action {
static readonly ID = 'workbench.action.navigateForward';
static readonly LABEL = nls.localize('navigateNext', "Go Forward");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.forward();
return Promise.resolve(null);
@@ -1114,11 +1114,11 @@ export class NavigateBackwardsAction extends Action {
static readonly ID = 'workbench.action.navigateBack';
static readonly LABEL = nls.localize('navigatePrevious', "Go Back");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.back();
return Promise.resolve(null);
@@ -1130,11 +1130,11 @@ export class NavigateToLastEditLocationAction extends Action {
static readonly ID = 'workbench.action.navigateToLastEditLocation';
static readonly LABEL = nls.localize('navigateToLastEditLocation', "Go to Last Edit Location");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.openLastEditLocation();
return Promise.resolve(null);
@@ -1146,11 +1146,11 @@ export class NavigateLastAction extends Action {
static readonly ID = 'workbench.action.navigateLast';
static readonly LABEL = nls.localize('navigateLast', "Go Last");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.last();
return Promise.resolve(null);
@@ -1165,12 +1165,12 @@ export class ReopenClosedEditorAction extends Action {
constructor(
id: string,
label: string,
@IHistoryService private historyService: IHistoryService
@IHistoryService private readonly historyService: IHistoryService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.reopenLastClosedEditor();
return Promise.resolve(false);
@@ -1185,13 +1185,13 @@ export class ClearRecentFilesAction extends Action {
constructor(
id: string,
label: string,
@IWindowsService private windowsService: IWindowsService,
@IHistoryService private historyService: IHistoryService
@IWindowsService private readonly windowsService: IWindowsService,
@IHistoryService private readonly historyService: IHistoryService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
// Clear global recently opened
this.windowsService.clearRecentlyOpened();
@@ -1232,13 +1232,13 @@ export class BaseQuickOpenEditorInGroupAction extends Action {
constructor(
id: string,
label: string,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IKeybindingService private keybindingService: IKeybindingService
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const keys = this.keybindingService.lookupKeybindings(this.id);
@@ -1287,13 +1287,13 @@ export class OpenPreviousEditorFromHistoryAction extends Action {
constructor(
id: string,
label: string,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IKeybindingService private keybindingService: IKeybindingService
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
const keys = this.keybindingService.lookupKeybindings(this.id);
this.quickOpenService.show(null, { quickNavigateConfiguration: { keybindings: keys } });
@@ -1307,11 +1307,11 @@ export class OpenNextRecentlyUsedEditorAction extends Action {
static readonly ID = 'workbench.action.openNextRecentlyUsedEditor';
static readonly LABEL = nls.localize('openNextRecentlyUsedEditor', "Open Next Recently Used Editor");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.forward(true);
return Promise.resolve(null);
@@ -1323,11 +1323,11 @@ export class OpenPreviousRecentlyUsedEditorAction extends Action {
static readonly ID = 'workbench.action.openPreviousRecentlyUsedEditor';
static readonly LABEL = nls.localize('openPreviousRecentlyUsedEditor', "Open Previous Recently Used Editor");
constructor(id: string, label: string, @IHistoryService private historyService: IHistoryService) {
constructor(id: string, label: string, @IHistoryService private readonly historyService: IHistoryService) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.historyService.back(true);
return Promise.resolve(null);
@@ -1342,12 +1342,12 @@ export class ClearEditorHistoryAction extends Action {
constructor(
id: string,
label: string,
@IHistoryService private historyService: IHistoryService
@IHistoryService private readonly historyService: IHistoryService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
// Editor history
this.historyService.clear();
@@ -1619,7 +1619,7 @@ export class BaseCreateEditorGroupAction extends Action {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
this.editorGroupService.addGroup(this.editorGroupService.activeGroup, this.direction, { activate: true });
return Promise.resolve(true);

View File

@@ -267,8 +267,8 @@ function registerDiffEditorCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: TOGGLE_DIFF_SIDE_BY_SIDE,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
primary: void 0,
when: undefined,
primary: undefined,
handler: accessor => toggleDiffSideBySide(accessor)
});
@@ -287,8 +287,8 @@ function registerDiffEditorCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
primary: void 0,
when: undefined,
primary: undefined,
handler: accessor => toggleDiffIgnoreTrimWhitespace(accessor)
});
}
@@ -319,7 +319,7 @@ function registerOpenEditorAtIndexCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: OPEN_EDITOR_AT_INDEX_COMMAND_ID + visibleIndex,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyMod.Alt | toKeyCode(visibleIndex),
mac: { primary: KeyMod.WinCtrl | toKeyCode(visibleIndex) },
handler: accessor => openEditorAtIndex(accessor, editorIndex)
@@ -340,7 +340,7 @@ function registerOpenEditorAtIndexCommands(): void {
case 9: return KeyCode.KEY_9;
}
return void 0;
return undefined;
}
}
@@ -351,7 +351,7 @@ function registerFocusEditorGroupAtIndexCommands(): void {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: toCommandId(groupIndex),
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyMod.CtrlCmd | toKeyCode(groupIndex),
handler: accessor => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -392,7 +392,7 @@ function registerFocusEditorGroupAtIndexCommands(): void {
case 7: return 'workbench.action.focusEighthEditorGroup';
}
return void 0;
return undefined;
}
function toKeyCode(index: number): KeyCode {
@@ -406,7 +406,7 @@ function registerFocusEditorGroupAtIndexCommands(): void {
case 7: return KeyCode.KEY_8;
}
return void 0;
return undefined;
}
}
@@ -455,7 +455,7 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: CLOSE_SAVED_EDITORS_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_U),
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -475,7 +475,7 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.KEY_W),
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -495,7 +495,7 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: CLOSE_EDITOR_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyMod.CtrlCmd | KeyCode.KEY_W,
win: { primary: KeyMod.CtrlCmd | KeyCode.F4, secondary: [KeyMod.CtrlCmd | KeyCode.KEY_W] },
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
@@ -544,8 +544,8 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
primary: void 0,
when: undefined,
primary: undefined,
mac: { primary: KeyMod.CtrlCmd | KeyMod.Alt | KeyCode.KEY_T },
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -573,8 +573,8 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
primary: void 0,
when: undefined,
primary: undefined,
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -590,7 +590,7 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: KEEP_EDITOR_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
when: undefined,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyCode.Enter),
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
@@ -607,8 +607,8 @@ function registerCloseEditorCommands() {
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: SHOW_EDITORS_IN_GROUP,
weight: KeybindingWeight.WorkbenchContrib,
when: void 0,
primary: void 0,
when: undefined,
primary: undefined,
handler: (accessor, resourceOrContext: URI | IEditorCommandsContext, context?: IEditorCommandsContext) => {
const editorGroupService = accessor.get(IEditorGroupsService);
const quickOpenService = accessor.get(IQuickOpenService);
@@ -638,7 +638,7 @@ function registerCloseEditorCommands() {
});
}
return void 0;
return undefined;
});
}
@@ -655,7 +655,7 @@ function getCommandsContext(resourceOrContext: URI | IEditorCommandsContext, con
return context;
}
return void 0;
return undefined;
}
function resolveCommandsContext(editorGroupService: IEditorGroupsService, context?: IEditorCommandsContext): { group: IEditorGroup, editor: IEditorInput, control: IEditor } {
@@ -682,7 +682,7 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon
if (list instanceof List && list.getHTMLElement() === document.activeElement) {
const elementToContext = (element: IEditorIdentifier | IEditorGroup) => {
if (isEditorGroup(element)) {
return { groupId: element.id, editorIndex: void 0 };
return { groupId: element.id, editorIndex: undefined };
}
return { groupId: element.groupId, editorIndex: editorGroupService.getGroup(element.groupId).getIndexOfEditor(element.editor) };
@@ -690,11 +690,11 @@ export function getMultiSelectedEditorContexts(editorContext: IEditorCommandsCon
const onlyEditorGroupAndEditor = (e: IEditorIdentifier | IEditorGroup) => isEditorGroup(e) || isEditorIdentifier(e);
const focusedElements: (IEditorIdentifier | IEditorGroup)[] = list.getFocusedElements().filter(onlyEditorGroupAndEditor);
const focus = editorContext ? editorContext : focusedElements.length ? focusedElements.map(elementToContext)[0] : void 0; // need to take into account when editor context is { group: group }
const focusedElements: Array<IEditorIdentifier | IEditorGroup> = list.getFocusedElements().filter(onlyEditorGroupAndEditor);
const focus = editorContext ? editorContext : focusedElements.length ? focusedElements.map(elementToContext)[0] : undefined; // need to take into account when editor context is { group: group }
if (focus) {
const selection: (IEditorIdentifier | IEditorGroup)[] = list.getSelectedElements().filter(onlyEditorGroupAndEditor);
const selection: Array<IEditorIdentifier | IEditorGroup> = list.getSelectedElements().filter(onlyEditorGroupAndEditor);
// Only respect selection if it contains focused element
if (selection && selection.some(s => isEditorGroup(s) ? s.id === focus.groupId : s.groupId === focus.groupId && editorGroupService.getGroup(s.groupId).getIndexOfEditor(s.editor) === focus.editorIndex)) {

View File

@@ -8,7 +8,6 @@ import { EditorInput, EditorOptions } from 'vs/workbench/common/editor';
import { Dimension, show, hide, addClass } from 'vs/base/browser/dom';
import { Registry } from 'vs/platform/registry/common/platform';
import { IEditorRegistry, Extensions as EditorExtensions, IEditorDescriptor } from 'vs/workbench/browser/editor';
import { TPromise } from 'vs/base/common/winjs.base';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -31,10 +30,10 @@ export class EditorControl extends Disposable {
private _onDidFocus: Emitter<void> = this._register(new Emitter<void>());
get onDidFocus(): Event<void> { return this._onDidFocus.event; }
private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; }>());
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; }> { return this._onDidSizeConstraintsChange.event; }
private _onDidSizeConstraintsChange = this._register(new Emitter<{ width: number; height: number; } | undefined>());
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return this._onDidSizeConstraintsChange.event; }
private _activeControl: BaseEditor;
private _activeControl: BaseEditor | null;
private controls: BaseEditor[] = [];
private activeControlDisposeables: IDisposable[] = [];
@@ -44,8 +43,8 @@ export class EditorControl extends Disposable {
constructor(
private parent: HTMLElement,
private groupView: IEditorGroupView,
@IPartService private partService: IPartService,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IProgressService progressService: IProgressService
) {
super();
@@ -53,21 +52,24 @@ export class EditorControl extends Disposable {
this.editorOperation = this._register(new LongRunningOperation(progressService));
}
get activeControl(): BaseEditor {
get activeControl() {
return this._activeControl;
}
openEditor(editor: EditorInput, options?: EditorOptions): TPromise<IOpenEditorResult> {
openEditor(editor: EditorInput, options?: EditorOptions): Promise<IOpenEditorResult> {
// Editor control
const descriptor = Registry.as<IEditorRegistry>(EditorExtensions.Editors).getEditor(editor);
const control = this.doShowEditorControl(descriptor, options);
if (!descriptor) {
throw new Error('No editor descriptor found');
}
const control = this.doShowEditorControl(descriptor);
// Set input
return this.doSetInput(control, editor, options).then((editorChanged => (({ control, editorChanged } as IOpenEditorResult))));
return this.doSetInput(control, editor, options || null).then((editorChanged => (({ control, editorChanged } as IOpenEditorResult))));
}
private doShowEditorControl(descriptor: IEditorDescriptor, options: EditorOptions): BaseEditor {
private doShowEditorControl(descriptor: IEditorDescriptor): BaseEditor {
// Return early if the currently active editor control can handle the input
if (this._activeControl && descriptor.describes(this._activeControl)) {
@@ -130,7 +132,7 @@ export class EditorControl extends Disposable {
return control;
}
private doSetActiveControl(control: BaseEditor) {
private doSetActiveControl(control: BaseEditor | null) {
this._activeControl = control;
// Clear out previous active control listeners
@@ -143,10 +145,10 @@ export class EditorControl extends Disposable {
}
// Indicate that size constraints could have changed due to new editor
this._onDidSizeConstraintsChange.fire();
this._onDidSizeConstraintsChange.fire(undefined);
}
private doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions): TPromise<boolean> {
private doSetInput(control: BaseEditor, editor: EditorInput, options: EditorOptions | null): Promise<boolean> {
// If the input did not change, return early and only apply the options
// unless the options instruct us to force open it even if it is the same
@@ -163,7 +165,7 @@ export class EditorControl extends Disposable {
control.focus();
}
return TPromise.as(false);
return Promise.resolve(false);
}
// Show progress while setting input after a certain timeout. If the workbench is opening
@@ -172,7 +174,7 @@ export class EditorControl extends Disposable {
// Call into editor control
const editorWillChange = !inputMatches;
return TPromise.wrap(control.setInput(editor, options, operation.token)).then(() => {
return control.setInput(editor, options, operation.token).then(() => {
// Focus (unless prevented or another operation is running)
if (operation.isCurrent()) {
@@ -191,7 +193,7 @@ export class EditorControl extends Disposable {
// Operation done
operation.stop();
return TPromise.wrapError(e);
return Promise.reject(e);
});
}

View File

@@ -96,7 +96,7 @@ class DropOverlay extends Themable {
private registerListeners(): void {
this._register(new DragAndDropObserver(this.container, {
onDragEnter: e => void 0,
onDragEnter: e => undefined,
onDragOver: e => {
const isDraggingGroup = this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype);
const isDraggingEditor = this.editorTransfer.hasData(DraggedEditorIdentifier.prototype);
@@ -170,7 +170,7 @@ class DropOverlay extends Themable {
return this.accessor.getGroup(this.editorTransfer.getData(DraggedEditorIdentifier.prototype)[0].identifier.groupId);
}
return void 0;
return undefined;
}
private handleDrop(event: DragEvent, splitDirection?: GroupDirection): void {
@@ -303,7 +303,7 @@ class DropOverlay extends Themable {
mousePosX > edgeWidthThreshold && mousePosX < editorControlWidth - edgeWidthThreshold &&
mousePosY > edgeHeightThreshold && mousePosY < editorControlHeight - edgeHeightThreshold
) {
splitDirection = void 0;
splitDirection = undefined;
}
// Offer to split otherwise
@@ -413,7 +413,7 @@ class DropOverlay extends Themable {
removeClass(this.overlay, 'overlay-move-transition');
// Reset current operation
this.currentDropOperation = void 0;
this.currentDropOperation = undefined;
}
contains(element: HTMLElement): boolean {
@@ -440,7 +440,7 @@ export class EditorDropTarget extends Themable {
private accessor: IEditorGroupsAccessor,
private container: HTMLElement,
@IThemeService themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
super(themeService);
@@ -452,7 +452,7 @@ export class EditorDropTarget extends Themable {
return this._overlay;
}
return void 0;
return undefined;
}
private registerListeners(): void {
@@ -512,15 +512,13 @@ export class EditorDropTarget extends Themable {
private findTargetGroupView(child: HTMLElement): IEditorGroupView {
const groups = this.accessor.groups;
for (let i = 0; i < groups.length; i++) {
const groupView = groups[i];
for (const groupView of groups) {
if (isAncestor(child, groupView.element)) {
return groupView;
}
}
return void 0;
return undefined;
}
private updateContainer(isDraggedOver: boolean): void {
@@ -536,7 +534,7 @@ export class EditorDropTarget extends Themable {
private disposeOverlay(): void {
if (this.overlay) {
this.overlay.dispose();
this._overlay = void 0;
this._overlay = undefined;
}
}
}

View File

@@ -4,10 +4,9 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/editorgroupview';
import { TPromise } from 'vs/base/common/winjs.base';
import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext } from 'vs/workbench/common/editor';
import { Event, Emitter, once, Relay } from 'vs/base/common/event';
import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor } from 'vs/workbench/common/editor';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
@@ -100,7 +99,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
private active: boolean;
private dimension: Dimension;
private _whenRestored: Thenable<void>;
private _whenRestored: Promise<void>;
private isRestored: boolean;
private scopedInstantiationService: IInstantiationService;
@@ -116,21 +115,21 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
private ignoreOpenEditorErrors: boolean;
private disposedEditorsWorker: RunOnceWorker<EditorInput>;
private mapEditorToPendingConfirmation: Map<EditorInput, TPromise<boolean>> = new Map<EditorInput, TPromise<boolean>>();
private mapEditorToPendingConfirmation: Map<EditorInput, Promise<boolean>> = new Map<EditorInput, Promise<boolean>>();
constructor(
private accessor: IEditorGroupsAccessor,
from: IEditorGroupView | ISerializedEditorGroup,
private _label: string,
@IInstantiationService private instantiationService: IInstantiationService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService,
@INotificationService private notificationService: INotificationService,
@ITelemetryService private telemetryService: ITelemetryService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
@IKeybindingService private keybindingService: IKeybindingService,
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService,
@INotificationService private readonly notificationService: INotificationService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
// {{SQL CARBON EDIT}}
@ICommandService private commandService: ICommandService
) {
@@ -141,7 +140,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
} else if (isSerializedEditorGroup(from)) {
this._group = this._register(instantiationService.createInstance(EditorGroup, from));
} else {
this._group = this._register(instantiationService.createInstance(EditorGroup, void 0));
this._group = this._register(instantiationService.createInstance(EditorGroup, undefined));
}
this.disposedEditorsWorker = this._register(new RunOnceWorker(editors => this.handleDisposedEditors(editors), 0));
@@ -283,9 +282,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
});
// Toolbar actions
const removeGroupAction = this._register(new Action(CLOSE_EDITOR_GROUP_COMMAND_ID, localize('closeGroupAction', "Close"), 'close-editor-group', true, () => { this.accessor.removeGroup(this); return TPromise.as(true); }));
const removeGroupAction = this._register(new Action(CLOSE_EDITOR_GROUP_COMMAND_ID, localize('closeGroupAction', "Close"), 'close-editor-group', true, () => { this.accessor.removeGroup(this); return Promise.resolve(true); }));
const keybinding = this.keybindingService.lookupKeybinding(removeGroupAction.id);
containerToolbar.push(removeGroupAction, { icon: true, label: false, keybinding: keybinding ? keybinding.getLabel() : void 0 });
containerToolbar.push(removeGroupAction, { icon: true, label: false, keybinding: keybinding ? keybinding.getLabel() : undefined });
}
private createContainerContextMenu(): void {
@@ -309,7 +308,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Fill in contributed actions
const actions: IAction[] = [];
fillInContextMenuActions(menu, void 0, actions, this.contextMenuService);
fillInContextMenuActions(menu, undefined, actions, this.contextMenuService);
// Show it
this.contextMenuService.showContextMenu({
@@ -334,7 +333,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
let target: HTMLElement;
if (e instanceof MouseEvent) {
if (e.button !== 0) {
return void 0; // only for left mouse click
return undefined; // only for left mouse click
}
target = e.target as HTMLElement;
@@ -404,9 +403,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
}
private restoreEditors(from: IEditorGroupView | ISerializedEditorGroup): Thenable<void> {
private restoreEditors(from: IEditorGroupView | ISerializedEditorGroup): Promise<void> {
if (this._group.count === 0) {
return Promise.resolve(void 0); // nothing to show
return Promise.resolve(); // nothing to show
}
// Determine editor options
@@ -491,7 +490,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Close the editor when it is no longer open in any group including diff editors
editorsToClose.forEach(editorToClose => {
const resource = editorToClose ? editorToClose.getResource() : void 0; // prefer resource to not close right-hand side editors of a diff editor
const resource = editorToClose ? editorToClose.getResource() : undefined; // prefer resource to not close right-hand side editors of a diff editor
if (!this.accessor.groups.some(groupView => groupView.group.contains(resource || editorToClose))) {
editorToClose.close();
}
@@ -609,7 +608,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._disposed;
}
get whenRestored(): Thenable<void> {
get whenRestored(): Promise<void> {
return this._whenRestored;
}
@@ -660,7 +659,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
get activeControl(): BaseEditor {
return this.editorControl ? this.editorControl.activeControl : void 0;
return this.editorControl ? this.editorControl.activeControl : undefined;
}
get activeEditor(): EditorInput {
@@ -731,11 +730,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region openEditor()
openEditor(editor: EditorInput, options?: EditorOptions): TPromise<void> {
openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor | null> {
// Guard against invalid inputs
if (!editor) {
return TPromise.as(void 0);
return Promise.resolve(null);
}
// Editor opening event allows for prevention
@@ -750,11 +749,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this.doOpenEditor(editor, options);
}
private doOpenEditor(editor: EditorInput, options?: EditorOptions): TPromise<void> {
private doOpenEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditor> {
// Determine options
const openEditorOptions: IEditorOpenOptions = {
index: options ? options.index : void 0,
index: options ? options.index : undefined,
pinned: !this.accessor.partOptions.enablePreview || editor.isDirty() || (options && options.pinned) || (options && typeof options.index === 'number'),
active: this._group.count === 0 || !options || !options.inactive
};
@@ -791,10 +790,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this.doShowEditor(editor, openEditorOptions.active, options);
}
private doShowEditor(editor: EditorInput, active: boolean, options?: EditorOptions): TPromise<void> {
private doShowEditor(editor: EditorInput, active: boolean, options?: EditorOptions): Promise<IEditor> {
// Show in editor control if the active editor changed
let openEditorPromise: TPromise<void>;
let openEditorPromise: Promise<IEditor>;
if (active) {
openEditorPromise = this.editorControl.openEditor(editor, options).then(result => {
@@ -802,13 +801,17 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
if (result.editorChanged) {
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_ACTIVE, editor });
}
return result.control;
}, error => {
// Handle errors but do not bubble them up
this.doHandleOpenEditorError(error, editor, options);
return null; // error: return NULL as result to signal this
});
} else {
openEditorPromise = TPromise.as(void 0);
openEditorPromise = Promise.resolve(null); // inactive: return NULL as result to signal this
}
// Show in title control after editor control because some actions depend on it
@@ -833,7 +836,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
actions
});
once(handle.onDidClose)(() => dispose(actions.primary));
Event.once(handle.onDidClose)(() => dispose(actions.primary));
}
// Event
@@ -850,17 +853,21 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region openEditors()
openEditors(editors: { editor: EditorInput, options?: EditorOptions }[]): TPromise<void> {
openEditors(editors: { editor: EditorInput, options?: EditorOptions }[]): Promise<IEditor | null> {
if (!editors.length) {
return TPromise.as(void 0);
return Promise.resolve(null);
}
// Do not modify original array
editors = editors.slice(0);
let result: IEditor;
// Use the first editor as active editor
const { editor, options } = editors.shift();
return this.openEditor(editor, options).then(() => {
return this.openEditor(editor, options).then(activeEditor => {
result = activeEditor; // this can be NULL if the opening failed
const startingIndex = this.getIndexOfEditor(editor) + 1;
// Open the other ones inactive
@@ -870,8 +877,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
adjustedEditorOptions.pinned = true;
adjustedEditorOptions.index = startingIndex + index;
return this.openEditor(editor, adjustedEditorOptions);
})).then(() => void 0);
return this.openEditor(editor, adjustedEditorOptions).then(activeEditor => {
if (!result) {
result = activeEditor; // only take if the first editor opening failed
}
});
})).then(() => result);
});
}
@@ -893,7 +904,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
private doMoveEditorInsideGroup(editor: EditorInput, moveOptions?: IMoveEditorOptions): void {
const moveToIndex = moveOptions ? moveOptions.index : void 0;
const moveToIndex = moveOptions ? moveOptions.index : undefined;
if (typeof moveToIndex !== 'number') {
return; // do nothing if we move into same group without index
}
@@ -953,9 +964,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeEditor()
closeEditor(editor: EditorInput = this.activeEditor): TPromise<void> {
closeEditor(editor: EditorInput = this.activeEditor): Promise<void> {
if (!editor) {
return TPromise.as(void 0);
return Promise.resolve();
}
// Check for dirty and veto
@@ -1025,7 +1036,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this.ignoreOpenEditorErrors = true;
}
const options = !focusNext ? EditorOptions.create({ preserveFocus: true }) : void 0;
const options = !focusNext ? EditorOptions.create({ preserveFocus: true }) : undefined;
this.openEditor(nextActiveEditor, options).then(() => {
this.ignoreOpenEditorErrors = false;
});
@@ -1069,9 +1080,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._group.closeEditor(editor);
}
private handleDirty(editors: EditorInput[]): TPromise<boolean /* veto */> {
private handleDirty(editors: EditorInput[]): Promise<boolean /* veto */> {
if (!editors.length) {
return TPromise.as(false); // no veto
return Promise.resolve(false); // no veto
}
const editor = editors.shift();
@@ -1099,13 +1110,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
});
}
private doHandleDirty(editor: EditorInput): TPromise<boolean /* veto */> {
private doHandleDirty(editor: EditorInput): Promise<boolean /* veto */> {
if (
!editor.isDirty() || // editor must be dirty
this.accessor.groups.some(groupView => groupView !== this && groupView.group.contains(editor, true /* support side by side */)) || // editor is opened in other group
editor instanceof SideBySideEditorInput && this.isOpened(editor.master) // side by side editor master is still opened
) {
return TPromise.as(false);
return Promise.resolve(false);
}
// Switch to editor that we want to handle and confirm to save/revert
@@ -1146,9 +1157,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeEditors()
closeEditors(args: EditorInput[] | ICloseEditorsFilter): TPromise<void> {
closeEditors(args: EditorInput[] | ICloseEditorsFilter): Promise<void> {
if (this.isEmpty()) {
return TPromise.as(void 0);
return Promise.resolve();
}
const editors = this.getEditorsToClose(args);
@@ -1219,7 +1230,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeAllEditors()
closeAllEditors(): TPromise<void> {
closeAllEditors(): Promise<void> {
if (this.isEmpty()) {
// If the group is empty and the request is to close all editors, we still close
@@ -1229,7 +1240,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this.accessor.removeGroup(this);
}
return TPromise.as(void 0);
return Promise.resolve();
}
// Check for dirty and veto
@@ -1264,7 +1275,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region replaceEditors()
replaceEditors(editors: EditorReplacement[]): TPromise<void> {
replaceEditors(editors: EditorReplacement[]): Promise<void> {
// Extract active vs. inactive replacements
let activeReplacement: EditorReplacement;
@@ -1322,10 +1333,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Forward to title control
this.titleAreaControl.closeEditor(activeReplacement.editor);
return openEditorResult;
return openEditorResult.then(() => undefined);
}
return TPromise.as(void 0);
return Promise.resolve();
}
//#endregion
@@ -1379,6 +1390,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
layout(width: number, height: number): void {
this.dimension = new Dimension(width, height);
// Ensure editor container gets height as CSS depending
// on the preferred height of the title control
this.editorContainer.style.height = `calc(100% - ${this.titleAreaControl.getPreferredHeight()}px)`;
// Forward to controls
this.titleAreaControl.layout(new Dimension(this.dimension.width, this.titleAreaControl.getPreferredHeight()));
this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - this.titleAreaControl.getPreferredHeight()));
@@ -1410,7 +1425,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
class EditorOpeningEvent implements IEditorOpeningEvent {
private override: () => TPromise<any>;
private override: () => Promise<IEditor>;
constructor(
private _group: GroupIdentifier,
@@ -1431,11 +1446,11 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
return this._options;
}
prevent(callback: () => TPromise<any>): void {
prevent(callback: () => Promise<IEditor>): void {
this.override = callback;
}
isPrevented(): () => TPromise<any> {
isPrevented(): () => Promise<IEditor> {
return this.override;
}
}
@@ -1451,7 +1466,7 @@ registerThemingParticipant((theme, collector, environment) => {
// Letterpress
const letterpress = `resources/letterpress${theme.type === 'dark' ? '-dark' : theme.type === 'hc' ? '-hc' : ''}.svg`;
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container.empty .editor-group-letterpress {
.monaco-workbench .part.editor > .content .editor-group-container.empty .editor-group-letterpress {
background-image: url('${URI.file(join(environment.appRoot, letterpress)).toString()}')
}
`);
@@ -1460,20 +1475,20 @@ registerThemingParticipant((theme, collector, environment) => {
const focusedEmptyGroupBorder = theme.getColor(EDITOR_GROUP_FOCUSED_EMPTY_BORDER);
if (focusedEmptyGroupBorder) {
collector.addRule(`
.monaco-workbench > .part.editor > .content:not(.empty) .editor-group-container.empty.active:focus {
.monaco-workbench .part.editor > .content:not(.empty) .editor-group-container.empty.active:focus {
outline-width: 1px;
outline-color: ${focusedEmptyGroupBorder};
outline-offset: -2px;
outline-style: solid;
}
.monaco-workbench > .part.editor > .content.empty .editor-group-container.empty.active:focus {
.monaco-workbench .part.editor > .content.empty .editor-group-container.empty.active:focus {
outline: none; /* never show outline for empty group if it is the last */
}
`);
} else {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container.empty.active:focus {
.monaco-workbench .part.editor > .content .editor-group-container.empty.active:focus {
outline: none; /* disable focus outline unless active empty group border is defined */
}
`);

View File

@@ -7,11 +7,11 @@ import 'vs/workbench/browser/parts/editor/editor.contribution';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Part } from 'vs/workbench/browser/part';
import { Dimension, isAncestor, toggleClass, addClass, $ } from 'vs/base/browser/dom';
import { Event, Emitter, once, Relay, anyEvent } from 'vs/base/common/event';
import { Event, Emitter, Relay } from 'vs/base/common/event';
import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry';
import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument } from 'vs/workbench/services/group/common/editorGroupsService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid';
import { Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid, ISerializableView } from 'vs/base/browser/ui/grid/grid';
import { GroupIdentifier, IWorkbenchEditorConfiguration } from 'vs/workbench/common/editor';
import { values } from 'vs/base/common/map';
import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme';
@@ -23,13 +23,13 @@ import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { always } from 'vs/base/common/async';
import { EditorDropTarget } from 'vs/workbench/browser/parts/editor/editorDropTarget';
import { localize } from 'vs/nls';
import { Color } from 'vs/base/common/color';
import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout';
import { IView, orthogonal } from 'vs/base/browser/ui/grid/gridview';
import { IView, orthogonal, LayoutPriority } from 'vs/base/browser/ui/grid/gridview';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Parts } from 'vs/workbench/services/part/common/partService';
// {{SQL CARBON EDIT}}
import { convertEditorInput } from 'sql/parts/common/customInputConverter';
@@ -83,7 +83,7 @@ class GridWidgetView<T extends IView> implements IView {
}
}
export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditorGroupsAccessor {
export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditorGroupsAccessor, ISerializableView {
_serviceBrand: any;
@@ -109,11 +109,14 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
private onDidSetGridWidget = this._register(new Emitter<{ width: number; height: number; }>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; }>());
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; }> { return anyEvent(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); }
get onDidSizeConstraintsChange(): Event<{ width: number; height: number; }> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); }
private _onDidPreferredSizeChange: Emitter<void> = this._register(new Emitter<void>());
get onDidPreferredSizeChange(): Event<void> { return this._onDidPreferredSizeChange.event; }
private _onDidActivateGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
get onDidActivateGroup(): Event<IEditorGroupView> { return this._onDidActivateGroup.event; }
//#endregion
private dimension: Dimension;
@@ -133,15 +136,22 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
private gridWidget: SerializableGrid<IEditorGroupView>;
private gridWidgetView: GridWidgetView<IEditorGroupView>;
private _whenRestored: Thenable<void>;
private _whenRestored: Promise<void>;
private whenRestoredResolve: () => void;
element: HTMLElement;
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
priority: LayoutPriority = LayoutPriority.High;
constructor(
id: string,
private restorePreviousState: boolean,
@IInstantiationService private instantiationService: IInstantiationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IConfigurationService private configurationService: IConfigurationService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IStorageService storageService: IStorageService
) {
super(id, { hasTitle: false }, themeService, storageService);
@@ -220,13 +230,13 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
get orientation(): GroupOrientation {
if (!this.gridWidget) {
return void 0; // we have not been created yet
return undefined; // we have not been created yet
}
return this.gridWidget.orientation === Orientation.VERTICAL ? GroupOrientation.VERTICAL : GroupOrientation.HORIZONTAL;
}
get whenRestored(): Thenable<void> {
get whenRestored(): Promise<void> {
return this._whenRestored;
}
@@ -316,6 +326,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
const groupView = this.assertGroupView(group);
this.doSetGroupActive(groupView);
this._onDidActivateGroup.fire(groupView);
return groupView;
}
@@ -527,7 +538,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
}));
// Track dispose
once(groupView.onWillDispose)(() => {
Event.once(groupView.onWillDispose)(() => {
groupDisposables = dispose(groupDisposables);
this.groupViews.delete(groupView.id);
this.doUpdateMostRecentActive(groupView);
@@ -762,7 +773,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
private resetPreferredSize(): void {
// Reset (will be computed upon next access)
this._preferredSize = void 0;
this._preferredSize = undefined;
// Event
this._onDidPreferredSizeChange.fire();
@@ -783,6 +794,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
createContentArea(parent: HTMLElement): HTMLElement {
// Container
this.element = parent;
this.container = document.createElement('div');
addClass(this.container, 'content');
parent.appendChild(this.container);
@@ -824,7 +836,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
}
// Signal restored
always(Promise.all(this.groups.map(group => group.whenRestored)), () => this.whenRestoredResolve());
Promise.all(this.groups.map(group => group.whenRestored)).finally(() => this.whenRestoredResolve());
// Update container
this.updateContainer();
@@ -861,7 +873,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
this.groupViews.forEach(group => group.dispose());
this.groupViews.clear();
this._activeGroup = void 0;
this._activeGroup = undefined;
this.mostRecentActiveGroups = [];
}
@@ -924,7 +936,7 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
this._onDidSizeConstraintsChange.input = gridWidget.onDidChange;
}
this.onDidSetGridWidget.fire();
this.onDidSetGridWidget.fire(undefined);
}
private updateContainer(): void {
@@ -950,12 +962,16 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
return this.groupViews.size === 1 && this._activeGroup.isEmpty();
}
layout(dimension: Dimension): Dimension[] {
const sizes = super.layout(dimension);
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
const sizes = super.layout(dim1 instanceof Dimension ? dim1 : new Dimension(dim1, dim2));
this.doLayout(sizes[1]);
return sizes;
if (dim1 instanceof Dimension) {
return sizes;
}
}
private doLayout(dimension: Dimension): void {
@@ -1016,4 +1032,10 @@ export class EditorPart extends Part implements EditorGroupsServiceImpl, IEditor
}
//#endregion
}
toJSON(): object {
return {
type: Parts.EDITOR_PART
};
}
}

View File

@@ -25,8 +25,8 @@ export class EditorPickerEntry extends QuickOpenEntryGroup {
constructor(
private editor: EditorInput,
private _group: IEditorGroup,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService
) {
super();
}
@@ -90,7 +90,7 @@ export abstract class BaseEditorPicker extends QuickOpenHandler {
this.scorerCache = Object.create(null);
}
getResults(searchValue: string, token: CancellationToken): Thenable<QuickOpenModel> {
getResults(searchValue: string, token: CancellationToken): Promise<QuickOpenModel | null> {
const editorEntries = this.getEditorEntries();
if (!editorEntries.length) {
return Promise.resolve(null);

View File

@@ -50,7 +50,7 @@ import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { timeout } from 'vs/base/common/async';
import { INotificationHandle, INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { once } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
class SideBySideEditorEncodingSupport implements IEncodingSupport {
constructor(private master: IEncodingSupport, private details: IEncodingSupport) { }
@@ -290,12 +290,12 @@ export class EditorStatus implements IStatusbarItem {
private screenReaderNotification: INotificationHandle;
constructor(
@IEditorService private editorService: IEditorService,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IInstantiationService private instantiationService: IInstantiationService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
@IModeService private modeService: IModeService,
@ITextFileService private textFileService: ITextFileService,
@IEditorService private readonly editorService: IEditorService,
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IModeService private readonly modeService: IModeService,
@ITextFileService private readonly textFileService: ITextFileService,
@IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService,
@INotificationService private readonly notificationService: INotificationService
) {
@@ -518,7 +518,7 @@ export class EditorStatus implements IStatusbarItem {
{ sticky: true }
);
once(this.screenReaderNotification.onDidClose)(() => {
Event.once(this.screenReaderNotification.onDidClose)(() => {
this.screenReaderNotification = null;
});
}
@@ -548,7 +548,7 @@ export class EditorStatus implements IStatusbarItem {
private updateStatusBar(): void {
const activeControl = this.editorService.activeControl;
const activeCodeEditor = activeControl ? getCodeEditor(activeControl.getControl()) : void 0;
const activeCodeEditor = activeControl ? getCodeEditor(activeControl.getControl()) : undefined;
// Update all states
this.onScreenReaderModeChange(activeCodeEditor);
@@ -587,8 +587,8 @@ export class EditorStatus implements IStatusbarItem {
this.onEOLChange(activeCodeEditor);
let selections = activeCodeEditor.getSelections();
for (let i = 0; i < e.changes.length; i++) {
if (selections.some(selection => Range.areIntersecting(selection, e.changes[i].range))) {
for (const change of e.changes) {
if (selections.some(selection => Range.areIntersecting(selection, change.range))) {
this.onSelectionChange(activeCodeEditor);
break;
}
@@ -820,7 +820,7 @@ export class ShowLanguageExtensionsAction extends Action {
constructor(
private fileExtension: string,
@ICommandService private commandService: ICommandService,
@ICommandService private readonly commandService: ICommandService,
@IExtensionGalleryService galleryService: IExtensionGalleryService
) {
super(ShowLanguageExtensionsAction.ID, nls.localize('showLanguageExtensions', "Search Marketplace Extensions for '{0}'...", fileExtension));
@@ -828,8 +828,8 @@ export class ShowLanguageExtensionsAction extends Action {
this.enabled = galleryService.isEnabled();
}
run(): Thenable<void> {
return this.commandService.executeCommand('workbench.extensions.action.showExtensionsForLanguage', this.fileExtension).then(() => void 0);
run(): Promise<void> {
return this.commandService.executeCommand('workbench.extensions.action.showExtensionsForLanguage', this.fileExtension).then(() => undefined);
}
}
@@ -841,19 +841,19 @@ export class ChangeModeAction extends Action {
constructor(
actionId: string,
actionLabel: string,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService,
@IEditorService private editorService: IEditorService,
@IWorkspaceConfigurationService private configurationService: IWorkspaceConfigurationService,
@IQuickInputService private quickInputService: IQuickInputService,
@IPreferencesService private preferencesService: IPreferencesService,
@IInstantiationService private instantiationService: IInstantiationService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@IEditorService private readonly editorService: IEditorService,
@IWorkspaceConfigurationService private readonly configurationService: IWorkspaceConfigurationService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService
) {
super(actionId, actionLabel);
}
run(): Thenable<any> {
run(): Promise<any> {
const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget);
if (!activeTextEditorWidget) {
return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
@@ -958,6 +958,7 @@ export class ChangeModeAction extends Action {
}
// Change mode for active editor
// {{SQL CARBON EDIT}} - Get activeControl instead of activeEditor
const activeEditor = this.editorService.activeControl;
const activeTextEditorWidget = this.editorService.activeTextEditorWidget;
const models: ITextModel[] = [];
@@ -1012,7 +1013,7 @@ export class ChangeModeAction extends Action {
return <IQuickPickItem>{
id,
label: lang,
description: (id === currentAssociation) ? nls.localize('currentAssociation', "Current Association") : void 0
description: (id === currentAssociation) ? nls.localize('currentAssociation', "Current Association") : undefined
};
});
@@ -1061,13 +1062,13 @@ class ChangeIndentationAction extends Action {
constructor(
actionId: string,
actionLabel: string,
@IEditorService private editorService: IEditorService,
@IQuickInputService private quickInputService: IQuickInputService
@IEditorService private readonly editorService: IEditorService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(actionId, actionLabel);
}
run(): Thenable<any> {
run(): Promise<any> {
const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget);
if (!activeTextEditorWidget) {
return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
@@ -1111,13 +1112,13 @@ export class ChangeEOLAction extends Action {
constructor(
actionId: string,
actionLabel: string,
@IEditorService private editorService: IEditorService,
@IQuickInputService private quickInputService: IQuickInputService
@IEditorService private readonly editorService: IEditorService,
@IQuickInputService private readonly quickInputService: IQuickInputService
) {
super(actionId, actionLabel);
}
run(): Thenable<any> {
run(): Promise<any> {
const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget);
if (!activeTextEditorWidget) {
return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
@@ -1156,15 +1157,15 @@ export class ChangeEncodingAction extends Action {
constructor(
actionId: string,
actionLabel: string,
@IEditorService private editorService: IEditorService,
@IQuickInputService private quickInputService: IQuickInputService,
@ITextResourceConfigurationService private textResourceConfigurationService: ITextResourceConfigurationService,
@IFileService private fileService: IFileService
@IEditorService private readonly editorService: IEditorService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@ITextResourceConfigurationService private readonly textResourceConfigurationService: ITextResourceConfigurationService,
@IFileService private readonly fileService: IFileService
) {
super(actionId, actionLabel);
}
run(): Thenable<any> {
run(): Promise<any> {
if (!getCodeEditor(this.editorService.activeTextEditorWidget)) {
return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
}
@@ -1196,7 +1197,7 @@ export class ChangeEncodingAction extends Action {
return pickActionPromise.then(action => {
if (!action) {
return void 0;
return undefined;
}
const resource = toResource(activeControl.input, { supportSideBySide: true });

View File

@@ -34,7 +34,7 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
private label: string,
keyBindingAction: string,
@IKeybindingService keybindingService: IKeybindingService,
@IThemeService private themeService: IThemeService
@IThemeService private readonly themeService: IThemeService
) {
super();
@@ -106,9 +106,9 @@ export class OpenWorkspaceButtonContribution extends Disposable implements IEdit
constructor(
private editor: ICodeEditor,
@IInstantiationService private instantiationService: IInstantiationService,
@IWindowService private windowService: IWindowService,
@IWorkspaceContextService private contextService: IWorkspaceContextService
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IWindowService private readonly windowService: IWindowService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService
) {
super();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 266 B

View File

@@ -3,17 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control.hidden {
.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control.hidden {
display: none;
}
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .monaco-icon-label,
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .monaco-icon-label {
.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .monaco-icon-label,
.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .monaco-icon-label {
text-decoration-line: underline;
}
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .hint-more,
.monaco-workbench>.part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .hint-more {
.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.selected .hint-more,
.monaco-workbench .part.editor>.content .editor-group-container .breadcrumbs-control .monaco-breadcrumb-item.focused .hint-more {
text-decoration-line: underline;
}

View File

@@ -5,26 +5,26 @@
/* Container */
.monaco-workbench > .part.editor > .content .editor-group-container {
.monaco-workbench .part.editor > .content .editor-group-container {
height: 100%;
}
.monaco-workbench > .part.editor > .content .editor-group-container.empty {
.monaco-workbench .part.editor > .content .editor-group-container.empty {
opacity: 0.5; /* dimmed to indicate inactive state */
}
.monaco-workbench > .part.editor > .content .editor-group-container.empty.active,
.monaco-workbench > .part.editor > .content .editor-group-container.empty.dragged-over {
.monaco-workbench .part.editor > .content .editor-group-container.empty.active,
.monaco-workbench .part.editor > .content .editor-group-container.empty.dragged-over {
opacity: 1; /* indicate active/dragged-over group through undimmed state */
}
/* Letterpress */
.monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-letterpress {
.monaco-workbench .part.editor > .content .editor-group-container > .editor-group-letterpress {
display: none; /* only visible when empty */
}
.monaco-workbench > .part.editor > .content .editor-group-container.empty > .editor-group-letterpress {
.monaco-workbench .part.editor > .content .editor-group-container.empty > .editor-group-letterpress {
display: block;
margin: auto;
width: 100%;
@@ -35,25 +35,25 @@
background-size: 70% 70%;
}
.monaco-workbench > .part.editor > .content.empty .editor-group-container.empty > .editor-group-letterpress {
.monaco-workbench .part.editor > .content.empty .editor-group-container.empty > .editor-group-letterpress {
background-size: 100% 100%; /* larger for empty editor part */
height: 100%; /* no toolbar in this case */
}
/* Title */
.monaco-workbench > .part.editor > .content .editor-group-container > .title {
.monaco-workbench .part.editor > .content .editor-group-container > .title {
position: relative;
box-sizing: border-box;
overflow: hidden;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title:not(.tabs) {
.monaco-workbench .part.editor > .content .editor-group-container > .title:not(.tabs) {
display: flex; /* when tabs are not shown, use flex layout */
flex-wrap: nowrap;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.title-border-bottom::after {
.monaco-workbench .part.editor > .content .editor-group-container > .title.title-border-bottom::after {
content: '';
position: absolute;
bottom: 0;
@@ -65,21 +65,21 @@
height: 1px;
}
.monaco-workbench > .part.editor > .content .editor-group-container.empty > .title {
.monaco-workbench .part.editor > .content .editor-group-container.empty > .title {
display: none;
}
/* Toolbar */
.monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-container-toolbar {
.monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar {
display: none;
}
.monaco-workbench > .part.editor > .content:not(.empty) .editor-group-container.empty > .editor-group-container-toolbar {
.monaco-workbench .part.editor > .content:not(.empty) .editor-group-container.empty > .editor-group-container-toolbar {
display: block;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-container-toolbar .action-label {
.monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .action-label {
display: block;
height: 35px;
line-height: 35px;
@@ -89,30 +89,26 @@
background-repeat: no-repeat;
}
.vs .monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group {
.vs .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group {
background-image: url('close-big.svg');
}
.vs-dark .monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group {
.vs-dark .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group,
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group {
background-image: url('close-big-inverse.svg');
}
/* Editor */
.monaco-workbench > .part.editor > .content .editor-group-container > .editor-container {
height: calc(100% - 35px); /* below title control */
}
.monaco-workbench > .part.editor > .content .editor-group-container.empty > .editor-container {
.monaco-workbench .part.editor > .content .editor-group-container.empty > .editor-container {
display: none;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .editor-container > .editor-instance {
.monaco-workbench .part.editor > .content .editor-group-container > .editor-container > .editor-instance {
height: 100%;
}
.monaco-workbench > .part.editor > .content .grid-view-container {
.monaco-workbench .part.editor > .content .grid-view-container {
width: 100%;
height: 100%;
}

View File

@@ -22,7 +22,7 @@
cursor: default !important;
}
.monaco-shell .screen-reader-detected-explanation {
.monaco-workbench .screen-reader-detected-explanation {
width: 420px;
top: 30px;
right: 6px;
@@ -30,7 +30,7 @@
cursor: default;
}
.monaco-shell .screen-reader-detected-explanation .cancel {
.monaco-workbench .screen-reader-detected-explanation .cancel {
position: absolute;
top: 0;
right: 0;
@@ -41,27 +41,27 @@
cursor: pointer;
}
.monaco-shell .screen-reader-detected-explanation h2 {
.monaco-workbench .screen-reader-detected-explanation h2 {
margin: 0;
padding: 0;
font-weight: 400;
font-size: 1.8em;
}
.monaco-shell .screen-reader-detected-explanation p {
.monaco-workbench .screen-reader-detected-explanation p {
font-size: 1.2em;
}
.monaco-shell .screen-reader-detected-explanation hr {
.monaco-workbench .screen-reader-detected-explanation hr {
border: 0;
height: 2px;
}
.monaco-shell .screen-reader-detected-explanation .buttons {
.monaco-workbench .screen-reader-detected-explanation .buttons {
display: flex;
}
.monaco-shell .screen-reader-detected-explanation .buttons a {
.monaco-workbench .screen-reader-detected-explanation .buttons a {
font-size: 13px;
padding-left: 12px;
padding-right: 12px;
@@ -69,11 +69,11 @@
max-width: fit-content;
}
.monaco-shell.vs .screen-reader-detected-explanation .cancel {
.vs .monaco-workbench .screen-reader-detected-explanation .cancel {
background: url('close-statusview.svg') center center no-repeat;
}
.monaco-shell.vs-dark .screen-reader-detected-explanation .cancel,
.monaco-shell.hc-black .screen-reader-detected-explanation .cancel {
.vs-dark .monaco-workbench .screen-reader-detected-explanation .cancel,
.hc-black .monaco-workbench .screen-reader-detected-explanation .cancel {
background: url('close-statusview-inverse.svg') center center no-repeat;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 B

After

Width:  |  Height:  |  Size: 258 B

View File

@@ -5,7 +5,8 @@
/* Title Label */
.monaco-workbench > .part.editor > .content .editor-group-container > .title > .label-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title > .label-container {
height: 35px;
display: flex;
justify-content: flex-start;
align-items: center;
@@ -13,7 +14,7 @@
flex: auto;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-label {
line-height: 35px;
overflow: hidden;
text-overflow: ellipsis;
@@ -21,31 +22,31 @@
padding-left: 20px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .no-tabs.title-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .no-tabs.title-label {
flex: none;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .monaco-icon-label::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title .monaco-icon-label::before {
height: 35px; /* tweak the icon size of the editor labels when icons are enabled */
}
/* Breadcrumbs */
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control {
flex: 1 50%;
overflow: hidden;
margin-left: .45em;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item {
font-size: 0.9em;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.preview .monaco-breadcrumb-item {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.preview .monaco-breadcrumb-item {
font-style: italic;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
content: '/';
opacity: 1;
height: inherit;
@@ -54,35 +55,36 @@
}
/* {{SQL CARBON EDIT}} */
.monaco-workbench.windows > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
.windows > .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
content: '/';
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder::before,
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder + .monaco-breadcrumb-item::before,
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.relative-path .monaco-breadcrumb-item:nth-child(2)::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder + .monaco-breadcrumb-item::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control.relative-path .monaco-breadcrumb-item:nth-child(2)::before,
.windows > .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:nth-child(2)::before {
/* workspace folder, item following workspace folder, or relative path -> hide first seperator */
display: none;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder::after {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item.root_folder::after {
/* use dot separator for workspace folder */
content: '\00a0•\00a0';
padding: 0px;
padding: 0;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
.monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
padding-right: 4px; /* does not have trailing separator*/
}
/* Title Actions */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-actions {
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions {
display: flex;
flex: initial;
opacity: 0.5;
height: 35px;
}
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .title-actions {
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .title-actions {
opacity: 1;
}

View File

@@ -5,37 +5,37 @@
/* Title Container */
.monaco-workbench > .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container {
display: flex;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container > .monaco-scrollable-element {
.monaco-workbench .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container > .monaco-scrollable-element {
flex: 1;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container > .monaco-scrollable-element .scrollbar {
.monaco-workbench .part.editor > .content .editor-group-container > .title.tabs > .tabs-and-actions-container > .monaco-scrollable-element .scrollbar {
z-index: 3; /* on top of tabs */
cursor: default;
}
/* Tabs Container */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container {
display: flex;
height: 35px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container.scroll {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container.scroll {
overflow: scroll !important;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container::-webkit-scrollbar {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container::-webkit-scrollbar {
display: none;
}
/* Tab */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab {
position: relative;
display: flex;
white-space: nowrap;
@@ -45,45 +45,45 @@
padding-left: 10px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-right,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-off {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-right,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.has-icon-theme.close-button-off {
padding-left: 5px; /* reduce padding when we show icons and are in shrinking mode and tab close button is not left */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit {
width: 120px;
min-width: fit-content;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink {
min-width: 60px;
flex-basis: 0; /* all tabs are even */
flex-grow: 1; /* all tabs grow even */
max-width: fit-content;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-left::after,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off::after {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-left::after,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off::after {
content: '';
display: flex;
flex: 0;
width: 5px; /* Reserve space to hide tab fade when close button is left or off (fixes https://github.com/Microsoft/vscode/issues/45728) */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-left {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-left {
min-width: 80px; /* make more room for close button when it shows to the left */
padding-right: 5px; /* we need less room when sizing is shrink */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged {
will-change: transform; /* forces tab to be drawn on a separate layer (fixes https://github.com/Microsoft/vscode/issues/18733) */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged-over div {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dragged-over div {
pointer-events: none; /* prevents cursor flickering (fixes https://github.com/Microsoft/vscode/issues/38753) */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-left {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-left {
flex-direction: row-reverse;
padding-left: 0;
padding-right: 10px;
@@ -91,14 +91,14 @@
/* Tab border top/bottom */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-top-container,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-border-bottom-container {
display: none; /* hidden by default until a color is provided (see below) */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-top > .tab-border-top-container,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-bottom > .tab-border-bottom-container,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty-border-top > .tab-border-top-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-top > .tab-border-top-container,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-bottom > .tab-border-bottom-container,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty-border-top > .tab-border-top-container {
display: block;
position: absolute;
left: 0;
@@ -107,19 +107,19 @@
width: 100%;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-top > .tab-border-top-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-top > .tab-border-top-container {
top: 0;
height: 1px;
background-color: var(--tab-border-top-color);
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-bottom > .tab-border-bottom-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active.tab-border-bottom > .tab-border-bottom-container {
bottom: 0;
height: 1px;
background-color: var(--tab-border-bottom-color);
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty-border-top > .tab-border-top-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty-border-top > .tab-border-top-container {
top: 0;
height: 2px;
background-color: var(--tab-dirty-border-top-color);
@@ -127,16 +127,16 @@
/* Tab Label */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label {
margin-top: auto;
margin-bottom: auto;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink .tab-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink .tab-label {
position: relative;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label::after {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .tab-label::after {
content: '';
position: absolute;
right: 0;
@@ -146,66 +146,66 @@
padding: 0;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink:focus > .tab-label::after {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink:focus > .tab-label::after {
opacity: 0; /* when tab has the focus this shade breaks the tab border (fixes https://github.com/Microsoft/vscode/issues/57819) */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label > .monaco-icon-label-description-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label > .monaco-icon-label-description-container {
overflow: visible; /* fixes https://github.com/Microsoft/vscode/issues/20182 */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-description-container {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-description-container {
text-overflow: clip;
}
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-description-container {
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-description-container {
text-overflow: ellipsis;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .monaco-icon-label::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .monaco-icon-label::before {
height: 16px; /* tweak the icon size of the editor labels when icons are enabled */
}
/* Tab Close */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-close {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-close {
margin-top: auto;
margin-bottom: auto;
width: 28px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink > .tab-close {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink > .tab-close {
flex: 0;
overflow: hidden; /* let the close button be pushed out of view when sizing is set to shrink to make more room... */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty.close-button-right.sizing-shrink > .tab-close,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink:hover > .tab-close,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink > .tab-close:focus-within {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty.close-button-right.sizing-shrink > .tab-close,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink:hover > .tab-close,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-right.sizing-shrink > .tab-close:focus-within {
overflow: visible; /* ...but still show the close button on hover, focus and when dirty */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off > .tab-close {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off > .tab-close {
display: none; /* hide the close action bar when we are configured to hide it */
}
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active > .tab-close .action-label, /* always show it for active tab */
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab > .tab-close .action-label:focus, /* always show it on focus */
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover > .tab-close .action-label, /* always show it on hover */
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active:hover > .tab-close .action-label, /* always show it on hover */
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-close .action-label { /* always show it for dirty tabs */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active > .tab-close .action-label, /* always show it for active tab */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab > .tab-close .action-label:focus, /* always show it on focus */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover > .tab-close .action-label, /* always show it on hover */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.active:hover > .tab-close .action-label, /* always show it on hover */
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab.dirty > .tab-close .action-label { /* always show it for dirty tabs */
opacity: 1;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover > .tab-close .action-label { /* show dimmed for inactive group */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label, /* show dimmed for inactive group */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover > .tab-close .action-label { /* show dimmed for inactive group */
opacity: 0.5;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-close .action-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab > .tab-close .action-label {
opacity: 0;
display: block;
height: 16px;
@@ -216,53 +216,53 @@
margin-right: 0.5em;
}
.vs .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action {
.vs .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action {
background: url('close-dirty.svg') center center no-repeat;
}
.vs-dark .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action {
.vs-dark .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action,
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action {
background: url('close-dirty-inverse.svg') center center no-repeat;
}
.vs .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover {
.vs .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover {
background: url('close.svg') center center no-repeat;
}
.vs-dark .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover {
.vs-dark .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover,
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover {
background: url('close-inverse.svg') center center no-repeat;
}
/* No Tab Close Button */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off {
padding-right: 10px; /* give a little bit more room if close button is off */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink.close-button-off {
padding-right: 5px; /* we need less room when sizing is shrink */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top) {
background-repeat: no-repeat;
background-position-y: center;
background-position-x: calc(100% - 6px); /* to the right of the tab label */
padding-right: 28px; /* make room for dirty indication when we are running without close button */
}
.vs .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty {
.vs .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top) {
background-image: url('close-dirty.svg');
}
.vs-dark .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty {
.vs-dark .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top),
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty {
background-image: url('close-dirty-inverse.svg');
}
/* Editor Actions */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .editor-actions {
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions {
cursor: default;
flex: initial;
padding-left: 4px;
@@ -271,30 +271,30 @@
/* Breadcrumbs */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control {
flex: 1 100%;
height: 22px;
cursor: default;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-icon-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-icon-label {
height: 22px;
line-height: 22px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-icon-label::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-icon-label::before {
height: 22px; /* tweak the icon size of the editor labels when icons are enabled */
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item {
max-width: 80%;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before {
min-width: 16px;
height: 22px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item:last-child {
padding-right: 8px;
}

View File

@@ -5,31 +5,31 @@
/* Editor Label */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label {
white-space: nowrap;
flex: 1;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label a,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label a {
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-label a,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label a {
text-decoration: none;
font-size: 13px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .monaco-icon-label::before,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .monaco-icon-label::before,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label a,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label a,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-label h2,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label span {
.monaco-workbench .part.editor > .content .editor-group-container > .title .monaco-icon-label::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .monaco-icon-label::before,
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-label a,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label a,
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-label h2,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab .tab-label span {
cursor: pointer;
}
/* Title Actions */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-actions .action-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .editor-actions .action-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label {
display: block;
height: 35px;
line-height: 35px;
@@ -39,29 +39,29 @@
background-repeat: no-repeat;
}
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .title-actions .action-label,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .editor-actions .action-label {
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label,
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label {
line-height: initial;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .editor-actions .action-label .label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .title-actions .action-label .label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label .label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label .label {
display: none;
}
/* Drag Cursor */
.monaco-workbench > .part.editor > .content .editor-group-container > .title {
.monaco-workbench .part.editor > .content .editor-group-container > .title {
cursor: -webkit-grab;
}
/* Actions */
.monaco-workbench > .part.editor > .content .editor-group-container > .title .close-editor-action {
.monaco-workbench .part.editor > .content .editor-group-container > .title .close-editor-action {
background: url('close.svg') center center no-repeat;
}
.vs-dark .monaco-workbench > .part.editor > .content .editor-group-container > .title .close-editor-action,
.hc-black .monaco-workbench > .part.editor > .content .editor-group-container > .title .close-editor-action {
.vs-dark .monaco-workbench .part.editor > .content .editor-group-container > .title .close-editor-action,
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .close-editor-action {
background: url('close-inverse.svg') center center no-repeat;
}

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/notabstitlecontrol';
import { toResource, Verbosity, IEditorInput } from 'vs/workbench/common/editor';
import { TitleControl, IToolbarActions } from 'vs/workbench/browser/parts/editor/titleControl';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import { ResourceLabel, IResourceLabel } from 'vs/workbench/browser/labels';
import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
import { addDisposableListener, EventType, addClass, EventHelper, removeClass, toggleClass } from 'vs/base/browser/dom';
@@ -22,7 +22,7 @@ interface IRenderedEditorLabel {
export class NoTabsTitleControl extends TitleControl {
private titleContainer: HTMLElement;
private editorLabel: ResourceLabel;
private editorLabel: IResourceLabel;
private activeLabel: IRenderedEditorLabel = Object.create(null);
protected create(parent: HTMLElement): void {
@@ -40,8 +40,8 @@ export class NoTabsTitleControl extends TitleControl {
this.titleContainer.appendChild(labelContainer);
// Editor Label
this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, void 0));
this._register(this.editorLabel.onClick(e => this.onTitleLabelClick(e)));
this.editorLabel = this._register(this.instantiationService.createInstance(ResourceLabel, labelContainer, undefined)).element;
this._register(addDisposableListener(this.editorLabel.element, EventType.CLICK, e => this.onTitleLabelClick(e)));
// Breadcrumbs
this.createBreadcrumbsControl(labelContainer, { showFileIcons: false, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: () => Color.transparent });
@@ -244,7 +244,7 @@ export class NoTabsTitleControl extends TitleControl {
title = ''; // dont repeat what is already shown
}
this.editorLabel.setLabel({ name, description, resource }, { title, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] });
this.editorLabel.setResource({ name, description, resource }, { title, italic: !isEditorPinned, extraClasses: ['no-tabs', 'title-label'] });
if (isGroupActive) {
this.editorLabel.element.style.color = this.getColor(TAB_ACTIVE_FOREGROUND);
} else {

View File

@@ -28,7 +28,7 @@ export class RangeHighlightDecorations extends Disposable {
private readonly _onHighlightRemoved: Emitter<void> = this._register(new Emitter<void>());
get onHighlghtRemoved(): Event<void> { return this._onHighlightRemoved.event; }
constructor(@IEditorService private editorService: IEditorService) {
constructor(@IEditorService private readonly editorService: IEditorService) {
super();
}
@@ -58,7 +58,7 @@ export class RangeHighlightDecorations extends Disposable {
this.setEditor(editor);
}
private getEditor(resourceRange: IRangeHighlightDecoration): ICodeEditor {
private getEditor(resourceRange: IRangeHighlightDecoration): ICodeEditor | undefined {
const activeEditor = this.editorService.activeEditor;
const resource = activeEditor && activeEditor.getResource();
if (resource) {
@@ -67,7 +67,7 @@ export class RangeHighlightDecorations extends Disposable {
}
}
return null;
return undefined;
}
private setEditor(editor: ICodeEditor) {

View File

@@ -13,12 +13,10 @@ import { LRUCache } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import { clamp } from 'vs/base/common/numbers';
import { Themable } from 'vs/workbench/common/theme';
import { IStatusbarItem, StatusbarItemDescriptor, IStatusbarRegistry, Extensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { memoize } from 'vs/base/common/decorators';
@@ -234,7 +232,7 @@ class FileSeemsBinaryFileView {
type Scale = number | 'fit';
class ZoomStatusbarItem extends Themable implements IStatusbarItem {
export class ZoomStatusbarItem extends Themable implements IStatusbarItem {
static instance: ZoomStatusbarItem;
@@ -244,7 +242,7 @@ class ZoomStatusbarItem extends Themable implements IStatusbarItem {
private onSelectScale?: (scale: Scale) => void;
constructor(
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IEditorService editorService: IEditorService,
@IThemeService themeService: IThemeService
) {
@@ -257,7 +255,7 @@ class ZoomStatusbarItem extends Themable implements IStatusbarItem {
private onActiveEditorChanged(): void {
this.hide();
this.onSelectScale = void 0;
this.onSelectScale = undefined;
}
show(scale: Scale, onSelectScale: (scale: number) => void) {
@@ -298,12 +296,12 @@ class ZoomStatusbarItem extends Themable implements IStatusbarItem {
private get zoomActions(): Action[] {
const scales: Scale[] = [10, 5, 2, 1, 0.5, 0.2, 'fit'];
return scales.map(scale =>
new Action(`zoom.${scale}`, ZoomStatusbarItem.zoomLabel(scale), void 0, void 0, () => {
new Action(`zoom.${scale}`, ZoomStatusbarItem.zoomLabel(scale), undefined, undefined, () => {
if (this.onSelectScale) {
this.onSelectScale(scale);
}
return void 0;
return Promise.resolve(undefined);
}));
}
@@ -314,10 +312,6 @@ class ZoomStatusbarItem extends Themable implements IStatusbarItem {
}
}
Registry.as<IStatusbarRegistry>(Extensions.Statusbar).registerStatusbarItem(
new StatusbarItemDescriptor(ZoomStatusbarItem, StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */)
);
interface ImageState {
scale: Scale;
offsetX: number;
@@ -394,7 +388,7 @@ class InlineImageView {
DOM.removeClass(image, 'pixelated');
image.style.minWidth = 'auto';
image.style.width = 'auto';
InlineImageView.imageStateCache.set(cacheKey, null);
InlineImageView.imageStateCache.delete(cacheKey);
} else {
const oldWidth = image.width;
const oldHeight = image.height;
@@ -432,6 +426,10 @@ class InlineImageView {
}
function firstZoom() {
if (!image) {
return;
}
scale = image.clientWidth / image.naturalWidth;
updateScale(scale);
}
@@ -537,10 +535,13 @@ class InlineImageView {
DOM.clearNode(container);
DOM.addClasses(container, 'image', 'zoom-in');
image = DOM.append(container, DOM.$('img.scale-to-fit'));
image = DOM.append(container, DOM.$<HTMLImageElement>('img.scale-to-fit'));
image.style.visibility = 'hidden';
disposables.push(DOM.addDisposableListener(image, DOM.EventType.LOAD, e => {
if (!image) {
return;
}
if (typeof descriptor.size === 'number') {
metadataClb(nls.localize('imgMeta', '{0}x{1} {2}', image.naturalWidth, image.naturalHeight, BinarySize.formatSize(descriptor.size)));
} else {
@@ -568,7 +569,7 @@ class InlineImageView {
return context;
}
private static imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Thenable<string> {
private static imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Promise<string> {
if (descriptor.resource.scheme === Schemas.data) {
return Promise.resolve(descriptor.resource.toString(true /* skip encoding */));
}
@@ -582,7 +583,7 @@ class InlineImageView {
}
function getMime(descriptor: IResourceDescriptor) {
let mime = descriptor.mime;
let mime: string | undefined = descriptor.mime;
if (!mime && descriptor.resource.scheme !== Schemas.data) {
mime = mimes.getMediaMime(descriptor.resource.path);
}

View File

@@ -15,7 +15,7 @@ import { IEditorRegistry, Extensions as EditorExtensions } from 'vs/workbench/br
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorGroup } from 'vs/workbench/services/group/common/editorGroupsService';
import { SplitView, Sizing, Orientation } from 'vs/base/browser/ui/splitview/splitview';
import { Event, Relay, anyEvent, mapEvent, Emitter } from 'vs/base/common/event';
import { Event, Relay, Emitter } from 'vs/base/common/event';
import { IStorageService } from 'vs/platform/storage/common/storage';
export class SideBySideEditor extends BaseEditor {
@@ -43,8 +43,8 @@ export class SideBySideEditor extends BaseEditor {
get minimumHeight() { return this.minimumMasterHeight + this.minimumDetailsHeight; }
get maximumHeight() { return this.maximumMasterHeight + this.maximumDetailsHeight; }
protected masterEditor: BaseEditor;
protected detailsEditor: BaseEditor;
protected masterEditor?: BaseEditor;
protected detailsEditor?: BaseEditor;
private masterEditorContainer: HTMLElement;
private detailsEditorContainer: HTMLElement;
@@ -52,13 +52,13 @@ export class SideBySideEditor extends BaseEditor {
private splitview: SplitView;
private dimension: DOM.Dimension = new DOM.Dimension(0, 0);
private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; }>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; }>());
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; }> = anyEvent(this.onDidCreateEditors.event, this._onDidSizeConstraintsChange.event);
private onDidCreateEditors = this._register(new Emitter<{ width: number; height: number; } | undefined>());
private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>());
readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = Event.any(this.onDidCreateEditors.event, this._onDidSizeConstraintsChange.event);
constructor(
@ITelemetryService telemetryService: ITelemetryService,
@IInstantiationService private instantiationService: IInstantiationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
) {
@@ -92,7 +92,7 @@ export class SideBySideEditor extends BaseEditor {
this.updateStyles();
}
setInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
const oldInput = <SideBySideEditorInput>this.input;
return super.setInput(newInput, options, token)
.then(() => this.updateInput(oldInput, newInput, options, token));
@@ -141,7 +141,7 @@ export class SideBySideEditor extends BaseEditor {
this.splitview.layout(dimension.width);
}
getControl(): IEditorControl {
getControl(): IEditorControl | null {
if (this.masterEditor) {
return this.masterEditor.getControl();
}
@@ -149,15 +149,15 @@ export class SideBySideEditor extends BaseEditor {
return null;
}
getMasterEditor(): IEditor {
getMasterEditor(): IEditor | undefined {
return this.masterEditor;
}
getDetailsEditor(): IEditor {
getDetailsEditor(): IEditor | undefined {
return this.detailsEditor;
}
private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
private updateInput(oldInput: SideBySideEditorInput, newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
if (!newInput.matches(oldInput)) {
if (oldInput) {
this.disposeEditors();
@@ -165,22 +165,28 @@ export class SideBySideEditor extends BaseEditor {
return this.setNewInput(newInput, options, token);
}
if (!this.detailsEditor || !this.masterEditor) {
return Promise.resolve();
}
return Promise.all([
this.detailsEditor.setInput(newInput.details, null, token),
this.masterEditor.setInput(newInput.master, options, token)]
).then(() => void 0);
).then(() => undefined);
}
private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
const detailsEditor = this._createEditor(<EditorInput>newInput.details, this.detailsEditorContainer);
const masterEditor = this._createEditor(<EditorInput>newInput.master, this.masterEditorContainer);
private setNewInput(newInput: SideBySideEditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
const detailsEditor = this.doCreateEditor(<EditorInput>newInput.details, this.detailsEditorContainer);
const masterEditor = this.doCreateEditor(<EditorInput>newInput.master, this.masterEditorContainer);
return this.onEditorsCreated(detailsEditor, masterEditor, newInput.details, newInput.master, options, token);
}
private _createEditor(editorInput: EditorInput, container: HTMLElement): BaseEditor {
private doCreateEditor(editorInput: EditorInput, container: HTMLElement): BaseEditor {
const descriptor = Registry.as<IEditorRegistry>(EditorExtensions.Editors).getEditor(editorInput);
if (!descriptor) {
throw new Error('No descriptor for editor found');
}
const editor = descriptor.instantiate(this.instantiationService);
editor.create(container);
@@ -193,12 +199,12 @@ export class SideBySideEditor extends BaseEditor {
this.detailsEditor = details;
this.masterEditor = master;
this._onDidSizeConstraintsChange.input = anyEvent(
mapEvent(details.onDidSizeConstraintsChange, () => undefined),
mapEvent(master.onDidSizeConstraintsChange, () => undefined)
this._onDidSizeConstraintsChange.input = Event.any(
Event.map(details.onDidSizeConstraintsChange, () => undefined),
Event.map(master.onDidSizeConstraintsChange, () => undefined)
);
this.onDidCreateEditors.fire();
this.onDidCreateEditors.fire(undefined);
return Promise.all([this.detailsEditor.setInput(detailsInput, null, token), this.masterEditor.setInput(masterInput, options, token)]).then(() => this.focus());
}
@@ -214,12 +220,12 @@ export class SideBySideEditor extends BaseEditor {
private disposeEditors(): void {
if (this.detailsEditor) {
this.detailsEditor.dispose();
this.detailsEditor = null;
this.detailsEditor = undefined;
}
if (this.masterEditor) {
this.masterEditor.dispose();
this.masterEditor = null;
this.masterEditor = undefined;
}
this.detailsEditorContainer.innerHTML = '';

View File

@@ -10,7 +10,7 @@ import { toResource, GroupIdentifier, IEditorInput, Verbosity, EditorCommandsCon
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
import { KeyCode } from 'vs/base/common/keyCodes';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import { ResourceLabels, IResourceLabel, DEFAULT_LABELS_CONTAINER } from 'vs/workbench/browser/labels';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@@ -69,7 +69,7 @@ export class TabsTitleControl extends TitleControl {
private tabsScrollbar: ScrollableElement;
private closeOneEditorAction: CloseOneEditorAction;
private tabLabelWidgets: ResourceLabel[] = [];
private tabResourceLabels: ResourceLabels;
private tabLabels: IEditorInputLabel[] = [];
private tabDisposeables: IDisposable[] = [];
@@ -83,7 +83,7 @@ export class TabsTitleControl extends TitleControl {
group: IEditorGroupView,
@IContextMenuService contextMenuService: IContextMenuService,
@IInstantiationService instantiationService: IInstantiationService,
@IUntitledEditorService private untitledEditorService: IUntitledEditorService,
@IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService,
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService keybindingService: IKeybindingService,
@ITelemetryService telemetryService: ITelemetryService,
@@ -142,6 +142,9 @@ export class TabsTitleControl extends TitleControl {
addClass(breadcrumbsContainer, 'tabs-breadcrumbs');
this.titleContainer.appendChild(breadcrumbsContainer);
this.createBreadcrumbsControl(breadcrumbsContainer, { showFileIcons: true, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: breadcrumbsBackground });
// Tab Labels
this.tabResourceLabels = this._register(this.instantiationService.createInstance(ResourceLabels, DEFAULT_LABELS_CONTAINER));
}
private createTabsScrollbar(scrollable: HTMLElement): ScrollableElement {
@@ -314,7 +317,6 @@ export class TabsTitleControl extends TitleControl {
(this.tabsContainer.lastChild as HTMLElement).remove();
// Remove associated tab label and widget
this.tabLabelWidgets.pop();
this.tabDisposeables.pop().dispose();
}
@@ -330,7 +332,7 @@ export class TabsTitleControl extends TitleControl {
clearNode(this.tabsContainer);
this.tabDisposeables = dispose(this.tabDisposeables);
this.tabLabelWidgets = [];
this.tabResourceLabels.clear();
this.tabLabels = [];
this.clearEditorActionsToolbar();
@@ -414,12 +416,12 @@ export class TabsTitleControl extends TitleControl {
this.redraw();
}
private withTab(editor: IEditorInput, fn: (tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel) => void): void {
private withTab(editor: IEditorInput, fn: (tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void {
const editorIndex = this.group.getIndexOfEditor(editor);
const tabContainer = this.tabsContainer.children[editorIndex] as HTMLElement;
if (tabContainer) {
fn(tabContainer, this.tabLabelWidgets[editorIndex], this.tabLabels[editorIndex]);
fn(tabContainer, this.tabResourceLabels.get(editorIndex), this.tabLabels[editorIndex]);
}
}
@@ -441,8 +443,7 @@ export class TabsTitleControl extends TitleControl {
tabContainer.appendChild(tabBorderTopContainer);
// Tab Editor Label
const editorLabel = this.instantiationService.createInstance(ResourceLabel, tabContainer, void 0);
this.tabLabelWidgets.push(editorLabel);
const editorLabel = this.tabResourceLabels.create(tabContainer);
// Tab Close Button
const tabCloseContainer = document.createElement('div');
@@ -479,7 +480,7 @@ export class TabsTitleControl extends TitleControl {
e.preventDefault(); // required to prevent auto-scrolling (https://github.com/Microsoft/vscode/issues/16690)
}
return void 0; // only for left mouse click
return undefined; // only for left mouse click
}
if (this.originatesFromTabActionBar(e)) {
@@ -489,7 +490,7 @@ export class TabsTitleControl extends TitleControl {
// Open tabs editor
this.group.openEditor(this.group.getEditor(index));
return void 0;
return undefined;
};
const showContextMenu = (e: Event) => {
@@ -836,16 +837,16 @@ export class TabsTitleControl extends TitleControl {
this.layout(this.dimension);
}
private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel) => void): void {
private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel) => void): void {
this.group.editors.forEach((editor, index) => {
const tabContainer = this.tabsContainer.children[index] as HTMLElement;
if (tabContainer) {
fn(editor, index, tabContainer, this.tabLabelWidgets[index], this.tabLabels[index]);
fn(editor, index, tabContainer, this.tabResourceLabels.get(index), this.tabLabels[index]);
}
});
}
private redrawTab(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel): void {
private redrawTab(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void {
// Label
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
@@ -880,7 +881,7 @@ export class TabsTitleControl extends TitleControl {
this.setEditorTabColor(editor, tabContainer, this.group.isActive(editor));
}
private redrawLabel(editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel): void {
private redrawLabel(editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel, tabLabel: IEditorInputLabel): void {
const name = tabLabel.name;
const description = tabLabel.description || '';
const title = tabLabel.title || '';
@@ -890,14 +891,14 @@ export class TabsTitleControl extends TitleControl {
tabContainer.title = title;
// Label
tabLabelWidget.setLabel({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
tabLabelWidget.setResource({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { title, extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
// {{SQL CARBON EDIT}} -- Display the editor's tab color
const isTabActive = this.group.isActive(editor);
this.setEditorTabColor(editor, tabContainer, isTabActive);
}
private redrawEditorActiveAndDirty(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel): void {
private redrawEditorActiveAndDirty(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void {
const isTabActive = this.group.isActive(editor);
const hasModifiedBorderTop = this.doRedrawEditorDirty(isGroupActive, isTabActive, editor, tabContainer);
@@ -905,7 +906,7 @@ export class TabsTitleControl extends TitleControl {
this.doRedrawEditorActive(isGroupActive, !hasModifiedBorderTop, editor, tabContainer, tabLabelWidget);
}
private doRedrawEditorActive(isGroupActive: boolean, allowBorderTop: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel): void {
private doRedrawEditorActive(isGroupActive: boolean, allowBorderTop: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: IResourceLabel): void {
// Tab is active
if (this.group.isActive(editor)) {
@@ -924,7 +925,7 @@ export class TabsTitleControl extends TitleControl {
tabContainer.style.removeProperty('--tab-border-bottom-color');
}
const activeTabBorderColorTop = allowBorderTop ? this.getColor(isGroupActive ? TAB_ACTIVE_BORDER_TOP : TAB_UNFOCUSED_ACTIVE_BORDER_TOP) : void 0;
const activeTabBorderColorTop = allowBorderTop ? this.getColor(isGroupActive ? TAB_ACTIVE_BORDER_TOP : TAB_UNFOCUSED_ACTIVE_BORDER_TOP) : undefined;
if (activeTabBorderColorTop) {
addClass(tabContainer, 'tab-border-top');
tabContainer.style.setProperty('--tab-border-top-color', activeTabBorderColorTop.toString());
@@ -1008,7 +1009,7 @@ export class TabsTitleControl extends TitleControl {
if (!this.layoutScheduled) {
this.layoutScheduled = scheduleAtNextAnimationFrame(() => {
this.doLayout(this.dimension);
this.layoutScheduled = void 0;
this.layoutScheduled = undefined;
});
}
}
@@ -1073,7 +1074,7 @@ export class TabsTitleControl extends TitleControl {
return this.tabsContainer.children[editorIndex] as HTMLElement;
}
return void 0;
return undefined;
}
private blockRevealActiveTabOnce(): void {
@@ -1094,7 +1095,7 @@ export class TabsTitleControl extends TitleControl {
element = (e as GestureEvent).initialTarget as HTMLElement;
}
return !!findParentWithClass(element, 'monaco-action-bar', 'tab');
return !!findParentWithClass(element, 'action-item', 'tab');
}
private onDrop(e: DragEvent, targetIndex: number): void {
@@ -1185,21 +1186,21 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const activeContrastBorderColor = theme.getColor(activeContrastBorder);
if (activeContrastBorderColor) {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover {
outline: 1px solid;
outline-offset: -5px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
outline: 1px dashed;
outline-offset: -5px;
}
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active > .tab-close .action-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover > .tab-close .action-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label,
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover > .tab-close .action-label {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active > .tab-close .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.active:hover > .tab-close .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty > .tab-close .action-label,
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover > .tab-close .action-label {
opacity: 1 !important;
}
`);
@@ -1209,7 +1210,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const tabHoverBackground = theme.getColor(TAB_HOVER_BACKGROUND);
if (tabHoverBackground) {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover {
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover {
background-color: ${tabHoverBackground} !important;
}
`);
@@ -1218,7 +1219,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const tabUnfocusedHoverBackground = theme.getColor(TAB_UNFOCUSED_HOVER_BACKGROUND);
if (tabUnfocusedHoverBackground) {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
background-color: ${tabUnfocusedHoverBackground} !important;
}
`);
@@ -1228,7 +1229,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const tabHoverBorder = theme.getColor(TAB_HOVER_BORDER);
if (tabHoverBorder) {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover {
.monaco-workbench .part.editor > .content .editor-group-container.active > .title .tabs-container > .tab:hover {
box-shadow: ${tabHoverBorder} 0 -1px inset !important;
}
`);
@@ -1237,7 +1238,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const tabUnfocusedHoverBorder = theme.getColor(TAB_UNFOCUSED_HOVER_BORDER);
if (tabUnfocusedHoverBorder) {
collector.addRule(`
.monaco-workbench > .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab:hover {
box-shadow: ${tabUnfocusedHoverBorder} 0 -1px inset !important;
}
`);
@@ -1265,12 +1266,12 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const adjustedColor = tabHoverBackground.flatten(adjustedTabBackground);
const adjustedColorDrag = tabHoverBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench > .part.editor > .content:not(.dragged-over) .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
background: linear-gradient(to left, ${adjustedColor}, transparent) !important;
}
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important;
}
`);
@@ -1281,11 +1282,11 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const adjustedColor = tabUnfocusedHoverBackground.flatten(adjustedTabBackground);
const adjustedColorDrag = tabUnfocusedHoverBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench > .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
background: linear-gradient(to left, ${adjustedColor}, transparent) !important;
}
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important;
}
`);
@@ -1295,8 +1296,8 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (editorDragAndDropBackground && adjustedTabDragBackground) {
const adjustedColorDrag = editorDragAndDropBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.active):not(.dragged) > .tab-label::after,
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container:not(.active) > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.active):not(.dragged) > .tab-label::after,
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container:not(.active) > .title .tabs-container > .tab.sizing-shrink.dragged-over:not(.dragged) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important;
}
`);
@@ -1308,11 +1309,11 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const adjustedColor = tabActiveBackground.flatten(adjustedTabBackground);
const adjustedColorDrag = tabActiveBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench > .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColor}, transparent);
}
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent);
}
`);
@@ -1324,11 +1325,11 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const adjustedColor = tabInactiveBackground.flatten(adjustedTabBackground);
const adjustedColorDrag = tabInactiveBackground.flatten(adjustedTabDragBackground);
collector.addRule(`
.monaco-workbench > .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColor}, transparent);
}
.monaco-workbench > .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged) > .tab-label::after {
.monaco-workbench .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged) > .tab-label::after {
background: linear-gradient(to left, ${adjustedColorDrag}, transparent);
}
`);

View File

@@ -26,7 +26,7 @@ import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/co
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { URI } from 'vs/base/common/uri';
import { once } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -73,7 +73,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
return this.instantiationService.createInstance(DiffEditorWidget, parent, configuration);
}
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
// Dispose previous diff navigator
this.diffNavigatorDisposables = dispose(this.diffNavigatorDisposables);
@@ -87,12 +87,12 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
// Check for cancellation
if (token.isCancellationRequested) {
return void 0;
return undefined;
}
// Assert Model Instance
if (!(resolvedModel instanceof TextDiffEditorModel) && this.openAsBinary(input, options)) {
return void 0;
return undefined;
}
// Set Editor Model
@@ -282,7 +282,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditor {
super.saveTextEditorViewState(resource);
// Make sure to clean up when the input gets disposed
once(input.onDispose)(() => {
Event.once(input.onDispose)(() => {
super.clearTextEditorViewState([resource]);
});
}

View File

@@ -40,7 +40,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
private editorControl: IEditor;
private _editorContainer: HTMLElement;
private hasPendingConfigurationChange: boolean;
private lastAppliedEditorOptions: IEditorOptions;
private lastAppliedEditorOptions?: IEditorOptions;
private editorMemento: IEditorMemento<IEditorViewState>;
constructor(
@@ -53,13 +53,17 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
@ITextFileService private readonly _textFileService: ITextFileService,
@IEditorService protected editorService: IEditorService,
@IEditorGroupsService protected editorGroupService: IEditorGroupsService,
@IWindowService private windowService: IWindowService
@IWindowService private readonly windowService: IWindowService
) {
super(id, telemetryService, themeService, storageService);
this.editorMemento = this.getEditorMemento<IEditorViewState>(editorGroupService, TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
this._register(this.configurationService.onDidChangeConfiguration(e => this.handleConfigurationChangeEvent(this.configurationService.getValue<IEditorConfiguration>(this.getResource()))));
this._register(this.configurationService.onDidChangeConfiguration(e => {
const resource = this.getResource();
const value = resource ? this.configurationService.getValue<IEditorConfiguration>(resource) : undefined;
return this.handleConfigurationChangeEvent(value);
}));
}
protected get instantiationService(): IInstantiationService {
@@ -129,7 +133,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
// Editor for Text
this._editorContainer = parent;
this.editorControl = this._register(this.createEditorControl(parent, this.computeConfiguration(this.configurationService.getValue<IEditorConfiguration>(this.getResource()))));
this.editorControl = this._register(this.createEditorControl(parent, this.computeConfiguration(this.configurationService.getValue<IEditorConfiguration>(this.getResource()!))));
// Model & Language changes
const codeEditor = getCodeEditor(this.editorControl);
@@ -170,7 +174,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
(reason === SaveReason.FOCUS_CHANGE && mode === AutoSaveMode.ON_FOCUS_CHANGE)
) {
if (this.textFileService.isDirty()) {
this.textFileService.saveAll(void 0, { reason });
this.textFileService.saveAll(undefined, { reason });
}
}
}
@@ -187,7 +191,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
return this.instantiationService.createInstance(CodeEditorWidget, parent, configuration, {});
}
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
return super.setInput(input, options, token).then(() => {
// Update editor options after having set the input. We do this because there can be
@@ -229,14 +233,14 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
*/
protected saveTextEditorViewState(resource: URI): void {
const editorViewState = this.retrieveTextEditorViewState(resource);
if (!editorViewState) {
if (!editorViewState || !this.group) {
return;
}
this.editorMemento.saveEditorState(this.group, resource, editorViewState);
}
protected retrieveTextEditorViewState(resource: URI): IEditorViewState {
protected retrieveTextEditorViewState(resource: URI): IEditorViewState | null {
const control = this.getControl() as ICodeEditor;
const model = control.getModel();
if (!model) {
@@ -267,12 +271,18 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
/**
* Loads the text editor view state for the given resource and returns it.
*/
protected loadTextEditorViewState(resource: URI): IEditorViewState {
return this.editorMemento.loadEditorState(this.group, resource);
protected loadTextEditorViewState(resource: URI): IEditorViewState | undefined {
return this.group ? this.editorMemento.loadEditorState(this.group, resource) : undefined;
}
private updateEditorConfiguration(configuration = this.configurationService.getValue<IEditorConfiguration>(this.getResource())): void {
if (!this.editorControl) {
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {
if (!configuration) {
const resource = this.getResource();
if (resource) {
configuration = this.configurationService.getValue<IEditorConfiguration>(resource);
}
}
if (!this.editorControl || !configuration) {
return;
}
@@ -292,7 +302,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
}
}
protected getResource(): URI {
protected getResource(): URI | null {
const codeEditor = getCodeEditor(this.editorControl);
if (codeEditor) {
const model = codeEditor.getModel();
@@ -311,7 +321,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
protected abstract getAriaLabel(): string;
dispose(): void {
this.lastAppliedEditorOptions = void 0;
this.lastAppliedEditorOptions = undefined;
super.dispose();
}

View File

@@ -18,7 +18,7 @@ import { ITextResourceConfigurationService } from 'vs/editor/common/services/res
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { once } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { ScrollType } from 'vs/editor/common/editorCommon';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -54,7 +54,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
return nls.localize('textEditor', "Text Editor");
}
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Thenable<void> {
setInput(input: EditorInput, options: EditorOptions, token: CancellationToken): Promise<void> {
// Remember view settings if input changes
this.saveTextResourceEditorViewState(this.input);
@@ -65,7 +65,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
// Check for cancellation
if (token.isCancellationRequested) {
return void 0;
return undefined;
}
// Assert Model instance
@@ -90,7 +90,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
this.restoreTextResourceEditorViewState(input);
}
return void 0;
return undefined;
});
});
}
@@ -136,19 +136,14 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
/**
* Reveals the last line of this editor if it has a model set.
* When smart is true only scroll if the cursor is currently on the last line of the output panel.
* This allows users to click on the output panel to stop scrolling when they see something of interest.
* To resume, they should scroll to the end of the output panel again.
*/
revealLastLine(smart: boolean): void {
revealLastLine(): void {
const codeEditor = <ICodeEditor>this.getControl();
const model = codeEditor.getModel();
if (model) {
const lastLine = model.getLineCount();
if (!smart || codeEditor.getPosition().lineNumber === lastLine) {
codeEditor.revealPosition({ lineNumber: lastLine, column: model.getLineMaxColumn(lastLine) }, ScrollType.Smooth);
}
codeEditor.revealPosition({ lineNumber: lastLine, column: model.getLineMaxColumn(lastLine) }, ScrollType.Smooth);
}
}
@@ -190,7 +185,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
super.saveTextEditorViewState(resource);
// Make sure to clean up when the input gets disposed
once(input.onDispose)(() => {
Event.once(input.onDispose)(() => {
super.clearTextEditorViewState([resource]);
});
}

View File

@@ -65,17 +65,17 @@ export abstract class TitleControl extends Themable {
parent: HTMLElement,
protected accessor: IEditorGroupsAccessor,
protected group: IEditorGroupView,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IInstantiationService protected instantiationService: IInstantiationService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IKeybindingService private keybindingService: IKeybindingService,
@ITelemetryService private telemetryService: ITelemetryService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
// {{SQL CARBON EDIT}} -- need to make the notification service protected
@INotificationService protected notificationService: INotificationService,
@IMenuService private menuService: IMenuService,
@INotificationService protected readonly notificationService: INotificationService,
@IMenuService private readonly menuService: IMenuService,
@IQuickOpenService protected quickOpenService: IQuickOpenService,
@IThemeService themeService: IThemeService,
@IExtensionService private extensionService: IExtensionService,
@IExtensionService private readonly extensionService: IExtensionService,
@IConfigurationService protected configurationService: IConfigurationService,
@IFileService private readonly fileService: IFileService,
) {
@@ -320,11 +320,9 @@ export abstract class TitleControl extends Themable {
protected getKeybindingLabel(action: IAction): string {
const keybinding = this.getKeybinding(action);
return keybinding ? keybinding.getLabel() : void 0;
return keybinding ? keybinding.getLabel() : undefined;
}
//#region ITitleAreaControl
abstract openEditor(editor: IEditorInput): void;
abstract closeEditor(editor: IEditorInput): void;
@@ -348,8 +346,6 @@ export abstract class TitleControl extends Themable {
abstract updateStyles(): void;
layout(dimension: Dimension): void {
// Optionally implemented in subclasses
if (this.breadcrumbsControl) {
this.breadcrumbsControl.layout(undefined);
}
@@ -365,8 +361,6 @@ export abstract class TitleControl extends Themable {
super.dispose();
}
//#endregion
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {

View File

@@ -3,15 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .part > .content > .composite {
.monaco-workbench .part > .content > .composite {
height: 100%;
}
.monaco-workbench > .part > .composite.title {
.monaco-workbench .part > .composite.title {
display: flex;
}
.monaco-workbench > .part > .composite.title > .title-actions {
.monaco-workbench .part > .composite.title > .title-actions {
flex: 1;
padding-left: 5px;
}

View File

@@ -21,7 +21,7 @@ export class ClearNotificationAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'clear-notification-action');
}
@@ -29,7 +29,7 @@ export class ClearNotificationAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(CLEAR_NOTIFICATION, notification);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
@@ -41,7 +41,7 @@ export class ClearAllNotificationsAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'clear-all-notifications-action');
}
@@ -49,7 +49,7 @@ export class ClearAllNotificationsAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(CLEAR_ALL_NOTIFICATIONS);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
@@ -61,7 +61,7 @@ export class HideNotificationsCenterAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'hide-all-notifications-action');
}
@@ -69,7 +69,7 @@ export class HideNotificationsCenterAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(HIDE_NOTIFICATIONS_CENTER);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
@@ -81,7 +81,7 @@ export class ExpandNotificationAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'expand-notification-action');
}
@@ -89,7 +89,7 @@ export class ExpandNotificationAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(EXPAND_NOTIFICATION, notification);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
@@ -101,7 +101,7 @@ export class CollapseNotificationAction extends Action {
constructor(
id: string,
label: string,
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, 'collapse-notification-action');
}
@@ -109,7 +109,7 @@ export class CollapseNotificationAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.commandService.executeCommand(COLLAPSE_NOTIFICATION, notification);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
@@ -139,7 +139,7 @@ export class CopyNotificationMessageAction extends Action {
constructor(
id: string,
label: string,
@IClipboardService private clipboardService: IClipboardService
@IClipboardService private readonly clipboardService: IClipboardService
) {
super(id, label);
}
@@ -147,15 +147,15 @@ export class CopyNotificationMessageAction extends Action {
run(notification: INotificationViewItem): Promise<any> {
this.clipboardService.writeText(notification.message.raw);
return Promise.resolve(void 0);
return Promise.resolve();
}
}
export class NotificationActionRunner extends ActionRunner {
constructor(
@ITelemetryService private telemetryService: ITelemetryService,
@INotificationService private notificationService: INotificationService
@ITelemetryService private readonly telemetryService: ITelemetryService,
@INotificationService private readonly notificationService: INotificationService
) {
super();
}
@@ -171,8 +171,8 @@ export class NotificationActionRunner extends ActionRunner {
this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'message' });
// Run and make sure to notify on any error again
super.runAction(action, context).then(null, error => this.notificationService.error(error));
super.runAction(action, context).then(undefined, error => this.notificationService.error(error));
return Promise.resolve(void 0);
return Promise.resolve();
}
}

View File

@@ -9,7 +9,7 @@ import { INotificationViewItem, INotificationsModel, NotificationChangeType, INo
import { Disposable } from 'vs/base/common/lifecycle';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { Severity } from 'vs/platform/notification/common/notification';
import { once } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
export class NotificationsAlerts extends Disposable {
@@ -52,7 +52,7 @@ export class NotificationsAlerts extends Disposable {
}
});
once(notifiation.onDidClose)(() => listener.dispose());
Event.once(notifiation.onDidClose)(() => listener.dispose());
this.doTriggerAriaAlert(notifiation);
}

View File

@@ -42,11 +42,11 @@ export class NotificationsCenter extends Themable {
private container: HTMLElement,
private model: INotificationsModel,
@IThemeService themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private partService: IPartService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IContextKeyService contextKeyService: IContextKeyService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IKeybindingService private keybindingService: IKeybindingService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(themeService);
@@ -152,10 +152,10 @@ export class NotificationsCenter extends Themable {
this.container.appendChild(this.notificationsCenterContainer);
}
private getKeybindingLabel(action: IAction): string {
private getKeybindingLabel(action: IAction): string | null {
const keybinding = this.keybindingService.lookupKeybinding(action.id);
return keybinding ? keybinding.getLabel() : void 0;
return keybinding ? keybinding.getLabel() : null;
}
private onDidNotificationChange(e: INotificationChangeEvent): void {

View File

@@ -62,7 +62,7 @@ export interface INotificationsToastController {
export function registerNotificationCommands(center: INotificationsCenterController, toasts: INotificationsToastController): void {
function getNotificationFromContext(listService: IListService, context?: any): INotificationViewItem {
function getNotificationFromContext(listService: IListService, context?: any): INotificationViewItem | undefined {
if (isNotificationViewItem(context)) {
return context;
}
@@ -75,7 +75,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl
}
}
return void 0;
return undefined;
}
// Show Notifications Cneter

View File

@@ -26,9 +26,9 @@ export class NotificationsList extends Themable {
constructor(
private container: HTMLElement,
private options: IListOptions<INotificationViewItem>,
@IInstantiationService private instantiationService: IInstantiationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextMenuService private contextMenuService: IContextMenuService
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
super(themeService);
@@ -77,7 +77,8 @@ export class NotificationsList extends Themable {
[renderer],
{
...this.options,
setRowLineHeight: false
setRowLineHeight: false,
horizontalScrolling: false
}
));
@@ -89,7 +90,7 @@ export class NotificationsList extends Themable {
}
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getAnchor: () => e.anchor!,
getActions: () => [copyAction],
getActionsContext: () => e.element,
actionRunner
@@ -133,7 +134,7 @@ export class NotificationsList extends Themable {
const focusedIndex = this.list.getFocus()[0];
const focusedItem = this.viewModel[focusedIndex];
let focusRelativeTop: number;
let focusRelativeTop: number | null = null;
if (typeof focusedIndex === 'number') {
focusRelativeTop = this.list.getRelativeTop(focusedIndex);
}

View File

@@ -16,7 +16,7 @@ export class NotificationsStatus extends Disposable {
constructor(
private model: INotificationsModel,
@IStatusbarService private statusbarService: IStatusbarService
@IStatusbarService private readonly statusbarService: IStatusbarService
) {
super();

View File

@@ -9,7 +9,7 @@ import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { addClass, removeClass, isAncestor, addDisposableListener, EventType, Dimension } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
import { once } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
import { Themable, NOTIFICATIONS_TOAST_BORDER } from 'vs/workbench/common/theme';
import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -22,6 +22,7 @@ import { Severity } from 'vs/platform/notification/common/notification';
import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { timeout } from 'vs/base/common/async';
interface INotificationToast {
item: INotificationViewItem;
@@ -53,7 +54,6 @@ export class NotificationsToasts extends Themable {
private notificationsToastsContainer: HTMLElement;
private workbenchDimensions: Dimension;
private windowHasFocus: boolean;
private isNotificationsCenterVisible: boolean;
private mapNotificationToToast: Map<INotificationViewItem, INotificationToast>;
private notificationsToastsVisibleContextKey: IContextKey<boolean>;
@@ -61,28 +61,26 @@ export class NotificationsToasts extends Themable {
constructor(
private container: HTMLElement,
private model: INotificationsModel,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private partService: IPartService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IThemeService themeService: IThemeService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IContextKeyService contextKeyService: IContextKeyService,
@ILifecycleService private lifecycleService: ILifecycleService,
@IWindowService private windowService: IWindowService
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IWindowService private readonly windowService: IWindowService
) {
super(themeService);
this.mapNotificationToToast = new Map<INotificationViewItem, INotificationToast>();
this.notificationsToastsVisibleContextKey = NotificationsToastsVisibleContext.bindTo(contextKeyService);
this.windowService.isFocused().then(isFocused => this.windowHasFocus = isFocused);
this.registerListeners();
}
private registerListeners(): void {
// Wait for the running phase to ensure we can draw notifications properly
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
// Delay some tasks until after we can show notifications
this.onCanShowNotifications().then(() => {
// Show toast for initial notifications if any
this.model.notifications.forEach(notification => this.addToast(notification));
@@ -90,9 +88,20 @@ export class NotificationsToasts extends Themable {
// Update toasts on notification changes
this._register(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e)));
});
}
// Track window focus
this.windowService.onDidChangeFocus(hasFocus => this.windowHasFocus = hasFocus);
private onCanShowNotifications(): Promise<void> {
// Wait for the running phase to ensure we can draw notifications properly
return this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
// Push notificiations out until either workbench is restored
// or some time has ellapsed to reduce pressure on the startup
return Promise.race([
this.lifecycleService.when(LifecyclePhase.Restored),
timeout(2000)
]);
});
}
private onDidNotificationChange(e: INotificationChangeEvent): void {
@@ -185,7 +194,7 @@ export class NotificationsToasts extends Themable {
}));
// Remove when item gets closed
once(item.onDidClose)(() => {
Event.once(item.onDidClose)(() => {
this.removeToast(item);
});
@@ -226,7 +235,7 @@ export class NotificationsToasts extends Themable {
// the timeout again. This prevents an issue where focussing the window
// could immediately hide the notification because the timeout was triggered
// again.
if ((item.sticky || item.hasPrompt()) && !this.windowHasFocus) {
if ((item.sticky || item.hasPrompt()) && !this.windowService.hasFocus) {
if (!listener) {
listener = this.windowService.onDidChangeFocus(focus => {
if (focus) {
@@ -447,7 +456,7 @@ export class NotificationsToasts extends Themable {
let maxWidth = NotificationsToasts.MAX_WIDTH;
let availableWidth = maxWidth;
let availableHeight: number;
let availableHeight: number | undefined;
if (this.workbenchDimensions) {
@@ -468,7 +477,9 @@ export class NotificationsToasts extends Themable {
availableHeight -= (2 * 12); // adjust for paddings top and bottom
}
availableHeight = Math.round(availableHeight * 0.618); // try to not cover the full height for stacked toasts
availableHeight = typeof availableHeight === 'number'
? Math.round(availableHeight * 0.618) // try to not cover the full height for stacked toasts
: 0;
return new Dimension(Math.min(maxWidth, availableWidth), availableHeight);
}

View File

@@ -16,12 +16,13 @@ import { IAction, IActionRunner } from 'vs/base/common/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { DropdownMenuActionItem } from 'vs/base/browser/ui/dropdown/dropdown';
import { DropdownMenuActionItem, IContextMenuProvider } from 'vs/base/browser/ui/dropdown/dropdown';
import { INotificationViewItem, NotificationViewItem, NotificationViewItemLabelKind, INotificationMessage, ChoiceAction } from 'vs/workbench/common/notifications';
import { ClearNotificationAction, ExpandNotificationAction, CollapseNotificationAction, ConfigureNotificationAction } from 'vs/workbench/browser/parts/notifications/notificationsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { Severity } from 'vs/platform/notification/common/notification';
import { isNonEmptyArray } from 'vs/base/common/arrays';
export class NotificationsListDelegate implements IListVirtualDelegate<INotificationViewItem> {
@@ -61,7 +62,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
}
// Last row: source and buttons if we have any
if (notification.source || notification.actions.primary.length > 0) {
if (notification.source || isNonEmptyArray(notification.actions.primary)) {
expandedHeight += NotificationsListDelegate.ROW_HEIGHT;
}
@@ -81,7 +82,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
if (notification.canCollapse) {
actions++; // expand/collapse
}
if (notification.actions.secondary.length > 0) {
if (isNonEmptyArray(notification.actions.secondary)) {
actions++; // secondary actions
}
this.offsetHelper.style.width = `calc(100% - ${10 /* padding */ + 24 /* severity icon */ + (actions * 24) /* 24px per action */}px)`;
@@ -104,7 +105,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
return NotificationRenderer.TEMPLATE_ID;
}
return void 0;
throw new Error('unknown element type: ' + element);
}
}
@@ -143,8 +144,7 @@ class NotificationMessageRenderer {
// Message has links
else {
let index = 0;
for (let i = 0; i < message.links.length; i++) {
const link = message.links[i];
for (const link of message.links) {
const textBefore = message.value.substring(index, link.offset);
if (textBefore) {
@@ -182,9 +182,9 @@ export class NotificationRenderer implements IListRenderer<INotificationViewItem
constructor(
private actionRunner: IActionRunner,
@IThemeService private themeService: IThemeService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IInstantiationService private instantiationService: IInstantiationService
@IThemeService private readonly themeService: IThemeService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
}
@@ -220,8 +220,8 @@ export class NotificationRenderer implements IListRenderer<INotificationViewItem
{
ariaLabel: localize('notificationActions', "Notification Actions"),
actionItemProvider: action => {
if (action instanceof ConfigureNotificationAction) {
const item = new DropdownMenuActionItem(action, action.configurationActions, this.contextMenuService, null, this.actionRunner, null, action.class);
if (action && action instanceof ConfigureNotificationAction) {
const item = new DropdownMenuActionItem(action, action.configurationActions, this.contextMenuService as IContextMenuProvider, undefined, this.actionRunner, undefined, action.class as string);
data.toDispose.push(item);
return item;
@@ -275,10 +275,6 @@ export class NotificationRenderer implements IListRenderer<INotificationViewItem
data.renderer.setInput(notification);
}
disposeElement(): void {
// noop
}
disposeTemplate(templateData: INotificationTemplateData): void {
templateData.toDispose = dispose(templateData.toDispose);
}
@@ -290,17 +286,17 @@ export class NotificationTemplateRenderer {
private static expandNotificationAction: ExpandNotificationAction;
private static collapseNotificationAction: CollapseNotificationAction;
private static readonly SEVERITIES: ('info' | 'warning' | 'error')[] = ['info', 'warning', 'error'];
private static readonly SEVERITIES: Array<'info' | 'warning' | 'error'> = ['info', 'warning', 'error'];
private inputDisposeables: IDisposable[] = [];
constructor(
private template: INotificationTemplateData,
private actionRunner: IActionRunner,
@IOpenerService private openerService: IOpenerService,
@IInstantiationService private instantiationService: IInstantiationService,
@IThemeService private themeService: IThemeService,
@IKeybindingService private keybindingService: IKeybindingService
@IOpenerService private readonly openerService: IOpenerService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService private readonly themeService: IThemeService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
if (!NotificationTemplateRenderer.closeNotificationAction) {
NotificationTemplateRenderer.closeNotificationAction = instantiationService.createInstance(ClearNotificationAction, ClearNotificationAction.ID, ClearNotificationAction.LABEL);
@@ -374,7 +370,7 @@ export class NotificationTemplateRenderer {
const messageOverflows = notification.canCollapse && !notification.expanded && this.template.message.scrollWidth > this.template.message.clientWidth;
if (messageOverflows) {
this.template.message.title = this.template.message.textContent;
this.template.message.title = this.template.message.textContent + '';
} else {
this.template.message.removeAttribute('title');
}
@@ -391,7 +387,7 @@ export class NotificationTemplateRenderer {
const actions: IAction[] = [];
// Secondary Actions
if (notification.actions.secondary.length > 0) {
if (isNonEmptyArray(notification.actions.secondary)) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, notification.actions.secondary);
actions.push(configureNotificationAction);
this.inputDisposeables.push(configureNotificationAction);
@@ -434,10 +430,10 @@ export class NotificationTemplateRenderer {
private renderButtons(notification: INotificationViewItem): void {
clearNode(this.template.buttonsContainer);
if (notification.expanded) {
if (notification.expanded && notification.actions.primary) {
const buttonGroup = new ButtonGroup(this.template.buttonsContainer, notification.actions.primary.length, { title: true /* assign titles to buttons in case they overflow */ });
buttonGroup.buttons.forEach((button, index) => {
const action = notification.actions.primary[index];
const action = notification.actions.primary![index];
button.label = action.label;
this.inputDisposeables.push(button.onDidClick(e => {
@@ -502,10 +498,10 @@ export class NotificationTemplateRenderer {
}
}
private getKeybindingLabel(action: IAction): string {
private getKeybindingLabel(action: IAction): string | null {
const keybinding = this.keybindingService.lookupKeybinding(action.id);
return keybinding ? keybinding.getLabel() : void 0;
return keybinding ? keybinding.getLabel() : null;
}
dispose(): void {

View File

@@ -3,16 +3,16 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench.nopanel > .part.panel {
.monaco-workbench.nopanel .part.panel {
display: none !important;
visibility: hidden !important;
}
.monaco-workbench > .part.panel {
.monaco-workbench .part.panel {
z-index: initial;
}
.monaco-workbench > .part.panel .title {
.monaco-workbench .part.panel .title {
padding-right: 0px;
height: 35px;
display: flex;
@@ -20,23 +20,23 @@
justify-content: space-between;
}
.monaco-workbench > .part.panel.bottom .title {
.monaco-workbench .part.panel.bottom .title {
border-top-width: 1px;
border-top-style: solid;
}
.monaco-workbench > .part.panel.right {
.monaco-workbench .part.panel.right {
border-left-width: 1px;
border-left-style: solid;
}
.monaco-workbench > .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label {
.monaco-workbench .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label {
outline-offset: -2px;
}
/** Panel Switcher */
.monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more {
.monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more {
background-image: url('ellipsis.svg');
display: block;
height: 28px;
@@ -48,16 +48,16 @@
background-position: center center;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar {
line-height: 27px; /* matches panel titles in settings */
height: 35px;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:first-child {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:first-child {
padding-left: 12px;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item {
text-transform: uppercase;
padding-left: 10px;
padding-right: 10px;
@@ -67,24 +67,24 @@
display: flex;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label{
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label{
margin-right: 0;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:last-child {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:last-child {
padding-right: 10px;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label {
border-bottom: 1px solid;
margin-right: 0;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .badge {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .badge {
margin-left: 8px;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .badge .badge-content {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .badge .badge-content {
padding: 0.3em 0.5em;
border-radius: 1em;
font-weight: normal;
@@ -152,7 +152,7 @@
background: url('close-inverse.svg') center center no-repeat;
}
.vs-dark .monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more,
.hc-black .monaco-workbench > .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more {
.vs-dark .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more,
.hc-black .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more {
background-image: url('ellipsis-inverse.svg');
}

View File

@@ -24,12 +24,12 @@ export class ClosePanelAction extends Action {
constructor(
id: string,
name: string,
@IPartService private partService: IPartService
@IPartService private readonly partService: IPartService
) {
super(id, name, 'hide-panel-action');
}
run(): Thenable<any> {
run(): Promise<any> {
this.partService.setPanelHidden(true);
return Promise.resolve(null);
}
@@ -43,12 +43,12 @@ export class TogglePanelAction extends Action {
constructor(
id: string,
name: string,
@IPartService private partService: IPartService
@IPartService private readonly partService: IPartService
) {
super(id, name, partService.isVisible(Parts.PANEL_PART) ? 'panel expanded' : 'panel');
}
run(): Thenable<any> {
run(): Promise<any> {
this.partService.setPanelHidden(this.partService.isVisible(Parts.PANEL_PART));
return Promise.resolve(null);
}
@@ -62,13 +62,13 @@ class FocusPanelAction extends Action {
constructor(
id: string,
label: string,
@IPanelService private panelService: IPanelService,
@IPartService private partService: IPartService
@IPanelService private readonly panelService: IPanelService,
@IPartService private readonly partService: IPartService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
// Show panel
if (!this.partService.isVisible(Parts.PANEL_PART)) {
@@ -99,7 +99,7 @@ export class TogglePanelPositionAction extends Action {
constructor(
id: string,
label: string,
@IPartService private partService: IPartService,
@IPartService private readonly partService: IPartService,
) {
super(id, label, partService.getPanelPosition() === Position.RIGHT ? 'move-panel-to-bottom' : 'move-panel-to-right');
@@ -116,7 +116,7 @@ export class TogglePanelPositionAction extends Action {
setClassAndLabel();
}
run(): Thenable<any> {
run(): Promise<any> {
const position = this.partService.getPanelPosition();
this.partService.setPanelPosition(position === Position.BOTTOM ? Position.RIGHT : Position.BOTTOM);
@@ -143,7 +143,7 @@ export class ToggleMaximizedPanelAction extends Action {
constructor(
id: string,
label: string,
@IPartService private partService: IPartService
@IPartService private readonly partService: IPartService
) {
super(id, label, partService.isPanelMaximized() ? 'minimize-panel-action' : 'maximize-panel-action');
@@ -156,7 +156,7 @@ export class ToggleMaximizedPanelAction extends Action {
}));
}
run(): Thenable<any> {
run(): Promise<any> {
if (!this.partService.isVisible(Parts.PANEL_PART)) {
this.partService.setPanelHidden(false);
}
@@ -176,12 +176,12 @@ export class PanelActivityAction extends ActivityAction {
constructor(
activity: IActivity,
@IPanelService private panelService: IPanelService
@IPanelService private readonly panelService: IPanelService
) {
super(activity);
}
run(event: any): Thenable<any> {
run(event: any): Promise<any> {
this.panelService.openPanel(this.activity.id, true);
this.activate();
return Promise.resolve(null);
@@ -193,12 +193,12 @@ export class SwitchPanelViewAction extends Action {
constructor(
id: string,
name: string,
@IPanelService private panelService: IPanelService
@IPanelService private readonly panelService: IPanelService
) {
super(id, name);
}
run(offset: number): Thenable<any> {
run(offset: number): Promise<any> {
const pinnedPanels = this.panelService.getPinnedPanels();
const activePanel = this.panelService.getActivePanel();
if (!activePanel) {
@@ -229,7 +229,7 @@ export class PreviousPanelViewAction extends SwitchPanelViewAction {
super(id, name, panelService);
}
run(): Thenable<any> {
run(): Promise<any> {
return super.run(-1);
}
}
@@ -247,7 +247,7 @@ export class NextPanelViewAction extends SwitchPanelViewAction {
super(id, name, panelService);
}
public run(): Thenable<any> {
public run(): Promise<any> {
return super.run(1);
}
}

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/panelpart';
import { IAction } from 'vs/base/common/actions';
import { Event, mapEvent } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { Registry } from 'vs/platform/registry/common/platform';
import { ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar';
import { IPanel } from 'vs/workbench/common/panel';
@@ -13,7 +13,7 @@ import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/
import { Panel, PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
import { IPartService, Parts, Position } from 'vs/workbench/services/part/common/partService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -22,7 +22,7 @@ import { ClosePanelAction, TogglePanelPositionAction, PanelActivityAction, Toggl
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar } from 'vs/workbench/browser/parts/compositeBar';
import { CompositeBar, ICompositeBarItem } from 'vs/workbench/browser/parts/compositeBar';
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { IBadge } from 'vs/workbench/services/activity/common/activity';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -30,11 +30,22 @@ import { Dimension, trackFocus } from 'vs/base/browser/dom';
import { localize } from 'vs/nls';
import { IDisposable } from 'vs/base/common/lifecycle';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
import { LayoutPriority } from 'vs/base/browser/ui/grid/gridview';
export const ActivePanelContext = new RawContextKey<string>('activePanel', '');
export const PanelFocusContext = new RawContextKey<boolean>('panelFocus', false);
export class PanelPart extends CompositePart<Panel> implements IPanelService {
interface ICachedPanel {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
export class PanelPart extends CompositePart<Panel> implements IPanelService, ISerializableView {
static readonly activePanelSettingsKey = 'workbench.panelpart.activepanelid';
@@ -50,6 +61,17 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
private compositeActions: { [compositeId: string]: { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction } } = Object.create(null);
private dimension: Dimension;
element: HTMLElement;
minimumWidth: number = 300;
maximumWidth: number = Number.POSITIVE_INFINITY;
minimumHeight: number = 77;
maximumHeight: number = Number.POSITIVE_INFINITY;
snapSize: number = 50;
priority: LayoutPriority = LayoutPriority.Low;
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
constructor(
id: string,
@INotificationService notificationService: INotificationService,
@@ -61,6 +83,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@ILifecycleService private readonly lifecycleService: ILifecycleService
) {
super(
notificationService,
@@ -81,9 +104,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
{ hasTitle: true }
);
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, {
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.getCachedPanels(), {
icon: false,
storageId: PanelPart.PINNED_PANELS,
orientation: ActionsOrientation.HORIZONTAL,
openComposite: (compositeId: string) => Promise.resolve(this.openPanel(compositeId, true)),
getActivityAction: (compositeId: string) => this.getCompositeActions(compositeId).activityAction,
@@ -120,6 +142,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
create(parent: HTMLElement): void {
this.element = parent;
super.create(parent);
const focusTracker = trackFocus(parent);
@@ -137,6 +161,10 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
this._register(this.onDidPanelClose(this._onDidPanelClose, this));
this._register(this.registry.onDidRegister(panelDescriptor => this.compositeBar.addComposite(panelDescriptor)));
this._register(this.registry.onDidDeregister(panelDescriptor => {
this.compositeBar.hideComposite(panelDescriptor.id);
this.removeComposite(panelDescriptor.id);
}));
// Activate panel action on opening of a panel
this._register(this.onDidPanelOpen(({ panel }) => {
@@ -146,6 +174,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
// Deactivate panel action on close
this._register(this.onDidPanelClose(panel => this.compositeBar.deactivateComposite(panel.getId())));
this.lifecycleService.when(LifecyclePhase.Eventually).then(() => {
this._register(this.compositeBar.onDidChange(() => this.saveCachedPanels()));
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
});
}
private _onDidPanelOpen(panel: IPanel): void {
@@ -161,7 +194,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean }> {
return mapEvent(this._onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus }));
return Event.map(this._onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus }));
}
get onDidPanelClose(): Event<IPanel> {
@@ -207,7 +240,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
getPanels(): PanelDescriptor[] {
return Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels()
.filter(p => p.enabled)
.sort((v1, v2) => v1.order - v2.order);
}
@@ -218,18 +250,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
.sort((p1, p2) => pinnedCompositeIds.indexOf(p1.id) - pinnedCompositeIds.indexOf(p2.id));
}
setPanelEnablement(id: string, enabled: boolean): void {
const descriptor = Registry.as<PanelRegistry>(PanelExtensions.Panels).getPanels().filter(p => p.id === id).pop();
if (descriptor && descriptor.enabled !== enabled) {
descriptor.enabled = enabled;
if (enabled) {
this.compositeBar.addComposite(descriptor);
} else {
this.removeComposite(id);
}
}
}
protected getActions(): IAction[] {
return [
this.instantiationService.createInstance(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL),
@@ -266,21 +286,32 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
};
}
layout(dimension: Dimension): Dimension[] {
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
if (!this.partService.isVisible(Parts.PANEL_PART)) {
return [dimension];
if (dim1 instanceof Dimension) {
return [dim1];
}
return;
}
const { width, height } = dim1 instanceof Dimension ? dim1 : { width: dim1, height: dim2 };
if (this.partService.getPanelPosition() === Position.RIGHT) {
// Take into account the 1px border when layouting
this.dimension = new Dimension(dimension.width - 1, dimension.height);
this.dimension = new Dimension(width - 1, height);
} else {
this.dimension = dimension;
this.dimension = new Dimension(width, height);
}
const sizes = super.layout(this.dimension);
const sizes = super.layout(this.dimension.width, this.dimension.height);
this.layoutCompositeBar();
return sizes;
if (dim1 instanceof Dimension) {
return sizes;
}
}
private layoutCompositeBar(): void {
@@ -306,14 +337,17 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
return compositeActions;
}
private removeComposite(compositeId: string): void {
this.compositeBar.hideComposite(compositeId);
const compositeActions = this.compositeActions[compositeId];
if (compositeActions) {
compositeActions.activityAction.dispose();
compositeActions.pinnedAction.dispose();
delete this.compositeActions[compositeId];
protected removeComposite(compositeId: string): boolean {
if (super.removeComposite(compositeId)) {
const compositeActions = this.compositeActions[compositeId];
if (compositeActions) {
compositeActions.activityAction.dispose();
compositeActions.pinnedAction.dispose();
delete this.compositeActions[compositeId];
}
return true;
}
return false;
}
private getToolbarWidth(): number {
@@ -323,6 +357,89 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
return this.toolBar.getItemsWidth();
}
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
if (e.key === PanelPart.PINNED_PANELS && e.scope === StorageScope.GLOBAL
&& this.cachedPanelsValue !== this.getStoredCachedPanelsValue() /* This checks if current window changed the value or not */) {
this._cachedPanelsValue = null;
const newCompositeItems: ICompositeBarItem[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
const cachedPanels = this.getCachedPanels();
for (const cachedPanel of cachedPanels) {
// Add and update existing items
const existingItem = compositeItems.filter(({ id }) => id === cachedPanel.id)[0];
if (existingItem) {
newCompositeItems.push({
id: existingItem.id,
name: existingItem.name,
order: existingItem.order,
pinned: cachedPanel.pinned,
visible: existingItem.visible
});
}
}
for (let index = 0; index < compositeItems.length; index++) {
// Add items currently exists but does not exist in new.
if (!newCompositeItems.some(({ id }) => id === compositeItems[index].id)) {
newCompositeItems.splice(index, 0, compositeItems[index]);
}
}
this.compositeBar.setCompositeBarItems(newCompositeItems);
}
}
private saveCachedPanels(): void {
const state: ICachedPanel[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
for (const compositeItem of compositeItems) {
state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible });
}
this.cachedPanelsValue = JSON.stringify(state);
}
private getCachedPanels(): ICachedPanel[] {
const storedStates = <Array<string | ICachedPanel>>JSON.parse(this.cachedPanelsValue);
const registeredPanels = this.getPanels();
const cachedPanels = <ICachedPanel[]>storedStates.map(c => {
const serialized: ICachedPanel = typeof c === 'string' /* migration from pinned states to composites states */ ? <ICachedPanel>{ id: c, pinned: true, order: undefined, visible: true } : c;
const registered = registeredPanels.some(p => p.id === serialized.id);
serialized.visible = registered ? isUndefinedOrNull(serialized.visible) ? true : serialized.visible : false;
return serialized;
});
return cachedPanels;
}
private _cachedPanelsValue: string;
private get cachedPanelsValue(): string {
if (!this._cachedPanelsValue) {
this._cachedPanelsValue = this.getStoredCachedPanelsValue();
}
return this._cachedPanelsValue;
}
private set cachedPanelsValue(cachedViewletsValue: string) {
if (this.cachedPanelsValue !== cachedViewletsValue) {
this._cachedPanelsValue = cachedViewletsValue;
this.setStoredCachedViewletsValue(cachedViewletsValue);
}
}
private getStoredCachedPanelsValue(): string {
return this.storageService.get(PanelPart.PINNED_PANELS, StorageScope.GLOBAL, '[]');
}
private setStoredCachedViewletsValue(value: string): void {
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL);
}
toJSON(): object {
return {
type: Parts.PANEL_PART
};
}
}
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
@@ -333,9 +450,9 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const panelBackground = theme.getColor(PANEL_BACKGROUND);
if (panelBackground && panelBackground !== theme.getColor(editorBackground)) {
collector.addRule(`
.monaco-workbench > .part.panel > .content .monaco-editor,
.monaco-workbench > .part.panel > .content .monaco-editor .margin,
.monaco-workbench > .part.panel > .content .monaco-editor .monaco-editor-background {
.monaco-workbench .part.panel > .content .monaco-editor,
.monaco-workbench .part.panel > .content .monaco-editor .margin,
.monaco-workbench .part.panel > .content .monaco-editor .monaco-editor-background {
background-color: ${panelBackground};
}
`);
@@ -346,7 +463,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const titleActiveBorder = theme.getColor(PANEL_ACTIVE_TITLE_BORDER);
if (titleActive || titleActiveBorder) {
collector.addRule(`
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:hover .action-label {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:hover .action-label {
color: ${titleActive} !important;
border-bottom-color: ${titleActiveBorder} !important;
}
@@ -357,14 +474,14 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const focusBorderColor = theme.getColor(focusBorder);
if (focusBorderColor) {
collector.addRule(`
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus .action-label {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus .action-label {
color: ${titleActive} !important;
border-bottom-color: ${focusBorderColor} !important;
border-bottom: 1px solid;
}
`);
collector.addRule(`
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:focus {
outline: none;
}
`);
@@ -376,8 +493,8 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const outline = theme.getColor(activeContrastBorder);
collector.addRule(`
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label,
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item.checked .action-label,
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item .action-label:hover {
outline-color: ${outline};
outline-width: 1px;
outline-style: solid;
@@ -386,7 +503,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
outline-offset: 1px;
}
.monaco-workbench > .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:not(.checked) .action-label:hover {
.monaco-workbench .part.panel > .title > .panel-switcher-container > .monaco-action-bar .action-item:not(.checked) .action-label:hover {
outline-style: dashed;
}
`);

View File

@@ -25,7 +25,7 @@ import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { attachBadgeStyler, attachProgressBarStyler, attachButtonStyler } from 'vs/platform/theme/common/styler';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { debounceEvent, Emitter, Event } from 'vs/base/common/event';
import { Emitter, Event } from 'vs/base/common/event';
import { Button } from 'vs/base/browser/ui/button/button';
import { dispose, IDisposable } from 'vs/base/common/lifecycle';
import Severity from 'vs/base/common/severity';
@@ -252,14 +252,20 @@ class QuickInput implements IQuickInput {
this.ui.leftActionBar.clear();
const leftButtons = this.buttons.filter(button => button === backButton);
this.ui.leftActionBar.push(leftButtons.map((button, index) => {
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => this.onDidTriggerButtonEmitter.fire(button));
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
this.onDidTriggerButtonEmitter.fire(button);
return Promise.resolve(null);
});
action.tooltip = button.tooltip;
return action;
}), { icon: true, label: false });
this.ui.rightActionBar.clear();
const rightButtons = this.buttons.filter(button => button !== backButton);
this.ui.rightActionBar.push(rightButtons.map((button, index) => {
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => this.onDidTriggerButtonEmitter.fire(button));
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
this.onDidTriggerButtonEmitter.fire(button);
return Promise.resolve(null);
});
action.tooltip = button.tooltip;
return action;
}), { icon: true, label: false });
@@ -306,7 +312,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
private _placeholder;
private onDidChangeValueEmitter = new Emitter<string>();
private onDidAcceptEmitter = new Emitter<string>();
private _items: (T | IQuickPickSeparator)[] = [];
private _items: Array<T | IQuickPickSeparator> = [];
private itemsUpdated = false;
private _canSelectMany = false;
private _matchOnDescription = false;
@@ -360,7 +366,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
return this._items;
}
set items(items: (T | IQuickPickSeparator)[]) {
set items(items: Array<T | IQuickPickSeparator>) {
this._items = items;
this.itemsUpdated = true;
this.update();
@@ -482,7 +488,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this._selectedItems = [this.activeItems[0]];
this.onDidChangeSelectionEmitter.fire(this.selectedItems);
}
this.onDidAcceptEmitter.fire();
this.onDidAcceptEmitter.fire(undefined);
}),
this.ui.list.onDidChangeFocus(focusedItems => {
if (this.activeItemsUpdated) {
@@ -507,7 +513,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
this._selectedItems = selectedItems as T[];
this.onDidChangeSelectionEmitter.fire(selectedItems as T[]);
if (selectedItems.length) {
this.onDidAcceptEmitter.fire();
this.onDidAcceptEmitter.fire(undefined);
}
}),
this.ui.list.onChangedCheckedElements(checkedItems => {
@@ -570,7 +576,7 @@ class QuickPick<T extends IQuickPickItem> extends QuickInput implements IQuickPi
if (wasTriggerKeyPressed && this.activeItems[0]) {
this._selectedItems = [this.activeItems[0]];
this.onDidChangeSelectionEmitter.fire(this.selectedItems);
this.onDidAcceptEmitter.fire();
this.onDidAcceptEmitter.fire(undefined);
}
});
}
@@ -723,7 +729,7 @@ class InputBox extends QuickInput implements IInputBox {
this._value = value;
this.onDidValueChangeEmitter.fire(value);
}),
this.ui.onDidAccept(() => this.onDidAcceptEmitter.fire()),
this.ui.onDidAccept(() => this.onDidAcceptEmitter.fire(undefined)),
);
this.valueSelectionUpdated = true;
}
@@ -788,14 +794,14 @@ export class QuickInputService extends Component implements IQuickInputService {
private controller: QuickInput;
constructor(
@IEnvironmentService private environmentService: IEnvironmentService,
@IConfigurationService private configurationService: IConfigurationService,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private partService: IPartService,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IKeybindingService private keybindingService: IKeybindingService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
) {
@@ -1129,7 +1135,7 @@ export class QuickInputService extends Component implements IQuickInputService {
}
});
input.show();
Promise.resolve(picks).then(null, err => {
Promise.resolve(picks).then(undefined, err => {
reject(err);
input.hide();
});
@@ -1143,8 +1149,8 @@ export class QuickInputService extends Component implements IQuickInputService {
return;
}
const input = this.createInputBox();
const validateInput = options.validateInput || (() => <Thenable<undefined>>Promise.resolve(undefined));
const onDidValueChange = debounceEvent(input.onDidChangeValue, (last, cur) => cur, 100);
const validateInput = options.validateInput || (() => <Promise<undefined>>Promise.resolve(undefined));
const onDidValueChange = Event.debounce(input.onDidChangeValue, (last, cur) => cur, 100);
let validationValue = options.value || '';
let validation = Promise.resolve(validateInput(validationValue));
const disposables = [
@@ -1406,7 +1412,7 @@ export class BackAction extends Action {
public static readonly ID = 'workbench.action.quickInputBack';
public static readonly LABEL = localize('back', "Back");
constructor(id: string, label: string, @IQuickInputService private quickInputService: IQuickInputService) {
constructor(id: string, label: string, @IQuickInputService private readonly quickInputService: IQuickInputService) {
super(id, label);
}

View File

@@ -24,7 +24,7 @@ export class QuickInputBox {
private parent: HTMLElement
) {
this.container = dom.append(this.parent, $('.quick-input-box'));
this.inputBox = new InputBox(this.container, null);
this.inputBox = new InputBox(this.container, undefined);
this.disposables.push(this.inputBox);
}
@@ -55,7 +55,7 @@ export class QuickInputBox {
}
get placeholder() {
return this.inputBox.inputElement.getAttribute('placeholder');
return this.inputBox.inputElement.getAttribute('placeholder') || '';
}
set placeholder(placeholder: string) {

View File

@@ -13,7 +13,7 @@ import { IQuickPickItem, IQuickPickItemButtonEvent, IQuickPickSeparator } from '
import { IMatch } from 'vs/base/common/filters';
import { matchesFuzzyOcticonAware, parseOcticons } from 'vs/base/common/octicon';
import { compareAnything } from 'vs/base/common/comparers';
import { Emitter, Event, mapEvent } from 'vs/base/common/event';
import { Emitter, Event } from 'vs/base/common/event';
import { assign } from 'vs/base/common/objects';
import { KeyCode } from 'vs/base/common/keyCodes';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -32,14 +32,14 @@ import { IListOptions } from 'vs/base/browser/ui/list/listWidget';
const $ = dom.$;
interface IListElement {
index: number;
item: IQuickPickItem;
saneLabel: string;
saneDescription?: string;
saneDetail?: string;
checked: boolean;
separator: IQuickPickSeparator;
fireButtonTriggered: (event: IQuickPickItemButtonEvent<IQuickPickItem>) => void;
readonly index: number;
readonly item: IQuickPickItem;
readonly saneLabel: string;
readonly saneDescription?: string;
readonly saneDetail?: string;
readonly checked: boolean;
readonly separator?: IQuickPickSeparator;
readonly fireButtonTriggered: (event: IQuickPickItemButtonEvent<IQuickPickItem>) => void;
}
class ListElement implements IListElement {
@@ -53,7 +53,7 @@ class ListElement implements IListElement {
onChecked = this._onChecked.event;
_checked?: boolean;
get checked() {
return this._checked;
return !!this._checked;
}
set checked(value: boolean) {
if (value !== this._checked) {
@@ -61,7 +61,7 @@ class ListElement implements IListElement {
this._onChecked.fire(value);
}
}
separator: IQuickPickSeparator;
separator?: IQuickPickSeparator;
labelHighlights?: IMatch[];
descriptionHighlights?: IMatch[];
detailHighlights?: IMatch[];
@@ -144,7 +144,7 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
options.descriptionTitle = element.saneDescription;
options.descriptionMatches = descriptionHighlights || [];
options.extraClasses = element.item.iconClasses;
data.label.setValue(element.saneLabel, element.saneDescription, options);
data.label.setLabel(element.saneLabel, element.saneDescription, options);
// Meta
data.detail.set(element.saneDetail, detailHighlights);
@@ -173,14 +173,14 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
const buttons = element.item.buttons;
if (buttons && buttons.length) {
data.actionBar.push(buttons.map((button, index) => {
const action = new Action(`id-${index}`, '', button.iconClass || getIconClass(button.iconPath), true, () => {
const action = new Action(`id-${index}`, '', button.iconClass || (button.iconPath ? getIconClass(button.iconPath) : undefined), true, () => {
element.fireButtonTriggered({
button,
item: element.item
});
return null;
return Promise.resolve();
});
action.tooltip = button.tooltip;
action.tooltip = button.tooltip || '';
return action;
}), { icon: true, label: false });
dom.addClass(data.entry, 'has-actions');
@@ -215,7 +215,7 @@ export class QuickInputList {
readonly id: string;
private container: HTMLElement;
private list: WorkbenchList<ListElement>;
private inputElements: (IQuickPickItem | IQuickPickSeparator)[];
private inputElements: Array<IQuickPickItem | IQuickPickSeparator>;
private elements: ListElement[] = [];
private elementsToIndexes = new Map<IQuickPickItem, number>();
matchOnDescription = false;
@@ -239,7 +239,7 @@ export class QuickInputList {
constructor(
private parent: HTMLElement,
id: string,
@IInstantiationService private instantiationService: IInstantiationService
@IInstantiationService private readonly instantiationService: IInstantiationService
) {
this.id = id;
this.container = dom.append(this.parent, $('.quick-input-list'));
@@ -248,7 +248,8 @@ export class QuickInputList {
identityProvider: { getId: element => element.saneLabel },
openController: { shouldOpen: () => false }, // Workaround #58124
setRowLineHeight: false,
multipleSelectionSupport: false
multipleSelectionSupport: false,
horizontalScrolling: false
} as IListOptions<ListElement>) as WorkbenchList<ListElement>;
this.list.getHTMLElement().id = id;
this.disposables.push(this.list);
@@ -294,12 +295,12 @@ export class QuickInputList {
@memoize
get onDidChangeFocus() {
return mapEvent(this.list.onFocusChange, e => e.elements.map(e => e.item));
return Event.map(this.list.onFocusChange, e => e.elements.map(e => e.item));
}
@memoize
get onDidChangeSelection() {
return mapEvent(this.list.onSelectionChange, e => e.elements.map(e => e.item));
return Event.map(this.list.onSelectionChange, e => e.elements.map(e => e.item));
}
getAllVisibleChecked() {
@@ -356,7 +357,7 @@ export class QuickInputList {
}
}
setElements(inputElements: (IQuickPickItem | IQuickPickSeparator)[]): void {
setElements(inputElements: Array<IQuickPickItem | IQuickPickSeparator>): void {
this.elementDisposables = dispose(this.elementDisposables);
const fireButtonTriggered = (event: IQuickPickItemButtonEvent<IQuickPickItem>) => this.fireButtonTriggered(event);
this.inputElements = inputElements;
@@ -395,7 +396,7 @@ export class QuickInputList {
setFocusedElements(items: IQuickPickItem[]) {
this.list.setFocus(items
.filter(item => this.elementsToIndexes.has(item))
.map(item => this.elementsToIndexes.get(item)));
.map(item => this.elementsToIndexes.get(item)!));
}
getActiveDescendant() {
@@ -410,7 +411,7 @@ export class QuickInputList {
setSelectedElements(items: IQuickPickItem[]) {
this.list.setSelection(items
.filter(item => this.elementsToIndexes.has(item))
.map(item => this.elementsToIndexes.get(item)));
.map(item => this.elementsToIndexes.get(item)!));
}
getCheckedElements() {
@@ -484,9 +485,9 @@ export class QuickInputList {
// Filter by value (since we support octicons, use octicon aware fuzzy matching)
else {
this.elements.forEach(element => {
const labelHighlights = matchesFuzzyOcticonAware(query, parseOcticons(element.saneLabel));
const descriptionHighlights = this.matchOnDescription ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDescription || '')) : undefined;
const detailHighlights = this.matchOnDetail ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDetail || '')) : undefined;
const labelHighlights = matchesFuzzyOcticonAware(query, parseOcticons(element.saneLabel)) || undefined;
const descriptionHighlights = this.matchOnDescription ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDescription || '')) || undefined : undefined;
const detailHighlights = this.matchOnDetail ? matchesFuzzyOcticonAware(query, parseOcticons(element.saneDetail || '')) || undefined : undefined;
if (labelHighlights || descriptionHighlights || detailHighlights) {
element.labelHighlights = labelHighlights;

View File

@@ -53,7 +53,7 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
const HELP_PREFIX = '?';
type ValueCallback<T = any> = (value: T | Thenable<T>) => void;
type ValueCallback<T = any> = (value: T | Promise<T>) => void;
export class QuickOpenController extends Component implements IQuickOpenService {
@@ -86,13 +86,13 @@ export class QuickOpenController extends Component implements IQuickOpenService
private pendingGetResultsInvocation: CancellationTokenSource;
constructor(
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@INotificationService private notificationService: INotificationService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IConfigurationService private configurationService: IConfigurationService,
@IInstantiationService private instantiationService: IInstantiationService,
@IPartService private partService: IPartService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@INotificationService private readonly notificationService: INotificationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IPartService private readonly partService: IPartService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IThemeService themeService: IThemeService,
@IStorageService storageService: IStorageService
) {
@@ -155,9 +155,9 @@ export class QuickOpenController extends Component implements IQuickOpenService
}
show(prefix?: string, options?: IShowOptions): Promise<void> {
let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : void 0;
let inputSelection = options ? options.inputSelection : void 0;
let autoFocus = options ? options.autoFocus : void 0;
let quickNavigateConfiguration = options ? options.quickNavigateConfiguration : undefined;
let inputSelection = options ? options.inputSelection : undefined;
let autoFocus = options ? options.autoFocus : undefined;
const promiseCompletedOnHide = new Promise<void>(c => {
this.promisesToCompleteOnHide.push(c);
@@ -452,11 +452,11 @@ export class QuickOpenController extends Component implements IQuickOpenService
const previousInput = this.quickOpenWidget.getInput();
const wasShowingHistory = previousInput && previousInput.entries && previousInput.entries.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup);
if (wasShowingHistory || matchingHistoryEntries.length > 0) {
let responseDelay: Thenable<void>;
let responseDelay: Promise<void>;
if (resolvedHandler.hasShortResponseTime()) {
responseDelay = timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME);
} else {
responseDelay = Promise.resolve(void 0);
responseDelay = Promise.resolve();
}
responseDelay.then(() => {
@@ -490,8 +490,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
// Remove results already showing by checking for a "resource" property
const mapEntryToResource = this.mapEntriesToResource(quickOpenModel);
const additionalHandlerResults: QuickOpenEntry[] = [];
for (let i = 0; i < handlerResults.length; i++) {
const result = handlerResults[i];
for (const result of handlerResults) {
const resource = result.getResource();
if (!result.mergeWithEditorHistory() || !resource || !mapEntryToResource[resource.toString()]) {
@@ -529,7 +528,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider);
this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), resolvedHandler.getAriaLabel());
return Promise.resolve(null);
return Promise.resolve(undefined);
}
// Support extra class from handler
@@ -646,9 +645,9 @@ class EditorHistoryHandler {
private scorerCache: ScorerCache;
constructor(
@IHistoryService private historyService: IHistoryService,
@IInstantiationService private instantiationService: IInstantiationService,
@IFileService private fileService: IFileService
@IHistoryService private readonly historyService: IHistoryService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IFileService private readonly fileService: IFileService
) {
this.scorerCache = Object.create(null);
}
@@ -709,7 +708,7 @@ class EditorHistoryItemAccessorClass extends QuickOpenItemAccessorClass {
}
getItemDescription(entry: QuickOpenEntry): string {
return this.allowMatchOnDescription ? entry.getDescription() : void 0;
return this.allowMatchOnDescription ? entry.getDescription() : undefined;
}
}
@@ -730,10 +729,10 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry {
constructor(
input: IEditorInput | IResourceInput,
@IEditorService editorService: IEditorService,
@IModeService private modeService: IModeService,
@IModelService private modelService: IModelService,
@ITextFileService private textFileService: ITextFileService,
@IConfigurationService private configurationService: IConfigurationService,
@IModeService private readonly modeService: IModeService,
@IModelService private readonly modelService: IModelService,
@ITextFileService private readonly textFileService: ITextFileService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService labelService: ILabelService,
@IFileService fileService: IFileService
) {
@@ -808,7 +807,7 @@ export class EditorHistoryEntry extends EditorQuickOpenEntry {
}
function resourceForEditorHistory(input: EditorInput, fileService: IFileService): URI {
const resource = input ? input.getResource() : void 0;
const resource = input ? input.getResource() : undefined;
// For the editor history we only prefer resources that are either untitled or
// can be handled by the file service which indicates they are editable resources.
@@ -816,7 +815,7 @@ function resourceForEditorHistory(input: EditorInput, fileService: IFileService)
return resource;
}
return void 0;
return undefined;
}
export class RemoveFromEditorHistoryAction extends Action {
@@ -827,16 +826,16 @@ export class RemoveFromEditorHistoryAction extends Action {
constructor(
id: string,
label: string,
@IQuickInputService private quickInputService: IQuickInputService,
@IModelService private modelService: IModelService,
@IModeService private modeService: IModeService,
@IInstantiationService private instantiationService: IInstantiationService,
@IHistoryService private historyService: IHistoryService
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IHistoryService private readonly historyService: IHistoryService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
interface IHistoryPickEntry extends IQuickPickItem {
input: IEditorInput | IResourceInput;
}

View File

@@ -23,7 +23,7 @@ CommandsRegistry.registerCommand(QUICKOPEN_ACTION_ID, function (accessor: Servic
const quickOpenService = accessor.get(IQuickOpenService);
return quickOpenService.show(typeof prefix === 'string' ? prefix : undefined).then(() => {
return void 0;
return undefined;
});
});
@@ -32,7 +32,7 @@ CommandsRegistry.registerCommand(QUICKOPEN_FOCUS_SECONDARY_ACTION_ID, function (
const quickOpenService = accessor.get(IQuickOpenService);
return quickOpenService.show(undefined, { autoFocus: { autoFocusSecondEntry: true } }).then(() => {
return void 0;
return undefined;
});
});
@@ -43,16 +43,16 @@ export class BaseQuickOpenNavigateAction extends Action {
label: string,
private next: boolean,
private quickNavigate: boolean,
@IQuickOpenService private quickOpenService: IQuickOpenService,
@IQuickInputService private quickInputService: IQuickInputService,
@IKeybindingService private keybindingService: IKeybindingService
@IQuickOpenService private readonly quickOpenService: IQuickOpenService,
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IKeybindingService private readonly keybindingService: IKeybindingService
) {
super(id, label);
}
run(event?: any): Thenable<any> {
run(event?: any): Promise<any> {
const keys = this.keybindingService.lookupKeybindings(this.id);
const quickNavigate = this.quickNavigate ? { keybindings: keys } : void 0;
const quickNavigate = this.quickNavigate ? { keybindings: keys } : undefined;
this.quickOpenService.navigate(this.next, quickNavigate);
this.quickInputService.navigate(this.next, quickNavigate);

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .sidebar > .content {
.monaco-workbench .sidebar > .content {
overflow: hidden;
}
@@ -12,7 +12,7 @@
visibility: hidden !important;
}
.monaco-workbench > .sidebar > .title > .title-label h2 {
.monaco-workbench .sidebar > .title > .title-label h2 {
text-transform: uppercase;
}

View File

@@ -8,7 +8,7 @@ import * as nls from 'vs/nls';
import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { CompositePart } from 'vs/workbench/browser/parts/compositePart';
import { Viewlet, ViewletRegistry, Extensions as ViewletExtensions } from 'vs/workbench/browser/viewlet';
import { Viewlet, ViewletRegistry, Extensions as ViewletExtensions, ViewletDescriptor } from 'vs/workbench/browser/viewlet';
import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -20,25 +20,43 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Event, mapEvent } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { SIDE_BAR_TITLE_FOREGROUND, SIDE_BAR_BACKGROUND, SIDE_BAR_FOREGROUND, SIDE_BAR_BORDER } from 'vs/workbench/common/theme';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { Dimension, EventType, addDisposableListener, trackFocus } from 'vs/base/browser/dom';
import { EventType, addDisposableListener, trackFocus, Dimension } from 'vs/base/browser/dom';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
import { LayoutPriority } from 'vs/base/browser/ui/grid/gridview';
const SideBarFocusContextId = 'sideBarFocus';
export const SidebarFocusContext = new RawContextKey<boolean>(SideBarFocusContextId, false);
export const SidebarFocusContext = new RawContextKey<boolean>('sideBarFocus', false);
export const ActiveViewletContext = new RawContextKey<string>('activeViewlet', '');
export class SidebarPart extends CompositePart<Viewlet> {
export class SidebarPart extends CompositePart<Viewlet> implements ISerializableView, IViewletService {
_serviceBrand: any;
static readonly activeViewletSettingsKey = 'workbench.sidebar.activeviewletid';
private viewletRegistry: ViewletRegistry;
private sideBarFocusContextKey: IContextKey<boolean>;
private activeViewletContextKey: IContextKey<string>;
private blockOpeningViewlet: boolean;
private _onDidViewletDeregister = this._register(new Emitter<ViewletDescriptor>());
element: HTMLElement;
minimumWidth: number = 170;
maximumWidth: number = Number.POSITIVE_INFINITY;
minimumHeight: number = 0;
maximumHeight: number = Number.POSITIVE_INFINITY;
snapSize: number = 50;
priority: LayoutPriority = LayoutPriority.Low;
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
constructor(
id: string,
@@ -51,6 +69,7 @@ export class SidebarPart extends CompositePart<Viewlet> {
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IContextKeyService contextKeyService: IContextKeyService,
@IExtensionService private readonly extensionService: IExtensionService
) {
super(
notificationService,
@@ -72,10 +91,32 @@ export class SidebarPart extends CompositePart<Viewlet> {
);
this.sideBarFocusContextKey = SidebarFocusContext.bindTo(contextKeyService);
this.viewletRegistry = Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets);
this.activeViewletContextKey = ActiveViewletContext.bindTo(contextKeyService);
this._register(this.onDidViewletOpen(viewlet => {
this.activeViewletContextKey.set(viewlet.getId());
}));
this._register(this.onDidViewletClose(viewlet => {
if (this.activeViewletContextKey.get() === viewlet.getId()) {
this.activeViewletContextKey.reset();
}
}));
this._register(this.registry.onDidDeregister(async (viewletDescriptor: ViewletDescriptor) => {
if (this.getActiveViewlet().getId() === viewletDescriptor.id) {
await this.openViewlet(this.getDefaultViewletId());
}
this.removeComposite(viewletDescriptor.id);
this._onDidViewletDeregister.fire(viewletDescriptor);
}));
}
get onDidViewletRegister(): Event<ViewletDescriptor> { return <Event<ViewletDescriptor>>this.viewletRegistry.onDidRegister; }
get onDidViewletDeregister(): Event<ViewletDescriptor> { return this._onDidViewletDeregister.event; }
get onDidViewletOpen(): Event<IViewlet> {
return mapEvent(this._onDidCompositeOpen.event, compositeEvent => <IViewlet>compositeEvent.composite);
return Event.map(this._onDidCompositeOpen.event, compositeEvent => <IViewlet>compositeEvent.composite);
}
get onDidViewletClose(): Event<IViewlet> {
@@ -83,6 +124,8 @@ export class SidebarPart extends CompositePart<Viewlet> {
}
create(parent: HTMLElement): void {
this.element = parent;
super.create(parent);
const focusTracker = trackFocus(parent);
@@ -124,7 +167,65 @@ export class SidebarPart extends CompositePart<Viewlet> {
container.style.borderLeftColor = !isPositionLeft ? borderColor : null;
}
openViewlet(id: string, focus?: boolean): Viewlet {
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
if (dim1 instanceof Dimension) {
return [dim1];
}
return;
}
if (dim1 instanceof Dimension) {
return super.layout(dim1);
}
super.layout(dim1, dim2!);
}
// Viewlet service
getActiveViewlet(): IViewlet {
return <IViewlet>this.getActiveComposite();
}
getLastActiveViewletId(): string {
return this.getLastActiveCompositetId();
}
hideActiveViewlet(): void {
this.hideActiveComposite();
}
openViewlet(id: string, focus?: boolean): Promise<IViewlet | null> {
if (this.getViewlet(id)) {
return Promise.resolve(this.doOpenViewlet(id, focus));
}
return this.extensionService.whenInstalledExtensionsRegistered()
.then(() => {
if (this.getViewlet(id)) {
return this.doOpenViewlet(id, focus);
}
return null;
});
}
getViewlets(): ViewletDescriptor[] {
return this.viewletRegistry.getViewlets()
.sort((v1, v2) => v1.order! - v2.order!);
}
getDefaultViewletId(): string {
return this.viewletRegistry.getDefaultViewletId();
}
getViewlet(id: string): ViewletDescriptor {
return this.getViewlets().filter(viewlet => viewlet.id === id)[0];
}
private doOpenViewlet(id: string, focus?: boolean): Viewlet | null {
if (this.blockOpeningViewlet) {
return null; // Workaround against a potential race condition
}
@@ -142,26 +243,6 @@ export class SidebarPart extends CompositePart<Viewlet> {
return this.openComposite(id, focus) as Viewlet;
}
getActiveViewlet(): IViewlet {
return <IViewlet>this.getActiveComposite();
}
getLastActiveViewletId(): string {
return this.getLastActiveCompositetId();
}
hideActiveViewlet(): void {
this.hideActiveComposite();
}
layout(dimension: Dimension): Dimension[] {
if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {
return [dimension];
}
return super.layout(dimension);
}
protected getTitleAreaDropDownAnchorAlignment(): AnchorAlignment {
return this.partService.getSideBarPosition() === SideBarPosition.LEFT ? AnchorAlignment.LEFT : AnchorAlignment.RIGHT;
}
@@ -181,6 +262,12 @@ export class SidebarPart extends CompositePart<Viewlet> {
}
}
}
toJSON(): object {
return {
type: Parts.SIDEBAR_PART
};
}
}
class FocusSideBarAction extends Action {
@@ -191,13 +278,13 @@ class FocusSideBarAction extends Action {
constructor(
id: string,
label: string,
@IViewletService private viewletService: IViewletService,
@IPartService private partService: IPartService
@IViewletService private readonly viewletService: IViewletService,
@IPartService private readonly partService: IPartService
) {
super(id, label);
}
run(): Thenable<any> {
run(): Promise<any> {
// Show side bar
if (!this.partService.isVisible(Parts.SIDEBAR_PART)) {

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .part.statusbar {
.monaco-workbench .part.statusbar {
box-sizing: border-box;
cursor: default;
width: 100%;
@@ -11,18 +11,18 @@
font-size: 12px;
}
.monaco-workbench > .part.statusbar > .statusbar-item {
.monaco-workbench .part.statusbar > .statusbar-item {
display: inline-block;
line-height: 22px;
height: 100%;
vertical-align: top;
}
.monaco-workbench > .part.statusbar > .statusbar-item.has-beak {
.monaco-workbench .part.statusbar > .statusbar-item.has-beak {
position: relative;
}
.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before {
.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before {
content: '';
position: absolute;
left: 11px;
@@ -33,48 +33,48 @@
border-right: 5px solid transparent;
}
.monaco-workbench > .part.statusbar > .statusbar-item.left > :first-child {
.monaco-workbench .part.statusbar > .statusbar-item.left > :first-child {
margin-right: 5px;
}
.monaco-workbench > .part.statusbar > .statusbar-item.right {
.monaco-workbench .part.statusbar > .statusbar-item.right {
float: right;
}
.monaco-workbench > .part.statusbar > .statusbar-item.right > :first-child {
.monaco-workbench .part.statusbar > .statusbar-item.right > :first-child {
margin-left: 5px;
}
/* adding padding to the most left status bar item */
.monaco-workbench > .part.statusbar > .statusbar-item.left:first-child, .monaco-workbench > .part.statusbar > .statusbar-item.right + .statusbar-item.left {
.monaco-workbench .part.statusbar > .statusbar-item.left:first-child, .monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left {
padding-left: 10px;
}
/* adding padding to the most right status bar item */
.monaco-workbench > .part.statusbar > .statusbar-item.right:first-child {
.monaco-workbench .part.statusbar > .statusbar-item.right:first-child {
padding-right: 10px;
}
.monaco-workbench > .part.statusbar > .statusbar-item a {
.monaco-workbench .part.statusbar > .statusbar-item a {
cursor: pointer;
display: inline-block;
height: 100%;
}
.monaco-workbench > .part.statusbar > .statusbar-entry > span {
.monaco-workbench .part.statusbar > .statusbar-entry > span {
height: 100%;
}
.monaco-workbench > .part.statusbar > .statusbar-entry > span,
.monaco-workbench > .part.statusbar > .statusbar-entry > a {
.monaco-workbench .part.statusbar > .statusbar-entry > span,
.monaco-workbench .part.statusbar > .statusbar-entry > a {
padding: 0 5px 0 5px;
white-space: pre; /* gives some degree of styling */
}
.monaco-workbench > .part.statusbar > .statusbar-entry span.octicon {
.monaco-workbench .part.statusbar > .statusbar-entry span.octicon {
text-align: center;
font-size: 14px;
}
.monaco-workbench > .part.statusbar > .statusbar-item a:hover {
.monaco-workbench .part.statusbar > .statusbar-item a:hover {
text-decoration: none;
}

View File

@@ -24,27 +24,39 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { isThemeColor } from 'vs/editor/common/editorCommon';
import { Color } from 'vs/base/common/color';
import { addClass, EventHelper, createStyleSheet, addDisposableListener } from 'vs/base/browser/dom';
import { addClass, EventHelper, createStyleSheet, addDisposableListener, Dimension } from 'vs/base/browser/dom';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Emitter } from 'vs/base/common/event';
import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
import { Parts } from 'vs/workbench/services/part/common/partService';
export class StatusbarPart extends Part implements IStatusbarService {
export class StatusbarPart extends Part implements IStatusbarService, ISerializableView {
_serviceBrand: any;
private static readonly PRIORITY_PROP = 'statusbar-entry-priority';
private static readonly ALIGNMENT_PROP = 'statusbar-entry-alignment';
private statusItemsContainer: HTMLElement;
element: HTMLElement;
private statusMsgDispose: IDisposable;
minimumWidth: number = 0;
maximumWidth: number = Number.POSITIVE_INFINITY;
minimumHeight: number = 22;
maximumHeight: number = 22;
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
private styleElement: HTMLStyleElement;
constructor(
id: string,
@IInstantiationService private instantiationService: IInstantiationService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IStorageService storageService: IStorageService
) {
super(id, { hasTitle: false }, themeService, storageService);
@@ -59,16 +71,15 @@ export class StatusbarPart extends Part implements IStatusbarService {
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
// Render entry in status bar
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : void 0);
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : undefined);
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
const toDispose = item.render(el);
// Insert according to priority
const container = this.statusItemsContainer;
const container = this.element;
const neighbours = this.getEntries(alignment);
let inserted = false;
for (let i = 0; i < neighbours.length; i++) {
const neighbour = neighbours[i];
for (const neighbour of neighbours) {
const nPriority = Number(neighbour.getAttribute(StatusbarPart.PRIORITY_PROP));
if (
alignment === StatusbarAlignment.LEFT && nPriority < priority ||
@@ -96,7 +107,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
private getEntries(alignment: StatusbarAlignment): HTMLElement[] {
const entries: HTMLElement[] = [];
const container = this.statusItemsContainer;
const container = this.element;
const children = container.children;
for (let i = 0; i < children.length; i++) {
const childElement = <HTMLElement>children.item(i);
@@ -109,7 +120,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
}
createContentArea(parent: HTMLElement): HTMLElement {
this.statusItemsContainer = parent;
this.element = parent;
// Fill in initial items that were contributed from the registry
const registry = Registry.as<IStatusbarRegistry>(Extensions.Statusbar);
@@ -135,10 +146,10 @@ export class StatusbarPart extends Part implements IStatusbarService {
const el = this.doCreateStatusItem(descriptor.alignment, descriptor.priority);
this._register(item.render(el));
this.statusItemsContainer.appendChild(el);
this.element.appendChild(el);
}
return this.statusItemsContainer;
return this.element;
}
protected updateStyles(): void {
@@ -162,7 +173,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.styleElement = createStyleSheet(container);
}
this.styleElement.innerHTML = `.monaco-workbench > .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
}
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, extraClass?: string): HTMLElement {
@@ -191,7 +202,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
// Create new
let statusDispose: IDisposable;
let showHandle = setTimeout(() => {
let showHandle: any = setTimeout(() => {
statusDispose = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
showHandle = null;
}, delayBy);
@@ -221,6 +232,22 @@ export class StatusbarPart extends Part implements IStatusbarService {
return dispose;
}
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
if (dim1 instanceof Dimension) {
return super.layout(dim1);
} else {
super.layout(new Dimension(dim1, dim2!));
}
}
toJSON(): object {
return {
type: Parts.STATUSBAR_PART
};
}
}
let manageExtensionAction: ManageExtensionAction;
@@ -228,13 +255,13 @@ class StatusBarEntryItem implements IStatusbarItem {
constructor(
private entry: IStatusbarEntry,
@ICommandService private commandService: ICommandService,
@IInstantiationService private instantiationService: IInstantiationService,
@INotificationService private notificationService: INotificationService,
@ITelemetryService private telemetryService: ITelemetryService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IEditorService private editorService: IEditorService,
@IThemeService private themeService: IThemeService
@ICommandService private readonly commandService: ICommandService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@INotificationService private readonly notificationService: INotificationService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IEditorService private readonly editorService: IEditorService,
@IThemeService private readonly themeService: IThemeService
) {
this.entry = entry;
@@ -252,7 +279,7 @@ class StatusBarEntryItem implements IStatusbarItem {
if (this.entry.command) {
textContainer = document.createElement('a');
toDispose.push(addDisposableListener(textContainer, 'click', () => this.executeCommand(this.entry.command, this.entry.arguments)));
toDispose.push(addDisposableListener(textContainer, 'click', () => this.executeCommand(this.entry.command!, this.entry.arguments)));
} else {
textContainer = document.createElement('span');
}
@@ -286,7 +313,7 @@ class StatusBarEntryItem implements IStatusbarItem {
this.contextMenuService.showContextMenu({
getAnchor: () => el,
getActionsContext: () => this.entry.extensionId,
getActionsContext: () => this.entry.extensionId!.value,
getActions: () => [manageExtensionAction]
});
}));
@@ -324,12 +351,12 @@ class StatusBarEntryItem implements IStatusbarItem {
class ManageExtensionAction extends Action {
constructor(
@ICommandService private commandService: ICommandService
@ICommandService private readonly commandService: ICommandService
) {
super('statusbar.manage.extension', nls.localize('manageExtension', "Manage Extension"));
}
run(extensionId: string): Thenable<any> {
run(extensionId: string): Promise<any> {
return this.commandService.executeCommand('_extensions.manage', extensionId);
}
}
@@ -337,21 +364,21 @@ class ManageExtensionAction extends Action {
registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND);
if (statusBarItemHoverBackground) {
collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item a:hover { background-color: ${statusBarItemHoverBackground}; }`);
collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a:hover { background-color: ${statusBarItemHoverBackground}; }`);
}
const statusBarItemActiveBackground = theme.getColor(STATUS_BAR_ITEM_ACTIVE_BACKGROUND);
if (statusBarItemActiveBackground) {
collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item a:active { background-color: ${statusBarItemActiveBackground}; }`);
collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a:active { background-color: ${statusBarItemActiveBackground}; }`);
}
const statusBarProminentItemBackground = theme.getColor(STATUS_BAR_PROMINENT_ITEM_BACKGROUND);
if (statusBarProminentItemBackground) {
collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item .status-bar-info { background-color: ${statusBarProminentItemBackground}; }`);
collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item .status-bar-info { background-color: ${statusBarProminentItemBackground}; }`);
}
const statusBarProminentItemHoverBackground = theme.getColor(STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND);
if (statusBarProminentItemHoverBackground) {
collector.addRule(`.monaco-workbench > .part.statusbar > .statusbar-item a.status-bar-info:hover { background-color: ${statusBarProminentItemHoverBackground}; }`);
collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a.status-bar-info:hover { background-color: ${statusBarProminentItemHoverBackground}; }`);
}
});

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench > .part.titlebar {
.monaco-workbench .part.titlebar {
box-sizing: border-box;
width: 100%;
padding: 0 70px;
@@ -18,7 +18,7 @@
display: flex;
}
.monaco-workbench > .part.titlebar > .titlebar-drag-region {
.monaco-workbench .part.titlebar > .titlebar-drag-region {
top: 0;
left: 0;
display: block;
@@ -29,7 +29,7 @@
-webkit-app-region: drag;
}
.monaco-workbench > .part.titlebar > .window-title {
.monaco-workbench .part.titlebar > .window-title {
flex: 0 1 auto;
font-size: 12px;
overflow: hidden;
@@ -42,8 +42,8 @@
/* Windows/Linux: Rules for custom title (icon, window controls) */
.monaco-workbench.windows > .part.titlebar,
.monaco-workbench.linux > .part.titlebar {
.windows > .monaco-workbench .part.titlebar,
.linux > .monaco-workbench .part.titlebar {
padding: 0;
height: 30px;
line-height: 30px;
@@ -51,17 +51,17 @@
overflow: visible;
}
.monaco-workbench.windows > .part.titlebar > .window-title,
.monaco-workbench.linux > .part.titlebar > .window-title {
.windows > .monaco-workbench .part.titlebar > .window-title,
.linux > .monaco-workbench .part.titlebar > .window-title {
cursor: default;
}
.monaco-workbench.linux > .part.titlebar > .window-title {
.linux > .monaco-workbench .part.titlebar > .window-title {
font-size: inherit;
}
.monaco-workbench.windows > .part.titlebar > .resizer,
.monaco-workbench.linux > .part.titlebar > .resizer {
.windows > .monaco-workbench .part.titlebar > .resizer,
.linux > .monaco-workbench .part.titlebar > .resizer {
-webkit-app-region: no-drag;
position: absolute;
top: 0;
@@ -69,13 +69,13 @@
height: 20%;
}
.monaco-workbench.windows.fullscreen > .part.titlebar > .resizer,
.monaco-workbench.linux.fullscreen > .part.titlebar > .resizer {
.windows > .monaco-workbench.fullscreen .part.titlebar > .resizer,
.linux > .monaco-workbench.fullscreen .part.titlebar > .resizer {
display: none;
}
.monaco-workbench > .part.titlebar > .window-appicon {
.monaco-workbench .part.titlebar > .window-appicon {
width: 35px;
height: 100%;
position: relative;
@@ -87,11 +87,11 @@
flex-shrink: 0;
}
.monaco-workbench.fullscreen > .part.titlebar > .window-appicon {
.monaco-workbench.fullscreen .part.titlebar > .window-appicon {
display: none;
}
.monaco-workbench > .part.titlebar > .window-controls-container {
.monaco-workbench .part.titlebar > .window-controls-container {
display: flex;
flex-grow: 0;
flex-shrink: 0;
@@ -104,56 +104,56 @@
margin-left: auto;
}
.monaco-workbench.fullscreen > .part.titlebar > .window-controls-container {
.monaco-workbench.fullscreen .part.titlebar > .window-controls-container {
display: none;
}
.monaco-workbench > .part.titlebar > .window-controls-container > .window-icon-bg {
.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg {
display: inline-block;
-webkit-app-region: no-drag;
height: 100%;
width: 33.34%;
}
.monaco-workbench > .part.titlebar > .window-controls-container .window-icon svg {
.monaco-workbench .part.titlebar > .window-controls-container .window-icon svg {
shape-rendering: crispEdges;
text-align: center;
}
.monaco-workbench > .part.titlebar.titlebar > .window-controls-container .window-close {
.monaco-workbench .part.titlebar.titlebar > .window-controls-container .window-close {
-webkit-mask: url('chrome-close.svg') no-repeat 50% 50%;
}
.monaco-workbench > .part.titlebar.titlebar > .window-controls-container .window-unmaximize {
.monaco-workbench .part.titlebar.titlebar > .window-controls-container .window-unmaximize {
-webkit-mask: url('chrome-restore.svg') no-repeat 50% 50%;
}
.monaco-workbench > .part.titlebar > .window-controls-container .window-maximize {
.monaco-workbench .part.titlebar > .window-controls-container .window-maximize {
-webkit-mask: url('chrome-maximize.svg') no-repeat 50% 50%;
}
.monaco-workbench > .part.titlebar > .window-controls-container .window-minimize {
.monaco-workbench .part.titlebar > .window-controls-container .window-minimize {
-webkit-mask: url('chrome-minimize.svg') no-repeat 50% 50%;
}
.monaco-workbench > .part.titlebar > .window-controls-container > .window-icon-bg > .window-icon {
.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg > .window-icon {
height: 100%;
width: 100%;
-webkit-mask-size: 23.1%;
}
.monaco-workbench > .part.titlebar > .window-controls-container > .window-icon-bg:hover {
.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg:hover {
background-color: rgba(255, 255, 255, 0.1);
}
.monaco-workbench > .part.titlebar.light > .window-controls-container > .window-icon-bg:hover {
.monaco-workbench .part.titlebar.light > .window-controls-container > .window-icon-bg:hover {
background-color: rgba(0, 0, 0, 0.1);
}
.monaco-workbench > .part.titlebar > .window-controls-container > .window-icon-bg.window-close-bg:hover {
.monaco-workbench .part.titlebar > .window-controls-container > .window-icon-bg.window-close-bg:hover {
background-color: rgba(232, 17, 35, 0.9);
}
.monaco-workbench > .part.titlebar > .window-controls-container .window-icon.window-close:hover {
.monaco-workbench .part.titlebar > .window-controls-container .window-icon.window-close:hover {
background-color: white;
}
}

View File

@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IMenubarMenu, IMenubarMenuItemAction, IMenubarMenuItemSubmenu, IMenubarKeybinding, IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar';
import { IMenubarMenu, IMenubarMenuItemAction, IMenubarMenuItemSubmenu, IMenubarKeybinding, IMenubarService, IMenubarData, MenubarMenuItem } from 'vs/platform/menubar/common/menubar';
import { IMenuService, MenuId, IMenu, SubmenuItemAction } from 'vs/platform/actions/common/actions';
import { registerThemingParticipant, ITheme, ICssStyleCollector, IThemeService } from 'vs/platform/theme/common/themeService';
import { IWindowService, MenuBarVisibility, IWindowsService, getTitleBarStyle } from 'vs/platform/windows/common/windows';
@@ -31,6 +31,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { MenuBar } from 'vs/base/browser/ui/menu/menubar';
import { SubmenuAction } from 'vs/base/browser/ui/menu/menu';
import { attachMenuStyler } from 'vs/platform/theme/common/styler';
import { assign } from 'vs/base/common/objects';
export class MenubarControl extends Disposable {
@@ -45,27 +46,29 @@ export class MenubarControl extends Disposable {
'window.nativeTabs'
];
// {{SQL CARBON EDIT}} - Disable unusued menus
private topLevelMenus: {
'File': IMenu;
'Edit': IMenu;
'Selection': IMenu;
// 'Selection': IMenu;
'View': IMenu;
'Go': IMenu;
'Debug': IMenu;
'Terminal': IMenu;
// 'Go': IMenu;
// 'Debug': IMenu;
// 'Terminal': IMenu;
'Window'?: IMenu;
'Help': IMenu;
[index: string]: IMenu;
// [index: string]: IMenu;
};
// {{SQL CARBON EDIT}} - Disable unused menus
private topLevelTitles = {
'File': nls.localize({ key: 'mFile', comment: ['&& denotes a mnemonic'] }, "&&File"),
'Edit': nls.localize({ key: 'mEdit', comment: ['&& denotes a mnemonic'] }, "&&Edit"),
'Selection': nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection"),
// 'Selection': nls.localize({ key: 'mSelection', comment: ['&& denotes a mnemonic'] }, "&&Selection"),
'View': nls.localize({ key: 'mView', comment: ['&& denotes a mnemonic'] }, "&&View"),
'Go': nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go"),
'Debug': nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug"),
'Terminal': nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"),
// 'Go': nls.localize({ key: 'mGoto', comment: ['&& denotes a mnemonic'] }, "&&Go"),
// 'Debug': nls.localize({ key: 'mDebug', comment: ['&& denotes a mnemonic'] }, "&&Debug"),
// 'Terminal': nls.localize({ key: 'mTerminal', comment: ['&& denotes a mnemonic'] }, "&&Terminal"),
'Help': nls.localize({ key: 'mHelp', comment: ['&& denotes a mnemonic'] }, "&&Help")
};
@@ -80,32 +83,33 @@ export class MenubarControl extends Disposable {
private static MAX_MENU_RECENT_ENTRIES = 10;
constructor(
@IThemeService private themeService: IThemeService,
@IMenubarService private menubarService: IMenubarService,
@IMenuService private menuService: IMenuService,
@IWindowService private windowService: IWindowService,
@IWindowsService private windowsService: IWindowsService,
@IContextKeyService private contextKeyService: IContextKeyService,
@IKeybindingService private keybindingService: IKeybindingService,
@IConfigurationService private configurationService: IConfigurationService,
@ILabelService private labelService: ILabelService,
@IUpdateService private updateService: IUpdateService,
@IStorageService private storageService: IStorageService,
@INotificationService private notificationService: INotificationService,
@IPreferencesService private preferencesService: IPreferencesService,
@IEnvironmentService private environmentService: IEnvironmentService
@IThemeService private readonly themeService: IThemeService,
@IMenubarService private readonly menubarService: IMenubarService,
@IMenuService private readonly menuService: IMenuService,
@IWindowService private readonly windowService: IWindowService,
@IWindowsService private readonly windowsService: IWindowsService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService private readonly labelService: ILabelService,
@IUpdateService private readonly updateService: IUpdateService,
@IStorageService private readonly storageService: IStorageService,
@INotificationService private readonly notificationService: INotificationService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
) {
super();
// {{SQL CARBON EDIT}} - Disable unused menus
this.topLevelMenus = {
'File': this._register(this.menuService.createMenu(MenuId.MenubarFileMenu, this.contextKeyService)),
'Edit': this._register(this.menuService.createMenu(MenuId.MenubarEditMenu, this.contextKeyService)),
'Selection': this._register(this.menuService.createMenu(MenuId.MenubarSelectionMenu, this.contextKeyService)),
// 'Selection': this._register(this.menuService.createMenu(MenuId.MenubarSelectionMenu, this.contextKeyService)),
'View': this._register(this.menuService.createMenu(MenuId.MenubarViewMenu, this.contextKeyService)),
'Go': this._register(this.menuService.createMenu(MenuId.MenubarGoMenu, this.contextKeyService)),
'Debug': this._register(this.menuService.createMenu(MenuId.MenubarDebugMenu, this.contextKeyService)),
'Terminal': this._register(this.menuService.createMenu(MenuId.MenubarTerminalMenu, this.contextKeyService)),
// 'Go': this._register(this.menuService.createMenu(MenuId.MenubarGoMenu, this.contextKeyService)),
// 'Debug': this._register(this.menuService.createMenu(MenuId.MenubarDebugMenu, this.contextKeyService)),
// 'Terminal': this._register(this.menuService.createMenu(MenuId.MenubarTerminalMenu, this.contextKeyService)),
'Help': this._register(this.menuService.createMenu(MenuId.MenubarHelpMenu, this.contextKeyService))
};
@@ -263,6 +267,9 @@ export class MenubarControl extends Disposable {
this.menubar.blur();
}));
}
// Update recent menu items on formatter registration
this._register(this.labelService.onDidChangeFormatters(() => { this.onRecentlyOpenedChange(); }));
}
private doUpdateMenubar(firstTime: boolean): void {
@@ -315,7 +322,7 @@ export class MenubarControl extends Disposable {
return label;
}
private createOpenRecentMenuAction(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI, commandId: string, isFile: boolean): IAction {
private createOpenRecentMenuAction(workspace: IWorkspaceIdentifier | ISingleFolderWorkspaceIdentifier | URI, commandId: string, isFile: boolean): IAction & { uri: URI } {
let label: string;
let uri: URI;
@@ -331,7 +338,7 @@ export class MenubarControl extends Disposable {
label = this.labelService.getUriLabel(uri);
}
return new Action(commandId, label, undefined, undefined, (event) => {
const ret: IAction = new Action(commandId, label, undefined, undefined, (event) => {
const openInNewWindow = event && ((!isMacintosh && (event.ctrlKey || event.shiftKey)) || (isMacintosh && (event.metaKey || event.altKey)));
return this.windowService.openWindow([uri], {
@@ -339,8 +346,11 @@ export class MenubarControl extends Disposable {
forceOpenWorkspaceAsFile: isFile
});
});
return assign(ret, { uri: uri });
}
/* Custom Menu takes actions */
private getOpenRecentActions(): IAction[] {
if (!this.recentlyOpened) {
return [];
@@ -369,6 +379,19 @@ export class MenubarControl extends Disposable {
return result;
}
private transformOpenRecentAction(action: Separator | (IAction & { uri: URI })): MenubarMenuItem {
if (action instanceof Separator) {
return { id: 'vscode.menubar.separator' };
}
return {
id: action.id,
uri: action.uri,
enabled: action.enabled,
label: action.label
};
}
private getUpdateAction(): IAction | null {
const state = this.updateService.state;
@@ -501,13 +524,13 @@ export class MenubarControl extends Disposable {
// first try to resolve a native accelerator
const electronAccelerator = binding.getElectronAccelerator();
if (electronAccelerator) {
return { label: electronAccelerator };
return { label: electronAccelerator, userSettingsLabel: binding.getUserSettingsLabel() };
}
// we need this fallback to support keybindings that cannot show in electron menus (e.g. chords)
const acceleratorLabel = binding.getLabel();
if (acceleratorLabel) {
return { label: acceleratorLabel, isNative: false };
return { label: acceleratorLabel, isNative: false, userSettingsLabel: binding.getUserSettingsLabel() };
}
return null;
@@ -534,6 +557,11 @@ export class MenubarControl extends Disposable {
menuToPopulate.items.push(menubarSubmenuItem);
menuToDispose.dispose();
} else {
if (menuItem.id === 'workbench.action.openRecent') {
const actions = this.getOpenRecentActions().map(this.transformOpenRecentAction);
menuToPopulate.items.push(...actions);
}
let menubarMenuItem: IMenubarMenuItemAction = {
id: menuItem.id,
label: menuItem.label

View File

@@ -5,6 +5,7 @@
import 'vs/css!./media/titlebarpart';
import * as paths from 'vs/base/common/paths';
import * as resources from 'vs/base/common/resources';
import { Part } from 'vs/workbench/browser/part';
import { ITitleService, ITitleProperties } from 'vs/workbench/services/title/common/titleService';
import { getZoomFactor } from 'vs/base/browser/browser';
@@ -25,15 +26,17 @@ import { isMacintosh, isWindows, isLinux } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
import { Color } from 'vs/base/common/color';
import { trim } from 'vs/base/common/strings';
import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener } from 'vs/base/browser/dom';
import { EventType, EventHelper, Dimension, isAncestor, hide, show, removeClass, addClass, append, $, addDisposableListener, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { MenubarControl } from 'vs/workbench/browser/parts/titlebar/menubarControl';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { template, getBaseLabel } from 'vs/base/common/labels';
import { ILabelService } from 'vs/platform/label/common/label';
import { Event } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
import { Parts } from 'vs/workbench/services/part/common/partService';
export class TitlebarPart extends Part implements ITitleService {
export class TitlebarPart extends Part implements ITitleService, ISerializableView {
_serviceBrand: any;
@@ -43,7 +46,7 @@ export class TitlebarPart extends Part implements ITitleService {
private static readonly TITLE_DIRTY = '\u25cf ';
private static readonly TITLE_SEPARATOR = isMacintosh ? ' — ' : ' - '; // macOS uses special - separator
private titleContainer: HTMLElement;
element: HTMLElement;
private title: HTMLElement;
private dragRegion: HTMLElement;
private windowControls: HTMLElement;
@@ -61,18 +64,26 @@ export class TitlebarPart extends Part implements ITitleService {
private properties: ITitleProperties;
private activeEditorListeners: IDisposable[];
minimumWidth: number = 0;
maximumWidth: number = Number.POSITIVE_INFINITY;
get minimumHeight(): number { return isMacintosh ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue<MenuBarVisibility>('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); }
get maximumHeight(): number { return isMacintosh ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue<MenuBarVisibility>('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); }
private _onDidChange = new Emitter<{ width: number; height: number; }>();
readonly onDidChange = this._onDidChange.event;
constructor(
id: string,
@IContextMenuService private contextMenuService: IContextMenuService,
@IWindowService private windowService: IWindowService,
@IConfigurationService private configurationService: IConfigurationService,
@IWindowsService private windowsService: IWindowsService,
@IEditorService private editorService: IEditorService,
@IEnvironmentService private environmentService: IEnvironmentService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IInstantiationService private instantiationService: IInstantiationService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IWindowService private readonly windowService: IWindowService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWindowsService private readonly windowsService: IWindowsService,
@IEditorService private readonly editorService: IEditorService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@ILabelService private labelService: ILabelService,
@ILabelService private readonly labelService: ILabelService,
@IStorageService storageService: IStorageService
) {
super(id, { hasTitle: false }, themeService, storageService);
@@ -90,7 +101,7 @@ export class TitlebarPart extends Part implements ITitleService {
this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.doUpdateTitle()));
this._register(this.contextService.onDidChangeWorkbenchState(() => this.doUpdateTitle()));
this._register(this.contextService.onDidChangeWorkspaceName(() => this.doUpdateTitle()));
this._register(this.labelService.onDidRegisterFormatter(() => this.doUpdateTitle()));
this._register(this.labelService.onDidChangeFormatters(() => this.doUpdateTitle()));
}
private onBlur(): void {
@@ -107,6 +118,12 @@ export class TitlebarPart extends Part implements ITitleService {
if (event.affectsConfiguration('window.title')) {
this.doUpdateTitle();
}
if (event.affectsConfiguration('window.doubleClickIconToClose')) {
if (this.appIcon) {
this.onUpdateAppIconDragBehavior();
}
}
}
private onMenubarVisibilityChanged(visible: boolean) {
@@ -184,7 +201,7 @@ export class TitlebarPart extends Part implements ITitleService {
this.pendingTitle = title;
}
if (isWindows || isLinux) {
if ((isWindows || isLinux) && this.title) {
this.adjustTitleMarginToCenter();
}
}
@@ -222,21 +239,25 @@ export class TitlebarPart extends Part implements ITitleService {
/**
* Possible template values:
*
* {activeEditorLong}: e.g. /Users/Development/myProject/myFolder/myFile.txt
* {activeEditorMedium}: e.g. myFolder/myFile.txt
* {activeEditorLong}: e.g. /Users/Development/myFolder/myFileFolder/myFile.txt
* {activeEditorMedium}: e.g. myFolder/myFileFolder/myFile.txt
* {activeEditorShort}: e.g. myFile.txt
* {activeFolderLong}: e.g. /Users/Development/myFolder/myFileFolder
* {activeFolderMedium}: e.g. myFolder/myFileFolder
* {activeFolderShort}: e.g. myFileFolder
* {rootName}: e.g. myFolder1, myFolder2, myFolder3
* {rootPath}: e.g. /Users/Development/myProject
* {rootPath}: e.g. /Users/Development
* {folderName}: e.g. myFolder
* {folderPath}: e.g. /Users/Development/myFolder
* {appName}: e.g. VS Code
* {dirty}: indiactor
* {dirty}: indicator
* {separator}: conditional separator
*/
private doGetWindowTitle(): string {
const editor = this.editorService.activeEditor;
const workspace = this.contextService.getWorkspace();
// Compute root
let root: URI;
if (workspace.configuration) {
root = workspace.configuration;
@@ -244,15 +265,25 @@ export class TitlebarPart extends Part implements ITitleService {
root = workspace.folders[0].uri;
}
// Compute active editor folder
const editorResource = editor ? toResource(editor) : undefined;
let editorFolderResource = editorResource ? resources.dirname(editorResource) : undefined;
if (editorFolderResource && editorFolderResource.path === '.') {
editorFolderResource = undefined;
}
// Compute folder resource
// Single Root Workspace: always the root single workspace in this case
// Otherwise: root folder of the currently active file if any
let folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: true }));
const folder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER ? workspace.folders[0] : this.contextService.getWorkspaceFolder(toResource(editor, { supportSideBySide: true }));
// Variables
const activeEditorShort = editor ? editor.getTitle(Verbosity.SHORT) : '';
const activeEditorMedium = editor ? editor.getTitle(Verbosity.MEDIUM) : activeEditorShort;
const activeEditorLong = editor ? editor.getTitle(Verbosity.LONG) : activeEditorMedium;
const activeFolderShort = editorFolderResource ? resources.basename(editorFolderResource) : '';
const activeFolderMedium = editorFolderResource ? this.labelService.getUriLabel(editorFolderResource, { relative: true }) : '';
const activeFolderLong = editorFolderResource ? this.labelService.getUriLabel(editorFolderResource) : '';
const rootName = this.labelService.getWorkspaceLabel(workspace);
const rootPath = root ? this.labelService.getUriLabel(root) : '';
const folderName = folder ? folder.name : '';
@@ -266,6 +297,9 @@ export class TitlebarPart extends Part implements ITitleService {
activeEditorShort,
activeEditorLong,
activeEditorMedium,
activeFolderShort,
activeFolderMedium,
activeFolderLong,
rootName,
rootPath,
folderName,
@@ -277,19 +311,24 @@ export class TitlebarPart extends Part implements ITitleService {
}
createContentArea(parent: HTMLElement): HTMLElement {
this.titleContainer = parent;
this.element = parent;
// Draggable region that we can manipulate for #52522
this.dragRegion = append(this.titleContainer, $('div.titlebar-drag-region'));
this.dragRegion = append(this.element, $('div.titlebar-drag-region'));
// App Icon (Windows/Linux)
if (!isMacintosh) {
this.appIcon = append(this.titleContainer, $('div.window-appicon'));
this.appIcon = append(this.element, $('div.window-appicon'));
this.onUpdateAppIconDragBehavior();
this._register(addDisposableListener(this.appIcon, EventType.DBLCLICK, (e => {
this.windowService.closeWindow();
})));
}
// Menubar: the menubar part which is responsible for populating both the custom and native menubars
this.menubarPart = this.instantiationService.createInstance(MenubarControl);
this.menubar = append(this.titleContainer, $('div.menubar'));
this.menubar = append(this.element, $('div.menubar'));
this.menubar.setAttribute('role', 'menubar');
this.menubarPart.create(this.menubar);
@@ -300,7 +339,7 @@ export class TitlebarPart extends Part implements ITitleService {
}
// Title
this.title = append(this.titleContainer, $('div.window-title'));
this.title = append(this.element, $('div.window-title'));
if (this.pendingTitle) {
this.title.innerText = this.pendingTitle;
} else {
@@ -309,7 +348,7 @@ export class TitlebarPart extends Part implements ITitleService {
// Maximize/Restore on doubleclick
if (isMacintosh) {
this._register(addDisposableListener(this.titleContainer, EventType.DBLCLICK, e => {
this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => {
EventHelper.stop(e);
this.onTitleDoubleclick();
@@ -329,7 +368,7 @@ export class TitlebarPart extends Part implements ITitleService {
// Window Controls (Windows/Linux)
if (!isMacintosh) {
this.windowControls = append(this.titleContainer, $('div.window-controls-container'));
this.windowControls = append(this.element, $('div.window-controls-container'));
// Minimize
@@ -364,7 +403,7 @@ export class TitlebarPart extends Part implements ITitleService {
}));
// Resizer
this.resizer = append(this.titleContainer, $('div.resizer'));
this.resizer = append(this.element, $('div.resizer'));
const isMaximized = this.windowService.getConfiguration().maximized ? true : false;
this.onDidChangeMaximized(isMaximized);
@@ -373,7 +412,7 @@ export class TitlebarPart extends Part implements ITitleService {
// Since the title area is used to drag the window, we do not want to steal focus from the
// currently active element. So we restore focus after a timeout back to where it was.
this._register(addDisposableListener(this.titleContainer, EventType.MOUSE_DOWN, e => {
this._register(addDisposableListener(this.element, EventType.MOUSE_DOWN, e => {
if (e.target && isAncestor(e.target as HTMLElement, this.menubar)) {
return;
}
@@ -388,7 +427,7 @@ export class TitlebarPart extends Part implements ITitleService {
this.updateStyles();
return this.titleContainer;
return this.element;
}
private onDidChangeMaximized(maximized: boolean) {
@@ -417,26 +456,26 @@ export class TitlebarPart extends Part implements ITitleService {
super.updateStyles();
// Part container
if (this.titleContainer) {
if (this.element) {
if (this.isInactive) {
addClass(this.titleContainer, 'inactive');
addClass(this.element, 'inactive');
} else {
removeClass(this.titleContainer, 'inactive');
removeClass(this.element, 'inactive');
}
const titleBackground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_BACKGROUND : TITLE_BAR_ACTIVE_BACKGROUND);
this.titleContainer.style.backgroundColor = titleBackground;
this.element.style.backgroundColor = titleBackground;
if (Color.fromHex(titleBackground).isLighter()) {
addClass(this.titleContainer, 'light');
addClass(this.element, 'light');
} else {
removeClass(this.titleContainer, 'light');
removeClass(this.element, 'light');
}
const titleForeground = this.getColor(this.isInactive ? TITLE_BAR_INACTIVE_FOREGROUND : TITLE_BAR_ACTIVE_FOREGROUND);
this.titleContainer.style.color = titleForeground;
this.element.style.color = titleForeground;
const titleBorder = this.getColor(TITLE_BAR_BORDER);
this.titleContainer.style.borderBottom = titleBorder ? `1px solid ${titleBorder}` : null;
this.element.style.borderBottom = titleBorder ? `1px solid ${titleBorder}` : null;
}
}
@@ -444,6 +483,16 @@ export class TitlebarPart extends Part implements ITitleService {
this.windowService.onWindowTitleDoubleClick();
}
private onUpdateAppIconDragBehavior() {
const setting = this.configurationService.getValue('window.doubleClickIconToClose');
if (setting) {
this.appIcon.style['-webkit-app-region'] = 'no-drag';
}
else {
this.appIcon.style['-webkit-app-region'] = 'drag';
}
}
private onContextMenu(e: MouseEvent): void {
// Find target anchor
@@ -491,30 +540,27 @@ export class TitlebarPart extends Part implements ITitleService {
}
private adjustTitleMarginToCenter(): void {
setTimeout(() => {
// Cannot center
if (!isMacintosh &&
(this.appIcon.clientWidth + this.menubar.clientWidth + 10 > (this.titleContainer.clientWidth - this.title.clientWidth) / 2 ||
this.titleContainer.clientWidth - this.windowControls.clientWidth - 10 < (this.titleContainer.clientWidth + this.title.clientWidth) / 2)) {
this.title.style.position = null;
this.title.style.left = null;
this.title.style.transform = null;
} else {
this.title.style.position = 'absolute';
this.title.style.left = '50%';
this.title.style.transform = 'translate(-50%, 0)';
}
}, 0); // delay so that we can get accurate information about widths
if (!isMacintosh &&
(this.appIcon.clientWidth + this.menubar.clientWidth + 10 > (this.element.clientWidth - this.title.clientWidth) / 2 ||
this.element.clientWidth - this.windowControls.clientWidth - 10 < (this.element.clientWidth + this.title.clientWidth) / 2)) {
this.title.style.position = null;
this.title.style.left = null;
this.title.style.transform = null;
} else {
this.title.style.position = 'absolute';
this.title.style.left = '50%';
this.title.style.transform = 'translate(-50%, 0)';
}
}
layout(dimension: Dimension): Dimension[] {
updateLayout(dimension: Dimension): void {
if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
// Only prevent zooming behavior on macOS or when the menubar is not visible
if (isMacintosh || this.configurationService.getValue<MenuBarVisibility>('window.menuBarVisibility') === 'hidden') {
this.title.style.zoom = `${1.0 / getZoomFactor()}`;
this.title.style.zoom = `${1 / getZoomFactor()}`;
if (isWindows || isLinux) {
this.appIcon.style.zoom = `${1.0 / getZoomFactor()}`;
this.windowControls.style.zoom = `${1.0 / getZoomFactor()}`;
this.appIcon.style.zoom = `${1 / getZoomFactor()}`;
this.windowControls.style.zoom = `${1 / getZoomFactor()}`;
}
} else {
this.title.style.zoom = null;
@@ -524,15 +570,34 @@ export class TitlebarPart extends Part implements ITitleService {
}
}
this.adjustTitleMarginToCenter();
runAtThisOrScheduleAtNextAnimationFrame(() => this.adjustTitleMarginToCenter());
if (this.menubarPart) {
const menubarDimension = new Dimension(undefined, dimension.height);
this.menubarPart.layout(menubarDimension);
}
}
}
return super.layout(dimension);
layout(dimension: Dimension): Dimension[];
layout(width: number, height: number): void;
layout(dim1: Dimension | number, dim2?: number): Dimension[] | void {
if (dim1 instanceof Dimension) {
this.updateLayout(dim1);
return super.layout(dim1);
}
const dimensions = new Dimension(dim1, dim2);
this.updateLayout(dimensions);
super.layout(dimensions);
}
toJSON(): object {
return {
type: Parts.TITLEBAR_PART
};
}
}
@@ -542,7 +607,7 @@ class ShowItemInFolderAction extends Action {
super('showItemInFolder.action.id', label);
}
run(): Thenable<void> {
run(): Promise<void> {
return this.windowsService.showItemInFolder(this.path);
}
}
@@ -551,7 +616,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const titlebarActiveFg = theme.getColor(TITLE_BAR_ACTIVE_FOREGROUND);
if (titlebarActiveFg) {
collector.addRule(`
.monaco-workbench > .part.titlebar > .window-controls-container .window-icon {
.monaco-workbench .part.titlebar > .window-controls-container .window-icon {
background-color: ${titlebarActiveFg};
}
`);
@@ -560,7 +625,7 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
const titlebarInactiveFg = theme.getColor(TITLE_BAR_INACTIVE_FOREGROUND);
if (titlebarInactiveFg) {
collector.addRule(`
.monaco-workbench > .part.titlebar.inactive > .window-controls-container .window-icon {
.monaco-workbench .part.titlebar.inactive > .window-controls-container .window-icon {
background-color: ${titlebarInactiveFg};
}
`);

View File

@@ -13,7 +13,7 @@ import { IContextMenuService } from 'vs/platform/contextview/browser/contextView
import { IMenuService, MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
import { ContextAwareMenuItemActionItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuItemActionItem';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IViewsService, ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ICustomViewDescriptor, ViewsRegistry, ViewContainer, ITreeItemLabel } from 'vs/workbench/common/views';
import { IViewsService, ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ITreeViewDescriptor, ViewsRegistry, ViewContainer, ITreeItemLabel } from 'vs/workbench/common/views';
import { IViewletViewOptions, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -23,7 +23,7 @@ import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/work
import { ICommandService } from 'vs/platform/commands/common/commands';
import * as DOM from 'vs/base/browser/dom';
import { IDataSource, ITree, IRenderer, ContextMenuEvent } from 'vs/base/parts/tree/browser/tree';
import { ResourceLabel } from 'vs/workbench/browser/labels';
import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionItemProvider, ActionItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { URI } from 'vs/base/common/uri';
import { basename } from 'vs/base/common/paths';
@@ -51,22 +51,18 @@ export class CustomTreeViewPanel extends ViewletPanel {
constructor(
options: IViewletViewOptions,
@INotificationService private notificationService: INotificationService,
@INotificationService private readonly notificationService: INotificationService,
@IKeybindingService keybindingService: IKeybindingService,
@IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService configurationService: IConfigurationService,
@IViewsService viewsService: IViewsService,
) {
super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService);
const { treeView } = (<ICustomViewDescriptor>ViewsRegistry.getView(options.id));
const { treeView } = (<ITreeViewDescriptor>ViewsRegistry.getView(options.id));
this.treeView = treeView;
this.treeView.onDidChangeActions(() => this.updateActions(), this, this.disposables);
this.disposables.push(toDisposable(() => this.treeView.setVisibility(false)));
this.updateTreeVisibility();
}
setVisible(visible: boolean): void {
super.setVisible(visible);
this.disposables.push(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility()));
this.updateTreeVisibility();
}
@@ -79,11 +75,6 @@ export class CustomTreeViewPanel extends ViewletPanel {
this.treeView.show(container);
}
setExpanded(expanded: boolean): void {
this.treeView.setVisibility(this.isVisible() && expanded);
super.setExpanded(expanded);
}
layoutBody(size: number): void {
this.treeView.layout(size);
}
@@ -105,7 +96,7 @@ export class CustomTreeViewPanel extends ViewletPanel {
}
private updateTreeVisibility(): void {
this.treeView.setVisibility(this.isVisible() && this.isExpanded());
this.treeView.setVisibility(this.isBodyVisible());
}
dispose(): void {
@@ -126,8 +117,8 @@ class TitleMenus implements IDisposable {
constructor(
id: string,
@IContextKeyService private contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
) {
if (this.titleDisposable) {
this.titleDisposable.dispose();
@@ -175,7 +166,7 @@ class Root implements ITreeItem {
handle = '0';
parentHandle = null;
collapsibleState = TreeItemCollapsibleState.Expanded;
children = void 0;
children = undefined;
}
const noDataProviderMessage = localize('no-dataprovider', "There is no data provider registered that can provide view data.");
@@ -194,6 +185,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
private _messageValue: string | IMarkdownString | undefined;
private messageElement: HTMLDivElement;
private tree: FileIconThemableWorkbenchTree;
private treeLabels: ResourceLabels;
private root: ITreeItem;
private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus;
@@ -218,13 +210,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
constructor(
private id: string,
private container: ViewContainer,
@IExtensionService private extensionService: IExtensionService,
@IWorkbenchThemeService private themeService: IWorkbenchThemeService,
@IInstantiationService private instantiationService: IInstantiationService,
@ICommandService private commandService: ICommandService,
@IConfigurationService private configurationService: IConfigurationService,
@IProgressService2 private progressService: IProgressService2
private viewContainer: ViewContainer,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommandService private readonly commandService: ICommandService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProgressService2 private readonly progressService: IProgressService2
) {
super();
this.root = new Root();
@@ -243,6 +235,11 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.markdownResult.dispose();
}
}));
this._register(ViewsRegistry.onDidChangeContainer(({ views, from, to }) => {
if (from === this.viewContainer && views.some(v => v.id === this.id)) {
this.viewContainer = to;
}
}));
this.create();
}
@@ -382,13 +379,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
private createTree() {
const actionItemProvider = (action: IAction) => action instanceof MenuItemAction ? this.instantiationService.createInstance(ContextAwareMenuItemActionItem, action) : undefined;
const menus = this.instantiationService.createInstance(TreeMenus, this.id);
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, this.container);
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, menus, actionItemProvider);
const menus = this._register(this.instantiationService.createInstance(TreeMenus, this.id));
this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, this));
const dataSource = this.instantiationService.createInstance(TreeDataSource, this, <T>(task: Promise<T>) => this.progressService.withProgress({ location: this.viewContainer.id }, () => task));
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, menus, this.treeLabels, actionItemProvider);
const controller = this.instantiationService.createInstance(TreeController, this.id, menus);
this.tree = this.instantiationService.createInstance(FileIconThemableWorkbenchTree, this.treeContainer, { dataSource, renderer, controller }, {});
this.tree = this._register(this.instantiationService.createInstance(FileIconThemableWorkbenchTree, this.treeContainer, { dataSource, renderer, controller }, {}));
this.tree.contextKeyService.createKey<boolean>(this.id, true);
this._register(this.tree);
this._register(this.tree.onDidChangeSelection(e => this.onSelection(e)));
this._register(this.tree.onDidExpandItem(e => this._onDidExpandItem.fire(e.item.getElement())));
this._register(this.tree.onDidCollapseItem(e => this._onDidCollapseItem.fire(e.item.getElement())));
@@ -451,7 +448,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
getOptimalWidth(): number {
if (this.tree) {
const parentNode = this.tree.getHTMLElement();
const childNodes = ([] as Element[]).slice.call(parentNode.querySelectorAll('.outline-item-label > a'));
const childNodes = ([] as HTMLElement[]).slice.call(parentNode.querySelectorAll('.outline-item-label > a'));
return DOM.getLargestChildWidth(parentNode, childNodes);
}
return 0;
@@ -459,25 +456,39 @@ export class CustomTreeView extends Disposable implements ITreeView {
refresh(elements?: ITreeItem[]): Promise<void> {
if (this.dataProvider && this.tree) {
elements = elements || [this.root];
if (!elements) {
elements = [this.root];
// remove all waiting elements to refresh if root is asked to refresh
this.elementsToRefresh = [];
}
for (const element of elements) {
element.children = null; // reset children
}
if (this.isVisible) {
return this.doRefresh(elements);
} else {
this.elementsToRefresh.push(...elements);
if (this.elementsToRefresh.length) {
const seen: Set<string> = new Set<string>();
this.elementsToRefresh.forEach(element => seen.add(element.handle));
for (const element of elements) {
if (!seen.has(element.handle)) {
this.elementsToRefresh.push(element);
}
}
} else {
this.elementsToRefresh.push(...elements);
}
}
}
return Promise.resolve(null);
return Promise.resolve(undefined);
}
expand(itemOrItems: ITreeItem | ITreeItem[]): Thenable<void> {
expand(itemOrItems: ITreeItem | ITreeItem[]): Promise<void> {
if (this.tree) {
itemOrItems = Array.isArray(itemOrItems) ? itemOrItems : [itemOrItems];
return this.tree.expandAll(itemOrItems);
}
return Promise.arguments(null);
return Promise.resolve(undefined);
}
setSelection(items: ITreeItem[]): void {
@@ -493,17 +504,17 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}
reveal(item: ITreeItem): Thenable<void> {
reveal(item: ITreeItem): Promise<void> {
if (this.tree) {
return this.tree.reveal(item);
}
return Promise.arguments(null);
return Promise.resolve(null);
}
private activate() {
if (!this.activated) {
this.createTree();
this.progressService.withProgress({ location: this.container.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
this.progressService.withProgress({ location: this.viewContainer.id }, () => this.extensionService.activateByEvent(`onView:${this.id}`))
.then(() => timeout(2000))
.then(() => {
this.updateMessage();
@@ -525,7 +536,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
});
}
return Promise.resolve(null);
return Promise.resolve(undefined);
}
private updateContentAreas(): void {
@@ -563,8 +574,7 @@ class TreeDataSource implements IDataSource {
constructor(
private treeView: ITreeView,
private container: ViewContainer,
@IProgressService2 private progressService: IProgressService2
private withProgress: <T>(task: Promise<T>) => Promise<T>
) {
}
@@ -578,7 +588,7 @@ class TreeDataSource implements IDataSource {
getChildren(tree: ITree, node: ITreeItem): Promise<any[]> {
if (this.treeView.dataProvider) {
return this.progressService.withProgress({ location: this.container.id }, () => this.treeView.dataProvider.getChildren(node));
return this.withProgress(this.treeView.dataProvider.getChildren(node));
}
return Promise.resolve([]);
}
@@ -593,7 +603,7 @@ class TreeDataSource implements IDataSource {
}
interface ITreeExplorerTemplateData {
resourceLabel: ResourceLabel;
resourceLabel: IResourceLabel;
icon: HTMLElement;
actionBar: ActionBar;
aligner: Aligner;
@@ -605,10 +615,12 @@ registerThemingParticipant((theme, collector) => {
const findMatchHighlightColor = theme.getColor(editorFindMatchHighlight);
if (findMatchHighlightColor) {
collector.addRule(`.file-icon-themable-tree .monaco-tree-row .content .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; background-color: ${findMatchHighlightColor}; }`);
}
const findMatchHighlightColorBorder = theme.getColor(editorFindMatchHighlightBorder);
if (findMatchHighlightColorBorder) {
collector.addRule(`.file-icon-themable-tree .monaco-tree-row .content .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`);
collector.addRule(`.monaco-tl-contents .monaco-highlighted-label .highlight { color: unset !important; border: 1px dotted ${findMatchHighlightColorBorder}; box-sizing: border-box; }`);
}
const link = theme.getColor(textLinkForeground);
if (link) {
@@ -632,11 +644,11 @@ class TreeRenderer implements IRenderer {
constructor(
private treeViewId: string,
private menus: TreeMenus,
private labels: ResourceLabels,
private actionItemProvider: IActionItemProvider,
@IInstantiationService private instantiationService: IInstantiationService,
@IWorkbenchThemeService private themeService: IWorkbenchThemeService,
@IConfigurationService private configurationService: IConfigurationService,
@ILabelService private labelService: ILabelService
@IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ILabelService private readonly labelService: ILabelService
) {
}
@@ -652,7 +664,7 @@ class TreeRenderer implements IRenderer {
DOM.addClass(container, 'custom-view-tree-node-item');
const icon = DOM.append(container, DOM.$('.custom-view-tree-node-item-icon'));
const resourceLabel = this.instantiationService.createInstance(ResourceLabel, container, { supportHighlights: true, donotSupportOcticons: true });
const resourceLabel = this.labels.create(container, { supportHighlights: true, donotSupportOcticons: true });
DOM.addClass(resourceLabel.element, 'custom-view-tree-node-item-resourceLabel');
const actionsContainer = DOM.append(resourceLabel.element, DOM.$('.actions'));
const actionBar = new ActionBar(actionsContainer, {
@@ -665,23 +677,22 @@ class TreeRenderer implements IRenderer {
renderElement(tree: ITree, node: ITreeItem, templateId: string, templateData: ITreeExplorerTemplateData): void {
const resource = node.resourceUri ? URI.revive(node.resourceUri) : null;
const treeItemLabel: ITreeItemLabel = node.label ? node.label : resource ? { label: basename(resource.path) } : void 0;
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : void 0;
const label = treeItemLabel ? treeItemLabel.label : void 0;
const matches = treeItemLabel && treeItemLabel.highlights ? treeItemLabel.highlights.map(([start, end]) => ({ start, end })) : void 0;
const treeItemLabel: ITreeItemLabel = node.label ? node.label : resource ? { label: basename(resource.path) } : undefined;
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
const label = treeItemLabel ? treeItemLabel.label : undefined;
const matches = treeItemLabel && treeItemLabel.highlights ? treeItemLabel.highlights.map(([start, end]) => ({ start, end })) : undefined;
const icon = this.themeService.getTheme().type === LIGHT ? node.icon : node.iconDark;
const iconUrl = icon ? URI.revive(icon) : null;
const title = node.tooltip ? node.tooltip : resource ? void 0 : label;
const title = node.tooltip ? node.tooltip : resource ? undefined : label;
// reset
templateData.resourceLabel.clear();
templateData.actionBar.clear();
if (resource || node.themeIcon) {
const fileDecorations = this.configurationService.getValue<{ colors: boolean, badges: boolean }>('explorer.decorations');
templateData.resourceLabel.setLabel({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches });
templateData.resourceLabel.setResource({ name: label, description, resource: resource ? resource : URI.parse('missing:_icon_resource') }, { fileKind: this.getFileKind(node), title, hideIcon: !!iconUrl, fileDecorations, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches });
} else {
templateData.resourceLabel.setLabel({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches });
templateData.resourceLabel.setResource({ name: label, description }, { title, hideIcon: true, extraClasses: ['custom-view-tree-node-item-resourceLabel'], matches });
}
templateData.icon.style.backgroundImage = iconUrl ? `url('${iconUrl.toString(true)}')` : '';
@@ -772,7 +783,7 @@ class TreeController extends WorkbenchTreeController {
constructor(
private treeViewId: string,
private menus: TreeMenus,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@IConfigurationService configurationService: IConfigurationService
) {
@@ -827,7 +838,7 @@ class MultipleSelectionActionRunner extends ActionRunner {
super();
}
runAction(action: IAction, context: any): Thenable<any> {
runAction(action: IAction, context: any): Promise<any> {
if (action instanceof MenuItemAction) {
const selection = this.getSelectedResources();
const filteredSelection = selection.filter(s => s !== context);
@@ -847,9 +858,9 @@ class TreeMenus extends Disposable implements IDisposable {
constructor(
private id: string,
@IContextKeyService private contextKeyService: IContextKeyService,
@IMenuService private menuService: IMenuService,
@IContextMenuService private contextMenuService: IContextMenuService
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService
) {
super();
}
@@ -914,4 +925,4 @@ class MarkdownRenderer {
dispose: () => dispose(disposeables)
};
}
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* File icon themeable tree style */
/* File icon themeable OLD tree style */
.file-icon-themable-tree .monaco-tree-row .content {
display: flex;
}
@@ -50,6 +50,17 @@
display: none;
}
/* File icons in trees */
.file-icon-themable-tree.align-icons-and-twisties .monaco-tl-twistie:not(.collapsible),
.file-icon-themable-tree.hide-arrows .monaco-tl-twistie {
background-image: none !important;
width: 0 !important;
margin-right: 0 !important;
}
/* Misc */
.monaco-workbench .tree-explorer-viewlet-tree-view {
height: 100%;
}

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/panelviewlet';
import * as nls from 'vs/nls';
import { Event, Emitter, filterEvent } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
import { attachStyler, IColorMapping } from 'vs/platform/theme/common/styler';
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER } from 'vs/workbench/common/theme';
@@ -52,14 +52,17 @@ export abstract class ViewletPanel extends Panel implements IView {
private _onDidBlur = new Emitter<void>();
readonly onDidBlur: Event<void> = this._onDidBlur.event;
private _onDidChangeBodyVisibility = new Emitter<boolean>();
readonly onDidChangeBodyVisibility: Event<boolean> = this._onDidChangeBodyVisibility.event;
protected _onDidChangeTitleArea = new Emitter<void>();
readonly onDidChangeTitleArea: Event<void> = this._onDidChangeTitleArea.event;
private _isVisible: boolean = true;
private _isVisible: boolean = false;
readonly id: string;
readonly title: string;
protected actionRunner: IActionRunner;
protected actionRunner?: IActionRunner;
protected toolbar: ToolBar;
private headerContainer: HTMLElement;
@@ -74,11 +77,17 @@ export abstract class ViewletPanel extends Panel implements IView {
this.id = options.id;
this.title = options.title;
this.actionRunner = options.actionRunner;
this.disposables.push(this._onDidFocus, this._onDidBlur, this._onDidChangeBodyVisibility, this._onDidChangeTitleArea);
}
setVisible(visible: boolean): void {
if (this._isVisible !== visible) {
this._isVisible = visible;
if (this.isExpanded()) {
this._onDidChangeBodyVisibility.fire(visible);
}
}
}
@@ -86,6 +95,19 @@ export abstract class ViewletPanel extends Panel implements IView {
return this._isVisible;
}
isBodyVisible(): boolean {
return this._isVisible && this.isExpanded();
}
setExpanded(expanded: boolean): boolean {
const changed = super.setExpanded(expanded);
if (changed) {
this._onDidChangeBodyVisibility.fire(expanded);
}
return changed;
}
render(): void {
super.render();
@@ -105,20 +127,20 @@ export abstract class ViewletPanel extends Panel implements IView {
orientation: ActionsOrientation.HORIZONTAL,
actionItemProvider: action => this.getActionItem(action),
ariaLabel: nls.localize('viewToolbarAriaLabel', "{0} actions", this.title),
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id),
getKeyBinding: action => this.keybindingService.lookupKeybinding(action.id) || undefined,
actionRunner: this.actionRunner
});
this.disposables.push(this.toolbar);
this.setActions();
const onDidRelevantConfigurationChange = filterEvent(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewletPanel.AlwaysShowActionsConfig));
const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewletPanel.AlwaysShowActionsConfig));
onDidRelevantConfigurationChange(this.updateActionsVisibility, this, this.disposables);
this.updateActionsVisibility();
}
protected renderHeaderTitle(container: HTMLElement, title: string): void {
append(container, $('h3.title', null, title));
append(container, $('h3.title', undefined, title));
}
focus(): void {
@@ -151,7 +173,7 @@ export abstract class ViewletPanel extends Panel implements IView {
return [];
}
getActionItem(action: IAction): IActionItem {
getActionItem(action: IAction): IActionItem | null {
return null;
}
@@ -237,7 +259,7 @@ export class PanelViewlet extends Viewlet {
let title = Registry.as<ViewletRegistry>(Extensions.Viewlets).getViewlet(this.getId()).name;
if (this.isSingleView()) {
title += ': ' + this.panelItems[0].panel.title;
title = `${title}: ${this.panelItems[0].panel.title}`;
}
return title;
@@ -259,7 +281,7 @@ export class PanelViewlet extends Viewlet {
return [];
}
getActionItem(action: IAction): IActionItem {
getActionItem(action: IAction): IActionItem | null {
if (this.isSingleView()) {
return this.panelItems[0].panel.getActionItem(action);
}
@@ -283,7 +305,7 @@ export class PanelViewlet extends Viewlet {
}
layout(dimension: Dimension): void {
this.panelview.layout(dimension.height);
this.panelview.layout(dimension.height, dimension.width);
}
getOptimalWidth(): number {

View File

@@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/views';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { IViewsService, ViewsRegistry, IViewsViewlet, ViewContainer, IViewDescriptor, IViewContainersRegistry, Extensions as ViewContainerExtensions, IView, IViewDescriptorCollection } from 'vs/workbench/common/views';
import { Registry } from 'vs/platform/registry/common/platform';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IContextKeyService, IContextKeyChangeEvent, IReadableSet, IContextKey, RawContextKey, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { Event, chain, filterEvent, Emitter } from 'vs/base/common/event';
import { sortedDiff, firstIndex, move } from 'vs/base/common/arrays';
import { Event, Emitter } from 'vs/base/common/event';
import { sortedDiff, firstIndex, move, isNonEmptyArray } from 'vs/base/common/arrays';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { MenuId, MenuRegistry, ICommandAction } from 'vs/platform/actions/common/actions';
@@ -19,14 +19,23 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { localize } from 'vs/nls';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { values } from 'vs/base/common/map';
import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { toggleClass, addClass } from 'vs/base/browser/dom';
function filterViewEvent(container: ViewContainer, event: Event<IViewDescriptor[]>): Event<IViewDescriptor[]> {
return chain(event)
.map(views => views.filter(view => view.container === container))
function filterViewRegisterEvent(container: ViewContainer, event: Event<{ viewContainer: ViewContainer, views: IViewDescriptor[] }>): Event<IViewDescriptor[]> {
return Event.chain(event)
.map(({ views, viewContainer }) => viewContainer === container ? views : [])
.filter(views => views.length > 0)
.event;
}
function filterViewMoveEvent(container: ViewContainer, event: Event<{ from: ViewContainer, to: ViewContainer, views: IViewDescriptor[] }>): Event<{ added?: IViewDescriptor[], removed?: IViewDescriptor[] }> {
return Event.chain(event)
.map(({ views, from, to }) => from === container ? { removed: views } : to === container ? { added: views } : {})
.filter(({ added, removed }) => isNonEmptyArray(added) || isNonEmptyArray(removed))
.event;
}
class CounterSet<T> implements IReadableSet<T> {
private map = new Map<T, number>();
@@ -84,16 +93,26 @@ class ViewDescriptorCollection extends Disposable implements IViewDescriptorColl
constructor(
container: ViewContainer,
@IContextKeyService private contextKeyService: IContextKeyService
@IContextKeyService private readonly contextKeyService: IContextKeyService
) {
super();
const onRelevantViewsRegistered = filterViewEvent(container, ViewsRegistry.onViewsRegistered);
const onRelevantViewsRegistered = filterViewRegisterEvent(container, ViewsRegistry.onViewsRegistered);
this._register(onRelevantViewsRegistered(this.onViewsRegistered, this));
const onRelevantViewsDeregistered = filterViewEvent(container, ViewsRegistry.onViewsDeregistered);
const onRelevantViewsMoved = filterViewMoveEvent(container, ViewsRegistry.onDidChangeContainer);
this._register(onRelevantViewsMoved(({ added, removed }) => {
if (isNonEmptyArray(added)) {
this.onViewsRegistered(added);
}
if (isNonEmptyArray(removed)) {
this.onViewsDeregistered(removed);
}
}));
const onRelevantViewsDeregistered = filterViewRegisterEvent(container, ViewsRegistry.onViewsDeregistered);
this._register(onRelevantViewsDeregistered(this.onViewsDeregistered, this));
const onRelevantContextChange = filterEvent(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys));
const onRelevantContextChange = Event.filter(contextKeyService.onDidChangeContext, e => e.affectsSome(this.contextKeys));
this._register(onRelevantContextChange(this.onContextChanged, this));
this.onViewsRegistered(ViewsRegistry.getViews(container));
@@ -204,7 +223,7 @@ export class ContributableViewsModel extends Disposable {
readonly viewDescriptors: IViewDescriptor[] = [];
get visibleViewDescriptors(): IViewDescriptor[] {
return this.viewDescriptors.filter(v => this.viewStates.get(v.id).visible);
return this.viewDescriptors.filter(v => this.viewStates.get(v.id)!.visible);
}
private _onDidAdd = this._register(new Emitter<IAddedViewDescriptorRef[]>());
@@ -224,8 +243,10 @@ export class ContributableViewsModel extends Disposable {
super();
const viewDescriptorCollection = viewsService.getViewDescriptors(container);
this._register(viewDescriptorCollection.onDidChangeActiveViews(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors)));
this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors);
if (viewDescriptorCollection) {
this._register(viewDescriptorCollection.onDidChangeActiveViews(() => this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors)));
this.onDidChangeViewDescriptors(viewDescriptorCollection.activeViewDescriptors);
}
}
isVisible(id: string): boolean {
@@ -298,7 +319,7 @@ export class ContributableViewsModel extends Disposable {
move(this.viewDescriptors, fromIndex, toIndex);
for (let index = 0; index < this.viewDescriptors.length; index++) {
const state = this.viewStates.get(this.viewDescriptors[index].id);
const state = this.viewStates.get(this.viewDescriptors[index].id)!;
state.order = index;
}
@@ -312,6 +333,9 @@ export class ContributableViewsModel extends Disposable {
for (let i = 0, visibleIndex = 0; i < this.viewDescriptors.length; i++) {
const viewDescriptor = this.viewDescriptors[i];
const state = this.viewStates.get(viewDescriptor.id);
if (!state) {
throw new Error(`View state for ${id} not found`);
}
if (viewDescriptor.id === id) {
return { index: i, visibleIndex, viewDescriptor, state };
@@ -357,7 +381,7 @@ export class ContributableViewsModel extends Disposable {
} else {
this.viewStates.set(viewDescriptor.id, {
visible: !viewDescriptor.hideByDefault,
collapsed: viewDescriptor.collapsed
collapsed: !!viewDescriptor.collapsed
});
}
}
@@ -369,7 +393,7 @@ export class ContributableViewsModel extends Disposable {
).reverse();
const toRemove: { index: number, viewDescriptor: IViewDescriptor }[] = [];
const toAdd: { index: number, viewDescriptor: IViewDescriptor, size: number, collapsed: boolean }[] = [];
const toAdd: { index: number, viewDescriptor: IViewDescriptor, size?: number, collapsed: boolean }[] = [];
for (const splice of splices) {
const startViewDescriptor = this.viewDescriptors[splice.start];
@@ -384,9 +408,8 @@ export class ContributableViewsModel extends Disposable {
}
}
for (let i = 0; i < splice.toInsert.length; i++) {
const viewDescriptor = splice.toInsert[i];
const state = this.viewStates.get(viewDescriptor.id);
for (const viewDescriptor of splice.toInsert) {
const state = this.viewStates.get(viewDescriptor.id)!;
if (state.visible) {
toAdd.push({ index: startIndex++, viewDescriptor, size: state.size, collapsed: state.collapsed });
@@ -437,7 +460,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
}
private saveViewsStates(): void {
const storedViewsStates: { [id: string]: { collapsed: boolean, size: number, order: number } } = {};
const storedViewsStates: { [id: string]: { collapsed: boolean, size?: number, order?: number } } = {};
let hasState = false;
for (const viewDescriptor of this.viewDescriptors) {
@@ -460,7 +483,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
for (const viewDescriptor of viewDescriptors) {
if (viewDescriptor.canToggleVisibility) {
const viewState = this.viewStates.get(viewDescriptor.id);
storedViewsVisibilityStates.set(viewDescriptor.id, { id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : void 0 });
storedViewsVisibilityStates.set(viewDescriptor.id, { id: viewDescriptor.id, isHidden: viewState ? !viewState.visible : false });
}
}
this.storageService.store(this.hiddenViewsStorageId, JSON.stringify(values(storedViewsVisibilityStates)), StorageScope.GLOBAL);
@@ -513,34 +536,49 @@ export class ViewsService extends Disposable implements IViewsService {
_serviceBrand: any;
private readonly viewDescriptorCollections: Map<ViewContainer, IViewDescriptorCollection>;
private readonly viewDescriptorCollections: Map<ViewContainer, { viewDescriptorCollection: IViewDescriptorCollection, disposable: IDisposable }>;
private readonly viewDisposable: Map<IViewDescriptor, IDisposable>;
private readonly activeViewContextKeys: Map<string, IContextKey<boolean>>;
constructor(
@IViewletService private viewletService: IViewletService,
@IContextKeyService private contextKeyService: IContextKeyService
@IViewletService private readonly viewletService: IViewletService,
@IContextKeyService private readonly contextKeyService: IContextKeyService
) {
super();
this.viewDescriptorCollections = new Map<ViewContainer, IViewDescriptorCollection>();
this.viewDescriptorCollections = new Map<ViewContainer, { viewDescriptorCollection: IViewDescriptorCollection, disposable: IDisposable }>();
this.viewDisposable = new Map<IViewDescriptor, IDisposable>();
this.activeViewContextKeys = new Map<string, IContextKey<boolean>>();
this.onDidRegisterViews(ViewsRegistry.getAllViews());
this._register(ViewsRegistry.onViewsRegistered(views => this.onDidRegisterViews(views)));
const viewContainersRegistry = Registry.as<IViewContainersRegistry>(ViewContainerExtensions.ViewContainersRegistry);
viewContainersRegistry.all.forEach(viewContainer => this.onDidRegisterViewContainer(viewContainer));
viewContainersRegistry.all.forEach(viewContainer => {
this.onDidRegisterViews(viewContainer, ViewsRegistry.getViews(viewContainer));
this.onDidRegisterViewContainer(viewContainer);
});
this._register(ViewsRegistry.onViewsRegistered(({ views, viewContainer }) => this.onDidRegisterViews(viewContainer, views)));
this._register(ViewsRegistry.onViewsDeregistered(({ views }) => this.onDidDeregisterViews(views)));
this._register(ViewsRegistry.onDidChangeContainer(({ views, to }) => { this.onDidDeregisterViews(views); this.onDidRegisterViews(to, views); }));
this._register(toDisposable(() => {
this.viewDisposable.forEach(disposable => disposable.dispose());
this.viewDisposable.clear();
}));
this._register(viewContainersRegistry.onDidRegister(viewContainer => this.onDidRegisterViewContainer(viewContainer)));
this._register(viewContainersRegistry.onDidDeregister(viewContainer => this.onDidDeregisterViewContainer(viewContainer)));
this._register(toDisposable(() => {
this.viewDescriptorCollections.forEach(({ disposable }) => disposable.dispose());
this.viewDescriptorCollections.clear();
}));
}
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection {
return this.viewDescriptorCollections.get(container);
getViewDescriptors(container: ViewContainer): IViewDescriptorCollection | null {
const viewDescriptorCollectionItem = this.viewDescriptorCollections.get(container);
return viewDescriptorCollectionItem ? viewDescriptorCollectionItem.viewDescriptorCollection : null;
}
openView(id: string, focus: boolean): Thenable<IView> {
const viewDescriptor = ViewsRegistry.getView(id);
if (viewDescriptor) {
const viewletDescriptor = this.viewletService.getViewlet(viewDescriptor.container.id);
openView(id: string, focus: boolean): Promise<IView | null> {
const viewContainer = ViewsRegistry.getViewContainer(id);
if (viewContainer) {
const viewletDescriptor = this.viewletService.getViewlet(viewContainer.id);
if (viewletDescriptor) {
return this.viewletService.openViewlet(viewletDescriptor.id, focus)
.then((viewlet: IViewsViewlet) => {
@@ -555,12 +593,21 @@ export class ViewsService extends Disposable implements IViewsService {
}
private onDidRegisterViewContainer(viewContainer: ViewContainer): void {
const viewDescriptorCollection = this._register(new ViewDescriptorCollection(viewContainer, this.contextKeyService));
const viewDescriptorCollection = new ViewDescriptorCollection(viewContainer, this.contextKeyService);
const disposables: IDisposable[] = [viewDescriptorCollection];
this.onDidChangeActiveViews({ added: viewDescriptorCollection.activeViewDescriptors, removed: [] });
this._register(viewDescriptorCollection.onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed)));
viewDescriptorCollection.onDidChangeActiveViews(changed => this.onDidChangeActiveViews(changed), this, disposables);
this.viewDescriptorCollections.set(viewContainer, viewDescriptorCollection);
this.viewDescriptorCollections.set(viewContainer, { viewDescriptorCollection, disposable: toDisposable(() => dispose(disposables)) });
}
private onDidDeregisterViewContainer(viewContainer: ViewContainer): void {
const viewDescriptorCollectionItem = this.viewDescriptorCollections.get(viewContainer);
if (viewDescriptorCollectionItem) {
viewDescriptorCollectionItem.disposable.dispose();
this.viewDescriptorCollections.delete(viewContainer);
}
}
private onDidChangeActiveViews({ added, removed }: { added: IViewDescriptor[], removed: IViewDescriptor[] }): void {
@@ -568,9 +615,10 @@ export class ViewsService extends Disposable implements IViewsService {
removed.forEach(viewDescriptor => this.getOrCreateActiveViewContextKey(viewDescriptor).set(false));
}
private onDidRegisterViews(viewDescriptors: IViewDescriptor[]): void {
for (const viewDescriptor of viewDescriptors) {
const viewlet = this.viewletService.getViewlet(viewDescriptor.container.id);
private onDidRegisterViews(container: ViewContainer, views: IViewDescriptor[]): void {
const viewlet = this.viewletService.getViewlet(container.id);
for (const viewDescriptor of views) {
const disposables: IDisposable[] = [];
const command: ICommandAction = {
id: viewDescriptor.focusCommand ? viewDescriptor.focusCommand.id : `${viewDescriptor.id}.focus`,
title: { original: `Focus on ${viewDescriptor.name} View`, value: localize('focus view', "Focus on {0} View", viewDescriptor.name) },
@@ -578,12 +626,12 @@ export class ViewsService extends Disposable implements IViewsService {
};
const when = ContextKeyExpr.has(`${viewDescriptor.id}.active`);
CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true).then(() => null));
disposables.push(CommandsRegistry.registerCommand(command.id, () => this.openView(viewDescriptor.id, true).then(() => null)));
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
disposables.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command,
when
});
}));
if (viewDescriptor.focusCommand && viewDescriptor.focusCommand.keybindings) {
KeybindingsRegistry.registerKeybindingRule({
@@ -597,6 +645,18 @@ export class ViewsService extends Disposable implements IViewsService {
win: viewDescriptor.focusCommand.keybindings.win
});
}
this.viewDisposable.set(viewDescriptor, toDisposable(() => dispose(disposables)));
}
}
private onDidDeregisterViews(views: IViewDescriptor[]): void {
for (const view of views) {
const disposable = this.viewDisposable.get(view);
if (disposable) {
disposable.dispose();
this.viewDisposable.delete(view);
}
}
}
@@ -610,3 +670,16 @@ export class ViewsService extends Disposable implements IViewsService {
return contextKey;
}
}
export function createFileIconThemableTreeContainerScope(container: HTMLElement, themeService: IWorkbenchThemeService): IDisposable {
addClass(container, 'file-icon-themable-tree');
addClass(container, 'show-file-icons');
const onDidChangeFileIconTheme = (theme: IFileIconTheme) => {
toggleClass(container, 'align-icons-and-twisties', theme.hasFileIcons && !theme.hasFolderIcons);
toggleClass(container, 'hide-arrows', theme.hidesExplorerArrows === true);
};
onDidChangeFileIconTheme(themeService.getFileIconTheme());
return themeService.onDidFileIconThemeChange(onDidChangeFileIconTheme);
}

View File

@@ -23,83 +23,13 @@ import { DefaultPanelDndController } from 'vs/base/browser/ui/splitview/panelvie
import { WorkbenchTree, IListService } from 'vs/platform/list/browser/listService';
import { IWorkbenchThemeService, IFileIconTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree';
import { latch, mapEvent } from 'vs/base/common/event';
import { Event } from 'vs/base/common/event';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IPartService } from 'vs/workbench/services/part/common/partService';
import { localize } from 'vs/nls';
import { IAddedViewDescriptorRef, IViewDescriptorRef, PersistentContributableViewsModel } from 'vs/workbench/browser/parts/views/views';
import { Registry } from 'vs/platform/registry/common/platform';
export abstract class TreeViewsViewletPanel extends ViewletPanel {
protected tree: WorkbenchTree;
setExpanded(expanded: boolean): void {
if (this.isExpanded() !== expanded) {
this.updateTreeVisibility(this.tree, expanded);
super.setExpanded(expanded);
}
}
setVisible(visible: boolean): void {
if (this.isVisible() !== visible) {
super.setVisible(visible);
this.updateTreeVisibility(this.tree, visible && this.isExpanded());
}
}
focus(): void {
super.focus();
this.focusTree();
}
layoutBody(size: number): void {
if (this.tree) {
this.tree.layout(size);
}
}
protected updateTreeVisibility(tree: WorkbenchTree, isVisible: boolean): void {
if (!tree) {
return;
}
if (isVisible) {
DOM.show(tree.getHTMLElement());
} else {
DOM.hide(tree.getHTMLElement()); // make sure the tree goes out of the tabindex world by hiding it
}
if (isVisible) {
tree.onVisible();
} else {
tree.onHidden();
}
}
private focusTree(): void {
if (!this.tree) {
return; // return early if viewlet has not yet been created
}
// Make sure the current selected element is revealed
const selectedElement = this.tree.getSelection()[0];
if (selectedElement) {
this.tree.reveal(selectedElement);
}
// Pass Focus to Viewer
this.tree.domFocus();
}
dispose(): void {
if (this.tree) {
this.tree.dispose();
}
super.dispose();
}
}
export interface IViewletViewOptions extends IViewletPanelOptions {
viewletState: object;
}
@@ -274,7 +204,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView
this.onContextMenu(new StandardMouseEvent(e), viewDescriptor);
});
const collapseDisposable = latch(mapEvent(panel.onDidChange, () => !panel.isExpanded()))(collapsed => {
const collapseDisposable = Event.latch(Event.map(panel.onDidChange, () => !panel.isExpanded()))(collapsed => {
this.viewsModel.setCollapsed(viewDescriptor.id, collapsed);
});
@@ -284,7 +214,13 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView
this.addPanels(panelsToAdd);
this.restoreViewSizes();
return panelsToAdd.map(({ panel }) => panel);
const panels: ViewletPanel[] = [];
for (const { panel } of panelsToAdd) {
panel.setVisible(this.isVisible());
panels.push(panel);
}
return panels;
}
private onDidRemoveViews(removed: IViewDescriptorRef[]): void {

View File

@@ -43,14 +43,14 @@ export class QuickOpenHandler {
* As such, returning the same model instance across multiple searches will yield best
* results in terms of performance when many items are shown.
*/
getResults(searchValue: string, token: CancellationToken): Thenable<IModel<any>> {
getResults(searchValue: string, token: CancellationToken): Promise<IModel<any> | null> {
return Promise.resolve(null);
}
/**
* The ARIA label to apply when this quick open handler is active in quick open.
*/
getAriaLabel(): string {
getAriaLabel() {
return null;
}
@@ -317,7 +317,7 @@ export class QuickOpenAction extends Action {
id: string,
label: string,
prefix: string,
@IQuickOpenService private quickOpenService: IQuickOpenService
@IQuickOpenService private readonly quickOpenService: IQuickOpenService
) {
super(id, label);
@@ -330,6 +330,6 @@ export class QuickOpenAction extends Action {
// Show with prefix
this.quickOpenService.show(this.prefix);
return Promise.resolve(null);
return Promise.resolve(undefined);
}
}

View File

@@ -12,13 +12,12 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
import { IConstructorSignature0 } from 'vs/platform/instantiation/common/instantiation';
import { ToggleSidebarVisibilityAction } from 'vs/workbench/browser/actions/toggleSidebarVisibility';
import { ToggleSidebarVisibilityAction, ToggleSidebarPositionAction } from 'vs/workbench/browser/actions/layoutActions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPartService, Parts } from 'vs/workbench/services/part/common/partService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IEditorGroupsService } from 'vs/workbench/services/group/common/editorGroupsService';
import { URI } from 'vs/base/common/uri';
import { ToggleSidebarPositionAction } from 'vs/workbench/browser/actions/toggleSidebarPosition';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree';
@@ -35,7 +34,7 @@ export abstract class Viewlet extends Composite implements IViewlet {
super(id, telemetryService, themeService, storageService);
}
getOptimalWidth(): number {
getOptimalWidth(): number | null {
return null;
}
@@ -67,7 +66,7 @@ export class ViewletDescriptor extends CompositeDescriptor<Viewlet> {
super(ctor, id, name, cssClass, order, id);
}
get iconUrl(): URI {
get iconUrl(): URI | undefined {
return this._iconUrl;
}
}
@@ -86,6 +85,16 @@ export class ViewletRegistry extends CompositeRegistry<Viewlet> {
super.registerComposite(descriptor);
}
/**
* Deregisters a viewlet to the platform.
*/
deregisterViewlet(id: string): void {
if (id === this.defaultViewletId) {
throw new Error('Cannot deregister default viewlet');
}
super.deregisterComposite(id);
}
/**
* Returns the viewlet descriptor for the given id or null if none.
*/
@@ -128,8 +137,8 @@ export class ShowViewletAction extends Action {
name: string,
viewletId: string,
@IViewletService protected viewletService: IViewletService,
@IEditorGroupsService private editorGroupService: IEditorGroupsService,
@IPartService private partService: IPartService
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService,
@IPartService private readonly partService: IPartService
) {
super(id, name);
@@ -137,7 +146,7 @@ export class ShowViewletAction extends Action {
this.enabled = !!this.viewletService && !!this.editorGroupService;
}
run(): Thenable<any> {
run(): Promise<any> {
// Pass focus to viewlet if not open or focused
if (this.otherViewletShowing() || !this.sidebarHasFocus()) {
@@ -160,7 +169,7 @@ export class ShowViewletAction extends Action {
const activeViewlet = this.viewletService.getActiveViewlet();
const activeElement = document.activeElement;
return activeViewlet && activeElement && DOM.isAncestor(activeElement, this.partService.getContainer(Parts.SIDEBAR_PART));
return !!(activeViewlet && activeElement && DOM.isAncestor(activeElement, this.partService.getContainer(Parts.SIDEBAR_PART)));
}
}
@@ -186,7 +195,7 @@ export class CollapseAction extends Action {
// Collapse All action for the new tree
export class CollapseAction2 extends Action {
constructor(tree: AsyncDataTree<any>, enabled: boolean, clazz: string) {
constructor(tree: AsyncDataTree<any, any, any>, enabled: boolean, clazz: string) {
super('workbench.action.collapse', nls.localize('collapse', "Collapse All"), clazz, enabled, () => {
tree.collapseAll();
return Promise.resolve(undefined);

View File

@@ -0,0 +1,287 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import * as nls from 'vs/nls';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions, ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
import { isMacintosh } from 'vs/base/common/platform';
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
// Configuration: Workbench
configurationRegistry.registerConfiguration({
'id': 'workbench',
'order': 7,
'title': nls.localize('workbenchConfigurationTitle', "Workbench"),
'type': 'object',
'properties': {
'workbench.editor.showTabs': {
'type': 'boolean',
'description': nls.localize('showEditorTabs', "Controls whether opened editors should show in tabs or not."),
'default': true
},
'workbench.editor.highlightModifiedTabs': {
'type': 'boolean',
'description': nls.localize('highlightModifiedTabs', "Controls whether a top border is drawn on modified (dirty) editor tabs or not."),
'default': false
},
'workbench.editor.labelFormat': {
'type': 'string',
'enum': ['default', 'short', 'medium', 'long'],
'enumDescriptions': [
nls.localize('workbench.editor.labelFormat.default', "Show the name of the file. When tabs are enabled and two files have the same name in one group the distinguishing sections of each file's path are added. When tabs are disabled, the path relative to the workspace folder is shown if the editor is active."),
nls.localize('workbench.editor.labelFormat.short', "Show the name of the file followed by its directory name."),
nls.localize('workbench.editor.labelFormat.medium', "Show the name of the file followed by its path relative to the workspace folder."),
nls.localize('workbench.editor.labelFormat.long', "Show the name of the file followed by its absolute path.")
],
'default': 'default',
'description': nls.localize({
comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'],
key: 'tabDescription'
}, "Controls the format of the label for an editor."),
},
'workbench.editor.tabCloseButton': {
'type': 'string',
'enum': ['left', 'right', 'off'],
'default': 'right',
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorTabCloseButton' }, "Controls the position of the editor's tabs close buttons, or disables them when set to 'off'.")
},
'workbench.editor.tabSizing': {
'type': 'string',
'enum': ['fit', 'shrink'],
'default': 'fit',
'enumDescriptions': [
nls.localize('workbench.editor.tabSizing.fit', "Always keep tabs large enough to show the full editor label."),
nls.localize('workbench.editor.tabSizing.shrink', "Allow tabs to get smaller when the available space is not enough to show all tabs at once.")
],
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'tabSizing' }, "Controls the sizing of editor tabs.")
},
'workbench.editor.focusRecentEditorAfterClose': {
'type': 'boolean',
'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."),
'default': true
},
'workbench.editor.showIcons': {
'type': 'boolean',
'description': nls.localize('showIcons', "Controls whether opened editors should show with an icon or not. This requires an icon theme to be enabled as well."),
'default': true
},
'workbench.editor.enablePreview': {
'type': 'boolean',
'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing) and show up with an italic font style."),
'default': true
},
'workbench.editor.enablePreviewFromQuickOpen': {
'type': 'boolean',
'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether opened editors from Quick Open show as preview. Preview editors are reused until they are pinned (e.g. via double click or editing)."),
'default': true
},
'workbench.editor.closeOnFileDelete': {
'type': 'boolean',
'description': nls.localize('closeOnFileDelete', "Controls whether editors showing a file that was opened during the session should close automatically when getting deleted or renamed by some other process. Disabling this will keep the editor open on such an event. Note that deleting from within the application will always close the editor and that dirty files will never close to preserve your data."),
'default': false
},
'workbench.editor.openPositioning': {
'type': 'string',
'enum': ['left', 'right', 'first', 'last'],
'default': 'right',
'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'editorOpenPositioning' }, "Controls where editors open. Select `left` or `right` to open editors to the left or right of the currently active one. Select `first` or `last` to open editors independently from the currently active one.")
},
'workbench.editor.openSideBySideDirection': {
'type': 'string',
'enum': ['right', 'down'],
'default': 'right',
'markdownDescription': nls.localize('sideBySideDirection', "Controls the default direction of editors that are opened side by side (e.g. from the explorer). By default, editors will open on the right hand side of the currently active one. If changed to `down`, the editors will open below the currently active one.")
},
'workbench.editor.closeEmptyGroups': {
'type': 'boolean',
'description': nls.localize('closeEmptyGroups', "Controls the behavior of empty editor groups when the last tab in the group is closed. When enabled, empty groups will automatically close. When disabled, empty groups will remain part of the grid."),
'default': true
},
'workbench.editor.revealIfOpen': {
'type': 'boolean',
'description': nls.localize('revealIfOpen', "Controls whether an editor is revealed in any of the visible groups if opened. If disabled, an editor will prefer to open in the currently active editor group. If enabled, an already opened editor will be revealed instead of opened again in the currently active editor group. Note that there are some cases where this setting is ignored, e.g. when forcing an editor to open in a specific group or to the side of the currently active group."),
'default': false
},
'workbench.editor.swipeToNavigate': {
'type': 'boolean',
'description': nls.localize('swipeToNavigate', "Navigate between open files using three-finger swipe horizontally."),
'default': false,
'included': isMacintosh
},
'workbench.editor.restoreViewState': {
'type': 'boolean',
'description': nls.localize('restoreViewState', "Restores the last view state (e.g. scroll position) when re-opening files after they have been closed."),
'default': true,
},
'workbench.editor.centeredLayoutAutoResize': {
'type': 'boolean',
'default': true,
'description': nls.localize('centeredLayoutAutoResize', "Controls if the centered layout should automatically resize to maximum width when more than one group is open. Once only one group is open it will resize back to the original centered width.")
},
'workbench.commandPalette.history': {
'type': 'number',
'description': nls.localize('commandHistory', "Controls the number of recently used commands to keep in history for the command palette. Set to 0 to disable command history."),
'default': 50
},
'workbench.commandPalette.preserveInput': {
'type': 'boolean',
'description': nls.localize('preserveInput', "Controls whether the last typed input to the command palette should be restored when opening it the next time."),
'default': false
},
'workbench.quickOpen.closeOnFocusLost': {
'type': 'boolean',
'description': nls.localize('closeOnFocusLost', "Controls whether Quick Open should close automatically once it loses focus."),
'default': true
},
'workbench.quickOpen.preserveInput': {
'type': 'boolean',
'description': nls.localize('workbench.quickOpen.preserveInput', "Controls whether the last typed input to Quick Open should be restored when opening it the next time."),
'default': false
},
'workbench.settings.openDefaultSettings': {
'type': 'boolean',
'description': nls.localize('openDefaultSettings', "Controls whether opening settings also opens an editor showing all default settings."),
'default': false
},
'workbench.settings.useSplitJSON': {
'type': 'boolean',
'markdownDescription': nls.localize('useSplitJSON', "Controls whether to use the split JSON editor when editing settings as JSON."),
'default': false
},
'workbench.settings.openDefaultKeybindings': {
'type': 'boolean',
'description': nls.localize('openDefaultKeybindings', "Controls whether opening keybinding settings also opens an editor showing all default keybindings."),
'default': true
},
'workbench.sideBar.location': {
'type': 'string',
'enum': ['left', 'right'],
'default': 'left',
'description': nls.localize('sideBarLocation', "Controls the location of the sidebar. It can either show on the left or right of the workbench.")
},
'workbench.panel.defaultLocation': {
'type': 'string',
'enum': ['bottom', 'right'],
'default': 'bottom',
'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom or on the right of the workbench.")
},
'workbench.statusBar.visible': {
'type': 'boolean',
'default': true,
'description': nls.localize('statusBarVisibility', "Controls the visibility of the status bar at the bottom of the workbench.")
},
'workbench.activityBar.visible': {
'type': 'boolean',
'default': true,
'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.")
},
'workbench.view.alwaysShowHeaderActions': {
'type': 'boolean',
'default': false,
'description': nls.localize('viewVisibility', "Controls the visibility of view header actions. View header actions may either be always visible, or only visible when that view is focused or hovered over.")
},
'workbench.fontAliasing': {
'type': 'string',
'enum': ['default', 'antialiased', 'none', 'auto'],
'default': 'default',
'description':
nls.localize('fontAliasing', "Controls font aliasing method in the workbench."),
'enumDescriptions': [
nls.localize('workbench.fontAliasing.default', "Sub-pixel font smoothing. On most non-retina displays this will give the sharpest text."),
nls.localize('workbench.fontAliasing.antialiased', "Smooth the font on the level of the pixel, as opposed to the subpixel. Can make the font appear lighter overall."),
nls.localize('workbench.fontAliasing.none', "Disables font smoothing. Text will show with jagged sharp edges."),
nls.localize('workbench.fontAliasing.auto', "Applies `default` or `antialiased` automatically based on the DPI of displays.")
],
'included': isMacintosh
},
'workbench.settings.enableNaturalLanguageSearch': {
'type': 'boolean',
'description': nls.localize('enableNaturalLanguageSettingsSearch', "Controls whether to enable the natural language search mode for settings. The natural language search is provided by a Microsoft online service."),
'default': true,
'scope': ConfigurationScope.WINDOW,
'tags': ['usesOnlineServices']
},
'workbench.settings.settingsSearchTocBehavior': {
'type': 'string',
'enum': ['hide', 'filter'],
'enumDescriptions': [
nls.localize('settingsSearchTocBehavior.hide', "Hide the Table of Contents while searching."),
nls.localize('settingsSearchTocBehavior.filter', "Filter the Table of Contents to just categories that have matching settings. Clicking a category will filter the results to that category."),
],
'description': nls.localize('settingsSearchTocBehavior', "Controls the behavior of the settings editor Table of Contents while searching."),
'default': 'filter',
'scope': ConfigurationScope.WINDOW
},
'workbench.settings.editor': {
'type': 'string',
'enum': ['ui', 'json'],
'enumDescriptions': [
nls.localize('settings.editor.ui', "Use the settings UI editor."),
nls.localize('settings.editor.json', "Use the JSON file editor."),
],
'description': nls.localize('settings.editor.desc', "Determines which settings editor to use by default."),
'default': 'ui',
'scope': ConfigurationScope.WINDOW
},
'workbench.enableExperiments': {
'type': 'boolean',
'description': nls.localize('workbench.enableExperiments', "Fetches experiments to run from a Microsoft online service."),
'default': true,
'tags': ['usesOnlineServices']
},
'workbench.useExperimentalGridLayout': {
'type': 'boolean',
'description': nls.localize('workbench.useExperimentalGridLayout', "Enables the grid layout for the workbench. This setting may enable additional layout options for workbench components."),
'default': false,
'scope': ConfigurationScope.APPLICATION
}
}
});
// Configuration: Zen Mode
configurationRegistry.registerConfiguration({
'id': 'zenMode',
'order': 9,
'title': nls.localize('zenModeConfigurationTitle', "Zen Mode"),
'type': 'object',
'properties': {
'zenMode.fullScreen': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.fullScreen', "Controls whether turning on Zen Mode also puts the workbench into full screen mode.")
},
'zenMode.centerLayout': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.centerLayout', "Controls whether turning on Zen Mode also centers the layout.")
},
'zenMode.hideTabs': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideTabs', "Controls whether turning on Zen Mode also hides workbench tabs.")
},
'zenMode.hideStatusBar': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideStatusBar', "Controls whether turning on Zen Mode also hides the status bar at the bottom of the workbench.")
},
'zenMode.hideActivityBar': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideActivityBar', "Controls whether turning on Zen Mode also hides the activity bar at the left of the workbench.")
},
'zenMode.hideLineNumbers': {
'type': 'boolean',
'default': true,
'description': nls.localize('zenMode.hideLineNumbers', "Controls whether turning on Zen Mode also hides the editor line numbers.")
},
'zenMode.restore': {
'type': 'boolean',
'default': false,
'description': nls.localize('zenMode.restore', "Controls whether a window should restore to zen mode if it was exited in zen mode.")
}
}
});