mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-07 09:35:41 -05:00
Merge from vscode 79a1f5a5ca0c6c53db617aa1fa5a2396d2caebe2
This commit is contained in:
@@ -141,15 +141,25 @@ class ToggleScreencastModeAction extends Action {
|
||||
const keyboardMarker = append(container, $('.screencast-keyboard'));
|
||||
disposables.add(toDisposable(() => keyboardMarker.remove()));
|
||||
|
||||
const updateKeyboardFontSize = () => {
|
||||
keyboardMarker.style.fontSize = `${clamp(this.configurationService.getValue<number>('screencastMode.fontSize') || 56, 20, 100)}px`;
|
||||
};
|
||||
|
||||
const updateKeyboardMarker = () => {
|
||||
keyboardMarker.style.bottom = `${clamp(this.configurationService.getValue<number>('screencastMode.verticalOffset') || 0, 0, 90)}%`;
|
||||
};
|
||||
|
||||
updateKeyboardFontSize();
|
||||
updateKeyboardMarker();
|
||||
|
||||
disposables.add(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration('screencastMode.verticalOffset')) {
|
||||
updateKeyboardMarker();
|
||||
}
|
||||
|
||||
if (e.affectsConfiguration('screencastMode.fontSize')) {
|
||||
updateKeyboardFontSize();
|
||||
}
|
||||
}));
|
||||
|
||||
const onKeyDown = domEvent(window, 'keydown', true);
|
||||
@@ -261,6 +271,13 @@ configurationRegistry.registerConfiguration({
|
||||
maximum: 90,
|
||||
description: nls.localize('screencastMode.location.verticalPosition', "Controls the vertical offset of the screencast mode overlay from the bottom as a percentage of the workbench height.")
|
||||
},
|
||||
'screencastMode.fontSize': {
|
||||
type: 'number',
|
||||
default: 56,
|
||||
minimum: 20,
|
||||
maximum: 100,
|
||||
description: nls.localize('screencastMode.fontSize', "Controls the font size (in pixels) of the screencast mode keyboard.")
|
||||
},
|
||||
'screencastMode.onlyKeyboardShortcuts': {
|
||||
type: 'boolean',
|
||||
description: nls.localize('screencastMode.onlyKeyboardShortcuts', "Only show keyboard shortcuts in Screencast Mode."),
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IWorkbenchActionRegistry, Extensions as WorkbenchExtensions } from 'vs/
|
||||
import { IConfigurationService, ConfigurationTarget } 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 } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { KeyMod, KeyCode, KeyChord } from 'vs/base/common/keyCodes';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { getMenuBarVisibility } from 'vs/platform/windows/common/windows';
|
||||
@@ -542,6 +542,117 @@ export abstract class ToggleViewAction extends Action {
|
||||
}
|
||||
|
||||
// --- Move View with Command
|
||||
export class MoveViewAction extends Action {
|
||||
static readonly ID = 'workbench.action.moveView';
|
||||
static readonly LABEL = nls.localize('moveView', "Move View");
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
label: string,
|
||||
@IViewDescriptorService private viewDescriptorService: IViewDescriptorService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IQuickInputService private quickInputService: IQuickInputService,
|
||||
@IContextKeyService private contextKeyService: IContextKeyService,
|
||||
@IActivityBarService private activityBarService: IActivityBarService,
|
||||
@IPanelService private panelService: IPanelService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
private getViewItems(): Array<IQuickPickItem | IQuickPickSeparator> {
|
||||
const results: Array<IQuickPickItem | IQuickPickSeparator> = [];
|
||||
|
||||
const viewlets = this.activityBarService.getVisibleViewContainerIds();
|
||||
viewlets.forEach(viewletId => {
|
||||
const container = this.viewDescriptorService.getViewContainerById(viewletId)!;
|
||||
const containerModel = this.viewDescriptorService.getViewContainerModel(container);
|
||||
|
||||
let hasAddedView = false;
|
||||
containerModel.visibleViewDescriptors.forEach(viewDescriptor => {
|
||||
if (viewDescriptor.canMoveView) {
|
||||
if (!hasAddedView) {
|
||||
results.push({
|
||||
type: 'separator',
|
||||
label: nls.localize('sidebarContainer', "Side Bar / {0}", containerModel.title)
|
||||
});
|
||||
hasAddedView = true;
|
||||
}
|
||||
|
||||
results.push({
|
||||
id: viewDescriptor.id,
|
||||
label: viewDescriptor.name
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
const panels = this.panelService.getPinnedPanels();
|
||||
panels.forEach(panel => {
|
||||
const container = this.viewDescriptorService.getViewContainerById(panel.id)!;
|
||||
const containerModel = this.viewDescriptorService.getViewContainerModel(container);
|
||||
|
||||
let hasAddedView = false;
|
||||
containerModel.visibleViewDescriptors.forEach(viewDescriptor => {
|
||||
if (viewDescriptor.canMoveView) {
|
||||
if (!hasAddedView) {
|
||||
results.push({
|
||||
type: 'separator',
|
||||
label: nls.localize('panelContainer', "Panel / {0}", containerModel.title)
|
||||
});
|
||||
hasAddedView = true;
|
||||
}
|
||||
|
||||
results.push({
|
||||
id: viewDescriptor.id,
|
||||
label: viewDescriptor.name
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
private async getView(viewId?: string): Promise<string> {
|
||||
const quickPick = this.quickInputService.createQuickPick();
|
||||
quickPick.placeholder = nls.localize('moveFocusedView.selectView', "Select a View to Move");
|
||||
quickPick.items = this.getViewItems();
|
||||
quickPick.selectedItems = quickPick.items.filter(item => (item as IQuickPickItem).id === viewId) as IQuickPickItem[];
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
quickPick.onDidAccept(() => {
|
||||
const viewId = quickPick.selectedItems[0];
|
||||
resolve(viewId.id);
|
||||
quickPick.hide();
|
||||
});
|
||||
|
||||
quickPick.onDidHide(() => reject());
|
||||
|
||||
quickPick.show();
|
||||
});
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
|
||||
let viewId: string;
|
||||
|
||||
if (focusedViewId && this.viewDescriptorService.getViewDescriptorById(focusedViewId)?.canMoveView) {
|
||||
viewId = focusedViewId;
|
||||
}
|
||||
|
||||
viewId = await this.getView(viewId!);
|
||||
|
||||
if (!viewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.instantiationService.createInstance(MoveFocusedViewAction, MoveFocusedViewAction.ID, MoveFocusedViewAction.LABEL).run(viewId);
|
||||
}
|
||||
}
|
||||
|
||||
registry.registerWorkbenchAction(SyncActionDescriptor.from(MoveViewAction), 'View: Move View', viewCategory);
|
||||
|
||||
// --- Move Focused View with Command
|
||||
export class MoveFocusedViewAction extends Action {
|
||||
static readonly ID = 'workbench.action.moveFocusedView';
|
||||
static readonly LABEL = nls.localize('moveFocusedView', "Move Focused View");
|
||||
@@ -560,8 +671,8 @@ export class MoveFocusedViewAction extends Action {
|
||||
super(id, label);
|
||||
}
|
||||
|
||||
async run(): Promise<void> {
|
||||
const focusedViewId = FocusedViewContext.getValue(this.contextKeyService);
|
||||
async run(viewId: string): Promise<void> {
|
||||
const focusedViewId = viewId || FocusedViewContext.getValue(this.contextKeyService);
|
||||
|
||||
if (focusedViewId === undefined || focusedViewId.trim() === '') {
|
||||
this.notificationService.error(nls.localize('moveFocusedView.error.noFocusedView', "There is no view currently focused."));
|
||||
@@ -576,27 +687,33 @@ export class MoveFocusedViewAction extends Action {
|
||||
|
||||
const quickPick = this.quickInputService.createQuickPick();
|
||||
quickPick.placeholder = nls.localize('moveFocusedView.selectDestination', "Select a Destination for the View");
|
||||
quickPick.title = nls.localize('moveFocusedView.title', "View: Move {0}", viewDescriptor.name);
|
||||
quickPick.title = nls.localize({ key: 'moveFocusedView.title', comment: ['{0} indicates the title of the view the user has selected to move.'] }, "View: Move {0}", viewDescriptor.name);
|
||||
|
||||
const items: Array<IQuickPickItem | IQuickPickSeparator> = [];
|
||||
const currentContainer = this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!;
|
||||
const currentLocation = this.viewDescriptorService.getViewLocationById(focusedViewId)!;
|
||||
const isViewSolo = this.viewDescriptorService.getViewContainerModel(currentContainer).allViewDescriptors.length === 1;
|
||||
|
||||
if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) {
|
||||
items.push({
|
||||
id: '_.panel.newcontainer',
|
||||
label: nls.localize('moveFocusedView.newContainerInPanel', "New Panel Entry"),
|
||||
});
|
||||
}
|
||||
|
||||
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
|
||||
items.push({
|
||||
id: '_.sidebar.newcontainer',
|
||||
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Side Bar Entry")
|
||||
});
|
||||
}
|
||||
|
||||
items.push({
|
||||
type: 'separator',
|
||||
label: nls.localize('sidebar', "Side Bar")
|
||||
});
|
||||
|
||||
const currentContainer = this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!;
|
||||
const currentLocation = this.viewDescriptorService.getViewLocationById(focusedViewId)!;
|
||||
const isViewSolo = this.viewDescriptorService.getViewContainerModel(currentContainer).allViewDescriptors.length === 1;
|
||||
|
||||
if (!(isViewSolo && currentLocation === ViewContainerLocation.Sidebar)) {
|
||||
items.push({
|
||||
id: '_.sidebar.newcontainer',
|
||||
label: nls.localize('moveFocusedView.newContainerInSidebar', "New Container in Side Bar")
|
||||
});
|
||||
}
|
||||
|
||||
const pinnedViewlets = this.activityBarService.getPinnedViewContainerIds();
|
||||
const pinnedViewlets = this.activityBarService.getVisibleViewContainerIds();
|
||||
items.push(...pinnedViewlets
|
||||
.filter(viewletId => {
|
||||
if (viewletId === this.viewDescriptorService.getViewContainerByViewId(focusedViewId)!.id) {
|
||||
@@ -617,13 +734,6 @@ export class MoveFocusedViewAction extends Action {
|
||||
label: nls.localize('panel', "Panel")
|
||||
});
|
||||
|
||||
if (!(isViewSolo && currentLocation === ViewContainerLocation.Panel)) {
|
||||
items.push({
|
||||
id: '_.panel.newcontainer',
|
||||
label: nls.localize('moveFocusedView.newContainerInPanel', "New Container in Panel"),
|
||||
});
|
||||
}
|
||||
|
||||
const pinnedPanels = this.panelService.getPinnedPanels();
|
||||
items.push(...pinnedPanels
|
||||
.filter(panel => {
|
||||
|
||||
@@ -25,15 +25,12 @@
|
||||
position: absolute;
|
||||
background-color: rgba(0, 0, 0 ,0.5);
|
||||
width: 100%;
|
||||
height: 100px;
|
||||
bottom: 20%;
|
||||
left: 0;
|
||||
z-index: 100000;
|
||||
pointer-events: none;
|
||||
color: #eee;
|
||||
line-height: 100px;
|
||||
line-height: 1.75em;
|
||||
text-align: center;
|
||||
font-size: 56px;
|
||||
transition: opacity 0.3s ease-out;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -151,7 +151,7 @@ CommandsRegistry.registerCommand({
|
||||
}
|
||||
});
|
||||
|
||||
CommandsRegistry.registerCommand('workbench.action.quickOpenPreviousEditor', async function (accessor: ServicesAccessor, prefix: string | null = null) {
|
||||
CommandsRegistry.registerCommand('workbench.action.quickOpenPreviousEditor', async accessor => {
|
||||
const quickInputService = accessor.get(IQuickInputService);
|
||||
|
||||
quickInputService.quickAccess.show('', { itemActivation: ItemActivation.SECOND });
|
||||
|
||||
@@ -47,11 +47,7 @@ export class DraggedEditorIdentifier {
|
||||
|
||||
export class DraggedEditorGroupIdentifier {
|
||||
|
||||
constructor(private _identifier: GroupIdentifier) { }
|
||||
|
||||
get identifier(): GroupIdentifier {
|
||||
return this._identifier;
|
||||
}
|
||||
constructor(public readonly identifier: GroupIdentifier) { }
|
||||
}
|
||||
|
||||
export interface IDraggedEditor extends IDraggedResource {
|
||||
@@ -675,6 +671,11 @@ export class CompositeDragAndDropObserver extends Disposable {
|
||||
disposableStore.add(addDisposableListener(element, EventType.DRAG_START, e => {
|
||||
const { id, type } = draggedItemProvider();
|
||||
this.writeDragData(id, type);
|
||||
|
||||
if (e.dataTransfer) {
|
||||
e.dataTransfer.setDragImage(element, 0, 0);
|
||||
}
|
||||
|
||||
this._onDragStart.fire({ eventData: e, dragAndDropData: this.readDragData(type)! });
|
||||
}));
|
||||
disposableStore.add(new DragAndDropObserver(element, {
|
||||
|
||||
@@ -505,6 +505,7 @@ class ResourceLabelWidget extends IconLabel {
|
||||
italic: this.options?.italic,
|
||||
strikethrough: this.options?.strikethrough,
|
||||
matches: this.options?.matches,
|
||||
descriptionMatches: this.options?.descriptionMatches,
|
||||
extraClasses: [],
|
||||
separator: this.options?.separator,
|
||||
domId: this.options?.domId
|
||||
|
||||
@@ -44,6 +44,7 @@ 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';
|
||||
|
||||
export enum Settings {
|
||||
ACTIVITYBAR_VISIBLE = 'workbench.activityBar.visible',
|
||||
@@ -178,6 +179,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
private notificationService!: INotificationService;
|
||||
private themeService!: IThemeService;
|
||||
private activityBarService!: IActivityBarService;
|
||||
private statusBarService!: IStatusbarService;
|
||||
|
||||
protected readonly state = {
|
||||
fullscreen: false,
|
||||
@@ -262,7 +264,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
this.titleService = accessor.get(ITitleService);
|
||||
this.notificationService = accessor.get(INotificationService);
|
||||
this.activityBarService = accessor.get(IActivityBarService);
|
||||
accessor.get(IStatusbarService); // not used, but called to ensure instantiated
|
||||
this.statusBarService = accessor.get(IStatusbarService);
|
||||
|
||||
// Listeners
|
||||
this.registerLayoutListeners();
|
||||
@@ -397,6 +399,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
const newMenubarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
|
||||
this.setMenubarVisibility(newMenubarVisibility, !!skipLayout);
|
||||
|
||||
// Centered Layout
|
||||
this.centerEditorLayout(this.state.editor.centered, skipLayout);
|
||||
}
|
||||
|
||||
private setSideBarPosition(position: Position): void {
|
||||
@@ -850,8 +854,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
case Parts.ACTIVITYBAR_PART:
|
||||
this.activityBarService.focusActivityBar();
|
||||
break;
|
||||
case Parts.STATUSBAR_PART:
|
||||
this.statusBarService.focus();
|
||||
default:
|
||||
// Status Bar, Activity Bar and Title Bar simply pass focus to container
|
||||
// Title Bar simply pass focus to container
|
||||
const container = this.getContainer(part);
|
||||
if (container) {
|
||||
container.focus();
|
||||
@@ -1205,9 +1211,18 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi
|
||||
|
||||
let smartActive = active;
|
||||
const activeEditor = this.editorService.activeEditor;
|
||||
if (this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize')
|
||||
&& (this.editorGroupService.groups.length > 1 || (activeEditor && activeEditor instanceof SideBySideEditorInput))) {
|
||||
smartActive = false; // Respect the auto resize setting - do not go into centered layout if there is more than 1 group.
|
||||
|
||||
const isSideBySideLayout = activeEditor
|
||||
&& activeEditor instanceof SideBySideEditorInput
|
||||
// DiffEditorInput inherits from SideBySideEditorInput but can still be functionally an inline editor.
|
||||
&& (!(activeEditor instanceof DiffEditorInput) || this.configurationService.getValue('diffEditor.renderSideBySide'));
|
||||
|
||||
const isCenteredLayoutAutoResizing = this.configurationService.getValue('workbench.editor.centeredLayoutAutoResize');
|
||||
if (
|
||||
isCenteredLayoutAutoResizing
|
||||
&& (this.editorGroupService.groups.length > 1 || isSideBySideLayout)
|
||||
) {
|
||||
smartActive = false;
|
||||
}
|
||||
|
||||
// Enter Centered Editor Layout
|
||||
|
||||
@@ -5,23 +5,23 @@
|
||||
|
||||
/* Font Families (with CJK support) */
|
||||
|
||||
.mac { font-family: -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
.mac:lang(zh-Hans) { font-family: -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
|
||||
.mac:lang(zh-Hant) { font-family: -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
|
||||
.mac:lang(ja) { font-family: -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
|
||||
.mac:lang(ko) { font-family: -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; }
|
||||
.mac { font-family: system-ui, -apple-system, BlinkMacSystemFont, sans-serif; }
|
||||
.mac:lang(zh-Hans) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "PingFang SC", "Hiragino Sans GB", sans-serif; }
|
||||
.mac:lang(zh-Hant) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "PingFang TC", sans-serif; }
|
||||
.mac:lang(ja) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Hiragino Kaku Gothic Pro", sans-serif; }
|
||||
.mac:lang(ko) { font-family: system-ui, -apple-system, BlinkMacSystemFont, "Nanum Gothic", "Apple SD Gothic Neo", "AppleGothic", sans-serif; }
|
||||
|
||||
.windows { font-family: "Segoe WPC", "Segoe UI", sans-serif; }
|
||||
.windows:lang(zh-Hans) { font-family: "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
|
||||
.windows:lang(zh-Hant) { font-family: "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
|
||||
.windows:lang(ja) { font-family: "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
|
||||
.windows:lang(ko) { font-family: "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
|
||||
.windows { font-family: system-ui, "Segoe WPC", "Segoe UI", sans-serif; }
|
||||
.windows:lang(zh-Hans) { font-family: system-ui, "Segoe WPC", "Segoe UI", "Microsoft YaHei", sans-serif; }
|
||||
.windows:lang(zh-Hant) { font-family: system-ui, "Segoe WPC", "Segoe UI", "Microsoft Jhenghei", sans-serif; }
|
||||
.windows:lang(ja) { font-family: system-ui, "Segoe WPC", "Segoe UI", "Yu Gothic UI", "Meiryo UI", sans-serif; }
|
||||
.windows:lang(ko) { font-family: system-ui, "Segoe WPC", "Segoe UI", "Malgun Gothic", "Dotom", sans-serif; }
|
||||
|
||||
.linux { font-family: "Ubuntu", "Droid Sans", sans-serif; }
|
||||
.linux:lang(zh-Hans) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(zh-Hant) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ja) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ko) { font-family: "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
.linux { font-family: system-ui, "Ubuntu", "Droid Sans", sans-serif; }
|
||||
.linux:lang(zh-Hans) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans SC", "Source Han Sans CN", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(zh-Hant) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans TC", "Source Han Sans TW", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ja) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans J", "Source Han Sans JP", "Source Han Sans", sans-serif; }
|
||||
.linux:lang(ko) { font-family: system-ui, "Ubuntu", "Droid Sans", "Source Han Sans K", "Source Han Sans JR", "Source Han Sans", "UnDotum", "FBaekmuk Gulim", sans-serif; }
|
||||
|
||||
.mac { --monaco-monospace-font: "SF Mono", Monaco, Menlo, Courier, monospace; }
|
||||
.windows { --monaco-monospace-font: Consolas, "Courier New", monospace; }
|
||||
|
||||
@@ -16,29 +16,28 @@ import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace
|
||||
import { ViewPaneContainer } from './parts/views/viewPaneContainer';
|
||||
import { IPaneComposite } from 'vs/workbench/common/panecomposite';
|
||||
import { IAction, IActionViewItem } from 'vs/base/common/actions';
|
||||
import { ViewContainerMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
||||
export class PaneComposite extends Composite implements IPaneComposite {
|
||||
|
||||
private menuActions: ViewContainerMenuActions;
|
||||
|
||||
constructor(
|
||||
id: string,
|
||||
protected readonly viewPaneContainer: ViewPaneContainer,
|
||||
@ITelemetryService
|
||||
telemetryService: ITelemetryService,
|
||||
@IStorageService
|
||||
protected storageService: IStorageService,
|
||||
@IInstantiationService
|
||||
protected instantiationService: IInstantiationService,
|
||||
@IThemeService
|
||||
themeService: IThemeService,
|
||||
@IContextMenuService
|
||||
protected contextMenuService: IContextMenuService,
|
||||
@IExtensionService
|
||||
protected extensionService: IExtensionService,
|
||||
@IWorkspaceContextService
|
||||
protected contextService: IWorkspaceContextService
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService protected storageService: IStorageService,
|
||||
@IInstantiationService protected instantiationService: IInstantiationService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IContextMenuService protected contextMenuService: IContextMenuService,
|
||||
@IExtensionService protected extensionService: IExtensionService,
|
||||
@IWorkspaceContextService protected contextService: IWorkspaceContextService
|
||||
) {
|
||||
super(id, telemetryService, themeService, storageService);
|
||||
|
||||
this.menuActions = this._register(this.instantiationService.createInstance(ViewContainerMenuActions, this.getId(), MenuId.ViewContainerTitleContext));
|
||||
this._register(this.viewPaneContainer.onTitleAreaUpdate(() => this.updateTitleArea()));
|
||||
}
|
||||
|
||||
@@ -68,7 +67,15 @@ export class PaneComposite extends Composite implements IPaneComposite {
|
||||
}
|
||||
|
||||
getContextMenuActions(): ReadonlyArray<IAction> {
|
||||
return this.viewPaneContainer.getContextMenuActions();
|
||||
const result = [];
|
||||
result.push(...this.menuActions.getContextMenuActions());
|
||||
|
||||
if (result.length) {
|
||||
result.push(new Separator());
|
||||
}
|
||||
|
||||
result.push(...this.viewPaneContainer.getContextMenuActions());
|
||||
return result;
|
||||
}
|
||||
|
||||
getActions(): ReadonlyArray<IAction> {
|
||||
|
||||
@@ -5,21 +5,19 @@
|
||||
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IPanel } from 'vs/workbench/common/panel';
|
||||
import { Composite, CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
|
||||
import { CompositeDescriptor, CompositeRegistry } from 'vs/workbench/browser/composite';
|
||||
import { IConstructorSignature0, BrandedService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { PaneComposite } from 'vs/workbench/browser/panecomposite';
|
||||
|
||||
export abstract class Panel extends Composite implements IPanel { }
|
||||
|
||||
export abstract class PaneCompositePanel extends PaneComposite implements IPanel { }
|
||||
export abstract class Panel extends PaneComposite implements IPanel { }
|
||||
|
||||
/**
|
||||
* A panel descriptor is a leightweight descriptor of a panel in the workbench.
|
||||
*/
|
||||
export class PanelDescriptor extends CompositeDescriptor<Panel> {
|
||||
|
||||
public static create<Services extends BrandedService[]>(ctor: { new(...services: Services): Panel }, id: string, name: string, cssClass?: string, order?: number, _commandId?: string): PanelDescriptor {
|
||||
static create<Services extends BrandedService[]>(ctor: { new(...services: Services): Panel }, id: string, name: string, cssClass?: string, order?: number, _commandId?: string): PanelDescriptor {
|
||||
return new PanelDescriptor(ctor as IConstructorSignature0<Panel>, id, name, cssClass, order, _commandId);
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { createAndFillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
|
||||
export class ViewContainerActivityAction extends ActivityAction {
|
||||
|
||||
@@ -287,6 +289,42 @@ export class NextSideBarViewAction extends SwitchSideBarViewAction {
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class HomeActionViewItem extends ActionViewItem {
|
||||
|
||||
constructor(action: IAction) {
|
||||
super(undefined, action, { icon: true, label: false, useEventAsContext: true });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated TODO@ben remove me eventually
|
||||
*/
|
||||
export class DeprecatedHomeAction extends Action {
|
||||
|
||||
constructor(
|
||||
private readonly command: string,
|
||||
name: string,
|
||||
|
||||
@@ -6,16 +6,16 @@
|
||||
import 'vs/css!./media/activitybarpart';
|
||||
import * as nls from 'vs/nls';
|
||||
import { ActionsOrientation, ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { GLOBAL_ACTIVITY_ID, IActivity } from 'vs/workbench/common/activity';
|
||||
import { GLOBAL_ACTIVITY_ID, IActivity, ACCOUNTS_ACTIIVTY_ID } from 'vs/workbench/common/activity';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { GlobalActivityActionViewItem, ViewContainerActivityAction, PlaceHolderToggleCompositePinnedAction, PlaceHolderViewContainerActivityAction, AccountsActionViewItem, HomeAction, HomeActionViewItem, DeprecatedHomeAction } from 'vs/workbench/browser/parts/activitybar/activitybarActions';
|
||||
import { IBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity';
|
||||
import { IWorkbenchLayoutService, Parts, Position as SideBarPosition } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IDisposable, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { ToggleActivityBarVisibilityAction, ToggleMenuBarAction } from 'vs/workbench/browser/actions/layoutActions';
|
||||
import { IThemeService, IColorTheme } 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_DRAG_AND_DROP_BACKGROUND, ACTIVITY_BAR_INACTIVE_FOREGROUND, ACTIVITY_BAR_ACTIVE_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
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, addClass, removeNode, createCSSRule, asCSSUrl } from 'vs/base/browser/dom';
|
||||
@@ -74,6 +74,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
private static readonly ACTION_HEIGHT = 48;
|
||||
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';
|
||||
|
||||
//#region IView
|
||||
|
||||
@@ -98,7 +99,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
private globalActivityActionBar: ActionBar | undefined;
|
||||
private readonly globalActivity: ICompositeActivity[] = [];
|
||||
|
||||
private readonly cachedViewContainers: ICachedViewContainer[] = [];
|
||||
private accountsActivityAction: ActivityAction | undefined;
|
||||
|
||||
private readonly compositeActions = new Map<string, { activityAction: ViewContainerActivityAction, pinnedAction: ToggleCompositePinnedAction }>();
|
||||
private readonly viewContainerDisposables = new Map<string, IDisposable>();
|
||||
|
||||
@@ -121,9 +123,9 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
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 });
|
||||
this.migrateFromOldCachedViewContainersValue();
|
||||
|
||||
this.cachedViewContainers = this.getCachedViewContainers();
|
||||
for (const cachedViewContainer of this.cachedViewContainers) {
|
||||
if (environmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered.
|
||||
|| this.shouldBeHidden(cachedViewContainer.id, cachedViewContainer)
|
||||
@@ -144,6 +146,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
getContextMenuActions: () => {
|
||||
const menuBarVisibility = getMenuBarVisibility(this.configurationService, this.environmentService);
|
||||
const actions = [];
|
||||
if (this.homeBarContainer) {
|
||||
actions.push(new Action('toggleHomeBarAction',
|
||||
this.homeBarVisibilityPreference ? nls.localize('hideHomeBar', "Hide Home Button") : nls.localize('showHomeBar', "Show Home Button"),
|
||||
undefined,
|
||||
true,
|
||||
async () => { this.homeBarVisibilityPreference = !this.homeBarVisibilityPreference; }));
|
||||
}
|
||||
|
||||
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")));
|
||||
@@ -157,7 +166,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
hidePart: () => this.layoutService.setSideBarHidden(true),
|
||||
dndHandler: new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Sidebar,
|
||||
(id: string, focus?: boolean) => this.viewsService.openViewContainer(id, focus),
|
||||
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore)
|
||||
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.verticallyBefore),
|
||||
() => this.compositeBar.getCompositeBarItems(),
|
||||
),
|
||||
compositeSize: 52,
|
||||
colors: (theme: IColorTheme) => this.getActivitybarItemColors(theme),
|
||||
@@ -226,6 +236,12 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeHomeBarVisibility(): void {
|
||||
if (this.homeBarContainer) {
|
||||
this.homeBarContainer.style.display = this.homeBarVisibilityPreference ? '' : 'none';
|
||||
}
|
||||
}
|
||||
|
||||
private onDidRegisterExtensions(): void {
|
||||
this.removeNotExistingComposites();
|
||||
this.saveCachedViewContainers();
|
||||
@@ -256,6 +272,14 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
return this.showGlobalActivity(badge, clazz, priority);
|
||||
}
|
||||
|
||||
if (viewContainerOrActionId === ACCOUNTS_ACTIIVTY_ID) {
|
||||
if (this.accountsActivityAction) {
|
||||
this.accountsActivityAction.setBadge(badge, clazz);
|
||||
|
||||
return toDisposable(() => this.accountsActivityAction?.setBadge(undefined));
|
||||
}
|
||||
}
|
||||
|
||||
return Disposable.None;
|
||||
}
|
||||
|
||||
@@ -354,7 +378,8 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
console.warn(`Unknown home indicator icon ${homeIndicator.icon}`);
|
||||
codicon = Codicon.code;
|
||||
}
|
||||
this.createHomeBar(homeIndicator.command, homeIndicator.title, codicon);
|
||||
this.createHomeBar(homeIndicator.href, homeIndicator.command, homeIndicator.title, codicon);
|
||||
this.onDidChangeHomeBarVisibility();
|
||||
}
|
||||
|
||||
// Install menubar if compact
|
||||
@@ -375,7 +400,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
return this.content;
|
||||
}
|
||||
|
||||
private createHomeBar(command: string, title: string, icon: Codicon): void {
|
||||
private createHomeBar(href: string, command: string | undefined, title: string, icon: Codicon): void {
|
||||
this.homeBarContainer = document.createElement('div');
|
||||
this.homeBarContainer.setAttribute('aria-label', nls.localize('homeIndicator', "Home"));
|
||||
this.homeBarContainer.setAttribute('role', 'toolbar');
|
||||
@@ -383,14 +408,21 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
this.homeBar = this._register(new ActionBar(this.homeBarContainer, {
|
||||
orientation: ActionsOrientation.VERTICAL,
|
||||
animated: false
|
||||
animated: false,
|
||||
ariaLabel: nls.localize('home', "Home"),
|
||||
actionViewItemProvider: command ? undefined : action => new HomeActionViewItem(action),
|
||||
allowContextMenu: true
|
||||
}));
|
||||
|
||||
const homeBarIconBadge = document.createElement('div');
|
||||
addClass(homeBarIconBadge, 'home-bar-icon-badge');
|
||||
this.homeBarContainer.appendChild(homeBarIconBadge);
|
||||
|
||||
this.homeBar.push(this._register(this.instantiationService.createInstance(HomeAction, command, title, icon)), { icon: true, label: false });
|
||||
if (command) {
|
||||
this.homeBar.push(this._register(this.instantiationService.createInstance(DeprecatedHomeAction, command, title, icon)), { icon: true, label: false });
|
||||
} else {
|
||||
this.homeBar.push(this._register(this.instantiationService.createInstance(HomeAction, href, title, icon)));
|
||||
}
|
||||
|
||||
const content = assertIsDefined(this.content);
|
||||
content.prepend(this.homeBarContainer);
|
||||
@@ -422,7 +454,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
activeBackground: theme.getColor(ACTIVITY_BAR_ACTIVE_BACKGROUND),
|
||||
badgeBackground: theme.getColor(ACTIVITY_BAR_BADGE_BACKGROUND),
|
||||
badgeForeground: theme.getColor(ACTIVITY_BAR_BADGE_FOREGROUND),
|
||||
dragAndDropBackground: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BACKGROUND),
|
||||
dragAndDropBorder: theme.getColor(ACTIVITY_BAR_DRAG_AND_DROP_BORDER),
|
||||
activeBackgroundColor: undefined, inactiveBackgroundColor: undefined, activeBorderBottomColor: undefined,
|
||||
};
|
||||
}
|
||||
@@ -452,13 +484,13 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
});
|
||||
|
||||
if (getUserDataSyncStore(this.productService, this.configurationService)) {
|
||||
const profileAction = new ActivityAction({
|
||||
this.accountsActivityAction = new ActivityAction({
|
||||
id: 'workbench.actions.accounts',
|
||||
name: nls.localize('accounts', "Accounts"),
|
||||
cssClass: Codicon.account.classNames
|
||||
});
|
||||
|
||||
this.globalActivityActionBar.push(profileAction);
|
||||
this.globalActivityActionBar.push(this.accountsActivityAction);
|
||||
}
|
||||
|
||||
this.globalActivityActionBar.push(this.globalActivityAction);
|
||||
@@ -528,7 +560,7 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
|
||||
this.viewContainerDisposables.delete(viewContainer.id);
|
||||
this.hideComposite(viewContainer.id);
|
||||
this.removeComposite(viewContainer.id);
|
||||
}
|
||||
|
||||
private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
|
||||
@@ -605,6 +637,17 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
}
|
||||
}
|
||||
|
||||
private removeComposite(compositeId: string): void {
|
||||
this.compositeBar.removeComposite(compositeId);
|
||||
|
||||
const compositeActions = this.compositeActions.get(compositeId);
|
||||
if (compositeActions) {
|
||||
compositeActions.activityAction.dispose();
|
||||
compositeActions.pinnedAction.dispose();
|
||||
this.compositeActions.delete(compositeId);
|
||||
}
|
||||
}
|
||||
|
||||
getPinnedViewContainerIds(): string[] {
|
||||
const pinnedCompositeIds = this.compositeBar.getPinnedComposites().map(v => v.id);
|
||||
return this.getViewContainers()
|
||||
@@ -654,22 +697,19 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
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;
|
||||
this._cachedViewContainers = undefined;
|
||||
|
||||
const newCompositeItems: ICompositeBarItem[] = [];
|
||||
const compositeItems = this.compositeBar.getCompositeBarItems();
|
||||
const cachedViewContainers = this.getCachedViewContainers();
|
||||
|
||||
for (const cachedViewContainer of cachedViewContainers) {
|
||||
// Add and update existing items
|
||||
const existingItem = compositeItems.filter(({ id }) => id === cachedViewContainer.id)[0];
|
||||
if (existingItem) {
|
||||
newCompositeItems.push({
|
||||
id: existingItem.id,
|
||||
name: existingItem.name,
|
||||
order: existingItem.order,
|
||||
pinned: cachedViewContainer.pinned,
|
||||
visible: existingItem.visible
|
||||
});
|
||||
}
|
||||
for (const cachedViewContainer of this.cachedViewContainers) {
|
||||
newCompositeItems.push({
|
||||
id: cachedViewContainer.id,
|
||||
name: cachedViewContainer.name,
|
||||
order: cachedViewContainer.order,
|
||||
pinned: cachedViewContainer.pinned,
|
||||
visible: !!compositeItems.find(({ id }) => id === cachedViewContainer.id)
|
||||
});
|
||||
}
|
||||
|
||||
for (let index = 0; index < compositeItems.length; index++) {
|
||||
@@ -681,6 +721,10 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
|
||||
this.compositeBar.setCompositeBarItems(newCompositeItems);
|
||||
}
|
||||
|
||||
if (e.key === ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE && e.scope === StorageScope.GLOBAL) {
|
||||
this.onDidChangeHomeBarVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
private saveCachedViewContainers(): void {
|
||||
@@ -713,19 +757,21 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.storeCachedViewContainersState(state);
|
||||
}
|
||||
|
||||
private getCachedViewContainers(): ICachedViewContainer[] {
|
||||
const cachedViewContainers: ICachedViewContainer[] = this.getPinnedViewContainers();
|
||||
for (const placeholderViewContainer of this.getPlaceholderViewContainers()) {
|
||||
const cachedViewContainer = cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0];
|
||||
if (cachedViewContainer) {
|
||||
cachedViewContainer.name = placeholderViewContainer.name;
|
||||
cachedViewContainer.icon = placeholderViewContainer.iconCSS ? placeholderViewContainer.iconCSS :
|
||||
placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined;
|
||||
cachedViewContainer.views = placeholderViewContainer.views;
|
||||
private _cachedViewContainers: ICachedViewContainer[] | undefined = undefined;
|
||||
private get cachedViewContainers(): ICachedViewContainer[] {
|
||||
if (this._cachedViewContainers === undefined) {
|
||||
this._cachedViewContainers = this.getPinnedViewContainers();
|
||||
for (const placeholderViewContainer of this.getPlaceholderViewContainers()) {
|
||||
const cachedViewContainer = this._cachedViewContainers.filter(cached => cached.id === placeholderViewContainer.id)[0];
|
||||
if (cachedViewContainer) {
|
||||
cachedViewContainer.name = placeholderViewContainer.name;
|
||||
cachedViewContainer.icon = placeholderViewContainer.iconCSS ? placeholderViewContainer.iconCSS :
|
||||
placeholderViewContainer.iconUrl ? URI.revive(placeholderViewContainer.iconUrl) : undefined;
|
||||
cachedViewContainer.views = placeholderViewContainer.views;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cachedViewContainers;
|
||||
return this._cachedViewContainers;
|
||||
}
|
||||
|
||||
private storeCachedViewContainersState(cachedViewContainers: ICachedViewContainer[]): void {
|
||||
@@ -808,6 +854,14 @@ export class ActivitybarPart extends Part implements IActivityBarService {
|
||||
this.storageService.store(ActivitybarPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private get homeBarVisibilityPreference(): boolean {
|
||||
return this.storageService.getBoolean(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, StorageScope.GLOBAL, true);
|
||||
}
|
||||
|
||||
private set homeBarVisibilityPreference(value: boolean) {
|
||||
this.storageService.store(ActivitybarPart.HOME_BAR_VISIBILITY_PREFERENCE, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private migrateFromOldCachedViewContainersValue(): void {
|
||||
const value = this.storageService.get('workbench.activity.pinnedViewlets', StorageScope.GLOBAL);
|
||||
if (value !== undefined) {
|
||||
|
||||
@@ -20,9 +20,8 @@
|
||||
width: 48px;
|
||||
height: 2px;
|
||||
display: block;
|
||||
background-color: var(--insert-border-color);
|
||||
opacity: 0;
|
||||
transition-property: opacity;
|
||||
background-color: transparent;
|
||||
transition-property: background-color;
|
||||
transition-duration: 0ms;
|
||||
transition-delay: 100ms;
|
||||
}
|
||||
@@ -53,7 +52,7 @@
|
||||
.monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-item.top::before,
|
||||
.monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-item.bottom::after,
|
||||
.monaco-workbench .activitybar > .content.dragged-over > .composite-bar > .monaco-action-bar .action-item:last-of-type::after {
|
||||
opacity: 1;
|
||||
background-color: var(--insert-border-color);
|
||||
}
|
||||
|
||||
.monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-label {
|
||||
@@ -101,7 +100,7 @@
|
||||
}
|
||||
|
||||
/* Hides active elements in high contrast mode */
|
||||
.hc-black .monaco-workbench .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator {
|
||||
.monaco-workbench.hc-black .activitybar > .content :not(.monaco-menu) > .monaco-action-bar .action-item.checked .active-item-indicator {
|
||||
display: none;
|
||||
}
|
||||
|
||||
@@ -120,8 +119,8 @@
|
||||
}
|
||||
|
||||
/* Hides outline on HC as focus is handled by border */
|
||||
.hc-black .monaco-workbench .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before,
|
||||
.hc-black .monaco-workbench .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
.monaco-workbench.hc-black .activitybar.left > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before,
|
||||
.monaco-workbench.hc-black .activitybar.right > .content :not(.monaco-menu) > .monaco-action-bar .action-item:focus:before {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,6 +39,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
private targetContainerLocation: ViewContainerLocation,
|
||||
private openComposite: (id: string, focus?: boolean) => Promise<IPaneComposite | null>,
|
||||
private moveComposite: (from: string, to: string, before?: Before2D) => void,
|
||||
private getItems: () => ICompositeBarItem[],
|
||||
) { }
|
||||
|
||||
drop(data: CompositeDragAndDropData, targetCompositeId: string | undefined, originalEvent: DragEvent, before?: Before2D): void {
|
||||
@@ -61,11 +62,7 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
return;
|
||||
}
|
||||
|
||||
this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.targetContainerLocation);
|
||||
|
||||
if (targetCompositeId) {
|
||||
this.moveComposite(currentContainer.id, targetCompositeId, before);
|
||||
}
|
||||
this.viewDescriptorService.moveViewContainerToLocation(currentContainer, this.targetContainerLocation, this.getTargetIndex(targetCompositeId, before));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,6 +95,16 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
|
||||
return this.canDrop(data, targetCompositeId);
|
||||
}
|
||||
|
||||
private getTargetIndex(targetId: string | undefined, before2d: Before2D | undefined): number | undefined {
|
||||
if (!targetId) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const items = this.getItems();
|
||||
const before = this.targetContainerLocation === ViewContainerLocation.Panel ? before2d?.horizontallyBefore : before2d?.verticallyBefore;
|
||||
return items.findIndex(o => o.id === targetId) + (before ? 0 : 1);
|
||||
}
|
||||
|
||||
private canDrop(data: CompositeDragAndDropData, targetCompositeId: string | undefined): boolean {
|
||||
const dragData = data.getData();
|
||||
|
||||
@@ -226,8 +233,8 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
// Register a drop target on the whole bar to prevent forbidden feedback
|
||||
this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(parent, {
|
||||
onDragOver: (e: IDraggedCompositeData) => {
|
||||
// don't add feedback if this is over the composite bar actions
|
||||
if (e.eventData.target && isAncestor(e.eventData.target as HTMLElement, actionBarDiv)) {
|
||||
// don't add feedback if this is over the composite bar actions or there are no actions
|
||||
if (!(this.compositeSwitcherBar?.length()) || (e.eventData.target && isAncestor(e.eventData.target as HTMLElement, actionBarDiv))) {
|
||||
toggleClass(parent, 'dragged-over', false);
|
||||
return;
|
||||
}
|
||||
@@ -245,7 +252,9 @@ export class CompositeBar extends Widget implements ICompositeBar {
|
||||
},
|
||||
onDrop: (e: IDraggedCompositeData) => {
|
||||
const pinnedItems = this.getPinnedComposites();
|
||||
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, { horizontallyBefore: false, verticallyBefore: false });
|
||||
if (pinnedItems.length) {
|
||||
this.options.dndHandler.drop(e.dragAndDropData, pinnedItems[pinnedItems.length - 1].id, e.eventData, { horizontallyBefore: false, verticallyBefore: false });
|
||||
}
|
||||
toggleClass(parent, 'dragged-over', false);
|
||||
}
|
||||
}));
|
||||
@@ -664,9 +673,18 @@ class CompositeBarModel {
|
||||
}
|
||||
this._items = result;
|
||||
}
|
||||
|
||||
this.updateItemsOrder();
|
||||
return hasChanges;
|
||||
}
|
||||
|
||||
|
||||
private updateItemsOrder(): void {
|
||||
if (this._items) {
|
||||
this.items.forEach((item, index) => { if (item.order !== undefined) { item.order = index; } });
|
||||
}
|
||||
}
|
||||
|
||||
get visibleItems(): ICompositeBarModelItem[] {
|
||||
return this.items.filter(item => item.visible);
|
||||
}
|
||||
@@ -702,6 +720,8 @@ class CompositeBarModel {
|
||||
item.visible = true;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
this.updateItemsOrder();
|
||||
return changed;
|
||||
} else {
|
||||
const item = this.createCompositeBarItem(id, name, order, true, true);
|
||||
@@ -714,6 +734,8 @@ class CompositeBarModel {
|
||||
}
|
||||
this.items.splice(index, 0, item);
|
||||
}
|
||||
|
||||
this.updateItemsOrder();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -722,6 +744,7 @@ class CompositeBarModel {
|
||||
for (let index = 0; index < this.items.length; index++) {
|
||||
if (this.items[index].id === id) {
|
||||
this.items.splice(index, 1);
|
||||
this.updateItemsOrder();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -757,6 +780,8 @@ class CompositeBarModel {
|
||||
// Make sure a moved composite gets pinned
|
||||
sourceItem.pinned = true;
|
||||
|
||||
this.updateItemsOrder();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -119,7 +119,7 @@ export interface ICompositeBarColors {
|
||||
inactiveForegroundColor?: Color;
|
||||
badgeBackground?: Color;
|
||||
badgeForeground?: Color;
|
||||
dragAndDropBackground?: Color;
|
||||
dragAndDropBorder?: Color;
|
||||
}
|
||||
|
||||
export interface IActivityActionViewItemOptions extends IBaseActionViewItemOptions {
|
||||
@@ -169,16 +169,14 @@ export class ActivityActionViewItem extends BaseActionViewItem {
|
||||
this.label.style.color = foreground ? foreground.toString() : '';
|
||||
this.label.style.backgroundColor = '';
|
||||
}
|
||||
|
||||
const dragColor = colors.activeBackgroundColor || colors.activeForegroundColor;
|
||||
this.container.style.setProperty('--insert-border-color', dragColor ? dragColor.toString() : '');
|
||||
} else {
|
||||
const foreground = this._action.checked ? colors.activeForegroundColor : colors.inactiveForegroundColor;
|
||||
const borderBottomColor = this._action.checked ? colors.activeBorderBottomColor : null;
|
||||
this.label.style.color = foreground ? foreground.toString() : '';
|
||||
this.label.style.borderBottomColor = borderBottomColor ? borderBottomColor.toString() : '';
|
||||
this.container.style.setProperty('--insert-border-color', colors.activeForegroundColor ? colors.activeForegroundColor.toString() : '');
|
||||
}
|
||||
|
||||
this.container.style.setProperty('--insert-border-color', colors.dragAndDropBorder ? colors.dragAndDropBorder.toString() : '');
|
||||
}
|
||||
|
||||
// Badge
|
||||
@@ -203,7 +201,7 @@ export class ActivityActionViewItem extends BaseActionViewItem {
|
||||
|
||||
// Make the container tab-able for keyboard navigation
|
||||
this.container.tabIndex = 0;
|
||||
this.container.setAttribute('role', this.options.icon ? 'button' : 'tab');
|
||||
this.container.setAttribute('role', 'tab');
|
||||
|
||||
// Try hard to prevent keyboard only focus feedback when using mouse
|
||||
this._register(dom.addDisposableListener(this.container, dom.EventType.MOUSE_DOWN, () => {
|
||||
@@ -649,9 +647,11 @@ export class CompositeActionViewItem extends ActivityActionViewItem {
|
||||
if (this.getAction().checked) {
|
||||
dom.addClass(this.container, 'checked');
|
||||
this.container.setAttribute('aria-label', nls.localize('compositeActive', "{0} active", this.container.title));
|
||||
this.container.setAttribute('aria-expanded', 'true');
|
||||
} else {
|
||||
dom.removeClass(this.container, 'checked');
|
||||
this.container.setAttribute('aria-label', this.container.title);
|
||||
this.container.setAttribute('aria-expanded', 'false');
|
||||
}
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
@@ -316,11 +316,11 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
toolBar.setAriaLabel(nls.localize('ariaCompositeToolbarLabel', "{0} actions", compositeTitle));
|
||||
}
|
||||
|
||||
private collectCompositeActions(composite: Composite): () => void {
|
||||
private collectCompositeActions(composite?: Composite): () => void {
|
||||
|
||||
// From Composite
|
||||
const primaryActions: IAction[] = composite.getActions().slice(0);
|
||||
const secondaryActions: IAction[] = composite.getSecondaryActions().slice(0);
|
||||
const primaryActions: IAction[] = composite?.getActions().slice(0) || [];
|
||||
const secondaryActions: IAction[] = composite?.getSecondaryActions().slice(0) || [];
|
||||
|
||||
// From Part
|
||||
primaryActions.push(...this.getActions());
|
||||
@@ -368,7 +368,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
|
||||
// Empty Actions
|
||||
if (this.toolBar) {
|
||||
this.toolBar.setActions([])();
|
||||
this.collectCompositeActions()();
|
||||
}
|
||||
this.onDidCompositeClose.fire(composite);
|
||||
|
||||
@@ -395,6 +395,8 @@ export abstract class CompositePart<T extends Composite> extends Part {
|
||||
anchorAlignmentProvider: () => this.getTitleAreaDropDownAnchorAlignment()
|
||||
}));
|
||||
|
||||
this.collectCompositeActions()();
|
||||
|
||||
return titleArea;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { LRUCache } from 'vs/base/common/map';
|
||||
import { LRUCache, Touch } from 'vs/base/common/map';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { isEmptyObject } from 'vs/base/common/types';
|
||||
@@ -106,10 +106,6 @@ export abstract class BaseEditor extends Composite implements IEditorPane {
|
||||
this.createEditor(parent);
|
||||
}
|
||||
|
||||
onHide() { }
|
||||
|
||||
onWillHide() { }
|
||||
|
||||
/**
|
||||
* Called to create the editor in the parent HTMLElement.
|
||||
*/
|
||||
@@ -133,6 +129,16 @@ export abstract class BaseEditor extends Composite implements IEditorPane {
|
||||
this._group = group;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called before the editor is being removed from the DOM.
|
||||
*/
|
||||
onWillHide() { }
|
||||
|
||||
/**
|
||||
* Called after the editor has been removed from the DOM.
|
||||
*/
|
||||
onDidHide() { }
|
||||
|
||||
protected getEditorMemento<T>(editorGroupService: IEditorGroupsService, key: string, limit: number = 10): IEditorMemento<T> {
|
||||
const mementoKey = `${this.getId()}${key}`;
|
||||
|
||||
@@ -256,7 +262,9 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
moveEditorState(source: URI, target: URI): void {
|
||||
const cache = this.doLoad();
|
||||
|
||||
const cacheKeys = cache.keys();
|
||||
// We need a copy of the keys to not iterate over
|
||||
// newly inserted elements.
|
||||
const cacheKeys = [...cache.keys()];
|
||||
for (const cacheKey of cacheKeys) {
|
||||
const resource = URI.parse(cacheKey);
|
||||
|
||||
@@ -273,7 +281,8 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
targetResource = joinPath(target, resource.path.substr(index + source.path.length + 1)); // parent folder got moved
|
||||
}
|
||||
|
||||
const value = cache.get(cacheKey);
|
||||
// Don't modify LRU state.
|
||||
const value = cache.get(cacheKey, Touch.None);
|
||||
if (value) {
|
||||
cache.delete(cacheKey);
|
||||
cache.set(targetResource.toString(), value);
|
||||
@@ -318,18 +327,19 @@ export class EditorMemento<T> implements IEditorMemento<T> {
|
||||
private cleanUp(): void {
|
||||
const cache = this.doLoad();
|
||||
|
||||
// Remove groups from states that no longer exist
|
||||
cache.forEach((mapGroupToMemento, resource) => {
|
||||
// Remove groups from states that no longer exist. Since we modify the
|
||||
// cache and its is a LRU cache make a copy to ensure iteration succeeds
|
||||
const entries = [...cache.entries()];
|
||||
for (const [resource, mapGroupToMemento] of entries) {
|
||||
Object.keys(mapGroupToMemento).forEach(group => {
|
||||
const groupId: GroupIdentifier = Number(group);
|
||||
if (!this.editorGroupService.getGroup(groupId)) {
|
||||
delete mapGroupToMemento[groupId];
|
||||
|
||||
if (isEmptyObject(mapGroupToMemento)) {
|
||||
cache.delete(resource);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,6 +160,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor {
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export interface IResourceDescriptor {
|
||||
readonly resource: URI;
|
||||
readonly name: string;
|
||||
|
||||
@@ -11,7 +11,7 @@ import { tail } from 'vs/base/common/arrays';
|
||||
import { timeout } from 'vs/base/common/async';
|
||||
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
|
||||
import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { isEqual } from 'vs/base/common/resources';
|
||||
import { extUri } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import 'vs/css!./media/breadcrumbscontrol';
|
||||
import { ICodeEditor, isCodeEditor, isDiffEditor } from 'vs/editor/browser/editorBrowser';
|
||||
@@ -71,7 +71,7 @@ class Item extends BreadcrumbsItem {
|
||||
return false;
|
||||
}
|
||||
if (this.element instanceof FileElement && other.element instanceof FileElement) {
|
||||
return (isEqual(this.element.uri, other.element.uri, false) &&
|
||||
return (extUri.isEqual(this.element.uri, other.element.uri) &&
|
||||
this.options.showFileIcons === other.options.showFileIcons &&
|
||||
this.options.showSymbolIcons === other.options.showSymbolIcons);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditorPane, IEditorPartOptions, IEditorPartOptionsChangeEvent, EditorInput } from 'vs/workbench/common/editor';
|
||||
import { EditorGroup } from 'vs/workbench/common/editor/editorGroup';
|
||||
import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IEditorGroup, GroupDirection, IAddGroupOptions, IMergeGroupOptions, GroupsOrder, GroupsArrangement, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Dimension } from 'vs/base/browser/dom';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
@@ -14,6 +14,7 @@ import { ISerializableView } from 'vs/base/browser/ui/grid/grid';
|
||||
import { getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||
import { IEditorService, IResourceEditorInputType } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export const EDITOR_TITLE_HEIGHT = 35;
|
||||
|
||||
@@ -41,6 +42,26 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
|
||||
splitSizing: 'distribute'
|
||||
};
|
||||
|
||||
export function computeEditorAriaLabel(input: IEditorInput, index: number | undefined, group: IEditorGroup | undefined, groupCount: number): string {
|
||||
let ariaLabel = input.getAriaLabel();
|
||||
if (group && !group.isPinned(input)) {
|
||||
ariaLabel = localize('preview', "{0}, preview", ariaLabel);
|
||||
}
|
||||
|
||||
if (group && group.isSticky(index ?? input)) {
|
||||
ariaLabel = localize('pinned', "{0}, pinned", ariaLabel);
|
||||
}
|
||||
|
||||
// Apply group information to help identify in
|
||||
// which group we are (only if more than one group
|
||||
// is actually opened)
|
||||
if (group && groupCount > 1) {
|
||||
ariaLabel = `${ariaLabel}, ${group.ariaLabel}`;
|
||||
}
|
||||
|
||||
return ariaLabel;
|
||||
}
|
||||
|
||||
export function impactsEditorPartOptions(event: IConfigurationChangeEvent): boolean {
|
||||
return event.affectsConfiguration('workbench.editor') || event.affectsConfiguration('workbench.iconTheme');
|
||||
}
|
||||
@@ -68,6 +89,11 @@ export interface IEditorOpeningEvent extends IEditorIdentifier {
|
||||
*/
|
||||
options?: IEditorOptions;
|
||||
|
||||
/**
|
||||
* Context indicates how the editor open event is initialized.
|
||||
*/
|
||||
context?: OpenEditorContext;
|
||||
|
||||
/**
|
||||
* Allows to prevent the opening of an editor by providing a callback
|
||||
* that will be executed instead. By returning another editor promise
|
||||
@@ -144,11 +170,6 @@ export function getActiveTextEditorOptions(group: IEditorGroup, expectedActiveEd
|
||||
*/
|
||||
export interface EditorServiceImpl extends IEditorService {
|
||||
|
||||
/**
|
||||
* Emitted when an editor is closed.
|
||||
*/
|
||||
readonly onDidCloseEditor: Event<IEditorCloseEvent>;
|
||||
|
||||
/**
|
||||
* Emitted when an editor failed to open.
|
||||
*/
|
||||
|
||||
@@ -1339,7 +1339,8 @@ export class QuickAccessPreviousEditorFromHistoryAction extends Action {
|
||||
id: string,
|
||||
label: string,
|
||||
@IQuickInputService private readonly quickInputService: IQuickInputService,
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService
|
||||
@IKeybindingService private readonly keybindingService: IKeybindingService,
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
|
||||
) {
|
||||
super(id, label);
|
||||
}
|
||||
@@ -1347,7 +1348,14 @@ export class QuickAccessPreviousEditorFromHistoryAction extends Action {
|
||||
async run(): Promise<void> {
|
||||
const keybindings = this.keybindingService.lookupKeybindings(this.id);
|
||||
|
||||
this.quickInputService.quickAccess.show('', { quickNavigateConfiguration: { keybindings } });
|
||||
// Enforce to activate the first item in quick access if
|
||||
// the currently active editor group has n editor opened
|
||||
let itemActivation: ItemActivation | undefined = undefined;
|
||||
if (this.editorGroupService.activeGroup.count === 0) {
|
||||
itemActivation = ItemActivation.FIRST;
|
||||
}
|
||||
|
||||
this.quickInputService.quickAccess.show('', { quickNavigateConfiguration: { keybindings }, itemActivation });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@ export class EditorControl extends Disposable {
|
||||
readonly onDidSizeConstraintsChange = this._onDidSizeConstraintsChange.event;
|
||||
|
||||
private _activeEditorPane: BaseEditor | null = null;
|
||||
get activeEditorPane(): IVisibleEditorPane | null { return this._activeEditorPane as IVisibleEditorPane | null; }
|
||||
|
||||
private readonly editorPanes: BaseEditor[] = [];
|
||||
|
||||
private readonly activeEditorPaneDisposables = this._register(new DisposableStore());
|
||||
@@ -53,10 +55,6 @@ export class EditorControl extends Disposable {
|
||||
this.editorOperation = this._register(new LongRunningOperation(editorProgressService));
|
||||
}
|
||||
|
||||
get activeEditorPane(): IVisibleEditorPane | null {
|
||||
return this._activeEditorPane as IVisibleEditorPane | null;
|
||||
}
|
||||
|
||||
async openEditor(editor: EditorInput, options?: EditorOptions): Promise<IOpenEditorResult> {
|
||||
|
||||
// Editor pane
|
||||
@@ -208,7 +206,7 @@ export class EditorControl extends Disposable {
|
||||
this._activeEditorPane.onWillHide();
|
||||
this.parent.removeChild(editorPaneContainer);
|
||||
hide(editorPaneContainer);
|
||||
this._activeEditorPane.onHide();
|
||||
this._activeEditorPane.onDidHide();
|
||||
}
|
||||
|
||||
// Indicate to editor pane
|
||||
|
||||
@@ -22,6 +22,9 @@ import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { assertIsDefined, assertAllDefined } from 'vs/base/common/types';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
interface IDropOperation {
|
||||
splitDirection?: GroupDirection;
|
||||
@@ -31,8 +34,10 @@ class DropOverlay extends Themable {
|
||||
|
||||
private static readonly OVERLAY_ID = 'monaco-workbench-editor-drop-overlay';
|
||||
|
||||
private container!: HTMLElement;
|
||||
private overlay!: HTMLElement;
|
||||
private static readonly MAX_FILE_UPLOAD_SIZE = 100 * 1024 * 1024; // 100mb
|
||||
|
||||
private container: HTMLElement | undefined;
|
||||
private overlay: HTMLElement | undefined;
|
||||
|
||||
private currentDropOperation: IDropOperation | undefined;
|
||||
private _disposed: boolean | undefined;
|
||||
@@ -48,7 +53,8 @@ class DropOverlay extends Themable {
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IInstantiationService private instantiationService: IInstantiationService,
|
||||
@IFileDialogService private readonly fileDialogService: IFileDialogService,
|
||||
@IEditorService private readonly editorService: IEditorService
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@INotificationService private readonly notificationService: INotificationService
|
||||
) {
|
||||
super(themeService);
|
||||
|
||||
@@ -65,45 +71,46 @@ class DropOverlay extends Themable {
|
||||
const overlayOffsetHeight = this.getOverlayOffsetHeight();
|
||||
|
||||
// Container
|
||||
this.container = document.createElement('div');
|
||||
this.container.id = DropOverlay.OVERLAY_ID;
|
||||
this.container.style.top = `${overlayOffsetHeight}px`;
|
||||
const container = this.container = document.createElement('div');
|
||||
container.id = DropOverlay.OVERLAY_ID;
|
||||
container.style.top = `${overlayOffsetHeight}px`;
|
||||
|
||||
// Parent
|
||||
this.groupView.element.appendChild(this.container);
|
||||
this.groupView.element.appendChild(container);
|
||||
addClass(this.groupView.element, 'dragged-over');
|
||||
this._register(toDisposable(() => {
|
||||
this.groupView.element.removeChild(this.container);
|
||||
this.groupView.element.removeChild(container);
|
||||
removeClass(this.groupView.element, 'dragged-over');
|
||||
}));
|
||||
|
||||
// Overlay
|
||||
this.overlay = document.createElement('div');
|
||||
addClass(this.overlay, 'editor-group-overlay-indicator');
|
||||
this.container.appendChild(this.overlay);
|
||||
container.appendChild(this.overlay);
|
||||
|
||||
// Overlay Event Handling
|
||||
this.registerListeners();
|
||||
this.registerListeners(container);
|
||||
|
||||
// Styles
|
||||
this.updateStyles();
|
||||
}
|
||||
|
||||
protected updateStyles(): void {
|
||||
const overlay = assertIsDefined(this.overlay);
|
||||
|
||||
// Overlay drop background
|
||||
this.overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) || '';
|
||||
overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) || '';
|
||||
|
||||
// Overlay contrast border (if any)
|
||||
const activeContrastBorderColor = this.getColor(activeContrastBorder);
|
||||
this.overlay.style.outlineColor = activeContrastBorderColor || '';
|
||||
this.overlay.style.outlineOffset = activeContrastBorderColor ? '-2px' : '';
|
||||
this.overlay.style.outlineStyle = activeContrastBorderColor ? 'dashed' : '';
|
||||
this.overlay.style.outlineWidth = activeContrastBorderColor ? '2px' : '';
|
||||
overlay.style.outlineColor = activeContrastBorderColor || '';
|
||||
overlay.style.outlineOffset = activeContrastBorderColor ? '-2px' : '';
|
||||
overlay.style.outlineStyle = activeContrastBorderColor ? 'dashed' : '';
|
||||
overlay.style.outlineWidth = activeContrastBorderColor ? '2px' : '';
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
this._register(new DragAndDropObserver(this.container, {
|
||||
private registerListeners(container: HTMLElement): void {
|
||||
this._register(new DragAndDropObserver(container, {
|
||||
onDragEnter: e => undefined,
|
||||
onDragOver: e => {
|
||||
const isDraggingGroup = this.groupTransfer.hasData(DraggedEditorGroupIdentifier.prototype);
|
||||
@@ -161,7 +168,7 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(addDisposableListener(this.container, EventType.MOUSE_OVER, () => {
|
||||
this._register(addDisposableListener(container, EventType.MOUSE_OVER, () => {
|
||||
// Under some circumstances we have seen reports where the drop overlay is not being
|
||||
// cleaned up and as such the editor area remains under the overlay so that you cannot
|
||||
// type into the editor anymore. This seems related to using VMs and DND via host and
|
||||
@@ -295,6 +302,14 @@ class DropOverlay extends Themable {
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const file = files.item(i);
|
||||
if (file) {
|
||||
|
||||
// Skip for very large files because this operation is unbuffered
|
||||
if (file.size > DropOverlay.MAX_FILE_UPLOAD_SIZE) {
|
||||
this.notificationService.warn(localize('fileTooLarge', "File is too large to open as untitled editor. Please upload it first into the file explorer and then try again."));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Read file fully and open as untitled editor
|
||||
const reader = new FileReader();
|
||||
reader.readAsArrayBuffer(file);
|
||||
reader.onload = async event => {
|
||||
@@ -456,30 +471,32 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
|
||||
// Make sure the overlay is visible now
|
||||
this.overlay.style.opacity = '1';
|
||||
const overlay = assertIsDefined(this.overlay);
|
||||
overlay.style.opacity = '1';
|
||||
|
||||
// Enable transition after a timeout to prevent initial animation
|
||||
setTimeout(() => addClass(this.overlay, 'overlay-move-transition'), 0);
|
||||
setTimeout(() => addClass(overlay, 'overlay-move-transition'), 0);
|
||||
|
||||
// Remember as current split direction
|
||||
this.currentDropOperation = { splitDirection };
|
||||
}
|
||||
|
||||
private doPositionOverlay(options: { top: string, left: string, width: string, height: string }): void {
|
||||
const [container, overlay] = assertAllDefined(this.container, this.overlay);
|
||||
|
||||
// Container
|
||||
const offsetHeight = this.getOverlayOffsetHeight();
|
||||
if (offsetHeight) {
|
||||
this.container.style.height = `calc(100% - ${offsetHeight}px)`;
|
||||
container.style.height = `calc(100% - ${offsetHeight}px)`;
|
||||
} else {
|
||||
this.container.style.height = '100%';
|
||||
container.style.height = '100%';
|
||||
}
|
||||
|
||||
// Overlay
|
||||
this.overlay.style.top = options.top;
|
||||
this.overlay.style.left = options.left;
|
||||
this.overlay.style.width = options.width;
|
||||
this.overlay.style.height = options.height;
|
||||
overlay.style.top = options.top;
|
||||
overlay.style.left = options.left;
|
||||
overlay.style.width = options.width;
|
||||
overlay.style.height = options.height;
|
||||
}
|
||||
|
||||
private getOverlayOffsetHeight(): number {
|
||||
@@ -491,11 +508,12 @@ class DropOverlay extends Themable {
|
||||
}
|
||||
|
||||
private hideOverlay(): void {
|
||||
const overlay = assertIsDefined(this.overlay);
|
||||
|
||||
// Reset overlay
|
||||
this.doPositionOverlay({ top: '0', left: '0', width: '100%', height: '100%' });
|
||||
this.overlay.style.opacity = '0';
|
||||
removeClass(this.overlay, 'overlay-move-transition');
|
||||
overlay.style.opacity = '0';
|
||||
removeClass(overlay, 'overlay-move-transition');
|
||||
|
||||
// Reset current operation
|
||||
this.currentDropOperation = undefined;
|
||||
|
||||
@@ -4,9 +4,8 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/editorgroupview';
|
||||
|
||||
import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup';
|
||||
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane } from 'vs/workbench/common/editor';
|
||||
import { EditorInput, EditorOptions, GroupIdentifier, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditorPane, EditorGroupEditorsCountContext, SaveReason, IEditorPartOptionsChangeEvent, EditorsOrder, IVisibleEditorPane, EditorStickyContext, EditorPinnedContext } from 'vs/workbench/common/editor';
|
||||
import { Event, Emitter, Relay } from 'vs/base/common/event';
|
||||
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom';
|
||||
@@ -17,7 +16,7 @@ import { attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { IThemeService, registerThemingParticipant, Themable } from 'vs/platform/theme/common/themeService';
|
||||
import { editorBackground, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_HEADER_NO_TABS_BACKGROUND, EDITOR_GROUP_EMPTY_BACKGROUND, EDITOR_GROUP_FOCUSED_EMPTY_BORDER, EDITOR_GROUP_HEADER_BORDER } from 'vs/workbench/common/theme';
|
||||
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, GroupsOrder, ICloseEditorOptions, ICloseAllEditorsOptions, OpenEditorContext } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl';
|
||||
import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl';
|
||||
import { IEditorProgressService } from 'vs/platform/progress/common/progress';
|
||||
@@ -220,8 +219,10 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
private handleGroupContextKeys(contextKeyService: IContextKeyService): void {
|
||||
const groupActiveEditorDirtyContextKey = EditorGroupActiveEditorDirtyContext.bindTo(contextKeyService);
|
||||
const groupEditorsCountContext = EditorGroupEditorsCountContext.bindTo(contextKeyService);
|
||||
const groupActiveEditorPinnedContext = EditorPinnedContext.bindTo(contextKeyService);
|
||||
const groupActiveEditorStickyContext = EditorStickyContext.bindTo(contextKeyService);
|
||||
|
||||
let activeEditorListener = new MutableDisposable();
|
||||
const activeEditorListener = new MutableDisposable();
|
||||
|
||||
const observeActiveEditor = () => {
|
||||
activeEditorListener.clear();
|
||||
@@ -237,11 +238,22 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
// Update group contexts based on group changes
|
||||
this._register(this.onDidGroupChange(e => {
|
||||
|
||||
// Track the active editor and update context key that reflects
|
||||
// the dirty state of this editor
|
||||
if (e.kind === GroupChangeKind.EDITOR_ACTIVE) {
|
||||
observeActiveEditor();
|
||||
switch (e.kind) {
|
||||
case GroupChangeKind.EDITOR_ACTIVE:
|
||||
// Track the active editor and update context key that reflects
|
||||
// the dirty state of this editor
|
||||
observeActiveEditor();
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_PIN:
|
||||
if (e.editor && e.editor === this._group.activeEditor) {
|
||||
groupActiveEditorPinnedContext.set(this._group.isPinned(this._group.activeEditor));
|
||||
}
|
||||
break;
|
||||
case GroupChangeKind.EDITOR_STICKY:
|
||||
if (e.editor && e.editor === this._group.activeEditor) {
|
||||
groupActiveEditorStickyContext.set(this._group.isSticky(this._group.activeEditor));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Group editors count context
|
||||
@@ -464,6 +476,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
// Model Events
|
||||
this._register(this._group.onDidChangeEditorPinned(editor => this.onDidChangeEditorPinned(editor)));
|
||||
this._register(this._group.onDidChangeEditorSticky(editor => this.onDidChangeEditorSticky(editor)));
|
||||
this._register(this._group.onDidOpenEditor(editor => this.onDidOpenEditor(editor)));
|
||||
this._register(this._group.onDidCloseEditor(editor => this.handleOnDidCloseEditor(editor)));
|
||||
this._register(this._group.onDidDisposeEditor(editor => this.onDidDisposeEditor(editor)));
|
||||
@@ -478,11 +491,13 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
private onDidChangeEditorPinned(editor: EditorInput): void {
|
||||
|
||||
// Event
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_PIN, editor });
|
||||
}
|
||||
|
||||
private onDidChangeEditorSticky(editor: EditorInput): void {
|
||||
this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_STICKY, editor });
|
||||
}
|
||||
|
||||
private onDidOpenEditor(editor: EditorInput): void {
|
||||
|
||||
/* __GDPR__
|
||||
@@ -596,11 +611,11 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
// Title control Switch between showing tabs <=> not showing tabs
|
||||
if (event.oldPartOptions.showTabs !== event.newPartOptions.showTabs) {
|
||||
|
||||
// Recreate and layout control
|
||||
// Recreate title control
|
||||
this.createTitleAreaControl();
|
||||
if (this.dimension) {
|
||||
this.layoutTitleAreaControl(this.dimension.width);
|
||||
}
|
||||
|
||||
// Re-layout
|
||||
this.relayout();
|
||||
|
||||
// Ensure to show active editor if any
|
||||
if (this._group.activeEditor) {
|
||||
@@ -848,7 +863,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
//#region openEditor()
|
||||
|
||||
async openEditor(editor: EditorInput, options?: EditorOptions): Promise<IEditorPane | null> {
|
||||
async openEditor(editor: EditorInput, options?: EditorOptions, context?: OpenEditorContext): Promise<IEditorPane | null> {
|
||||
|
||||
// Guard against invalid inputs
|
||||
if (!editor) {
|
||||
@@ -856,7 +871,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}
|
||||
|
||||
// Editor opening event allows for prevention
|
||||
const event = new EditorOpeningEvent(this._group.id, editor, options);
|
||||
const event = new EditorOpeningEvent(this._group.id, editor, options, context);
|
||||
this._onWillOpenEditor.fire(event);
|
||||
const prevented = event.isPrevented();
|
||||
if (prevented) {
|
||||
@@ -1110,7 +1125,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
|
||||
// Move across groups
|
||||
else {
|
||||
this.doMoveOrCopyEditorAcrossGroups(editor, target, options);
|
||||
this.doMoveOrCopyEditorAcrossGroups(editor, target, options, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1156,7 +1171,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
|
||||
}));
|
||||
|
||||
// A move to another group is an open first...
|
||||
target.openEditor(editor, options);
|
||||
target.openEditor(editor, options, keepCopy ? OpenEditorContext.COPY_EDITOR : OpenEditorContext.MOVE_EDITOR);
|
||||
|
||||
// ...and a close afterwards (unless we copy)
|
||||
if (!keepCopy) {
|
||||
@@ -1702,7 +1717,8 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
constructor(
|
||||
private _group: GroupIdentifier,
|
||||
private _editor: EditorInput,
|
||||
private _options: EditorOptions | undefined
|
||||
private _options: EditorOptions | undefined,
|
||||
private _context: OpenEditorContext | undefined
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -1718,6 +1734,10 @@ class EditorOpeningEvent implements IEditorOpeningEvent {
|
||||
return this._options;
|
||||
}
|
||||
|
||||
get context(): OpenEditorContext | undefined {
|
||||
return this._context;
|
||||
}
|
||||
|
||||
prevent(callback: () => Promise<IEditorPane | undefined>): void {
|
||||
this.override = callback;
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ import { EditorDropTarget, EditorDropTargetDelegate } from 'vs/workbench/browser
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { Parts, IWorkbenchLayoutService, Position } from 'vs/workbench/services/layout/browser/layoutService';
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { MementoObject } from 'vs/workbench/common/memento';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
@@ -839,12 +839,62 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
|
||||
}
|
||||
}));
|
||||
|
||||
let panelOpenerTimeout: any;
|
||||
this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(overlay, {
|
||||
onDragOver: e => {
|
||||
EventHelper.stop(e.eventData, true);
|
||||
if (e.eventData.dataTransfer) {
|
||||
e.eventData.dataTransfer.dropEffect = 'none';
|
||||
}
|
||||
|
||||
if (!this.layoutService.isVisible(Parts.PANEL_PART)) {
|
||||
const boundingRect = overlay.getBoundingClientRect();
|
||||
|
||||
let openPanel = false;
|
||||
const proximity = 100;
|
||||
switch (this.layoutService.getPanelPosition()) {
|
||||
case Position.BOTTOM:
|
||||
if (e.eventData.clientY > boundingRect.bottom - proximity) {
|
||||
openPanel = true;
|
||||
}
|
||||
break;
|
||||
case Position.LEFT:
|
||||
if (e.eventData.clientX < boundingRect.left + proximity) {
|
||||
openPanel = true;
|
||||
}
|
||||
break;
|
||||
case Position.RIGHT:
|
||||
if (e.eventData.clientX > boundingRect.right - proximity) {
|
||||
openPanel = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!panelOpenerTimeout && openPanel) {
|
||||
panelOpenerTimeout = setTimeout(() => this.layoutService.setPanelHidden(false), 200);
|
||||
} else if (panelOpenerTimeout && !openPanel) {
|
||||
clearTimeout(panelOpenerTimeout);
|
||||
panelOpenerTimeout = undefined;
|
||||
}
|
||||
}
|
||||
},
|
||||
onDragLeave: () => {
|
||||
if (panelOpenerTimeout) {
|
||||
clearTimeout(panelOpenerTimeout);
|
||||
panelOpenerTimeout = undefined;
|
||||
}
|
||||
},
|
||||
onDragEnd: () => {
|
||||
if (panelOpenerTimeout) {
|
||||
clearTimeout(panelOpenerTimeout);
|
||||
panelOpenerTimeout = undefined;
|
||||
}
|
||||
},
|
||||
onDrop: () => {
|
||||
if (panelOpenerTimeout) {
|
||||
clearTimeout(panelOpenerTimeout);
|
||||
panelOpenerTimeout = undefined;
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ export class EditorsObserver extends Disposable {
|
||||
}
|
||||
|
||||
get editors(): IEditorIdentifier[] {
|
||||
return this.mostRecentEditorsMap.values();
|
||||
return [...this.mostRecentEditorsMap.values()];
|
||||
}
|
||||
|
||||
hasEditor(resource: URI): boolean {
|
||||
@@ -283,7 +283,7 @@ export class EditorsObserver extends Disposable {
|
||||
|
||||
// Across all editor groups
|
||||
else {
|
||||
await this.doEnsureOpenedEditorsLimit(limit, this.mostRecentEditorsMap.values(), exclude);
|
||||
await this.doEnsureOpenedEditorsLimit(limit, [...this.mostRecentEditorsMap.values()], exclude);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -346,7 +346,7 @@ export class EditorsObserver extends Disposable {
|
||||
private serialize(): ISerializedEditorsList {
|
||||
const registry = Registry.as<IEditorInputFactoryRegistry>(Extensions.EditorInputFactories);
|
||||
|
||||
const entries = this.mostRecentEditorsMap.values();
|
||||
const entries = [...this.mostRecentEditorsMap.values()];
|
||||
const mapGroupToSerializableEditorsOfGroup = new Map<IEditorGroup, IEditorInput[]>();
|
||||
|
||||
return {
|
||||
|
||||
@@ -211,7 +211,7 @@
|
||||
text-overflow: clip;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container {
|
||||
.monaco-workbench.hc-black .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-shrink > .monaco-icon-label > .monaco-icon-label-container {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
@@ -290,13 +290,12 @@
|
||||
padding-right: 5px; /* we need less room when sizing is shrink (unless tab is sticky) */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close,
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty-border-top > .tab-close {
|
||||
display: none; /* hide dirty state when highlightModifiedTabs is enabled and when running without close button */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top) {
|
||||
padding-right: 0; /* remove extra padding when we are running without close button */
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off.dirty:not(.dirty-border-top):not(.sticky) {
|
||||
padding-right: 0; /* remove extra padding when we are running without close button (unless tab is sticky) */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.close-button-off > .tab-close {
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/* Title Actions */
|
||||
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label,
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label {
|
||||
.monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label:not(span) {
|
||||
display: flex;
|
||||
height: 35px;
|
||||
min-width: 28px;
|
||||
@@ -40,8 +40,8 @@
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label,
|
||||
.hc-black .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label:not(.codicon) {
|
||||
.monaco-workbench.hc-black .part.editor > .content .editor-group-container > .title .title-actions .action-label,
|
||||
.monaco-workbench.hc-black .part.editor > .content .editor-group-container > .title .editor-actions .action-label:not(.codicon) {
|
||||
line-height: initial;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { TitleControl, IToolbarActions } from 'vs/workbench/browser/parts/editor
|
||||
import { ResourceLabel, IResourceLabel } from 'vs/workbench/browser/labels';
|
||||
import { TAB_ACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { EventType as TouchEventType, GestureEvent, Gesture } from 'vs/base/browser/touch';
|
||||
import { addDisposableListener, EventType, addClass, EventHelper, removeClass, toggleClass } from 'vs/base/browser/dom';
|
||||
import { addDisposableListener, EventType, addClass, EventHelper, removeClass, toggleClass, Dimension } from 'vs/base/browser/dom';
|
||||
import { EDITOR_TITLE_HEIGHT } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { CLOSE_EDITOR_COMMAND_ID } from 'vs/workbench/browser/parts/editor/editorCommands';
|
||||
@@ -232,7 +232,7 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
private redraw(): void {
|
||||
const editor = withNullAsUndefined(this.group.activeEditor);
|
||||
|
||||
const isEditorPinned = this.group.activeEditor ? this.group.isPinned(this.group.activeEditor) : false;
|
||||
const isEditorPinned = editor ? this.group.isPinned(editor) : false;
|
||||
const isGroupActive = this.accessor.activeGroup === this.group;
|
||||
|
||||
this.activeLabel = { editor, pinned: isEditorPinned };
|
||||
@@ -320,4 +320,10 @@ export class NoTabsTitleControl extends TitleControl {
|
||||
// Group inactive: only show close action
|
||||
return { primaryEditorActions: editorActions.primary.filter(action => action.id === CLOSE_EDITOR_COMMAND_ID), secondaryEditorActions: [] };
|
||||
}
|
||||
|
||||
layout(dimension: Dimension): void {
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.layout(undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { IRange } from 'vs/editor/common/core/range';
|
||||
import { CursorChangeReason, ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents';
|
||||
@@ -26,9 +26,11 @@ export class RangeHighlightDecorations extends Disposable {
|
||||
private readonly editorDisposables = this._register(new DisposableStore());
|
||||
|
||||
private readonly _onHighlightRemoved: Emitter<void> = this._register(new Emitter<void>());
|
||||
readonly onHighlightRemoved: Event<void> = this._onHighlightRemoved.event;
|
||||
readonly onHighlightRemoved = this._onHighlightRemoved.event;
|
||||
|
||||
constructor(@IEditorService private readonly editorService: IEditorService) {
|
||||
constructor(
|
||||
@IEditorService private readonly editorService: IEditorService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,10 +31,10 @@ import { ResourcesDropHandler, DraggedEditorIdentifier, DraggedEditorGroupIdenti
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { MergeGroupMode, IMergeGroupOptions, GroupsArrangement } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { MergeGroupMode, IMergeGroupOptions, GroupsArrangement, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { addClass, addDisposableListener, hasClass, EventType, EventHelper, removeClass, Dimension, scheduleAtNextAnimationFrame, findParentWithClass, clearNode } from 'vs/base/browser/dom';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView, EditorServiceImpl, EDITOR_TITLE_HEIGHT, computeEditorAriaLabel } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { CloseOneEditorAction } from 'vs/workbench/browser/parts/editor/editorActions';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { BreadcrumbsControl } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
@@ -107,7 +107,8 @@ export class TabsTitleControl extends TitleControl {
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IFileService fileService: IFileService,
|
||||
@IEditorService private readonly editorService: EditorServiceImpl,
|
||||
@IPathService private readonly pathService: IPathService
|
||||
@IPathService private readonly pathService: IPathService,
|
||||
@IEditorGroupsService private readonly editorGroupService: IEditorGroupsService
|
||||
) {
|
||||
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickInputService, themeService, extensionService, configurationService, fileService);
|
||||
|
||||
@@ -199,15 +200,12 @@ export class TabsTitleControl extends TitleControl {
|
||||
|
||||
private updateBreadcrumbsControl(): void {
|
||||
if (this.breadcrumbsControl && this.breadcrumbsControl.update()) {
|
||||
// relayout when we have a breadcrumbs and when update changed
|
||||
// its hidden-status
|
||||
this.group.relayout();
|
||||
this.group.relayout(); // relayout when we have a breadcrumbs and when update changed its hidden-status
|
||||
}
|
||||
}
|
||||
|
||||
protected handleBreadcrumbsEnablementChange(): void {
|
||||
// relayout when breadcrumbs are enable/disabled
|
||||
this.group.relayout();
|
||||
this.group.relayout(); // relayout when breadcrumbs are enable/disabled
|
||||
}
|
||||
|
||||
private registerTabsContainerListeners(tabsContainer: HTMLElement, tabsScrollbar: ScrollableElement): void {
|
||||
@@ -898,12 +896,12 @@ export class TabsTitleControl extends TitleControl {
|
||||
const { verbosity, shortenDuplicates } = this.getLabelConfigFlags(labelFormat);
|
||||
|
||||
// Build labels and descriptions for each editor
|
||||
const labels = this.group.editors.map(editor => ({
|
||||
const labels = this.group.editors.map((editor, index) => ({
|
||||
editor,
|
||||
name: editor.getName(),
|
||||
description: editor.getDescription(verbosity),
|
||||
title: withNullAsUndefined(editor.getTitle(Verbosity.LONG)),
|
||||
ariaLabel: editor.isReadonly() ? localize('readonlyEditor', "{0} readonly", editor.getTitle(Verbosity.SHORT)) : editor.getTitle(Verbosity.SHORT)
|
||||
ariaLabel: computeEditorAriaLabel(editor, index, this.group, this.editorGroupService.count)
|
||||
}));
|
||||
|
||||
// Shorten labels as needed
|
||||
@@ -1211,6 +1209,10 @@ export class TabsTitleControl extends TitleControl {
|
||||
return hasModifiedBorderColor;
|
||||
}
|
||||
|
||||
getPreferredHeight(): number {
|
||||
return EDITOR_TITLE_HEIGHT + (this.breadcrumbsControl && !this.breadcrumbsControl.isHidden() ? BreadcrumbsControl.HEIGHT : 0);
|
||||
}
|
||||
|
||||
layout(dimension: Dimension | undefined): void {
|
||||
this.dimension = dimension;
|
||||
|
||||
|
||||
@@ -223,19 +223,6 @@ export class TextDiffEditor extends BaseTextEditor implements ITextDiffEditorPan
|
||||
return options;
|
||||
}
|
||||
|
||||
protected getAriaLabel(): string {
|
||||
let ariaLabel: string;
|
||||
|
||||
const inputName = this.input?.getName();
|
||||
if (this.input?.isReadonly()) {
|
||||
ariaLabel = inputName ? nls.localize('readonlyEditorWithInputAriaLabel', "{0} readonly compare", inputName) : nls.localize('readonlyEditorAriaLabel', "Readonly compare");
|
||||
} else {
|
||||
ariaLabel = inputName ? nls.localize('editableEditorWithInputAriaLabel', "{0} compare", inputName) : nls.localize('editableEditorAriaLabel', "Compare");
|
||||
}
|
||||
|
||||
return ariaLabel;
|
||||
}
|
||||
|
||||
private isFileBinaryError(error: Error[]): boolean;
|
||||
private isFileBinaryError(error: Error): boolean;
|
||||
private isFileBinaryError(error: Error | Error[]): boolean {
|
||||
|
||||
@@ -23,6 +23,7 @@ import { isCodeEditor, getCodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { IEditorGroupsService, IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { computeEditorAriaLabel } from 'vs/workbench/browser/parts/editor/editor';
|
||||
|
||||
export interface IEditorConfiguration {
|
||||
editor: object;
|
||||
@@ -102,16 +103,7 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditorPa
|
||||
}
|
||||
|
||||
private computeAriaLabel(): string {
|
||||
let ariaLabel = this.getAriaLabel();
|
||||
|
||||
// Apply group information to help identify in
|
||||
// which group we are (only if more than one group
|
||||
// is actually opened)
|
||||
if (ariaLabel && this.group && this.editorGroupService.count > 1) {
|
||||
ariaLabel = localize('editorLabelWithGroup', "{0}, {1}", ariaLabel, this.group.ariaLabel);
|
||||
}
|
||||
|
||||
return ariaLabel;
|
||||
return this._input ? computeEditorAriaLabel(this._input, undefined, this.group, this.editorGroupService.count) : localize('editor', "Editor");
|
||||
}
|
||||
|
||||
protected getConfigurationOverrides(): IEditorOptions {
|
||||
@@ -303,8 +295,6 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditorPa
|
||||
return undefined;
|
||||
}
|
||||
|
||||
protected abstract getAriaLabel(): string;
|
||||
|
||||
dispose(): void {
|
||||
this.lastAppliedEditorOptions = undefined;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ import { IModelService } from 'vs/editor/common/services/modelService';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { PLAINTEXT_MODE_ID } from 'vs/editor/common/modes/modesRegistry';
|
||||
import { EditorOption, IEditorOptions } from 'vs/editor/common/config/editorOptions';
|
||||
import { basenameOrAuthority } from 'vs/base/common/resources';
|
||||
import { ModelConstants } from 'vs/editor/common/model';
|
||||
|
||||
/**
|
||||
@@ -108,11 +107,6 @@ export class AbstractTextResourceEditor extends BaseTextEditor {
|
||||
}
|
||||
}
|
||||
|
||||
protected getAriaLabel(): string {
|
||||
const inputName = this.input instanceof UntitledTextEditorInput ? basenameOrAuthority(this.input.resource) : this.input?.getName() || nls.localize('writeableEditorAriaLabel', "Editor");
|
||||
return this.input?.isReadonly() ? nls.localize('readonlyEditor', "{0} readonly", inputName) : inputName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reveals the last line of this editor if it has a model set.
|
||||
*/
|
||||
|
||||
@@ -31,7 +31,7 @@ import { DraggedEditorGroupIdentifier, DraggedEditorIdentifier, fillResourceData
|
||||
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
|
||||
import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs';
|
||||
import { BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl';
|
||||
import { EDITOR_TITLE_HEIGHT, IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor';
|
||||
import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor, EditorPinnedContext, EditorStickyContext } from 'vs/workbench/common/editor';
|
||||
import { ResourceContextKey } from 'vs/workbench/common/resources';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
@@ -51,7 +51,7 @@ export abstract class TitleControl extends Themable {
|
||||
protected readonly groupTransfer = LocalSelectionTransfer.getInstance<DraggedEditorGroupIdentifier>();
|
||||
protected readonly editorTransfer = LocalSelectionTransfer.getInstance<DraggedEditorIdentifier>();
|
||||
|
||||
protected breadcrumbsControl?: BreadcrumbsControl;
|
||||
protected breadcrumbsControl: BreadcrumbsControl | undefined = undefined;
|
||||
|
||||
private currentPrimaryEditorActionIds: string[] = [];
|
||||
private currentSecondaryEditorActionIds: string[] = [];
|
||||
@@ -118,6 +118,7 @@ export abstract class TitleControl extends Themable {
|
||||
this.handleBreadcrumbsEnablementChange();
|
||||
}
|
||||
}));
|
||||
|
||||
if (config.getValue()) {
|
||||
this.breadcrumbsControl = this.instantiationService.createInstance(BreadcrumbsControl, container, options, this.group);
|
||||
}
|
||||
@@ -401,15 +402,9 @@ export abstract class TitleControl extends Themable {
|
||||
|
||||
abstract updateStyles(): void;
|
||||
|
||||
layout(dimension: Dimension): void {
|
||||
if (this.breadcrumbsControl) {
|
||||
this.breadcrumbsControl.layout(undefined);
|
||||
}
|
||||
}
|
||||
abstract layout(dimension: Dimension): void;
|
||||
|
||||
getPreferredHeight(): number {
|
||||
return EDITOR_TITLE_HEIGHT + (this.breadcrumbsControl && !this.breadcrumbsControl.isHidden() ? BreadcrumbsControl.HEIGHT : 0);
|
||||
}
|
||||
abstract getPreferredHeight(): number;
|
||||
|
||||
dispose(): void {
|
||||
dispose(this.breadcrumbsControl);
|
||||
|
||||
@@ -305,7 +305,7 @@ export class NotificationsCenter extends Themable implements INotificationsCente
|
||||
this.hide();
|
||||
|
||||
// Close all
|
||||
for (const notification of this.model.notifications) {
|
||||
for (const notification of [...this.model.notifications] /* copy array since we modify it from closing */) {
|
||||
if (!notification.hasProgress) {
|
||||
notification.close();
|
||||
}
|
||||
|
||||
@@ -63,12 +63,9 @@
|
||||
}
|
||||
|
||||
.monaco-workbench .part.panel .empty-panel-message-area {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.monaco-workbench .part.panel .empty-panel-message-area.visible {
|
||||
|
||||
@@ -282,7 +282,6 @@ actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(TogglePanelActi
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(FocusPanelAction), 'View: Focus into Panel', nls.localize('view', "View"));
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleMaximizedPanelAction), 'View: Toggle Maximized Panel', nls.localize('view', "View"));
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ClosePanelAction), 'View: Close Panel', nls.localize('view', "View"));
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(ToggleMaximizedPanelAction), 'View: Toggle Panel Position', nls.localize('view', "View"));
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(PreviousPanelViewAction), 'View: Previous Panel View', nls.localize('view', "View"));
|
||||
actionRegistry.registerWorkbenchAction(SyncActionDescriptor.from(NextPanelViewAction), 'View: Next Panel View', nls.localize('view', "View"));
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ClosePanelAction, PanelActivityAction, ToggleMaximizedPanelAction, TogglePanelAction, PlaceHolderPanelActivityAction, PlaceHolderToggleCompositePinnedAction, PositionPanelActionConfigs, SetPanelPositionAction } from 'vs/workbench/browser/parts/panel/panelActions';
|
||||
import { IThemeService, registerThemingParticipant, IColorTheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
|
||||
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_DRAG_AND_DROP_BACKGROUND, PANEL_INPUT_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND } from 'vs/workbench/common/theme';
|
||||
import { PANEL_BACKGROUND, PANEL_BORDER, PANEL_ACTIVE_TITLE_FOREGROUND, PANEL_INACTIVE_TITLE_FOREGROUND, PANEL_ACTIVE_TITLE_BORDER, PANEL_INPUT_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, PANEL_DRAG_AND_DROP_BORDER } from 'vs/workbench/common/theme';
|
||||
import { activeContrastBorder, focusBorder, contrastBorder, editorBackground, badgeBackground, badgeForeground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
|
||||
import { ToggleCompositePinnedAction } from 'vs/workbench/browser/parts/compositeBarActions';
|
||||
@@ -35,7 +35,7 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ViewContainer, IViewDescriptorService, IViewContainerModel, ViewContainerLocation } from 'vs/workbench/common/views';
|
||||
import { MenuId } from 'vs/platform/actions/common/actions';
|
||||
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||
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 } from 'vs/workbench/browser/dnd';
|
||||
@@ -50,11 +50,17 @@ interface ICachedPanel {
|
||||
views?: { when?: string }[];
|
||||
}
|
||||
|
||||
interface IPlaceholderViewContainer {
|
||||
id: string;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
|
||||
static readonly activePanelSettingsKey = 'workbench.panelpart.activepanelid';
|
||||
|
||||
static readonly PINNED_PANELS = 'workbench.panel.pinnedPanels';
|
||||
static readonly PLACEHOLDER_VIEW_CONTAINERS = 'workbench.panel.placeholderPanels';
|
||||
private static readonly MIN_COMPOSITE_BAR_WIDTH = 50;
|
||||
|
||||
_serviceBrand: undefined;
|
||||
@@ -94,6 +100,8 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
private blockOpeningPanel = false;
|
||||
private contentDimension: Dimension | undefined;
|
||||
|
||||
private extensionsRegistered = false;
|
||||
|
||||
private panelRegistry: PanelRegistry;
|
||||
|
||||
private dndHandler: ICompositeDragAndDrop;
|
||||
@@ -135,8 +143,9 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
storageKeysSyncRegistryService.registerStorageKey({ key: PanelPart.PINNED_PANELS, version: 1 });
|
||||
|
||||
this.dndHandler = new CompositeDragAndDrop(this.viewDescriptorService, ViewContainerLocation.Panel,
|
||||
(id: string, focus?: boolean) => (<unknown>this.openPanel(id, focus) as Promise<IPaneComposite | undefined>).then(panel => panel || null),
|
||||
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.horizontallyBefore)
|
||||
(id: string, focus?: boolean) => (this.openPanel(id, focus) as Promise<IPaneComposite | undefined>).then(panel => panel || null),
|
||||
(from: string, to: string, before?: Before2D) => this.compositeBar.move(from, to, before?.horizontallyBefore),
|
||||
() => this.compositeBar.getCompositeBarItems()
|
||||
);
|
||||
|
||||
this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.getCachedPanels(), {
|
||||
@@ -167,7 +176,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
inactiveForegroundColor: theme.getColor(PANEL_INACTIVE_TITLE_FOREGROUND),
|
||||
badgeBackground: theme.getColor(badgeBackground),
|
||||
badgeForeground: theme.getColor(badgeForeground),
|
||||
dragAndDropBackground: theme.getColor(PANEL_DRAG_AND_DROP_BACKGROUND)
|
||||
dragAndDropBorder: theme.getColor(PANEL_DRAG_AND_DROP_BORDER)
|
||||
})
|
||||
}));
|
||||
|
||||
@@ -188,6 +197,10 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
result.push(...viewMenuActions.getContextMenuActions());
|
||||
viewMenuActions.dispose();
|
||||
}
|
||||
|
||||
const viewContainerMenuActions = this.instantiationService.createInstance(ViewContainerMenuActions, container.id, MenuId.ViewContainerTitleContext);
|
||||
result.push(...viewContainerMenuActions.getContextMenuActions());
|
||||
viewContainerMenuActions.dispose();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -196,10 +209,21 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
for (const panel of panels) {
|
||||
const cachedPanel = this.getCachedPanels().filter(({ id }) => id === panel.id)[0];
|
||||
const activePanel = this.getActivePanel();
|
||||
const isActive = activePanel?.getId() === panel.id || (!activePanel && this.getLastActivePanelId() === panel.id);
|
||||
const isActive =
|
||||
activePanel?.getId() === panel.id ||
|
||||
(!activePanel && this.getLastActivePanelId() === panel.id) ||
|
||||
(this.extensionsRegistered && this.compositeBar.getVisibleComposites().length === 0);
|
||||
|
||||
if (isActive || !this.shouldBeHidden(panel.id, cachedPanel)) {
|
||||
this.compositeBar.addComposite(panel);
|
||||
|
||||
// Override order
|
||||
const newPanel = {
|
||||
id: panel.id,
|
||||
name: panel.name,
|
||||
order: cachedPanel?.order === undefined ? panel.order : cachedPanel.order
|
||||
};
|
||||
|
||||
this.compositeBar.addComposite(newPanel);
|
||||
|
||||
// Pin it by default if it is new
|
||||
if (!cachedPanel) {
|
||||
@@ -255,9 +279,11 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private updateActivity(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
|
||||
const cachedTitle = this.getPlaceholderViewContainers().filter(panel => panel.id === viewContainer.id)[0]?.name;
|
||||
|
||||
const activity: IActivity = {
|
||||
id: viewContainer.id,
|
||||
name: viewContainerModel.title,
|
||||
name: this.extensionsRegistered || cachedTitle === undefined ? viewContainerModel.title : cachedTitle,
|
||||
keybindingId: viewContainer.focusCommand?.id
|
||||
};
|
||||
|
||||
@@ -268,7 +294,10 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
pinnedAction.setActivity(activity);
|
||||
}
|
||||
|
||||
this.saveCachedPanels();
|
||||
// only update our cached panel info after extensions are done registering
|
||||
if (this.extensionsRegistered) {
|
||||
this.saveCachedPanels();
|
||||
}
|
||||
}
|
||||
|
||||
private onDidChangeActiveViews(viewContainer: ViewContainer, viewContainerModel: IViewContainerModel): void {
|
||||
@@ -291,6 +320,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// Panel registration
|
||||
this._register(this.registry.onDidRegister(panel => this.onDidRegisterPanels([panel])));
|
||||
this._register(this.registry.onDidDeregister(panel => this.onDidDeregisterPanel(panel.id)));
|
||||
@@ -313,6 +343,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private onDidRegisterExtensions(): void {
|
||||
this.extensionsRegistered = true;
|
||||
this.removeNotExistingComposites();
|
||||
|
||||
this.saveCachedPanels();
|
||||
@@ -388,15 +419,16 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
|
||||
private createEmptyPanelMessage(): void {
|
||||
const contentArea = this.getContentArea()!;
|
||||
this.emptyPanelMessageElement = document.createElement('div');
|
||||
addClass(this.emptyPanelMessageElement, 'empty-panel-message-area');
|
||||
|
||||
const messageElement = document.createElement('div');
|
||||
addClass(messageElement, 'empty-panel-message');
|
||||
messageElement.innerText = localize('panel.emptyMessage', "No panels to display. Drag a view into the panel.");
|
||||
messageElement.innerText = localize('panel.emptyMessage', "Drag a view into the panel to display.");
|
||||
|
||||
this.emptyPanelMessageElement.appendChild(messageElement);
|
||||
this.element.appendChild(this.emptyPanelMessageElement);
|
||||
contentArea.appendChild(this.emptyPanelMessageElement);
|
||||
|
||||
this._register(CompositeDragAndDropObserver.INSTANCE.registerTarget(this.emptyPanelMessageElement, {
|
||||
onDragOver: (e) => {
|
||||
@@ -455,7 +487,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
}
|
||||
}
|
||||
|
||||
return this.openComposite(id, focus);
|
||||
return this.openComposite(id, focus) as Panel;
|
||||
}
|
||||
|
||||
async openPanel(id?: string, focus?: boolean): Promise<Panel | undefined> {
|
||||
@@ -670,6 +702,7 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
|
||||
private saveCachedPanels(): void {
|
||||
const state: ICachedPanel[] = [];
|
||||
const placeholders: IPlaceholderViewContainer[] = [];
|
||||
|
||||
const compositeItems = this.compositeBar.getCompositeBarItems();
|
||||
for (const compositeItem of compositeItems) {
|
||||
@@ -677,10 +710,12 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
if (viewContainer) {
|
||||
const viewContainerModel = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
state.push({ id: compositeItem.id, name: viewContainerModel.title, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible });
|
||||
placeholders.push({ id: compositeItem.id, name: this.getCompositeActions(compositeItem.id).activityAction.label });
|
||||
}
|
||||
}
|
||||
|
||||
this.cachedPanelsValue = JSON.stringify(state);
|
||||
this.setPlaceholderViewContainers(placeholders);
|
||||
}
|
||||
|
||||
private getCachedPanels(): ICachedPanel[] {
|
||||
@@ -694,6 +729,13 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
return serialized;
|
||||
});
|
||||
|
||||
for (const placeholderViewContainer of this.getPlaceholderViewContainers()) {
|
||||
const cachedViewContainer = cachedPanels.filter(cached => cached.id === placeholderViewContainer.id)[0];
|
||||
if (cachedViewContainer) {
|
||||
cachedViewContainer.name = placeholderViewContainer.name;
|
||||
}
|
||||
}
|
||||
|
||||
return cachedPanels;
|
||||
}
|
||||
|
||||
@@ -721,6 +763,38 @@ export class PanelPart extends CompositePart<Panel> implements IPanelService {
|
||||
this.storageService.store(PanelPart.PINNED_PANELS, value, StorageScope.GLOBAL);
|
||||
}
|
||||
|
||||
private getPlaceholderViewContainers(): IPlaceholderViewContainer[] {
|
||||
return JSON.parse(this.placeholderViewContainersValue);
|
||||
}
|
||||
|
||||
private setPlaceholderViewContainers(placeholderViewContainers: IPlaceholderViewContainer[]): void {
|
||||
this.placeholderViewContainersValue = JSON.stringify(placeholderViewContainers);
|
||||
}
|
||||
|
||||
private _placeholderViewContainersValue: string | undefined;
|
||||
private get placeholderViewContainersValue(): string {
|
||||
if (!this._placeholderViewContainersValue) {
|
||||
this._placeholderViewContainersValue = this.getStoredPlaceholderViewContainersValue();
|
||||
}
|
||||
|
||||
return this._placeholderViewContainersValue;
|
||||
}
|
||||
|
||||
private set placeholderViewContainersValue(placeholderViewContainesValue: string) {
|
||||
if (this.placeholderViewContainersValue !== placeholderViewContainesValue) {
|
||||
this._placeholderViewContainersValue = placeholderViewContainesValue;
|
||||
this.setStoredPlaceholderViewContainersValue(placeholderViewContainesValue);
|
||||
}
|
||||
}
|
||||
|
||||
private getStoredPlaceholderViewContainersValue(): string {
|
||||
return this.storageService.get(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, StorageScope.WORKSPACE, '[]');
|
||||
}
|
||||
|
||||
private setStoredPlaceholderViewContainersValue(value: string): void {
|
||||
this.storageService.store(PanelPart.PLACEHOLDER_VIEW_CONTAINERS, value, StorageScope.WORKSPACE);
|
||||
}
|
||||
|
||||
private getViewContainer(panelId: string): ViewContainer | undefined {
|
||||
return this.viewDescriptorService.getViewContainerById(panelId) || undefined;
|
||||
}
|
||||
|
||||
@@ -98,6 +98,7 @@
|
||||
align-items: center;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
outline-width: 0px; /* do not render focus outline, we already have background */
|
||||
}
|
||||
|
||||
.monaco-workbench .part.statusbar > .items-container > .statusbar-item > a:hover {
|
||||
|
||||
@@ -9,7 +9,6 @@ import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { dispose, IDisposable, Disposable, toDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { CodiconLabel } from 'vs/base/browser/ui/codicons/codiconLabel';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||
import { Part } from 'vs/workbench/browser/part';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
@@ -69,6 +68,10 @@ class StatusbarViewModel extends Disposable {
|
||||
get entries(): IStatusbarViewModelEntry[] { return this._entries; }
|
||||
|
||||
private hidden!: Set<string>;
|
||||
get lastFocusedEntry(): IStatusbarViewModelEntry | undefined {
|
||||
return this._lastFocusedEntry && !this.isHidden(this._lastFocusedEntry.id) ? this._lastFocusedEntry : undefined;
|
||||
}
|
||||
private _lastFocusedEntry: IStatusbarViewModelEntry | undefined;
|
||||
|
||||
private readonly _onDidChangeEntryVisibility = this._register(new Emitter<{ id: string, visible: boolean }>());
|
||||
readonly onDidChangeEntryVisibility = this._onDidChangeEntryVisibility.event;
|
||||
@@ -219,6 +222,7 @@ class StatusbarViewModel extends Disposable {
|
||||
if (focused) {
|
||||
const entry = getVisibleEntry(this._entries.indexOf(focused) + delta);
|
||||
if (entry) {
|
||||
this._lastFocusedEntry = entry;
|
||||
entry.labelContainer.focus();
|
||||
return;
|
||||
}
|
||||
@@ -226,6 +230,7 @@ class StatusbarViewModel extends Disposable {
|
||||
|
||||
const entry = getVisibleEntry(restartPosition);
|
||||
if (entry) {
|
||||
this._lastFocusedEntry = entry;
|
||||
entry.labelContainer.focus();
|
||||
}
|
||||
}
|
||||
@@ -493,6 +498,15 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
this.viewModel.focusPreviousEntry();
|
||||
}
|
||||
|
||||
focus(preserveEntryFocus = true): void {
|
||||
this.getContainer()?.focus();
|
||||
const lastFocusedEntry = this.viewModel.lastFocusedEntry;
|
||||
if (preserveEntryFocus && lastFocusedEntry) {
|
||||
// Need a timeout, for some reason without it the inner label container will not get focused
|
||||
setTimeout(() => lastFocusedEntry.labelContainer.focus(), 0);
|
||||
}
|
||||
}
|
||||
|
||||
createContentArea(parent: HTMLElement): HTMLElement {
|
||||
this.element = parent;
|
||||
|
||||
@@ -680,10 +694,6 @@ export class StatusbarPart extends Part implements IStatusbarService {
|
||||
return itemContainer;
|
||||
}
|
||||
|
||||
focus(): void {
|
||||
this.getContainer();
|
||||
}
|
||||
|
||||
layout(width: number, height: number): void {
|
||||
super.layout(width, height);
|
||||
super.layoutContents(width, height);
|
||||
@@ -715,7 +725,6 @@ class StatusbarEntryItem extends Disposable {
|
||||
@ICommandService private readonly commandService: ICommandService,
|
||||
@INotificationService private readonly notificationService: INotificationService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IEditorService private readonly editorService: IEditorService,
|
||||
@IThemeService private readonly themeService: IThemeService
|
||||
) {
|
||||
super();
|
||||
@@ -773,7 +782,7 @@ class StatusbarEntryItem extends Disposable {
|
||||
const command = entry.command;
|
||||
if (command) {
|
||||
this.commandMouseListener.value = addDisposableListener(this.labelContainer, EventType.CLICK, () => this.executeCommand(command));
|
||||
this.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_UP, e => {
|
||||
this.commandKeyboardListener.value = addDisposableListener(this.labelContainer, EventType.KEY_DOWN, e => {
|
||||
const event = new StandardKeyboardEvent(e);
|
||||
if (event.equals(KeyCode.Space) || event.equals(KeyCode.Enter)) {
|
||||
this.executeCommand(command);
|
||||
@@ -818,12 +827,6 @@ class StatusbarEntryItem extends Disposable {
|
||||
const id = typeof command === 'string' ? command : command.id;
|
||||
const args = typeof command === 'string' ? [] : command.arguments ?? [];
|
||||
|
||||
// Maintain old behaviour of always focusing the editor here
|
||||
const activeTextEditorControl = this.editorService.activeTextEditorControl;
|
||||
if (activeTextEditorControl) {
|
||||
activeTextEditorControl.focus();
|
||||
}
|
||||
|
||||
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id, from: 'status bar' });
|
||||
try {
|
||||
await this.commandService.executeCommand(id, ...args);
|
||||
@@ -935,3 +938,38 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
statusBarService.focusNextEntry();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.statusBar.focusFirst',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.Home,
|
||||
when: CONTEXT_STATUS_BAR_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const statusBarService = accessor.get(IStatusbarService);
|
||||
statusBarService.focus(false);
|
||||
statusBarService.focusNextEntry();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.statusBar.focusLast',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.End,
|
||||
when: CONTEXT_STATUS_BAR_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const statusBarService = accessor.get(IStatusbarService);
|
||||
statusBarService.focus(false);
|
||||
statusBarService.focusPreviousEntry();
|
||||
}
|
||||
});
|
||||
|
||||
KeybindingsRegistry.registerCommandAndKeybindingRule({
|
||||
id: 'workbench.statusBar.clearFocus',
|
||||
weight: KeybindingWeight.WorkbenchContrib,
|
||||
primary: KeyCode.Escape,
|
||||
when: CONTEXT_STATUS_BAR_FOCUSED,
|
||||
handler: (accessor: ServicesAccessor) => {
|
||||
const statusBarService = accessor.get(IStatusbarService);
|
||||
statusBarService.focus(false);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -333,7 +333,6 @@ export class TitlebarPart extends Part implements ITitleService {
|
||||
this.customMenubar = this._register(this.instantiationService.createInstance(CustomMenubarControl));
|
||||
|
||||
this.menubar = this.element.insertBefore($('div.menubar'), this.title);
|
||||
|
||||
this.menubar.setAttribute('role', 'menubar');
|
||||
|
||||
this.customMenubar.create(this.menubar);
|
||||
|
||||
@@ -18,6 +18,16 @@
|
||||
.monaco-pane-view .pane > .pane-header > .actions.show {
|
||||
display: initial;
|
||||
}
|
||||
.monaco-pane-view .pane > .pane-header .icon {
|
||||
display: none;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane.pane.horizontal:not(.expanded) > .pane-header .icon {
|
||||
display: inline;
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane > .pane-header h3.title {
|
||||
white-space: nowrap;
|
||||
@@ -28,6 +38,11 @@
|
||||
-webkit-margin-after: 0;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane.horizontal:not(.expanded) > .pane-header h3.title,
|
||||
.monaco-pane-view .pane.horizontal:not(.expanded) > .pane-header .description {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-pane-view .pane .monaco-progress-container {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
@@ -68,6 +68,9 @@ export class TreeViewPane extends ViewPane {
|
||||
this._register(toDisposable(() => this.treeView.setVisibility(false)));
|
||||
this._register(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility()));
|
||||
this._register(this.treeView.onDidChangeWelcomeState(() => this._onDidChangeViewWelcomeState.fire()));
|
||||
if (options.title !== this.treeView.title) {
|
||||
this.updateTitle(this.treeView.title);
|
||||
}
|
||||
this.updateTreeVisibility();
|
||||
}
|
||||
|
||||
@@ -161,7 +164,7 @@ export class TreeView extends Disposable implements ITreeView {
|
||||
private readonly _onDidCompleteRefresh: Emitter<void> = this._register(new Emitter<void>());
|
||||
|
||||
constructor(
|
||||
protected readonly id: string,
|
||||
readonly id: string,
|
||||
private _title: string,
|
||||
@IThemeService private readonly themeService: IThemeService,
|
||||
@IInstantiationService private readonly instantiationService: IInstantiationService,
|
||||
@@ -425,8 +428,15 @@ export class TreeView extends Disposable implements ITreeView {
|
||||
identityProvider: new TreeViewIdentityProvider(),
|
||||
accessibilityProvider: {
|
||||
getAriaLabel(element: ITreeItem): string {
|
||||
if (element.accessibilityInformation) {
|
||||
return element.accessibilityInformation.label;
|
||||
}
|
||||
|
||||
return element.tooltip ? element.tooltip : element.label ? element.label.label : '';
|
||||
},
|
||||
getRole(element: ITreeItem): string | undefined {
|
||||
return element.accessibilityInformation?.role;
|
||||
},
|
||||
getWidgetAriaLabel(): string {
|
||||
return widgetAriaLabel;
|
||||
}
|
||||
@@ -783,15 +793,15 @@ class TreeRenderer extends Disposable implements ITreeRenderer<ITreeItem, FuzzyS
|
||||
const description = isString(node.description) ? node.description : resource && node.description === true ? this.labelService.getUriLabel(dirname(resource), { relative: true }) : undefined;
|
||||
const label = treeItemLabel ? treeItemLabel.label : undefined;
|
||||
const matches = (treeItemLabel && treeItemLabel.highlights && label) ? treeItemLabel.highlights.map(([start, end]) => {
|
||||
if ((Math.abs(start) > label.length) || (Math.abs(end) >= label.length)) {
|
||||
return ({ start: 0, end: 0 });
|
||||
}
|
||||
if (start < 0) {
|
||||
start = label.length + start;
|
||||
}
|
||||
if (end < 0) {
|
||||
end = label.length + end;
|
||||
}
|
||||
if ((start >= label.length) || (end > label.length)) {
|
||||
return ({ start: 0, end: 0 });
|
||||
}
|
||||
if (start > end) {
|
||||
const swap = start;
|
||||
start = end;
|
||||
|
||||
@@ -69,3 +69,37 @@ export class ViewMenuActions extends Disposable {
|
||||
return this.contextMenuActions;
|
||||
}
|
||||
}
|
||||
|
||||
export class ViewContainerMenuActions extends Disposable {
|
||||
|
||||
private readonly titleActionsDisposable = this._register(new MutableDisposable());
|
||||
private contextMenuActions: IAction[] = [];
|
||||
|
||||
constructor(
|
||||
containerId: string,
|
||||
contextMenuId: MenuId,
|
||||
@IContextKeyService private readonly contextKeyService: IContextKeyService,
|
||||
@IMenuService private readonly menuService: IMenuService,
|
||||
) {
|
||||
super();
|
||||
|
||||
const scopedContextKeyService = this._register(this.contextKeyService.createScoped());
|
||||
scopedContextKeyService.createKey('container', containerId);
|
||||
|
||||
const contextMenu = this._register(this.menuService.createMenu(contextMenuId, scopedContextKeyService));
|
||||
const updateContextMenuActions = () => {
|
||||
this.contextMenuActions = [];
|
||||
this.titleActionsDisposable.value = createAndFillInActionBarActions(contextMenu, { shouldForwardArgs: true }, { primary: [], secondary: this.contextMenuActions });
|
||||
};
|
||||
this._register(contextMenu.onDidChange(updateContextMenuActions));
|
||||
updateContextMenuActions();
|
||||
|
||||
this._register(toDisposable(() => {
|
||||
this.contextMenuActions = [];
|
||||
}));
|
||||
}
|
||||
|
||||
getContextMenuActions(): IAction[] {
|
||||
return this.contextMenuActions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
import 'vs/css!./media/paneviewlet';
|
||||
import * as nls from 'vs/nls';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ColorIdentifier, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { ColorIdentifier, activeContrastBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { attachStyler, IColorMapping, attachButtonStyler, attachLinkStyler, attachProgressBarStyler } from 'vs/platform/theme/common/styler';
|
||||
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER, PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, EDITOR_DRAG_AND_DROP_BACKGROUND, PANEL_BORDER } from 'vs/workbench/common/theme';
|
||||
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener, removeClass, addClass } from 'vs/base/browser/dom';
|
||||
import { SIDE_BAR_DRAG_AND_DROP_BACKGROUND, SIDE_BAR_SECTION_HEADER_FOREGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, SIDE_BAR_SECTION_HEADER_BORDER, PANEL_BACKGROUND, SIDE_BAR_BACKGROUND, PANEL_SECTION_HEADER_FOREGROUND, PANEL_SECTION_HEADER_BACKGROUND, PANEL_SECTION_HEADER_BORDER, PANEL_SECTION_DRAG_AND_DROP_BACKGROUND, PANEL_SECTION_BORDER } from 'vs/workbench/common/theme';
|
||||
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener, removeClass, addClass, createCSSRule, asCSSUrl, addClasses } from 'vs/base/browser/dom';
|
||||
import { IDisposable, combinedDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
@@ -20,20 +20,20 @@ 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 { PaneView, IPaneViewOptions, IPaneOptions, Pane } from 'vs/base/browser/ui/splitview/paneview';
|
||||
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 { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { assertIsDefined, isString } 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';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { Component } from 'vs/workbench/common/component';
|
||||
import { MenuId, MenuItemAction } from 'vs/platform/actions/common/actions';
|
||||
import { MenuId, MenuItemAction, registerAction2, Action2, IAction2Options } from 'vs/platform/actions/common/actions';
|
||||
import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem';
|
||||
import { ViewMenuActions } from 'vs/workbench/browser/parts/views/viewMenuActions';
|
||||
import { parseLinkedText } from 'vs/base/common/linkedText';
|
||||
@@ -48,6 +48,9 @@ import { IProgressIndicator } from 'vs/platform/progress/common/progress';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
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';
|
||||
|
||||
export interface IPaneColors extends IColorMapping {
|
||||
dropBackground?: ColorIdentifier;
|
||||
@@ -185,6 +188,7 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
private readonly showActionsAlways: boolean = false;
|
||||
private headerContainer?: HTMLElement;
|
||||
private titleContainer?: HTMLElement;
|
||||
private iconContainer?: HTMLElement;
|
||||
protected twistiesContainer?: HTMLElement;
|
||||
|
||||
private bodyContainer!: HTMLElement;
|
||||
@@ -290,6 +294,10 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
this._register(this.toolbar);
|
||||
this.setActions();
|
||||
|
||||
this._register(this.viewDescriptorService.getViewContainerModel(this.viewDescriptorService.getViewContainerByViewId(this.id)!)!.onDidChangeContainerInfo(({ title }) => {
|
||||
this.updateTitle(this.title);
|
||||
}));
|
||||
|
||||
const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewPane.AlwaysShowActionsConfig));
|
||||
this._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this));
|
||||
this.updateActionsVisibility();
|
||||
@@ -299,18 +307,86 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
this.twistiesContainer = append(container, $('.twisties.codicon.codicon-chevron-right'));
|
||||
}
|
||||
|
||||
style(styles: IPaneStyles): void {
|
||||
super.style(styles);
|
||||
|
||||
const icon = this.getIcon();
|
||||
if (this.iconContainer) {
|
||||
const fgColor = styles.headerForeground || this.themeService.getColorTheme().getColor(foreground);
|
||||
if (URI.isUri(icon)) {
|
||||
// Apply background color to activity bar item provided with iconUrls
|
||||
this.iconContainer.style.backgroundColor = fgColor ? fgColor.toString() : '';
|
||||
this.iconContainer.style.color = '';
|
||||
} else {
|
||||
// Apply foreground color to activity bar items provided with codicons
|
||||
this.iconContainer.style.color = fgColor ? fgColor.toString() : '';
|
||||
this.iconContainer.style.backgroundColor = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private getIcon(): string | URI {
|
||||
return this.viewDescriptorService.getViewDescriptorById(this.id)?.containerIcon || 'codicon-window';
|
||||
}
|
||||
|
||||
protected renderHeaderTitle(container: HTMLElement, title: string): void {
|
||||
this.titleContainer = append(container, $('h3.title', undefined, title));
|
||||
this.iconContainer = append(container, $('.icon', undefined));
|
||||
const icon = this.getIcon();
|
||||
|
||||
let cssClass: string | undefined = undefined;
|
||||
if (URI.isUri(icon)) {
|
||||
cssClass = `view-${this.id.replace(/[\.\:]/g, '-')}`;
|
||||
const iconClass = `.pane-header .icon.${cssClass}`;
|
||||
|
||||
createCSSRule(iconClass, `
|
||||
mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
|
||||
mask-size: 24px;
|
||||
-webkit-mask: ${asCSSUrl(icon)} no-repeat 50% 50%;
|
||||
-webkit-mask-size: 16px;
|
||||
`);
|
||||
} else if (isString(icon)) {
|
||||
addClass(this.iconContainer, 'codicon');
|
||||
cssClass = icon;
|
||||
}
|
||||
|
||||
if (cssClass) {
|
||||
addClasses(this.iconContainer, cssClass);
|
||||
}
|
||||
|
||||
const calculatedTitle = this.calculateTitle(title);
|
||||
this.titleContainer = append(container, $('h3.title', undefined, calculatedTitle));
|
||||
this.iconContainer.title = calculatedTitle;
|
||||
this.iconContainer.setAttribute('aria-label', calculatedTitle);
|
||||
}
|
||||
|
||||
protected updateTitle(title: string): void {
|
||||
const calculatedTitle = this.calculateTitle(title);
|
||||
if (this.titleContainer) {
|
||||
this.titleContainer.textContent = title;
|
||||
this.titleContainer.textContent = calculatedTitle;
|
||||
}
|
||||
|
||||
if (this.iconContainer) {
|
||||
this.iconContainer.title = calculatedTitle;
|
||||
this.iconContainer.setAttribute('aria-label', calculatedTitle);
|
||||
}
|
||||
|
||||
this.title = title;
|
||||
this._onDidChangeTitleArea.fire();
|
||||
}
|
||||
|
||||
private calculateTitle(title: string): string {
|
||||
const viewContainer = this.viewDescriptorService.getViewContainerByViewId(this.id)!;
|
||||
const model = this.viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
const viewDescriptor = this.viewDescriptorService.getViewDescriptorById(this.id);
|
||||
const isDefault = this.viewDescriptorService.getDefaultContainerById(this.id) === viewContainer;
|
||||
|
||||
if (!isDefault && viewDescriptor?.containerTitle && model.title !== viewDescriptor.containerTitle) {
|
||||
return `${viewDescriptor.containerTitle}: ${title}`;
|
||||
}
|
||||
|
||||
return title;
|
||||
}
|
||||
|
||||
private scrollableElement!: DomScrollableElement;
|
||||
|
||||
protected renderBody(container: HTMLElement): void {
|
||||
@@ -510,7 +586,6 @@ export abstract class ViewPane extends Pane implements IView {
|
||||
|
||||
export interface IViewPaneContainerOptions extends IPaneViewOptions {
|
||||
mergeViewWithContainerWhenSingleView: boolean;
|
||||
donotShowContainerTitleWhenMergedWithContainer?: boolean;
|
||||
}
|
||||
|
||||
interface IViewPaneItem {
|
||||
@@ -546,7 +621,8 @@ class ViewPaneDropOverlay extends Themable {
|
||||
constructor(
|
||||
private paneElement: HTMLElement,
|
||||
private orientation: Orientation | undefined,
|
||||
protected themeService: IThemeService
|
||||
protected location: ViewContainerLocation,
|
||||
protected themeService: IThemeService,
|
||||
) {
|
||||
super(themeService);
|
||||
this.cleanupOverlayScheduler = this._register(new RunOnceScheduler(() => this.dispose(), 300));
|
||||
@@ -587,7 +663,7 @@ class ViewPaneDropOverlay extends Themable {
|
||||
protected updateStyles(): void {
|
||||
|
||||
// Overlay drop background
|
||||
this.overlay.style.backgroundColor = this.getColor(EDITOR_DRAG_AND_DROP_BACKGROUND) || '';
|
||||
this.overlay.style.backgroundColor = this.getColor(this.location === ViewContainerLocation.Panel ? PANEL_SECTION_DRAG_AND_DROP_BACKGROUND : SIDE_BAR_DRAG_AND_DROP_BACKGROUND) || '';
|
||||
|
||||
// Overlay contrast border (if any)
|
||||
const activeContrastBorderColor = this.getColor(activeContrastBorder);
|
||||
@@ -830,7 +906,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
return;
|
||||
}
|
||||
|
||||
overlay = new ViewPaneDropOverlay(parent, undefined, this.themeService);
|
||||
overlay = new ViewPaneDropOverlay(parent, undefined, this.viewDescriptorService.getViewContainerLocation(this.viewContainer)!, this.themeService);
|
||||
}
|
||||
|
||||
if (dropData.type === 'composite' && dropData.id !== this.viewContainer.id) {
|
||||
@@ -838,7 +914,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewsToMove = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
|
||||
if (!viewsToMove.some(v => !v.canMoveView)) {
|
||||
overlay = new ViewPaneDropOverlay(parent, undefined, this.themeService);
|
||||
overlay = new ViewPaneDropOverlay(parent, undefined, this.viewDescriptorService.getViewContainerLocation(this.viewContainer)!, this.themeService);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -904,7 +980,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
|
||||
if (this.isViewMergedWithContainer()) {
|
||||
const paneItemTitle = this.paneItems[0].pane.title;
|
||||
if (this.options.donotShowContainerTitleWhenMergedWithContainer || containerTitle === paneItemTitle) {
|
||||
if (containerTitle === paneItemTitle) {
|
||||
return this.paneItems[0].pane.title;
|
||||
}
|
||||
return paneItemTitle ? `${containerTitle}: ${paneItemTitle}` : containerTitle;
|
||||
@@ -1227,6 +1303,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
this.updateTitleArea();
|
||||
}
|
||||
});
|
||||
|
||||
const onDidChangeVisibility = pane.onDidChangeBodyVisibility(() => this._onDidChangeViewVisibility.fire(pane));
|
||||
const onDidChange = pane.onDidChange(() => {
|
||||
if (pane === this.lastFocusedPane && !pane.isExpanded()) {
|
||||
@@ -1234,13 +1311,13 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}
|
||||
});
|
||||
|
||||
// TODO@sbatten Styling is viewlet specific, must fix
|
||||
const isPanel = this.viewDescriptorService.getViewLocationById(this.viewContainer.id) === ViewContainerLocation.Panel;
|
||||
const paneStyler = attachStyler<IPaneColors>(this.themeService, {
|
||||
headerForeground: SIDE_BAR_SECTION_HEADER_FOREGROUND,
|
||||
headerBackground: SIDE_BAR_SECTION_HEADER_BACKGROUND,
|
||||
headerBorder: SIDE_BAR_SECTION_HEADER_BORDER,
|
||||
leftBorder: PANEL_BORDER,
|
||||
dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND
|
||||
headerForeground: isPanel ? PANEL_SECTION_HEADER_FOREGROUND : SIDE_BAR_SECTION_HEADER_FOREGROUND,
|
||||
headerBackground: isPanel ? PANEL_SECTION_HEADER_BACKGROUND : SIDE_BAR_SECTION_HEADER_BACKGROUND,
|
||||
headerBorder: isPanel ? PANEL_SECTION_HEADER_BORDER : SIDE_BAR_SECTION_HEADER_BORDER,
|
||||
dropBackground: isPanel ? PANEL_SECTION_DRAG_AND_DROP_BACKGROUND : SIDE_BAR_DRAG_AND_DROP_BACKGROUND,
|
||||
leftBorder: isPanel ? PANEL_SECTION_BORDER : undefined
|
||||
}, pane);
|
||||
const disposable = combinedDisposable(pane, onDidFocus, onDidChangeTitleArea, paneStyler, onDidChange, onDidChangeVisibility);
|
||||
const paneItem: IViewPaneItem = { pane, disposable };
|
||||
@@ -1265,7 +1342,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
return;
|
||||
}
|
||||
|
||||
overlay = new ViewPaneDropOverlay(pane.dropTargetElement, this.orientation ?? Orientation.VERTICAL, this.themeService);
|
||||
overlay = new ViewPaneDropOverlay(pane.dropTargetElement, this.orientation ?? Orientation.VERTICAL, this.viewDescriptorService.getViewContainerLocation(this.viewContainer)!, this.themeService);
|
||||
}
|
||||
|
||||
if (dropData.type === 'composite' && dropData.id !== this.viewContainer.id && !this.viewContainer.rejectAddedViews) {
|
||||
@@ -1273,7 +1350,7 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
const viewsToMove = this.viewDescriptorService.getViewContainerModel(container).allViewDescriptors;
|
||||
|
||||
if (!viewsToMove.some(v => !v.canMoveView)) {
|
||||
overlay = new ViewPaneDropOverlay(pane.dropTargetElement, this.orientation ?? Orientation.VERTICAL, this.themeService);
|
||||
overlay = new ViewPaneDropOverlay(pane.dropTargetElement, this.orientation ?? Orientation.VERTICAL, this.viewDescriptorService.getViewContainerLocation(this.viewContainer)!, this.themeService);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1466,3 +1543,96 @@ export class ViewPaneContainer extends Component implements IViewPaneContainer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MoveViewPosition extends Action2 {
|
||||
constructor(desc: Readonly<IAction2Options>, private readonly offset: number) {
|
||||
super(desc);
|
||||
}
|
||||
|
||||
async run(accessor: ServicesAccessor): Promise<void> {
|
||||
const viewDescriptorService = accessor.get(IViewDescriptorService);
|
||||
const contextKeyService = accessor.get(IContextKeyService);
|
||||
|
||||
const viewId = FocusedViewContext.getValue(contextKeyService);
|
||||
if (viewId === undefined) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewContainer = viewDescriptorService.getViewContainerByViewId(viewId)!;
|
||||
const model = viewDescriptorService.getViewContainerModel(viewContainer);
|
||||
|
||||
const viewDescriptor = model.visibleViewDescriptors.find(vd => vd.id === viewId)!;
|
||||
const currentIndex = model.visibleViewDescriptors.indexOf(viewDescriptor);
|
||||
if (currentIndex + this.offset < 0 || currentIndex + this.offset >= model.visibleViewDescriptors.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const newPosition = model.visibleViewDescriptors[currentIndex + this.offset];
|
||||
|
||||
model.move(viewDescriptor.id, newPosition.id);
|
||||
}
|
||||
}
|
||||
|
||||
registerAction2(
|
||||
class MoveViewUp extends MoveViewPosition {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'views.moveViewUp',
|
||||
title: nls.localize('viewMoveUp', "Move View Up"),
|
||||
keybinding: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd + KeyCode.KEY_K, KeyCode.UpArrow),
|
||||
weight: KeybindingWeight.WorkbenchContrib + 1,
|
||||
when: FocusedViewContext.notEqualsTo('')
|
||||
}
|
||||
}, -1);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerAction2(
|
||||
class MoveViewLeft extends MoveViewPosition {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'views.moveViewLeft',
|
||||
title: nls.localize('viewMoveLeft', "Move View Left"),
|
||||
keybinding: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd + KeyCode.KEY_K, KeyCode.LeftArrow),
|
||||
weight: KeybindingWeight.WorkbenchContrib + 1,
|
||||
when: FocusedViewContext.notEqualsTo('')
|
||||
}
|
||||
}, -1);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerAction2(
|
||||
class MoveViewDown extends MoveViewPosition {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'views.moveViewDown',
|
||||
title: nls.localize('viewMoveDown', "Move View Down"),
|
||||
keybinding: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd + KeyCode.KEY_K, KeyCode.DownArrow),
|
||||
weight: KeybindingWeight.WorkbenchContrib + 1,
|
||||
when: FocusedViewContext.notEqualsTo('')
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
registerAction2(
|
||||
class MoveViewRight extends MoveViewPosition {
|
||||
constructor() {
|
||||
super({
|
||||
id: 'views.moveViewRight',
|
||||
title: nls.localize('viewMoveRight', "Move View Right"),
|
||||
keybinding: {
|
||||
primary: KeyChord(KeyMod.CtrlCmd + KeyCode.KEY_K, KeyCode.RightArrow),
|
||||
weight: KeybindingWeight.WorkbenchContrib + 1,
|
||||
when: FocusedViewContext.notEqualsTo('')
|
||||
}
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
@@ -20,7 +20,7 @@ import { IPaneComposite } from 'vs/workbench/common/panecomposite';
|
||||
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
|
||||
import { ServicesAccessor, IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
|
||||
import { PaneCompositePanel, PanelRegistry, PanelDescriptor, Extensions as PanelExtensions } from 'vs/workbench/browser/panel';
|
||||
import { PanelRegistry, PanelDescriptor, Extensions as PanelExtensions, Panel } from 'vs/workbench/browser/panel';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
@@ -186,8 +186,8 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
super({
|
||||
id: `${viewDescriptor.id}.resetViewLocation`,
|
||||
title: {
|
||||
original: 'Reset View Location',
|
||||
value: localize('resetViewLocation', "Reset View Location")
|
||||
original: 'Reset Location',
|
||||
value: localize('resetViewLocation', "Reset Location")
|
||||
},
|
||||
menu: [{
|
||||
id: MenuId.ViewTitleContext,
|
||||
@@ -202,6 +202,15 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
}
|
||||
run(accessor: ServicesAccessor): void {
|
||||
const viewDescriptorService = accessor.get(IViewDescriptorService);
|
||||
const defaultContainer = viewDescriptorService.getDefaultContainerById(viewDescriptor.id)!;
|
||||
const containerModel = viewDescriptorService.getViewContainerModel(defaultContainer)!;
|
||||
|
||||
// The default container is hidden so we should try to reset its location first
|
||||
if (defaultContainer.hideIfEmpty && containerModel.visibleViewDescriptors.length === 0) {
|
||||
const defaultLocation = viewDescriptorService.getDefaultViewContainerLocation(defaultContainer)!;
|
||||
viewDescriptorService.moveViewContainerToLocation(defaultContainer, defaultLocation);
|
||||
}
|
||||
|
||||
viewDescriptorService.moveViewsToContainer([viewDescriptor], viewDescriptorService.getDefaultContainerById(viewDescriptor.id)!);
|
||||
accessor.get(IViewsService).openView(viewDescriptor.id, true);
|
||||
}
|
||||
@@ -414,7 +423,7 @@ export class ViewsService extends Disposable implements IViewsService {
|
||||
|
||||
private registerPanel(viewContainer: ViewContainer): void {
|
||||
const that = this;
|
||||
class PaneContainerPanel extends PaneCompositePanel {
|
||||
class PaneContainerPanel extends Panel {
|
||||
constructor(
|
||||
@ITelemetryService telemetryService: ITelemetryService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { mark } from 'vs/base/common/performance';
|
||||
import { domContentLoaded, addDisposableListener, EventType, addClass, EventHelper } from 'vs/base/browser/dom';
|
||||
import { domContentLoaded, addDisposableListener, EventType, EventHelper } from 'vs/base/browser/dom';
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { ILogService, ConsoleLogService, MultiplexLogService } from 'vs/platform/log/common/log';
|
||||
import { ConsoleLogInAutomationService } from 'vs/platform/log/browser/log';
|
||||
@@ -39,7 +39,6 @@ import { BACKUPS } from 'vs/platform/environment/common/environment';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
|
||||
import { registerWindowDriver } from 'vs/platform/driver/browser/driver';
|
||||
import { BufferLogService } from 'vs/platform/log/common/bufferLog';
|
||||
import { FileLogService } from 'vs/platform/log/common/fileLogService';
|
||||
@@ -74,9 +73,6 @@ class BrowserMain extends Disposable {
|
||||
await domContentLoaded();
|
||||
mark('willStartWorkbench');
|
||||
|
||||
// Base Theme
|
||||
this.restoreBaseTheme();
|
||||
|
||||
// Create Workbench
|
||||
const workbench = new Workbench(
|
||||
this.domElement,
|
||||
@@ -131,7 +127,6 @@ class BrowserMain extends Disposable {
|
||||
}));
|
||||
this._register(workbench.onWillShutdown(() => {
|
||||
storageService.close();
|
||||
this.saveBaseTheme();
|
||||
}));
|
||||
this._register(workbench.onShutdown(() => this.dispose()));
|
||||
|
||||
@@ -147,21 +142,6 @@ class BrowserMain extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private restoreBaseTheme(): void {
|
||||
addClass(this.domElement, window.localStorage.getItem('vscode.baseTheme') || getThemeTypeSelector(LIGHT) /* Fallback to a light theme by default on web */);
|
||||
}
|
||||
|
||||
private saveBaseTheme(): void {
|
||||
const classes = this.domElement.className;
|
||||
const baseThemes = [DARK, LIGHT, HIGH_CONTRAST].map(baseTheme => getThemeTypeSelector(baseTheme));
|
||||
for (const baseTheme of baseThemes) {
|
||||
if (classes.indexOf(baseTheme) >= 0) {
|
||||
window.localStorage.setItem('vscode.baseTheme', baseTheme);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService, storageService: BrowserStorageService }> {
|
||||
const serviceCollection = new ServiceCollection();
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
|
||||
},
|
||||
'workbench.editor.scrollToSwitchTabs': {
|
||||
'type': 'boolean',
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls wether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behaviour for that duration."),
|
||||
'description': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'scrollToSwitchTabs' }, "Controls whether scrolling over tabs will open them or not. By default tabs will only reveal upon scrolling, but not open. You can press and hold the Shift-key while scrolling to change this behaviour for that duration."),
|
||||
'default': false
|
||||
},
|
||||
'workbench.editor.highlightModifiedTabs': {
|
||||
|
||||
Reference in New Issue
Block a user