Update to VS Code 1.52.1

This commit is contained in:
Asher
2021-02-09 16:08:37 +00:00
1351 changed files with 56560 additions and 38990 deletions

View File

@@ -8,7 +8,7 @@ import { Registry } from 'vs/platform/registry/common/platform';
import { Action } from 'vs/base/common/actions';
import { SyncActionDescriptor, MenuId, MenuRegistry, registerAction2, Action2 } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions, CATEGORIES } from 'vs/workbench/common/actions';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IEditorGroupsService, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
@@ -21,7 +21,6 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co
import { InEditorZenModeContext, IsCenteredLayoutContext, EditorAreaVisibleContext } from 'vs/workbench/common/editor';
import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { SideBarVisibleContext } from 'vs/workbench/common/viewlet';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IViewDescriptorService, IViewsService, FocusedViewContext, ViewContainerLocation, IViewDescriptor } from 'vs/workbench/common/views';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { INotificationService } from 'vs/platform/notification/common/notification';
@@ -76,7 +75,7 @@ export class ToggleActivityBarVisibilityAction extends Action2 {
const visibility = layoutService.isVisible(Parts.ACTIVITYBAR_PART);
const newVisibilityValue = !visibility;
configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
configurationService.updateValue(ToggleActivityBarVisibilityAction.activityBarVisibleKey, newVisibilityValue);
}
}
@@ -196,7 +195,7 @@ export class ToggleSidebarPositionAction extends Action {
const position = this.layoutService.getSideBarPosition();
const newPositionValue = (position === Position.LEFT) ? 'right' : 'left';
return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue, ConfigurationTarget.USER);
return this.configurationService.updateValue(ToggleSidebarPositionAction.sidebarPositionConfigurationKey, newPositionValue);
}
static getLabel(layoutService: IWorkbenchLayoutService): string {
@@ -317,7 +316,7 @@ export class ToggleStatusbarVisibilityAction extends Action {
const visibility = this.layoutService.isVisible(Parts.STATUSBAR_PART);
const newVisibilityValue = !visibility;
return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue, ConfigurationTarget.USER);
return this.configurationService.updateValue(ToggleStatusbarVisibilityAction.statusbarVisibleKey, newVisibilityValue);
}
}
@@ -419,14 +418,13 @@ export class ToggleMenuBarAction extends Action {
constructor(
id: string,
label: string,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(id, label);
}
run(): Promise<void> {
let currentVisibilityValue = getMenuBarVisibility(this.configurationService, this.environmentService);
let currentVisibilityValue = getMenuBarVisibility(this.configurationService);
if (typeof currentVisibilityValue !== 'string') {
currentVisibilityValue = 'default';
}

View File

@@ -356,19 +356,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusPreviousPage();
list.reveal(list.getFocus()[0]);
focused.focusPreviousPage();
}
// Tree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
list.focusPreviousPage(fakeKeyboardEvent);
list.reveal(list.getFocus()[0]);
focused.focusPreviousPage(fakeKeyboardEvent);
}
// Ensure DOM Focus
@@ -386,19 +380,13 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// List
if (focused instanceof List || focused instanceof PagedList) {
const list = focused;
list.focusNextPage();
list.reveal(list.getFocus()[0]);
focused.focusNextPage();
}
// Tree
else if (focused instanceof ObjectTree || focused instanceof DataTree || focused instanceof AsyncDataTree) {
const list = focused;
const fakeKeyboardEvent = new KeyboardEvent('keydown');
list.focusNextPage(fakeKeyboardEvent);
list.reveal(list.getFocus()[0]);
focused.focusNextPage(fakeKeyboardEvent);
}
// Ensure DOM Focus

View File

@@ -12,13 +12,10 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IViewlet } from 'vs/workbench/common/viewlet';
import { IPanel } from 'vs/workbench/common/panel';
import { Action2, MenuId, registerAction2, SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { SyncActionDescriptor } from 'vs/platform/actions/common/actions';
import { IWorkbenchActionRegistry, Extensions, CATEGORIES } from 'vs/workbench/common/actions';
import { Direction } from 'vs/base/browser/ui/grid/grid';
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { isAncestor } from 'vs/base/browser/dom';
@@ -275,29 +272,6 @@ export class FocusPreviousPart extends Action {
}
}
class GoHomeContributor implements IWorkbenchContribution {
constructor(
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
) {
const homeIndicator = environmentService.options?.homeIndicator;
if (homeIndicator) {
registerAction2(class extends Action2 {
constructor() {
super({
id: `workbench.actions.goHome`,
title: nls.localize('goHome', "Go Home"),
menu: { id: MenuId.MenubarWebNavigationMenu }
});
}
async run(): Promise<void> {
window.location.href = homeIndicator.href;
}
});
}
}
}
// --- Actions Registration
const actionsRegistry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
@@ -308,9 +282,12 @@ actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateLeftAc
actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NavigateRightAction, undefined), 'View: Navigate to the View on the Right', CATEGORIES.View.value);
actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusNextPart, { primary: KeyCode.F6 }), 'View: Focus Next Part', CATEGORIES.View.value);
actionsRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPreviousPart, { primary: KeyMod.Shift | KeyCode.F6 }), 'View: Focus Previous Part', CATEGORIES.View.value);
<<<<<<< HEAD
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(GoHomeContributor, LifecyclePhase.Ready);
export const _1 = workbenchRegistry;
export const _2 = GoHomeContributor;
export const _3 = LifecyclePhase.Ready;
=======
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775

View File

@@ -141,7 +141,7 @@ export class OpenWorkspaceConfigFileAction extends Action {
async run(): Promise<void> {
const configuration = this.workspaceContextService.getWorkspace().configuration;
if (configuration) {
await this.editorService.openEditor({ resource: configuration });
await this.editorService.openEditor({ resource: configuration, options: { pinned: true } });
}
}
}

View File

@@ -9,7 +9,7 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/commo
import * as resources from 'vs/base/common/resources';
import { CancellationToken } from 'vs/base/common/cancellation';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { CommandsRegistry } from 'vs/platform/commands/common/commands';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { FileKind } from 'vs/platform/files/common/files';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { ILabelService } from 'vs/platform/label/common/label';
@@ -18,6 +18,10 @@ import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { IOpenWindowOptions, IWindowOpenable } from 'vs/platform/windows/common/windows';
import { hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces';
export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder';
export const ADD_ROOT_FOLDER_LABEL = nls.localize('addFolderToWorkspace', "Add Folder to Workspace...");
@@ -61,7 +65,7 @@ CommandsRegistry.registerCommand({
title: nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"),
canSelectFolders: true,
canSelectMany: true,
defaultUri: dialogsService.defaultFolderPath()
defaultUri: await dialogsService.defaultFolderPath()
});
if (!folders || !folders.length) {
@@ -116,3 +120,46 @@ CommandsRegistry.registerCommand(PICK_WORKSPACE_FOLDER_COMMAND_ID, async functio
return;
});
// API Command registration
interface IOpenFolderAPICommandOptions {
forceNewWindow?: boolean;
forceReuseWindow?: boolean;
noRecentEntry?: boolean;
}
CommandsRegistry.registerCommand({
id: 'vscode.openFolder',
handler: (accessor: ServicesAccessor, uri?: URI, arg?: boolean | IOpenFolderAPICommandOptions) => {
const commandService = accessor.get(ICommandService);
// Be compatible to previous args by converting to options
if (typeof arg === 'boolean') {
arg = { forceNewWindow: arg };
}
// Without URI, ask to pick a folder or workpsace to open
if (!uri) {
return commandService.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg?.forceNewWindow });
}
uri = URI.revive(uri);
const options: IOpenWindowOptions = {
forceNewWindow: arg?.forceNewWindow,
forceReuseWindow: arg?.forceReuseWindow,
noRecentEntry: arg?.noRecentEntry
};
const uriToOpen: IWindowOpenable = (hasWorkspaceFileExtension(uri) || uri.scheme === Schemas.untitled) ? { workspaceUri: uri } : { folderUri: uri };
return commandService.executeCommand('_files.windowOpen', [uriToOpen], options);
},
description: {
description: 'Open a folder or workspace in the current window or new window depending on the newWindow argument. Note that opening in the same window will shutdown the current extension host process and start a new one on the given folder/workspace unless the newWindow parameter is set to true.',
args: [
{ name: 'uri', description: '(optional) Uri of the folder or workspace file to open. If not provided, a native dialog will ask the user for the folder', constraint: (value: any) => value === undefined || value instanceof URI },
{ name: 'options', description: '(optional) Options. Object with the following properties: `forceNewWindow `: Whether to open the folder/workspace in a new window or the same. Defaults to opening in the same window. `noRecentEntry`: Wheter the opened URI will appear in the \'Open Recent\' list. Defaults to true. Note, for backward compatibility, options can also be of type boolean, representing the `forceNewWindow` setting.', constraint: (value: any) => value === undefined || typeof value === 'object' || typeof value === 'boolean' }
]
}
});

View File

