Merge from vscode 52dcb723a39ae75bee1bd56b3312d7fcdc87aeed (#6719)

This commit is contained in:
Anthony Dresser
2019-08-12 21:31:51 -07:00
committed by GitHub
parent 00250839fc
commit 7eba8c4c03
616 changed files with 9472 additions and 7087 deletions

View File

@@ -156,7 +156,7 @@ export interface IActionBarRegistry {
class ActionBarRegistry implements IActionBarRegistry {
private readonly actionBarContributorConstructors: { scope: string; ctor: IConstructorSignature0<ActionBarContributor>; }[] = [];
private readonly actionBarContributorInstances: Map<string, ActionBarContributor[]> = new Map();
private instantiationService: IInstantiationService;
private instantiationService!: IInstantiationService;
start(accessor: ServicesAccessor): void {
this.instantiationService = accessor.get(IInstantiationService);

View File

@@ -3,6 +3,8 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/screencast';
import { Action } from 'vs/base/common/actions';
import { IWindowService } from 'vs/platform/windows/common/windows';
import * as nls from 'vs/nls';
@@ -11,6 +13,7 @@ import { domEvent } from 'vs/base/browser/event';
import { Event } from 'vs/base/common/event';
import { IDisposable, toDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { getDomNodePagePosition, createStyleSheet, createCSSRule, append, $ } from 'vs/base/browser/dom';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { Context } from 'vs/platform/contextkey/browser/contextKeyService';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -20,6 +23,9 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { clamp } from 'vs/base/common/numbers';
import { KeyCode } from 'vs/base/common/keyCodes';
import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry';
export class InspectContextKeysAction extends Action {
@@ -96,7 +102,8 @@ export class ToggleScreencastModeAction extends Action {
id: string,
label: string,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
}
@@ -108,26 +115,17 @@ export class ToggleScreencastModeAction extends Action {
return;
}
const container = this.layoutService.getWorkbenchElement();
const disposables = new DisposableStore();
const mouseMarker = append(container, $('div'));
mouseMarker.style.position = 'absolute';
mouseMarker.style.border = '2px solid red';
mouseMarker.style.borderRadius = '20px';
mouseMarker.style.width = '20px';
mouseMarker.style.height = '20px';
mouseMarker.style.top = '0';
mouseMarker.style.left = '0';
mouseMarker.style.zIndex = '100000';
mouseMarker.style.content = ' ';
mouseMarker.style.pointerEvents = 'none';
mouseMarker.style.display = 'none';
const container = this.layoutService.getWorkbenchElement();
const mouseMarker = append(container, $('.screencast-mouse'));
disposables.add(toDisposable(() => mouseMarker.remove()));
const onMouseDown = domEvent(container, 'mousedown', true);
const onMouseUp = domEvent(container, 'mouseup', true);
const onMouseMove = domEvent(container, 'mousemove', true);
const mouseListener = onMouseDown(e => {
disposables.add(onMouseDown(e => {
mouseMarker.style.top = `${e.clientY - 10}px`;
mouseMarker.style.left = `${e.clientX - 10}px`;
mouseMarker.style.display = 'block';
@@ -141,56 +139,59 @@ export class ToggleScreencastModeAction extends Action {
mouseMarker.style.display = 'none';
mouseMoveListener.dispose();
});
});
}));
const keyboardMarker = append(container, $('div'));
keyboardMarker.style.position = 'absolute';
keyboardMarker.style.backgroundColor = 'rgba(0, 0, 0 ,0.5)';
keyboardMarker.style.width = '100%';
keyboardMarker.style.height = '100px';
keyboardMarker.style.bottom = '20%';
keyboardMarker.style.left = '0';
keyboardMarker.style.zIndex = '100000';
keyboardMarker.style.pointerEvents = 'none';
keyboardMarker.style.color = 'white';
keyboardMarker.style.lineHeight = '100px';
keyboardMarker.style.textAlign = 'center';
keyboardMarker.style.fontSize = '56px';
keyboardMarker.style.display = 'none';
const keyboardMarker = append(container, $('.screencast-keyboard'));
disposables.add(toDisposable(() => keyboardMarker.remove()));
const updateKeyboardMarker = () => {
keyboardMarker.style.bottom = `${clamp(this.configurationService.getValue<number>('screencastMode.verticalOffset') || 0, 0, 90)}%`;
};
updateKeyboardMarker();
disposables.add(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('screencastMode.verticalOffset')) {
updateKeyboardMarker();
}
}));
const onKeyDown = domEvent(container, 'keydown', true);
let keyboardTimeout: IDisposable = Disposable.None;
let length = 0;
const keyboardListener = onKeyDown(e => {
disposables.add(onKeyDown(e => {
keyboardTimeout.dispose();
const event = new StandardKeyboardEvent(e);
const keybinding = this.keybindingService.resolveKeyboardEvent(event);
const label = keybinding.getLabel();
const shortcut = this.keybindingService.softDispatch(event, event.target);
if (!event.ctrlKey && !event.altKey && !event.metaKey && !event.shiftKey && this.keybindingService.mightProducePrintableCharacter(event) && label) {
keyboardMarker.textContent += ' ' + label;
} else {
keyboardMarker.textContent = label;
if (shortcut || !this.configurationService.getValue<boolean>('screencastMode.onlyKeyboardShortcuts')) {
if (
event.ctrlKey || event.altKey || event.metaKey || event.shiftKey
|| length > 20
|| event.keyCode === KeyCode.Backspace || event.keyCode === KeyCode.Escape
) {
keyboardMarker.innerHTML = '';
length = 0;
}
const keybinding = this.keybindingService.resolveKeyboardEvent(event);
const label = keybinding.getLabel();
const key = $('span.key', {}, label || '');
length++;
append(keyboardMarker, key);
}
keyboardMarker.style.display = 'block';
const promise = timeout(800);
keyboardTimeout = toDisposable(() => promise.cancel());
promise.then(() => {
keyboardMarker.textContent = '';
keyboardMarker.style.display = 'none';
length = 0;
});
});
}));
ToggleScreencastModeAction.disposable = toDisposable(() => {
mouseListener.dispose();
keyboardListener.dispose();
mouseMarker.remove();
keyboardMarker.remove();
});
ToggleScreencastModeAction.disposable = disposables;
}
}
@@ -215,8 +216,35 @@ export class LogStorageAction extends Action {
}
}
// --- Actions Registration
const developerCategory = nls.localize('developer', "Developer");
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
registry.registerWorkbenchAction(new SyncActionDescriptor(InspectContextKeysAction, InspectContextKeysAction.ID, InspectContextKeysAction.LABEL), 'Developer: Inspect Context Keys', developerCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleScreencastModeAction, ToggleScreencastModeAction.ID, ToggleScreencastModeAction.LABEL), 'Developer: Toggle Screencast Mode', developerCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory);
registry.registerWorkbenchAction(new SyncActionDescriptor(LogStorageAction, LogStorageAction.ID, LogStorageAction.LABEL), 'Developer: Log Storage Database Contents', developerCategory);
// --- Menu Registration
// Screencast Mode
const configurationRegistry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Configuration);
configurationRegistry.registerConfiguration({
id: 'screencastMode',
order: 9,
title: nls.localize('screencastModeConfigurationTitle', "Screencast Mode"),
type: 'object',
properties: {
'screencastMode.verticalOffset': {
type: 'number',
default: 20,
minimum: 0,
maximum: 90,
description: nls.localize('screencastMode.location.verticalPosition', "Controls the vertical offset of the screencast mode overlay from the bottom as a percentage of the workbench height.")
},
'screencastMode.onlyKeyboardShortcuts': {
type: 'boolean',
description: nls.localize('screencastMode.onlyKeyboardShortcuts', "Only show keyboard shortcuts in Screencast Mode."),
default: false
}
}
});

View File

@@ -320,6 +320,38 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.focusParent',
weight: KeybindingWeight.WorkbenchContrib,
when: WorkbenchListFocusContextKey,
handler: (accessor) => {
const focused = accessor.get(IListService).lastFocusedList;
if (!focused || focused instanceof List || focused instanceof PagedList) {
return;
}
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];
const parent = tree.getParentElement(focus);
if (parent) {
const fakeKeyboardEvent = new KeyboardEvent('keydown');
tree.setFocus([parent], fakeKeyboardEvent);
tree.reveal(parent);
}
} else {
const tree = focused;
tree.focusParent({ origin: 'keyboard' });
}
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: 'list.expand',
weight: KeybindingWeight.WorkbenchContrib,
@@ -749,11 +781,8 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
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([]);
}
list.setSelection([]);
list.setFocus([]);
}
// ObjectTree
@@ -761,22 +790,16 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
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);
}
list.setSelection([], fakeKeyboardEvent);
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' });
}
tree.clearSelection({ origin: 'keyboard' });
tree.clearFocus({ origin: 'keyboard' });
}
}
});

View File

@@ -0,0 +1,50 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .screencast-mouse {
position: absolute;
border: 2px solid red;
border-radius: 20px;
width: 20px;
height: 20px;
top: 0;
left: 0;
z-index: 100000;
content: ' ';
pointer-events: none;
display: none;
}
.monaco-workbench .screencast-keyboard {
position: absolute;
background-color: rgba(0, 0, 0 ,0.5);
width: 100%;
height: 100px;
bottom: 20%;
left: 0;
z-index: 100000;
pointer-events: none;
color: #eee;
line-height: 100px;
text-align: center;
font-size: 56px;
transition: opacity 0.3s ease-out;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-workbench .screencast-keyboard:empty {
opacity: 0;
}
.monaco-workbench .screencast-keyboard > .key {
padding: 0 8px;
box-shadow: inset 0 -3px 0 hsla(0,0%,73%,.4);
margin-right: 6px;
border: 1px solid hsla(0,0%,80%,.4);
border-radius: 5px;
background-color: rgba(255, 255, 255, 0.05);
}

View File

@@ -7,11 +7,11 @@ import 'vs/css!./media/actions';
import * as nls from 'vs/nls';
import { Action } from 'vs/base/common/actions';
import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows';
import { IWindowService, IURIToOpen, IWindowsService } from 'vs/platform/windows/common/windows';
import { SyncActionDescriptor, MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { Registry } from 'vs/platform/registry/common/platform';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { IsFullscreenContext, IsDevelopmentContext } from 'vs/workbench/browser/contextkeys';
import { IsFullscreenContext, IsDevelopmentContext, IsMacNativeContext } from 'vs/workbench/browser/contextkeys';
import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -226,6 +226,24 @@ export class ReloadWindowAction extends Action {
}
}
export class ShowAboutDialogAction extends Action {
static readonly ID = 'workbench.action.showAboutDialog';
static readonly LABEL = nls.localize('about', "About");
constructor(
id: string,
label: string,
@IWindowsService private readonly windowsService: IWindowsService
) {
super(id, label);
}
run(): Promise<void> {
return this.windowsService.openAboutDialog();
}
}
const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
// --- Actions Registration
@@ -240,6 +258,9 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleFullScreenAction
const developerCategory = nls.localize('developer', "Developer");
registry.registerWorkbenchAction(new SyncActionDescriptor(ReloadWindowAction, ReloadWindowAction.ID, ReloadWindowAction.LABEL), 'Developer: Reload Window', developerCategory);
const helpCategory = nls.localize('help', "Help");
registry.registerWorkbenchAction(new SyncActionDescriptor(ShowAboutDialogAction, ShowAboutDialogAction.ID, ShowAboutDialogAction.LABEL), `Help: About`, helpCategory);
// --- Commands/Keybindings Registration
const recentFilesPickerContext = ContextKeyExpr.and(inQuickOpenContext, ContextKeyExpr.has(inRecentFilesPickerContextKey));
@@ -297,4 +318,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, {
toggled: IsFullscreenContext
},
order: 1
});
});
MenuRegistry.appendMenuItem(MenuId.MenubarHelpMenu, {
group: 'z_about',
command: {
id: ShowAboutDialogAction.ID,
title: nls.localize({ key: 'miAbout', comment: ['&& denotes a mnemonic'] }, "&&About")
},
order: 1,
when: IsMacNativeContext.toNegated()
});

