Merge from vscode 31e03b8ffbb218a87e3941f2b63a249f061fe0e4 (#4986)

This commit is contained in:
Anthony Dresser
2019-04-10 16:29:23 -07:00
committed by GitHub
parent 18c54f41bd
commit 8315dacda4
320 changed files with 5540 additions and 3822 deletions

View File

@@ -51,6 +51,8 @@ import { Schemas } from 'vs/base/common/network';
import { registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/editor/editorWidgets';
import { ZoomStatusbarItem } from 'vs/workbench/browser/parts/editor/resourceViewer';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { toLocalResource } from 'vs/base/common/resources';
// Register String Editor
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
@@ -111,7 +113,8 @@ interface ISerializedUntitledEditorInput {
class UntitledEditorInputFactory implements IEditorInputFactory {
constructor(
@ITextFileService private readonly textFileService: ITextFileService
@ITextFileService private readonly textFileService: ITextFileService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService
) { }
serialize(editorInput: EditorInput): string | undefined {
@@ -128,7 +131,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
let resource = untitledEditorInput.getResource();
if (untitledEditorInput.hasAssociatedFilePath) {
resource = resource.with({ scheme: Schemas.file }); // untitled with associated file path use the file schema
resource = toLocalResource(resource, this.environmentService.configuration.remoteAuthority); // untitled with associated file path use the local schema
}
const serialized: ISerializedUntitledEditorInput = {
@@ -145,7 +148,7 @@ class UntitledEditorInputFactory implements IEditorInputFactory {
return instantiationService.invokeFunction<UntitledEditorInput>(accessor => {
const deserialized: ISerializedUntitledEditorInput = JSON.parse(serializedEditorInput);
const resource = !!deserialized.resourceJSON ? URI.revive(deserialized.resourceJSON) : URI.parse(deserialized.resource);
const filePath = resource.scheme === Schemas.file ? resource.fsPath : undefined;
const filePath = resource.scheme === Schemas.untitled ? undefined : resource.scheme === Schemas.file ? resource.fsPath : resource.path;
const language = deserialized.modeId;
const encoding = deserialized.encoding;

View File

@@ -231,6 +231,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro
return this._whenRestored;
}
get willRestoreEditors(): boolean {
return !!this.workspaceMemento[EditorPart.EDITOR_PART_UI_STATE_STORAGE_KEY];
}
getGroups(order = GroupsOrder.CREATION_TIME): IEditorGroupView[] {
switch (order) {
case GroupsOrder.CREATION_TIME:

View File

@@ -4,13 +4,13 @@
*--------------------------------------------------------------------------------------------*/
import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem } from 'vs/workbench/common/notifications';
import { IStatusbarService, StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar';
import { IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { Disposable } from 'vs/base/common/lifecycle';
import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { localize } from 'vs/nls';
export class NotificationsStatus extends Disposable {
private statusItem: IDisposable;
private statusItem: IStatusbarEntryAccessor;
private isNotificationsCenterVisible: boolean;
private _counter: Set<INotificationViewItem>;
@@ -64,19 +64,18 @@ export class NotificationsStatus extends Disposable {
}
private updateNotificationsStatusItem(): void {
// Dispose old first
if (this.statusItem) {
this.statusItem.dispose();
}
// Create new
this.statusItem = this.statusbarService.addEntry({
const statusProperties: IStatusbarEntry = {
text: this.count === 0 ? '$(bell)' : `$(bell) ${this.count}`,
command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER,
tooltip: this.getTooltip(),
showBeak: this.isNotificationsCenterVisible
}, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */);
};
if (!this.statusItem) {
this.statusItem = this.statusbarService.addEntry(statusProperties, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */);
} else {
this.statusItem.update(statusProperties);
}
}
private getTooltip(): string {
@@ -98,12 +97,4 @@ export class NotificationsStatus extends Disposable {
return localize('notifications', "{0} New Notifications", this.count);
}
dispose() {
super.dispose();
if (this.statusItem) {
this.statusItem.dispose();
}
}
}

View File

@@ -49,16 +49,27 @@
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left {
padding-left: 7px;
}
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left:first-child,
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.has-background-color.left {
padding-right: 7px; /* expand padding if background color is configured for the status bar entry to make it look centered properly */
}
/* adding padding to the most right status bar item */
.monaco-workbench .part.statusbar > .statusbar-item.right:first-child {
padding-right: 7px;
}
/* tweak appearance for items with background to improve hover feedback */
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left:first-child,
.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.has-background-color.left,
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right:first-child {
padding-left: 7px; /* expand padding if background color is configured for the status bar entry to make it look centered properly */
padding-right: 0;
padding-left: 0;
}
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left > :first-child,
.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right > :first-child
{
margin-right: 0;
margin-left: 0;
padding-left: 10px;
padding-right: 10px;
}
.monaco-workbench .part.statusbar > .statusbar-item a {

View File

@@ -6,16 +6,16 @@
import 'vs/css!./media/statusbarpart';
import * as nls from 'vs/nls';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { dispose, IDisposable, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle';
import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle';
import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel';
import { Registry } from 'vs/platform/registry/common/platform';
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 { IStatusbarRegistry, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IStatusbarRegistry, Extensions } from 'vs/workbench/browser/parts/statusbar/statusbar';
import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar';
import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { Action } from 'vs/base/common/actions';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService';
@@ -24,11 +24,14 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { isThemeColor } from 'vs/editor/common/editorCommon';
import { Color } from 'vs/base/common/color';
import { addClass, EventHelper, createStyleSheet, addDisposableListener } from 'vs/base/browser/dom';
import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass } from 'vs/base/browser/dom';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { coalesce } from 'vs/base/common/arrays';
interface PendingEntry { entry: IStatusbarEntry; alignment: StatusbarAlignment; priority: number; accessor?: IStatusbarEntryAccessor; }
export class StatusbarPart extends Part implements IStatusbarService {
@@ -46,10 +49,10 @@ export class StatusbarPart extends Part implements IStatusbarService {
//#endregion
private statusMsgDispose: IDisposable;
private statusMessageDispose: IDisposable;
private styleElement: HTMLStyleElement;
private pendingEntries: { entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number, disposable: IDisposable }[] = [];
private pendingEntries: PendingEntry[] = [];
constructor(
@IInstantiationService private readonly instantiationService: IInstantiationService,
@@ -67,24 +70,38 @@ export class StatusbarPart extends Part implements IStatusbarService {
this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles()));
}
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IDisposable {
addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor {
// As long as we have not been created into a container yet, record all entries
// that are pending so that they can get created at a later point
if (!this.element) {
const pendingEntry = { entry, alignment, priority, disposable: Disposable.None };
const pendingEntry: PendingEntry = {
entry, alignment, priority
};
this.pendingEntries.push(pendingEntry);
return toDisposable(() => {
this.pendingEntries = this.pendingEntries.filter(e => e !== pendingEntry);
pendingEntry.disposable.dispose();
});
const accessor: IStatusbarEntryAccessor = {
update: (entry: IStatusbarEntry) => {
if (pendingEntry.accessor) {
pendingEntry.accessor.update(entry);
} else {
pendingEntry.entry = entry;
}
},
dispose: () => {
if (pendingEntry.accessor) {
pendingEntry.accessor.dispose();
} else {
this.pendingEntries = this.pendingEntries.filter(entry => entry !== pendingEntry);
}
}
};
return accessor;
}
// Render entry in status bar
const el = this.doCreateStatusItem(alignment, priority, entry.showBeak ? 'has-beak' : undefined);
const item = this.instantiationService.createInstance(StatusBarEntryItem, entry);
const toDispose = item.render(el);
const el = this.doCreateStatusItem(alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined]));
const item = this.instantiationService.createInstance(StatusBarEntryItem, el, entry);
// Insert according to priority
const container = this.element;
@@ -106,13 +123,24 @@ export class StatusbarPart extends Part implements IStatusbarService {
container.appendChild(el);
}
return toDisposable(() => {
el.remove();
return {
update: entry => {
if (toDispose) {
toDispose.dispose();
// Update beak
if (entry.showBeak) {
addClass(el, 'has-beak');
} else {
removeClass(el, 'has-beak');
}
// Update entry
item.update(entry);
},
dispose: () => {
el.remove();
dispose(item);
}
});
};
}
private getEntries(alignment: StatusbarAlignment): HTMLElement[] {
@@ -164,7 +192,7 @@ export class StatusbarPart extends Part implements IStatusbarService {
while (this.pendingEntries.length) {
const entry = this.pendingEntries.shift();
if (entry) {
entry.disposable = this.addEntry(entry.entry, entry.alignment, entry.priority);
entry.accessor = this.addEntry(entry.entry, entry.alignment, entry.priority);
}
}
@@ -195,11 +223,11 @@ export class StatusbarPart extends Part implements IStatusbarService {
this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`;
}
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, extraClass?: string): HTMLElement {
private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement {
const el = document.createElement('div');
addClass(el, 'statusbar-item');
if (extraClass) {
addClass(el, extraClass);
if (extraClasses) {
addClasses(el, ...extraClasses);
}
if (alignment === StatusbarAlignment.RIGHT) {
@@ -215,20 +243,20 @@ export class StatusbarPart extends Part implements IStatusbarService {
}
setStatusMessage(message: string, autoDisposeAfter: number = -1, delayBy: number = 0): IDisposable {
if (this.statusMsgDispose) {
this.statusMsgDispose.dispose(); // dismiss any previous
}
// Dismiss any previous
dispose(this.statusMessageDispose);
// Create new
let statusDispose: IDisposable;
let statusMessageEntry: IStatusbarEntryAccessor;
let showHandle: any = setTimeout(() => {
statusDispose = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
statusMessageEntry = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */);
showHandle = null;
}, delayBy);
let hideHandle: any;
// Dispose function takes care of timeouts and actual entry
const dispose = {
const statusMessageDispose = {
dispose: () => {
if (showHandle) {
clearTimeout(showHandle);
@@ -238,18 +266,18 @@ export class StatusbarPart extends Part implements IStatusbarService {
clearTimeout(hideHandle);
}
if (statusDispose) {
statusDispose.dispose();
if (statusMessageEntry) {
statusMessageEntry.dispose();
}
}
};
this.statusMsgDispose = dispose;
this.statusMessageDispose = statusMessageDispose;
if (typeof autoDisposeAfter === 'number' && autoDisposeAfter > 0) {
hideHandle = setTimeout(() => dispose.dispose(), autoDisposeAfter);
hideHandle = setTimeout(() => statusMessageDispose.dispose(), autoDisposeAfter);
}
return dispose;
return statusMessageDispose;
}
layout(width: number, height: number): void {
@@ -264,10 +292,12 @@ export class StatusbarPart extends Part implements IStatusbarService {
}
let manageExtensionAction: ManageExtensionAction;
class StatusBarEntryItem implements IStatusbarItem {
class StatusBarEntryItem extends Disposable {
private entryDisposables: IDisposable[] = [];
constructor(
private entry: IStatusbarEntry,
private container: HTMLElement,
entry: IStatusbarEntry,
@ICommandService private readonly commandService: ICommandService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@INotificationService private readonly notificationService: INotificationService,
@@ -276,78 +306,80 @@ class StatusBarEntryItem implements IStatusbarItem {
@IEditorService private readonly editorService: IEditorService,
@IThemeService private readonly themeService: IThemeService
) {
this.entry = entry;
super();
if (!manageExtensionAction) {
manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction);
}
this.render(entry);
}
render(el: HTMLElement): IDisposable {
let toDispose: IDisposable[] = [];
addClass(el, 'statusbar-entry');
update(entry: IStatusbarEntry): void {
clearNode(this.container);
this.entryDisposables = dispose(this.entryDisposables);
this.render(entry);
}
private render(entry: IStatusbarEntry): void {
// Text Container
let textContainer: HTMLElement;
if (this.entry.command) {
if (entry.command) {
textContainer = document.createElement('a');
toDispose.push(addDisposableListener(textContainer, 'click', () => this.executeCommand(this.entry.command!, this.entry.arguments)));
this.entryDisposables.push((addDisposableListener(textContainer, 'click', () => this.executeCommand(entry.command!, entry.arguments))));
} else {
textContainer = document.createElement('span');
}
// Label
new OcticonLabel(textContainer).text = this.entry.text;
new OcticonLabel(textContainer).text = entry.text;
// Tooltip
if (this.entry.tooltip) {
textContainer.title = this.entry.tooltip;
if (entry.tooltip) {
textContainer.title = entry.tooltip;
}
// Color (only applies to text container)
toDispose.push(this.applyColor(textContainer, this.entry.color));
this.applyColor(textContainer, entry.color);
// Background Color (applies to parent element to fully fill container)
if (this.entry.backgroundColor) {
toDispose.push(this.applyColor(el, this.entry.backgroundColor, true));
addClass(el, 'has-background-color');
if (entry.backgroundColor) {
this.applyColor(this.container, entry.backgroundColor, true);
addClass(this.container, 'has-background-color');
}
// Context Menu
if (this.entry.extensionId) {
toDispose.push(addDisposableListener(textContainer, 'contextmenu', e => {
if (entry.extensionId) {
this.entryDisposables.push((addDisposableListener(textContainer, 'contextmenu', e => {
EventHelper.stop(e, true);
this.contextMenuService.showContextMenu({
getAnchor: () => el,
getActionsContext: () => this.entry.extensionId!.value,
getAnchor: () => this.container,
getActionsContext: () => entry.extensionId!.value,
getActions: () => [manageExtensionAction]
});
}));
})));
}
el.appendChild(textContainer);
return toDisposable(() => toDispose = dispose(toDispose));
this.container.appendChild(textContainer);
}
private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): IDisposable {
const disposable: IDisposable[] = [];
private applyColor(container: HTMLElement, color: string | ThemeColor | undefined, isBackground?: boolean): void {
if (color) {
if (isThemeColor(color)) {
const colorId = color.id;
color = (this.themeService.getTheme().getColor(colorId) || Color.transparent).toString();
disposable.push(this.themeService.onThemeChange(theme => {
this.entryDisposables.push(((this.themeService.onThemeChange(theme => {
const colorValue = (theme.getColor(colorId) || Color.transparent).toString();
isBackground ? container.style.backgroundColor = colorValue : container.style.color = colorValue;
}));
}))));
}
isBackground ? container.style.backgroundColor = color : container.style.color = color;
}
return combinedDisposable(disposable);
}
private executeCommand(id: string, args?: unknown[]) {
@@ -368,6 +400,12 @@ class StatusBarEntryItem implements IStatusbarItem {
this.telemetryService.publicLog('workbenchActionExecuted', { id, from: 'status bar' });
this.commandService.executeCommand(id, ...args).then(undefined, err => this.notificationService.error(toErrorMessage(err)));
}
dispose(): void {
super.dispose();
this.entryDisposables = dispose(this.entryDisposables);
}
}
class ManageExtensionAction extends Action {

View File

@@ -312,7 +312,7 @@ export class MenubarControl extends Disposable {
// Send menus to main process to be rendered by Electron
const menubarData = { menus: {}, keybindings: {} };
if (this.getMenubarMenus(menubarData)) {
this.menubarService.updateMenubar(this.windowService.getCurrentWindowId(), menubarData);
this.menubarService.updateMenubar(this.windowService.windowId, menubarData);
}
}
}
@@ -440,7 +440,7 @@ export class MenubarControl extends Disposable {
return null;
case StateType.Idle:
const windowId = this.windowService.getCurrentWindowId();
const windowId = this.windowService.windowId;
return new Action('update.check', nls.localize({ key: 'checkForUpdates', comment: ['&& denotes a mnemonic'] }, "Check for &&Updates..."), undefined, true, () =>
this.updateService.checkForUpdates({ windowId }));

View File

@@ -18,7 +18,7 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import * as nls from 'vs/nls';
import { EditorInput, toResource, Verbosity, SideBySideEditor } from 'vs/workbench/common/editor';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme';
@@ -85,7 +85,7 @@ export class TitlebarPart extends Part implements ITitleService {
@IConfigurationService private readonly configurationService: IConfigurationService,
@IWindowsService private readonly windowsService: IWindowsService,
@IEditorService private readonly editorService: IEditorService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService,
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService,
@@ -412,7 +412,7 @@ export class TitlebarPart extends Part implements ITitleService {
// Resizer
this.resizer = append(this.element, $('div.resizer'));
const isMaximized = this.windowService.getConfiguration().maximized ? true : false;
const isMaximized = this.environmentService.configuration.maximized ? true : false;
this.onDidChangeMaximized(isMaximized);
this.windowService.onDidChangeMaximize(this.onDidChangeMaximized, this);
}

View File

@@ -66,6 +66,7 @@ export abstract class ViewletPanel extends Panel implements IView {
protected actionRunner?: IActionRunner;
protected toolbar: ToolBar;
private headerContainer: HTMLElement;
private titleContainer: HTMLElement;
constructor(
options: IViewletPanelOptions,
@@ -141,7 +142,12 @@ export abstract class ViewletPanel extends Panel implements IView {
}
protected renderHeaderTitle(container: HTMLElement, title: string): void {
append(container, $('h3.title', undefined, title));
this.titleContainer = append(container, $('h3.title', undefined, title));
}
protected updateTitle(title: string): void {
this.titleContainer.textContent = title;
this._onDidChangeTitleArea.fire();
}
focus(): void {