@@ -16,7 +16,7 @@ import { DataTransfers, IDragAndDropData } from 'vs/base/browser/dnd';
import { DragMouseEvent } from 'vs/base/browser/mouseEvent';
import { normalizeDriveLetter } from 'vs/base/common/labels';
import { MIME_BINARY } from 'vs/base/common/mime';
import { isWindows, isWeb } from 'vs/base/common/platform';
import { isWindows } from 'vs/base/common/platform';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { isCodeEditor } from 'vs/editor/browser/editorBrowser';
import { IEditorIdentifier, GroupIdentifier } from 'vs/workbench/common/editor';
@@ -27,7 +27,6 @@ import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsSe
import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing';
import { withNullAsUndefined } from 'vs/base/common/types';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { isStandalone } from 'vs/base/browser/browser';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { Emitter } from 'vs/base/common/event';
@@ -320,8 +319,7 @@ export function fillResourceDataTransfers(accessor: ServicesAccessor, resources:
event.dataTransfer.setData(DataTransfers.TEXT, sources.map(source => source.resource.scheme === Schemas.file ? normalize(normalizeDriveLetter(source.resource.fsPath)) : source.resource.toString()).join(lineDelimiter));
// Download URL: enables support to drag a tab as file to desktop (only single file supported)
// Disabled for PWA web due to: https://github.com/microsoft/vscode/issues/83441
if (!sources[0].isDirectory && (!isWeb || !isStandalone)) {
if (!sources[0].isDirectory) {
event.dataTransfer.setData(DataTransfers.DOWNLOAD_URL, [MIME_BINARY, basename(sources[0].resource), FileAccess.asBrowserUri(sources[0].resource).toString()].join(':'));
}

View File

@@ -5,7 +5,7 @@
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Emitter } from 'vs/base/common/event';
import { EventType, addDisposableListener, isAncestor, getClientArea, Dimension, position, size, IDimension } from 'vs/base/browser/dom';
import { EventType, addDisposableListener, getClientArea, Dimension, position, size, IDimension, isAncestorUsingFlowTo } from 'vs/base/browser/dom';
import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser';
import { IBackupFileService } from 'vs/workbench/services/backup/common/backup';
import { Registry } from 'vs/platform/registry/common/platform';
@@ -16,7 +16,7 @@ import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart';
import { PanelRegistry, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
import { Position, Parts, PanelOpensMaximizedOptions, IWorkbenchLayoutService, positionFromString, positionToString, panelOpensMaximizedFromString } from 'vs/workbench/services/layout/browser/layoutService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget, WillSaveStateReason } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
@@ -41,7 +41,6 @@ import { INotificationService, NotificationsFilter } from 'vs/platform/notificat
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { WINDOW_ACTIVE_BORDER, WINDOW_INACTIVE_BORDER } from 'vs/workbench/common/theme';
import { LineNumbersType } from 'vs/editor/common/config/editorOptions';
import { ActivitybarPart } from 'vs/workbench/browser/parts/activitybar/activitybarPart';
import { URI } from 'vs/base/common/uri';
import { IViewDescriptorService, ViewContainerLocation } from 'vs/workbench/common/views';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
@@ -91,21 +90,6 @@ enum Classes {
WINDOW_BORDER = 'border'
}
interface PanelActivityState {
id: string;
name?: string;
pinned: boolean;
order: number;
visible: boolean;
}
interface SideBarActivityState {
id: string;
pinned: boolean;
order: number;
visible: boolean;
}
export abstract class Layout extends Disposable implements IWorkbenchLayoutService {
declare readonly _serviceBrand: undefined;
@@ -319,7 +303,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this._register(addDisposableListener(this.container, EventType.SCROLL, () => this.container.scrollTop = 0));
// Menubar visibility changes
if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
if ((isWindows || isLinux || isWeb) && getTitleBarStyle(this.configurationService) === 'custom') {
this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible)));
}
@@ -357,8 +341,11 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
}
// Change edge snapping accordingly
this.workbenchGrid.edgeSnapping = this.state.fullscreen;
// 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') {
if (getTitleBarStyle(this.configurationService) === 'custom') {
// Propagate to grid
this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART));
@@ -407,7 +394,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
// Menubar visibility
const newMenubarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
const newMenubarVisibility = getMenuBarVisibility(this.configurationService);
this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
// Centered Layout
@@ -451,7 +438,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
private updateWindowBorder(skipLayout: boolean = false) {
if (isWeb || getTitleBarStyle(this.configurationService, this.environmentService) !== 'custom') {
if (isWeb || getTitleBarStyle(this.configurationService) !== 'custom') {
return;
}
@@ -495,7 +482,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.fullscreen = isFullscreen();
// Menubar visibility
this.state.menuBar.visibility = getMenuBarVisibility(this.configurationService, this.environmentService);
this.state.menuBar.visibility = getMenuBarVisibility(this.configurationService);
// Activity bar visibility
this.state.activityBar.hidden = !this.configurationService.getValue<string>(Settings.ACTIVITYBAR_VISIBLE);
@@ -582,167 +569,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const { views } = defaultLayout;
if (views?.length) {
this.state.views.defaults = views.map(v => v.id);
return;
}
// TODO@eamodio Everything below here is deprecated and will be removed once Codespaces migrates
const { sidebar } = defaultLayout;
if (sidebar) {
if (sidebar.visible !== undefined) {
if (sidebar.visible) {
storageService.remove(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE);
} else {
storageService.store(Storage.SIDEBAR_HIDDEN, true, StorageScope.WORKSPACE);
}
}
if (sidebar.containers?.length) {
const sidebarState: SideBarActivityState[] = [];
let order = -1;
for (const container of sidebar.containers.sort((a, b) => (a.order ?? 1) - (b.order ?? 1))) {
let viewletId;
switch (container.id) {
case 'explorer':
viewletId = 'workbench.view.explorer';
break;
case 'run':
viewletId = 'workbench.view.debug';
break;
case 'scm':
viewletId = 'workbench.view.scm';
break;
case 'search':
viewletId = 'workbench.view.search';
break;
case 'extensions':
viewletId = 'workbench.view.extensions';
break;
case 'remote':
viewletId = 'workbench.view.remote';
break;
default:
viewletId = `workbench.view.extension.${container.id}`;
}
if (container.active) {
storageService.store(SidebarPart.activeViewletSettingsKey, viewletId, StorageScope.WORKSPACE);
}
if (container.order !== undefined || (container.active === undefined && container.visible !== undefined)) {
order = container.order ?? (order + 1);
const state: SideBarActivityState = {
id: viewletId,
order: order,
pinned: (container.active || container.visible) ?? true,
visible: (container.active || container.visible) ?? true
};
sidebarState.push(state);
}
if (container.views !== undefined) {
const viewsState: { id: string, isHidden?: boolean, order?: number }[] = [];
const viewsWorkspaceState: { [id: string]: { collapsed: boolean, isHidden?: boolean, size?: number } } = {};
for (const view of container.views) {
if (view.order !== undefined || view.visible !== undefined) {
viewsState.push({
id: view.id,
isHidden: view.visible === undefined ? undefined : !view.visible,
order: view.order === undefined ? undefined : view.order
});
}
if (view.collapsed !== undefined) {
viewsWorkspaceState[view.id] = {
collapsed: view.collapsed,
isHidden: view.visible === undefined ? undefined : !view.visible,
};
}
}
storageService.store(`${viewletId}.state.hidden`, JSON.stringify(viewsState), StorageScope.GLOBAL);
storageService.store(`${viewletId}.state`, JSON.stringify(viewsWorkspaceState), StorageScope.WORKSPACE);
}
}
if (sidebarState.length) {
storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, JSON.stringify(sidebarState), StorageScope.GLOBAL);
}
}
}
const { panel } = defaultLayout;
if (panel) {
if (panel.visible !== undefined) {
if (panel.visible) {
storageService.store(Storage.PANEL_HIDDEN, false, StorageScope.WORKSPACE);
} else {
storageService.remove(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE);
}
}
if (panel.containers?.length) {
const panelState: PanelActivityState[] = [];
let order = -1;
for (const container of panel.containers.sort((a, b) => (a.order ?? 1) - (b.order ?? 1))) {
let name;
let panelId = container.id;
switch (panelId) {
case 'terminal':
name = 'Terminal';
panelId = 'workbench.panel.terminal';
break;
case 'debug':
name = 'Debug Console';
panelId = 'workbench.panel.repl';
break;
case 'problems':
name = 'Problems';
panelId = 'workbench.panel.markers';
break;
case 'output':
name = 'Output';
panelId = 'workbench.panel.output';
break;
case 'comments':
name = 'Comments';
panelId = 'workbench.panel.comments';
break;
case 'refactor':
name = 'Refactor Preview';
panelId = 'refactorPreview';
break;
default:
continue;
}
if (container.active) {
storageService.store(PanelPart.activePanelSettingsKey, panelId, StorageScope.WORKSPACE);
}
if (container.order !== undefined || (container.active === undefined && container.visible !== undefined)) {
order = container.order ?? (order + 1);
const state: PanelActivityState = {
id: panelId,
name: name,
order: order,
pinned: (container.active || container.visible) ?? true,
visible: (container.active || container.visible) ?? true
};
panelState.push(state);
}
}
if (panelState.length) {
storageService.store(PanelPart.PINNED_PANELS, JSON.stringify(panelState), StorageScope.GLOBAL);
}
}
}
}
@@ -750,7 +576,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const initialFilesToOpen = this.getInitialFilesToOpen();
// Only restore editors if we are not instructed to open files initially
this.state.editor.restoreEditors = initialFilesToOpen === undefined;
// or when `window.restoreWindows` setting is explicitly set to `preserve`
const forceRestoreEditors = this.configurationService.getValue<string>('window.restoreWindows') === 'preserve';
this.state.editor.restoreEditors = !!forceRestoreEditors || initialFilesToOpen === undefined;
// Files to open, diff or create
if (initialFilesToOpen !== undefined) {
@@ -996,7 +824,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
const container = this.getContainer(part);
return !!container && isAncestor(activeElement, container);
return !!container && isAncestorUsingFlowTo(activeElement, container);
}
focusPart(part: Parts): void {
@@ -1050,7 +878,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
isVisible(part: Parts): boolean {
switch (part) {
case Parts.TITLEBAR_PART:
if (getTitleBarStyle(this.configurationService, this.environmentService) === 'native') {
if (getTitleBarStyle(this.configurationService) === 'native') {
return false;
} else if (!this.state.fullscreen && !isWeb) {
return true;
@@ -1246,7 +1074,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// State
if (this.state.zenMode.active) {
this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE);
this.storageService.store(Storage.ZEN_MODE_ENABLED, true, StorageScope.WORKSPACE, StorageTarget.USER);
// Exit zen mode on shutdown unless configured to keep
this.state.zenMode.transitionDisposables.add(this.storageService.onWillSaveState(e => {
@@ -1310,6 +1138,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.container.prepend(workbenchGrid.element);
this.container.setAttribute('role', 'application');
this.workbenchGrid = workbenchGrid;
this.workbenchGrid.edgeSnapping = this.state.fullscreen;
[titleBar, editorPart, activityBar, panelPart, sideBar, statusBar].forEach((part: Part) => {
this._register(part.onDidVisibilityChange((visible) => {
@@ -1331,18 +1160,18 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
? grid.getViewCachedVisibleSize(this.sideBarPartView)
: grid.getViewSize(this.sideBarPartView).width;
this.storageService.store(Storage.SIDEBAR_SIZE, sideBarSize, StorageScope.GLOBAL);
this.storageService.store(Storage.SIDEBAR_SIZE, sideBarSize, StorageScope.GLOBAL, StorageTarget.MACHINE);
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);
this.storageService.store(Storage.PANEL_DIMENSION, positionToString(this.state.panel.position), StorageScope.GLOBAL);
this.storageService.store(Storage.PANEL_SIZE, panelSize, StorageScope.GLOBAL, StorageTarget.MACHINE);
this.storageService.store(Storage.PANEL_DIMENSION, positionToString(this.state.panel.position), StorageScope.GLOBAL, StorageTarget.MACHINE);
const gridSize = grid.getViewSize();
this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL);
this.storageService.store(Storage.GRID_HEIGHT, gridSize.height, StorageScope.GLOBAL);
this.storageService.store(Storage.GRID_WIDTH, gridSize.width, StorageScope.GLOBAL, StorageTarget.MACHINE);
this.storageService.store(Storage.GRID_HEIGHT, gridSize.height, StorageScope.GLOBAL, StorageTarget.MACHINE);
}));
}
@@ -1373,7 +1202,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
centerEditorLayout(active: boolean, skipLayout?: boolean): void {
this.state.editor.centered = active;
this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE);
this.storageService.store(Storage.CENTERED_LAYOUT_ENABLED, active, StorageScope.WORKSPACE, StorageTarget.USER);
let smartActive = active;
const activeEditor = this.editorService.activeEditor;
@@ -1486,7 +1315,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Remember in settings
if (hidden) {
this.storageService.store(Storage.EDITOR_HIDDEN, true, StorageScope.WORKSPACE);
this.storageService.store(Storage.EDITOR_HIDDEN, true, StorageScope.WORKSPACE, StorageTarget.USER);
} else {
this.storageService.remove(Storage.EDITOR_HIDDEN, StorageScope.WORKSPACE);
}
@@ -1547,7 +1376,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
// Remember in settings
const defaultHidden = this.contextService.getWorkbenchState() === WorkbenchState.EMPTY;
if (hidden !== defaultHidden) {
this.storageService.store(Storage.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE);
this.storageService.store(Storage.SIDEBAR_HIDDEN, hidden ? 'true' : 'false', StorageScope.WORKSPACE, StorageTarget.USER);
} else {
this.storageService.remove(Storage.SIDEBAR_HIDDEN, StorageScope.WORKSPACE);
}
@@ -1612,14 +1441,14 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
}
// Remember in settings
if (!hidden) {
this.storageService.store(Storage.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE);
this.storageService.store(Storage.PANEL_HIDDEN, 'false', StorageScope.WORKSPACE, StorageTarget.USER);
}
else {
this.storageService.remove(Storage.PANEL_HIDDEN, StorageScope.WORKSPACE);
// Remember this setting only when panel is hiding
if (this.state.panel.wasLastMaximized) {
this.storageService.store(Storage.PANEL_LAST_IS_MAXIMIZED, true, StorageScope.WORKSPACE);
this.storageService.store(Storage.PANEL_LAST_IS_MAXIMIZED, true, StorageScope.WORKSPACE, StorageTarget.USER);
}
else {
this.storageService.remove(Storage.PANEL_LAST_IS_MAXIMIZED, StorageScope.WORKSPACE);
@@ -1637,10 +1466,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
if (!this.state.panel.hidden) {
if (this.state.panel.position === Position.BOTTOM) {
this.state.panel.lastNonMaximizedHeight = size.height;
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_HEIGHT, this.state.panel.lastNonMaximizedHeight, StorageScope.GLOBAL);
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_HEIGHT, this.state.panel.lastNonMaximizedHeight, StorageScope.GLOBAL, StorageTarget.MACHINE);
} else {
this.state.panel.lastNonMaximizedWidth = size.width;
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_WIDTH, this.state.panel.lastNonMaximizedWidth, StorageScope.GLOBAL);
this.storageService.store(Storage.PANEL_LAST_NON_MAXIMIZED_WIDTH, this.state.panel.lastNonMaximizedWidth, StorageScope.GLOBAL, StorageTarget.MACHINE);
}
}
@@ -1715,7 +1544,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
this.state.panel.position = position;
// Save panel position
this.storageService.store(Storage.PANEL_POSITION, newPositionValue, StorageScope.WORKSPACE);
this.storageService.store(Storage.PANEL_POSITION, newPositionValue, StorageScope.WORKSPACE, StorageTarget.USER);
// Adjust CSS
const panelContainer = assertIsDefined(panelPart.getContainer());

View File

@@ -220,6 +220,10 @@ body.web {
opacity: 1 !important;
}
.monaco-workbench input[type="checkbox"]:focus {
outline-offset: 2px;
}
.monaco-workbench [tabindex="0"]:active,
.monaco-workbench [tabindex="-1"]:active,
.monaco-workbench select:active,

View File

@@ -10,15 +10,14 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { Action, IAction, Separator, SubmenuAction } from 'vs/base/common/actions';
import { KeyCode } from 'vs/base/common/keyCodes';
import { dispose } from 'vs/base/common/lifecycle';
import { SyncActionDescriptor, IMenuService, MenuId, IMenu } from 'vs/platform/actions/common/actions';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IMenuService, MenuId, IMenu, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Registry } from 'vs/platform/registry/common/platform';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { activeContrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { ICssStyleCollector, IColorTheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { ActivityAction, ActivityActionViewItem, ICompositeBar, ICompositeBarColors, ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
import { CATEGORIES, Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { IActivity } from 'vs/workbench/common/activity';
import { ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_ACTIVE_FOCUS_BORDER, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_BACKGROUND } from 'vs/workbench/common/theme';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
@@ -26,44 +25,31 @@ import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/bro
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { Codicon } from 'vs/base/common/codicons';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isWeb } from 'vs/base/common/platform';
import { getCurrentAuthenticationSessionInfo, IAuthenticationService } from 'vs/workbench/services/authentication/browser/authenticationService';
import { AuthenticationSession } from 'vs/editor/common/modes';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionViewItems';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IProductService } from 'vs/platform/product/common/productService';
import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { AnchorAlignment, AnchorAxisAlignment } from 'vs/base/browser/ui/contextview/contextview';
import { getTitleBarStyle } from 'vs/platform/windows/common/windows';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
export class ViewContainerActivityAction extends ActivityAction {
private static readonly preventDoubleClickDelay = 300;
private readonly viewletService: IViewletService;
private readonly layoutService: IWorkbenchLayoutService;
private readonly telemetryService: ITelemetryService;
private readonly configurationService: IConfigurationService;
private lastRun: number;
private lastRun = 0;
constructor(
activity: IActivity,
@IViewletService viewletService: IViewletService,
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@ITelemetryService telemetryService: ITelemetryService,
@IConfigurationService configurationService: IConfigurationService
@IViewletService private readonly viewletService: IViewletService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IConfigurationService private readonly configurationService: IConfigurationService
) {
super(activity);
this.lastRun = 0;
this.viewletService = viewletService;
this.layoutService = layoutService;
this.telemetryService = telemetryService;
this.configurationService = configurationService;
}
updateActivity(activity: IActivity): void {
@@ -105,6 +91,7 @@ export class ViewContainerActivityAction extends ActivityAction {
this.logAction('show');
await this.viewletService.openViewlet(this.activity.id, true);
return this.activate();
}
@@ -117,21 +104,18 @@ export class ViewContainerActivityAction extends ActivityAction {
}
}
export const ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
class MenuActivityActionViewItem extends ActivityActionViewItem {
export class AccountsActionViewItem extends ActivityActionViewItem {
constructor(
private readonly menuId: MenuId,
action: ActivityAction,
colors: (theme: IColorTheme) => ICompositeBarColors,
@IThemeService themeService: IThemeService,
@IContextMenuService protected contextMenuService: IContextMenuService,
@IMenuService protected menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IStorageService private readonly storageService: IStorageService,
@IProductService private readonly productService: IProductService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IMenuService protected readonly menuService: IMenuService,
@IContextMenuService protected readonly contextMenuService: IContextMenuService,
@IContextKeyService protected readonly contextKeyService: IContextKeyService,
@IConfigurationService protected readonly configurationService: IConfigurationService,
@IWorkbenchEnvironmentService protected readonly environmentService: IWorkbenchEnvironmentService
) {
super(action, { draggable: false, colors, icon: true }, themeService);
}
@@ -161,12 +145,103 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
}));
}
private async getActions(accountsMenu: IMenu) {
protected async showContextMenu(e?: MouseEvent): Promise<void> {
const disposables = new DisposableStore();
const menu = disposables.add(this.menuService.createMenu(this.menuId, this.contextKeyService));
const actions = await this.resolveActions(menu, disposables);
const isUsingCustomMenu = isWeb || (getTitleBarStyle(this.configurationService) !== 'native' && !isMacintosh); // see #40262
const position = this.configurationService.getValue('workbench.sideBar.location');
this.contextMenuService.showContextMenu({
getAnchor: () => isUsingCustomMenu ? this.container : e || this.container,
anchorAlignment: isUsingCustomMenu ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
anchorAxisAlignment: isUsingCustomMenu ? AnchorAxisAlignment.HORIZONTAL : AnchorAxisAlignment.VERTICAL,
getActions: () => actions,
onHide: () => disposables.dispose()
});
}
protected async resolveActions(menu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
const actions: IAction[] = [];
disposables.add(createAndFillInActionBarActions(menu, undefined, { primary: [], secondary: actions }));
return actions;
}
}
export class HomeActivityActionViewItem extends MenuActivityActionViewItem {
static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
constructor(
private readonly goHomeHref: string,
action: ActivityAction,
colors: (theme: IColorTheme) => ICompositeBarColors,
@IThemeService themeService: IThemeService,
@IMenuService menuService: IMenuService,
@IContextMenuService contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IStorageService private readonly storageService: IStorageService
) {
super(MenuId.MenubarHomeMenu, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
}
protected async resolveActions(homeMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
const actions = [];
// Go Home
actions.push(disposables.add(new Action('goHome', nls.localize('goHome', "Go Home"), undefined, true, async () => window.location.href = this.goHomeHref)));
actions.push(disposables.add(new Separator()));
// Contributed
const contributedActions = await super.resolveActions(homeMenu, disposables);
actions.push(...contributedActions);
// Hide
if (contributedActions.length > 0) {
actions.push(disposables.add(new Separator()));
}
actions.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => {
this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, false, StorageScope.GLOBAL, StorageTarget.USER);
})));
return actions;
}
}
export class AccountsActivityActionViewItem extends MenuActivityActionViewItem {
static readonly ACCOUNTS_VISIBILITY_PREFERENCE_KEY = 'workbench.activity.showAccounts';
constructor(
action: ActivityAction,
colors: (theme: IColorTheme) => ICompositeBarColors,
@IThemeService themeService: IThemeService,
@IContextMenuService contextMenuService: IContextMenuService,
@IMenuService menuService: IMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IAuthenticationService private readonly authenticationService: IAuthenticationService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IStorageService private readonly storageService: IStorageService,
@IProductService private readonly productService: IProductService,
@IConfigurationService configurationService: IConfigurationService,
) {
super(MenuId.AccountsContext, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
}
protected async resolveActions(accountsMenu: IMenu, disposables: DisposableStore): Promise<IAction[]> {
await super.resolveActions(accountsMenu, disposables);
const otherCommands = accountsMenu.getActions();
const providers = this.authenticationService.getProviderIds();
const allSessions = providers.map(async id => {
const allSessions = providers.map(async providerId => {
try {
const sessions = await this.authenticationService.getSessions(id);
const sessions = await this.authenticationService.getSessions(providerId);
const groupedSessions: { [label: string]: AuthenticationSession[] } = {};
sessions.forEach(session => {
@@ -177,14 +252,9 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
}
});
return {
providerId: id,
sessions: groupedSessions
};
return { providerId, sessions: groupedSessions };
} catch {
return {
providerId: id
};
return { providerId };
}
});
@@ -196,132 +266,67 @@ export class AccountsActionViewItem extends ActivityActionViewItem {
if (sessionInfo.sessions) {
Object.keys(sessionInfo.sessions).forEach(accountName => {
const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id));
const manageExtensionsAction = new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, _ => {
const manageExtensionsAction = disposables.add(new Action(`configureSessions${accountName}`, nls.localize('manageTrustedExtensions', "Manage Trusted Extensions"), '', true, () => {
return this.authenticationService.manageTrustedExtensionsForAccount(sessionInfo.providerId, accountName);
});
const signOutAction = new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, _ => {
return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName);
});
}));
const actions = [manageExtensionsAction];
const signOutAction = disposables.add(new Action('signOut', nls.localize('signOut', "Sign Out"), '', true, () => {
return this.authenticationService.signOutOfAccount(sessionInfo.providerId, accountName);
}));
const providerSubMenuActions = [manageExtensionsAction];
const hasEmbedderAccountSession = sessionInfo.sessions[accountName].some(session => session.id === (authenticationSession?.id));
if (!hasEmbedderAccountSession || authenticationSession?.canSignOut) {
actions.push(signOutAction);
providerSubMenuActions.push(signOutAction);
}
const menu = new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, actions);
menus.push(menu);
const providerSubMenu = disposables.add(new SubmenuAction('activitybar.submenu', `${accountName} (${providerDisplayName})`, providerSubMenuActions));
menus.push(providerSubMenu);
});
} else {
const menu = new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName));
menus.push(menu);
const providerUnavailableAction = disposables.add(new Action('providerUnavailable', nls.localize('authProviderUnavailable', '{0} is currently unavailable', providerDisplayName)));
menus.push(providerUnavailableAction);
}
});
if (menus.length && otherCommands.length) {
menus.push(new Separator());
menus.push(disposables.add(new Separator()));
}
otherCommands.forEach((group, i) => {
const actions = group[1];
menus = menus.concat(actions);
if (i !== otherCommands.length - 1) {
menus.push(new Separator());
menus.push(disposables.add(new Separator()));
}
});
if (menus.length) {
menus.push(new Separator());
menus.push(disposables.add(new Separator()));
}
menus.push(new Action('hide', nls.localize('hide', "Hide"), undefined, true, _ => {
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL);
return Promise.resolve();
}));
menus.push(disposables.add(new Action('hide', nls.localize('hide', "Hide"), undefined, true, async () => {
this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, false, StorageScope.GLOBAL, StorageTarget.USER);
})));
return menus;
}
private async showContextMenu(e?: MouseEvent): Promise<void> {
const accountsActions: IAction[] = [];
const accountsMenu = this.menuService.createMenu(MenuId.AccountsContext, this.contextKeyService);
const actionsDisposable = createAndFillInActionBarActions(accountsMenu, undefined, { primary: [], secondary: accountsActions });
const native = getTitleBarStyle(this.configurationService, this.environmentService) === 'native';
const position = this.configurationService.getValue('workbench.sideBar.location');
const containerPosition = DOM.getDomNodePagePosition(this.container);
const location = { x: containerPosition.left + (position === 'left' ? containerPosition.width : 0), y: containerPosition.top };
const actions = await this.getActions(accountsMenu);
this.contextMenuService.showContextMenu({
getAnchor: () => !native ? location : e || this.container,
anchorAlignment: !native ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
getActions: () => actions,
onHide: () => {
accountsMenu.dispose();
dispose(actionsDisposable);
}
});
}
}
export class GlobalActivityActionViewItem extends ActivityActionViewItem {
export class GlobalActivityActionViewItem extends MenuActivityActionViewItem {
constructor(
action: ActivityAction,
colors: (theme: IColorTheme) => ICompositeBarColors,
@IThemeService themeService: IThemeService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService protected readonly contextMenuService: IContextMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IEnvironmentService private readonly environmentService: IEnvironmentService
@IMenuService menuService: IMenuService,
@IContextMenuService contextMenuService: IContextMenuService,
@IContextKeyService contextKeyService: IContextKeyService,
@IConfigurationService configurationService: IConfigurationService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService
) {
super(action, { draggable: false, colors, icon: true }, themeService);
}
render(container: HTMLElement): void {
super.render(container);
// Context menus are triggered on mouse down so that an item can be picked
// and executed with releasing the mouse over it
this._register(DOM.addDisposableListener(this.container, DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => {
DOM.EventHelper.stop(e, true);
this.showContextMenu(e);
}));
this._register(DOM.addDisposableListener(this.container, DOM.EventType.KEY_UP, (e: KeyboardEvent) => {
let event = new StandardKeyboardEvent(e);
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
DOM.EventHelper.stop(e, true);
this.showContextMenu();
}
}));
this._register(DOM.addDisposableListener(this.container, TouchEventType.Tap, (e: GestureEvent) => {
DOM.EventHelper.stop(e, true);
this.showContextMenu();
}));
}
private showContextMenu(e?: MouseEvent): void {
const globalActivityActions: IAction[] = [];
const globalActivityMenu = this.menuService.createMenu(MenuId.GlobalActivity, this.contextKeyService);
const actionsDisposable = createAndFillInActionBarActions(globalActivityMenu, undefined, { primary: [], secondary: globalActivityActions });
const native = getTitleBarStyle(this.configurationService, this.environmentService) === 'native';
const position = this.configurationService.getValue('workbench.sideBar.location');
const containerPosition = DOM.getDomNodePagePosition(this.container);
const location = { x: containerPosition.left + (position === 'left' ? containerPosition.width : 0), y: containerPosition.top + containerPosition.height };
this.contextMenuService.showContextMenu({
getAnchor: () => !native ? location : e || this.container,
anchorAlignment: !native ? (position === 'left' ? AnchorAlignment.RIGHT : AnchorAlignment.LEFT) : undefined,
getActions: () => globalActivityActions,
onHide: () => {
globalActivityMenu.dispose();
dispose(actionsDisposable);
}
});
super(MenuId.GlobalActivity, action, colors, themeService, menuService, contextMenuService, contextKeyService, configurationService, environmentService);
}
}
@@ -338,106 +343,62 @@ export class PlaceHolderToggleCompositePinnedAction extends ToggleCompositePinne
}
}
class SwitchSideBarViewAction extends Action {
class SwitchSideBarViewAction extends Action2 {
constructor(
id: string,
name: string,
@IViewletService private readonly viewletService: IViewletService,
@IActivityBarService private readonly activityBarService: IActivityBarService
desc: Readonly<IAction2Options>,
private readonly offset: number
) {
super(id, name);
super(desc);
}
async run(offset: number): Promise<void> {
const visibleViewletIds = this.activityBarService.getVisibleViewContainerIds();
async run(accessor: ServicesAccessor): Promise<void> {
const activityBarService = accessor.get(IActivityBarService);
const viewletService = accessor.get(IViewletService);
const activeViewlet = this.viewletService.getActiveViewlet();
const visibleViewletIds = activityBarService.getVisibleViewContainerIds();
const activeViewlet = viewletService.getActiveViewlet();
if (!activeViewlet) {
return;
}
let targetViewletId: string | undefined;
for (let i = 0; i < visibleViewletIds.length; i++) {
if (visibleViewletIds[i] === activeViewlet.getId()) {
targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + offset) % visibleViewletIds.length];
targetViewletId = visibleViewletIds[(i + visibleViewletIds.length + this.offset) % visibleViewletIds.length];
break;
}
}
await this.viewletService.openViewlet(targetViewletId, true);
await viewletService.openViewlet(targetViewletId, true);
}
}
export class PreviousSideBarViewAction extends SwitchSideBarViewAction {
static readonly ID = 'workbench.action.previousSideBarView';
static readonly LABEL = nls.localize('previousSideBarView', 'Previous Side Bar View');
constructor(
id: string,
name: string,
@IViewletService viewletService: IViewletService,
@IActivityBarService activityBarService: IActivityBarService
) {
super(id, name, viewletService, activityBarService);
}
run(): Promise<void> {
return super.run(-1);
}
}
export class NextSideBarViewAction extends SwitchSideBarViewAction {
static readonly ID = 'workbench.action.nextSideBarView';
static readonly LABEL = nls.localize('nextSideBarView', 'Next Side Bar View');
constructor(
id: string,
name: string,
@IViewletService viewletService: IViewletService,
@IActivityBarService activityBarService: IActivityBarService
) {
super(id, name, viewletService, activityBarService);
}
run(): Promise<void> {
return super.run(1);
}
}
export class HomeAction extends Action {
constructor(
private readonly href: string,
name: string,
icon: Codicon
) {
super('workbench.action.home', name, icon.classNames);
}
async run(event: MouseEvent): Promise<void> {
let openInNewWindow = false;
if (isMacintosh) {
openInNewWindow = event.metaKey;
} else {
openInNewWindow = event.ctrlKey;
}
if (openInNewWindow) {
DOM.windowOpenNoOpener(this.href);
} else {
window.location.href = this.href;
registerAction2(
class PreviousSideBarViewAction extends SwitchSideBarViewAction {
constructor() {
super({
id: 'workbench.action.previousSideBarView',
title: { value: nls.localize('previousSideBarView', "Previous Side Bar View"), original: 'Previous Side Bar View' },
category: CATEGORIES.View,
f1: true
}, -1);
}
}
}
);
export class HomeActionViewItem extends ActionViewItem {
constructor(action: IAction) {
super(undefined, action, { icon: true, label: false, useEventAsContext: true });
registerAction2(
class NextSideBarViewAction extends SwitchSideBarViewAction {
constructor() {
super({
id: 'workbench.action.nextSideBarView',
title: { value: nls.localize('nextSideBarView', "Next Side Bar View"), original: 'Next Side Bar View' },
category: CATEGORIES.View,
f1: true
}, 1);
}
}
}
);
registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) => {
const activityBarBackgroundColor = theme.getColor(ACTIVITY_BAR_BACKGROUND);
@@ -510,6 +471,7 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
left: 9px;
height: 32px;
width: 32px;
z-index: 1;
}
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.active:before,
@@ -549,7 +511,3 @@ registerThemingParticipant((theme: IColorTheme, collector: ICssStyleCollector) =
}
}
});
const registry = Registry.as<IWorkbenchActionRegistry>(ActionExtensions.WorkbenchActions);
registry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousSideBarViewAction), 'View: Previous Side Bar View', CATEGORIES.View.value);
registry.registerWorkbenchAction(SyncActionDescriptor.from(NextSideBarViewAction), 'View: Next Side Bar View', CATEGORIES.View.value);

