Merge from vscode 1fbacccbc900bb59ba8a8f26a4128d48a1c97842

This commit is contained in:
ADS Merger
2020-02-13 02:56:02 +00:00
parent 9af1f3b0eb
commit 73ea8b79b2
229 changed files with 3192 additions and 2103 deletions

View File

@@ -238,9 +238,12 @@ export class ResourcesDropHandler {
private async handleDirtyEditorDrop(droppedDirtyEditor: IDraggedEditor): Promise<boolean> {
// Untitled: always ensure that we open a new untitled for each file we drop
// Untitled: always ensure that we open a new untitled editor for each file we drop
if (droppedDirtyEditor.resource.scheme === Schemas.untitled) {
droppedDirtyEditor.resource = this.textFileService.untitled.create({ mode: droppedDirtyEditor.mode, encoding: droppedDirtyEditor.encoding }).getResource();
const untitledEditorResource = this.editorService.createInput({ mode: droppedDirtyEditor.mode, encoding: droppedDirtyEditor.encoding, forceUntitled: true }).getResource();
if (untitledEditorResource) {
droppedDirtyEditor.resource = untitledEditorResource;
}
}
// File: ensure the file is not dirty or opened already

View File

@@ -105,8 +105,7 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
);
interface ISerializedUntitledTextEditorInput {
resource: string;
resourceJSON: object;
resourceJSON: UriComponents;
modeId: string | undefined;
encoding: string | undefined;
}
@@ -131,12 +130,11 @@ class UntitledTextEditorInputFactory implements IEditorInputFactory {
const untitledTextEditorInput = <UntitledTextEditorInput>editorInput;
let resource = untitledTextEditorInput.getResource();
if (untitledTextEditorInput.hasAssociatedFilePath) {
if (untitledTextEditorInput.model.hasAssociatedFilePath) {
resource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); // untitled with associated file path use the local schema
}
const serialized: ISerializedUntitledTextEditorInput = {
resource: resource.toString(), // Keep for backwards compatibility
resourceJSON: resource.toJSON(),
modeId: untitledTextEditorInput.getMode(),
encoding: untitledTextEditorInput.getEncoding()
@@ -148,7 +146,7 @@ class UntitledTextEditorInputFactory implements IEditorInputFactory {
deserialize(instantiationService: IInstantiationService, serializedEditorInput: string): UntitledTextEditorInput {
return instantiationService.invokeFunction<UntitledTextEditorInput>(accessor => {
const deserialized: ISerializedUntitledTextEditorInput = JSON.parse(serializedEditorInput);
const resource = !!deserialized.resourceJSON ? URI.revive(<UriComponents>deserialized.resourceJSON) : URI.parse(deserialized.resource);
const resource = URI.revive(deserialized.resourceJSON);
const mode = deserialized.modeId;
const encoding = deserialized.encoding;

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor, IEditorPartOptions, IEditorPartOptionsChangeEvent } from 'vs/workbench/common/editor';
import { GroupIdentifier, IWorkbenchEditorConfiguration, EditorOptions, TextEditorOptions, IEditorInput, IEditorIdentifier, IEditorCloseEvent, IEditor, 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 { IDisposable } from 'vs/base/common/lifecycle';
@@ -14,7 +14,7 @@ import { IConfigurationChangeEvent } from 'vs/platform/configuration/common/conf
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 } from 'vs/workbench/services/editor/common/editorService';
import { IEditorService, IResourceEditor } from 'vs/workbench/services/editor/common/editorService';
export const EDITOR_TITLE_HEIGHT = 35;
@@ -156,4 +156,9 @@ export interface EditorServiceImpl extends IEditorService {
* Emitted when the list of most recently active editors change.
*/
readonly onDidMostRecentlyActiveEditorsChange: Event<void>;
/**
* Override to return a typed `EditorInput`.
*/
createInput(input: IResourceEditor): EditorInput;
}

View File

@@ -18,11 +18,11 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
import { RunOnceScheduler } from 'vs/base/common/async';
import { find } from 'vs/base/common/arrays';
import { DataTransfers } from 'vs/base/browser/dnd';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { VSBuffer } from 'vs/base/common/buffer';
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';
interface IDropOperation {
splitDirection?: GroupDirection;
@@ -48,8 +48,8 @@ class DropOverlay extends Themable {
private groupView: IEditorGroupView,
@IThemeService themeService: IThemeService,
@IInstantiationService private instantiationService: IInstantiationService,
@ITextFileService private textFileService: ITextFileService,
@IFileDialogService private readonly fileDialogService: IFileDialogService
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@IEditorService private readonly editorService: IEditorService
) {
super(themeService);
@@ -308,8 +308,11 @@ class DropOverlay extends Themable {
}
// Open as untitled file with the provided contents
const contents = VSBuffer.wrap(new Uint8Array(event.target.result)).toString();
const untitledEditor = this.textFileService.untitled.create({ associatedResource: proposedFilePath, initialValue: contents });
const untitledEditor = this.editorService.createInput({
resource: proposedFilePath,
forceUntitled: true,
contents: VSBuffer.wrap(new Uint8Array(event.target.result)).toString()
});
if (!targetGroup) {
targetGroup = ensureTargetGroup();

View File

@@ -31,8 +31,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { RunOnceWorker } from 'vs/base/common/async';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl';
import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions, IEditorOpeningEvent } from 'vs/workbench/browser/parts/editor/editor';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorGroupsAccessor, IEditorGroupView, getActiveTextEditorOptions, IEditorOpeningEvent, EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { ActionRunner, IAction, Action } from 'vs/base/common/actions';
@@ -43,7 +42,7 @@ import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { createAndFillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { isErrorWithActions, IErrorWithActions } from 'vs/base/common/errorsWithActions';
import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService';
import { IVisibleEditor, IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types';
import { hash } from 'vs/base/common/hash';
import { guessMimeTypes } from 'vs/base/common/mime';
@@ -129,12 +128,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
@INotificationService private readonly notificationService: INotificationService,
@IDialogService private readonly dialogService: IDialogService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@ITextFileService private readonly textFileService: ITextFileService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IMenuService private readonly menuService: IMenuService,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IFileDialogService private readonly fileDialogService: IFileDialogService,
@ILogService private readonly logService: ILogService
@ILogService private readonly logService: ILogService,
@IEditorService private readonly editorService: EditorServiceImpl
) {
super(themeService);
@@ -256,7 +255,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView {
if (this.isEmpty) {
EventHelper.stop(e);
this.openEditor(this.textFileService.untitled.create(), EditorOptions.create({ pinned: true }));
this.openEditor(this.editorService.createInput({ forceUntitled: true }), EditorOptions.create({ pinned: true }));
}
}));

View File

@@ -31,6 +31,7 @@ import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/bro
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { MementoObject } from 'vs/workbench/common/memento';
import { assertIsDefined } from 'vs/base/common/types';
import { IBoundarySashes } from 'vs/base/browser/ui/grid/gridview';
interface IEditorPartUIState {
serializedGrid: ISerializedGrid;
@@ -947,11 +948,15 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
}
private doSetGridWidget(gridWidget: SerializableGrid<IEditorGroupView>): void {
let boundarySashes: IBoundarySashes = {};
if (this.gridWidget) {
boundarySashes = this.gridWidget.boundarySashes;
this.gridWidget.dispose();
}
this.gridWidget = gridWidget;
this.gridWidget.boundarySashes = boundarySashes;
this.gridWidgetView.gridWidget = gridWidget;
this._onDidSizeConstraintsChange.input = gridWidget.onDidChange;
@@ -972,6 +977,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
return this.groupViews.size === 1 && this._activeGroup.isEmpty;
}
setBoundarySashes(sashes: IBoundarySashes): void {
this.gridWidget.boundarySashes = sashes;
this.centeredLayoutWidget.boundarySashes = sashes;
}
layout(width: number, height: number): void {
// Layout contents

View File

@@ -34,14 +34,14 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { MergeGroupMode, IMergeGroupOptions, GroupsArrangement } 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 } from 'vs/workbench/browser/parts/editor/editor';
import { IEditorGroupsAccessor, IEditorGroupView, EditorServiceImpl } 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';
import { IFileService } from 'vs/platform/files/common/files';
import { withNullAsUndefined, assertAllDefined, assertIsDefined } from 'vs/base/common/types';
import { ILabelService } from 'vs/platform/label/common/label';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { basenameOrAuthority } from 'vs/base/common/resources';
// {{SQL CARBON EDIT}} -- Display the editor's tab color
@@ -80,7 +80,6 @@ export class TabsTitleControl extends TitleControl {
group: IEditorGroupView,
@IContextMenuService contextMenuService: IContextMenuService,
@IInstantiationService instantiationService: IInstantiationService,
@ITextFileService private readonly textFileService: ITextFileService,
@IContextKeyService contextKeyService: IContextKeyService,
@IKeybindingService keybindingService: IKeybindingService,
@ITelemetryService telemetryService: ITelemetryService,
@@ -91,7 +90,8 @@ export class TabsTitleControl extends TitleControl {
@IExtensionService extensionService: IExtensionService,
@IConfigurationService configurationService: IConfigurationService,
@IFileService fileService: IFileService,
@ILabelService labelService: ILabelService
@ILabelService labelService: ILabelService,
@IEditorService private readonly editorService: EditorServiceImpl
) {
super(parent, accessor, group, contextMenuService, instantiationService, contextKeyService, keybindingService, telemetryService, notificationService, menuService, quickOpenService, themeService, extensionService, configurationService, fileService, labelService);
@@ -198,7 +198,13 @@ export class TabsTitleControl extends TitleControl {
EventHelper.stop(e);
this.group.openEditor(this.textFileService.untitled.create(), { pinned: true /* untitled is always pinned */, index: this.group.count /* always at the end */ });
this.group.openEditor(this.editorService.createInput({
forceUntitled: true,
options: {
pinned: true, // untitled is always pinned
index: this.group.count // always at the end
}
}));
}));
});

View File

@@ -214,7 +214,7 @@ export class TextResourceEditor extends AbstractTextResourceEditor {
}
private onDidEditorPaste(e: IPasteEvent, codeEditor: ICodeEditor): void {
if (e.range.startLineNumber !== 1 && e.range.startColumn !== 1) {
if (e.range.startLineNumber !== 1 || e.range.startColumn !== 1) {
return; // only when pasting into first line, first column (= empty document)
}

View File

@@ -156,14 +156,14 @@ export abstract class MenubarControl extends Disposable {
return label;
}
protected getOpenRecentActions(): IAction[] {
protected getOpenRecentActions(): (Separator | IAction & { uri: URI })[] {
if (!this.recentlyOpened) {
return [];
}
const { workspaces, files } = this.recentlyOpened;
const result: IAction[] = [];
const result = [];
if (workspaces.length > 0) {
for (let i = 0; i < MenubarControl.MAX_MENU_RECENT_ENTRIES && i < workspaces.length; i++) {

View File

@@ -26,7 +26,7 @@ import { ResourceLabels, IResourceLabel } from 'vs/workbench/browser/labels';
import { ActionBar, IActionViewItemProvider, ActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar';
import { URI } from 'vs/base/common/uri';
import { dirname, basename } from 'vs/base/common/resources';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon } from 'vs/platform/theme/common/themeService';
import { LIGHT, FileThemeIcon, FolderThemeIcon, registerThemingParticipant, ThemeIcon, IThemeService } from 'vs/platform/theme/common/themeService';
import { FileKind } from 'vs/platform/files/common/files';
import { WorkbenchAsyncDataTree, TreeResourceNavigator } from 'vs/platform/list/browser/listService';
import { ViewPane, IViewPaneOptions } from 'vs/workbench/browser/parts/views/viewPaneContainer';
@@ -42,6 +42,7 @@ import { FuzzyScore, createMatches } from 'vs/base/common/filters';
import { CollapseAllAction } from 'vs/base/browser/ui/tree/treeDefaults';
import { isFalsyOrWhitespace } from 'vs/base/common/strings';
import { SIDE_BAR_BACKGROUND, PANEL_BACKGROUND } from 'vs/workbench/common/theme';
import { IOpenerService } from 'vs/platform/opener/common/opener';
export class CustomTreeViewPane extends ViewPane {
@@ -56,8 +57,10 @@ export class CustomTreeViewPane extends ViewPane {
@IContextKeyService contextKeyService: IContextKeyService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IInstantiationService instantiationService: IInstantiationService,
@IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
) {
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService);
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
this.treeView = treeView;
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));
@@ -73,6 +76,8 @@ export class CustomTreeViewPane extends ViewPane {
}
renderBody(container: HTMLElement): void {
super.renderBody(container);
if (this.treeView instanceof CustomTreeView) {
this.treeView.show(container);
}
@@ -113,6 +118,8 @@ class Root implements ITreeItem {
const noDataProviderMessage = localize('no-dataprovider', "There is no data provider registered that can provide view data.");
class CustomTree extends WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> { }
export class CustomTreeView extends Disposable implements ITreeView {
private isVisible: boolean = false;
@@ -127,7 +134,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
private _messageValue: string | undefined;
private _canSelectMany: boolean = false;
private messageElement!: HTMLDivElement;
private tree: WorkbenchAsyncDataTree<ITreeItem, ITreeItem, FuzzyScore> | undefined;
private tree: CustomTree | undefined;
private treeLabels: ResourceLabels | undefined;
private root: ITreeItem;
@@ -351,7 +358,7 @@ export class CustomTreeView extends Disposable implements ITreeView {
const aligner = new Aligner(this.themeService);
const renderer = this.instantiationService.createInstance(TreeRenderer, this.id, treeMenus, this.treeLabels, actionViewItemProvider, aligner);
this.tree = this._register(this.instantiationService.createInstance(WorkbenchAsyncDataTree, 'CustomView', this.treeContainer, new CustomTreeDelegate(), [renderer],
this.tree = this._register(this.instantiationService.createInstance(CustomTree, 'CustomView', this.treeContainer, new CustomTreeDelegate(), [renderer],
dataSource, {
identityProvider: new CustomViewIdentityProvider(),
accessibilityProvider: {

View File

@@ -71,6 +71,26 @@
display: none;
}
.monaco-workbench .pane > .pane-body > .empty-view {
width: 100%;
height: 100%;
padding: 0 20px 0 20px;
position: absolute;
box-sizing: border-box;
}
.monaco-workbench .pane > .pane-body:not(.empty) > .empty-view,
.monaco-workbench .pane > .pane-body.empty > :not(.empty-view) {
display: none;
}
.monaco-workbench .pane > .pane-body > .empty-view .monaco-button {
max-width: 260px;
margin-left: auto;
margin-right: auto;
display: block;
}
.customview-tree .monaco-list-row .monaco-tl-contents.align-icon-with-twisty::before {
display: none;
}

View File

@@ -7,10 +7,10 @@ import 'vs/css!./media/paneviewlet';
import * as nls from 'vs/nls';
import { Event, Emitter } from 'vs/base/common/event';
import { ColorIdentifier } from 'vs/platform/theme/common/colorRegistry';
import { attachStyler, IColorMapping } from 'vs/platform/theme/common/styler';
import { attachStyler, IColorMapping, attachButtonStyler, attachLinkStyler } 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 } from 'vs/workbench/common/theme';
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener } from 'vs/base/browser/dom';
import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { append, $, trackFocus, toggleClass, EventType, isAncestor, Dimension, addDisposableListener, removeClass, addClass } 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, IActionRunner, ActionRunner } from 'vs/base/common/actions';
import { IActionViewItem, ActionsOrientation, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
@@ -25,7 +25,7 @@ import { PaneView, IPaneViewOptions, IPaneOptions, Pane, DefaultPaneDndControlle
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { StandardMouseEvent } from 'vs/base/browser/mouseEvent';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer } from 'vs/workbench/common/views';
import { Extensions as ViewContainerExtensions, IView, FocusedViewContext, IViewContainersRegistry, IViewDescriptor, ViewContainer, IViewDescriptorService, ViewContainerLocation, IViewPaneContainer, IViewsRegistry } 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';
@@ -38,6 +38,10 @@ import { Component } from 'vs/workbench/common/component';
import { MenuId, MenuItemAction } 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/browser/linkedText';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { Button } from 'vs/base/browser/ui/button/button';
import { Link } from 'vs/platform/opener/browser/link';
export interface IPaneColors extends IColorMapping {
dropBackground?: ColorIdentifier;
@@ -54,6 +58,8 @@ export interface IViewPaneOptions extends IPaneOptions {
titleMenuId?: MenuId;
}
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
export abstract class ViewPane extends Pane implements IView {
private static readonly AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions';
@@ -70,6 +76,9 @@ export abstract class ViewPane extends Pane implements IView {
protected _onDidChangeTitleArea = this._register(new Emitter<void>());
readonly onDidChangeTitleArea: Event<void> = this._onDidChangeTitleArea.event;
protected _onDidChangeEmptyState = this._register(new Emitter<void>());
readonly onDidChangeEmptyState: Event<void> = this._onDidChangeEmptyState.event;
private focusedViewContextKey: IContextKey<string>;
private _isVisible: boolean = false;
@@ -79,12 +88,16 @@ export abstract class ViewPane extends Pane implements IView {
private readonly menuActions: ViewMenuActions;
protected actionRunner?: IActionRunner;
protected toolbar?: ToolBar;
private toolbar?: ToolBar;
private readonly showActionsAlways: boolean = false;
private headerContainer?: HTMLElement;
private titleContainer?: HTMLElement;
protected twistiesContainer?: HTMLElement;
private bodyContainer!: HTMLElement;
private emptyViewContainer!: HTMLElement;
private emptyViewDisposable: IDisposable = Disposable.None;
constructor(
options: IViewPaneOptions,
@IKeybindingService protected keybindingService: IKeybindingService,
@@ -93,6 +106,8 @@ export abstract class ViewPane extends Pane implements IView {
@IContextKeyService contextKeyService: IContextKeyService,
@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,
@IInstantiationService protected instantiationService: IInstantiationService,
@IOpenerService protected openerService: IOpenerService,
@IThemeService protected themeService: IThemeService,
) {
super(options);
@@ -189,6 +204,22 @@ export abstract class ViewPane extends Pane implements IView {
this._onDidChangeTitleArea.fire();
}
protected renderBody(container: HTMLElement): void {
this.bodyContainer = container;
this.emptyViewContainer = append(container, $('.empty-view', { tabIndex: 0 }));
// we should update our empty state whenever
const onEmptyViewContentChange = Event.any(
// the registry changes
Event.map(Event.filter(viewsRegistry.onDidChangeEmptyViewContent, id => id === this.id), () => this.isEmpty()),
// or the view's empty state changes
Event.latch(Event.map(this.onDidChangeEmptyState, () => this.isEmpty()))
);
this._register(onEmptyViewContentChange(this.updateEmptyState, this));
this.updateEmptyState(this.isEmpty());
}
protected getProgressLocation(): string {
return this.viewDescriptorService.getViewContainer(this.id)!.id;
}
@@ -254,6 +285,66 @@ export abstract class ViewPane extends Pane implements IView {
saveState(): void {
// Subclasses to implement for saving state
}
private updateEmptyState(isEmpty: boolean): void {
this.emptyViewDisposable.dispose();
if (!isEmpty) {
removeClass(this.bodyContainer, 'empty');
this.emptyViewContainer.innerHTML = '';
return;
}
const contents = viewsRegistry.getEmptyViewContent(this.id);
if (contents.length === 0) {
removeClass(this.bodyContainer, 'empty');
this.emptyViewContainer.innerHTML = '';
return;
}
const disposables = new DisposableStore();
addClass(this.bodyContainer, 'empty');
this.emptyViewContainer.innerHTML = '';
for (const { content } of contents) {
const lines = content.split('\n');
for (let line of lines) {
line = line.trim();
if (!line) {
continue;
}
const p = append(this.emptyViewContainer, $('p'));
const linkedText = parseLinkedText(line);
for (const node of linkedText) {
if (typeof node === 'string') {
append(p, document.createTextNode(node));
} else if (linkedText.length === 1) {
const button = new Button(p, { title: node.title });
button.label = node.label;
button.onDidClick(_ => this.openerService.open(node.href), null, disposables);
disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService));
} else {
const link = this.instantiationService.createInstance(Link, node);
append(p, link.el);
disposables.add(link);
disposables.add(attachLinkStyler(link, this.themeService));
}
}
}
}
this.emptyViewDisposable = disposables;
}
isEmpty(): boolean {
return false;
}
}
export interface IViewPaneContainerOptions extends IPaneViewOptions {

View File

@@ -191,7 +191,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
'type': 'string',
'enum': ['left', 'bottom', 'right'],
'default': 'bottom',
'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom or on the right of the workbench.")
'description': nls.localize('panelDefaultLocation', "Controls the default location of the panel (terminal, debug console, output, problems). It can either show at the bottom, right, or left of the workbench.")
},
'workbench.statusBar.visible': {
'type': 'boolean',
@@ -210,7 +210,7 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
},
'workbench.view.experimental.allowMovingToNewContainer': {
'type': 'boolean',
'default': false,
'default': true,
'description': nls.localize('movingViewContainer', "Controls whether specific views will have a context menu entry allowing them to be moved to a new container. Currently, this setting only affects the outline view and views contributed by extensions.")
},
'workbench.fontAliasing': {