View File

@@ -11,7 +11,7 @@ import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/p
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { IWorkspacesService } from 'vs/platform/workspaces/common/workspaces';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { ICommandService, ICommandHandler } from 'vs/platform/commands/common/commands';
import { ICommandService, ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands';
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -20,6 +20,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { ITextFileService, ISaveOptions } from 'vs/workbench/services/textfile/common/textfiles';
import { toResource } from 'vs/workbench/common/editor';
import { URI } from 'vs/base/common/uri';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { WorkbenchStateContext } from 'vs/workbench/browser/contextkeys';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class OpenFileAction extends Action {
@@ -305,3 +308,19 @@ export class DuplicateWorkspaceInNewWindowAction extends Action {
return this.windowService.openWindow([{ workspaceUri: newWorkspace.configPath }], { forceNewWindow: true });
}
}
// --- Menu Registration
const workspacesCategory = nls.localize('workspaces', "Workspaces");
CommandsRegistry.registerCommand(OpenWorkspaceConfigFileAction.ID, serviceAccessor => {
serviceAccessor.get(IInstantiationService).createInstance(OpenWorkspaceConfigFileAction, OpenWorkspaceConfigFileAction.ID, OpenWorkspaceConfigFileAction.LABEL).run();
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: OpenWorkspaceConfigFileAction.ID,
title: { value: `${workspacesCategory}: ${OpenWorkspaceConfigFileAction.LABEL}`, original: 'Workspaces: Open Workspace Configuration File' },
},
when: WorkbenchStateContext.isEqualTo('workspace')
});

View File