View File

@@ -8,24 +8,24 @@ import * as nls from 'vs/nls';
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIVITY_ID } from 'vs/workbench/common/activity';
import { Part } from 'vs/workbench/browser/part';
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction, HomeActionViewItem, ACCOUNTS_VISIBILITY_PREFERENCE_KEY } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActivityActionViewItem, HomeActivityActionViewItem } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { ToggleActivityBarVisibilityAction, ToggleMenuBarAction, ToggleSidebarPositionAction } from 'vs/workbench/browser/actions/layoutActions';
import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService';
import { IThemeService, IColorTheme, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND, ACTIVITY_BAR_ACTIVE_BORDER, ACTIVITY_BAR_BADGE_BACKGROUND, ACTIVITY_BAR_BADGE_FOREGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND, ACTIVITY_BAR_DRAG_AND_DROP_BORDER } from 'vs/workbench/common/theme';
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
import { Dimension, createCSSRule, asCSSUrl, addDisposableListener, EventType } from 'vs/base/browser/dom';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity } from 'vs/workbench/browser/parts/compositeBarActions';
import { IViewDescriptorService, ViewContainer, TEST_VIEW_CONTAINER_ID, IViewContainerModel, ViewContainerLocation, IViewsService } from 'vs/workbench/common/views';
import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { isUndefinedOrNull, assertIsDefined, isString } from 'vs/base/common/types';
import { assertIsDefined } from 'vs/base/common/types';
import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { Schemas } from 'vs/base/common/network';
@@ -34,7 +34,6 @@ import { CustomMenubarControl } from 'vs/workbench/browser/parts/titlebar/menuba
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
import { isWeb } from 'vs/base/common/platform';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { Before2D } from 'vs/workbench/browser/dnd';
import { Codicon, iconRegistry } from 'vs/base/common/codicons';
import { Action, Separator } from 'vs/base/common/actions';
@@ -43,41 +42,45 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
interface IPlaceholderViewContainer {
id: string;
name?: string;
iconUrl?: UriComponents;
iconCSS?: string;
views?: { when?: string }[];
readonly id: string;
readonly name?: string;
readonly iconUrl?: UriComponents;
readonly themeIcon?: ThemeIcon;
readonly views?: { when?: string }[];
}
interface IPinnedViewContainer {
id: string;
pinned: boolean;
order?: number;
visible: boolean;
readonly id: string;
readonly pinned: boolean;
readonly order?: number;
readonly visible: boolean;
}
interface ICachedViewContainer {
id: string;
readonly id: string;
name?: string;
icon?: URI | string;
pinned: boolean;
order?: number;
icon?: URI | ThemeIcon;
readonly pinned: boolean;
readonly order?: number;
visible: boolean;
views?: { when?: string }[];
}
const settingsViewBarIcon = registerIcon('settings-view-bar-icon', Codicon.settingsGear, nls.localize('settingsViewBarIcon', 'Settings icon in the view bar.'));
const accountsViewBarIcon = registerIcon('accounts-view-bar-icon', Codicon.account, nls.localize('accountsViewBarIcon', 'Accounts icon in the view bar.'));
export class ActivitybarPart extends Part implements IActivityBarService {
declare readonly _serviceBrand: undefined;
private static readonly ACTION_HEIGHT = 48;
static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
private static readonly PINNED_VIEW_CONTAINERS = 'workbench.activity.pinnedViewlets2';
private static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.activity.placeholderViewlets';
private static readonly HOME_BAR_VISIBILITY_PREFERENCE = 'workbench.activity.showHomeIndicator';
private static readonly ACTION_HEIGHT = 48;
private static readonly ACCOUNTS_ACTION_INDEX = 0;
//#region IView
readonly minimumWidth: number = 48;
@@ -100,17 +103,17 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private globalActivityAction: ActivityAction | undefined;
private globalActivityActionBar: ActionBar | undefined;
private readonly globalActivity: ICompositeActivity[] = [];
private globalActivitiesContainer: HTMLElement | undefined;
private readonly globalActivity: ICompositeActivity[] = [];
private accountsActivityAction: ActivityAction | undefined;
private accountsActivity: ICompositeActivity[] = [];
private readonly accountsActivity: ICompositeActivity[] = [];
private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction }>();
private readonly viewContainerDisposables = new Map<string, IDisposable>();
private readonly keyboardNavigationDisposables = new DisposableStore();
private readonly keyboardNavigationDisposables = this._register(new DisposableStore());
private readonly location = ViewContainerLocation.Sidebar;
@@ -125,27 +128,36 @@ export class ActivitybarPart extends Part implements IActivityBarService {
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
) {
super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.PINNED_VIEW_CONTAINERS, version: 1 });
storageKeysSyncRegistryService.registerStorageKey({ key: ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, version: 1 });
storageKeysSyncRegistryService.registerStorageKey({ key: ACCOUNTS_VISIBILITY_PREFERENCE_KEY, version: 1 });
this.migrateFromOldCachedViewContainersValue();
for (const cachedViewContainer of this.cachedViewContainers) {
if (environmentService.remoteAuthority // In remote window, hide activity bar entries until registered.
|| this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
if (
environmentService.remoteAuthority || // In remote window, hide activity bar entries until registered
this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
) {
cachedViewContainer.visible = false;
}
}
this.compositeBar = this.createCompositeBar();
this.onDidRegisterViewContainers(this.getViewContainers());
this.registerListeners();
}
private createCompositeBar() {
const cachedItems = this.cachedViewContainers
.map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned }));
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
.map(container => ({
id: container.id,
name: container.name,
visible: container.visible,
order: container.order,
pinned: container.pinned
}));
return this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, {
icon: true,
orientation: ActionsOrientation.VERTICAL,
preventLoopNavigation: true,
@@ -154,8 +166,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
getCompositePinnedAction: (compositeId: string) => this.getCompositeActions(compositeId).pinnedAction,
getOnCompositeClickAction: (compositeId: string) => new Action(compositeId, '', '', true, () => this.viewsService.isViewContainerVisible(compositeId) ? Promise.resolve(this.viewsService.closeViewContainer(compositeId)) : this.viewsService.openViewContainer(compositeId)),
getContextMenuActions: () => {
const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
const actions = [];
// Home
if (this.homeBarContainer) {
actions.push(new Action(
'toggleHomeBarAction',
@@ -166,22 +179,26 @@ export class ActivitybarPart extends Part implements IActivityBarService {
));
}
// Menu
const menuBarVisibility = getMenuBarVisibility(this.configurationService);
if (menuBarVisibility === 'compact' || (menuBarVisibility === 'hidden' && isWeb)) {
actions.push(this.instantiationService.createInstance(ToggleMenuBarAction, ToggleMenuBarAction.ID, menuBarVisibility === 'compact' ? nls.localize('hideMenu', "Hide Menu") : nls.localize('showMenu', "Show Menu")));
}
const toggleAccountsVisibilityAction = new Action(
// Accounts
actions.push(new Action(
'toggleAccountsVisibility',
this.accountsVisibilityPreference ? nls.localize('hideAccounts', "Hide Accounts") : nls.localize('showAccounts', "Show Accounts"),
undefined,
true,
async () => { this.accountsVisibilityPreference = !this.accountsVisibilityPreference; }
);
actions.push(toggleAccountsVisibilityAction);
));
actions.push(new Separator());
// Toggle Sidebar
actions.push(this.instantiationService.createInstance(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.getLabel(this.layoutService)));
// Toggle Activity Bar
actions.push(new Action(
ToggleActivityBarVisibilityAction.ID,
nls.localize('hideActivitBar', "Hide Activity Bar"),
@@ -204,19 +221,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme),
overflowActionSize: ActivitybarPart.ACTION_HEIGHT
}));
this.onDidRegisterViewContainers(this.getViewContainers());
this.registerListeners();
}
focusActivityBar(): void {
this.compositeBar.focus();
}
private getContextMenuActionsForComposite(compositeId: string): Action[] {
const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!;
const actions = [];
const viewContainer = this.viewDescriptorService.getViewContainerById(compositeId)!;
const defaultLocation = this.viewDescriptorService.getDefaultViewContainerLocation(viewContainer)!;
if (defaultLocation !== this.viewDescriptorService.getViewContainerLocation(viewContainer)) {
actions.push(new Action('resetLocationAction', nls.localize('resetLocation', "Reset Location"), undefined, true, async () => {
@@ -253,13 +263,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
disposables.clear();
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedViewContainers(), this, disposables);
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
}));
// Register for configuration changes
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration('window.menuBarVisibility')) {
if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') {
if (getMenuBarVisibility(this.configurationService) === 'compact') {
this.installMenubar();
} else {
this.uninstallMenubar();
@@ -277,6 +287,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (from === this.location) {
this.onDidDeregisterViewContainer(container);
}
if (to === this.location) {
this.onDidRegisterViewContainers([container]);
}
@@ -306,6 +317,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private onDidViewContainerVisible(id: string): void {
const viewContainer = this.getViewContainer(id);
if (viewContainer) {
// Update the composite bar by adding
this.compositeBar.addComposite(viewContainer);
this.compositeBar.activateComposite(viewContainer.id);
@@ -313,7 +325,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (viewContainer.hideIfEmpty) {
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
if (viewContainerModel.activeViewDescriptors.length === 0) {
this.hideComposite(viewContainer.id); // Update the composite bar by hiding
// Update the composite bar by hiding
this.hideComposite(viewContainer.id);
}
}
}
@@ -339,6 +352,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
if (typeof priority !== 'number') {
priority = 0;
}
const activity: ICompositeActivity = { badge, clazz, priority };
const activityCache = activityId === GLOBAL_ACTIVITY_ID ? this.globalActivity : this.accountsActivity;
@@ -387,16 +401,18 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private getCumulativeNumberBadge(activityCache: ICompositeActivity[], priority: number): NumberBadge {
const numberActivities = activityCache.filter(activity => activity.badge instanceof NumberBadge && activity.priority === priority);
let number = numberActivities.reduce((result, activity) => { return result + (<NumberBadge>activity.badge).number; }, 0);
let descriptorFn = (): string => {
const number = numberActivities.reduce((result, activity) => { return result + (<NumberBadge>activity.badge).number; }, 0);
const descriptorFn = (): string => {
return numberActivities.reduce((result, activity, index) => {
result = result + (<NumberBadge>activity.badge).getDescription();
if (index < numberActivities.length - 1) {
result = result + '\n';
result = `${result}\n`;
}
return result;
}, '');
};
return new NumberBadge(number, descriptorFn);
}
@@ -414,11 +430,19 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
private installMenubar() {
if (this.menuBar) {
return; // prevent menu bar from installing twice #110720
}
this.menuBarContainer = document.createElement('div');
this.menuBarContainer.classList.add('menubar');
const content = assertIsDefined(this.content);
content.prepend(this.menuBarContainer);
if (this.homeBarContainer) {
content.insertBefore(this.menuBarContainer, this.homeBarContainer.nextSibling);
} else {
content.prepend(this.menuBarContainer);
}
// Menubar: install a custom menu bar depending on configuration
this.menuBar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
@@ -442,12 +466,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
codicon = Codicon.code;
}
this.createHomeBar(homeIndicator.href, homeIndicator.title, codicon);
this.createHomeBar(homeIndicator.href, codicon);
this.onDidChangeHomeBarVisibility();
}
// Install menubar if compact
if (getMenuBarVisibility(this.configurationService, this.environmentService) === 'compact') {
if (getMenuBarVisibility(this.configurationService) === 'compact') {
this.installMenubar();
}
@@ -456,11 +480,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
// Global action bar
this.globalActivitiesContainer = document.createElement('div');
this.globalActivitiesContainer.classList.add('global-activity');
this.content.appendChild(this.globalActivitiesContainer);
this.createGlobalActivityActionBar(this.globalActivitiesContainer);
// Keyboard Navigation
this.registerKeyboardNavigationListeners();
return this.content;
@@ -528,23 +552,19 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
}));
}
}
private createHomeBar(href: string, title: string, icon: Codicon): void {
private createHomeBar(href: string, icon: Codicon): void {
this.homeBarContainer = document.createElement('div');
this.homeBarContainer.setAttribute('aria-label', nls.localize('homeIndicator', "Home"));
this.homeBarContainer.setAttribute('role', 'toolbar');
this.homeBarContainer.classList.add('home-bar');
this.homeBar = this._register(new ActionBar(this.homeBarContainer, {
actionViewItemProvider: action => this.instantiationService.createInstance(HomeActivityActionViewItem, href, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme)),
orientation: ActionsOrientation.VERTICAL,
animated: false,
ariaLabel: nls.localize('home', "Home"),
actionViewItemProvider: action => new HomeActionViewItem(action),
allowContextMenu: true,
animated: false,
preventLoopNavigation: true,
ignoreOrientationForPreviousAndNextKey: true
}));
@@ -552,35 +572,15 @@ export class ActivitybarPart extends Part implements IActivityBarService {
const homeBarIconBadge = document.createElement('div');
homeBarIconBadge.classList.add('home-bar-icon-badge');
this.homeBarContainer.appendChild(homeBarIconBadge);
this.homeBar.push(this._register(this.instantiationService.createInstance(HomeAction, href, title, icon)));
this.homeBar.push(this._register(new ActivityAction({
id: 'workbench.actions.home',
name: nls.localize('home', "Home"),
cssClass: icon.classNames
})));
const content = assertIsDefined(this.content);
content.prepend(this.homeBarContainer);
}
updateStyles(): void {
super.updateStyles();
const container = assertIsDefined(this.getContainer());
const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || '';
container.style.backgroundColor = background;
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || '';
container.classList.toggle('bordered', !!borderColor);
container.style.borderColor = borderColor ? borderColor : '';
}
private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors {
return {
activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND),
inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND),
activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER),
activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND),
badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),
badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),
dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER),
activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined,
};
content.appendChild(this.homeBarContainer);
}
private createGlobalActivityActionBar(container: HTMLElement): void {
@@ -591,7 +591,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
if (action.id === 'workbench.actions.accounts') {
return this.instantiationService.createInstance(AccountsActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme));
return this.instantiationService.createInstance(AccountsActivityActionViewItem, action as ActivityAction, (theme: IColorTheme) => this.getActivitybarItemColors(theme));
}
throw new Error(`No view item for action '${action.id}'`);
@@ -603,18 +603,18 @@ export class ActivitybarPart extends Part implements IActivityBarService {
ignoreOrientationForPreviousAndNextKey: true
}));
this.globalActivityAction = new ActivityAction({
this.globalActivityAction = this._register(new ActivityAction({
id: 'workbench.actions.manage',
name: nls.localize('manage', "Manage"),
cssClass: Codicon.settingsGear.classNames
});
cssClass: ThemeIcon.asClassName(settingsViewBarIcon)
}));
if (this.accountsVisibilityPreference) {
this.accountsActivityAction = new ActivityAction({
this.accountsActivityAction = this._register(new ActivityAction({
id: 'workbench.actions.accounts',
name: nls.localize('accounts', "Accounts"),
cssClass: Codicon.account.classNames
});
cssClass: ThemeIcon.asClassName(accountsViewBarIcon)
}));
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
}
@@ -628,11 +628,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.globalActivityActionBar.pull(ActivitybarPart.ACCOUNTS_ACTION_INDEX);
this.accountsActivityAction = undefined;
} else {
this.accountsActivityAction = new ActivityAction({
this.accountsActivityAction = this._register(new ActivityAction({
id: 'workbench.actions.accounts',
name: nls.localize('accounts', "Accounts"),
cssClass: Codicon.account.classNames
});
}));
this.globalActivityActionBar.push(this.accountsActivityAction, { index: ActivitybarPart.ACCOUNTS_ACTION_INDEX });
}
}
@@ -723,7 +723,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
return ActivitybarPart.toActivity(id, name, icon, focusCommand?.id || id);
}
private static toActivity(id: string, name: string, icon: URI | string | undefined, keybindingId: string | undefined): IActivity {
private static toActivity(id: string, name: string, icon: URI | ThemeIcon | undefined, keybindingId: string | undefined): IActivity {
let cssClass: string | undefined = undefined;
let iconUrl: URI | undefined = undefined;
if (URI.isUri(icon)) {
@@ -736,9 +736,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
-webkit-mask-size: 24px;
`);
} else if (isString(icon)) {
cssClass = icon;
} else if (ThemeIcon.isThemeIcon(icon)) {
cssClass = ThemeIcon.asClassName(icon);
}
return { id, name, cssClass, iconUrl, keybindingId };
}
@@ -810,6 +811,35 @@ export class ActivitybarPart extends Part implements IActivityBarService {
.map(v => v.id);
}
focusActivityBar(): void {
this.compositeBar.focus();
}
updateStyles(): void {
super.updateStyles();
const container = assertIsDefined(this.getContainer());
const background = this.getColor(ACTIVITY_BAR_BACKGROUND) || '';
container.style.backgroundColor = background;
const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder) || '';
container.classList.toggle('bordered', !!borderColor);
container.style.borderColor = borderColor ? borderColor : '';
}
private getActivitybarItemColors(theme: IColorTheme): ICompositeBarColors {
return {
activeForegroundColor: theme.getColor(ACTIVITY_BAR_FOREGROUND),
inactiveForegroundColor: theme.getColor(ACTIVITY_BAR_INACTIVE_FOREGROUND),
activeBorderColor: theme.getColor(ACTIVITY_BAR_ACTIVE_BORDER),
activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND),
badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),
badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),
dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER),
activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined,
};
}
layout(width: number, height: number): void {
if (!this.layoutService.isVisible(Parts.ACTIVITYBAR_PART)) {
return;
@@ -834,6 +864,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
private getViewContainer(id: string): ViewContainer | undefined {
const viewContainer = this.viewDescriptorService.getViewContainerById(id);
return viewContainer && this.viewDescriptorService.getViewContainerLocation(viewContainer) === this.location ? viewContainer : undefined;
}
@@ -841,7 +872,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
return this.viewDescriptorService.getViewContainersByLocation(this.location);
}
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
private onDidStorageValueChange(e: IStorageValueChangeEvent): void {
if (e.key === ActivitybarPart.PINNED_VIEW_CONTAINERS && e.scope === StorageScope.GLOBAL
&& this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) {
this._pinnedViewContainersValue = undefined;
@@ -870,11 +901,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
this.compositeBar.setCompositeBarItems(newCompositeItems);
}
if (e.key === ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
if (e.key === HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
this.onDidChangeHomeBarVisibility();
}
if (e.key === ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
if (e.key === AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY && e.scope === StorageScope.GLOBAL) {
this.toggleAccountsActivity();
}
}
@@ -917,12 +948,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
const cachedViewContainer = this._cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0];
if (cachedViewContainer) {
cachedViewContainer.name = placeholderViewContainer.name;
cachedViewContainer.icon = placeholderViewContainer.iconCSS ? placeholderViewContainer.iconCSS :
cachedViewContainer.icon = placeholderViewContainer.themeIcon ? ThemeIcon.revive(placeholderViewContainer.themeIcon) :
placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined;
cachedViewContainer.views = placeholderViewContainer.views;
}
}
}
return this._cachedViewContainers;
}
@@ -933,10 +965,11 @@ export class ActivitybarPart extends Part implements IActivityBarService {
visible,
order
})));
this.setPlaceholderViewContainers(cachedViewContainers.map(({ id, icon, name, views }) => (<IPlaceholderViewContainer>{
id,
iconUrl: URI.isUri(icon) ? icon : undefined,
iconCSS: isString(icon) ? icon : undefined,
themeIcon: ThemeIcon.isThemeIcon(icon) ? icon : undefined,
name,
views
})));
@@ -971,7 +1004,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
private setStoredPinnedViewContainersValue(value: string): void {
this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
this.storageService.store(ActivitybarPart.PINNED_VIEW_CONTAINERS, value, StorageScope.GLOBAL, StorageTarget.USER);
}
private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
@@ -1003,37 +1036,23 @@ export class ActivitybarPart extends Part implements IActivityBarService {
}
private setStoredPlaceholderViewContainersValue(value: string): void {
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL, StorageTarget.MACHINE);
}
private get homeBarVisibilityPreference(): boolean {
return this.storageService.getBoolean(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
return this.storageService.getBoolean(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
}
private set homeBarVisibilityPreference(value: boolean) {
this.storageService.store(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL);
this.storageService.store(HomeActivityActionViewItem.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL, StorageTarget.USER);
}
private get accountsVisibilityPreference(): boolean {
return this.storageService.getBoolean(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
return this.storageService.getBoolean(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, StorageScope.GLOBAL, true);
}
private set accountsVisibilityPreference(value: boolean) {
this.storageService.store(ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL);
}
private migrateFromOldCachedViewContainersValue(): void {
const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
if (value !== undefined) {
const storedStates: Array<string | ICachedViewContainer> = JSON.parse(value);
const cachedViewContainers = storedStates.map(c => {
const serialized: ICachedViewContainer = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, icon: undefined, views: undefined } : c;
serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible;
return serialized;
});
this.storeCachedViewContainersState(cachedViewContainers);
this.storageService.remove('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
}
this.storageService.store(AccountsActivityActionViewItem.ACCOUNTS_VISIBILITY_PREFERENCE_KEY, value, StorageScope.GLOBAL, StorageTarget.USER);
}
toJSON(): object {

View File

@@ -9,10 +9,6 @@
margin-bottom: 4px;
}
.monaco-workbench .activitybar > .content > .home-bar > .monaco-action-bar .action-item {
margin-bottom: 0;
}
.monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::before,
.monaco-workbench .activitybar > .content .composite-bar > .monaco-action-bar .action-item::after {
position: absolute;

View File

@@ -51,6 +51,7 @@
position: relative;
width: 100%;
height: 48px;
<<<<<<< HEAD
display: flex;
align-items: center;
justify-content: center;
@@ -59,6 +60,8 @@
/* NOTE@coder: Hide since it doesn't seem to do anything when used with
code-server except open the VS Code repository. */
display: none !important;
=======
>>>>>>> e4a830e9b7ca039c7c70697786d29f5b6679d775
}
.monaco-workbench .activitybar > .content > .home-bar > .home-bar-icon-badge {
@@ -92,10 +95,6 @@
margin-bottom: auto;
}
.monaco-workbench .activitybar > .content > .composite-bar-excess {
height: 100%;
}
/** Menu Bar */
.monaco-workbench .activitybar .menubar {

View File

@@ -18,7 +18,7 @@ import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite';
import { IComposite } from 'vs/workbench/common/composite';
import { CompositeProgressIndicator } from 'vs/workbench/services/progress/browser/progressIndicator';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
@@ -199,7 +199,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
// Store in preferences
const id = this.activeComposite.getId();
if (id !== this.defaultCompositeId) {
this.storageService.store(this.activeCompositeSettingsKey, id, StorageScope.WORKSPACE);
this.storageService.store(this.activeCompositeSettingsKey, id, StorageScope.WORKSPACE, StorageTarget.USER);
} else {
this.storageService.remove(this.activeCompositeSettingsKey, StorageScope.WORKSPACE);
}

View File

@@ -0,0 +1,76 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { IDialogHandler, IDialogResult, IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';
import { IProductService } from 'vs/platform/product/common/productService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { IDialogsModel, IDialogViewItem } from 'vs/workbench/common/dialogs';
import { BrowserDialogHandler } from 'vs/workbench/browser/parts/dialogs/dialogHandler';
import { DialogService } from 'vs/workbench/services/dialogs/common/dialogService';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
import { Disposable } from 'vs/base/common/lifecycle';
export class DialogHandlerContribution extends Disposable implements IWorkbenchContribution {
private impl: IDialogHandler;
private model: IDialogsModel;
private currentDialog: IDialogViewItem | undefined;
constructor(
@IDialogService private dialogService: IDialogService,
@ILogService logService: ILogService,
@ILayoutService layoutService: ILayoutService,
@IThemeService themeService: IThemeService,
@IKeybindingService keybindingService: IKeybindingService,
@IProductService productService: IProductService,
@IClipboardService clipboardService: IClipboardService
) {
super();
this.impl = new BrowserDialogHandler(logService, layoutService, themeService, keybindingService, productService, clipboardService);
this.model = (this.dialogService as DialogService).model;
this._register(this.model.onDidShowDialog(() => {
if (!this.currentDialog) {
this.processDialogs();
}
}));
this.processDialogs();
}
private async processDialogs(): Promise<void> {
while (this.model.dialogs.length) {
this.currentDialog = this.model.dialogs[0];
let result: IDialogResult | undefined = undefined;
if (this.currentDialog.args.confirmArgs) {
const args = this.currentDialog.args.confirmArgs;
result = await this.impl.confirm(args.confirmation);
} else if (this.currentDialog.args.inputArgs) {
const args = this.currentDialog.args.inputArgs;
result = await this.impl.input(args.severity, args.message, args.buttons, args.inputs, args.options);
} else if (this.currentDialog.args.showArgs) {
const args = this.currentDialog.args.showArgs;
result = await this.impl.show(args.severity, args.message, args.buttons, args.options);
} else {
await this.impl.about();
}
this.currentDialog.close(result);
this.currentDialog = undefined;
}
}
}
const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(DialogHandlerContribution, LifecyclePhase.Starting);

View File

@@ -0,0 +1,144 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import { IDialogOptions, IConfirmation, IConfirmationResult, DialogType, IShowResult, IInputResult, ICheckbox, IInput, IDialogHandler } from 'vs/platform/dialogs/common/dialogs';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
import { ILogService } from 'vs/platform/log/common/log';
import Severity from 'vs/base/common/severity';
import { Dialog, IDialogResult } from 'vs/base/browser/ui/dialog/dialog';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { attachDialogStyler } from 'vs/platform/theme/common/styler';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { EventHelper } from 'vs/base/browser/dom';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IProductService } from 'vs/platform/product/common/productService';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { fromNow } from 'vs/base/common/date';
export class BrowserDialogHandler implements IDialogHandler {
private static readonly ALLOWABLE_COMMANDS = [
'copy',
'cut',
'editor.action.selectAll',
'editor.action.clipboardCopyAction',
'editor.action.clipboardCutAction',
'editor.action.clipboardPasteAction'
];
constructor(
@ILogService private readonly logService: ILogService,
@ILayoutService private readonly layoutService: ILayoutService,
@IThemeService private readonly themeService: IThemeService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IProductService private readonly productService: IProductService,
@IClipboardService private readonly clipboardService: IClipboardService
) { }
async confirm(confirmation: IConfirmation): Promise<IConfirmationResult> {
this.logService.trace('DialogService#confirm', confirmation.message);
const buttons: string[] = [];
if (confirmation.primaryButton) {
buttons.push(confirmation.primaryButton);
} else {
buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
}
if (confirmation.secondaryButton) {
buttons.push(confirmation.secondaryButton);
} else if (typeof confirmation.secondaryButton === 'undefined') {
buttons.push(nls.localize('cancelButton', "Cancel"));
}
const result = await this.doShow(confirmation.type, confirmation.message, buttons, confirmation.detail, 1, confirmation.checkbox);
return { confirmed: result.button === 0, checkboxChecked: result.checkboxChecked };
}
private getDialogType(severity: Severity): DialogType {
return (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none';
}
async show(severity: Severity, message: string, buttons: string[], options?: IDialogOptions): Promise<IShowResult> {
this.logService.trace('DialogService#show', message);
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox);
return {
choice: result.button,
checkboxChecked: result.checkboxChecked
};
}
private async doShow(type: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending' | undefined, message: string, buttons: string[], detail?: string, cancelId?: number, checkbox?: ICheckbox, inputs?: IInput[]): Promise<IDialogResult> {
const dialogDisposables = new DisposableStore();
const dialog = new Dialog(
this.layoutService.container,
message,
buttons,
{
detail,
cancelId,
type,
keyEventProcessor: (event: StandardKeyboardEvent) => {
const resolved = this.keybindingService.softDispatch(event, this.layoutService.container);
if (resolved && resolved.commandId) {
if (BrowserDialogHandler.ALLOWABLE_COMMANDS.indexOf(resolved.commandId) === -1) {
EventHelper.stop(event, true);
}
}
},
checkboxLabel: checkbox?.label,
checkboxChecked: checkbox?.checked,
inputs
});
dialogDisposables.add(dialog);
dialogDisposables.add(attachDialogStyler(dialog, this.themeService));
const result = await dialog.show();
dialogDisposables.dispose();
return result;
}
async input(severity: Severity, message: string, buttons: string[], inputs: IInput[], options?: IDialogOptions): Promise<IInputResult> {
this.logService.trace('DialogService#input', message);
const result = await this.doShow(this.getDialogType(severity), message, buttons, options?.detail, options?.cancelId, options?.checkbox, inputs);
return {
choice: result.button,
checkboxChecked: result.checkboxChecked,
values: result.values
};
}
async about(): Promise<void> {
const detailString = (useAgo: boolean): string => {
return nls.localize('aboutDetail',
"code-server: v{4}\n VS Code: v{0}\nCommit: {1}\nDate: {2}\nBrowser: {3}",
this.productService.version || 'Unknown',
this.productService.commit || 'Unknown',
this.productService.date ? `${this.productService.date}${useAgo ? ' (' + fromNow(new Date(this.productService.date), true) + ')' : ''}` : 'Unknown',
navigator.userAgent,
this.productService.codeServerVersion || 'Unknown',
);
};
const detail = detailString(true);
const detailToCopy = detailString(false);
const { choice } = await this.show(Severity.Info, this.productService.nameLong, [nls.localize('copy', "Copy"), nls.localize('ok', "OK")], { detail, cancelId: 1 });
if (choice === 0) {
this.clipboardService.writeText(detailToCopy);
}
}
}

View File

@@ -20,7 +20,7 @@ import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/commo
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
import { BinarySize } from 'vs/platform/files/common/files';
import { ByteSize } from 'vs/platform/files/common/files';
export interface IOpenCallbacks {
openInternal: (input: EditorInput, options: EditorOptions | undefined) => Promise<void>;
@@ -182,7 +182,7 @@ interface ResourceViewerDelegate {
class ResourceViewer {
private static readonly MAX_OPEN_INTERNAL_SIZE = BinarySize.MB * 200; // max size until we offer an action to open internally
private static readonly MAX_OPEN_INTERNAL_SIZE = ByteSize.MB * 200; // max size until we offer an action to open internally
static show(
descriptor: IResourceDescriptor,
@@ -211,7 +211,7 @@ class FileTooLargeFileView {
scrollbar: DomScrollableElement,
delegate: ResourceViewerDelegate
) {
const size = BinarySize.formatSize(descriptorSize);
const size = ByteSize.formatSize(descriptorSize);
delegate.metadataClb(size);
clearNode(container);
@@ -233,7 +233,7 @@ class FileSeemsBinaryFileView {
scrollbar: DomScrollableElement,
delegate: ResourceViewerDelegate
) {
delegate.metadataClb(typeof descriptor.size === 'number' ? BinarySize.formatSize(descriptor.size) : '');
delegate.metadataClb(typeof descriptor.size === 'number' ? ByteSize.formatSize(descriptor.size) : '');
clearNode(container);

View File

@@ -491,7 +491,7 @@ export class BreadcrumbsControl {
if (element instanceof FileElement) {
if (element.kind === FileKind.FILE) {
// open file in any editor
this._editorService.openEditor({ resource: element.uri, options: { pinned: pinned } }, group);
this._editorService.openEditor({ resource: element.uri, options: { pinned } }, group);
} else {
// show next picker
let items = this._widget.getItems();
@@ -508,7 +508,8 @@ export class BreadcrumbsControl {
resource: model.uri,
options: {
selection: Range.collapseToStart(element.symbol.selectionRange),
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport
selectionRevealType: TextEditorSelectionRevealType.CenterIfOutsideViewport,
pinned
}
}, withUndefinedAsNull(this._getActiveCodeEditor()), group === SIDE_GROUP);
}
@@ -753,13 +754,14 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
// open symbol in editor
return editors.openEditor({
resource: outlineElement.uri,
options: { selection: Range.collapseToStart(element.symbol.selectionRange) }
options: { selection: Range.collapseToStart(element.symbol.selectionRange), pinned: true }
}, SIDE_GROUP);
} else if (element && URI.isUri(element.resource)) {
// open file in editor
return editors.openEditor({
resource: element.resource,
options: { pinned: true }
}, SIDE_GROUP);
} else {

View File

@@ -99,7 +99,7 @@ export abstract class BreadcrumbsPicker {
this._treeContainer = document.createElement('div');
this._treeContainer.style.background = color ? color.toString() : '';
this._treeContainer.style.paddingTop = '2px';
this._treeContainer.style.boxShadow = `0px 5px 8px ${this._themeService.getColorTheme().getColor(widgetShadow)}`;
this._treeContainer.style.boxShadow = `0 0 8px 2px ${this._themeService.getColorTheme().getColor(widgetShadow)}`;
this._domNode.appendChild(this._treeContainer);
this._layoutInfo = { maxHeight, width, arrowSize, arrowOffset, inputHeight: 0 };
@@ -436,7 +436,6 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker {
}
protected _getTargetFromEvent(element: any): any | undefined {
// todo@joh
if (element && !IWorkspaceFolder.isIWorkspaceFolder(element) && !(element as IFileStat).isDirectory) {
return new FileElement((element as IFileStat).resource, FileKind.FILE);
}

View File

@@ -55,6 +55,8 @@ import { IQuickAccessRegistry, Extensions as QuickAccessExtensions } from 'vs/pl
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess, AllEditorsByAppearanceQuickAccess, AllEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
import { IPathService } from 'vs/workbench/services/path/common/pathService';
import { FileAccess } from 'vs/base/common/network';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
@@ -238,27 +240,27 @@ export abstract class AbstractSideBySideEditorInputFactory implements IEditorInp
const secondaryInput = secondaryInputFactory.deserialize(instantiationService, deserialized.secondarySerialized);
if (primaryInput && secondaryInput) {
return this.createEditorInput(deserialized.name, deserialized.description, secondaryInput, primaryInput);
return this.createEditorInput(instantiationService, deserialized.name, deserialized.description, secondaryInput, primaryInput);
}
}
return undefined;
}
protected abstract createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
protected abstract createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput;
}
class SideBySideEditorInputFactory extends AbstractSideBySideEditorInputFactory {
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
return new SideBySideEditorInput(name, description, secondaryInput, primaryInput);
}
}
class DiffEditorInputFactory extends AbstractSideBySideEditorInputFactory {
protected createEditorInput(name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
return new DiffEditorInput(name, description, secondaryInput, primaryInput);
protected createEditorInput(instantiationService: IInstantiationService, name: string, description: string | undefined, secondaryInput: EditorInput, primaryInput: EditorInput): EditorInput {
return instantiationService.createInstance(DiffEditorInput, name, description, secondaryInput, primaryInput, undefined);
}
}
@@ -462,6 +464,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.SHOW_EDITORS_IN_GROUP, title: nls.localize('showOpenedEditors', "Show Opened Editors") }, group: '3_open', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '5_close', order: 10 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '5_close', order: 20 });
MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands.TOGGLE_KEEP_EDITORS_COMMAND_ID, title: nls.localize('toggleKeepEditors', "Keep Editors Open"), toggled: ContextKeyExpr.not('config.workbench.editor.enablePreview') }, group: '7_settings', order: 10 });
interface IEditorToolItem { id: string; title: string; icon?: { dark?: URI; light?: URI; } | ThemeIcon; }
@@ -494,14 +497,14 @@ appendEditorToolItem(
{
id: SplitEditorAction.ID,
title: nls.localize('splitEditorRight', "Split Editor Right"),
icon: { id: 'codicon/split-horizontal' }
icon: Codicon.splitHorizontal
},
ContextKeyExpr.not('splitEditorsVertically'),
100000, // towards the end
{
id: editorCommands.SPLIT_EDITOR_DOWN,
title: nls.localize('splitEditorDown', "Split Editor Down"),
icon: { id: 'codicon/split-vertical' }
icon: Codicon.splitVertical
}
);
@@ -509,14 +512,14 @@ appendEditorToolItem(
{
id: SplitEditorAction.ID,
title: nls.localize('splitEditorDown', "Split Editor Down"),
icon: { id: 'codicon/split-vertical' }
icon: Codicon.splitVertical
},
ContextKeyExpr.has('splitEditorsVertically'),
100000, // towards the end
{
id: editorCommands.SPLIT_EDITOR_RIGHT,
title: nls.localize('splitEditorRight', "Split Editor Right"),
icon: { id: 'codicon/split-horizontal' }
icon: Codicon.splitHorizontal
}
);
@@ -525,14 +528,14 @@ appendEditorToolItem(
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
icon: { id: 'codicon/close' }
icon: Codicon.close
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext.toNegated()),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: nls.localize('closeAll', "Close All"),
icon: { id: 'codicon/close-all' }
icon: Codicon.closeAll
}
);
@@ -541,14 +544,14 @@ appendEditorToolItem(
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
icon: { id: 'codicon/close-dirty' }
icon: Codicon.closeDirty
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext.toNegated()),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID,
title: nls.localize('closeAll', "Close All"),
icon: { id: 'codicon/close-all' }
icon: Codicon.closeAll
}
);
@@ -557,14 +560,14 @@ appendEditorToolItem(
{
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
title: nls.localize('unpin', "Unpin"),
icon: { id: 'codicon/pinned' }
icon: Codicon.pinned
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext.toNegated(), ActiveEditorStickyContext),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
icon: { id: 'codicon/close' }
icon: Codicon.close
}
);
@@ -573,23 +576,28 @@ appendEditorToolItem(
{
id: editorCommands.UNPIN_EDITOR_COMMAND_ID,
title: nls.localize('unpin', "Unpin"),
icon: { id: 'codicon/pinned-dirty' }
icon: Codicon.pinnedDirty
},
ContextKeyExpr.and(ContextKeyExpr.not('config.workbench.editor.showTabs'), ActiveEditorDirtyContext, ActiveEditorStickyContext),
1000000, // towards the far end
{
id: editorCommands.CLOSE_EDITOR_COMMAND_ID,
title: nls.localize('close', "Close"),
icon: { id: 'codicon/close' }
icon: Codicon.close
}
);
const previousChangeIcon = registerIcon('diff-editor-previous-change', Codicon.arrowUp, nls.localize('previousChangeIcon', 'Icon for the previous change action in the diff editor.'));
const nextChangeIcon = registerIcon('diff-editor-next-change', Codicon.arrowDown, nls.localize('nextChangeIcon', 'Icon for the next change action in the diff editor.'));
const toggleWhitespace = registerIcon('diff-editor-toggle-whitespace', Codicon.whitespace, nls.localize('toggleWhitespace', 'Icon for the toggle whitespace action in the diff editor.'));
// Diff Editor Title Menu: Previous Change
appendEditorToolItem(
{
id: editorCommands.GOTO_PREVIOUS_CHANGE,
title: nls.localize('navigate.prev.label', "Previous Change"),
icon: { id: 'codicon/arrow-up' }
icon: previousChangeIcon
},
TextCompareEditorActiveContext,
10
@@ -600,7 +608,7 @@ appendEditorToolItem(
{
id: editorCommands.GOTO_NEXT_CHANGE,
title: nls.localize('navigate.next.label', "Next Change"),
icon: { id: 'codicon/arrow-down' }
icon: nextChangeIcon
},
TextCompareEditorActiveContext,
11
@@ -611,7 +619,7 @@ appendEditorToolItem(
{
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: nls.localize('ignoreTrimWhitespace.label', "Ignore Leading/Trailing Whitespace Differences"),
icon: { id: 'codicon/whitespace' }
icon: toggleWhitespace
},
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', true)),
20
@@ -622,7 +630,7 @@ appendEditorToolItem(
{
id: editorCommands.TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE,
title: nls.localize('showTrimWhitespace.label', "Show Leading/Trailing Whitespace Differences"),
icon: { id: 'codicon/whitespace~disabled' }
icon: ThemeIcon.modify(toggleWhitespace, 'disabled')
},
ContextKeyExpr.and(TextCompareEditorActiveContext, ContextKeyExpr.notEquals('config.diffEditor.ignoreTrimWhitespace', false)),
20

View File

@@ -38,7 +38,8 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
openSideBySideDirection: 'right',
closeEmptyGroups: true,
labelFormat: 'default',
splitSizing: 'distribute'
splitSizing: 'distribute',
splitOnDragAndDrop: true
};
export function impactsEditorPartOptions(event: IConfigurationChangeEvent): boolean {
@@ -64,12 +65,12 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
/**
* The options used when opening the editor.
*/
options?: IEditorOptions;
readonly options?: IEditorOptions;
/**
* Context indicates how the editor open event is initialized.
*/
context?: OpenEditorContext;
readonly context?: OpenEditorContext;
/**
* Allows to prevent the opening of an editor by providing a callback

View File

@@ -7,22 +7,26 @@ import * as nls from 'vs/nls';
import { isObject, isString, isUndefined, isNumber, withNullAsUndefined } from 'vs/base/common/types';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder } from 'vs/workbench/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { TextCompareEditorVisibleContext, EditorInput, IEditorIdentifier, IEditorCommandsContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, CloseDirection, IEditorInput, IVisibleEditorPane, ActiveEditorStickyContext, EditorsOrder, viewColumnToEditorGroup, EditorGroupColumn } from 'vs/workbench/common/editor';
import { IEditorService, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor';
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
import { URI } from 'vs/base/common/uri';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput';
import { IListService } from 'vs/platform/list/browser/listService';
import { IListService, IOpenEvent } from 'vs/platform/list/browser/listService';
import { List } from 'vs/base/browser/ui/list/listWidget';
import { distinct, coalesce } from 'vs/base/common/arrays';
import { IEditorGroupsService, IEditorGroup, GroupDirection, GroupLocation, GroupsOrder, preferredSideBySideGroupDirection, EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { CommandsRegistry, ICommandHandler } from 'vs/platform/commands/common/commands';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { ActiveGroupEditorsByMostRecentlyUsedQuickAccess } from 'vs/workbench/browser/parts/editor/editorQuickAccess';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { ITextEditorOptions } from 'vs/platform/editor/common/editor';
import { openEditorWith } from 'vs/workbench/services/editor/common/editorOpenWith';
export const CLOSE_SAVED_EDITORS_COMMAND_ID = 'workbench.action.closeUnmodifiedEditors';
export const CLOSE_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeEditorsInGroup';
@@ -36,6 +40,7 @@ export const CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID = 'workbench.action.closeOt
export const MOVE_ACTIVE_EDITOR_COMMAND_ID = 'moveActiveEditor';
export const LAYOUT_EDITOR_GROUPS_COMMAND_ID = 'layoutEditorGroups';
export const KEEP_EDITOR_COMMAND_ID = 'workbench.action.keepEditor';
export const TOGGLE_KEEP_EDITORS_COMMAND_ID = 'workbench.action.toggleKeepEditors';
export const SHOW_EDITORS_IN_GROUP = 'workbench.action.showEditorsInGroup';
export const PIN_EDITOR_COMMAND_ID = 'workbench.action.pinEditor';
@@ -44,6 +49,9 @@ export const UNPIN_EDITOR_COMMAND_ID = 'workbench.action.unpinEditor';
export const TOGGLE_DIFF_SIDE_BY_SIDE = 'toggle.diff.renderSideBySide';
export const GOTO_NEXT_CHANGE = 'workbench.action.compareEditor.nextChange';
export const GOTO_PREVIOUS_CHANGE = 'workbench.action.compareEditor.previousChange';
export const DIFF_FOCUS_PRIMARY_SIDE = 'workbench.action.compareEditor.focusPrimarySide';
export const DIFF_FOCUS_SECONDARY_SIDE = 'workbench.action.compareEditor.focusSecondarySide';
export const DIFF_FOCUS_OTHER_SIDE = 'workbench.action.compareEditor.focusOtherSide';
export const TOGGLE_DIFF_IGNORE_TRIM_WHITESPACE = 'toggle.diff.ignoreTrimWhitespace';
export const SPLIT_EDITOR_UP = 'workbench.action.splitEditorUp';
@@ -58,6 +66,10 @@ export const FOCUS_BELOW_GROUP_WITHOUT_WRAP_COMMAND_ID = 'workbench.action.focus
export const OPEN_EDITOR_AT_INDEX_COMMAND_ID = 'workbench.action.openEditorAtIndex';
export const API_OPEN_EDITOR_COMMAND_ID = '_workbench.open';
export const API_OPEN_DIFF_EDITOR_COMMAND_ID = '_workbench.diff';
export const API_OPEN_WITH_EDITOR_COMMAND_ID = '_workbench.openWith';
export interface ActiveEditorMoveArguments {
to: 'first' | 'last' | 'left' | 'right' | 'up' | 'down' | 'center' | 'position' | 'previous' | 'next';
by: 'tab' | 'group';
@@ -227,13 +239,45 @@ function moveActiveEditorToGroup(args: ActiveEditorMoveArguments, control: IVisi
}
function registerEditorGroupsLayoutCommand(): void {
CommandsRegistry.registerCommand(LAYOUT_EDITOR_GROUPS_COMMAND_ID, (accessor: ServicesAccessor, args: EditorGroupLayout) => {
if (!args || typeof args !== 'object') {
function applyEditorLayout(accessor: ServicesAccessor, layout: EditorGroupLayout): void {
if (!layout || typeof layout !== 'object') {
return;
}
const editorGroupService = accessor.get(IEditorGroupsService);
editorGroupService.applyLayout(args);
editorGroupService.applyLayout(layout);
}
CommandsRegistry.registerCommand(LAYOUT_EDITOR_GROUPS_COMMAND_ID, (accessor: ServicesAccessor, args: EditorGroupLayout) => {
applyEditorLayout(accessor, args);
});
// API Command
CommandsRegistry.registerCommand({
id: 'vscode.setEditorLayout',
handler: (accessor: ServicesAccessor, args: EditorGroupLayout) => applyEditorLayout(accessor, args),
description: {
description: 'Set Editor Layout',
args: [{
name: 'args',
schema: {
'type': 'object',
'required': ['groups'],
'properties': {
'orientation': {
'type': 'number',
'default': 0,
'enum': [0, 1]
},
'groups': {
'$ref': '#/definitions/editorGroupsSchema',
'default': [{}, {}]
}
}
}
}]
}
});
}
@@ -265,30 +309,68 @@ function registerDiffEditorCommands(): void {
handler: accessor => navigateInDiffEditor(accessor, false)
});
function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
function getActiveTextDiffEditor(accessor: ServicesAccessor): TextDiffEditor | undefined {
const editorService = accessor.get(IEditorService);
const candidates = [editorService.activeEditorPane, ...editorService.visibleEditorPanes].filter(editor => editor instanceof TextDiffEditor);
if (candidates.length > 0) {
const navigator = (<TextDiffEditor>candidates[0]).getDiffNavigator();
for (const editor of [editorService.activeEditorPane, ...editorService.visibleEditorPanes]) {
if (editor instanceof TextDiffEditor) {
return editor;
}
}
return undefined;
}
function navigateInDiffEditor(accessor: ServicesAccessor, next: boolean): void {
const activeTextDiffEditor = getActiveTextDiffEditor(accessor);
if (activeTextDiffEditor) {
const navigator = activeTextDiffEditor.getDiffNavigator();
if (navigator) {
next ? navigator.next() : navigator.previous();
}
}
}
enum FocusTextDiffEditorMode {
Original,
Modified,
Toggle
}
function focusInDiffEditor(accessor: ServicesAccessor, mode: FocusTextDiffEditorMode): void {
const activeTextDiffEditor = getActiveTextDiffEditor(accessor);
if (activeTextDiffEditor) {
switch (mode) {
case FocusTextDiffEditorMode.Original:
activeTextDiffEditor.getControl()?.getOriginalEditor().focus();
break;
case FocusTextDiffEditorMode.Modified:
activeTextDiffEditor.getControl()?.getModifiedEditor().focus();
break;
case FocusTextDiffEditorMode.Toggle:
if (activeTextDiffEditor.getControl()?.getModifiedEditor().hasWidgetFocus()) {
return focusInDiffEditor(accessor, FocusTextDiffEditorMode.Original);
} else {
return focusInDiffEditor(accessor, FocusTextDiffEditorMode.Modified);
}
}
}
}
function toggleDiffSideBySide(accessor: ServicesAccessor): void {
const configurationService = accessor.get(IConfigurationService);
const newValue = !configurationService.getValue<boolean>('diffEditor.renderSideBySide');
configurationService.updateValue('diffEditor.renderSideBySide', newValue, ConfigurationTarget.USER);
configurationService.updateValue('diffEditor.renderSideBySide', newValue);
}
function toggleDiffIgnoreTrimWhitespace(accessor: ServicesAccessor): void {
const configurationService = accessor.get(IConfigurationService);
const newValue = !configurationService.getValue<boolean>('diffEditor.ignoreTrimWhitespace');
configurationService.updateValue('diffEditor.ignoreTrimWhitespace', newValue, ConfigurationTarget.USER);
configurationService.updateValue('diffEditor.ignoreTrimWhitespace', newValue);
}
KeybindingsRegistry.registerCommandAndKeybindingRule({
@@ -299,6 +381,30 @@ function registerDiffEditorCommands(): void {
handler: accessor => toggleDiffSideBySide(accessor)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: DIFF_FOCUS_PRIMARY_SIDE,
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: undefined,
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Modified)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: DIFF_FOCUS_SECONDARY_SIDE,
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: undefined,
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Original)
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: DIFF_FOCUS_OTHER_SIDE,
weight: KeybindingWeight.WorkbenchContrib,
when: undefined,
primary: undefined,
handler: accessor => focusInDiffEditor(accessor, FocusTextDiffEditorMode.Toggle)
});
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: TOGGLE_DIFF_SIDE_BY_SIDE,
@@ -320,6 +426,88 @@ function registerDiffEditorCommands(): void {
});
}
function registerOpenEditorAPICommands(): void {
function mixinContext(context: IOpenEvent<unknown> | undefined, options: ITextEditorOptions | undefined, column: EditorGroupColumn | undefined): [ITextEditorOptions | undefined, EditorGroupColumn | undefined] {
if (!context) {
return [options, column];
}
return [
{ ...context.editorOptions, ...(options ?? Object.create(null)) },
context.sideBySide ? SIDE_GROUP : column
];
}
CommandsRegistry.registerCommand(API_OPEN_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, resourceArg: UriComponents, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], label?: string, context?: IOpenEvent<unknown>) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const openerService = accessor.get(IOpenerService);
const resource = URI.revive(resourceArg);
const [columnArg, optionsArg] = columnAndOptions ?? [];
// use editor options or editor view column as a hint to use the editor service for opening
if (optionsArg || typeof columnArg === 'number') {
const [options, column] = mixinContext(context, optionsArg, columnArg);
await editorService.openEditor({ resource, options, label }, viewColumnToEditorGroup(editorGroupService, column));
}
// do not allow to execute commands from here
else if (resource.scheme === 'command') {
return;
}
// finally, delegate to opener service
else {
await openerService.open(resource, { openToSide: context?.sideBySide, editorOptions: context?.editorOptions });
}
});
CommandsRegistry.registerCommand(API_OPEN_DIFF_EDITOR_COMMAND_ID, async function (accessor: ServicesAccessor, leftResource: UriComponents, rightResource: UriComponents, label?: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?], context?: IOpenEvent<unknown>) {
const editorService = accessor.get(IEditorService);
const editorGroupService = accessor.get(IEditorGroupsService);
const [columnArg, optionsArg] = columnAndOptions ?? [];
const [options, column] = mixinContext(context, optionsArg, columnArg);
await editorService.openEditor({
leftResource: URI.revive(leftResource),
rightResource: URI.revive(rightResource),
label,
options
}, viewColumnToEditorGroup(editorGroupService, column));
});
CommandsRegistry.registerCommand(API_OPEN_WITH_EDITOR_COMMAND_ID, (accessor: ServicesAccessor, resource: UriComponents, id: string, columnAndOptions?: [EditorGroupColumn?, ITextEditorOptions?]) => {
const editorService = accessor.get(IEditorService);
const editorGroupsService = accessor.get(IEditorGroupsService);
const configurationService = accessor.get(IConfigurationService);
const quickInputService = accessor.get(IQuickInputService);
const [columnArg, optionsArg] = columnAndOptions ?? [];
let group: IEditorGroup | undefined = undefined;
if (columnArg === SIDE_GROUP) {
const direction = preferredSideBySideGroupDirection(configurationService);
let neighbourGroup = editorGroupsService.findGroup({ direction });
if (!neighbourGroup) {
neighbourGroup = editorGroupsService.addGroup(editorGroupsService.activeGroup, direction);
}
group = neighbourGroup;
} else {
group = editorGroupsService.getGroup(viewColumnToEditorGroup(editorGroupsService, columnArg)) ?? editorGroupsService.activeGroup;
}
const textOptions: ITextEditorOptions = optionsArg ? { ...optionsArg, override: false } : { override: false };
const input = editorService.createEditorInput({ resource: URI.revive(resource) });
return openEditorWith(input, id, textOptions, group, editorService, configurationService, quickInputService);
});
}
function registerOpenEditorAtIndexCommands(): void {
const openEditorAtIndex: ICommandHandler = (accessor: ServicesAccessor, editorIndex: number): void => {
const editorService = accessor.get(IEditorService);
@@ -710,6 +898,31 @@ function registerOtherEditorCommands(): void {
}
});
CommandsRegistry.registerCommand({
id: TOGGLE_KEEP_EDITORS_COMMAND_ID,
handler: accessor => {
const configurationService = accessor.get(IConfigurationService);
const notificationService = accessor.get(INotificationService);
const openerService = accessor.get(IOpenerService);
// Update setting
const currentSetting = configurationService.getValue<boolean>('workbench.editor.enablePreview');
const newSetting = currentSetting === true ? false : true;
configurationService.updateValue('workbench.editor.enablePreview', newSetting);
// Inform user
notificationService.prompt(
Severity.Info,
newSetting ?
nls.localize('enablePreview', "Preview editors have been enabled in settings.") :
nls.localize('disablePreview', "Preview editors have been disabled in settings."),
[{
label: nls.localize('learnMode', "Learn More"), run: () => openerService.open('https://go.microsoft.com/fwlink/?linkid=2147473')
}]
);
}
});
KeybindingsRegistry.registerCommandAndKeybindingRule({
id: PIN_EDITOR_COMMAND_ID,
weight: KeybindingWeight.WorkbenchContrib,
@@ -877,6 +1090,7 @@ export function setup(): void {
registerActiveEditorMoveCommand();
registerEditorGroupsLayoutCommand();
registerDiffEditorCommands();
registerOpenEditorAPICommands();
registerOpenEditorAtIndexCommands();
registerCloseEditorCommands();
registerOtherEditorCommands();

View File

@@ -12,7 +12,7 @@ import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { IEditorIdentifier, EditorInput, EditorOptions } from 'vs/workbench/common/editor';
import { isMacintosh, isWeb } from 'vs/base/common/platform';
import { GroupDirection, MergeGroupMode, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
import { GroupDirection, IEditorGroupsService, MergeGroupMode, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
import { toDisposable } from 'vs/base/common/lifecycle';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { RunOnceScheduler } from 'vs/base/common/async';
@@ -25,6 +25,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { localize } from 'vs/nls';
import { ByteSize } from 'vs/platform/files/common/files';
interface IDropOperation {
splitDirection?: GroupDirection;
@@ -34,7 +35,7 @@ class DropOverlay extends Themable {
private static readonly OVERLAY_ID = 'monaco-workbench-editor-drop-overlay';
private static readonly MAX_FILE_UPLOAD_SIZE = 100 * 1024 * 1024; // 100mb
private static readonly MAX_FILE_UPLOAD_SIZE = 100 * ByteSize.MB;
private container: HTMLElement | undefined;
private overlay: HTMLElement | undefined;
@@ -54,7 +55,8 @@ class DropOverlay extends Themable {
@IInstantiationService private instantiationService: IInstantiationService,
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IEditorService private readonly editorService: IEditorService,
@INotificationService private readonly notificationService: INotificationService
@INotificationService private readonly notificationService: INotificationService,
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
) {
super(themeService);
@@ -143,8 +145,14 @@ class DropOverlay extends Themable {
}
}
// Position overlay
this.positionOverlay(e.offsetX, e.offsetY, isDraggingGroup);
// Position overlay and conditionally enable or disable
// editor group splitting support based on setting and
// keymodifiers used.
let splitOnDragAndDrop = !!this.editorGroupService.partOptions.splitOnDragAndDrop;
if (this.isToggleSplitOperation(e)) {
splitOnDragAndDrop = !splitOnDragAndDrop;
}
this.positionOverlay(e.offsetX, e.offsetY, isDraggingGroup, splitOnDragAndDrop);
// Make sure to stop any running cleanup scheduler to remove the overlay
if (this.cleanupOverlayScheduler.isScheduled()) {
@@ -319,7 +327,7 @@ class DropOverlay extends Themable {
// Try to come up with a good file path for the untitled
// editor by asking the file dialog service for the default
let proposedFilePath: URI | undefined = undefined;
const defaultFilePath = this.fileDialogService.defaultFilePath();
const defaultFilePath = await this.fileDialogService.defaultFilePath();
if (defaultFilePath) {
proposedFilePath = joinPath(defaultFilePath, name);
}
@@ -362,24 +370,33 @@ class DropOverlay extends Themable {
return (e.ctrlKey && !isMacintosh) || (e.altKey && isMacintosh);
}
private positionOverlay(mousePosX: number, mousePosY: number, isDraggingGroup: boolean): void {
private isToggleSplitOperation(e: DragEvent): boolean {
return (e.altKey && !isMacintosh) || (e.shiftKey && isMacintosh);
}
private positionOverlay(mousePosX: number, mousePosY: number, isDraggingGroup: boolean, enableSplitting: boolean): void {
const preferSplitVertically = this.accessor.partOptions.openSideBySideDirection === 'right';
const editorControlWidth = this.groupView.element.clientWidth;
const editorControlHeight = this.groupView.element.clientHeight - this.getOverlayOffsetHeight();
let edgeWidthThresholdFactor: number;
if (isDraggingGroup) {
edgeWidthThresholdFactor = preferSplitVertically ? 0.3 : 0.1; // give larger threshold when dragging group depending on preferred split direction
} else {
edgeWidthThresholdFactor = 0.1; // 10% threshold to split if dragging editors
}
let edgeHeightThresholdFactor: number;
if (isDraggingGroup) {
edgeHeightThresholdFactor = preferSplitVertically ? 0.1 : 0.3; // give larger threshold when dragging group depending on preferred split direction
if (enableSplitting) {
if (isDraggingGroup) {
edgeWidthThresholdFactor = preferSplitVertically ? 0.3 : 0.1; // give larger threshold when dragging group depending on preferred split direction
} else {
edgeWidthThresholdFactor = 0.1; // 10% threshold to split if dragging editors
}
if (isDraggingGroup) {
edgeHeightThresholdFactor = preferSplitVertically ? 0.1 : 0.3; // give larger threshold when dragging group depending on preferred split direction
} else {
edgeHeightThresholdFactor = 0.1; // 10% threshold to split if dragging editors
}
} else {
edgeHeightThresholdFactor = 0.1; // 10% threshold to split if dragging editors
edgeWidthThresholdFactor = 0;
edgeHeightThresholdFactor = 0;
}
const edgeWidthThreshold = editorControlWidth * edgeWidthThresholdFactor;

View File

@@ -1742,28 +1742,17 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
private override: (() => Promise<IEditorPane | undefined>) | undefined = undefined;
constructor(
private _group: GroupIdentifier,
private _editor: EditorInput,
public readonly groupId: GroupIdentifier,
public readonly editor: EditorInput,
private _options: EditorOptions | undefined,
private _context: OpenEditorContext | undefined
public readonly context: OpenEditorContext | undefined
) {
}
get groupId(): GroupIdentifier {
return this._group;
}
get editor(): EditorInput {
return this._editor;
}
get options(): EditorOptions | undefined {
return this._options;
}
get context(): OpenEditorContext | undefined {
return this._context;
}
prevent(callback: () => Promise<IEditorPane | undefined>): void {
this.override = callback;
@@ -1775,9 +1764,9 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
}
export interface EditorReplacement {
editor: EditorInput;
replacement: EditorInput;
options?: EditorOptions;
readonly editor: EditorInput;
readonly replacement: EditorInput;
readonly options?: EditorOptions;
}
registerThemingParticipant((theme, collector, environment) => {

View File

@@ -9,7 +9,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IEditorGroup, IEditorGroupsService, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { LRUCache, Touch } from 'vs/base/common/map';
import { URI } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
@@ -156,7 +156,7 @@ export abstract class EditorPane extends Composite implements IEditorPane {
let editorMemento = EditorPane.EDITOR_MEMENTOS.get(mementoKey);
if (!editorMemento) {
editorMemento = new EditorMemento(this.getId(), key, this.getMemento(StorageScope.WORKSPACE), limit, editorGroupService);
editorMemento = new EditorMemento(this.getId(), key, this.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE), limit, editorGroupService);
EditorPane.EDITOR_MEMENTOS.set(mementoKey, editorMemento);
}
@@ -220,18 +220,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
// Automatically clear when editor input gets disposed if any
if (resourceOrEditor instanceof EditorInput) {
const editor = resourceOrEditor;
if (!this.editorDisposables) {
this.editorDisposables = new Map<EditorInput, IDisposable>();
}
if (!this.editorDisposables.has(editor)) {
this.editorDisposables.set(editor, Event.once(resourceOrEditor.onDispose)(() => {
this.clearEditorState(resource);
this.editorDisposables?.delete(editor);
}));
}
this.clearEditorStateOnDispose(resource, resourceOrEditor);
}
}
@@ -240,7 +229,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
loadEditorState(group: IEditorGroup, resourceOrEditor: URI | EditorInput, fallbackToOtherGroupState?: boolean): T | undefined {
const resource = this.doGetResource(resourceOrEditor);
if (!resource || !group) {
return undefined; // we are not in a good state to load any state for a resource
return; // we are not in a good state to load any state for a resource
}
const cache = this.doLoad();
@@ -261,12 +250,16 @@ export class EditorMemento<T> implements IEditorMemento<T> {
}
}
return undefined;
return;
}
clearEditorState(resource: URI, group?: IEditorGroup): void;
clearEditorState(editor: EditorInput, group?: IEditorGroup): void;
clearEditorState(resourceOrEditor: URI | EditorInput, group?: IEditorGroup): void {
if (resourceOrEditor instanceof EditorInput) {
this.editorDisposables?.delete(resourceOrEditor);
}
const resource = this.doGetResource(resourceOrEditor);
if (resource) {
const cache = this.doLoad();
@@ -286,6 +279,19 @@ export class EditorMemento<T> implements IEditorMemento<T> {
}
}
clearEditorStateOnDispose(resource: URI, editor: EditorInput): void {
if (!this.editorDisposables) {
this.editorDisposables = new Map<EditorInput, IDisposable>();
}
if (!this.editorDisposables.has(editor)) {
this.editorDisposables.set(editor, Event.once(editor.onDispose)(() => {
this.clearEditorState(resource);
this.editorDisposables?.delete(editor);
}));
}
}
moveEditorState(source: URI, target: URI, comparer: IExtUri): void {
const cache = this.doLoad();
@@ -342,7 +348,7 @@ export class EditorMemento<T> implements IEditorMemento<T> {
saveState(): void {
const cache = this.doLoad();
// Cleanup once during shutdown
// Cleanup once during session
if (!this.cleanedUp) {
this.cleanUp();
this.cleanedUp = true;

View File

@@ -19,7 +19,7 @@ import { IEditorGroupsAccessor, IEditorGroupView, getEditorPartOptions, impactsE
import { EditorGroupView } from 'vs/workbench/browser/parts/editor/editorGroupView';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
import { EditorDropTarget, IEditorDropTargetDelegate } from 'vs/workbench/browser/parts/editor/editorDropTarget';
import { IEditorDropService } from 'vs/workbench/services/editor/browser/editorDropService';
@@ -148,8 +148,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
this.gridWidgetView = new GridWidgetView<IEditorGroupView>();
this.workspaceMemento = this.getMemento(StorageScope.WORKSPACE);
this.globalMemento = this.getMemento(StorageScope.GLOBAL);
this.workspaceMemento = this.getMemento(StorageScope.WORKSPACE, StorageTarget.MACHINE);
this.globalMemento = this.getMemento(StorageScope.GLOBAL, StorageTarget.MACHINE);
this._whenRestored = new Promise(resolve => (this.whenRestoredResolve = resolve));

View File

@@ -6,7 +6,7 @@
import 'vs/css!./media/editorstatus';
import * as nls from 'vs/nls';
import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom';
import { format, compare } from 'vs/base/common/strings';
import { format, compare, splitLines } from 'vs/base/common/strings';
import { extname, basename, isEqual } from 'vs/base/common/resources';
import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { URI } from 'vs/base/common/uri';
@@ -346,12 +346,12 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution {
[{
label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"),
run: () => {
this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER);
this.configurationService.updateValue('editor.accessibilitySupport', 'on');
}
}, {
label: nls.localize('screenReaderDetectedExplanation.answerNo', "No"),
run: () => {
this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER);
this.configurationService.updateValue('editor.accessibilitySupport', 'off');
}
}],
{ sticky: true }
@@ -918,7 +918,7 @@ class ShowCurrentMarkerInStatusbarContribution extends Disposable {
this.currentMarker = this.getMarker();
if (this.hasToUpdateStatus(previousMarker, this.currentMarker)) {
if (this.currentMarker) {
const line = this.currentMarker.message.split(/\r\n|\r|\n/g)[0];
const line = splitLines(this.currentMarker.message)[0];
const text = `${this.getType(this.currentMarker)} ${line}`;
if (!this.statusBarEntryAccessor.value) {
this.statusBarEntryAccessor.value = this.statusbarService.addEntry({ text: '', ariaLabel: '' }, 'statusbar.currentProblem', nls.localize('currentProblem', "Current Problem"), StatusbarAlignment.LEFT);
@@ -1046,12 +1046,19 @@ export class ChangeModeAction extends Action {
@IQuickInputService private readonly quickInputService: IQuickInputService,
@IPreferencesService private readonly preferencesService: IPreferencesService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ITextFileService private readonly textFileService: ITextFileService
@ITextFileService private readonly textFileService: ITextFileService,
@ICommandService private readonly commandService: ICommandService
) {
super(actionId, actionLabel);
}
async run(): Promise<void> {
const activeEditorPane = this.editorService.activeEditorPane as unknown as { isNotebookEditor?: boolean } | undefined;
if (activeEditorPane?.isNotebookEditor) {
// it's inside notebook editor
return this.commandService.executeCommand('notebook.cell.changeLanguage');
}
const activeTextEditorControl = getCodeEditor(this.editorService.activeTextEditorControl);
if (!activeTextEditorControl) {
await this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]);
@@ -1143,7 +1150,7 @@ export class ChangeModeAction extends Action {
// User decided to configure settings for current language
if (pick === configureModeSettings) {
this.preferencesService.openGlobalSettings(true, { editSetting: `[${withUndefinedAsNull(currentModeId)}]` });
this.preferencesService.openGlobalSettings(true, { revealSetting: { key: `[${withUndefinedAsNull(currentModeId)}]`, edit: true } });
return;
}

View File

@@ -38,6 +38,8 @@ export class FloatingClickWidget extends Widget implements IOverlayWidget {
super();
this._domNode = $('.floating-click-widget');
this._domNode.style.padding = '10px';
this._domNode.style.cursor = 'pointer';
if (keyBindingAction) {
const keybinding = keybindingService.lookupKeybinding(keyBindingAction);

View File

@@ -5,7 +5,7 @@
import { IEditorInput, IEditorInputFactoryRegistry, IEditorIdentifier, GroupIdentifier, Extensions, IEditorPartOptionsChangeEvent, EditorsOrder, EditorResourceAccessor, SideBySideEditor } from 'vs/workbench/common/editor';
import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Registry } from 'vs/platform/registry/common/platform';
import { Event, Emitter } from 'vs/base/common/event';
import { IEditorGroupsService, IEditorGroup, GroupChangeKind, GroupsOrder } from 'vs/workbench/services/editor/common/editorGroupsService';
@@ -339,7 +339,7 @@ export class EditorsObserver extends Disposable {
if (this.mostRecentEditorsMap.isEmpty()) {
this.storageService.remove(EditorsObserver.STORAGE_KEY, StorageScope.WORKSPACE);
} else {
this.storageService.store(EditorsObserver.STORAGE_KEY, JSON.stringify(this.serialize()), StorageScope.WORKSPACE);
this.storageService.store(EditorsObserver.STORAGE_KEY, JSON.stringify(this.serialize()), StorageScope.WORKSPACE, StorageTarget.MACHINE);
}
}

View File

@@ -21,7 +21,7 @@
padding-right: 6px;
}
/* todo@joh move somewhere else */
/* breadcrumbs-picker-style */
.monaco-workbench .monaco-breadcrumbs-picker .arrow {
position: absolute;

View File

@@ -589,8 +589,8 @@ export class TabsTitleControl extends TitleControl {
const tabActionRunner = new EditorCommandsContextActionRunner({ groupId: this.group.id, editorIndex: index });
const tabActionBar = new ActionBar(tabActionsContainer, { ariaLabel: localize('ariaLabelTabActions', "Tab actions"), actionRunner: tabActionRunner, });
tabActionBar.onDidBeforeRun(e => {
const tabActionBar = new ActionBar(tabActionsContainer, { ariaLabel: localize('ariaLabelTabActions', "Tab actions"), actionRunner: tabActionRunner });
tabActionBar.onBeforeRun(e => {
if (e.action.id === this.closeEditorAction.id) {
this.blockRevealActiveTabOnce();
}

View File

@@ -24,7 +24,6 @@ import { ScrollType, IDiffEditorViewState, IDiffEditorModel } from 'vs/editor/co
import { DisposableStore } from 'vs/base/common/lifecycle';
import { Registry } from 'vs/platform/registry/common/platform';
import { URI } from 'vs/base/common/uri';
import { Event } from 'vs/base/common/event';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -32,6 +31,7 @@ import { EditorActivation, IEditorOptions } from 'vs/platform/editor/common/edit
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { isEqual } from 'vs/base/common/resources';
import { multibyteAwareBtoa } from 'vs/base/browser/dom';
import { IFileService } from 'vs/platform/files/common/files';
/**
* The text editor that leverages the diff text editor for the editing experience.
@@ -62,9 +62,28 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
@ITextResourceConfigurationService configurationService: ITextResourceConfigurationService,
@IEditorService editorService: IEditorService,
@IThemeService themeService: IThemeService,
@IEditorGroupsService editorGroupService: IEditorGroupsService
@IEditorGroupsService editorGroupService: IEditorGroupsService,
@IFileService private readonly fileService: IFileService
) {
super(TextDiffEditor.ID, telemetryService, instantiationService, storageService, configurationService, themeService, editorService, editorGroupService);
// Listen to file system provider changes
this._register(this.fileService.onDidChangeFileSystemProviderCapabilities(e => this.onDidFileSystemProviderChange(e.scheme)));
this._register(this.fileService.onDidChangeFileSystemProviderRegistrations(e => this.onDidFileSystemProviderChange(e.scheme)));
}
private onDidFileSystemProviderChange(scheme: string): void {
const control = this.getControl();
const input = this.input;
if (control && input instanceof DiffEditorInput) {
if (input.originalInput.resource?.scheme === scheme || input.modifiedInput.resource?.scheme === scheme) {
control.updateOptions({
readOnly: input.modifiedInput.isReadonly(),
originalEditable: !input.originalInput.isReadonly()
});
}
}
}
protected onWillCloseEditorInGroup(editor: IEditorInput): void {
@@ -175,7 +194,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
const originalInput = input.originalInput;
const modifiedInput = input.modifiedInput;
const binaryDiffInput = new DiffEditorInput(input.getName(), input.getDescription(), originalInput, modifiedInput, true);
const binaryDiffInput = this.instantiationService.createInstance(DiffEditorInput, input.getName(), input.getDescription(), originalInput, modifiedInput, true);
// Forward binary flag to input if supported
const fileEditorInputFactory = Registry.as<IEditorInputFactoryRegistry>(EditorInputExtensions.EditorInputFactories).getFileEditorInputFactory();
@@ -217,16 +236,17 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
// Handle diff editor specially by merging in diffEditor configuration
if (isObject(configuration.diffEditor)) {
// User settings defines `diffEditor.codeLens`, but there is also `editor.codeLens`.
// Due to the mixin, the two settings cannot be distinguished anymore.
//
// So we map `diffEditor.codeLens` to `diffEditor.originalCodeLens` and `diffEditor.modifiedCodeLens`.
const diffEditorConfiguration = <IDiffEditorOptions>objects.deepClone(configuration.diffEditor);
diffEditorConfiguration.originalCodeLens = diffEditorConfiguration.codeLens;
diffEditorConfiguration.modifiedCodeLens = diffEditorConfiguration.codeLens;
// User settings defines `diffEditor.codeLens`, but here we rename that to `diffEditor.diffCodeLens` to avoid collisions with `editor.codeLens`.
diffEditorConfiguration.diffCodeLens = diffEditorConfiguration.codeLens;
delete diffEditorConfiguration.codeLens;
objects.mixin(editorConfiguration, diffEditorConfiguration);
// User settings defines `diffEditor.wordWrap`, but here we rename that to `diffEditor.diffWordWrap` to avoid collisions with `editor.wordWrap`.
diffEditorConfiguration.diffWordWrap = <'off' | 'on' | 'inherit' | undefined>diffEditorConfiguration.wordWrap;
delete diffEditorConfiguration.wordWrap;
Object.assign(editorConfiguration, diffEditorConfiguration);
}
return editorConfiguration;
@@ -309,12 +329,7 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
// Otherwise save it
else {
super.saveTextEditorViewState(resource);
// Make sure to clean up when the input gets disposed
Event.once(input.onDispose)(() => {
super.clearTextEditorViewState([resource], this.group);
});
super.saveTextEditorViewState(resource, input);
}
}

View File

@@ -67,6 +67,7 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
@IEditorGroupsService protected editorGroupService: IEditorGroupsService
) {
super(id, telemetryService, themeService, storageService);
this._instantiationService = instantiationService;
this.editorMemento = this.getEditorMemento<IEditorViewState>(editorGroupService, BaseTextEditor.TEXT_EDITOR_VIEW_STATE_PREFERENCE_KEY, 100);
@@ -223,13 +224,27 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
return this.editorControl;
}
protected saveTextEditorViewState(resource: URI): void {
getViewState(): IEditorViewState | undefined {
const resource = this.input?.resource;
if (resource) {
return withNullAsUndefined(this.retrieveTextEditorViewState(resource));
}
return undefined;
}
protected saveTextEditorViewState(resource: URI, cleanUpOnDispose?: IEditorInput): void {
const editorViewState = this.retrieveTextEditorViewState(resource);
if (!editorViewState || !this.group) {
return;
}
this.editorMemento.saveEditorState(this.group, resource, editorViewState);
if (cleanUpOnDispose) {
this.editorMemento.clearEditorStateOnDispose(resource, cleanUpOnDispose);
}
}
protected shouldRestoreTextEditorViewState(editor: IEditorInput, context?: IEditorOpenContext): boolean {
@@ -243,15 +258,6 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
return true;
}
getViewState(): IEditorViewState | undefined {
const resource = this.input?.resource;
if (resource) {
return withNullAsUndefined(this.retrieveTextEditorViewState(resource));
}
return undefined;
}
protected retrieveTextEditorViewState(resource: URI): IEditorViewState | null {
const control = this.getControl();
if (!isCodeEditor(control)) {
@@ -284,9 +290,9 @@ export abstract class BaseTextEditor extends EditorPane implements ITextEditorPa
}
protected clearTextEditorViewState(resources: URI[], group?: IEditorGroup): void {
resources.forEach(resource => {
for (const resource of resources) {
this.editorMemento.clearEditorState(resource, group);
});
}
}
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {

View File

@@ -16,7 +16,6 @@ import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITextResourceConfigurationService } from 'vs/editor/common/services/textResourceConfigurationService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { Event } from 'vs/base/common/event';
import { ScrollType, IEditor } from 'vs/editor/common/editorCommon';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { CancellationToken } from 'vs/base/common/cancellation';
@@ -158,12 +157,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
// Otherwise save it
else {
super.saveTextEditorViewState(resource);
// Make sure to clean up when the input gets disposed
Event.once(input.onDispose)(() => {
super.clearTextEditorViewState([resource]);
});
super.saveTextEditorViewState(resource, input);
}
}
}

View File

@@ -105,18 +105,27 @@
overflow: hidden;
}
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container > .monaco-button-dropdown,
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container > .monaco-button {
margin: 4px 5px; /* allows button focus outline to be visible */
}
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-button {
outline-offset: 2px !important;
}
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-text-button {
width: fit-content;
width: -moz-fit-content;
padding: 5px 10px;
margin: 4px 5px; /* allows button focus outline to be visible */
display: inline-block; /* to enable ellipsis in text overflow */
font-size: 12px;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-text-button {
display: inline-block; /* to enable ellipsis in text overflow */
.monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-buttons-container .monaco-dropdown-button {
padding: 5px
}
/** Notification: Progress */

View File

@@ -26,7 +26,7 @@
}
.monaco-workbench > .notifications-toasts .notification-toast-container > .notification-toast {
margin: 5px; /* enables separation and drop shadows around toasts */
margin: 8px; /* enables separation and drop shadows around toasts */
transform: translate3d(0px, 100%, 0px); /* move the notification 50px to the bottom (to prevent bleed through) */
opacity: 0; /* fade the toast in */
transition: transform 300ms ease-out, opacity 300ms ease-out;

View File

@@ -12,14 +12,16 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { CLEAR_NOTIFICATION, EXPAND_NOTIFICATION, COLLAPSE_NOTIFICATION, CLEAR_ALL_NOTIFICATIONS, HIDE_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
const clearIcon = registerIcon('notifications-clear', Codicon.close);
const clearAllIcon = registerIcon('notifications-clear-all', Codicon.clearAll);
const hideIcon = registerIcon('notifications-hide', Codicon.chevronDown);
const expandIcon = registerIcon('notifications-expand', Codicon.chevronUp);
const collapseIcon = registerIcon('notifications-collapse', Codicon.chevronDown);
const configureIcon = registerIcon('notifications-configure', Codicon.gear);
const clearIcon = registerIcon('notifications-clear', Codicon.close, localize('clearIcon', 'Icon for the clear action in notifications.'));
const clearAllIcon = registerIcon('notifications-clear-all', Codicon.clearAll, localize('clearAllIcon', 'Icon for the clear all action in notifications.'));
const hideIcon = registerIcon('notifications-hide', Codicon.chevronDown, localize('hideIcon', 'Icon for the hide action in notifications.'));
const expandIcon = registerIcon('notifications-expand', Codicon.chevronUp, localize('expandIcon', 'Icon for the expand action in notifications.'));
const collapseIcon = registerIcon('notifications-collapse', Codicon.chevronDown, localize('collapseIcon', 'Icon for the collapse action in notifications.'));
const configureIcon = registerIcon('notifications-configure', Codicon.gear, localize('configureIcon', 'Icon for the configure action in notifications.'));
export class ClearNotificationAction extends Action {
@@ -31,7 +33,7 @@ export class ClearNotificationAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, clearIcon.classNames);
super(id, label, ThemeIcon.asClassName(clearIcon));
}
async run(notification: INotificationViewItem): Promise<void> {
@@ -49,7 +51,7 @@ export class ClearAllNotificationsAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, clearAllIcon.classNames);
super(id, label, ThemeIcon.asClassName(clearAllIcon));
}
async run(): Promise<void> {
@@ -67,7 +69,7 @@ export class HideNotificationsCenterAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, hideIcon.classNames);
super(id, label, ThemeIcon.asClassName(hideIcon));
}
async run(): Promise<void> {
@@ -85,7 +87,7 @@ export class ExpandNotificationAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, expandIcon.classNames);
super(id, label, ThemeIcon.asClassName(expandIcon));
}
async run(notification: INotificationViewItem): Promise<void> {
@@ -103,7 +105,7 @@ export class CollapseNotificationAction extends Action {
label: string,
@ICommandService private readonly commandService: ICommandService
) {
super(id, label, collapseIcon.classNames);
super(id, label, ThemeIcon.asClassName(collapseIcon));
}
async run(notification: INotificationViewItem): Promise<void> {
@@ -121,7 +123,7 @@ export class ConfigureNotificationAction extends Action {
label: string,
public readonly configurationActions: ReadonlyArray<IAction>
) {
super(id, label, configureIcon.classNames);
super(id, label, ThemeIcon.asClassName(configureIcon));
}
}

View File

@@ -251,7 +251,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
protected updateStyles(): void {
if (this.notificationsCenterContainer && this.notificationsCenterHeader) {
const widgetShadowColor = this.getColor(widgetShadow);
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : '';
this.notificationsCenterContainer.style.boxShadow = widgetShadowColor ? `0 0 8px 2px ${widgetShadowColor}` : '';
const borderColor = this.getColor(NOTIFICATIONS_CENTER_BORDER);
this.notificationsCenterContainer.style.border = borderColor ? `1px solid ${borderColor}` : '';

View File

@@ -15,20 +15,20 @@ import { IListService, WorkbenchList } from 'vs/platform/list/browser/listServic
// Center
export const SHOW_NOTIFICATIONS_CENTER = 'notifications.showList';
export const HIDE_NOTIFICATIONS_CENTER = 'notifications.hideList';
export const TOGGLE_NOTIFICATIONS_CENTER = 'notifications.toggleList';
const TOGGLE_NOTIFICATIONS_CENTER = 'notifications.toggleList';
// Toasts
export const HIDE_NOTIFICATION_TOAST = 'notifications.hideToasts';
export const FOCUS_NOTIFICATION_TOAST = 'notifications.focusToasts';
export const FOCUS_NEXT_NOTIFICATION_TOAST = 'notifications.focusNextToast';
export const FOCUS_PREVIOUS_NOTIFICATION_TOAST = 'notifications.focusPreviousToast';
export const FOCUS_FIRST_NOTIFICATION_TOAST = 'notifications.focusFirstToast';
export const FOCUS_LAST_NOTIFICATION_TOAST = 'notifications.focusLastToast';
const HIDE_NOTIFICATION_TOAST = 'notifications.hideToasts';
const FOCUS_NOTIFICATION_TOAST = 'notifications.focusToasts';
const FOCUS_NEXT_NOTIFICATION_TOAST = 'notifications.focusNextToast';
const FOCUS_PREVIOUS_NOTIFICATION_TOAST = 'notifications.focusPreviousToast';
const FOCUS_FIRST_NOTIFICATION_TOAST = 'notifications.focusFirstToast';
const FOCUS_LAST_NOTIFICATION_TOAST = 'notifications.focusLastToast';
// Notification
export const COLLAPSE_NOTIFICATION = 'notification.collapse';
export const EXPAND_NOTIFICATION = 'notification.expand';
export const TOGGLE_NOTIFICATION = 'notification.toggle';
const TOGGLE_NOTIFICATION = 'notification.toggle';
export const CLEAR_NOTIFICATION = 'notification.clear';
export const CLEAR_ALL_NOTIFICATIONS = 'notifications.clearAll';
@@ -159,12 +159,20 @@ export function registerNotificationCommands(center: INotificationsCenterControl
});
// Hide Toasts
KeybindingsRegistry.registerCommandAndKeybindingRule({
CommandsRegistry.registerCommand(HIDE_NOTIFICATION_TOAST, accessor => toasts.hide());
KeybindingsRegistry.registerKeybindingRule({
id: HIDE_NOTIFICATION_TOAST,
weight: KeybindingWeight.WorkbenchContrib + 50,
weight: KeybindingWeight.WorkbenchContrib - 50, // lower when not focused (e.g. let editor suggest win over this command)
when: NotificationsToastsVisibleContext,
primary: KeyCode.Escape,
handler: accessor => toasts.hide()
primary: KeyCode.Escape
});
KeybindingsRegistry.registerKeybindingRule({
id: HIDE_NOTIFICATION_TOAST,
weight: KeybindingWeight.WorkbenchContrib + 100, // higher when focused
when: ContextKeyExpr.and(NotificationsToastsVisibleContext, NotificationFocusedContext),
primary: KeyCode.Escape
});
// Focus Toasts

View File

@@ -482,7 +482,7 @@ export class NotificationsToasts extends Themable implements INotificationsToast
toast.style.background = backgroundColor ? backgroundColor : '';
const widgetShadowColor = this.getColor(widgetShadow);
toast.style.boxShadow = widgetShadowColor ? `0 0px 8px ${widgetShadowColor}` : '';
toast.style.boxShadow = widgetShadowColor ? `0 0 8px 2px ${widgetShadowColor}` : '';
const borderColor = this.getColor(NOTIFICATIONS_TOAST_BORDER);
toast.style.border = borderColor ? `1px solid ${borderColor}` : '';

View File

@@ -8,11 +8,11 @@ import { clearNode, addDisposableListener, EventType, EventHelper, $ } from 'vs/
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { URI } from 'vs/base/common/uri';
import { localize } from 'vs/nls';
import { ButtonGroup } from 'vs/base/browser/ui/button/button';
import { ButtonBar } from 'vs/base/browser/ui/button/button';
import { attachButtonStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IAction, IActionRunner } from 'vs/base/common/actions';
import { ActionRunner, ActionWithMenuAction, IAction, IActionRunner } from 'vs/base/common/actions';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { dispose, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
@@ -285,7 +285,8 @@ export class NotificationTemplateRenderer extends Disposable {
@IOpenerService private readonly openerService: IOpenerService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService private readonly themeService: IThemeService,
@IKeybindingService private readonly keybindingService: IKeybindingService
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
) {
super();
@@ -441,27 +442,40 @@ export class NotificationTemplateRenderer extends Disposable {
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 = primaryActions[index];
button.label = action.label;
this.inputDisposables.add(button.onDidClick(e => {
EventHelper.stop(e, true);
const that = this;
const actionRunner: IActionRunner = new class extends ActionRunner {
protected async runAction(action: IAction): Promise<void> {
// Run action
this.actionRunner.run(action, notification);
that.actionRunner.run(action, notification);
// Hide notification (unless explicitly prevented)
if (!(action instanceof ChoiceAction) || !action.keepOpen) {
notification.close();
}
}
}();
const buttonToolbar = this.inputDisposables.add(new ButtonBar(this.template.buttonsContainer));
for (const action of primaryActions) {
const buttonOptions = { title: true, /* assign titles to buttons in case they overflow */ };
const dropdownActions = action instanceof ChoiceAction ? action.menu
: action instanceof ActionWithMenuAction ? action.actions : undefined;
const button = this.inputDisposables.add(
dropdownActions
? buttonToolbar.addButtonWithDropdown({
...buttonOptions,
contextMenuProvider: this.contextMenuService,
actions: dropdownActions,
actionRunner
})
: buttonToolbar.addButton(buttonOptions));
button.label = action.label;
this.inputDisposables.add(button.onDidClick(e => {
EventHelper.stop(e, true);
actionRunner.run(action);
}));
this.inputDisposables.add(attachButtonStyler(button, this.themeService));
});
this.inputDisposables.add(buttonGroup);
}
}
}

View File

@@ -84,10 +84,6 @@
justify-content: center;
}
.monaco-workbench .part.panel > .composite.title > .composite-bar-excess {
width: 100px;
}
.monaco-workbench .part.panel > .composite.title> .panel-switcher-container > .monaco-action-bar {
line-height: 27px; /* matches panel titles in settings */
height: 35px;

View File

@@ -18,11 +18,13 @@ import { IActivity } from 'vs/workbench/common/activity';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel';
import { ContextKeyExpression } from 'vs/platform/contextkey/common/contextkey';
import { Codicon, registerIcon } from 'vs/base/common/codicons';
import { Codicon } from 'vs/base/common/codicons';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp);
const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown);
const closeIcon = registerIcon('panel-close', Codicon.close);
const maximizeIcon = registerIcon('panel-maximize', Codicon.chevronUp, nls.localize('maximizeIcon', 'Icon to maximize a panel.'));
const restoreIcon = registerIcon('panel-restore', Codicon.chevronDown, nls.localize('restoreIcon', 'Icon to restore a panel.'));
const closeIcon = registerIcon('panel-close', Codicon.close, nls.localize('closeIcon', 'Icon to close a panel.'));
export class ClosePanelAction extends Action {
@@ -34,7 +36,7 @@ export class ClosePanelAction extends Action {
name: string,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService
) {
super(id, name, closeIcon.classNames);
super(id, name, ThemeIcon.asClassName(closeIcon));
}
async run(): Promise<void> {
@@ -106,11 +108,11 @@ export class ToggleMaximizedPanelAction extends Action {
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@IEditorGroupsService editorGroupsService: IEditorGroupsService
) {
super(id, label, layoutService.isPanelMaximized() ? restoreIcon.classNames : maximizeIcon.classNames);
super(id, label, layoutService.isPanelMaximized() ? ThemeIcon.asClassName(restoreIcon) : ThemeIcon.asClassName(maximizeIcon));
this.toDispose.add(editorGroupsService.onDidLayout(() => {
const maximized = this.layoutService.isPanelMaximized();
this.class = maximized ? restoreIcon.classNames : maximizeIcon.classNames;
this.class = maximized ? ThemeIcon.asClassName(restoreIcon) : ThemeIcon.asClassName(maximizeIcon);
this.label = maximized ? ToggleMaximizedPanelAction.RESTORE_LABEL : ToggleMaximizedPanelAction.MAXIMIZE_LABEL;
}));
}

View File

@@ -13,7 +13,7 @@ import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/
import { Panel, PanelRegistry, Extensions as PanelExtensions, PanelDescriptor } from 'vs/workbench/browser/panel';
import { IPanelService, IPanelIdentifier } from 'vs/workbench/services/panel/common/panelService';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -37,7 +37,6 @@ import { ViewContainer, IViewDescriptorService, IViewContainerModel, ViewContain
import { MenuId } from 'vs/platform/actions/common/actions';
import { ViewMenuActions, ViewContainerMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { Before2D, CompositeDragAndDropObserver, ICompositeDragAndDrop, toggleDropEffect } from 'vs/workbench/browser/dnd';
import { IActivity } from 'vs/workbench/common/activity';
@@ -118,7 +117,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
@IViewDescriptorService private readonly viewDescriptorService: IViewDescriptorService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IExtensionService private readonly extensionService: IExtensionService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService
) {
super(
notificationService,
@@ -140,7 +138,6 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
);
this.panelRegistry = Registry.as<PanelRegistry>(PanelExtensions.Panels);
storageKeysSyncRegistryService.registerStorageKey({ key: PanelPart.PINNED_PANELS, version: 1 });
this.dndHandler = new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
(id: string, focus?: boolean) => (this.openPanel(id, focus) as Promise<IPaneComposite | undefined>).then(panel => panel || null),
@@ -338,7 +335,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
disposables.clear();
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedPanels(), this, disposables);
this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e), this, disposables);
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
}));
}
@@ -670,7 +667,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
return this.toolBar.getItemsWidth();
}
private onDidStorageChange(e: IWorkspaceStorageChangeEvent): void {
private onDidStorageValueChange(e: IStorageValueChangeEvent): 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 = undefined;
@@ -760,7 +757,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
private setStoredCachedViewletsValue(value: string): void {
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL);
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL, StorageTarget.USER);
}
private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
@@ -792,7 +789,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
}
private setStoredPlaceholderViewContainersValue(value: string): void {
this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE);
this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE, StorageTarget.MACHINE);
}
private getViewContainer(panelId: string): ViewContainer | undefined {

View File

@@ -23,7 +23,7 @@ import { isThemeColor } from 'vs/editor/common/editorCommon';
import { Color } from 'vs/base/common/color';
import { EventHelper, createStyleSheet, addDisposableListener, EventType, hide, show, isAncestor, appendChildren } from 'vs/base/browser/dom';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { coalesce } from 'vs/base/common/arrays';
@@ -32,7 +32,6 @@ import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/la
import { assertIsDefined } from 'vs/base/common/types';
import { Emitter } from 'vs/base/common/event';
import { Command } from 'vs/editor/common/modes';
import { IStorageKeysSyncRegistryService } from 'vs/platform/userDataSync/common/storageKeys';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
@@ -102,10 +101,10 @@ class StatusbarViewModel extends Disposable {
}
private registerListeners(): void {
this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e)));
this._register(this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e)));
}
private onDidStorageChange(event: IWorkspaceStorageChangeEvent): void {
private onDidStorageValueChange(event: IStorageValueChangeEvent): void {
if (event.key === StatusbarViewModel.HIDDEN_ENTRIES_KEY && event.scope === StorageScope.GLOBAL) {
// Keep current hidden entries
@@ -275,7 +274,7 @@ class StatusbarViewModel extends Disposable {
private saveState(): void {
if (this.hidden.size > 0) {
this.storageService.store(StatusbarViewModel.HIDDEN_ENTRIES_KEY, JSON.stringify(Array.from(this.hidden.values())), StorageScope.GLOBAL);
this.storageService.store(StatusbarViewModel.HIDDEN_ENTRIES_KEY, JSON.stringify(Array.from(this.hidden.values())), StorageScope.GLOBAL, StorageTarget.USER);
} else {
this.storageService.remove(StatusbarViewModel.HIDDEN_ENTRIES_KEY, StorageScope.GLOBAL);
}
@@ -405,12 +404,9 @@ export class StatusbarPart extends Part implements IStatusbarService {
@IWorkbenchLayoutService layoutService: IWorkbenchLayoutService,
@IContextMenuService private contextMenuService: IContextMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
@IStorageKeysSyncRegistryService storageKeysSyncRegistryService: IStorageKeysSyncRegistryService,
) {
super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService);
storageKeysSyncRegistryService.registerStorageKey({ key: StatusbarViewModel.HIDDEN_ENTRIES_KEY, version: 1 });
this.registerListeners();
}

View File

@@ -11,7 +11,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IAction, Action, SubmenuAction, Separator } from 'vs/base/common/actions';
import * as DOM from 'vs/base/browser/dom';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { isMacintosh, isWeb, isIOS } from 'vs/base/common/platform';
import { isMacintosh, isWeb, isIOS, isNative } from 'vs/base/common/platform';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { Event, Emitter } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
@@ -21,7 +21,7 @@ import { MENUBAR_SELECTION_FOREGROUND, MENUBAR_SELECTION_BACKGROUND, MENUBAR_SEL
import { URI } from 'vs/base/common/uri';
import { ILabelService } from 'vs/platform/label/common/label';
import { IUpdateService, StateType } from 'vs/platform/update/common/update';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
@@ -122,7 +122,7 @@ export abstract class MenubarControl extends Disposable {
this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e)));
// Listen to update service
this.updateService.onStateChange(() => this.updateMenubar());
this.updateService.onStateChange(() => this.onUpdateStateChange());
// Listen for changes in recently opened menu
this._register(this.workspacesService.onRecentlyOpenedChange(() => { this.onRecentlyOpenedChange(); }));
@@ -148,6 +148,14 @@ export abstract class MenubarControl extends Disposable {
return label;
}
protected onUpdateStateChange(): void {
this.updateMenubar();
}
protected onUpdateKeybindings(): void {
this.updateMenubar();
}
protected getOpenRecentActions(): (Separator | IAction & { uri: URI })[] {
if (!this.recentlyOpened) {
return [];
@@ -191,13 +199,27 @@ export abstract class MenubarControl extends Disposable {
if (event.affectsConfiguration('editor.accessibilitySupport')) {
this.notifyUserOfCustomMenubarAccessibility();
}
// Since we try not update when hidden, we should
// try to update the recently opened list on visibility changes
if (event.affectsConfiguration('window.menuBarVisibility')) {
this.onRecentlyOpenedChange();
}
}
private onRecentlyOpenedChange(): void {
this.workspacesService.getRecentlyOpened().then(recentlyOpened => {
this.recentlyOpened = recentlyOpened;
this.updateMenubar();
});
private get menubarHidden(): boolean {
return isMacintosh && isNative ? false : getMenuBarVisibility(this.configurationService) === 'hidden';
}
protected onRecentlyOpenedChange(): void {
// Do not update recently opened when the menubar is hidden #108712
if (!this.menubarHidden) {
this.workspacesService.getRecentlyOpened().then(recentlyOpened => {
this.recentlyOpened = recentlyOpened;
this.updateMenubar();
});
}
}
private createOpenRecentMenuAction(recent: IRecent): IAction & { uri: URI } {
@@ -241,7 +263,7 @@ export abstract class MenubarControl extends Disposable {
}
const hasBeenNotified = this.storageService.getBoolean('menubar/accessibleMenubarNotified', StorageScope.GLOBAL, false);
const usingCustomMenubar = getTitleBarStyle(this.configurationService, this.environmentService) === 'custom';
const usingCustomMenubar = getTitleBarStyle(this.configurationService) === 'custom';
if (hasBeenNotified || usingCustomMenubar || !this.accessibilityService.isScreenReaderOptimized()) {
return;
@@ -257,7 +279,7 @@ export abstract class MenubarControl extends Disposable {
}
]);
this.storageService.store('menubar/accessibleMenubarNotified', true, StorageScope.GLOBAL);
this.storageService.store('menubar/accessibleMenubarNotified', true, StorageScope.GLOBAL, StorageTarget.USER);
}
}
@@ -266,6 +288,7 @@ export class CustomMenubarControl extends MenubarControl {
private container: HTMLElement | undefined;
private alwaysOnMnemonics: boolean = false;
private focusInsideMenubar: boolean = false;
private visible: boolean = true;
private readonly _onVisibilityChange: Emitter<boolean>;
private readonly _onFocusStateChange: Emitter<boolean>;
@@ -475,7 +498,7 @@ export class CustomMenubarControl extends MenubarControl {
}
private get currentMenubarVisibility(): MenuBarVisibility {
return getMenuBarVisibility(this.configurationService, this.environmentService);
return getMenuBarVisibility(this.configurationService);
}
private get currentDisableMenuBarAltFocus(): boolean {
@@ -530,6 +553,12 @@ export class CustomMenubarControl extends MenubarControl {
return currentSidebarLocation === 'right' ? Direction.Left : Direction.Right;
}
private onDidVisibilityChange(visible: boolean): void {
this.visible = visible;
this.onRecentlyOpenedChange();
this._onVisibilityChange.fire(visible);
}
private setupCustomMenubar(firstTime: boolean): void {
// If there is no container, we cannot setup the menubar
if (!this.container) {
@@ -554,7 +583,7 @@ export class CustomMenubarControl extends MenubarControl {
}
}));
this._register(this.menubar.onVisibilityChange(e => this._onVisibilityChange.fire(e)));
this._register(this.menubar.onVisibilityChange(e => this.onDidVisibilityChange(e)));
// Before we focus the menubar, stop updates to it so that focus-related context keys will work
this._register(DOM.addDisposableListener(this.container, DOM.EventType.FOCUS_IN, () => {
@@ -645,29 +674,15 @@ export class CustomMenubarControl extends MenubarControl {
visibility: this.currentMenubarVisibility,
getKeybinding: (action) => this.keybindingService.lookupKeybinding(action.id),
alwaysOnMnemonics: this.alwaysOnMnemonics,
compactMode: this.currentCompactMenuMode,
getCompactMenuActions: () => {
if (!isWeb) {
return []; // only for web
}
const webNavigationActions: IAction[] = [];
const webNavigationMenu = this.menuService.createMenu(MenuId.MenubarWebNavigationMenu, this.contextKeyService);
for (const groups of webNavigationMenu.getActions()) {
const [, actions] = groups;
for (const action of actions) {
action.label = mnemonicMenuLabel(this.calculateActionLabel(action));
webNavigationActions.push(action);
}
}
webNavigationMenu.dispose();
return webNavigationActions;
}
compactMode: this.currentCompactMenuMode
};
}
protected onDidChangeWindowFocus(hasFocus: boolean): void {
if (!this.visible) {
return;
}
super.onDidChangeWindowFocus(hasFocus);
if (this.container) {
@@ -682,6 +697,30 @@ export class CustomMenubarControl extends MenubarControl {
}
}
protected onUpdateStateChange(): void {
if (!this.visible) {
return;
}
super.onUpdateStateChange();
}
protected onRecentlyOpenedChange(): void {
if (!this.visible) {
return;
}
super.onRecentlyOpenedChange();
}
protected onUpdateKeybindings(): void {
if (!this.visible) {
return;
}
super.onUpdateKeybindings();
}
protected registerListeners(): void {
super.registerListeners();

View File

@@ -53,8 +53,8 @@ export class TitlebarPart extends Part implements ITitleService {
readonly minimumWidth: number = 0;
readonly maximumWidth: number = Number.POSITIVE_INFINITY;
get minimumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); }
get maximumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1)); }
get minimumHeight(): number { return 30 / (this.currentMenubarVisibility === 'hidden' ? getZoomFactor() : 1); }
get maximumHeight(): number { return this.minimumHeight; }
//#endregion
@@ -100,7 +100,7 @@ export class TitlebarPart extends Part implements ITitleService {
this.contextMenu = this._register(menuService.createMenu(MenuId.TitleBarContext, contextKeyService));
this.titleBarStyle = getTitleBarStyle(this.configurationService, this.environmentService);
this.titleBarStyle = getTitleBarStyle(this.configurationService);
this.registerListeners();
}
@@ -461,13 +461,13 @@ export class TitlebarPart extends Part implements ITitleService {
}
protected get currentMenubarVisibility(): MenuBarVisibility {
return getMenuBarVisibility(this.configurationService, this.environmentService);
return getMenuBarVisibility(this.configurationService);
}
updateLayout(dimension: Dimension): void {
this.lastLayoutDimensions = dimension;
if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') {
if (getTitleBarStyle(this.configurationService) === 'custom') {
// Only prevent zooming behavior on macOS or when the menubar is not visible
if ((!isWeb && isMacintosh) || this.currentMenubarVisibility === 'hidden') {
this.title.style.zoom = `${1 / getZoomFactor()}`;

View File

@@ -0,0 +1,174 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* File icons in trees */
.file-icon-themable-tree.align-icons-and-twisties .monaco-tl-twistie:not(.force-twistie):not(.collapsible),
.file-icon-themable-tree .align-icon-with-twisty .monaco-tl-twistie:not(.force-twistie):not(.collapsible),
.file-icon-themable-tree.hide-arrows .monaco-tl-twistie:not(.force-twistie),
.file-icon-themable-tree .monaco-tl-twistie.force-no-twistie {
background-image: none !important;
width: 0 !important;
padding-right: 0 !important;
visibility: hidden;
}
/* Misc */
.monaco-workbench .tree-explorer-viewlet-tree-view {
height: 100%;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .message {
display: flex;
padding: 4px 12px 4px 18px;
user-select: text;
-webkit-user-select: text;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .message p {
margin-top: 0px;
margin-bottom: 0px;
padding-bottom: 4px;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .message ul {
padding-left: 24px;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .message.hide {
display: none;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .customview-tree {
height: 100%;
}
.monaco-workbench .tree-explorer-viewlet-tree-view .customview-tree.hide {
display: none;
}
.monaco-workbench .pane > .pane-body > .welcome-view {
width: 100%;
height: 100%;
box-sizing: border-box;
display: flex;
flex-direction: column;
}
.monaco-workbench .pane > .pane-body:not(.welcome) > .welcome-view,
.monaco-workbench .pane > .pane-body.welcome > :not(.welcome-view) {
display: none;
}
.monaco-workbench .pane > .pane-body > .welcome-view .monaco-button {
margin-left: auto;
margin-right: auto;
}
.monaco-workbench .pane > .pane-body.wide > .welcome-view .monaco-button {
margin-left: inherit;
max-width: 260px;
}
.monaco-workbench .pane > .pane-body .welcome-view-content {
padding: 0 20px 0 20px;
box-sizing: border-box;
}
.monaco-workbench .pane > .pane-body .welcome-view-content > * {
margin-block-start: 1em;
margin-block-end: 1em;
margin-inline-start: 0px;
margin-inline-end: 0px;
}
.customview-tree .monaco-list-row .monaco-tl-contents.align-icon-with-twisty::before {
display: none;
}
.customview-tree .monaco-list-row .monaco-tl-contents:not(.align-icon-with-twisty)::before {
display: inline-block;
}
.customview-tree .monaco-list .monaco-list-row {
padding-right: 12px;
padding-left: 0px;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item {
display: flex;
height: 22px;
line-height: 22px;
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
flex-wrap: nowrap;
padding-left: 3px;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .monaco-inputbox {
line-height: normal;
flex: 1;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel {
flex: 1;
text-overflow: ellipsis;
overflow: hidden;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon {
background-size: 16px;
background-position: left center;
background-repeat: no-repeat;
padding-right: 6px;
width: 16px;
height: 22px;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon {
margin-top: 3px;
}
.customview-tree .monaco-list .monaco-list-row.selected .custom-view-tree-node-item > .custom-view-tree-node-item-icon.codicon {
color: currentColor !important;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel .monaco-icon-label-container > .monaco-icon-name-container {
flex: 1;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .custom-view-tree-node-item-resourceLabel::after {
padding-right: 0px;
}
.customview-tree .monaco-list .monaco-list-row .custom-view-tree-node-item .actions {
display: none;
}
.customview-tree .monaco-list .monaco-list-row:hover .custom-view-tree-node-item .actions,
.customview-tree .monaco-list .monaco-list-row.selected .custom-view-tree-node-item .actions,
.customview-tree .monaco-list .monaco-list-row.focused .custom-view-tree-node-item .actions {
display: block;
}
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label {
width: 16px;
height: 100%;
background-size: 16px;
background-position: 50% 50%;
background-repeat: no-repeat;
}
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label.codicon {
line-height: 22px;
}
.customview-tree .monaco-list .custom-view-tree-node-item .actions .action-label.codicon::before {
vertical-align: middle;
}

File diff suppressed because it is too large Load Diff

View File

@@ -18,15 +18,15 @@ import { ToolBar } from 'vs/base/browser/ui/toolbar/toolbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService, Themable } from 'vs/platform/theme/common/themeService';
import { IThemeService, Themable, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { PaneView, IPaneViewOptions, IPaneOptions, Pane, IPaneStyles } from 'vs/base/browser/ui/splitview/paneview';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewContainerModel } from 'vs/workbench/common/views';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry, IViewContentDescriptor, IAddedViewDescriptorRef, IViewDescriptorRef, IViewContainerModel, defaultViewIcon } from 'vs/workbench/common/views';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { assertIsDefined, isString } from 'vs/base/common/types';
import { assertIsDefined } from 'vs/base/common/types';
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -50,6 +50,8 @@ import { ScrollbarVisibility } from 'vs/base/common/scrollable';
import { URI } from 'vs/base/common/uri';
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
import { Codicon } from 'vs/base/common/codicons';
export interface IPaneColors extends IColorMapping {
dropBackground?: ColorIdentifier;
@@ -70,6 +72,9 @@ type WelcomeActionClassification = {
uri: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
const viewPaneContainerExpandedIcon = registerIcon('view-pane-container-expanded', Codicon.chevronDown, nls.localize('viewPaneContainerExpandedIcon', 'Icon for an expanded view pane container.'));
const viewPaneContainerCollapsedIcon = registerIcon('view-pane-container-collapsed', Codicon.chevronRight, nls.localize('viewPaneContainerCollapsedIcon', 'Icon for a collapsed view pane container.'));
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
interface IItem {
@@ -263,7 +268,10 @@ export abstract class ViewPane extends Pane implements IView {
if (changed) {
this._onDidChangeBodyVisibility.fire(expanded);
}
if (this.twistiesContainer) {
this.twistiesContainer.classList.remove(...ThemeIcon.asClassNameArray(this.getTwistyIcon(!expanded)));
this.twistiesContainer.classList.add(...ThemeIcon.asClassNameArray(this.getTwistyIcon(expanded)));
}
return changed;
}
@@ -288,7 +296,7 @@ export abstract class ViewPane extends Pane implements IView {
protected renderHeader(container: HTMLElement): void {
this.headerContainer = container;
this.renderTwisties(container);
this.twistiesContainer = append(container, $(ThemeIcon.asCSSSelector(this.getTwistyIcon(this.isExpanded()))));
this.renderHeaderTitle(container, this.title);
@@ -316,8 +324,8 @@ export abstract class ViewPane extends Pane implements IView {
this.updateActionsVisibility();
}
protected renderTwisties(container: HTMLElement): void {
this.twistiesContainer = append(container, $('.twisties.codicon.codicon-chevron-right'));
protected getTwistyIcon(expanded: boolean): ThemeIcon {
return expanded ? viewPaneContainerExpandedIcon : viewPaneContainerCollapsedIcon;
}
style(styles: IPaneStyles): void {
@@ -338,8 +346,8 @@ export abstract class ViewPane extends Pane implements IView {
}
}
private getIcon(): string | URI {
return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || 'codicon-window';
private getIcon(): ThemeIcon | URI {
return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || defaultViewIcon;
}
protected renderHeaderTitle(container: HTMLElement, title: string): void {
@@ -357,9 +365,8 @@ export abstract class ViewPane extends Pane implements IView {
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
-webkit-mask-size: 16px;
`);
} else if (isString(icon)) {
this.iconContainer.classList.add('codicon');
cssClass = icon;
} else if (ThemeIcon.isThemeIcon(icon)) {
cssClass = ThemeIcon.asClassName(icon);
}
if (cssClass) {
@@ -556,9 +563,7 @@ export abstract class ViewPane extends Pane implements IView {
this.bodyContainer.classList.add('welcome');
this.viewWelcomeContainer.innerText = '';
let buttonIndex = 0;
for (const { content, preconditions } of contents) {
for (const { content, precondition } of contents) {
const lines = content.split('\n');
for (let line of lines) {
@@ -581,21 +586,15 @@ export abstract class ViewPane extends Pane implements IView {
disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService));
if (preconditions) {
const precondition = preconditions[buttonIndex];
if (precondition) {
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
updateEnablement();
if (precondition) {
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
updateEnablement();
const keys = new Set();
precondition.keys().forEach(key => keys.add(key));
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
onDidChangeContext(updateEnablement, null, disposables);
}
const keys = new Set();
precondition.keys().forEach(key => keys.add(key));
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
onDidChangeContext(updateEnablement, null, disposables);
}
buttonIndex++;
} else {
const p = append(this.viewWelcomeContainer, $('p'));
@@ -1319,7 +1318,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
saveState(): void {
this.panes.forEach((view) => view.saveState());
this.storageService.store(this.visibleViewsStorageId, this.length, StorageScope.WORKSPACE);
this.storageService.store(this.visibleViewsStorageId, this.length, StorageScope.WORKSPACE, StorageTarget.USER);
}
private onContextMenu(event: StandardMouseEvent, viewDescriptor: IViewDescriptor): void {

View File

@@ -60,6 +60,8 @@ import { localize } from 'vs/nls';
import { CATEGORIES } from 'vs/workbench/common/actions';
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
import { IHostService } from 'vs/workbench/services/host/browser/host';
import { IUriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentity';
import { UriIdentityService } from 'vs/workbench/services/uriIdentity/common/uriIdentityService';
class BrowserMain extends Disposable {
@@ -201,9 +203,13 @@ class BrowserMain extends Disposable {
serviceCollection.set(IFileService, fileService);
await this.registerFileSystemProviders(environmentService, fileService, remoteAgentService, logService, logsPath);
// IURIIdentityService
const uriIdentityService = new UriIdentityService(fileService);
serviceCollection.set(IUriIdentityService, uriIdentityService);
// Long running services (workspace, config, storage)
const [configurationService, storageService] = await Promise.all([
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, uriIdentityService, logService).then(service => {
// Workspace
serviceCollection.set(IWorkspaceContextService, service);
@@ -333,8 +339,8 @@ class BrowserMain extends Disposable {
}
}
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService({ remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache() }, environmentService, fileService, remoteAgentService, logService);
private async createWorkspaceService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: FileService, remoteAgentService: IRemoteAgentService, uriIdentityService: IUriIdentityService, logService: ILogService): Promise<WorkspaceService> {
const workspaceService = new WorkspaceService({ remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache() }, environmentService, fileService, remoteAgentService, uriIdentityService, logService);
try {
await workspaceService.initialize(payload);

View File

@@ -108,6 +108,11 @@ import { isStandalone } from 'vs/base/browser/browser';
],
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'splitSizing' }, "Controls the sizing of editor groups when splitting them.")
},
'workbench.editor.splitOnDragAndDrop': {
'type': 'boolean',
'default': true,
'description': nls.localize('splitOnDragAndDrop', "Controls if editor groups can be split from drag and drop operations by dropping an editor or file on the edges of the editor area.")
},
'workbench.editor.focusRecentEditorAfterClose': {
'type': 'boolean',
'description': nls.localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."),
@@ -120,13 +125,13 @@ import { isStandalone } from 'vs/base/browser/browser';
},
'workbench.editor.enablePreview': {
'type': 'boolean',
'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors are reused until they are explicitly set to be kept open (e.g. via double click or editing) and show up with an italic font style."),
'description': nls.localize('enablePreview', "Controls whether opened editors show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing) and show up with an italic font style."),
'default': true
},
'workbench.editor.enablePreviewFromQuickOpen': {
'type': 'boolean',
'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether editors opened from Quick Open show as preview. Preview editors are reused until they are explicitly set to be kept open (e.g. via double click or editing)."),
'default': true
'description': nls.localize('enablePreviewFromQuickOpen', "Controls whether editors opened from Quick Open show as preview. Preview editors do not keep open and are reused until explicitly set to be kept open (e.g. via double click or editing)."),
'default': false
},
'workbench.editor.closeOnFileDelete': {
'type': 'boolean',

View File

@@ -17,7 +17,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr
import { IEditorInputFactoryRegistry, Extensions as EditorExtensions } from 'vs/workbench/common/editor';
import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions';
import { Position, Parts, IWorkbenchLayoutService, positionToString } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, WillSaveStateReason, StorageScope } from 'vs/platform/storage/common/storage';
import { IStorageService, WillSaveStateReason, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
@@ -297,7 +297,7 @@ export class Workbench extends Layout {
// local storage and not global storage because it would not make
// much sense to synchronize to other machines.
if (isNative) {
storageService.store('editorFontInfo', serializedFontInfoRaw, StorageScope.GLOBAL);
storageService.store('editorFontInfo', serializedFontInfoRaw, StorageScope.GLOBAL, StorageTarget.MACHINE);
} else {
window.localStorage.setItem('vscode.editorFontInfo', serializedFontInfoRaw);
}
@@ -415,8 +415,7 @@ export class Workbench extends Layout {
mark('didStartWorkbench');
// Perf reporting (devtools)
performance.mark('workbench-end');
performance.measure('perf: workbench create & restore', 'workbench-start', 'workbench-end');
performance.measure('perf: workbench create & restore', 'didLoadWorkbenchMain', 'didStartWorkbench');
}
}
}