Merge from vscode 33a65245075e4d18908652865a79cf5489c30f40 (#9279)

* Merge from vscode 33a65245075e4d18908652865a79cf5489c30f40

* remove github
This commit is contained in:
Anthony Dresser
2020-02-21 23:42:19 -08:00
committed by GitHub
parent c446cea3a0
commit de5f1eb780
250 changed files with 3724 additions and 2756 deletions

View File

@@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { URI } from 'vs/base/common/uri';
import * as resources from 'vs/base/common/resources';
import { posix } from 'vs/base/common/path';
import { dirname, isEqual, basenameOrAuthority } from 'vs/base/common/resources';
import { IconLabel, IIconLabelValueOptions, IIconLabelCreationOptions } from 'vs/base/browser/ui/iconLabel/iconLabel';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IModeService } from 'vs/editor/common/services/modeService';
@@ -323,7 +324,7 @@ class ResourceLabelWidget extends IconLabel {
}
notifyUntitledLabelChange(resource: URI): void {
if (resources.isEqual(resource, this.label?.resource)) {
if (isEqual(resource, this.label?.resource)) {
this.render(false);
}
}
@@ -340,19 +341,19 @@ class ResourceLabelWidget extends IconLabel {
}
if (!name) {
name = resources.basenameOrAuthority(resource);
name = basenameOrAuthority(resource);
}
}
let description: string | undefined;
if (!options?.hidePath) {
description = this.labelService.getUriLabel(resources.dirname(resource), { relative: true });
description = this.labelService.getUriLabel(dirname(resource), { relative: true });
}
this.setResource({ resource, name, description }, options);
}
setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void {
setResource(label: IResourceLabelProps, options: IResourceLabelOptions = Object.create(null)): void {
if (label.resource?.scheme === Schemas.untitled) {
// Untitled labels are very dynamic because they may change
// whenever the content changes (unless a path is associated).
@@ -368,17 +369,20 @@ class ResourceLabelWidget extends IconLabel {
}
if (typeof label.description === 'string') {
let untitledDescription: string;
if (untitledModel.hasAssociatedFilePath) {
untitledDescription = this.labelService.getUriLabel(resources.dirname(untitledModel.resource), { relative: true });
} else {
untitledDescription = untitledModel.resource.path;
}
let untitledDescription = untitledModel.resource.path;
if (label.name !== untitledDescription) {
label.description = untitledDescription;
} else if (label.description === posix.sep) {
label.description = undefined; // unset showing just "/" for untitled without associated resource
}
}
let untitledTitle = untitledModel.resource.path;
if (untitledModel.name !== untitledTitle) {
options.title = `${untitledModel.name}${untitledTitle}`;
} else {
options.title = untitledTitle;
}
}
}

View File

@@ -59,8 +59,16 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
} else {
this.moveComposite(dragData.id, targetCompositeId);
}
} else {
const draggedViews = this.viewDescriptorService.getViewDescriptors(currentContainer).allViewDescriptors;
if (draggedViews.length === 1 && draggedViews[0].canMoveView) {
dragData.type = 'view';
dragData.id = draggedViews[0].id;
}
}
} else {
}
if (dragData.type === 'view') {
const viewDescriptor = this.viewDescriptorService.getViewDescriptor(dragData.id);
if (viewDescriptor && viewDescriptor.canMoveView) {
if (targetCompositeId) {
@@ -105,7 +113,21 @@ export class CompositeDragAndDrop implements ICompositeDragAndDrop {
// ... across view containers but without a destination composite
if (!targetCompositeId) {
return false;
const draggedViews = this.viewDescriptorService.getViewDescriptors(currentContainer)!.allViewDescriptors;
if (draggedViews.some(vd => !vd.canMoveView)) {
return false;
}
if (draggedViews.length !== 1) {
return false;
}
const defaultLocation = viewContainerRegistry.getViewContainerLocation(this.viewDescriptorService.getDefaultContainer(draggedViews[0].id)!);
if (this.targetContainerLocation === ViewContainerLocation.Sidebar && this.targetContainerLocation !== defaultLocation) {
return false;
}
return true;
}
// ... from panel to the sidebar
@@ -241,10 +263,7 @@ export class CompositeBar extends Widget implements ICompositeBar {
const draggedCompositeId = data[0].id;
this.compositeTransfer.clearData(DraggedCompositeIdentifier.prototype);
const targetItem = this.model.visibleItems[this.model.visibleItems.length - 1];
if (targetItem && targetItem.id !== draggedCompositeId) {
this.move(draggedCompositeId, targetItem.id);
}
this.options.dndHandler.drop(new CompositeDragAndDropData('composite', draggedCompositeId), undefined, e);
}
}

View File

@@ -59,6 +59,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected readonly onDidCompositeClose = this._register(new Emitter<IComposite>());
protected toolBar: ToolBar | undefined;
protected titleLabelElement: HTMLElement | undefined;
private mapCompositeToCompositeContainer = new Map<string, HTMLElement>();
private mapActionsBindingToComposite = new Map<string, () => void>();
@@ -402,6 +403,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
protected createTitleLabel(parent: HTMLElement): ICompositeTitleLabel {
const titleContainer = append(parent, $('.title-label'));
const titleLabel = append(titleContainer, $('h2'));
this.titleLabelElement = titleLabel;
const $this = this;
return {

View File

@@ -16,6 +16,9 @@ import { Event } from 'vs/base/common/event';
import { isEmptyObject } from 'vs/base/common/types';
import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor';
import { MementoObject } from 'vs/workbench/common/memento';
import { isEqualOrParent, joinPath } from 'vs/base/common/resources';
import { isLinux } from 'vs/base/common/platform';
import { indexOfPath } from 'vs/base/common/extpath';
/**
* The base class of editors in the workbench. Editors register themselves for specific editor inputs.
@@ -249,6 +252,34 @@ export class EditorMemento<T> implements IEditorMemento<T> {
}
}
moveEditorState(source: URI, target: URI): void {
const cache = this.doLoad();
const cacheKeys = cache.keys();
for (const cacheKey of cacheKeys) {
const resource = URI.parse(cacheKey);
if (!isEqualOrParent(resource, source)) {
continue; // not matching our resource
}
// Determine new resulting target resource
let targetResource: URI;
if (source.toString() === resource.toString()) {
targetResource = target; // file got moved
} else {
const index = indexOfPath(resource.path, source.path, !isLinux);
targetResource = joinPath(target, resource.path.substr(index + source.path.length + 1)); // parent folder got moved
}
const value = cache.get(cacheKey);
if (value) {
cache.delete(cacheKey);
cache.set(targetResource.toString(), value);
}
}
}
private doGetResource(resourceOrEditor: URI | EditorInput): URI | undefined {
if (resourceOrEditor instanceof EditorInput) {
return resourceOrEditor.resource;

View File

@@ -1227,7 +1227,9 @@ export class ChangeEOLAction extends Action {
const activeCodeEditor = getCodeEditor(this.editorService.activeTextEditorWidget);
if (activeCodeEditor?.hasModel() && !this.editorService.activeEditor?.isReadonly()) {
textModel = activeCodeEditor.getModel();
textModel.pushStackElement();
textModel.pushEOL(eol.eol);
textModel.pushStackElement();
}
}
}

View File

@@ -204,9 +204,6 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
return this.editorControl;
}
/**
* Saves the text editor view state for the given resource.
*/
protected saveTextEditorViewState(resource: URI): void {
const editorViewState = this.retrieveTextEditorViewState(resource);
if (!editorViewState || !this.group) {
@@ -248,22 +245,20 @@ export abstract class BaseTextEditor extends BaseEditor implements ITextEditor {
return control.saveViewState();
}
/**
* Clears the text editor view state for the given resources.
*/
protected loadTextEditorViewState(resource: URI): IEditorViewState | undefined {
return this.group ? this.editorMemento.loadEditorState(this.group, resource) : undefined;
}
protected moveTextEditorViewState(source: URI, target: URI): void {
return this.editorMemento.moveEditorState(source, target);
}
protected clearTextEditorViewState(resources: URI[], group?: IEditorGroup): void {
resources.forEach(resource => {
this.editorMemento.clearEditorState(resource, group);
});
}
/**
* Loads the text editor view state for the given resource and returns it.
*/
protected loadTextEditorViewState(resource: URI): IEditorViewState | undefined {
return this.group ? this.editorMemento.loadEditorState(this.group, resource) : undefined;
}
private updateEditorConfiguration(configuration?: IEditorConfiguration): void {
if (!configuration) {
const resource = this.getActiveResource();

View File

@@ -11,7 +11,7 @@ import { INotificationsModel, INotificationChangeEvent, NotificationChangeType }
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { Emitter } from 'vs/base/common/event';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { NotificationsCenterVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { NotificationsCenterVisibleContext, INotificationsCenterController } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { addClass, removeClass, isAncestor, Dimension } from 'vs/base/browser/dom';
@@ -24,7 +24,7 @@ import { IAction } from 'vs/base/common/actions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { assertAllDefined, assertIsDefined } from 'vs/base/common/types';
export class NotificationsCenter extends Themable {
export class NotificationsCenter extends Themable implements INotificationsCenterController {
private static readonly MAX_DIMENSIONS = new Dimension(450, 400);
@@ -284,8 +284,10 @@ export class NotificationsCenter extends Themable {
this.hide();
// Close all
while (this.model.notifications.length) {
this.model.notifications[0].close();
for (const notification of this.model.notifications) {
if (!notification.hasProgress) {
notification.close();
}
}
}
}

View File

@@ -107,7 +107,7 @@ export function registerNotificationCommands(center: INotificationsCenterControl
},
handler: (accessor, args?: any) => {
const notification = getNotificationFromContext(accessor.get(IListService), args);
if (notification) {
if (notification && !notification.hasProgress) {
notification.close();
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications';
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
@@ -12,11 +12,12 @@ import { localize } from 'vs/nls';
export class NotificationsStatus extends Disposable {
private notificationsCenterStatusItem: IStatusbarEntryAccessor | undefined;
private currentNotifications = new Set<INotificationViewItem>();
private newNotificationsCount = 0;
private currentStatusMessage: [IStatusMessageViewItem, IDisposable] | undefined;
private isNotificationsCenterVisible: boolean | undefined;
private isNotificationsCenterVisible: boolean = false;
private isNotificationsToastsVisible: boolean = false;
constructor(
private model: INotificationsModel,
@@ -39,39 +40,56 @@ export class NotificationsStatus extends Disposable {
}
private onDidChangeNotification(e: INotificationChangeEvent): void {
if (this.isNotificationsCenterVisible) {
return; // no change if notification center is visible
}
// Notification got Added
if (e.kind === NotificationChangeType.ADD) {
this.currentNotifications.add(e.item);
}
// Notification got Removed
else if (e.kind === NotificationChangeType.REMOVE) {
this.currentNotifications.delete(e.item);
// Consider a notification as unread as long as it only
// appeared as toast and not in the notification center
if (!this.isNotificationsCenterVisible) {
if (e.kind === NotificationChangeType.ADD) {
this.newNotificationsCount++;
} else if (e.kind === NotificationChangeType.REMOVE) {
this.newNotificationsCount--;
}
}
// Update in status bar
this.updateNotificationsCenterStatusItem();
}
private updateNotificationsCenterStatusItem(): void {
// Figure out how many notifications have progress only if neither
// toasts are visible nor center is visible. In that case we still
// want to give a hint to the user that something is running.
let notificationsInProgress = 0;
if (!this.isNotificationsCenterVisible && !this.isNotificationsToastsVisible) {
for (const notification of this.model.notifications) {
if (notification.hasProgress) {
notificationsInProgress++;
}
}
}
const statusProperties: IStatusbarEntry = {
text: this.currentNotifications.size === 0 ? '$(bell)' : `$(bell) ${this.currentNotifications.size}`,
text: `${this.newNotificationsCount === 0 ? '$(bell)' : '$(bell-dot)'}${notificationsInProgress > 0 ? ' $(sync~spin)' : ''}`,
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
tooltip: this.getTooltip(),
tooltip: this.getTooltip(notificationsInProgress),
showBeak: this.isNotificationsCenterVisible
};
if (!this.notificationsCenterStatusItem) {
this.notificationsCenterStatusItem = this.statusbarService.addEntry(statusProperties, 'status.notifications', localize('status.notifications', "Notifications"), StatusbarAlignment.RIGHT, -Number.MAX_VALUE /* towards the far end of the right hand side */);
this.notificationsCenterStatusItem = this.statusbarService.addEntry(
statusProperties,
'status.notifications',
localize('status.notifications', "Notifications"),
StatusbarAlignment.RIGHT,
-Number.MAX_VALUE /* towards the far end of the right hand side */
);
} else {
this.notificationsCenterStatusItem.update(statusProperties);
}
}
private getTooltip(): string {
private getTooltip(notificationsInProgress: number): string {
if (this.isNotificationsCenterVisible) {
return localize('hideNotifications', "Hide Notifications");
}
@@ -80,23 +98,45 @@ export class NotificationsStatus extends Disposable {
return localize('zeroNotifications', "No Notifications");
}
if (this.currentNotifications.size === 0) {
return localize('noNotifications', "No New Notifications");
if (notificationsInProgress === 0) {
if (this.newNotificationsCount === 0) {
return localize('noNotifications', "No New Notifications");
}
if (this.newNotificationsCount === 1) {
return localize('oneNotification', "1 New Notification");
}
return localize('notifications', "{0} New Notifications", this.newNotificationsCount);
}
if (this.currentNotifications.size === 1) {
return localize('oneNotification', "1 New Notification");
if (this.newNotificationsCount === 0) {
return localize('noNotificationsWithProgress', "No New Notifications ({0} in progress)", notificationsInProgress);
}
return localize('notifications', "{0} New Notifications", this.currentNotifications.size);
if (this.newNotificationsCount === 1) {
return localize('oneNotificationWithProgress', "1 New Notification ({0} in progress)", notificationsInProgress);
}
return localize('notificationsWithProgress', "{0} New Notifications ({0} in progress)", this.newNotificationsCount, notificationsInProgress);
}
update(isCenterVisible: boolean): void {
update(isCenterVisible: boolean, isToastsVisible: boolean): void {
let updateNotificationsCenterStatusItem = false;
if (this.isNotificationsCenterVisible !== isCenterVisible) {
this.isNotificationsCenterVisible = isCenterVisible;
this.newNotificationsCount = 0; // Showing the notification center resets the unread counter to 0
updateNotificationsCenterStatusItem = true;
}
// Showing the notification center resets the counter to 0
this.currentNotifications.clear();
if (this.isNotificationsToastsVisible !== isToastsVisible) {
this.isNotificationsToastsVisible = isToastsVisible;
updateNotificationsCenterStatusItem = true;
}
// Update in status bar as needed
if (updateNotificationsCenterStatusItem) {
this.updateNotificationsCenterStatusItem();
}
}

View File

@@ -9,13 +9,13 @@ import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/com
import { addClass, removeClass, isAncestor, addDisposableListener, EventType, Dimension } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { NotificationsList } from 'vs/workbench/browser/parts/notifications/notificationsList';
import { Event } from 'vs/base/common/event';
import { Event, Emitter } from 'vs/base/common/event';
import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService';
import { Themable, NOTIFICATIONS_TOAST_BORDER, NOTIFICATIONS_BACKGROUND } from 'vs/workbench/common/theme';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { widgetShadow } from 'vs/platform/theme/common/colorRegistry';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { NotificationsToastsVisibleContext } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { NotificationsToastsVisibleContext, INotificationsToastController } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey';
import { localize } from 'vs/nls';
import { Severity, NotificationsFilter } from 'vs/platform/notification/common/notification';
@@ -39,7 +39,7 @@ enum ToastVisibility {
VISIBLE
}
export class NotificationsToasts extends Themable {
export class NotificationsToasts extends Themable implements INotificationsToastController {
private static readonly MAX_WIDTH = 450;
private static readonly MAX_NOTIFICATIONS = 3;
@@ -53,6 +53,12 @@ export class NotificationsToasts extends Themable {
return intervals;
})();
private readonly _onDidChangeVisibility = this._register(new Emitter<void>());
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
private _isVisible = false;
get isVisible(): boolean { return !!this._isVisible; }
private notificationsToastsContainer: HTMLElement | undefined;
private workbenchDimensions: Dimension | undefined;
private isNotificationsCenterVisible: boolean | undefined;
@@ -125,11 +131,11 @@ export class NotificationsToasts extends Themable {
private addToast(item: INotificationViewItem): void {
if (this.isNotificationsCenterVisible) {
return; // do not show toasts while notification center is visibles
return; // do not show toasts while notification center is visible
}
if (item.silent) {
return; // do not show toats for silenced notifications
return; // do not show toasts for silenced notifications
}
// Lazily create toasts containers
@@ -174,7 +180,7 @@ export class NotificationsToasts extends Themable {
this.mapNotificationToToast.set(item, toast);
itemDisposables.add(toDisposable(() => {
if (this.isVisible(toast) && notificationsToastsContainer) {
if (this.isToastVisible(toast) && notificationsToastsContainer) {
notificationsToastsContainer.removeChild(toast.container);
}
}));
@@ -229,6 +235,12 @@ export class NotificationsToasts extends Themable {
removeClass(notificationToast, 'notification-fade-in');
addClass(notificationToast, 'notification-fade-in-done');
}));
// Events
if (!this._isVisible) {
this._isVisible = true;
this._onDidChangeVisibility.fire();
}
}
private purgeNotification(item: INotificationViewItem, notificationToastContainer: HTMLElement, notificationList: NotificationsList, disposables: DisposableStore): void {
@@ -325,6 +337,12 @@ export class NotificationsToasts extends Themable {
// Context Key
this.notificationsToastsVisibleContextKey.set(false);
// Events
if (this._isVisible) {
this._isVisible = false;
this._onDidChangeVisibility.fire();
}
}
hide(): void {
@@ -441,12 +459,12 @@ export class NotificationsToasts extends Themable {
notificationToasts.push(toast);
break;
case ToastVisibility.HIDDEN:
if (!this.isVisible(toast)) {
if (!this.isToastVisible(toast)) {
notificationToasts.push(toast);
}
break;
case ToastVisibility.VISIBLE:
if (this.isVisible(toast)) {
if (this.isToastVisible(toast)) {
notificationToasts.push(toast);
}
break;
@@ -534,7 +552,7 @@ export class NotificationsToasts extends Themable {
}
private setVisibility(toast: INotificationToast, visible: boolean): void {
if (this.isVisible(toast) === visible) {
if (this.isToastVisible(toast) === visible) {
return;
}
@@ -546,7 +564,7 @@ export class NotificationsToasts extends Themable {
}
}
private isVisible(toast: INotificationToast): boolean {
private isToastVisible(toast: INotificationToast): boolean {
return !!toast.container.parentElement;
}
}

View File

@@ -306,7 +306,7 @@ export class NotificationTemplateRenderer extends Disposable {
// Container
toggleClass(this.template.container, 'expanded', notification.expanded);
this.inputDisposables.add(addDisposableListener(this.template.container, EventType.MOUSE_UP, e => {
if (e.button === 1 /* Middle Button */) {
if (!notification.hasProgress && e.button === 1 /* Middle Button */) {
EventHelper.stop(e);
notification.close();
@@ -403,8 +403,10 @@ export class NotificationTemplateRenderer extends Disposable {
actions.push(notification.expanded ? NotificationTemplateRenderer.collapseNotificationAction : NotificationTemplateRenderer.expandNotificationAction);
}
// Close
actions.push(NotificationTemplateRenderer.closeNotificationAction);
// Close (unless progress is showing)
if (!notification.hasProgress) {
actions.push(NotificationTemplateRenderer.closeNotificationAction);
}
this.template.toolbar.clear();
this.template.toolbar.context = notification;
@@ -453,7 +455,7 @@ export class NotificationTemplateRenderer extends Disposable {
private renderProgress(notification: INotificationViewItem): void {
// Return early if the item has no progress
if (!notification.hasProgress()) {
if (!notification.hasProgress) {
this.template.progress.stop().hide();
return;

View File

@@ -33,6 +33,9 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { LayoutPriority } from 'vs/base/browser/ui/grid/grid';
import { assertIsDefined } from 'vs/base/common/types';
import { LocalSelectionTransfer } from 'vs/workbench/browser/dnd';
import { DraggedViewIdentifier } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { DraggedCompositeIdentifier } from 'vs/workbench/browser/parts/compositeBarActions';
export class SidebarPart extends CompositePart<Viewlet> implements IViewletService {
@@ -163,6 +166,29 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
this.onTitleAreaContextMenu(new StandardMouseEvent(e));
}));
this.titleLabelElement!.draggable = true;
this._register(addDisposableListener(this.titleLabelElement!, EventType.DRAG_START, e => {
const activeViewlet = this.getActiveViewlet();
if (activeViewlet) {
const visibleViews = activeViewlet.getViewPaneContainer().views.filter(v => v.isVisible());
if (visibleViews.length === 1) {
LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().setData([new DraggedViewIdentifier(visibleViews[0].id)], DraggedViewIdentifier.prototype);
} else {
LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().setData([new DraggedCompositeIdentifier(activeViewlet.getId())], DraggedCompositeIdentifier.prototype);
}
}
}));
this._register(addDisposableListener(this.titleLabelElement!, EventType.DRAG_END, e => {
if (LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().hasData(DraggedViewIdentifier.prototype)) {
LocalSelectionTransfer.getInstance<DraggedViewIdentifier>().clearData(DraggedViewIdentifier.prototype);
}
if (LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().hasData(DraggedCompositeIdentifier.prototype)) {
LocalSelectionTransfer.getInstance<DraggedCompositeIdentifier>().clearData(DraggedCompositeIdentifier.prototype);
}
}));
return titleArea;
}

View File

@@ -43,6 +43,7 @@ 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';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
export class CustomTreeViewPane extends ViewPane {
@@ -59,8 +60,9 @@ export class CustomTreeViewPane extends ViewPane {
@IInstantiationService instantiationService: IInstantiationService,
@IOpenerService openerService: IOpenerService,
@IThemeService themeService: IThemeService,
@ITelemetryService telemetryService: ITelemetryService,
) {
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService);
super({ ...(options as IViewPaneOptions), ariaHeaderLabel: options.title, titleMenuId: MenuId.ViewTitle }, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService);
const { treeView } = (<ITreeViewDescriptor>Registry.as<IViewsRegistry>(Extensions.ViewsRegistry).getView(options.id));
this.treeView = treeView;
this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this));

View File

@@ -66,6 +66,10 @@ export class DraggedViewIdentifier {
}
}
type WelcomeActionClassification = {
viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
uri: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };
};
const viewsRegistry = Registry.as<IViewsRegistry>(ViewContainerExtensions.ViewsRegistry);
@@ -194,11 +198,12 @@ export abstract class ViewPane extends Pane implements IView {
@IKeybindingService protected keybindingService: IKeybindingService,
@IContextMenuService protected contextMenuService: IContextMenuService,
@IConfigurationService protected readonly configurationService: IConfigurationService,
@IContextKeyService contextKeyService: IContextKeyService,
@IContextKeyService protected contextKeyService: IContextKeyService,
@IViewDescriptorService protected viewDescriptorService: IViewDescriptorService,
@IInstantiationService protected instantiationService: IInstantiationService,
@IOpenerService protected openerService: IOpenerService,
@IThemeService protected themeService: IThemeService,
@ITelemetryService protected telemetryService: ITelemetryService,
) {
super(options);
@@ -397,7 +402,9 @@ export abstract class ViewPane extends Pane implements IView {
addClass(this.bodyContainer, 'welcome');
this.viewWelcomeContainer.innerHTML = '';
for (const { content } of contents) {
let buttonIndex = 0;
for (const { content, preconditions } of contents) {
const lines = content.split('\n');
for (let line of lines) {
@@ -416,9 +423,28 @@ export abstract class ViewPane extends Pane implements IView {
} else if (linkedText.nodes.length === 1) {
const button = new Button(p, { title: node.title });
button.label = node.label;
button.onDidClick(_ => this.openerService.open(node.href), null, disposables);
button.onDidClick(_ => {
this.telemetryService.publicLog2<{ viewId: string, uri: string }, WelcomeActionClassification>('views.welcomeAction', { viewId: this.id, uri: node.href });
this.openerService.open(node.href);
}, null, disposables);
disposables.add(button);
disposables.add(attachButtonStyler(button, this.themeService));
if (preconditions) {
const precondition = preconditions[buttonIndex];
if (precondition) {
const updateEnablement = () => button.enabled = this.contextKeyService.contextMatchesRules(precondition);
updateEnablement();
const keys = new Set();
precondition.keys().forEach(key => keys.add(key));
const onDidChangeContext = Event.filter(this.contextKeyService.onDidChangeContext, e => e.affectsSome(keys));
onDidChangeContext(updateEnablement, null, disposables);
}
}
buttonIndex++;
} else {
const link = this.instantiationService.createInstance(Link, node);
append(p, link.el);

View File

@@ -42,6 +42,19 @@ import { workbenchConfigurationNodeBase } from 'vs/workbench/common/configuratio
key: 'tabDescription'
}, "Controls the format of the label for an editor."),
},
'workbench.editor.untitled.labelFormat': {
'type': 'string',
'enum': ['content', 'name'],
'enumDescriptions': [
nls.localize('workbench.editor.untitled.labelFormat.content', "The name of the untitled file is derived from the contents of its first line unless it has an associated file path. It will fallback to the name in case the line is empty or contains no word characters."),
nls.localize('workbench.editor.untitled.labelFormat.name', "The name of the untitled file is not derived from the contents of the file."),
],
'default': 'content',
'description': nls.localize({
comment: ['This is the description for a setting. Values surrounded by parenthesis are not to be translated.'],
key: 'untitledLabelFormat'
}, "Controls the format of the label for an untitled editor."),
},
'workbench.editor.tabCloseButton': {
'type': 'string',
'enum': ['left', 'right', 'off'],

View File

@@ -386,10 +386,14 @@ export class Workbench extends Layout {
// Visibility
this._register(notificationsCenter.onDidChangeVisibility(() => {
notificationsStatus.update(notificationsCenter.isVisible);
notificationsStatus.update(notificationsCenter.isVisible, notificationsToasts.isVisible);
notificationsToasts.update(notificationsCenter.isVisible);
}));
this._register(notificationsToasts.onDidChangeVisibility(() => {
notificationsStatus.update(notificationsCenter.isVisible, notificationsToasts.isVisible);
}));
// Register Commands
registerNotificationCommands(notificationsCenter, notificationsToasts);
}