@@ -35,7 +35,7 @@ export abstract class Composite extends Component implements IComposite {
private readonly _onDidChangeVisibility: Emitter<boolean> = this._register(new Emitter<boolean>());
readonly onDidChangeVisibility: Event<boolean> = this._onDidChangeVisibility.event;
private _onDidFocus: Emitter<void>;
private _onDidFocus!: Emitter<void>;
get onDidFocus(): Event<void> {
if (!this._onDidFocus) {
this.registerFocusTrackEvents();
@@ -50,7 +50,7 @@ export abstract class Composite extends Component implements IComposite {
}
}
private _onDidBlur: Emitter<void>;
private _onDidBlur!: Emitter<void>;
get onDidBlur(): Event<void> {
if (!this._onDidBlur) {
this.registerFocusTrackEvents();
@@ -68,10 +68,10 @@ export abstract class Composite extends Component implements IComposite {
this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire()));
}
protected actionRunner: IActionRunner;
protected actionRunner: IActionRunner | undefined;
private visible: boolean;
private parent: HTMLElement;
private parent!: HTMLElement;
constructor(
id: string,

View File

@@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys';
import { IWindowsConfiguration } from 'vs/platform/windows/common/windows';
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor';
import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext, ActiveEditorGroupIndexContext, ActiveEditorGroupLastContext } from 'vs/workbench/common/editor';
import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
@@ -52,17 +52,20 @@ export class WorkbenchContextKeysHandler extends Disposable {
private inputFocusedContext: IContextKey<boolean>;
private activeEditorContext: IContextKey<string | null>;
private activeEditorGroupEmpty: IContextKey<boolean>;
private activeEditorGroupIndex: IContextKey<number>;
private activeEditorGroupLast: IContextKey<boolean>;
private multipleEditorGroupsContext: IContextKey<boolean>;
private editorsVisibleContext: IContextKey<boolean>;
private textCompareEditorVisibleContext: IContextKey<boolean>;
private textCompareEditorActiveContext: IContextKey<boolean>;
private activeEditorGroupEmpty: IContextKey<boolean>;
private multipleEditorGroupsContext: IContextKey<boolean>;
private splitEditorsVerticallyContext: IContextKey<boolean>;
private workbenchStateContext: IContextKey<string>;
private workspaceFolderCountContext: IContextKey<number>;
private inZenModeContext: IContextKey<boolean>;
private isFullscreenContext: IContextKey<boolean>;
private isCenteredLayoutContext: IContextKey<boolean>;
@@ -90,8 +93,10 @@ export class WorkbenchContextKeysHandler extends Disposable {
this._register(this.editorService.onDidActiveEditorChange(() => this.updateEditorContextKeys()));
this._register(this.editorService.onDidVisibleEditorsChange(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidAddGroup(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidRemoveGroup(() => this.updateEditorContextKeys()));
this._register(this.editorGroupService.onDidGroupIndexChange(() => this.updateEditorContextKeys()));
this._register(addDisposableListener(window, EventType.FOCUS_IN, () => this.updateInputContextKeys(), true));
@@ -141,6 +146,8 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.textCompareEditorVisibleContext = TextCompareEditorVisibleContext.bindTo(this.contextKeyService);
this.textCompareEditorActiveContext = TextCompareEditorActiveContext.bindTo(this.contextKeyService);
this.activeEditorGroupEmpty = ActiveEditorGroupEmptyContext.bindTo(this.contextKeyService);
this.activeEditorGroupIndex = ActiveEditorGroupIndexContext.bindTo(this.contextKeyService);
this.activeEditorGroupLast = ActiveEditorGroupLastContext.bindTo(this.contextKeyService);
this.multipleEditorGroupsContext = MultipleEditorGroupsContext.bindTo(this.contextKeyService);
// Inputs
@@ -176,6 +183,7 @@ export class WorkbenchContextKeysHandler extends Disposable {
}
private updateEditorContextKeys(): void {
const activeGroup = this.editorGroupService.activeGroup;
const activeControl = this.editorService.activeControl;
const visibleEditors = this.editorService.visibleControls;
@@ -194,12 +202,16 @@ export class WorkbenchContextKeysHandler extends Disposable {
this.activeEditorGroupEmpty.reset();
}
if (this.editorGroupService.count > 1) {
const groupCount = this.editorGroupService.count;
if (groupCount > 1) {
this.multipleEditorGroupsContext.set(true);
} else {
this.multipleEditorGroupsContext.reset();
}
this.activeEditorGroupIndex.set(activeGroup.index);
this.activeEditorGroupLast.set(activeGroup.index === groupCount - 1);
if (activeControl) {
this.activeEditorContext.set(activeControl.getId());
} else {

View File

@@ -27,13 +27,15 @@ import { IWindowService, MenuBarVisibility, getTitleBarStyle } from 'vs/platform
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { Sizing, Direction, Grid, SerializableGrid, ISerializableView, ISerializedGrid, GridBranchNode, GridLeafNode, isGridBranchNode } from 'vs/base/browser/ui/grid/grid';
import { Grid, SerializableGrid, ISerializableView, ISerializedGrid, Orientation, ISerializedNode, ISerializedLeafNode, Direction } from 'vs/base/browser/ui/grid/grid';
import { WorkbenchLegacyLayout } from 'vs/workbench/browser/legacyLayout';
import { IDimension } from 'vs/platform/layout/browser/layoutService';
import { Part } from 'vs/workbench/browser/part';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { IFileService } from 'vs/platform/files/common/files';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { coalesce } from 'vs/base/common/arrays';
enum Settings {
MENUBAR_VISIBLE = 'window.menuBarVisibility',
@@ -44,25 +46,36 @@ enum Settings {
PANEL_POSITION = 'workbench.panel.defaultLocation',
ZEN_MODE_RESTORE = 'zenMode.restore',
}
enum Storage {
SIDEBAR_HIDDEN = 'workbench.sidebar.hidden',
SIDEBAR_SIZE = 'workbench.sidebar.size',
PANEL_HIDDEN = 'workbench.panel.hidden',
PANEL_POSITION = 'workbench.panel.location',
PANEL_SIZE = 'workbench.panel.size',
PANEL_SIZE_BEFORE_MAXIMIZED = 'workbench.panel.sizeBeforeMaximized',
ZEN_MODE_ENABLED = 'workbench.zenmode.active',
CENTERED_LAYOUT_ENABLED = 'workbench.centerededitorlayout.active',
GRID_LAYOUT = 'workbench.grid.layout'
GRID_LAYOUT = 'workbench.grid.layout',
GRID_WIDTH = 'workbench.grid.width',
GRID_HEIGHT = 'workbench.grid.height'
}
enum Classes {
SIDEBAR_HIDDEN = 'nosidebar',
EDITOR_HIDDEN = 'noeditorarea',
PANEL_HIDDEN = 'nopanel',
STATUSBAR_HIDDEN = 'nostatusbar',
FULLSCREEN = 'fullscreen'
}
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private readonly _onTitleBarVisibilityChange: Emitter<void> = this._register(new Emitter<void>());
readonly onTitleBarVisibilityChange: Event<void> = this._onTitleBarVisibilityChange.event;
@@ -232,6 +245,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (this.state.fullscreen && (this.state.menuBar.visibility === 'toggle' || this.state.menuBar.visibility === 'default')) {
this._onTitleBarVisibilityChange.fire();
if (this.workbenchGrid instanceof SerializableGrid) {
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
}
this.layout();
}
}
@@ -242,9 +260,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Apply as CSS class
if (this.state.fullscreen) {
addClass(this.container, 'fullscreen');
addClass(this.container, Classes.FULLSCREEN);
} else {
removeClass(this.container, 'fullscreen');
removeClass(this.container, Classes.FULLSCREEN);
if (this.state.zenMode.transitionedToFullScreen && this.state.zenMode.active) {
this.toggleZenMode();
@@ -254,6 +272,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Changing fullscreen state of the window has an impact on custom title bar visibility, so we need to update
if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
this._onTitleBarVisibilityChange.fire();
if (this.workbenchGrid instanceof SerializableGrid) {
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
}
this.layout(); // handle title bar when fullscreen changes
}
@@ -297,11 +320,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const activityBar = this.getPart(Parts.ACTIVITYBAR_PART);
const sideBar = this.getPart(Parts.SIDEBAR_PART);
const wasHidden = this.state.sideBar.hidden;
if (this.state.sideBar.hidden) {
this.setSideBarHidden(false, true /* Skip Layout */);
}
const newPositionValue = (position === Position.LEFT) ? 'left' : 'right';
const oldPositionValue = (this.state.sideBar.position === Position.LEFT) ? 'left' : 'right';
this.state.sideBar.position = position;
@@ -322,11 +340,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.sideBar.width = this.workbenchGrid.getViewSize(this.sideBarPartView).width;
}
this.workbenchGrid.removeView(this.sideBarPartView);
this.workbenchGrid.removeView(this.activityBarPartView);
if (!this.state.panel.hidden && this.state.panel.position === Position.BOTTOM) {
this.workbenchGrid.removeView(this.panelPartView);
if (position === Position.LEFT) {
this.workbenchGrid.moveViewTo(this.activityBarPartView, [1, 0]);
this.workbenchGrid.moveViewTo(this.sideBarPartView, [1, 1]);
} else {
this.workbenchGrid.moveViewTo(this.sideBarPartView, [1, 4]);
this.workbenchGrid.moveViewTo(this.activityBarPartView, [1, 4]);
}
this.layout();
@@ -578,7 +597,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.zenMode.active = !this.state.zenMode.active;
this.state.zenMode.transitionDisposables.clear();
const setLineNumbers = (lineNumbers: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => editor.updateOptions({ lineNumbers }));
const setLineNumbers = (lineNumbers?: any) => this.editorService.visibleTextEditorWidgets.forEach(editor => {
// To properly reset line numbers we need to read the configuration for each editor respecting it's uri.
if (!lineNumbers && isCodeEditor(editor) && editor.hasModel()) {
const model = editor.getModel();
this.configurationService.getValue('editor.lineNumbers', { resource: model.uri });
} else {
editor.updateOptions({ lineNumbers });
}
});
// Check if zen mode transitioned to full screen and if now we are out of zen mode
// -> we need to go out of full screen (same goes for the centered editor layout)
@@ -641,7 +668,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.centerEditorLayout(false, true);
}
setLineNumbers(this.configurationService.getValue('editor.lineNumbers'));
setLineNumbers();
// Status bar and activity bar visibility come from settings -> update their visibility.
this.doUpdateLayoutConfiguration(true);
@@ -684,16 +711,19 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Adjust CSS
if (hidden) {
addClass(this.container, 'nostatusbar');
addClass(this.container, Classes.STATUSBAR_HIDDEN);
} else {
removeClass(this.container, 'nostatusbar');
removeClass(this.container, Classes.STATUSBAR_HIDDEN);
}
// Propagate to grid
if (this.workbenchGrid instanceof Grid) {
this.workbenchGrid.setViewVisible(this.statusBarPartView, !hidden);
}
// Layout
if (!skipLayout) {
if (this.workbenchGrid instanceof Grid) {
this.layout();
} else {
if (!(this.workbenchGrid instanceof Grid)) {
this.workbenchGrid.layout();
}
}
@@ -717,64 +747,21 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.panelPartView = panelPart;
this.statusBarPartView = statusBar;
let workbenchGrid: SerializableGrid<ISerializableView> | undefined;
const viewMap = {
[Parts.ACTIVITYBAR_PART]: this.activityBarPartView,
[Parts.TITLEBAR_PART]: this.titleBarPartView,
[Parts.EDITOR_PART]: this.editorPartView,
[Parts.PANEL_PART]: this.panelPartView,
[Parts.SIDEBAR_PART]: this.sideBarPartView,
[Parts.STATUSBAR_PART]: this.statusBarPartView
};
const savedGrid = this.storageService.get(Storage.GRID_LAYOUT, StorageScope.GLOBAL, undefined);
if (savedGrid) {
const parsedGrid: ISerializedGrid = JSON.parse(savedGrid);
const fromJSON = (serializedPart: { type: Parts } | null) => {
if (serializedPart && serializedPart.type) {
switch (serializedPart.type) {
case Parts.ACTIVITYBAR_PART:
return this.activityBarPartView;
case Parts.TITLEBAR_PART:
return this.titleBarPartView;
case Parts.EDITOR_PART:
return this.editorPartView;
case Parts.PANEL_PART:
return this.panelPartView;
case Parts.SIDEBAR_PART:
return this.sideBarPartView;
case Parts.STATUSBAR_PART:
return this.statusBarPartView;
default:
return this.editorPartView;
}
} else {
return this.editorPartView;
}
};
try {
workbenchGrid = SerializableGrid.deserialize(parsedGrid, { fromJSON }, { proportionalLayout: false });
const root = workbenchGrid.getViews();
const titleBarSection = root.children[0];
if (isGridBranchNode(titleBarSection) || titleBarSection.view !== this.titleBarPartView) {
throw new Error('Bad grid');
}
const middleSection = root.children[1] as GridBranchNode<ISerializableView>;
const sideBarPosition = (middleSection.children[0] as GridLeafNode<ISerializableView>).view === this.activityBarPartView ? Position.LEFT : Position.RIGHT;
if (sideBarPosition !== this.state.sideBar.position) {
throw new Error('Bad Grid');
}
const panelPosition = isGridBranchNode(middleSection.children[2]) || isGridBranchNode(middleSection.children[0]) ? Position.BOTTOM : Position.RIGHT;
if (panelPosition !== this.state.panel.position) {
throw new Error('Bad Grid');
}
} catch (err) {
workbenchGrid = undefined;
console.error(err);
}
}
if (!workbenchGrid) {
workbenchGrid = new SerializableGrid(this.editorPartView, { proportionalLayout: false });
}
const fromJSON = ({ type }: { type: Parts }) => viewMap[type];
const workbenchGrid = SerializableGrid.deserialize(
this.createGridDescriptor(),
{ fromJSON },
{ proportionalLayout: false }
);
this.container.prepend(workbenchGrid.element);
this.workbenchGrid = workbenchGrid;
@@ -791,15 +778,24 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.setEditorHidden(!visible, true);
}));
this._register(this.lifecycleService.onBeforeShutdown(beforeShutdownEvent => {
beforeShutdownEvent.veto(new Promise((resolve) => {
const grid = this.workbenchGrid as SerializableGrid<ISerializableView>;
const serializedGrid = grid.serialize();
this._register(this.storageService.onWillSaveState(() => {
const grid = this.workbenchGrid as SerializableGrid<ISerializableView>;
this.storageService.store(Storage.GRID_LAYOUT, JSON.stringify(serializedGrid), StorageScope.GLOBAL);
const sideBarSize = this.state.sideBar.hidden
? grid.getViewCachedVisibleSize(this.sideBarPartView)
: grid.getViewSize(this.sideBarPartView).width;
resolve();
}));
this.storageService.store(Storage.SIDEBAR_SIZE, sideBarSize, StorageScope.GLOBAL);
const panelSize = this.state.panel.hidden
? grid.getViewCachedVisibleSize(this.panelPartView)
: (this.state.panel.position === Position.BOTTOM ? grid.getViewSize(this.panelPartView).height : grid.getViewSize(this.panelPartView).width);
this.storageService.store(Storage.PANEL_SIZE, panelSize, StorageScope.GLOBAL);
const gridSize = grid.getViewSize();
this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL);
this.storageService.store(Storage.GRID_HEIGHT, gridSize.height, StorageScope.GLOBAL);
}));
} else {
this.workbenchGrid = instantiationService.createInstance(
@@ -828,9 +824,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Layout the grid widget
this.workbenchGrid.layout(this._dimension.width, this._dimension.height);
// Layout grid views
this.layoutGrid();
} else {
this.workbenchGrid.layout(options);
}
@@ -840,95 +833,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
private layoutGrid(): void {
if (!(this.workbenchGrid instanceof Grid)) {
return;
}
let panelInGrid = this.workbenchGrid.hasView(this.panelPartView);
let sidebarInGrid = this.workbenchGrid.hasView(this.sideBarPartView);
let activityBarInGrid = this.workbenchGrid.hasView(this.activityBarPartView);
let statusBarInGrid = this.workbenchGrid.hasView(this.statusBarPartView);
let titlebarInGrid = this.workbenchGrid.hasView(this.titleBarPartView);
// Add parts to grid
if (!statusBarInGrid) {
this.workbenchGrid.addView(this.statusBarPartView, Sizing.Split, this.editorPartView, Direction.Down);
statusBarInGrid = true;
}
if (!titlebarInGrid) {
this.workbenchGrid.addView(this.titleBarPartView, Sizing.Split, this.editorPartView, Direction.Up);
titlebarInGrid = true;
}
if (!activityBarInGrid) {
this.workbenchGrid.addView(this.activityBarPartView, Sizing.Split, panelInGrid && this.state.sideBar.position === this.state.panel.position ? this.panelPartView : this.editorPartView, this.state.sideBar.position === Position.RIGHT ? Direction.Right : Direction.Left);
activityBarInGrid = true;
}
if (!sidebarInGrid) {
this.workbenchGrid.addView(this.sideBarPartView, this.state.sideBar.width !== undefined ? this.state.sideBar.width : Sizing.Split, this.activityBarPartView, this.state.sideBar.position === Position.LEFT ? Direction.Right : Direction.Left);
sidebarInGrid = true;
}
if (!panelInGrid) {
this.workbenchGrid.addView(this.panelPartView, Sizing.Split, this.editorPartView, this.state.panel.position === Position.BOTTOM ? Direction.Down : Direction.Right);
panelInGrid = true;
}
// Hide parts
if (this.state.panel.hidden) {
this.workbenchGrid.setViewVisible(this.panelPartView, false);
}
if (this.state.statusBar.hidden) {
this.workbenchGrid.setViewVisible(this.statusBarPartView, false);
}
if (titlebarInGrid && !this.isVisible(Parts.TITLEBAR_PART)) {
this.workbenchGrid.setViewVisible(this.titleBarPartView, false);
}
if (this.state.activityBar.hidden) {
this.workbenchGrid.setViewVisible(this.activityBarPartView, false);
}
if (this.state.sideBar.hidden) {
this.workbenchGrid.setViewVisible(this.sideBarPartView, false);
}
if (this.state.editor.hidden) {
this.workbenchGrid.setViewVisible(this.editorPartView, false);
}
// Show visible parts
if (!this.state.editor.hidden) {
this.workbenchGrid.setViewVisible(this.editorPartView, true);
}
if (!this.state.statusBar.hidden) {
this.workbenchGrid.setViewVisible(this.statusBarPartView, true);
}
if (this.isVisible(Parts.TITLEBAR_PART)) {
this.workbenchGrid.setViewVisible(this.titleBarPartView, true);
}
if (!this.state.activityBar.hidden) {
this.workbenchGrid.setViewVisible(this.activityBarPartView, true);
}
if (!this.state.sideBar.hidden) {
this.workbenchGrid.setViewVisible(this.sideBarPartView, true);
}
if (!this.state.panel.hidden) {
this.workbenchGrid.setViewVisible(this.panelPartView, true);
}
}
isEditorLayoutCentered(): boolean {
return this.state.editor.centered;
}
@@ -1019,41 +923,60 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
setActivityBarHidden(hidden: boolean, skipLayout?: boolean): void {
this.state.activityBar.hidden = hidden;
// Propagate to grid
if (this.workbenchGrid instanceof Grid) {
this.workbenchGrid.setViewVisible(this.activityBarPartView, !hidden);
}
// Layout
if (!skipLayout) {
if (this.workbenchGrid instanceof Grid) {
this.layout();
} else {
if (!(this.workbenchGrid instanceof Grid)) {
this.workbenchGrid.layout();
}
}
}
setEditorHidden(hidden: boolean, skipLayout?: boolean): void {
if (!(this.workbenchGrid instanceof Grid) || hidden === this.state.editor.hidden) {
if (!(this.workbenchGrid instanceof Grid)) {
return;
}
this.state.editor.hidden = hidden;
// The editor and the panel cannot be hidden at the same time
if (this.state.editor.hidden && this.state.panel.hidden) {
this.setPanelHidden(false, true);
// Adjust CSS
if (hidden) {
addClass(this.container, Classes.EDITOR_HIDDEN);
} else {
removeClass(this.container, Classes.EDITOR_HIDDEN);
}
if (!skipLayout) {
this.layout();
// Propagate to grid
this.workbenchGrid.setViewVisible(this.editorPartView, !hidden);
// The editor and panel cannot be hidden at the same time
if (hidden && this.state.panel.hidden) {
this.setPanelHidden(false, true);
}
}
getLayoutClasses(): string[] {
return coalesce([
this.state.sideBar.hidden ? Classes.SIDEBAR_HIDDEN : undefined,
this.state.editor.hidden ? Classes.EDITOR_HIDDEN : undefined,
this.state.panel.hidden ? Classes.PANEL_HIDDEN : undefined,
this.state.statusBar.hidden ? Classes.STATUSBAR_HIDDEN : undefined,
this.state.fullscreen ? Classes.FULLSCREEN : undefined
]);
}
setSideBarHidden(hidden: boolean, skipLayout?: boolean): void {
this.state.sideBar.hidden = hidden;
// Adjust CSS
if (hidden) {
addClass(this.container, 'nosidebar');
addClass(this.container, Classes.SIDEBAR_HIDDEN);
} else {
removeClass(this.container, 'nosidebar');
removeClass(this.container, Classes.SIDEBAR_HIDDEN);
}
// If sidebar becomes hidden, also hide the current active Viewlet if any
@@ -1080,6 +1003,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
// Propagate to grid
if (this.workbenchGrid instanceof Grid) {
this.workbenchGrid.setViewVisible(this.sideBarPartView, !hidden);
}
// Remember in settings
const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
if (hidden !== defaultHidden) {
@@ -1090,9 +1018,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Layout
if (!skipLayout) {
if (this.workbenchGrid instanceof Grid) {
this.layout();
} else {
if (!(this.workbenchGrid instanceof Grid)) {
this.workbenchGrid.layout();
}
}
@@ -1103,9 +1029,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Adjust CSS
if (hidden) {
addClass(this.container, 'nopanel');
addClass(this.container, Classes.PANEL_HIDDEN);
} else {
removeClass(this.container, 'nopanel');
removeClass(this.container, Classes.PANEL_HIDDEN);
}
// If panel part becomes hidden, also hide the current active panel if any
@@ -1123,6 +1049,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
// Propagate to grid
if (this.workbenchGrid instanceof Grid) {
this.workbenchGrid.setViewVisible(this.panelPartView, !hidden);
}
// Remember in settings
if (!hidden) {
this.storageService.store(Storage.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE);
@@ -1137,9 +1068,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Layout
if (!skipLayout) {
if (this.workbenchGrid instanceof Grid) {
this.layout();
} else {
if (!(this.workbenchGrid instanceof Grid)) {
this.workbenchGrid.layout();
}
}
@@ -1147,33 +1076,15 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
toggleMaximizedPanel(): void {
if (this.workbenchGrid instanceof Grid) {
const curSize = this.workbenchGrid.getViewSize(this.panelPartView);
const size = { ...curSize };
const size = this.workbenchGrid.getViewSize(this.panelPartView);
if (!this.isPanelMaximized()) {
if (this.state.panel.position === Position.BOTTOM) {
size.height = this.panelPartView.maximumHeight;
this.state.panel.sizeBeforeMaximize = curSize.height;
} else {
size.width = this.panelPartView.maximumWidth;
this.state.panel.sizeBeforeMaximize = curSize.width;
}
this.state.panel.sizeBeforeMaximize = this.state.panel.position === Position.BOTTOM ? size.height : size.width;
this.storageService.store(Storage.PANEL_SIZE_BEFORE_MAXIMIZED, this.state.panel.sizeBeforeMaximize, StorageScope.GLOBAL);
this.setEditorHidden(true);
} else {
if (this.state.panel.position === Position.BOTTOM) {
size.height = this.state.panel.sizeBeforeMaximize;
} else {
size.width = this.state.panel.sizeBeforeMaximize;
}
// Unhide the editor if needed
if (this.state.editor.hidden) {
this.setEditorHidden(false);
}
this.setEditorHidden(false);
this.workbenchGrid.resizeView(this.panelPartView, { width: this.state.panel.position === Position.BOTTOM ? size.width : this.state.panel.sizeBeforeMaximize, height: this.state.panel.position === Position.BOTTOM ? this.state.panel.sizeBeforeMaximize : size.height });
}
this.workbenchGrid.resizeView(this.panelPartView, size);
} else {
this.workbenchGrid.layout({ toggleMaximizedPanel: true, source: Parts.PANEL_PART });
}
@@ -1185,16 +1096,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
if (this.workbenchGrid instanceof Grid) {
try {
// The panel is maximum when the editor is minimum
if (this.state.panel.position === Position.BOTTOM) {
return this.workbenchGrid.getViewSize(this.editorPartView).height <= this.editorPartView.minimumHeight;
} else {
return this.workbenchGrid.getViewSize(this.editorPartView).width <= this.editorPartView.minimumWidth;
}
} catch (e) {
return false;
}
return this.state.editor.hidden;
} else {
return this.workbenchGrid.isPanelMaximized();
}
@@ -1211,8 +1113,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Layout
if (!skipLayout) {
if (this.workbenchGrid instanceof Grid) {
const dimensions = getClientArea(this.parent);
this.workbenchGrid.layout(dimensions.width, dimensions.height);
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
} else {
this.workbenchGrid.layout();
}
@@ -1228,13 +1129,12 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
return this.state.panel.position;
}
setPanelPosition(position: Position): void {
const panelPart = this.getPart(Parts.PANEL_PART);
setPanelPosition(position: Position.BOTTOM | Position.RIGHT): void {
if (this.state.panel.hidden) {
this.setPanelHidden(false, true /* Skip Layout */);
this.setPanelHidden(false);
}
const panelPart = this.getPart(Parts.PANEL_PART);
const newPositionValue = (position === Position.BOTTOM) ? 'bottom' : 'right';
const oldPositionValue = (this.state.panel.position === Position.BOTTOM) ? 'bottom' : 'right';
this.state.panel.position = position;
@@ -1258,8 +1158,17 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Layout
if (this.workbenchGrid instanceof Grid) {
this.workbenchGrid.removeView(this.panelPartView);
this.layout();
const size = this.workbenchGrid.getViewSize(this.panelPartView);
const sideBarSize = this.workbenchGrid.getViewSize(this.sideBarPartView);
if (position === Position.BOTTOM) {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.height : size.width, this.editorPartView, Direction.Down);
} else {
this.workbenchGrid.moveView(this.panelPartView, this.state.editor.hidden ? size.width : size.height, this.editorPartView, Direction.Right);
}
// Reset sidebar to original size before shifting the panel
this.workbenchGrid.resizeView(this.sideBarPartView, sideBarSize);
} else {
this.workbenchGrid.layout();
}
@@ -1267,9 +1176,89 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this._onPanelPositionChange.fire(positionToString(this.state.panel.position));
}
private createGridDescriptor(): ISerializedGrid {
const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, 600);
const height = this.storageService.getNumber(Storage.GRID_HEIGHT, StorageScope.GLOBAL, 400);
const sideBarSize = this.storageService.getNumber(Storage.SIDEBAR_SIZE, StorageScope.GLOBAL, 300);
const panelSize = this.storageService.getNumber(Storage.PANEL_SIZE, StorageScope.GLOBAL, 300);
const titleBarHeight = this.titleBarPartView.minimumHeight;
const statusBarHeight = this.statusBarPartView.minimumHeight;
const activityBarWidth = this.activityBarPartView.minimumWidth;
const middleSectionHeight = height - titleBarHeight - statusBarHeight;
const editorSectionWidth = width - (this.state.activityBar.hidden ? 0 : activityBarWidth) - (this.state.sideBar.hidden ? 0 : sideBarSize);
const activityBarNode: ISerializedLeafNode = {
type: 'leaf',
data: { type: Parts.ACTIVITYBAR_PART },
size: activityBarWidth,
visible: !this.state.activityBar.hidden
};
const sideBarNode: ISerializedLeafNode = {
type: 'leaf',
data: { type: Parts.SIDEBAR_PART },
size: sideBarSize,
visible: !this.state.sideBar.hidden
};
const editorNode: ISerializedLeafNode = {
type: 'leaf',
data: { type: Parts.EDITOR_PART },
size: this.state.panel.position === Position.BOTTOM ? middleSectionHeight - (this.state.panel.hidden ? 0 : panelSize) : editorSectionWidth - (this.state.panel.hidden ? 0 : panelSize)
};
const panelNode: ISerializedLeafNode = {
type: 'leaf',
data: { type: Parts.PANEL_PART },
size: panelSize,
visible: !this.state.panel.hidden
};
const editorSectionNode: ISerializedNode[] = this.state.panel.position === Position.BOTTOM
? [{ type: 'branch', data: [editorNode, panelNode], size: editorSectionWidth }]
: [editorNode, panelNode];
const middleSection: ISerializedNode[] = this.state.sideBar.position === Position.LEFT
? [activityBarNode, sideBarNode, ...editorSectionNode]
: [...editorSectionNode, sideBarNode, activityBarNode];
const result: ISerializedGrid = {
root: {
type: 'branch',
size: width,
data: [
{
type: 'leaf',
data: { type: Parts.TITLEBAR_PART },
size: titleBarHeight,
visible: this.isVisible(Parts.TITLEBAR_PART)
},
{
type: 'branch',
data: middleSection,
size: middleSectionHeight
},
{
type: 'leaf',
data: { type: Parts.STATUSBAR_PART },
size: statusBarHeight,
visible: !this.state.statusBar.hidden
}
]
},
orientation: Orientation.VERTICAL,
width,
height
};
return result;
}
dispose(): void {
super.dispose();
this.disposed = true;
}
}

View File

@@ -25,7 +25,7 @@ export class PanelDescriptor extends CompositeDescriptor<Panel> {
}
export class PanelRegistry extends CompositeRegistry<Panel> {
private defaultPanelId: string;
private defaultPanelId!: string;
/**
* Registers a panel to the platform.

View File

@@ -48,7 +48,7 @@ interface ICachedViewlet {
export class ActivitybarPart extends Part implements IActivityBarService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private static readonly ACTION_HEIGHT = 48;
private static readonly PINNED_VIEWLETS = 'workbench.activity.pinnedViewlets';

View File

@@ -46,10 +46,10 @@ export interface ICompositeBarOptions {
export class CompositeBar extends Widget implements ICompositeBar {
private dimension: Dimension;
private dimension: Dimension | undefined;
private compositeSwitcherBar: ActionBar;
private compositeOverflowAction: CompositeOverflowActivityAction | null;
private compositeSwitcherBar!: ActionBar;
private compositeOverflowAction: CompositeOverflowActivityAction | undefined;
private compositeOverflowActionViewItem: CompositeOverflowActivityActionViewItem | undefined;
private model: CompositeBarModel;
@@ -343,7 +343,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
this.compositeSwitcherBar.pull(this.compositeSwitcherBar.length() - 1);
this.compositeOverflowAction.dispose();
this.compositeOverflowAction = null;
this.compositeOverflowAction = undefined;
if (this.compositeOverflowActionViewItem) {
this.compositeOverflowActionViewItem.dispose();
@@ -460,7 +460,7 @@ interface ICompositeBarModelItem extends ICompositeBarItem {
class CompositeBarModel {
private _items: ICompositeBarModelItem[];
private _items: ICompositeBarModelItem[] = [];
private readonly options: ICompositeBarOptions;
activeItem?: ICompositeBarModelItem;

View File

@@ -124,12 +124,12 @@ export interface IActivityActionViewItemOptions extends IBaseActionViewItemOptio
}
export class ActivityActionViewItem extends BaseActionViewItem {
protected container: HTMLElement;
protected label: HTMLElement;
protected badge: HTMLElement;
protected options: IActivityActionViewItemOptions;
protected container!: HTMLElement;
protected label!: HTMLElement;
protected badge!: HTMLElement;
protected options!: IActivityActionViewItemOptions;
private badgeContent: HTMLElement;
private badgeContent: HTMLElement | undefined;
private readonly badgeDisposable = this._register(new MutableDisposable());
private mouseUpTimeout: any;
@@ -347,7 +347,7 @@ export class CompositeOverflowActivityAction extends ActivityAction {
}
export class CompositeOverflowActivityActionViewItem extends ActivityActionViewItem {
private actions: Action[];
private actions: Action[] | undefined;
constructor(
action: ActivityAction,
@@ -371,8 +371,8 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI
this.contextMenuService.showContextMenu({
getAnchor: () => this.element!,
getActions: () => this.actions,
onHide: () => dispose(this.actions)
getActions: () => this.actions!,
onHide: () => dispose(this.actions!)
});
}
@@ -402,7 +402,9 @@ export class CompositeOverflowActivityActionViewItem extends ActivityActionViewI
dispose(): void {
super.dispose();
this.actions = dispose(this.actions);
if (this.actions) {
this.actions = dispose(this.actions);
}
}
}
@@ -431,7 +433,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
private static manageExtensionAction: ManageExtensionAction;
private compositeActivity: IActivity | null;
private compositeActivity: IActivity | undefined;
private compositeTransfer: LocalSelectionTransfer<DraggedCompositeIdentifier>;
constructor(
@@ -454,7 +456,7 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
CompositeActionViewItem.manageExtensionAction = instantiationService.createInstance(ManageExtensionAction);
}
this._register(compositeActivityAction.onDidChangeActivity(() => { this.compositeActivity = null; this.updateActivity(); }, this));
this._register(compositeActivityAction.onDidChangeActivity(() => { this.compositeActivity = undefined; this.updateActivity(); }, this));
}
protected get activity(): IActivity {

View File

@@ -58,18 +58,18 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected readonly onDidCompositeOpen = this._register(new Emitter<{ composite: IComposite, focus: boolean }>());
protected readonly onDidCompositeClose = this._register(new Emitter<IComposite>());
protected toolBar: ToolBar;
protected toolBar!: ToolBar;
private mapCompositeToCompositeContainer = new Map<string, HTMLElement>();
private mapActionsBindingToComposite = new Map<string, () => void>();
private activeComposite: Composite | null;
private lastActiveCompositeId: string;
private instantiatedCompositeItems: Map<string, CompositeItem>;
private titleLabel: ICompositeTitleLabel;
private progressBar: ProgressBar;
private contentAreaSize: Dimension;
private titleLabel!: ICompositeTitleLabel;
private progressBar!: ProgressBar;
private contentAreaSize: Dimension | undefined;
private readonly telemetryActionsListener = this._register(new MutableDisposable());
private currentCompositeOpenToken: string;
private currentCompositeOpenToken: string | undefined;
constructor(
private notificationService: INotificationService,

View File

@@ -29,7 +29,7 @@ export interface IBreadcrumbsService {
export class BreadcrumbsService implements IBreadcrumbsService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand: any;
private readonly _map = new Map<number, BreadcrumbsWidget>();
@@ -55,8 +55,8 @@ registerSingleton(IBreadcrumbsService, BreadcrumbsService, true);
export abstract class BreadcrumbsConfig<T> {
name: string;
onDidChange: Event<void>;
abstract get name(): string;
abstract get onDidChange(): Event<void>;
abstract getValue(overrides?: IConfigurationOverrides): T;
abstract updateValue(value: T, overrides?: IConfigurationOverrides): Promise<void>;

View File

@@ -56,11 +56,11 @@ export abstract class BreadcrumbsPicker {
protected readonly _disposables = new DisposableStore();
protected readonly _domNode: HTMLDivElement;
protected _arrow: HTMLDivElement;
protected _treeContainer: HTMLDivElement;
protected _tree: Tree<any, any>;
protected _arrow!: HTMLDivElement;
protected _treeContainer!: HTMLDivElement;
protected _tree!: Tree<any, any>;
protected _fakeEvent = new UIEvent('fakeEvent');
protected _layoutInfo: ILayoutInfo;
protected _layoutInfo!: ILayoutInfo;
private readonly _onDidPickElement = new Emitter<SelectEvent>();
readonly onDidPickElement: Event<SelectEvent> = this._onDidPickElement.event;

View File

@@ -36,7 +36,7 @@ import {
SplitEditorUpAction, SplitEditorDownAction, MoveEditorToLeftGroupAction, MoveEditorToRightGroupAction, MoveEditorToAboveGroupAction, MoveEditorToBelowGroupAction, CloseAllEditorGroupsAction,
JoinAllGroupsAction, FocusLeftGroup, FocusAboveGroup, FocusRightGroup, FocusBelowGroup, EditorLayoutSingleAction, EditorLayoutTwoColumnsAction, EditorLayoutThreeColumnsAction, EditorLayoutTwoByTwoGridAction,
EditorLayoutTwoRowsAction, EditorLayoutThreeRowsAction, EditorLayoutTwoColumnsBottomAction, EditorLayoutTwoRowsRightAction, NewEditorGroupLeftAction, NewEditorGroupRightAction,
NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction
NewEditorGroupAboveAction, NewEditorGroupBelowAction, SplitEditorOrthogonalAction, CloseEditorInAllGroupsAction, NavigateToLastEditLocationAction, ToggleGroupSizesAction
} from 'vs/workbench/browser/parts/editor/editorActions';
import * as editorCommands from 'vs/workbench/browser/parts/editor/editorCommands';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
@@ -339,6 +339,7 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(JoinTwoGroupsAction, J
registry.registerWorkbenchAction(new SyncActionDescriptor(JoinAllGroupsAction, JoinAllGroupsAction.ID, JoinAllGroupsAction.LABEL), 'View: Join All Editor Groups', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(NavigateBetweenGroupsAction, NavigateBetweenGroupsAction.ID, NavigateBetweenGroupsAction.LABEL), 'View: Navigate Between Editor Groups', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(ResetGroupSizesAction, ResetGroupSizesAction.ID, ResetGroupSizesAction.LABEL), 'View: Reset Editor Group Sizes', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleGroupSizesAction, ToggleGroupSizesAction.ID, ToggleGroupSizesAction.LABEL), 'View: Toggle Editor Group Sizes', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(MaximizeGroupAction, MaximizeGroupAction.ID, MaximizeGroupAction.LABEL), 'View: Maximize Editor Group and Hide Side Bar', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(MinimizeOtherGroupsAction, MinimizeOtherGroupsAction.ID, MinimizeOtherGroupsAction.LABEL), 'View: Maximize Editor Group', category);
registry.registerWorkbenchAction(new SyncActionDescriptor(MoveEditorLeftInGroupAction, MoveEditorLeftInGroupAction.ID, MoveEditorLeftInGroupAction.LABEL, { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.PageUp, mac: { primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KEY_K, KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.LeftArrow) } }), 'View: Move Editor Left', category);

View File

@@ -81,12 +81,15 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
}
export interface IEditorGroupsAccessor {
readonly groups: IEditorGroupView[];
readonly activeGroup: IEditorGroupView;
readonly partOptions: IEditorPartOptions;
readonly onDidEditorPartOptionsChange: Event<IEditorPartOptionsChangeEvent>;
readonly onDidVisibilityChange: Event<boolean>;
getGroup(identifier: GroupIdentifier): IEditorGroupView | undefined;
getGroups(order: GroupsOrder): IEditorGroupView[];
@@ -106,6 +109,9 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito
readonly whenRestored: Promise<void>;
readonly disposed: boolean;
readonly isEmpty: boolean;
readonly isMinimized: boolean;
readonly onDidFocus: Event<void>;
readonly onWillDispose: Event<void>;
readonly onWillOpenEditor: Event<IEditorOpeningEvent>;
@@ -113,9 +119,10 @@ export interface IEditorGroupView extends IDisposable, ISerializableView, IEdito
readonly onWillCloseEditor: Event<IEditorCloseEvent>;
readonly onDidCloseEditor: Event<IEditorCloseEvent>;
isEmpty(): boolean;
setActive(isActive: boolean): void;
setLabel(label: string): void;
notifyIndexChanged(newIndex: number): void;
relayout(): void;
}

View File

@@ -880,6 +880,22 @@ export class ResetGroupSizesAction extends Action {
}
}
export class ToggleGroupSizesAction extends Action {
static readonly ID = 'workbench.action.toggleEditorWidths';
static readonly LABEL = nls.localize('toggleEditorWidths', "Toggle Editor Group Sizes");
constructor(id: string, label: string, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService) {
super(id, label);
}
run(): Promise<any> {
this.editorGroupService.arrangeGroups(GroupsArrangement.TOGGLE);
return Promise.resolve(false);
}
}
export class MaximizeGroupAction extends Action {
static readonly ID = 'workbench.action.maximizeEditor';

View File

@@ -221,6 +221,12 @@ export class EditorControl extends Disposable {
}
}
setVisible(visible: boolean): void {
if (this._activeControl) {
this._activeControl.setVisible(visible, this.groupView);
}
}
layout(dimension: Dimension): void {
this.dimension = dimension;

View File

@@ -409,7 +409,7 @@ class DropOverlay extends Themable {
}
private getOverlayOffsetHeight(): number {
if (!this.groupView.isEmpty() && this.accessor.partOptions.showTabs) {
if (!this.groupView.isEmpty && this.accessor.partOptions.showTabs) {
return EDITOR_TITLE_HEIGHT; // show overlay below title if group shows tabs
}

View File

@@ -58,16 +58,16 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region factory
static createNew(accessor: IEditorGroupsAccessor, label: string, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, null, label);
static createNew(accessor: IEditorGroupsAccessor, index: number, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, null, index);
}
static createFromSerialized(serialized: ISerializedEditorGroup, accessor: IEditorGroupsAccessor, label: string, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, serialized, label);
static createFromSerialized(serialized: ISerializedEditorGroup, accessor: IEditorGroupsAccessor, index: number, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, serialized, index);
}
static createCopy(copyFrom: IEditorGroupView, accessor: IEditorGroupsAccessor, label: string, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, copyFrom, label);
static createCopy(copyFrom: IEditorGroupView, accessor: IEditorGroupsAccessor, index: number, instantiationService: IInstantiationService): IEditorGroupView {
return instantiationService.createInstance(EditorGroupView, accessor, copyFrom, index);
}
//#endregion
@@ -123,7 +123,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
constructor(
private accessor: IEditorGroupsAccessor,
from: IEditorGroupView | ISerializedEditorGroup,
private _label: string,
private _index: number,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IThemeService themeService: IThemeService,
@@ -256,7 +256,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Open new file via doubleclick on empty container
this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => {
if (this.isEmpty()) {
if (this.isEmpty) {
EventHelper.stop(e);
// {{SQL CARBON EDIT}}
this.commandService.executeCommand(GlobalNewUntitledFileAction.ID).then(undefined, err => this.notificationService.warn(err));
@@ -265,7 +265,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Close empty editor group via middle mouse click
this._register(addDisposableListener(this.element, EventType.MOUSE_UP, e => {
if (this.isEmpty() && e.button === 1 /* Middle Button */) {
if (this.isEmpty && e.button === 1 /* Middle Button */) {
EventHelper.stop(e);
this.accessor.removeGroup(this);
@@ -314,7 +314,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
}
private onShowContainerContextMenu(menu: IMenu, e?: MouseEvent): void {
if (!this.isEmpty()) {
if (!this.isEmpty) {
return; // only for empty editor groups
}
@@ -345,7 +345,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Container
const containerFocusTracker = this._register(trackFocus(this.element));
this._register(containerFocusTracker.onDidFocus(() => {
if (this.isEmpty()) {
if (this.isEmpty) {
this._onDidFocus.fire(); // only when empty to prevent accident focus
}
}));
@@ -387,7 +387,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
private updateContainer(): void {
// Empty Container: add some empty container attributes
if (this.isEmpty()) {
if (this.isEmpty) {
addClass(this.element, 'empty');
this.element.tabIndex = 0;
this.element.setAttribute('aria-label', localize('emptyEditorGroup', "{0} (empty)", this.label));
@@ -474,6 +474,9 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Option Changes
this._register(this.accessor.onDidEditorPartOptionsChange(e => this.onDidEditorPartOptionsChange(e)));
// Visibility
this._register(this.accessor.onDidVisibilityChange(e => this.onDidVisibilityChange(e)));
}
private onDidEditorPin(editor: EditorInput): void {
@@ -597,8 +600,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
// Title control Switch between showing tabs <=> not showing tabs
if (event.oldPartOptions.showTabs !== event.newPartOptions.showTabs) {
this.createTitleAreaControl();
// Recreate and layout control
this.createTitleAreaControl();
this.layoutTitleAreaControl();
// Ensure to show active editor if any
if (this._group.activeEditor) {
this.titleAreaControl.openEditor(this._group.activeEditor);
}
@@ -641,6 +648,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_LABEL, editor });
}
private onDidVisibilityChange(visible: boolean): void {
// Forward to editor control
this.editorControl.setVisible(visible);
}
//#endregion
//region IEditorGroupView
@@ -649,8 +662,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._group;
}
get index(): number {
return this._index;
}
get label(): string {
return this._label;
return localize('groupLabel', "Group {0}", this._index + 1);
}
get disposed(): boolean {
@@ -661,10 +678,22 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
return this._whenRestored;
}
setLabel(label: string): void {
if (this._label !== label) {
this._label = label;
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_LABEL });
get isEmpty(): boolean {
return this._group.count === 0;
}
get isMinimized(): boolean {
if (!this.dimension) {
return false;
}
return this.dimension.width === this.minimumWidth || this.dimension.height === this.minimumHeight;
}
notifyIndexChanged(newIndex: number): void {
if (this._index !== newIndex) {
this._index = newIndex;
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_INDEX });
}
}
@@ -685,10 +714,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._onDidGroupChange.fire({ kind: GroupChangeKind.GROUP_ACTIVE });
}
isEmpty(): boolean {
return this._group.count === 0;
}
//#endregion
//#region IEditorGroup
@@ -1213,7 +1238,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeEditors()
async closeEditors(args: EditorInput[] | ICloseEditorsFilter, options?: ICloseEditorOptions): Promise<void> {
if (this.isEmpty()) {
if (this.isEmpty) {
return;
}
@@ -1285,7 +1310,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region closeAllEditors()
async closeAllEditors(): Promise<void> {
if (this.isEmpty()) {
if (this.isEmpty) {
// If the group is empty and the request is to close all editors, we still close
// the editor group is the related setting to close empty groups is enabled for
@@ -1397,7 +1422,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
//#region Themable
protected updateStyles(): void {
const isEmpty = this.isEmpty();
const isEmpty = this.isEmpty;
// Container
if (isEmpty) {
@@ -1446,10 +1471,14 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
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.layoutTitleAreaControl();
this.editorControl.layout(new Dimension(this.dimension.width, this.dimension.height - this.titleAreaControl.getPreferredHeight()));
}
private layoutTitleAreaControl(): void {
this.titleAreaControl.layout(new Dimension(this.dimension.width, this.titleAreaControl.getPreferredHeight()));
}
relayout(): void {
if (this.dimension) {
const { width, height } = this.dimension;
@@ -1469,7 +1498,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
this._onWillDispose.fire();
this.titleAreaControl.dispose();
// this.editorControl = null;
super.dispose();
}

View File

@@ -24,7 +24,6 @@ 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 { 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 { onUnexpectedError } from 'vs/base/common/errors';
@@ -82,7 +81,7 @@ class GridWidgetView<T extends IView> implements IView {
export class EditorPart extends Part implements IEditorGroupsService, IEditorGroupsAccessor {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private static readonly EDITOR_PART_UI_STATE_STORAGE_KEY = 'editorpart.state';
private static readonly EDITOR_PART_CENTERED_VIEW_STORAGE_KEY = 'editorpart.centeredview';
@@ -95,6 +94,9 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
private readonly _onDidActiveGroupChange: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidActiveGroupChange: Event<IEditorGroupView> = this._onDidActiveGroupChange.event;
private readonly _onDidGroupIndexChange: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidGroupIndexChange: Event<IEditorGroupView> = this._onDidGroupIndexChange.event;
private readonly _onDidActivateGroup: Emitter<IEditorGroupView> = this._register(new Emitter<IEditorGroupView>());
readonly onDidActivateGroup: Event<IEditorGroupView> = this._onDidActivateGroup.event;
@@ -344,15 +346,36 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
return; // we have not been created yet
}
// Even all group sizes
if (arrangement === GroupsArrangement.EVEN) {
this.gridWidget.distributeViewSizes();
switch (arrangement) {
case GroupsArrangement.EVEN:
this.gridWidget.distributeViewSizes();
break;
case GroupsArrangement.MINIMIZE_OTHERS:
this.gridWidget.maximizeViewSize(this.activeGroup);
break;
case GroupsArrangement.TOGGLE:
if (this.isGroupMaximized(this.activeGroup)) {
this.arrangeGroups(GroupsArrangement.EVEN);
} else {
this.arrangeGroups(GroupsArrangement.MINIMIZE_OTHERS);
}
break;
}
}
private isGroupMaximized(targetGroup: IEditorGroupView): boolean {
for (const group of this.groups) {
if (group === targetGroup) {
continue; // ignore target group
}
if (!group.isMinimized) {
return false; // target cannot be maximized if one group is not minimized
}
}
// Maximize the current active group
else {
this.gridWidget.maximizeViewSize(this.activeGroup);
}
return true;
}
setGroupOrientation(orientation: GroupOrientation): void {
@@ -424,8 +447,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
}
});
// Update labels
this.updateGroupLabels();
// Notify group index change given layout has changed
this.notifyGroupIndexChange();
// Restore focus as needed
if (restoreFocus) {
@@ -484,25 +507,22 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
// Event
this._onDidAddGroup.fire(newGroupView);
// Update labels
this.updateGroupLabels();
// Notify group index change given a new group was added
this.notifyGroupIndexChange();
return newGroupView;
}
private doCreateGroupView(from?: IEditorGroupView | ISerializedEditorGroup | null): IEditorGroupView {
// Label: just use the number of existing groups as label
const label = this.getGroupLabel(this.count + 1);
// Create group view
let groupView: IEditorGroupView;
if (from instanceof EditorGroupView) {
groupView = EditorGroupView.createCopy(from, this, label, this.instantiationService);
groupView = EditorGroupView.createCopy(from, this, this.count, this.instantiationService);
} else if (isSerializedEditorGroup(from)) {
groupView = EditorGroupView.createFromSerialized(from, this, label, this.instantiationService);
groupView = EditorGroupView.createFromSerialized(from, this, this.count, this.instantiationService);
} else {
groupView = EditorGroupView.createNew(this, label, this.instantiationService);
groupView = EditorGroupView.createNew(this, this.count, this.instantiationService);
}
// Keep in map
@@ -516,8 +536,13 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
// Track editor change
groupDisposables.add(groupView.onDidGroupChange(e => {
if (e.kind === GroupChangeKind.EDITOR_ACTIVE) {
this.updateContainer();
switch (e.kind) {
case GroupChangeKind.EDITOR_ACTIVE:
this.updateContainer();
break;
case GroupChangeKind.GROUP_INDEX:
this._onDidGroupIndexChange.fire(groupView);
break;
}
}));
@@ -600,7 +625,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
}
// Remove empty group
if (groupView.isEmpty()) {
if (groupView.isEmpty) {
return this.doRemoveEmptyGroup(groupView);
}
@@ -643,8 +668,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this._activeGroup.focus();
}
// Update labels
this.updateGroupLabels();
// Notify group index change given a group was removed
this.notifyGroupIndexChange();
// Update container
this.updateContainer();
@@ -675,6 +700,9 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
// Event
this._onDidMoveGroup.fire(sourceView);
// Notify group index change given a group was moved
this.notifyGroupIndexChange();
return sourceView;
}
@@ -715,7 +743,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
});
// Remove source if the view is now empty and not already removed
if (sourceView.isEmpty() && !sourceView.disposed /* could have been disposed already via workbench.editor.closeEmptyGroups setting */) {
if (sourceView.isEmpty && !sourceView.disposed /* could have been disposed already via workbench.editor.closeEmptyGroups setting */) {
this.removeGroup(sourceView);
}
@@ -784,6 +812,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
centerLayout(active: boolean): void {
this.centeredLayoutWidget.activate(active);
this._activeGroup.focus();
}
@@ -813,6 +842,9 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
// Update container
this.updateContainer();
// Notify group index change we created the entire grid
this.notifyGroupIndexChange();
}
private doCreateGridControlWithPreviousState(): boolean {
@@ -906,26 +938,15 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
}
private updateContainer(): void {
toggleClass(this.container, 'empty', this.isEmpty());
toggleClass(this.container, 'empty', this.isEmpty);
}
private updateGroupLabels(): void {
// Since our labels are created using the index of the
// group, adding/removing a group might produce gaps.
// So we iterate over all groups and reassign the label
// based on the index.
this.getGroups(GroupsOrder.GRID_APPEARANCE).forEach((group, index) => {
group.setLabel(this.getGroupLabel(index + 1));
});
private notifyGroupIndexChange(): void {
this.getGroups(GroupsOrder.GRID_APPEARANCE).forEach((group, index) => group.notifyIndexChanged(index));
}
private getGroupLabel(index: number): string {
return localize('groupLabel', "Group {0}", index);
}
private isEmpty(): boolean {
return this.groupViews.size === 1 && this._activeGroup.isEmpty();
private get isEmpty(): boolean {
return this.groupViews.size === 1 && this._activeGroup.isEmpty;
}
layout(width: number, height: number): void {
@@ -957,7 +978,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
mostRecentActiveGroups: this.mostRecentActiveGroups
};
if (this.isEmpty()) {
if (this.isEmpty) {
delete this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY];
} else {
this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY] = uiState;

View File

@@ -285,4 +285,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (notificationBorderColor) {
collector.addRule(`.monaco-workbench > .notifications-center .notifications-list-container .monaco-list-row[data-last-element="false"] > .notification-list-item { border-bottom: 1px solid ${notificationBorderColor}; }`);
}
});
});

View File

@@ -11,12 +11,12 @@ import { localize } from 'vs/nls';
export class NotificationsStatus extends Disposable {
private notificationsCenterStatusItem: IStatusbarEntryAccessor;
private notificationsCenterStatusItem: IStatusbarEntryAccessor | undefined;
private currentNotifications = new Set<INotificationViewItem>();
private currentStatusMessage: [IStatusMessageViewItem, IDisposable] | undefined;
private isNotificationsCenterVisible: boolean;
private isNotificationsCenterVisible: boolean | undefined;
constructor(
private model: INotificationsModel,
@@ -172,4 +172,4 @@ export class NotificationsStatus extends Disposable {
// Remember as current status message
this.currentStatusMessage = [item, statusMessageDispose];
}
}
}

View File

@@ -62,7 +62,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
}
// Last row: source and buttons if we have any
if (notification.source || isNonEmptyArray(notification.actions.primary)) {
if (notification.source || isNonEmptyArray(notification.actions && notification.actions.primary)) {
expandedHeight += NotificationsListDelegate.ROW_HEIGHT;
}
@@ -82,7 +82,7 @@ export class NotificationsListDelegate implements IListVirtualDelegate<INotifica
if (notification.canCollapse) {
actions++; // expand/collapse
}
if (isNonEmptyArray(notification.actions.secondary)) {
if (isNonEmptyArray(notification.actions && notification.actions.secondary)) {
actions++; // secondary actions
}
this.offsetHelper.style.width = `calc(100% - ${10 /* padding */ + 24 /* severity icon */ + (actions * 24) /* 24px per action */}px)`;
@@ -392,8 +392,9 @@ export class NotificationTemplateRenderer extends Disposable {
const actions: IAction[] = [];
// Secondary Actions
if (isNonEmptyArray(notification.actions.secondary)) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, notification.actions.secondary);
const secondaryActions = notification.actions ? notification.actions.secondary : undefined;
if (isNonEmptyArray(secondaryActions)) {
const configureNotificationAction = this.instantiationService.createInstance(ConfigureNotificationAction, ConfigureNotificationAction.ID, ConfigureNotificationAction.LABEL, secondaryActions);
actions.push(configureNotificationAction);
this.inputDisposables.add(configureNotificationAction);
}
@@ -435,10 +436,11 @@ export class NotificationTemplateRenderer extends Disposable {
private renderButtons(notification: INotificationViewItem): void {
clearNode(this.template.buttonsContainer);
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 */ });
const primaryActions = notification.actions ? notification.actions.primary : undefined;
if (notification.expanded && isNonEmptyArray(primaryActions)) {
const buttonGroup = new ButtonGroup(this.template.buttonsContainer, primaryActions.length, { title: true /* assign titles to buttons in case they overflow */ });
buttonGroup.buttons.forEach((button, index) => {
const action = notification.actions.primary![index];
const action = primaryActions[index];
button.label = action.label;
this.inputDisposables.add(button.onDidClick(e => {

View File

@@ -25,11 +25,19 @@
border-top-style: solid;
}
.monaco-workbench.noeditorarea .part.panel.bottom .title {
border-top-width: 0; /* no border when editor area is hiden */
}
.monaco-workbench .part.panel.right {
border-left-width: 1px;
border-left-style: solid;
}
.monaco-workbench.noeditorarea .part.panel.right {
border-left-width: 0; /* no border when editor area is hiden */
}
.monaco-workbench .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label {
outline-offset: -2px;
}
@@ -181,4 +189,4 @@
.hc-black .monaco-workbench .panel.right .minimize-panel-action {
background-image: url('chevron-right-hc.svg');
}
}

View File

@@ -48,7 +48,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
private static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels';
private static readonly MIN_COMPOSITE_BAR_WIDTH = 50;
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
//#region IView
@@ -83,8 +83,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
private compositeBar: CompositeBar;
private compositeActions: Map<string, { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction }> = new Map();
private blockOpeningPanel: boolean;
private _contentDimension: Dimension;
private blockOpeningPanel = false;
private _contentDimension: Dimension | undefined;
constructor(
@INotificationService notificationService: INotificationService,
@@ -367,7 +367,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
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;
this._cachedPanelsValue = undefined;
const newCompositeItems: ICompositeBarItem[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
const cachedPanels = this.getCachedPanels();
@@ -422,7 +422,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
return cachedPanels;
}
private _cachedPanelsValue: string | null;
private _cachedPanelsValue: string | undefined;
private get cachedPanelsValue(): string {
if (!this._cachedPanelsValue) {
this._cachedPanelsValue = this.getStoredCachedPanelsValue();

View File

@@ -880,7 +880,7 @@ class InputBox extends QuickInput implements IInputBox {
export class QuickInputService extends Component implements IQuickInputService {
public _serviceBrand: ServiceIdentifier<any>;
public _serviceBrand!: ServiceIdentifier<any>;
private static readonly ID = 'workbench.component.quickinput';
private static readonly MAX_WIDTH = 600; // Max total width of quick open widget

View File

@@ -114,7 +114,7 @@ class ListElementRenderer implements IListRenderer<ListElement, IListElementTemp
const row2 = dom.append(rows, $('.quick-input-list-row'));
// Label
data.label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true });
data.label = new IconLabel(row1, { supportHighlights: true, supportDescriptionHighlights: true, supportOcticons: true });
// Detail
const detailContainer = dom.append(row2, $('.quick-input-list-label-meta'));

View File

@@ -61,7 +61,7 @@ export class QuickOpenController extends Component implements IQuickOpenService
private static readonly MAX_SHORT_RESPONSE_TIME = 500;
private static readonly ID = 'workbench.component.quickopen';
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private readonly _onShow: Emitter<void> = this._register(new Emitter<void>());
readonly onShow: Event<void> = this._onShow.event;
@@ -861,4 +861,4 @@ export class RemoveFromEditorHistoryAction extends Action {
}
}
registerSingleton(IQuickOpenService, QuickOpenController, true);
registerSingleton(IQuickOpenService, QuickOpenController, true);

View File

@@ -31,10 +31,11 @@ import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/c
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { LayoutPriority } from 'vs/base/browser/ui/grid/grid';
export class SidebarPart extends CompositePart<Viewlet> implements IViewletService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
static readonly activeViewletSettingsKey = 'workbench.sidebar.activeviewletid';
@@ -45,6 +46,8 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
readonly minimumHeight: number = 0;
readonly maximumHeight: number = Number.POSITIVE_INFINITY;
readonly priority: LayoutPriority = LayoutPriority.Low;
readonly snap = true;
get preferredWidth(): number | undefined {
@@ -79,7 +82,7 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
private viewletRegistry: ViewletRegistry;
private sideBarFocusContextKey: IContextKey<boolean>;
private activeViewletContextKey: IContextKey<string>;
private blockOpeningViewlet: boolean;
private blockOpeningViewlet = false;
constructor(
@INotificationService notificationService: INotificationService,

View File

@@ -323,7 +323,7 @@ class HideStatusbarEntryAction extends Action {
export class StatusbarPart extends Part implements IStatusbarService {
_serviceBrand: ServiceIdentifier<IStatusbarService>;
_serviceBrand!: ServiceIdentifier<IStatusbarService>;
//#region IView

View File

@@ -58,7 +58,7 @@ export class TitlebarPart extends Part implements ITitleService {
private _onMenubarVisibilityChange = this._register(new Emitter<boolean>());
readonly onMenubarVisibilityChange: Event<boolean> = this._onMenubarVisibilityChange.event;
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private title: HTMLElement;
private dragRegion: HTMLElement;
@@ -639,4 +639,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
}
});
registerSingleton(ITitleService, TitlebarPart);
registerSingleton(ITitleService, TitlebarPart);

View File

@@ -5,7 +5,7 @@
import 'vs/css!./media/views';
import { Event, Emitter } from 'vs/base/common/event';
import { IDisposable, Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { IDisposable, Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IAction, IActionViewItem, ActionRunner, Action } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -33,18 +33,14 @@ import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/v
import { localize } from 'vs/nls';
import { timeout } from 'vs/base/common/async';
import { editorFindMatchHighlight, editorFindMatchHighlightBorder, textLinkForeground, textCodeBlockBackground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { IMarkdownString } from 'vs/base/common/htmlContent';
import { isString } from 'vs/base/common/types';
import { renderMarkdown, RenderOptions } from 'vs/base/browser/htmlContentRenderer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IMarkdownRenderResult } from 'vs/editor/contrib/markdown/markdownRenderer';
import { ILabelService } from 'vs/platform/label/common/label';
import { Registry } from 'vs/platform/registry/common/platform';
import { IListVirtualDelegate, IIdentityProvider } from 'vs/base/browser/ui/list/list';
import { ITreeRenderer, ITreeNode, IAsyncDataSource, ITreeContextMenuEvent } from 'vs/base/browser/ui/tree/tree';
import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
export class CustomTreeViewPanel extends ViewletPanel {
@@ -167,7 +163,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
private focused: boolean = false;
private domNode: HTMLElement;
private treeContainer: HTMLElement;
private _messageValue: string | IMarkdownString | undefined;
private _messageValue: string | undefined;
private messageElement: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore>;
private treeLabels: ResourceLabels;
@@ -175,9 +171,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
private elementsToRefresh: ITreeItem[] = [];
private menus: TitleMenus;
private markdownRenderer: MarkdownRenderer;
private markdownResult: IMarkdownRenderResult | null;
private readonly _onDidExpandItem: Emitter<ITreeItem> = this._register(new Emitter<ITreeItem>());
readonly onDidExpandItem: Event<ITreeItem> = this._onDidExpandItem.event;
@@ -217,12 +210,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.doRefresh([this.root]); /** soft refresh **/
}
}));
this.markdownRenderer = instantiationService.createInstance(MarkdownRenderer);
this._register(toDisposable(() => {
if (this.markdownResult) {
this.markdownResult.dispose();
}
}));
this._register(Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).onDidChangeContainer(({ views, from, to }) => {
if (from === this.viewContainer && views.some(v => v.id === this.id)) {
this.viewContainer = to;
@@ -256,12 +243,12 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
}
private _message: string | IMarkdownString | undefined;
get message(): string | IMarkdownString | undefined {
private _message: string | undefined;
get message(): string | undefined {
return this._message;
}
set message(message: string | IMarkdownString | undefined) {
set message(message: string | undefined) {
this._message = message;
this.updateMessage();
}
@@ -470,16 +457,13 @@ export class CustomTreeView extends Disposable implements ITreeView {
this.updateContentAreas();
}
private showMessage(message: string | IMarkdownString): void {
private showMessage(message: string): void {
DOM.removeClass(this.messageElement, 'hide');
if (this._messageValue !== message) {
this.resetMessageElement();
this._messageValue = message;
if (isString(this._messageValue)) {
if (!isFalsyOrWhitespace(this._message)) {
this.messageElement.textContent = this._messageValue;
} else {
this.markdownResult = this.markdownRenderer.render(this._messageValue);
DOM.append(this.messageElement, this.markdownResult.element);
}
this.layout(this._height, this._width);
}
@@ -492,10 +476,6 @@ export class CustomTreeView extends Disposable implements ITreeView {
}
private resetMessageElement(): void {
if (this.markdownResult) {
this.markdownResult.dispose();
this.markdownResult = null;
}
DOM.clearNode(this.messageElement);
}
@@ -597,8 +577,16 @@ export class CustomTreeView extends Disposable implements ITreeView {
private async doRefresh(elements: ITreeItem[]): Promise<void> {
if (this.tree) {
this.refreshing = true;
await Promise.all(elements.map(element => this.tree.updateChildren(element, true)));
elements.map(element => this.tree.rerender(element));
const parents: Set<ITreeItem> = new Set<ITreeItem>();
elements.forEach(element => {
if (element !== this.root) {
const parent = this.tree.getParentElement(element);
parents.add(parent);
} else {
parents.add(element);
}
});
await Promise.all(Array.from(parents.values()).map(element => this.tree.updateChildren(element, true)));
this.refreshing = false;
this.updateContentAreas();
if (this.focused) {
@@ -718,7 +706,7 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
const icon = DOM.append(container, DOM.$('.custom-view-tree-node-item-icon'));
const resourceLabel = this.labels.create(container, { supportHighlights: true, donotSupportOcticons: true });
const resourceLabel = this.labels.create(container, { supportHighlights: true });
const actionsContainer = DOM.append(resourceLabel.element, DOM.$('.actions'));
const actionBar = new ActionBar(actionsContainer, {
actionViewItemProvider: this.actionViewItemProvider
@@ -885,38 +873,3 @@ class TreeMenus extends Disposable implements IDisposable {
}
}
class MarkdownRenderer {
constructor(
@IOpenerService private readonly _openerService: IOpenerService
) {
}
private getOptions(disposeables: DisposableStore): RenderOptions {
return {
actionHandler: {
callback: (content) => {
let uri: URI | undefined;
try {
uri = URI.parse(content);
} catch {
// ignore
}
if (uri && this._openerService) {
this._openerService.open(uri).catch(onUnexpectedError);
}
},
disposeables
}
};
}
render(markdown: IMarkdownString): IMarkdownRenderResult {
const disposeables = new DisposableStore();
const element: HTMLElement = markdown ? renderMarkdown(markdown, this.getOptions(disposeables)) : document.createElement('span');
return {
element,
dispose: () => disposeables.dispose()
};
}
}

View File

@@ -626,7 +626,7 @@ export class PersistentContributableViewsModel extends ContributableViewsModel {
export class ViewsService extends Disposable implements IViewsService {
_serviceBrand: ServiceIdentifier<any>;
_serviceBrand!: ServiceIdentifier<any>;
private readonly viewDescriptorCollections: Map<ViewContainer, { viewDescriptorCollection: IViewDescriptorCollection, disposable: IDisposable }>;
private readonly viewDisposable: Map<IViewDescriptor, IDisposable>;

View File

@@ -76,7 +76,7 @@ export const Extensions = {
};
export class ViewletRegistry extends CompositeRegistry<Viewlet> {
private defaultViewletId: string;
private defaultViewletId!: string;
/**
* Registers a viewlet to the platform.

View File

@@ -40,14 +40,10 @@ import { joinPath } from 'vs/base/common/resources';
import { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/workbench/services/request/browser/requestService';
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
class CodeRendererMain extends Disposable {
private workbench: Workbench;
constructor(
private readonly domElement: HTMLElement,
private readonly configuration: IWorkbenchConstructionOptions
@@ -65,24 +61,30 @@ class CodeRendererMain extends Disposable {
this.restoreBaseTheme();
// Create Workbench
this.workbench = new Workbench(
const workbench = new Workbench(
this.domElement,
services.serviceCollection,
services.logService
);
// Layout
this._register(addDisposableListener(window, EventType.RESIZE, () => this.workbench.layout()));
this._register(addDisposableListener(window, EventType.RESIZE, () => workbench.layout()));
// Workbench Lifecycle
this._register(this.workbench.onShutdown(() => this.dispose()));
this._register(this.workbench.onWillShutdown(() => {
this._register(workbench.onBeforeShutdown(event => {
if (services.storageService.hasPendingUpdate) {
console.warn('Unload prevented: pending storage update');
event.veto(true); // prevent data loss from pending storage update
}
}));
this._register(workbench.onWillShutdown(() => {
services.storageService.close();
this.saveBaseTheme();
}));
this._register(workbench.onShutdown(() => this.dispose()));
// Startup
this.workbench.startup();
workbench.startup();
}
private restoreBaseTheme(): void {
@@ -105,7 +107,7 @@ class CodeRendererMain extends Disposable {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
// CONTRIBUTE IT VIA WORKBENCH.MAIN.TS AND registerSingleton().
// CONTRIBUTE IT VIA WORKBENCH.WEB.MAIN.TS AND registerSingleton().
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Log
@@ -166,7 +168,7 @@ class CodeRendererMain extends Disposable {
// User Data Provider
fileService.registerProvider(Schemas.userData, userDataProvider);
const [configurationService, storageService] = await Promise.all([
const services = await Promise.all([
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
// Workspace
@@ -187,10 +189,7 @@ class CodeRendererMain extends Disposable {
})
]);
// Request Service
serviceCollection.set(IRequestService, new RequestService(this.configuration.requestHandler, remoteAgentService, configurationService, logService));
return { serviceCollection, logService, storageService };
return { serviceCollection, logService, storageService: services[1] };
}
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise<BrowserStorageService> {

View File

@@ -22,7 +22,6 @@ import { IRecentlyOpened, IRecent, isRecentFile, isRecentFolder } from 'vs/platf
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing';
import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { IExtensionHostDebugService } from 'vs/platform/debug/common/extensionHostDebug';
// tslint:disable-next-line: import-patterns
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
@@ -30,14 +29,17 @@ import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/co
import { pathsToEditors } from 'vs/workbench/common/editor';
import { IFileService } from 'vs/platform/files/common/files';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService';
// tslint:disable-next-line: import-patterns
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
import { ExtensionHostDebugChannelClient, ExtensionHostDebugBroadcastChannel } from 'vs/platform/debug/common/extensionHostDebugIpc';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IProductService } from 'vs/platform/product/common/product';
import Severity from 'vs/base/common/severity';
import { localize } from 'vs/nls';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
//#region Extension Tips
@@ -174,63 +176,6 @@ export class SimpleLogService extends ConsoleLogService { }
//#endregion
//#region Multi Extension Management
export class SimpleMultiExtensionsManagementService implements IExtensionManagementService {
_serviceBrand: any;
onInstallExtension = Event.None;
onDidInstallExtension = Event.None;
onUninstallExtension = Event.None;
onDidUninstallExtension = Event.None;
zip(extension: ILocalExtension): Promise<URI> {
// @ts-ignore
return Promise.resolve(undefined);
}
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier> {
// @ts-ignore
return Promise.resolve(undefined);
}
install(vsix: URI): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(undefined);
}
installFromGallery(extension: IGalleryExtension): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(undefined);
}
uninstall(extension: ILocalExtension, force?: boolean): Promise<void> {
return Promise.resolve(undefined);
}
reinstallFromGallery(extension: ILocalExtension): Promise<void> {
return Promise.resolve(undefined);
}
getInstalled(type?: ExtensionType): Promise<ILocalExtension[]> {
// @ts-ignore
return Promise.resolve(undefined);
}
getExtensionsReport(): Promise<IReportedExtension[]> {
// @ts-ignore
return Promise.resolve(undefined);
}
updateMetadata(local: ILocalExtension, metadata: IGalleryMetadata): Promise<ILocalExtension> {
// @ts-ignore
return Promise.resolve(undefined);
}
}
//#endregion
//#region Update
export class SimpleUpdateService implements IUpdateService {
@@ -571,41 +516,6 @@ registerSingleton(IWindowService, SimpleWindowService);
//#endregion
//#region ExtensionHostDebugService
export class SimpleExtensionHostDebugService extends ExtensionHostDebugChannelClient {
constructor(
@IRemoteAgentService remoteAgentService: IRemoteAgentService,
//@IWindowService windowService: IWindowService,
@IEnvironmentService environmentService: IEnvironmentService
) {
const connection = remoteAgentService.getConnection();
if (!connection) {
throw new Error('Missing agent connection');
}
super(connection.getChannel(ExtensionHostDebugBroadcastChannel.ChannelName));
this._register(this.onReload(event => {
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
//windowService.reloadWindow();
window.location.reload();
}
}));
this._register(this.onClose(event => {
if (environmentService.isExtensionDevelopment && environmentService.debugExtensionHost.debugId === event.sessionId) {
//this._windowService.closeWindow();
window.close();
}
}));
}
}
registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService);
//#endregion
//#region Window
export class SimpleWindowsService implements IWindowsService {
@@ -621,7 +531,10 @@ export class SimpleWindowsService implements IWindowsService {
readonly onRecentlyOpenedChange: Event<void> = Event.None;
constructor(
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService
@IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService,
@IDialogService private readonly dialogService: IDialogService,
@IProductService private readonly productService: IProductService,
@IClipboardService private readonly clipboardService: IClipboardService
) {
}
isFocused(_windowId: number): Promise<boolean> {
@@ -728,6 +641,8 @@ export class SimpleWindowsService implements IWindowsService {
}
relaunch(_options: { addArgs?: string[], removeArgs?: string[] }): Promise<void> {
window.location.reload();
return Promise.resolve();
}
@@ -753,6 +668,15 @@ export class SimpleWindowsService implements IWindowsService {
// we pass the "ParsedArgs" as query parameters of the URL
let newAddress = `${document.location.origin}/?`;
let gotFolder = false;
const addQueryParameter = (key: string, value: string) => {
const lastChar = newAddress.charAt(newAddress.length - 1);
if (lastChar !== '?' && lastChar !== '&') {
newAddress += '&';
}
newAddress += `${key}=${encodeURIComponent(value)}`;
};
const f = args['folder-uri'];
if (f) {
@@ -765,9 +689,14 @@ export class SimpleWindowsService implements IWindowsService {
u = URI.parse(f);
}
if (u) {
newAddress += `folder=${encodeURIComponent(u.path)}`;
gotFolder = true;
addQueryParameter('folder', u.path);
}
}
if (!gotFolder) {
// request empty window
addQueryParameter('ew', 'true');
}
const ep = args['extensionDevelopmentPath'];
if (ep) {
@@ -780,22 +709,24 @@ export class SimpleWindowsService implements IWindowsService {
u = ep;
}
if (u) {
newAddress += `&edp=${encodeURIComponent(u)}`;
addQueryParameter('edp', u);
}
}
const di = args['debugId'];
if (di) {
newAddress += `&di=${encodeURIComponent(di)}`;
addQueryParameter('di', di);
}
const ibe = args['inspect-brk-extensions'];
if (ibe) {
newAddress += `&ibe=${encodeURIComponent(ibe)}`;
addQueryParameter('ibe', ibe);
}
// add connection token
newAddress += `${this.workbenchEnvironmentService.configuration.connectionToken ? `tkn=${this.workbenchEnvironmentService.configuration.connectionToken}` : ''}`;
if (this.workbenchEnvironmentService.configuration.connectionToken) {
addQueryParameter('tkn', this.workbenchEnvironmentService.configuration.connectionToken);
}
window.open(newAddress);
@@ -873,8 +804,20 @@ export class SimpleWindowsService implements IWindowsService {
throw new Error('not implemented');
}
openAboutDialog(): Promise<void> {
return Promise.resolve();
async openAboutDialog(): Promise<void> {
const detail = localize('aboutDetail',
"Version: {0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
this.productService.version || 'Unknown',
this.productService.commit || 'Unknown',
this.productService.date || 'Unknown',
navigator.userAgent
);
const result = await this.dialogService.show(Severity.Info, this.productService.nameLong, [localize('copy', "Copy"), localize('ok', "OK")], { detail });
if (result === 0) {
this.clipboardService.writeText(detail);
}
}
resolveProxy(windowId: number, url: string): Promise<string | undefined> {

View File

@@ -237,7 +237,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'
'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,
'default': true,
'scope': ConfigurationScope.APPLICATION
}
}
@@ -246,7 +246,7 @@ import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'
// Window
let windowTitleDescription = nls.localize('windowTitle', "Controls the window title based on the active editor. Variables are substituted based on the context:");
windowTitleDescription += [
windowTitleDescription += '\n- ' + [
nls.localize('activeEditorShort', "`\${activeEditorShort}`: the file name (e.g. myFile.txt)."),
nls.localize('activeEditorMedium', "`\${activeEditorMedium}`: the path of the file relative to the workspace folder (e.g. myFolder/myFileFolder/myFile.txt)."),
nls.localize('activeEditorLong', "`\${activeEditorLong}`: the full path of the file (e.g. /Users/Development/myFolder/myFileFolder/myFile.txt)."),

View File

@@ -25,7 +25,7 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { LifecyclePhase, ILifecycleService, WillShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecyclePhase, ILifecycleService, WillShutdownEvent, BeforeShutdownEvent } from 'vs/platform/lifecycle/common/lifecycle';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { NotificationService } from 'vs/workbench/services/notification/common/notificationService';
import { NotificationsCenter } from 'vs/workbench/browser/parts/notifications/notificationsCenter';
@@ -47,6 +47,9 @@ import { Layout } from 'vs/workbench/browser/layout';
export class Workbench extends Layout {
private readonly _onBeforeShutdown = this._register(new Emitter<BeforeShutdownEvent>());
readonly onBeforeShutdown: Event<BeforeShutdownEvent> = this._onBeforeShutdown.event;
private readonly _onShutdown = this._register(new Emitter<void>());
readonly onShutdown: Event<void> = this._onShutdown.event;
@@ -182,7 +185,7 @@ export class Workbench extends Layout {
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: DO NOT ADD ANY OTHER SERVICE INTO THE COLLECTION HERE.
// CONTRIBUTE IT VIA WORKBENCH.MAIN.TS AND registerSingleton().
// CONTRIBUTE IT VIA WORKBENCH.DESKTOP.MAIN.TS AND registerSingleton().
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// All Contributed Services
@@ -225,6 +228,7 @@ export class Workbench extends Layout {
): void {
// Lifecycle
this._register(lifecycleService.onBeforeShutdown(event => this._onBeforeShutdown.fire(event)));
this._register(lifecycleService.onWillShutdown(event => this._onWillShutdown.fire(event)));
this._register(lifecycleService.onShutdown(() => {
this._onShutdown.fire();
@@ -238,7 +242,7 @@ export class Workbench extends Layout {
this._register(storageService.onWillSaveState(e => this.storeFontInfo(e, storageService)));
}
private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto';
private fontAliasing: 'default' | 'antialiased' | 'none' | 'auto' | undefined;
private setFontAliasing(configurationService: IConfigurationService) {
const aliasing = configurationService.getValue<'default' | 'antialiased' | 'none' | 'auto'>('workbench.fontAliasing');
if (this.fontAliasing === aliasing) {
@@ -294,10 +298,7 @@ export class Workbench extends Layout {
'monaco-workbench',
platformClass,
isWeb ? 'web' : undefined,
this.state.sideBar.hidden ? 'nosidebar' : undefined,
this.state.panel.hidden ? 'nopanel' : undefined,
this.state.statusBar.hidden ? 'nostatusbar' : undefined,
this.state.fullscreen ? 'fullscreen' : undefined
...this.getLayoutClasses()
]);
addClasses(this.container, ...workbenchClasses);